summaryrefslogtreecommitdiffstats
path: root/lib/libc/gen/glob.c
diff options
context:
space:
mode:
authorRenato Botelho <renato@netgate.com>2016-08-17 15:23:38 -0300
committerRenato Botelho <renato@netgate.com>2016-08-17 15:23:38 -0300
commit75cd8d40056c799f03b759475d9bfd10ba266a6c (patch)
tree60433235501684bffeab90e65139a8285fcf46a9 /lib/libc/gen/glob.c
parent99990a0d149f0eae805aa1f49d4a61be30c3b000 (diff)
parentad413762f28e3be343987e707b9cf4f10f963693 (diff)
downloadFreeBSD-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.c528
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
OpenPOWER on IntegriCloud