Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files. =================================================================== RCS file: /ftp/cvs/cvsroot/src/lib/libc/gen/glob.c,v rcsdiff: /ftp/cvs/cvsroot/src/lib/libc/gen/glob.c,v: warning: Unknown phrases like `commitid ...;' are present. retrieving revision 1.23.4.1 retrieving revision 1.37 diff -u -p -r1.23.4.1 -r1.37 --- src/lib/libc/gen/glob.c 2010/07/19 18:14:08 1.23.4.1 +++ src/lib/libc/gen/glob.c 2017/04/26 14:56:54 1.37 @@ -1,4 +1,4 @@ -/* $NetBSD: glob.c,v 1.23.4.1 2010/07/19 18:14:08 riz Exp $ */ +/* $NetBSD: glob.c,v 1.37 2017/04/26 14:56:54 christos Exp $ */ /* * Copyright (c) 1989, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93"; #else -__RCSID("$NetBSD: glob.c,v 1.23.4.1 2010/07/19 18:14:08 riz Exp $"); +__RCSID("$NetBSD: glob.c,v 1.37 2017/04/26 14:56:54 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -87,13 +87,18 @@ __RCSID("$NetBSD: glob.c,v 1.23.4.1 2010 #define NO_GETPW_R #endif -#define GLOB_LIMIT_MALLOC 65536 -#define GLOB_LIMIT_STAT 128 -#define GLOB_LIMIT_READDIR 16384 - -#define GLOB_INDEX_MALLOC 0 -#define GLOB_INDEX_STAT 1 -#define GLOB_INDEX_READDIR 2 +#define GLOB_LIMIT_STRING 524288 /* number of readdirs */ +#define GLOB_LIMIT_STAT 128 /* number of stat system calls */ +#define GLOB_LIMIT_READDIR 65536 /* total buffer size of path strings */ +#define GLOB_LIMIT_PATH 1024 /* number of path elements */ +#define GLOB_LIMIT_BRACE 128 /* Number of brace calls */ + +struct glob_limit { + size_t l_string; + size_t l_stat; + size_t l_readdir; + size_t l_brace; +}; /* * XXX: For NetBSD 1.4.x compatibility. (kill me l8r) @@ -127,7 +132,7 @@ __RCSID("$NetBSD: glob.c,v 1.23.4.1 2010 #define M_MASK 0xffff #define M_ASCII 0x00ff -typedef u_short Char; +typedef unsigned short Char; #else @@ -158,35 +163,34 @@ static int g_lstat(Char *, __gl_stat_t static DIR *g_opendir(Char *, glob_t *); static Char *g_strchr(const Char *, int); static int g_stat(Char *, __gl_stat_t *, glob_t *); -static int glob0(const Char *, glob_t *, size_t *); -static int glob1(Char *, glob_t *, size_t *); -static int glob2(Char *, Char *, Char *, Char *, glob_t *, - size_t *); -static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, - size_t *); -static int globextend(const Char *, glob_t *, size_t *); +static int glob0(const Char *, glob_t *, struct glob_limit *); +static int glob1(Char *, glob_t *, struct glob_limit *); +static int glob2(Char *, Char *, Char *, const Char *, glob_t *, + struct glob_limit *); +static int glob3(Char *, Char *, Char *, const Char *, const Char *, + const Char *, glob_t *, struct glob_limit *); +static int globextend(const Char *, glob_t *, struct glob_limit *); static const Char *globtilde(const Char *, Char *, size_t, glob_t *); -static int globexp1(const Char *, glob_t *, size_t *); +static int globexp1(const Char *, glob_t *, struct glob_limit *); static int globexp2(const Char *, const Char *, glob_t *, int *, - size_t *); -static int match(Char *, Char *, Char *); + struct glob_limit *); +static int match(const Char *, const Char *, const Char *); #ifdef DEBUG static void qprintf(const char *, Char *); #endif int -glob(const char *pattern, int flags, int (*errfunc)(const char *, int), - glob_t *pglob) +glob(const char * __restrict pattern, int flags, int (*errfunc)(const char *, + int), glob_t * __restrict pglob) { - const u_char *patnext; + const unsigned char *patnext; int c; Char *bufnext, *bufend, patbuf[MAXPATHLEN+1]; - /* 0 = malloc(), 1 = stat(), 2 = readdir() */ - size_t limit[] = { 0, 0, 0 }; + struct glob_limit limit = { 0, 0, 0, 0 }; _DIAGASSERT(pattern != NULL); - patnext = (const u_char *) pattern; + patnext = (const unsigned char *) pattern; if (!(flags & GLOB_APPEND)) { pglob->gl_pathc = 0; pglob->gl_pathv = NULL; @@ -218,9 +222,9 @@ glob(const char *pattern, int flags, int *bufnext = EOS; if (flags & GLOB_BRACE) - return globexp1(patbuf, pglob, limit); + return globexp1(patbuf, pglob, &limit); else - return glob0(patbuf, pglob, limit); + return glob0(patbuf, pglob, &limit); } /* @@ -229,7 +233,7 @@ glob(const char *pattern, int flags, int * characters */ static int -globexp1(const Char *pattern, glob_t *pglob, size_t *limit) +globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit) { const Char* ptr = pattern; int rv; @@ -237,6 +241,12 @@ globexp1(const Char *pattern, glob_t *pg _DIAGASSERT(pattern != NULL); _DIAGASSERT(pglob != NULL); + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_brace++ >= GLOB_LIMIT_BRACE) { + errno = 0; + return GLOB_NOSPACE; + } + /* Protect a single {}, for find(1), like csh */ if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) return glob0(pattern, pglob, limit); @@ -256,7 +266,7 @@ globexp1(const Char *pattern, glob_t *pg */ static int globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, - size_t *limit) + struct glob_limit *limit) { int i; Char *lm, *ls; @@ -346,7 +356,7 @@ globexp2(const Char *ptr, const Char *pa /* Expand the current pattern */ #ifdef DEBUG - qprintf("globexp2:", patbuf); + qprintf("globexp2", patbuf); #endif *rv = globexp1(patbuf, pglob, limit); @@ -461,7 +471,7 @@ globtilde(const Char *pattern, Char *pat * to find no matches. */ static int -glob0(const Char *pattern, glob_t *pglob, size_t *limit) +glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit) { const Char *qpatnext; int c, error; @@ -513,10 +523,13 @@ glob0(const Char *pattern, glob_t *pglob break; case STAR: pglob->gl_flags |= GLOB_MAGCHAR; - /* collapse adjacent stars to one, + /* collapse adjacent stars to one [or three if globstar] * to avoid exponential behavior */ - if (bufnext == patbuf || bufnext[-1] != M_ALL) + if (bufnext == patbuf || bufnext[-1] != M_ALL || + ((pglob->gl_flags & GLOB_STAR) != 0 && + (bufnext - 1 == patbuf || bufnext[-2] != M_ALL || + bufnext - 2 == patbuf || bufnext[-3] != M_ALL))) *bufnext++ = M_ALL; break; default: @@ -526,7 +539,7 @@ glob0(const Char *pattern, glob_t *pglob } *bufnext = EOS; #ifdef DEBUG - qprintf("glob0:", patbuf); + qprintf("glob0", patbuf); #endif if ((error = glob1(patbuf, pglob, limit)) != 0) @@ -567,7 +580,7 @@ compare(const void *p, const void *q) } static int -glob1(Char *pattern, glob_t *pglob, size_t *limit) +glob1(Char *pattern, glob_t *pglob, struct glob_limit *limit) { Char pathbuf[MAXPATHLEN+1]; @@ -592,20 +605,22 @@ glob1(Char *pattern, glob_t *pglob, size * meta characters. */ static int -glob2(Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern, glob_t *pglob, - size_t *limit) +glob2(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern, + glob_t *pglob, struct glob_limit *limit) { __gl_stat_t sb; - Char *p, *q; + const Char *p; + Char *q; int anymeta; - Char *pend; - ptrdiff_t diff; _DIAGASSERT(pathbuf != NULL); _DIAGASSERT(pathend != NULL); _DIAGASSERT(pattern != NULL); _DIAGASSERT(pglob != NULL); +#ifdef DEBUG + qprintf("glob2", pathbuf); +#endif /* * Loop over pattern segments until end of pattern or until * segment with meta character found. @@ -617,7 +632,7 @@ glob2(Char *pathbuf, Char *pathend, Char return 0; if ((pglob->gl_flags & GLOB_LIMIT) && - limit[GLOB_INDEX_STAT]++ >= GLOB_LIMIT_STAT) { + limit->l_stat++ >= GLOB_LIMIT_STAT) { errno = 0; *pathend++ = SEP; *pathend = EOS; @@ -648,26 +663,7 @@ glob2(Char *pathbuf, Char *pathend, Char *q++ = *p++; } - /* - * No expansion, or path ends in slash-dot shash-dot-dot, - * do next segment. - */ - if (pglob->gl_flags & GLOB_PERIOD) { - for (pend = pathend; pend > pathbuf && pend[-1] == '/'; - pend--) - continue; - diff = pend - pathbuf; - } else { - /* XXX: GCC */ - diff = 0; - pend = pathend; - } - - if ((!anymeta) || - ((pglob->gl_flags & GLOB_PERIOD) && - (diff >= 1 && pend[-1] == DOT) && - (diff >= 2 && (pend[-2] == SLASH || pend[-2] == DOT)) && - (diff < 3 || pend[-3] == SLASH))) { + if (!anymeta) { pathend = q; pattern = p; while (*pattern == SEP) { @@ -677,19 +673,24 @@ glob2(Char *pathbuf, Char *pathend, Char } } else /* Need expansion, recurse. */ return glob3(pathbuf, pathend, pathlim, pattern, p, - pglob, limit); + pattern, pglob, limit); } /* NOTREACHED */ } static int -glob3(Char *pathbuf, Char *pathend, Char *pathlim, Char *pattern, - Char *restpattern, glob_t *pglob, size_t *limit) +glob3(Char *pathbuf, Char *pathend, Char *pathlim, const Char *pattern, + const Char *restpattern, const Char *pglobstar, glob_t *pglob, + struct glob_limit *limit) { struct dirent *dp; DIR *dirp; + __gl_stat_t sbuf; int error; char buf[MAXPATHLEN]; + int globstar = 0; + int chase_symlinks = 0; + const Char *termstar = NULL; /* * The readdirfunc declaration can't be prototyped, because it is @@ -708,6 +709,39 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend = EOS; errno = 0; + while (pglobstar < restpattern) { + if ((pglobstar[0] & M_MASK) == M_ALL && + (pglobstar[1] & M_MASK) == M_ALL) { + globstar = 1; + chase_symlinks = (pglobstar[2] & M_MASK) == M_ALL; + termstar = pglobstar + (2 + chase_symlinks); + break; + } + pglobstar++; + } + + if (globstar) { + error = pglobstar == pattern && termstar == restpattern ? + *restpattern == EOS ? + glob2(pathbuf, pathend, pathlim, restpattern - 1, pglob, + limit) : + glob2(pathbuf, pathend, pathlim, restpattern + 1, pglob, + limit) : + glob3(pathbuf, pathend, pathlim, pattern, restpattern, + termstar, pglob, limit); + if (error) + return error; + *pathend = EOS; + } + + if (*pathbuf && (g_lstat(pathbuf, &sbuf, pglob) || + !S_ISDIR(sbuf.st_mode) +#ifdef S_IFLINK + && ((globstar && !chase_symlinks) || !S_ISLNK(sbuf.st_mode)) +#endif + )) + return 0; + if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { if (pglob->gl_errfunc) { if (g_Ctoc(pathbuf, buf, sizeof(buf))) @@ -734,17 +768,18 @@ glob3(Char *pathbuf, Char *pathend, Char if (pglob->gl_flags & GLOB_ALTDIRFUNC) readdirfunc = pglob->gl_readdir; else - readdirfunc = (struct dirent *(*)__P((void *))) readdir; + readdirfunc = (struct dirent *(*)(void *)) readdir; while ((dp = (*readdirfunc)(dirp)) != NULL) { - u_char *sc; + unsigned char *sc; Char *dc; if ((pglob->gl_flags & GLOB_LIMIT) && - limit[GLOB_INDEX_READDIR]++ >= GLOB_LIMIT_READDIR) { + limit->l_readdir++ >= GLOB_LIMIT_READDIR) { errno = 0; *pathend++ = SEP; *pathend = EOS; - return GLOB_NOSPACE; + error = GLOB_NOSPACE; + break; } /* @@ -766,7 +801,7 @@ glob3(Char *pathbuf, Char *pathend, Char * The resulting string contains EOS, so we can * use the pathlim character, if it is the nul */ - for (sc = (u_char *) dp->d_name, dc = pathend; + for (sc = (unsigned char *) dp->d_name, dc = pathend; dc <= pathlim && (*dc++ = *sc++) != EOS;) continue; @@ -789,16 +824,36 @@ glob3(Char *pathbuf, Char *pathend, Char } } - if (!match(pathend, pattern, restpattern)) { + if (globstar) { +#ifdef S_IFLNK + if (!chase_symlinks && + (g_lstat(pathbuf, &sbuf, pglob) || + S_ISLNK(sbuf.st_mode))) + continue; +#endif + + if (!match(pathend, pattern, termstar)) + continue; + + if (--dc < pathlim - 2) + *dc++ = SEP; + *dc = EOS; + error = glob2(pathbuf, dc, pathlim, pglobstar, + pglob, limit); + if (error) + break; *pathend = EOS; - continue; + } else { + if (!match(pathend, pattern, restpattern)) { + *pathend = EOS; + continue; + } + error = glob2(pathbuf, --dc, pathlim, restpattern, + pglob, limit); + if (error) + break; } - error = glob2(pathbuf, --dc, pathlim, restpattern, pglob, - limit); - if (error) - break; } - if (pglob->gl_flags & GLOB_ALTDIRFUNC) (*pglob->gl_closedir)(dirp); else @@ -829,7 +884,7 @@ 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, size_t *limit) +globextend(const Char *path, glob_t *pglob, struct glob_limit *limit) { char **pathv; size_t i, newsize, len; @@ -840,6 +895,9 @@ globextend(const Char *path, glob_t *pgl _DIAGASSERT(pglob != NULL); newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); + if ((pglob->gl_flags & GLOB_LIMIT) && + newsize > GLOB_LIMIT_PATH * sizeof(*pathv)) + goto nospace; pathv = pglob->gl_pathv ? realloc(pglob->gl_pathv, newsize) : malloc(newsize); if (pathv == NULL) @@ -856,7 +914,7 @@ globextend(const Char *path, glob_t *pgl for (p = path; *p++;) continue; len = (size_t)(p - path); - limit[GLOB_INDEX_MALLOC] += len; + limit->l_string += len; if ((copy = malloc(len)) != NULL) { if (g_Ctoc(path, copy, len)) { free(copy); @@ -867,48 +925,56 @@ globextend(const Char *path, glob_t *pgl pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; if ((pglob->gl_flags & GLOB_LIMIT) && - (newsize + limit[GLOB_INDEX_MALLOC]) >= GLOB_LIMIT_MALLOC) { - errno = 0; - return GLOB_NOSPACE; - } + (newsize + limit->l_string) >= GLOB_LIMIT_STRING) + goto nospace; return copy == NULL ? GLOB_NOSPACE : 0; +nospace: + errno = 0; + return GLOB_NOSPACE; } /* - * pattern matching function for filenames. Each occurrence of the * - * pattern causes a recursion level. + * pattern matching function for filenames. */ static int -match(Char *name, Char *pat, Char *patend) +match(const Char *name, const Char *pat, const Char *patend) { int ok, negate_range; Char c, k; + const Char *patNext, *nameNext, *nameStart, *nameEnd; _DIAGASSERT(name != NULL); _DIAGASSERT(pat != NULL); _DIAGASSERT(patend != NULL); - - while (pat < patend) { - c = *pat++; + patNext = pat; + nameStart = nameNext = name; + nameEnd = NULL; + + while (pat < patend || *name) { + c = *pat; + if (*name == EOS) + nameEnd = name; switch (c & M_MASK) { case M_ALL: - if (pat == patend) - return 1; - do - if (match(name, pat, patend)) - return 1; - while (*name++ != EOS); - return 0; + while (pat[1] == '*') pat++; + patNext = pat; + nameNext = name + 1; + pat++; + continue; case M_ONE: - if (*name++ == EOS) - return 0; - break; + if (*name == EOS) + break; + pat++; + name++; + continue; case M_SET: ok = 0; - if ((k = *name++) == EOS) - return 0; + if ((k = *name) == EOS) + break; + pat++; + name++; if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) ++pat; while (((c = *pat++) & M_MASK) != M_END) @@ -919,15 +985,24 @@ match(Char *name, Char *pat, Char *paten } else if (c == k) ok = 1; if (ok == negate_range) - return 0; - break; + break; + continue; default: - if (*name++ != c) - return 0; - break; + if (*name != c) + break; + pat++; + name++; + continue; + } + if (nameNext != nameStart + && (nameEnd == NULL || nameNext <= nameEnd)) { + pat = patNext; + name = nameNext; + continue; } + return 0; } - return *name == EOS; + return 1; } /* Free allocated data belonging to a glob_t structure. */ @@ -950,6 +1025,39 @@ globfree(glob_t *pglob) } } +#ifndef __LIBC12_SOURCE__ +int +glob_pattern_p(const char *pattern, int quote) +{ + int range = 0; + + for (; *pattern; pattern++) + switch (*pattern) { + case QUESTION: + case STAR: + return 1; + + case QUOTE: + if (quote && pattern[1] != EOS) + ++pattern; + break; + + case LBRACKET: + range = 1; + break; + + case RBRACKET: + if (range) + return 1; + break; + default: + break; + } + + return 0; +} +#endif + static DIR * g_opendir(Char *str, glob_t *pglob) {