Browse Source

allow escaped path-separator slashes in glob

previously (before and after rewrite), spurious escaping of path
separators as \/ was not treated the same as /, but rather got split
as an unpaired \ at the end of the fnmatch pattern and an unescaped /,
resulting in a mismatch/error.

for the case of \/ as part of the maximal literal prefix, remove the
explicit rejection of it and move the handling of / below escape
processing.

for the case of \/ after a proper glob pattern, it's hard to parse the
pattern, so don't. instead cheat and count repetitions of \ prior to
the already-found / character. if there are an odd number, the last is
escaping the /, so back up the split position by one. now the
char clobbered by null termination is variable, so save it and restore
as needed.
master
Rich Felker 8 years ago
parent
commit
481006fd88
  1. 33
      src/regex/glob.c

33
src/regex/glob.c

@ -53,22 +53,23 @@ static int do_glob(char *buf, size_t pos, int type, char *pat, int flags, int (*
break; break;
} else if (pat[i] == '[') { } else if (pat[i] == '[') {
in_bracket = 1; in_bracket = 1;
} else if (pat[i] == '/') {
if (overflow) return 0;
in_bracket = 0;
pat += i+1;
i = -1;
pos += j+1;
j = -1;
} else if (pat[i] == '\\' && !(flags & GLOB_NOESCAPE)) { } else if (pat[i] == '\\' && !(flags & GLOB_NOESCAPE)) {
/* Backslashes inside a bracket are (at least by /* Backslashes inside a bracket are (at least by
* our interpretation) non-special, so if next * our interpretation) non-special, so if next
* char is ']' we have a complete expression. */ * char is ']' we have a complete expression. */
if (in_bracket && pat[i+1]==']') break; if (in_bracket && pat[i+1]==']') break;
/* Unpaired final backslash never matches. */ /* Unpaired final backslash never matches. */
if (!pat[i+1] || pat[i+1]=='/') return 0; if (!pat[i+1]) return 0;
i++; i++;
} }
if (pat[i] == '/') {
if (overflow) return 0;
in_bracket = 0;
pat += i+1;
i = -1;
pos += j+1;
j = -1;
}
/* Only store a character if it fits in the buffer, but if /* Only store a character if it fits in the buffer, but if
* a potential bracket expression is open, the overflow * a potential bracket expression is open, the overflow
* must be remembered and handled later only if the bracket * must be remembered and handled later only if the bracket
@ -103,7 +104,17 @@ static int do_glob(char *buf, size_t pos, int type, char *pat, int flags, int (*
return GLOB_NOSPACE; return GLOB_NOSPACE;
return 0; return 0;
} }
char *p2 = strchr(pat, '/'); char *p2 = strchr(pat, '/'), saved_sep = '/';
/* Check if the '/' was escaped and, if so, remove the escape char
* so that it will not be unpaired when passed to fnmatch. */
if (p2 && !(flags & GLOB_NOESCAPE)) {
char *p;
for (p=p2; p>pat && p[-1]=='\\'; p--);
if ((p2-p)%2) {
p2--;
saved_sep = '\\';
}
}
DIR *dir = opendir(pos ? buf : "."); DIR *dir = opendir(pos ? buf : ".");
if (!dir) { if (!dir) {
if (errfunc(buf, errno) || (flags & GLOB_ERR)) if (errfunc(buf, errno) || (flags & GLOB_ERR))
@ -136,7 +147,7 @@ static int do_glob(char *buf, size_t pos, int type, char *pat, int flags, int (*
continue; continue;
memcpy(buf+pos, de->d_name, l+1); memcpy(buf+pos, de->d_name, l+1);
if (p2) *p2 = '/'; if (p2) *p2 = saved_sep;
int r = do_glob(buf, pos+l, de->d_type, p2 ? p2 : "", flags, errfunc, tail); int r = do_glob(buf, pos+l, de->d_type, p2 ? p2 : "", flags, errfunc, tail);
if (r) { if (r) {
closedir(dir); closedir(dir);
@ -144,7 +155,7 @@ static int do_glob(char *buf, size_t pos, int type, char *pat, int flags, int (*
} }
} }
int readerr = errno; int readerr = errno;
if (p2) *p2 = '/'; if (p2) *p2 = saved_sep;
closedir(dir); closedir(dir);
if (readerr && (errfunc(buf, errno) || (flags & GLOB_ERR))) if (readerr && (errfunc(buf, errno) || (flags & GLOB_ERR)))
return GLOB_ABORTED; return GLOB_ABORTED;

Loading…
Cancel
Save