From a7b2d69c273d008ddc712bc3304c6f8d20b84fd7 Mon Sep 17 00:00:00 2001 From: Michael Elkins Date: Sat, 7 Apr 2007 14:33:27 -0700 Subject: [PATCH] bug #2871 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 | 18 +++++++----------- lib.c | 41 +++++++++++++++++++++++++++++++++++++++++ lib.h | 1 + 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/complete.c b/complete.c index bb728dacc..aca5ecafa 100644 --- a/complete.c +++ b/complete.c @@ -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 53ccb8423..4113af654 100644 --- 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 952a1b4ed..e022bb34d 100644 --- 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 *); -- 2.40.0