Date: Wed, 20 Jul 2016 07:30:44 +0000 (UTC) From: "Andrey A. Chernov" <ache@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r303074 - head/lib/libc/gen Message-ID: <201607200730.u6K7Ui3s096327@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: ache Date: Wed Jul 20 07:30:44 2016 New Revision: 303074 URL: https://svnweb.freebsd.org/changeset/base/303074 Log: 1) Per POSIX (and glibc) GLOB_NOCHECK should return original pattern, unmodified, if no matches found. But our original code strips all '\' returning it. Rewrite the code to allow to reconstruct exact the original pattern with backslashes for this case. 2) Prevent to use truncated pattern if MAXPATHLEN exceeded, return GLOB_NOMATCH instead. 3) Fix few end loop conditions filling Char arrays with mbrtowc(), MB_CUR_MAX is unneeded in two places and condition is less by one in other place. 4) Prevent to use truncated filenames match if MAXPATHLEN exceeded, skip such directory entries. 5) Don't end *pathend with L'/' in glob3() if limit is reached, this change will be not visible since error is returned. 6) If error happens in (*readdirfunc)(), do the same GLOB_ABORTED processing as for g_opendir() as POSIX requires. Modified: head/lib/libc/gen/glob.c Modified: head/lib/libc/gen/glob.c ============================================================================== --- head/lib/libc/gen/glob.c Wed Jul 20 06:29:26 2016 (r303073) +++ head/lib/libc/gen/glob.c Wed Jul 20 07:30:44 2016 (r303074) @@ -152,6 +152,7 @@ typedef char Char; #define CHAR(c) ((Char)((c)&M_CHAR)) #define META(c) ((Char)((c)|M_QUOTE)) +#define UNPROT(c) ((c) & ~M_PROTECT) #define M_ALL META(L'*') #define M_END META(L']') #define M_NOT META(L'!') @@ -159,10 +160,11 @@ typedef char Char; #define M_RNG META(L'-') #define M_SET META(L'[') #define ismeta(c) (((c)&M_QUOTE) != 0) +#define isprot(c) (((c)&M_PROTECT) != 0) static int compare(const void *, const void *); -static int g_Ctoc(const Char *, char *, size_t); +static int g_Ctoc(const Char *, char *, size_t, int); static int g_lstat(Char *, struct stat *, glob_t *); static DIR *g_opendir(Char *, glob_t *); static const Char *g_strchr(const Char *, wchar_t); @@ -176,7 +178,7 @@ static int glob2(Char *, Char *, Char * struct glob_limit *); static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, struct glob_limit *); -static int globextend(const Char *, glob_t *, struct glob_limit *); +static int globextend(const Char *, glob_t *, struct glob_limit *, int); static const Char * globtilde(const Char *, Char *, size_t, glob_t *); static int globexp1(const Char *, glob_t *, struct glob_limit *); @@ -197,6 +199,7 @@ glob(const char * __restrict pattern, in mbstate_t mbs; wchar_t wc; size_t clen; + int too_long; patnext = pattern; if (!(flags & GLOB_APPEND)) { @@ -216,24 +219,27 @@ glob(const char * __restrict pattern, in bufnext = patbuf; bufend = bufnext + MAXPATHLEN - 1; + too_long = 1; if (flags & GLOB_NOESCAPE) { memset(&mbs, 0, sizeof(mbs)); - while (bufend - bufnext >= MB_CUR_MAX) { + while (bufnext <= bufend) { clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs); if (clen == (size_t)-1 || clen == (size_t)-2) return (GLOB_NOMATCH); - else if (clen == 0) + else if (clen == 0) { + too_long = 0; break; + } *bufnext++ = wc; patnext += clen; } } else { /* Protect the quoted characters. */ memset(&mbs, 0, sizeof(mbs)); - while (bufend - bufnext >= MB_CUR_MAX) { + while (bufnext <= bufend) { if (*patnext == '\\') { if (*++patnext == '\0') { - *bufnext++ = QUOTE | M_PROTECT; + *bufnext++ = QUOTE; continue; } prot = M_PROTECT; @@ -242,13 +248,16 @@ glob(const char * __restrict pattern, in clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs); if (clen == (size_t)-1 || clen == (size_t)-2) return (GLOB_NOMATCH); - else if (clen == 0) + else if (clen == 0) { + too_long = 0; break; - *bufnext++ = wc | ((wc != DOT && wc != SEP) ? - prot : 0); + } + *bufnext++ = wc | prot; patnext += clen; } } + if (too_long) + return (GLOB_NOMATCH); *bufnext = EOS; if (flags & GLOB_BRACE) @@ -447,7 +456,7 @@ globtilde(const Char *pattern, Char *pat /* * Expand a ~user */ - if (g_Ctoc(patbuf, (char *)wbuf, sizeof(wbuf))) + if (g_Ctoc(patbuf, (char *)wbuf, sizeof(wbuf), 0)) return (NULL); if ((pwd = getpwnam((char *)wbuf)) == NULL) return (pattern); @@ -479,8 +488,8 @@ globtilde(const Char *pattern, Char *pat return (NULL); dc = wbuf; - for (b = patbuf; b < eb && *dc != EOS; b++, dc++) - *b = *dc | ((*dc != DOT && *dc != SEP) ? M_PROTECT : 0); + for (b = patbuf; b < eb && *dc != EOS; *b++ = *dc++ | M_PROTECT) + continue; if (*dc != EOS) return (NULL); @@ -589,7 +598,7 @@ glob0(const Char *pattern, glob_t *pglob if (((pglob->gl_flags & GLOB_NOCHECK) || ((pglob->gl_flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR)))) - return (globextend(pattern, pglob, limit)); + return (globextend(pattern, pglob, limit, 1)); else return (GLOB_NOMATCH); } @@ -645,10 +654,11 @@ glob2(Char *pathbuf, Char *pathend, Char errno = 0; return (GLOB_NOSPACE); } - if (((pglob->gl_flags & GLOB_MARK) && - pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) - || (S_ISLNK(sb.st_mode) && - (g_stat(pathbuf, &sb, pglob) == 0) && + if ((pglob->gl_flags & GLOB_MARK) && + UNPROT(pathend[-1]) != SEP && + (S_ISDIR(sb.st_mode) || + (S_ISLNK(sb.st_mode) && + g_stat(pathbuf, &sb, pglob) == 0 && S_ISDIR(sb.st_mode)))) { if (pathend + 1 > pathend_last) { errno = 0; @@ -658,13 +668,13 @@ glob2(Char *pathbuf, Char *pathend, Char *pathend = EOS; } ++pglob->gl_matchc; - return (globextend(pathbuf, pglob, limit)); + return (globextend(pathbuf, pglob, limit, 0)); } /* Find end of next segment, copy tentatively to pathend. */ q = pathend; p = pattern; - while (*p != EOS && *p != SEP) { + while (*p != EOS && UNPROT(*p) != SEP) { if (ismeta(*p)) anymeta = 1; if (q + 1 > pathend_last) { @@ -677,7 +687,7 @@ glob2(Char *pathbuf, Char *pathend, Char if (!anymeta) { /* No expansion, do next segment. */ pathend = q; pattern = p; - while (*pattern == SEP) { + while (UNPROT(*pattern) == SEP) { if (pathend + 1 > pathend_last) { errno = 0; return (GLOB_NOSPACE); @@ -698,28 +708,29 @@ glob3(Char *pathbuf, Char *pathend, Char { struct dirent *dp; DIR *dirp; - int err; + int err, too_long, saverrno; char buf[MAXPATHLEN + MB_LEN_MAX - 1]; struct dirent *(*readdirfunc)(DIR *); - errno = 0; - if (pathend > pathend_last) + if (pathend > pathend_last) { + errno = 0; return (GLOB_NOSPACE); + } *pathend = EOS; + if (pglob->gl_errfunc != NULL && + g_Ctoc(pathbuf, buf, sizeof(buf), 0)) { + errno = 0; + return (GLOB_NOSPACE); + } + errno = 0; if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { if (errno == ENOENT || errno == ENOTDIR) return (0); - if (pglob->gl_errfunc != NULL) { - if (g_Ctoc(pathbuf, buf, sizeof(buf))) { - errno = 0; - return (GLOB_NOSPACE); - } - if (pglob->gl_errfunc(buf, errno)) - return (GLOB_ABORTED); - } - if (pglob->gl_flags & GLOB_ERR) + if ((pglob->gl_errfunc != NULL && + pglob->gl_errfunc(buf, errno)) || + (pglob->gl_flags & GLOB_ERR)) return (GLOB_ABORTED); return (0); } @@ -732,6 +743,7 @@ glob3(Char *pathbuf, Char *pathend, Char else readdirfunc = readdir; + errno = 0; /* Search directory for matching names. */ while ((dp = (*readdirfunc)(dirp)) != NULL) { char *sc; @@ -743,23 +755,18 @@ glob3(Char *pathbuf, Char *pathend, Char if ((pglob->gl_flags & GLOB_LIMIT) && limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) { errno = 0; - if (pathend + 1 > pathend_last) - err = GLOB_NOSPACE; - else { - *pathend++ = SEP; - *pathend = EOS; - err = GLOB_NOSPACE; - } + err = GLOB_NOSPACE; break; } /* Initial DOT must be matched literally. */ - if (dp->d_name[0] == '.' && *pattern != DOT) + if (dp->d_name[0] == '.' && UNPROT(*pattern) != DOT) continue; memset(&mbs, 0, sizeof(mbs)); dc = pathend; sc = dp->d_name; - while (dc < pathend_last) { + too_long = 1; + while (dc <= pathend_last) { clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs); if (clen == (size_t)-1 || clen == (size_t)-2) { /* XXX See initial comment #2. */ @@ -767,11 +774,13 @@ glob3(Char *pathbuf, Char *pathend, Char clen = 1; memset(&mbs, 0, sizeof(mbs)); } - if ((*dc++ = wc) == EOS) + if ((*dc++ = wc) == EOS) { + too_long = 0; break; + } sc += clen; } - if (!match(pathend, pattern, restpattern)) { + if (too_long || !match(pathend, pattern, restpattern)) { *pathend = EOS; continue; } @@ -779,13 +788,24 @@ glob3(Char *pathbuf, Char *pathend, Char pglob, limit); if (err) break; + errno = 0; } + saverrno = errno; if (pglob->gl_flags & GLOB_ALTDIRFUNC) (*pglob->gl_closedir)(dirp); else closedir(dirp); - return (err); + errno = saverrno; + + if (err) + return (err); + + if (dp == NULL && errno != 0 && ((pglob->gl_errfunc != NULL && + pglob->gl_errfunc(buf, errno)) || (pglob->gl_flags & GLOB_ERR))) + return (GLOB_ABORTED); + + return (0); } @@ -804,7 +824,8 @@ glob3(Char *pathbuf, Char *pathend, Char * gl_pathv points to (gl_offs + gl_pathc + 1) items. */ static int -globextend(const Char *path, glob_t *pglob, struct glob_limit *limit) +globextend(const Char *path, glob_t *pglob, struct glob_limit *limit, + int prot) { char **pathv; size_t i, newsize, len; @@ -831,9 +852,11 @@ globextend(const Char *path, glob_t *pgl } pglob->gl_pathv = pathv; - for (p = path; *p++;) + for (p = path; *p++ != EOS;) continue; len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */ + if (prot) + len += (size_t)(p - path) - 1; limit->l_string_cnt += len; if ((pglob->gl_flags & GLOB_LIMIT) && limit->l_string_cnt >= GLOB_LIMIT_STRING) { @@ -841,7 +864,7 @@ globextend(const Char *path, glob_t *pgl return (GLOB_NOSPACE); } if ((copy = malloc(len)) != NULL) { - if (g_Ctoc(path, copy, len)) { + if (g_Ctoc(path, copy, len, prot)) { free(copy); errno = 0; return (GLOB_NOSPACE); @@ -935,7 +958,7 @@ g_opendir(Char *str, glob_t *pglob) if (*str == EOS) strcpy(buf, "."); else { - if (g_Ctoc(str, buf, sizeof(buf))) { + if (g_Ctoc(str, buf, sizeof(buf), 0)) { errno = ENAMETOOLONG; return (NULL); } @@ -952,7 +975,7 @@ g_lstat(Char *fn, struct stat *sb, glob_ { char buf[MAXPATHLEN + MB_LEN_MAX - 1]; - if (g_Ctoc(fn, buf, sizeof(buf))) { + if (g_Ctoc(fn, buf, sizeof(buf), 0)) { errno = ENAMETOOLONG; return (-1); } @@ -966,7 +989,7 @@ g_stat(Char *fn, struct stat *sb, glob_t { char buf[MAXPATHLEN + MB_LEN_MAX - 1]; - if (g_Ctoc(fn, buf, sizeof(buf))) { + if (g_Ctoc(fn, buf, sizeof(buf), 0)) { errno = ENAMETOOLONG; return (-1); } @@ -987,23 +1010,31 @@ g_strchr(const Char *str, wchar_t ch) } static int -g_Ctoc(const Char *str, char *buf, size_t len) +g_Ctoc(const Char *str, char *buf, size_t len, int prot) { mbstate_t mbs; size_t clen; + Char Ch; + Ch = *str; memset(&mbs, 0, sizeof(mbs)); while (len >= MB_CUR_MAX) { - clen = wcrtomb(buf, CHAR(*str), &mbs); + if (prot && isprot(Ch)) { + Ch = UNPROT(Ch); + *buf++ = '\\'; + len--; + continue; + } + clen = wcrtomb(buf, CHAR(Ch), &mbs); if (clen == (size_t)-1) { /* XXX See initial comment #2. */ - *buf = (char)CHAR(*str); + *buf = (char)CHAR(Ch); clen = 1; memset(&mbs, 0, sizeof(mbs)); } - if (CHAR(*str) == EOS) + if (CHAR(Ch) == EOS) return (0); - str++; + Ch = *++str; buf += clen; len -= clen; }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201607200730.u6K7Ui3s096327>