From f0dd3cce086d1383f966931cb1a8256db0febf9f Mon Sep 17 00:00:00 2001 From: Stefan Sperling Date: Sun, 25 Apr 2010 09:11:55 +0000 Subject: Fix auto-completion of filenames containing whitespace. Before this change whitespace wasn't escaped during completion which caused the ftp command to see multiple arguments where a single path was expected. Based on similar commit made to NetBSD's ftp in 1999. help and ok uwe tedu deraadt --- usr.bin/ftp/complete.c | 55 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 49 insertions(+), 6 deletions(-) (limited to 'usr.bin/ftp') diff --git a/usr.bin/ftp/complete.c b/usr.bin/ftp/complete.c index aaedf2dbafc..245bc572b5f 100644 --- a/usr.bin/ftp/complete.c +++ b/usr.bin/ftp/complete.c @@ -1,4 +1,4 @@ -/* $OpenBSD: complete.c,v 1.23 2009/05/05 19:35:30 martynas Exp $ */ +/* $OpenBSD: complete.c,v 1.24 2010/04/25 09:11:54 stsp Exp $ */ /* $NetBSD: complete.c,v 1.10 1997/08/18 10:20:18 lukem Exp $ */ /*- @@ -50,6 +50,7 @@ static unsigned char complete_ambiguous(char *, int, StringList *); static unsigned char complete_command(char *, int); static unsigned char complete_local(char *, int); static unsigned char complete_remote(char *, int); +static void ftpvis(char *, size_t, const char *, size_t); static int comparstr(const void *a, const void *b) @@ -70,7 +71,7 @@ comparstr(const void *a, const void *b) static unsigned char complete_ambiguous(char *word, int list, StringList *words) { - char insertstr[MAXPATHLEN]; + char insertstr[MAXPATHLEN * 2]; char *lastmatch; int i, j; size_t matchlen, wordlen; @@ -80,8 +81,9 @@ complete_ambiguous(char *word, int list, StringList *words) return (CC_ERROR); /* no choices available */ if (words->sl_cur == 1) { /* only once choice available */ - (void)strlcpy(insertstr, words->sl_str[0], sizeof insertstr); - if (el_insertstr(el, insertstr + wordlen) == -1) + char *p = words->sl_str[0] + wordlen; + ftpvis(insertstr, sizeof(insertstr), p, strlen(p)); + if (el_insertstr(el, insertstr) == -1) return (CC_ERROR); else return (CC_REFRESH); @@ -99,8 +101,9 @@ complete_ambiguous(char *word, int list, StringList *words) matchlen = j; } if (matchlen > wordlen) { - (void)strlcpy(insertstr, lastmatch, matchlen+1); - if (el_insertstr(el, insertstr + wordlen) == -1) + ftpvis(insertstr, sizeof(insertstr), + lastmatch + wordlen, matchlen); + if (el_insertstr(el, insertstr) == -1) return (CC_ERROR); else /* @@ -347,5 +350,45 @@ complete(EditLine *el, int ch) return (CC_ERROR); } +/* + * Copy characters from src into dst, \ quoting characters that require it. + */ +static void +ftpvis(char *dst, size_t dstlen, const char *src, size_t srclen) +{ + size_t di, si; + + /* paranoia paranoia everybody's trying to get me */ + if (dstlen == 0) + return; + if (srclen == 0) { + dst[0] = '\0'; + return; + } + + di = si = 0; + while (src[si] != '\0' && di < dstlen && si < srclen) { + switch (src[si]) { + case '\\': + case ' ': + case '\t': + case '\r': + case '\n': + case '"': + /* Need room for two characters and NUL, avoiding + * incomplete escape sequences at end of dst. */ + if (di >= dstlen - 3) + break; + dst[di++] = '\\'; + /* FALLTHROUGH */ + default: + dst[di] = src[si++]; + if (di < dstlen) + di++; + } + } + dst[di] = '\0'; +} + #endif /* !SMALL */ -- cgit v1.2.3