From 481006fd8887b80c4f794085179047e28102b01a Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Sat, 13 Oct 2018 00:55:48 -0400 Subject: 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. --- src/regex/glob.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) (limited to 'src/regex') diff --git a/src/regex/glob.c b/src/regex/glob.c index 751b6966..aa1c6a44 100644 --- a/src/regex/glob.c +++ b/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; } else if (pat[i] == '[') { 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)) { /* Backslashes inside a bracket are (at least by * our interpretation) non-special, so if next * char is ']' we have a complete expression. */ if (in_bracket && pat[i+1]==']') break; /* Unpaired final backslash never matches. */ - if (!pat[i+1] || pat[i+1]=='/') return 0; + if (!pat[i+1]) return 0; 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 * a potential bracket expression is open, the overflow * 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 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 : "."); if (!dir) { 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; 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); if (r) { 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; - if (p2) *p2 = '/'; + if (p2) *p2 = saved_sep; closedir(dir); if (readerr && (errfunc(buf, errno) || (flags & GLOB_ERR))) return GLOB_ABORTED; -- cgit v1.2.1