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;
        }
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to