]> granicus.if.org Git - neomutt/commitdiff
bug #2871
authorMichael Elkins <me@mutt.org>
Sat, 7 Apr 2007 21:33:27 +0000 (14:33 -0700)
committerMichael Elkins <me@mutt.org>
Sat, 7 Apr 2007 21:33:27 +0000 (14:33 -0700)
Avoid altering the argument to mutt_complete() when completion fails.  Previously, the trailing component of filename was removed each time the user pressed TAB.

complete.c
lib.c
lib.h

index bb728dacc2b0dabcfa95c084212480c891f97d6e..aca5ecafa9282cdaf5ae2100309dedde00ab4527 100644 (file)
@@ -79,12 +79,12 @@ int mutt_complete (char *s, size_t slen)
     if ((p = strrchr (s, '/')))
     {
       char buf[_POSIX_PATH_MAX];
-      *p++ = 0;
-      mutt_concat_path (buf, exp_dirpart, s + 1, sizeof (buf));
+      if (mutt_concatn_path (buf, sizeof(buf), exp_dirpart, strlen(exp_dirpart), s + 1, (size_t)(p - s - 1)) == NULL) {
+             return -1;
+      }
       strfcpy (exp_dirpart, buf, sizeof (exp_dirpart));
-      snprintf (buf, sizeof (buf), "%s%s/", dirpart, s+1);
-      strfcpy (dirpart, buf, sizeof (dirpart));
-      strfcpy (filepart, p, sizeof (filepart));
+      mutt_substrcpy(dirpart, s, p+1, sizeof(dirpart));
+      strfcpy (filepart, p + 1, sizeof (filepart));
     }
     else
       strfcpy (filepart, s + 1, sizeof (filepart));
@@ -104,12 +104,8 @@ int mutt_complete (char *s, size_t slen)
       }
       else
       {
-       *p = 0;
-       len = (size_t)(p - s);
-       strncpy (dirpart, s, len);
-       dirpart[len]=0;
-       p++;
-       strfcpy (filepart, p, sizeof (filepart));
+       mutt_substrcpy(dirpart, s, p, sizeof(dirpart));
+       strfcpy (filepart, p + 1, sizeof (filepart));
        strfcpy (exp_dirpart, dirpart, sizeof (exp_dirpart));
        mutt_expand_path (exp_dirpart, sizeof (exp_dirpart));
        dirp = opendir (exp_dirpart);
diff --git a/lib.c b/lib.c
index 53ccb842362ea6f2c2568172384fe3bef1ad8757..4113af65454cb33d0f03c0a313d013f27dfdc6e0 100644 (file)
--- a/lib.c
+++ b/lib.c
@@ -858,6 +858,47 @@ void mutt_remove_trailing_ws (char *s)
     *p = 0;
 }
 
+/*
+ * Write the concatened pathname (dir + "/" + fname) into dst.
+ * The slash is ommitted when dir or fname is of 0 length.
+ * Returns NULL on error or a pointer to dst otherwise.
+ */
+char *mutt_concatn_path (char *dst, size_t dstlen,
+    const char *dir, size_t dirlen, const char *fname, size_t fnamelen)
+{
+  if (dstlen == 0)
+    return NULL; /* probably should not mask errors like this */
+
+  /* size check */
+  size_t req = dirlen + fnamelen + 1; /* +1 for the trailing nul */
+  if (dirlen && fnamelen)
+    req++; /* when both components are non-nul, we add a "/" in between */
+  if (req > dstlen) { /* check for condition where the dst length is too short */
+    /* Two options here:
+     * 1) assert(0) or return NULL to signal error
+     * 2) copy as much of the path as will fit
+     * It doesn't appear that the return value is actually checked anywhere mutt_concat_path()
+     * is called, so we should just copy set dst to nul and let the calling function fail later.
+     */
+    dst[0] = 0; /* safe since we bail out early if dstlen == 0 */
+    return NULL;
+  }
+
+  size_t offset = 0;
+  if (dirlen) { /* when dir is not empty */
+    memcpy(dst, dir, dirlen);
+    offset = dirlen;
+    if (fnamelen)
+      dst[offset++] = '/';
+  }
+  if (fnamelen) { /* when fname is not empty */
+    memcpy(dst + offset, fname, fnamelen);
+    offset += fnamelen;
+  }
+  dst[offset] = 0;
+  return dst;
+}
+
 char *mutt_concat_path (char *d, const char *dir, const char *fname, size_t l)
 {
   const char *fmt = "%s/%s";
diff --git a/lib.h b/lib.h
index 952a1b4edcf77cb42c8738160591c5c24339b408..e022bb34d74d9dfd8d7aca8c08508e20222bf3d5 100644 (file)
--- a/lib.h
+++ b/lib.h
@@ -136,6 +136,7 @@ MUTT_LIB_WHERE int debuglevel MUTT_LIB_INITVAL(0);
 
 FILE *safe_fopen (const char *, const char *);
 
+char *mutt_concatn_path (char *, size_t, const char *, size_t, const char *, size_t);
 char *mutt_concat_path (char *, const char *, const char *, size_t);
 char *mutt_read_line (char *, size_t *, FILE *, int *);
 char *mutt_skip_whitespace (char *);