diff options
author | Renato Botelho <renato@netgate.com> | 2016-08-17 15:23:38 -0300 |
---|---|---|
committer | Renato Botelho <renato@netgate.com> | 2016-08-17 15:23:38 -0300 |
commit | 75cd8d40056c799f03b759475d9bfd10ba266a6c (patch) | |
tree | 60433235501684bffeab90e65139a8285fcf46a9 /lib/libc/gen/glob.c | |
parent | 99990a0d149f0eae805aa1f49d4a61be30c3b000 (diff) | |
parent | ad413762f28e3be343987e707b9cf4f10f963693 (diff) | |
download | FreeBSD-src-75cd8d40056c799f03b759475d9bfd10ba266a6c.zip FreeBSD-src-75cd8d40056c799f03b759475d9bfd10ba266a6c.tar.gz |
Merge remote-tracking branch 'origin/stable/10' into devel
Diffstat (limited to 'lib/libc/gen/glob.c')
-rw-r--r-- | lib/libc/gen/glob.c | 528 |
1 files changed, 332 insertions, 196 deletions
diff --git a/lib/libc/gen/glob.c b/lib/libc/gen/glob.c index 6c86297..5df0b74 100644 --- a/lib/libc/gen/glob.c +++ b/lib/libc/gen/glob.c @@ -71,7 +71,7 @@ __FBSDID("$FreeBSD$"); * 1. Patterns with illegal byte sequences match nothing - even if * GLOB_NOCHECK is specified. * 2. Illegal byte sequences in filenames are handled by treating them as - * single-byte characters with a value of the first byte of the sequence + * single-byte characters with a values of such bytes of the sequence * cast to wchar_t. * 3. State-dependent encodings are not currently supported. */ @@ -113,25 +113,20 @@ struct glob_limit { size_t l_string_cnt; }; -#define DOLLAR '$' -#define DOT '.' -#define EOS '\0' -#define LBRACKET '[' -#define NOT '!' -#define QUESTION '?' -#define QUOTE '\\' -#define RANGE '-' -#define RBRACKET ']' -#define SEP '/' -#define STAR '*' -#define TILDE '~' -#define UNDERSCORE '_' -#define LBRACE '{' -#define RBRACE '}' -#define SLASH '/' -#define COMMA ',' - -#ifndef DEBUG +#define DOT L'.' +#define EOS L'\0' +#define LBRACKET L'[' +#define NOT L'!' +#define QUESTION L'?' +#define QUOTE L'\\' +#define RANGE L'-' +#define RBRACKET L']' +#define SEP L'/' +#define STAR L'*' +#define TILDE L'~' +#define LBRACE L'{' +#define RBRACE L'}' +#define COMMA L',' #define M_QUOTE 0x8000000000ULL #define M_PROTECT 0x4000000000ULL @@ -140,28 +135,19 @@ struct glob_limit { typedef uint_fast64_t Char; -#else - -#define M_QUOTE 0x80 -#define M_PROTECT 0x40 -#define M_MASK 0xff -#define M_CHAR 0x7f - -typedef char Char; - -#endif - - #define CHAR(c) ((Char)((c)&M_CHAR)) #define META(c) ((Char)((c)|M_QUOTE)) -#define M_ALL META('*') -#define M_END META(']') -#define M_NOT META('!') -#define M_ONE META('?') -#define M_RNG META('-') -#define M_SET META('[') +#define UNPROT(c) ((c) & ~M_PROTECT) +#define M_ALL META(L'*') +#define M_END META(L']') +#define M_NOT META(L'!') +#define M_ONE META(L'?') +#define M_RNG META(L'-') +#define M_SET META(L'[') #define ismeta(c) (((c)&M_QUOTE) != 0) - +#ifdef DEBUG +#define isprot(c) (((c)&M_PROTECT) != 0) +#endif static int compare(const void *, const void *); static int g_Ctoc(const Char *, char *, size_t); @@ -172,19 +158,27 @@ static const Char *g_strchr(const Char *, wchar_t); static Char *g_strcat(Char *, const Char *); #endif static int g_stat(Char *, struct stat *, glob_t *); -static int glob0(const Char *, glob_t *, struct glob_limit *); +static int glob0(const Char *, glob_t *, struct glob_limit *, + const char *); static int glob1(Char *, glob_t *, struct glob_limit *); static int glob2(Char *, Char *, Char *, Char *, glob_t *, 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 *, + const char *); static const Char * globtilde(const Char *, Char *, size_t, glob_t *); +static int globexp0(const Char *, glob_t *, struct glob_limit *, + const char *); static int globexp1(const Char *, glob_t *, struct glob_limit *); -static int globexp2(const Char *, const Char *, glob_t *, int *, +static int globexp2(const Char *, const Char *, glob_t *, struct glob_limit *); +static int globfinal(glob_t *, struct glob_limit *, size_t, + const char *); static int match(Char *, Char *, Char *); +static int err_nomatch(glob_t *, struct glob_limit *, const char *); +static int err_aborted(glob_t *, int, char *); #ifdef DEBUG static void qprintf(const char *, Char *); #endif @@ -199,6 +193,7 @@ glob(const char * __restrict pattern, int flags, mbstate_t mbs; wchar_t wc; size_t clen; + int too_long; patnext = pattern; if (!(flags & GLOB_APPEND)) { @@ -218,24 +213,27 @@ glob(const char * __restrict pattern, int flags, 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) + return (err_nomatch(pglob, &limit, pattern)); + 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) { - if (*patnext == QUOTE) { - if (*++patnext == EOS) { - *bufnext++ = QUOTE | M_PROTECT; + while (bufnext <= bufend) { + if (*patnext == '\\') { + if (*++patnext == '\0') { + *bufnext++ = QUOTE; continue; } prot = M_PROTECT; @@ -243,19 +241,47 @@ glob(const char * __restrict pattern, int flags, prot = 0; clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs); if (clen == (size_t)-1 || clen == (size_t)-2) - return (GLOB_NOMATCH); - else if (clen == 0) + return (err_nomatch(pglob, &limit, pattern)); + else if (clen == 0) { + too_long = 0; break; + } *bufnext++ = wc | prot; patnext += clen; } } + if (too_long) + return (err_nomatch(pglob, &limit, pattern)); *bufnext = EOS; if (flags & GLOB_BRACE) - return (globexp1(patbuf, pglob, &limit)); + return (globexp0(patbuf, pglob, &limit, pattern)); else - return (glob0(patbuf, pglob, &limit)); + return (glob0(patbuf, pglob, &limit, pattern)); +} + +static int +globexp0(const Char *pattern, glob_t *pglob, struct glob_limit *limit, + const char *origpat) { + int rv; + size_t oldpathc; + + /* Protect a single {}, for find(1), like csh */ + if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) { + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + return (glob0(pattern, pglob, limit, origpat)); + } + + oldpathc = pglob->gl_pathc; + + if ((rv = globexp1(pattern, pglob, limit)) != 0) + return rv; + + return (globfinal(pglob, limit, oldpathc, origpat)); } /* @@ -266,24 +292,18 @@ glob(const char * __restrict pattern, int flags, static int globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit) { - const Char* ptr = pattern; - int rv; + const Char* ptr; - if ((pglob->gl_flags & GLOB_LIMIT) && - limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) { - errno = 0; - return (GLOB_NOSPACE); + if ((ptr = g_strchr(pattern, LBRACE)) != NULL) { + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + return (globexp2(ptr, pattern, pglob, limit)); } - /* Protect a single {}, for find(1), like csh */ - if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) - return glob0(pattern, pglob, limit); - - while ((ptr = g_strchr(ptr, LBRACE)) != NULL) - if (!globexp2(ptr, pattern, pglob, &rv, limit)) - return rv; - - return glob0(pattern, pglob, limit); + return (glob0(pattern, pglob, limit, NULL)); } @@ -293,10 +313,10 @@ globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit) * 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, +globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, struct glob_limit *limit) { - int i; + int i, rv; Char *lm, *ls; const Char *pe, *pm, *pm1, *pl; Char patbuf[MAXPATHLEN]; @@ -308,7 +328,7 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, ls = lm; /* Find the balanced brace */ - for (i = 0, pe = ++ptr; *pe; pe++) + for (i = 0, pe = ++ptr; *pe != EOS; pe++) if (*pe == LBRACKET) { /* Ignore everything between [] */ for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) @@ -330,10 +350,8 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, } /* Non matching braces; just glob the pattern */ - if (i != 0 || *pe == EOS) { - *rv = glob0(patbuf, pglob, limit); - return (0); - } + if (i != 0 || *pe == EOS) + return (glob0(pattern, pglob, limit, NULL)); for (i = 0, pl = pm = ptr; pm <= pe; pm++) switch (*pm) { @@ -378,7 +396,9 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, #ifdef DEBUG qprintf("globexp2:", patbuf); #endif - *rv = globexp1(patbuf, pglob, limit); + rv = globexp1(patbuf, pglob, limit); + if (rv) + return (rv); /* move after the comma, to the next string */ pl = pm + 1; @@ -388,7 +408,6 @@ globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, default: break; } - *rv = 0; return (0); } @@ -401,9 +420,15 @@ static const Char * globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob) { struct passwd *pwd; - char *h; + char *h, *sc; const Char *p; Char *b, *eb; + wchar_t wc; + wchar_t wbuf[MAXPATHLEN]; + wchar_t *wbufend, *dc; + size_t clen; + mbstate_t mbs; + int too_long; if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) return (pattern); @@ -412,13 +437,17 @@ globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob) * Copy up to the end of the string or / */ eb = &patbuf[patbuf_len - 1]; - for (p = pattern + 1, h = (char *) patbuf; - h < (char *)eb && *p && *p != SLASH; *h++ = *p++) + for (p = pattern + 1, b = patbuf; + b < eb && *p != EOS && UNPROT(*p) != SEP; *b++ = *p++) continue; - *h = EOS; + if (*p != EOS && UNPROT(*p) != SEP) + return (NULL); + + *b = EOS; + h = NULL; - if (((char *) patbuf)[0] == EOS) { + if (patbuf[0] == EOS) { /* * handle a plain ~ or ~/ by expanding $HOME first (iff * we're not running setuid or setgid) and then trying @@ -438,20 +467,56 @@ globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob) /* * Expand a ~user */ - if ((pwd = getpwnam((char*) patbuf)) == NULL) + if (g_Ctoc(patbuf, (char *)wbuf, sizeof(wbuf))) + return (NULL); + if ((pwd = getpwnam((char *)wbuf)) == NULL) return (pattern); else h = pwd->pw_dir; } /* Copy the home directory */ - for (b = patbuf; b < eb && *h; *b++ = *h++) + dc = wbuf; + sc = h; + wbufend = wbuf + MAXPATHLEN - 1; + too_long = 1; + memset(&mbs, 0, sizeof(mbs)); + while (dc <= wbufend) { + clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs); + if (clen == (size_t)-1 || clen == (size_t)-2) { + /* XXX See initial comment #2. */ + wc = (unsigned char)*sc; + clen = 1; + memset(&mbs, 0, sizeof(mbs)); + } + if ((*dc++ = wc) == EOS) { + too_long = 0; + break; + } + sc += clen; + } + if (too_long) + return (NULL); + + dc = wbuf; + for (b = patbuf; b < eb && *dc != EOS; *b++ = *dc++ | M_PROTECT) continue; + if (*dc != EOS) + return (NULL); /* Append the rest of the pattern */ - while (b < eb && (*b++ = *p++) != EOS) - continue; - *b = EOS; + if (*p != EOS) { + too_long = 1; + while (b <= eb) { + if ((*b++ = *p++) == EOS) { + too_long = 0; + break; + } + } + if (too_long) + return (NULL); + } else + *b = EOS; return (patbuf); } @@ -464,14 +529,18 @@ globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob) * if things went well, nonzero if errors occurred. */ static int -glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit) -{ +glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit, + const char *origpat) { const Char *qpatnext; int err; size_t oldpathc; Char *bufnext, c, patbuf[MAXPATHLEN]; qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob); + if (qpatnext == NULL) { + errno = E2BIG; + return (GLOB_NOSPACE); + } oldpathc = pglob->gl_pathc; bufnext = patbuf; @@ -530,30 +599,29 @@ glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit) if ((err = glob1(patbuf, pglob, limit)) != 0) return(err); - /* - * If there was no match we are going to append the pattern - * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified - * and the pattern did not contain any magic characters - * GLOB_NOMAGIC is there just for compatibility with csh. - */ - if (pglob->gl_pathc == oldpathc) { - if (((pglob->gl_flags & GLOB_NOCHECK) || - ((pglob->gl_flags & GLOB_NOMAGIC) && - !(pglob->gl_flags & GLOB_MAGCHAR)))) - return (globextend(pattern, pglob, limit)); - else - return (GLOB_NOMATCH); - } + if (origpat != NULL) + return (globfinal(pglob, limit, oldpathc, origpat)); + + return (0); +} + +static int +globfinal(glob_t *pglob, struct glob_limit *limit, size_t oldpathc, + const char *origpat) { + if (pglob->gl_pathc == oldpathc) + return (err_nomatch(pglob, limit, origpat)); + if (!(pglob->gl_flags & GLOB_NOSORT)) qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, pglob->gl_pathc - oldpathc, sizeof(char *), compare); + return (0); } static int compare(const void *p, const void *q) { - return (strcmp(*(char **)p, *(char **)q)); + return (strcoll(*(char **)p, *(char **)q)); } static int @@ -593,44 +661,47 @@ glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern, if ((pglob->gl_flags & GLOB_LIMIT) && limit->l_stat_cnt++ >= GLOB_LIMIT_STAT) { - errno = 0; - if (pathend + 1 > pathend_last) - return (GLOB_ABORTED); - *pathend++ = SEP; - *pathend = EOS; + errno = E2BIG; 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) - return (GLOB_ABORTED); + if (pathend + 1 > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } *pathend++ = SEP; *pathend = EOS; } ++pglob->gl_matchc; - return (globextend(pathbuf, pglob, limit)); + return (globextend(pathbuf, pglob, limit, NULL)); } /* 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) - return (GLOB_ABORTED); + if (q + 1 > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } *q++ = *p++; } if (!anymeta) { /* No expansion, do next segment. */ pathend = q; pattern = p; - while (*pattern == SEP) { - if (pathend + 1 > pathend_last) - return (GLOB_ABORTED); + while (UNPROT(*pattern) == SEP) { + if (pathend + 1 > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } *pathend++ = *pattern++; } } else /* Need expansion, recurse. */ @@ -647,42 +718,44 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last, { struct dirent *dp; DIR *dirp; - int err; - char buf[MAXPATHLEN]; + int err, too_long, saverrno, saverrno2; + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; - /* - * The readdirfunc declaration can't be prototyped, because it is - * assigned, below, to two functions which are prototyped in glob.h - * and dirent.h as taking pointers to differently typed opaque - * structures. - */ - struct dirent *(*readdirfunc)(); + struct dirent *(*readdirfunc)(DIR *); - if (pathend > pathend_last) - return (GLOB_ABORTED); + if (pathend > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } *pathend = EOS; - errno = 0; + if (pglob->gl_errfunc != NULL && + g_Ctoc(pathbuf, buf, sizeof(buf))) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + saverrno = errno; + errno = 0; if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { - /* TODO: don't call for ENOENT or ENOTDIR? */ - if (pglob->gl_errfunc) { - if (g_Ctoc(pathbuf, buf, sizeof(buf))) - return (GLOB_ABORTED); - if (pglob->gl_errfunc(buf, errno) || - pglob->gl_flags & GLOB_ERR) - return (GLOB_ABORTED); - } - return (0); + if (errno == ENOENT || errno == ENOTDIR) + return (0); + err = err_aborted(pglob, errno, buf); + if (errno == 0) + errno = saverrno; + return (err); } err = 0; - /* Search directory for matching names. */ + /* pglob->gl_readdir takes a void *, fix this manually */ if (pglob->gl_flags & GLOB_ALTDIRFUNC) - readdirfunc = pglob->gl_readdir; + readdirfunc = (struct dirent *(*)(DIR *))pglob->gl_readdir; else readdirfunc = readdir; - while ((dp = (*readdirfunc)(dirp))) { + + errno = 0; + /* Search directory for matching names. */ + while ((dp = (*readdirfunc)(dirp)) != NULL) { char *sc; Char *dc; wchar_t wc; @@ -691,49 +764,70 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last, if ((pglob->gl_flags & GLOB_LIMIT) && limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) { - errno = 0; - if (pathend + 1 > pathend_last) - err = GLOB_ABORTED; - else { - *pathend++ = SEP; - *pathend = EOS; - err = GLOB_NOSPACE; - } + errno = E2BIG; + err = GLOB_NOSPACE; break; } /* Initial DOT must be matched literally. */ - if (dp->d_name[0] == DOT && *pattern != DOT) + if (dp->d_name[0] == '.' && UNPROT(*pattern) != DOT) { + errno = 0; 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) { - wc = *sc; + /* XXX See initial comment #2. */ + wc = (unsigned char)*sc; 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 && (err = err_aborted(pglob, ENAMETOOLONG, + buf))) { + errno = ENAMETOOLONG; + break; + } + if (too_long || !match(pathend, pattern, restpattern)) { *pathend = EOS; + errno = 0; continue; } + if (errno == 0) + errno = saverrno; err = glob2(pathbuf, --dc, pathend_last, restpattern, pglob, limit); if (err) break; + errno = 0; } + saverrno2 = errno; if (pglob->gl_flags & GLOB_ALTDIRFUNC) (*pglob->gl_closedir)(dirp); else closedir(dirp); - return (err); + errno = saverrno2; + + if (err) + return (err); + + if (dp == NULL && errno != 0 && + (err = err_aborted(pglob, errno, buf))) + return (err); + + if (errno == 0) + errno = saverrno; + return (0); } @@ -752,7 +846,8 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last, * 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, + const char *origpat) { char **pathv; size_t i, newsize, len; @@ -761,7 +856,7 @@ globextend(const Char *path, glob_t *pglob, struct glob_limit *limit) if ((pglob->gl_flags & GLOB_LIMIT) && pglob->gl_matchc > limit->l_path_lim) { - errno = 0; + errno = E2BIG; return (GLOB_NOSPACE); } @@ -779,18 +874,26 @@ globextend(const Char *path, glob_t *pglob, struct glob_limit *limit) } pglob->gl_pathv = pathv; - for (p = path; *p++;) - continue; - len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */ - limit->l_string_cnt += len; - if ((pglob->gl_flags & GLOB_LIMIT) && - limit->l_string_cnt >= GLOB_LIMIT_STRING) { - errno = 0; - return (GLOB_NOSPACE); + if (origpat != NULL) + copy = strdup(origpat); + else { + for (p = path; *p++ != EOS;) + continue; + len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */ + if ((copy = malloc(len)) != NULL) { + if (g_Ctoc(path, copy, len)) { + free(copy); + errno = E2BIG; + return (GLOB_NOSPACE); + } + } } - if ((copy = malloc(len)) != NULL) { - if (g_Ctoc(path, copy, len)) { + if (copy != NULL) { + limit->l_string_cnt += strlen(copy) + 1; + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_string_cnt >= GLOB_LIMIT_STRING) { free(copy); + errno = E2BIG; return (GLOB_NOSPACE); } pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; @@ -830,15 +933,17 @@ match(Char *name, Char *pat, Char *patend) ok = 0; if ((k = *name++) == EOS) return (0); - if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS) + if ((negate_range = ((*pat & M_MASK) == M_NOT)) != 0) ++pat; while (((c = *pat++) & M_MASK) != M_END) if ((*pat & M_MASK) == M_RNG) { if (table->__collate_load_error ? - CHAR(c) <= CHAR(k) && CHAR(k) <= CHAR(pat[1]) : - __wcollate_range_cmp(CHAR(c), CHAR(k)) <= 0 - && __wcollate_range_cmp(CHAR(k), CHAR(pat[1])) <= 0 - ) + CHAR(c) <= CHAR(k) && + CHAR(k) <= CHAR(pat[1]) : + __wcollate_range_cmp(CHAR(c), + CHAR(k)) <= 0 && + __wcollate_range_cmp(CHAR(k), + CHAR(pat[1])) <= 0) ok = 1; pat += 2; } else if (c == k) @@ -875,13 +980,15 @@ globfree(glob_t *pglob) static DIR * g_opendir(Char *str, glob_t *pglob) { - char buf[MAXPATHLEN]; + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; - if (!*str) + if (*str == EOS) strcpy(buf, "."); else { - if (g_Ctoc(str, buf, sizeof(buf))) + if (g_Ctoc(str, buf, sizeof(buf))) { + errno = ENAMETOOLONG; return (NULL); + } } if (pglob->gl_flags & GLOB_ALTDIRFUNC) @@ -893,7 +1000,7 @@ g_opendir(Char *str, glob_t *pglob) static int g_lstat(Char *fn, struct stat *sb, glob_t *pglob) { - char buf[MAXPATHLEN]; + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; if (g_Ctoc(fn, buf, sizeof(buf))) { errno = ENAMETOOLONG; @@ -907,7 +1014,7 @@ g_lstat(Char *fn, struct stat *sb, glob_t *pglob) static int g_stat(Char *fn, struct stat *sb, glob_t *pglob) { - char buf[MAXPATHLEN]; + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; if (g_Ctoc(fn, buf, sizeof(buf))) { errno = ENAMETOOLONG; @@ -937,10 +1044,14 @@ g_Ctoc(const Char *str, char *buf, size_t len) memset(&mbs, 0, sizeof(mbs)); while (len >= MB_CUR_MAX) { - clen = wcrtomb(buf, *str, &mbs); - if (clen == (size_t)-1) - return (1); - if (*str == L'\0') + clen = wcrtomb(buf, CHAR(*str), &mbs); + if (clen == (size_t)-1) { + /* XXX See initial comment #2. */ + *buf = (char)CHAR(*str); + clen = 1; + memset(&mbs, 0, sizeof(mbs)); + } + if (CHAR(*str) == EOS) return (0); str++; buf += clen; @@ -949,21 +1060,46 @@ g_Ctoc(const Char *str, char *buf, size_t len) return (1); } +static int +err_nomatch(glob_t *pglob, struct glob_limit *limit, const char *origpat) { + /* + * If there was no match we are going to append the origpat + * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified + * and the origpat did not contain any magic characters + * GLOB_NOMAGIC is there just for compatibility with csh. + */ + if ((pglob->gl_flags & GLOB_NOCHECK) || + ((pglob->gl_flags & GLOB_NOMAGIC) && + !(pglob->gl_flags & GLOB_MAGCHAR))) + return (globextend(NULL, pglob, limit, origpat)); + return (GLOB_NOMATCH); +} + +static int +err_aborted(glob_t *pglob, int err, char *buf) { + if ((pglob->gl_errfunc != NULL && pglob->gl_errfunc(buf, err)) || + (pglob->gl_flags & GLOB_ERR)) + return (GLOB_ABORTED); + return (0); +} + #ifdef DEBUG static void qprintf(const char *str, Char *s) { Char *p; - (void)printf("%s:\n", str); - for (p = s; *p; p++) - (void)printf("%c", CHAR(*p)); - (void)printf("\n"); - for (p = s; *p; p++) - (void)printf("%c", *p & M_PROTECT ? '"' : ' '); - (void)printf("\n"); - for (p = s; *p; p++) - (void)printf("%c", ismeta(*p) ? '_' : ' '); - (void)printf("\n"); + (void)printf("%s\n", str); + if (s != NULL) { + for (p = s; *p != EOS; p++) + (void)printf("%c", (char)CHAR(*p)); + (void)printf("\n"); + for (p = s; *p != EOS; p++) + (void)printf("%c", (isprot(*p) ? '\\' : ' ')); + (void)printf("\n"); + for (p = s; *p != EOS; p++) + (void)printf("%c", (ismeta(*p) ? '_' : ' ')); + (void)printf("\n"); + } } #endif |