diff options
| author | Rich Felker <dalias@aerifal.cx> | 2018-10-13 00:55:48 -0400 | 
|---|---|---|
| committer | Rich Felker <dalias@aerifal.cx> | 2018-10-13 01:28:07 -0400 | 
| commit | 481006fd8887b80c4f794085179047e28102b01a (patch) | |
| tree | 88d0d14996530069c6c4116cb73a9d40b0465ac0 /src/regex/glob.c | |
| parent | d44b07fc904f6a0d31ba025f3e9f423c1e47547e (diff) | |
| download | musl-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/glob.c')
| -rw-r--r-- | src/regex/glob.c | 33 | 
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;  | 
