--- glob.c.orig 2011-01-25 17:41:37.000000000 -0800 +++ glob.c 2011-01-26 11:50:09.000000000 -0800 @@ -36,6 +36,8 @@ static char sccsid[] = "@(#)glob.c 8.3 ( #include <sys/cdefs.h> __FBSDID("$FreeBSD: src/lib/libc/gen/glob.c,v 1.28 2010/05/12 17:44:00 gordon Exp $"); +#include "xlocale_private.h" + /* * glob(3) -- a superset of the one defined in POSIX 1003.2. * @@ -89,6 +91,19 @@ __FBSDID("$FreeBSD: src/lib/libc/gen/glo #include "collate.h" +#define GLOB_LIMIT_STRING 65536 /* number of readdirs */ +#define GLOB_LIMIT_STAT 128 /* number of stat system calls */ +#define GLOB_LIMIT_READDIR 16384 /* 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; +}; + #define DOLLAR '$' #define DOT '.' #define EOS '\0' @@ -139,62 +154,64 @@ typedef char Char; #define ismeta(c) (((c)&M_QUOTE) != 0) -static int compare(const void *, const void *); -static int g_Ctoc(const Char *, char *, size_t); -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); +#define compare __gl_compare +#define g_Ctoc __gl_g_Ctoc +#define g_strchr __gl_g_strchr +#define globextend __gl_globextend +#define globtilde __gl_globtilde +#define match __gl_match +__private_extern__ int compare(const void *, const void *); +__private_extern__ int g_Ctoc(const Char *, char *, size_t, locale_t); +__private_extern__ const Char *g_strchr(const Char *, wchar_t); +__private_extern__ int globextend(const Char *, glob_t *, struct glob_limit *, locale_t); +__private_extern__ const Char * + globtilde(const Char *, Char *, size_t, glob_t *); +__private_extern__ int match(Char *, Char *, Char *, locale_t); + + +static int g_lstat(Char *, struct stat *, glob_t *, locale_t); +static DIR *g_opendir(Char *, glob_t *, locale_t); #ifdef notdef static Char *g_strcat(Char *, const Char *); #endif -static int g_stat(Char *, struct stat *, 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 const Char * - globtilde(const Char *, Char *, size_t, glob_t *); -static int globexp1(const Char *, glob_t *, size_t *); -static int globexp2(const Char *, const Char *, glob_t *, int *, size_t *); -static int match(Char *, Char *, Char *); +static int g_stat(Char *, struct stat *, glob_t *, locale_t); +static int glob0(const Char *, glob_t *, struct glob_limit *, locale_t); +static int glob1(Char *, glob_t *, struct glob_limit *, locale_t); +static int glob2(Char *, Char *, Char *, Char *, glob_t *, struct glob_limit *, locale_t); +static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, struct glob_limit *, locale_t); +static int globexp1(const Char *, glob_t *, struct glob_limit *, locale_t); +static int globexp2(const Char *, const Char *, glob_t *, int *, struct glob_limit *, locale_t); #ifdef DEBUG static void qprintf(const char *, Char *); #endif -int -glob(const char *pattern, int flags, int (*errfunc)(const char *, int), glob_t *pglob) +static int +__glob(const char *pattern, glob_t *pglob) { const char *patnext; - size_t limit; + struct glob_limit limit = { 0, 0, 0, 0 }; Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot; mbstate_t mbs; wchar_t wc; size_t clen; + locale_t loc = __current_locale(); + int mb_cur_max = MB_CUR_MAX_L(loc); patnext = pattern; - if (!(flags & GLOB_APPEND)) { + if (!(pglob->gl_flags & GLOB_APPEND)) { pglob->gl_pathc = 0; pglob->gl_pathv = NULL; - if (!(flags & GLOB_DOOFFS)) + if (!(pglob->gl_flags & GLOB_DOOFFS)) pglob->gl_offs = 0; } - if (flags & GLOB_LIMIT) { - limit = pglob->gl_matchc; - if (limit == 0) - limit = ARG_MAX; - } else - limit = 0; - pglob->gl_flags = flags & ~GLOB_MAGCHAR; - pglob->gl_errfunc = errfunc; pglob->gl_matchc = 0; bufnext = patbuf; bufend = bufnext + MAXPATHLEN - 1; - if (flags & GLOB_NOESCAPE) { + if (pglob->gl_flags & GLOB_NOESCAPE) { memset(&mbs, 0, sizeof(mbs)); - while (bufend - bufnext >= MB_CUR_MAX) { - clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs); + while (bufend - bufnext >= mb_cur_max) { + clen = mbrtowc_l(&wc, patnext, MB_LEN_MAX, &mbs, loc); if (clen == (size_t)-1 || clen == (size_t)-2) return (GLOB_NOMATCH); else if (clen == 0) @@ -205,7 +222,7 @@ glob(const char *pattern, int flags, int } else { /* Protect the quoted characters. */ memset(&mbs, 0, sizeof(mbs)); - while (bufend - bufnext >= MB_CUR_MAX) { + while (bufend - bufnext >= mb_cur_max) { if (*patnext == QUOTE) { if (*++patnext == EOS) { *bufnext++ = QUOTE | M_PROTECT; @@ -214,7 +231,7 @@ glob(const char *pattern, int flags, int prot = M_PROTECT; } else prot = 0; - clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs); + clen = mbrtowc_l(&wc, patnext, MB_LEN_MAX, &mbs, loc); if (clen == (size_t)-1 || clen == (size_t)-2) return (GLOB_NOMATCH); else if (clen == 0) @@ -225,11 +242,34 @@ glob(const char *pattern, int flags, int } *bufnext = EOS; - if (flags & GLOB_BRACE) - return globexp1(patbuf, pglob, &limit); + if (pglob->gl_flags & GLOB_BRACE) + return globexp1(patbuf, pglob, &limit, loc); else - return glob0(patbuf, pglob, &limit); + return glob0(patbuf, pglob, &limit, loc); +} + +int +glob(const char *pattern, int flags, int (*errfunc)(const char *, int), glob_t *pglob) +{ +#ifdef __BLOCKS__ + pglob->gl_flags = flags & ~(GLOB_MAGCHAR | _GLOB_ERR_BLOCK); +#else /* !__BLOCKS__ */ + pglob->gl_flags = flags & ~GLOB_MAGCHAR; +#endif /* __BLOCKS__ */ + pglob->gl_errfunc = errfunc; + return __glob(pattern, pglob); +} + +#ifdef __BLOCKS__ +int +glob_b(const char *pattern, int flags, int (^errblk)(const char *, int), glob_t *pglob) +{ + pglob->gl_flags = flags & ~GLOB_MAGCHAR; + pglob->gl_flags |= _GLOB_ERR_BLOCK; + pglob->gl_errblk = errblk; + return __glob(pattern, pglob); } +#endif /* __BLOCKS__ */ /* * Expand recursively a glob {} pattern. When there is no more expansion @@ -237,20 +277,26 @@ 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, locale_t loc) { const Char* ptr = pattern; int rv; + 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); + return glob0(pattern, pglob, limit, loc); while ((ptr = g_strchr(ptr, LBRACE)) != NULL) - if (!globexp2(ptr, pattern, pglob, &rv, limit)) + if (!globexp2(ptr, pattern, pglob, &rv, limit, loc)) return rv; - return glob0(pattern, pglob, limit); + return glob0(pattern, pglob, limit, loc); } @@ -260,7 +306,7 @@ globexp1(const Char *pattern, glob_t *pg * If it fails then it tries to glob the rest of the pattern and returns. */ static int -globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, size_t *limit) +globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, struct glob_limit *limit, locale_t loc) { int i; Char *lm, *ls; @@ -297,7 +343,7 @@ globexp2(const Char *ptr, const Char *pa /* Non matching braces; just glob the pattern */ if (i != 0 || *pe == EOS) { - *rv = glob0(patbuf, pglob, limit); + *rv = glob0(patbuf, pglob, limit, loc); return 0; } @@ -344,7 +390,7 @@ globexp2(const Char *ptr, const Char *pa #ifdef DEBUG qprintf("globexp2:", patbuf); #endif - *rv = globexp1(patbuf, pglob, limit); + *rv = globexp1(patbuf, pglob, limit, loc); /* move after the comma, to the next string */ pl = pm + 1; @@ -360,10 +406,11 @@ globexp2(const Char *ptr, const Char *pa +#ifndef BUILDING_VARIANT /* * expand tilde from the passwd file. */ -static const Char * +__private_extern__ const Char * globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob) { struct passwd *pwd; @@ -421,6 +468,7 @@ globtilde(const Char *pattern, Char *pat return patbuf; } +#endif /* BUILDING_VARIANT */ /* @@ -430,7 +478,7 @@ globtilde(const Char *pattern, Char *pat * if things went well, nonzero if errors occurred. */ static int -glob0(const Char *pattern, glob_t *pglob, size_t *limit) +glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit, locale_t loc) { const Char *qpatnext; int err; @@ -443,6 +491,10 @@ glob0(const Char *pattern, glob_t *pglob /* We don't need to check for buffer overflow any more. */ while ((c = *qpatnext++) != EOS) { + if (c & M_PROTECT) { + *bufnext++ = CHAR(c); + continue; + } /* else */ switch (c) { case LBRACKET: c = *qpatnext; @@ -493,7 +545,7 @@ glob0(const Char *pattern, glob_t *pglob qprintf("glob0:", patbuf); #endif - if ((err = glob1(patbuf, pglob, limit)) != 0) + if ((err = glob1(patbuf, pglob, limit, loc)) != 0) return(err); /* @@ -506,7 +558,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, loc)); else return(GLOB_NOMATCH); } @@ -516,14 +568,16 @@ glob0(const Char *pattern, glob_t *pglob return(0); } -static int +#ifndef BUILDING_VARIANT +__private_extern__ int compare(const void *p, const void *q) { - return(strcmp(*(char **)p, *(char **)q)); + return(strcoll(*(char **)p, *(char **)q)); } +#endif /* BUILDING_VARIANT */ static int -glob1(Char *pattern, glob_t *pglob, size_t *limit) +glob1(Char *pattern, glob_t *pglob, struct glob_limit *limit, locale_t loc) { Char pathbuf[MAXPATHLEN]; @@ -531,7 +585,7 @@ glob1(Char *pattern, glob_t *pglob, size if (*pattern == EOS) return(0); return(glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1, - pattern, pglob, limit)); + pattern, pglob, limit, loc)); } /* @@ -541,7 +595,7 @@ glob1(Char *pattern, glob_t *pglob, size */ static int glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern, - glob_t *pglob, size_t *limit) + glob_t *pglob, struct glob_limit *limit, locale_t loc) { struct stat sb; Char *p, *q; @@ -554,13 +608,20 @@ glob2(Char *pathbuf, Char *pathend, Char for (anymeta = 0;;) { if (*pattern == EOS) { /* End of pattern? */ *pathend = EOS; - if (g_lstat(pathbuf, &sb, pglob)) + if (g_lstat(pathbuf, &sb, pglob, loc)) return(0); + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_stat++ >= GLOB_LIMIT_STAT) { + errno = 0; + *pathend++ = SEP; + *pathend = EOS; + 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) && + (g_stat(pathbuf, &sb, pglob, loc) == 0) && S_ISDIR(sb.st_mode)))) { if (pathend + 1 > pathend_last) return (GLOB_ABORTED); @@ -568,7 +629,7 @@ glob2(Char *pathbuf, Char *pathend, Char *pathend = EOS; } ++pglob->gl_matchc; - return(globextend(pathbuf, pglob, limit)); + return(globextend(pathbuf, pglob, limit, loc)); } /* Find end of next segment, copy tentatively to pathend. */ @@ -592,7 +653,7 @@ glob2(Char *pathbuf, Char *pathend, Char } } else /* Need expansion, recurse. */ return(glob3(pathbuf, pathend, pathend_last, pattern, p, - pglob, limit)); + pglob, limit, loc)); } /* NOTREACHED */ } @@ -600,7 +661,7 @@ glob2(Char *pathbuf, Char *pathend, Char static int glob3(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern, Char *restpattern, - glob_t *pglob, size_t *limit) + glob_t *pglob, struct glob_limit *limit, locale_t loc) { struct dirent *dp; DIR *dirp; @@ -620,15 +681,22 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend = EOS; errno = 0; - if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { + if ((dirp = g_opendir(pathbuf, pglob, loc)) == NULL) { /* TODO: don't call for ENOENT or ENOTDIR? */ if (pglob->gl_errfunc) { - if (g_Ctoc(pathbuf, buf, sizeof(buf))) + if (g_Ctoc(pathbuf, buf, sizeof(buf), loc)) return (GLOB_ABORTED); - if (pglob->gl_errfunc(buf, errno) || - pglob->gl_flags & GLOB_ERR) +#ifdef __BLOCKS__ + if (pglob->gl_flags & _GLOB_ERR_BLOCK) { + if (pglob->gl_errblk(buf, errno)) + return (GLOB_ABORTED); + } else +#endif /* __BLOCKS__ */ + if (pglob->gl_errfunc(buf, errno)) return (GLOB_ABORTED); } + if (pglob->gl_flags & GLOB_ERR) + return (GLOB_ABORTED); return(0); } @@ -646,6 +714,14 @@ glob3(Char *pathbuf, Char *pathend, Char size_t clen; mbstate_t mbs; + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_readdir++ >= GLOB_LIMIT_READDIR) { + errno = 0; + *pathend++ = SEP; + *pathend = EOS; + return GLOB_NOSPACE; + } + /* Initial DOT must be matched literally. */ if (dp->d_name[0] == DOT && *pattern != DOT) continue; @@ -653,7 +729,7 @@ glob3(Char *pathbuf, Char *pathend, Char dc = pathend; sc = dp->d_name; while (dc < pathend_last) { - clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs); + clen = mbrtowc_l(&wc, sc, MB_LEN_MAX, &mbs, loc); if (clen == (size_t)-1 || clen == (size_t)-2) { wc = *sc; clen = 1; @@ -663,12 +739,12 @@ glob3(Char *pathbuf, Char *pathend, Char break; sc += clen; } - if (!match(pathend, pattern, restpattern)) { + if (!match(pathend, pattern, restpattern, loc)) { *pathend = EOS; continue; } err = glob2(pathbuf, --dc, pathend_last, restpattern, - pglob, limit); + pglob, limit, loc); if (err) break; } @@ -681,6 +757,7 @@ glob3(Char *pathbuf, Char *pathend, Char } +#ifndef BUILDING_VARIANT /* * Extend the gl_pathv member of a glob_t structure to accomodate a new item, * add the new item, and update gl_pathc. @@ -695,20 +772,18 @@ glob3(Char *pathbuf, Char *pathend, Char * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and * gl_pathv points to (gl_offs + gl_pathc + 1) items. */ -static int -globextend(const Char *path, glob_t *pglob, size_t *limit) +__private_extern__ int +globextend(const Char *path, glob_t *pglob, struct glob_limit *limit, locale_t loc) { char **pathv; size_t i, newsize, len; char *copy; const Char *p; - if (*limit && pglob->gl_pathc > *limit) { - errno = 0; - return (GLOB_NOSPACE); - } - 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((char *)pglob->gl_pathv, newsize) : malloc(newsize); @@ -730,24 +805,33 @@ globextend(const Char *path, glob_t *pgl for (p = path; *p++;) continue; - len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */ + len = MB_CUR_MAX_L(loc) * (size_t)(p - path); /* XXX overallocation */ + limit->l_string += len; if ((copy = malloc(len)) != NULL) { - if (g_Ctoc(path, copy, len)) { + if (g_Ctoc(path, copy, len, loc)) { free(copy); return (GLOB_NOSPACE); } pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; } pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + + if ((pglob->gl_flags & GLOB_LIMIT) && + (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. */ -static int -match(Char *name, Char *pat, Char *patend) +__private_extern__ int +match(Char *name, Char *pat, Char *patend, locale_t loc) { int ok, negate_range; Char c, k; @@ -759,7 +843,7 @@ match(Char *name, Char *pat, Char *paten if (pat == patend) return(1); do - if (match(name, pat, patend)) + if (match(name, pat, patend, loc)) return(1); while (*name++ != EOS); return(0); @@ -775,10 +859,10 @@ match(Char *name, Char *pat, Char *paten ++pat; while (((c = *pat++) & M_MASK) != M_END) if ((*pat & M_MASK) == M_RNG) { - if (__collate_load_error ? + if (loc->__collate_load_error ? CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) : - __collate_range_cmp(CHAR(c), CHAR(k)) <= 0 - && __collate_range_cmp(CHAR(k), CHAR(pat[1])) <= 0 + __collate_range_cmp(CHAR(c), CHAR(k), loc) <= 0 + && __collate_range_cmp(CHAR(k), CHAR(pat[1]), loc) <= 0 ) ok = 1; pat += 2; @@ -812,16 +896,17 @@ globfree(glob_t *pglob) pglob->gl_pathv = NULL; } } +#endif /* !BUILDING_VARIANT */ static DIR * -g_opendir(Char *str, glob_t *pglob) +g_opendir(Char *str, glob_t *pglob, locale_t loc) { char buf[MAXPATHLEN]; if (!*str) strcpy(buf, "."); else { - if (g_Ctoc(str, buf, sizeof(buf))) + if (g_Ctoc(str, buf, sizeof(buf), loc)) return (NULL); } @@ -832,11 +917,11 @@ g_opendir(Char *str, glob_t *pglob) } static int -g_lstat(Char *fn, struct stat *sb, glob_t *pglob) +g_lstat(Char *fn, struct stat *sb, glob_t *pglob, locale_t loc) { char buf[MAXPATHLEN]; - if (g_Ctoc(fn, buf, sizeof(buf))) { + if (g_Ctoc(fn, buf, sizeof(buf), loc)) { errno = ENAMETOOLONG; return (-1); } @@ -846,11 +931,11 @@ g_lstat(Char *fn, struct stat *sb, glob_ } static int -g_stat(Char *fn, struct stat *sb, glob_t *pglob) +g_stat(Char *fn, struct stat *sb, glob_t *pglob, locale_t loc) { char buf[MAXPATHLEN]; - if (g_Ctoc(fn, buf, sizeof(buf))) { + if (g_Ctoc(fn, buf, sizeof(buf), loc)) { errno = ENAMETOOLONG; return (-1); } @@ -859,7 +944,8 @@ g_stat(Char *fn, struct stat *sb, glob_t return(stat(buf, sb)); } -static const Char * +#ifndef BUILDING_VARIANT +__private_extern__ const Char * g_strchr(const Char *str, wchar_t ch) { @@ -870,15 +956,16 @@ g_strchr(const Char *str, wchar_t ch) return (NULL); } -static int -g_Ctoc(const Char *str, char *buf, size_t len) +__private_extern__ int +g_Ctoc(const Char *str, char *buf, size_t len, locale_t loc) { mbstate_t mbs; size_t clen; + int mb_cur_max = MB_CUR_MAX_L(loc); memset(&mbs, 0, sizeof(mbs)); - while (len >= MB_CUR_MAX) { - clen = wcrtomb(buf, *str, &mbs); + while (len >= mb_cur_max) { + clen = wcrtomb_l(buf, *str, &mbs, loc); if (clen == (size_t)-1) return (1); if (*str == L'\0') @@ -908,3 +995,4 @@ qprintf(const char *str, Char *s) (void)printf("\n"); } #endif +#endif /* !BUILDING_VARIANT */