summaryrefslogtreecommitdiff
path: root/src/regex
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2018-10-13 00:55:48 -0400
committerRich Felker <dalias@aerifal.cx>2018-10-13 01:28:07 -0400
commit481006fd8887b80c4f794085179047e28102b01a (patch)
tree88d0d14996530069c6c4116cb73a9d40b0465ac0 /src/regex
parentd44b07fc904f6a0d31ba025f3e9f423c1e47547e (diff)
downloadmusl-481006fd8887b80c4f794085179047e28102b01a.tar.gz
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.
Diffstat (limited to 'src/regex')
-rw-r--r--src/regex/glob.c33
1 files changed, 22 insertions, 11 deletions
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;