ash: fix globbing bugs when using glibc glob()
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
37dc08b874
commit
8e2c9cc2fc
29
shell/ash.c
29
shell/ash.c
@ -7038,27 +7038,42 @@ expandmeta(struct strlist *str /*, int flag*/)
|
|||||||
goto nometa;
|
goto nometa;
|
||||||
INT_OFF;
|
INT_OFF;
|
||||||
p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
|
p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
|
||||||
/*
|
// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
|
||||||
* GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
|
// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
|
||||||
* TODO?: GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
|
//
|
||||||
*/
|
// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
|
||||||
i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
|
// if you pass it "file\?", it returns "file\?", not "file?", if no match.
|
||||||
|
// Which means you need to unescape the string, right? Not so fast:
|
||||||
|
// if there _is_ a file named "file\?" (with backslash), it is returned
|
||||||
|
// as "file\?" too (whichever pattern you used to find it, say, "file*").
|
||||||
|
// You DONT KNOW by looking at the result whether you need to unescape it.
|
||||||
|
//
|
||||||
|
// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
|
||||||
|
// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
|
||||||
|
// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
|
||||||
|
// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
|
||||||
|
// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
|
||||||
|
// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
|
||||||
|
i = glob(p, 0, NULL, &pglob);
|
||||||
|
//bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
|
||||||
if (p != str->text)
|
if (p != str->text)
|
||||||
free(p);
|
free(p);
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0:
|
case 0:
|
||||||
|
#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
|
||||||
/* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
|
/* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
|
||||||
if (!(pglob.gl_flags & GLOB_MAGCHAR))
|
if (!(pglob.gl_flags & GLOB_MAGCHAR))
|
||||||
goto nometa2;
|
goto nometa2;
|
||||||
|
#endif
|
||||||
addglob(&pglob);
|
addglob(&pglob);
|
||||||
globfree(&pglob);
|
globfree(&pglob);
|
||||||
INT_ON;
|
INT_ON;
|
||||||
break;
|
break;
|
||||||
case GLOB_NOMATCH:
|
case GLOB_NOMATCH:
|
||||||
nometa2:
|
//nometa2:
|
||||||
globfree(&pglob);
|
globfree(&pglob);
|
||||||
INT_ON;
|
INT_ON;
|
||||||
nometa:
|
nometa:
|
||||||
*exparg.lastp = str;
|
*exparg.lastp = str;
|
||||||
rmescapes(str->text, 0);
|
rmescapes(str->text, 0);
|
||||||
exparg.lastp = &str->next;
|
exparg.lastp = &str->next;
|
||||||
|
19
shell/ash_test/ash-glob/glob_dir.right
Normal file
19
shell/ash_test/ash-glob/glob_dir.right
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
dirtest/z.tmp
|
||||||
|
dirtest/z.tmp
|
||||||
|
dirtest/z.tmp
|
||||||
|
dirtest/z.tmp
|
||||||
|
dirtest/z.tmp
|
||||||
|
dirtest/z.tmp
|
||||||
|
dirtest/z.tmp
|
||||||
|
dirtest/z.tmp
|
||||||
|
dirtest/z.tmp
|
||||||
|
|
||||||
|
*/z.tmp
|
||||||
|
*/z.*
|
||||||
|
*/?.*
|
||||||
|
*/z*p
|
||||||
|
d*r*e*t/z*p
|
||||||
|
*\/z.tmp
|
||||||
|
*/z.*
|
||||||
|
*/z*p
|
||||||
|
d*r*e*t/z*p
|
25
shell/ash_test/ash-glob/glob_dir.tests
Executable file
25
shell/ash_test/ash-glob/glob_dir.tests
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
mkdir dirtest
|
||||||
|
>dirtest/z.tmp
|
||||||
|
|
||||||
|
echo */z.tmp
|
||||||
|
echo */z.*
|
||||||
|
echo */?.*
|
||||||
|
echo */z*p
|
||||||
|
echo d*r*e*t/z*p
|
||||||
|
echo *"/z.t"mp
|
||||||
|
echo */z"."*
|
||||||
|
echo *"/z"*"p"
|
||||||
|
echo "d"*r*e*t"/"z*p
|
||||||
|
echo
|
||||||
|
echo \*/z.tmp
|
||||||
|
echo "*"/z.*
|
||||||
|
echo */"?".*
|
||||||
|
echo */z"*p"
|
||||||
|
echo d*r*e\*t/z*p
|
||||||
|
echo *"\\/z.t"mp
|
||||||
|
echo */z".*"
|
||||||
|
echo *"/z"\*"p"
|
||||||
|
echo "d*"r*e*t"/"z*p
|
||||||
|
|
||||||
|
rm dirtest/z.tmp
|
||||||
|
rmdir dirtest
|
Loading…
Reference in New Issue
Block a user