Avoid altering the argument to mutt_complete() when completion fails. Previously, the trailing component of filename was removed each time the user pressed TAB.
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));
}
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);
*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";
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 *);