aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2016-10-02 15:17:15 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2016-10-02 15:17:15 +0200
commit8e2c9cc2fcfe23625e1c5845f99dfc93e022fc9b (patch)
treecc2a99f8b7840b57adcf0998d7e3916a337644dc /shell
parent37dc08b874d6a24bd5e4b6aff62577ecc1364275 (diff)
downloadbusybox-w32-8e2c9cc2fcfe23625e1c5845f99dfc93e022fc9b.tar.gz
busybox-w32-8e2c9cc2fcfe23625e1c5845f99dfc93e022fc9b.tar.bz2
busybox-w32-8e2c9cc2fcfe23625e1c5845f99dfc93e022fc9b.zip
ash: fix globbing bugs when using glibc glob()
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell')
-rw-r--r--shell/ash.c29
-rw-r--r--shell/ash_test/ash-glob/glob_dir.right19
-rwxr-xr-xshell/ash_test/ash-glob/glob_dir.tests25
3 files changed, 66 insertions, 7 deletions
diff --git a/shell/ash.c b/shell/ash.c
index f8c3e0c19..40b3ef3e3 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -7038,27 +7038,42 @@ expandmeta(struct strlist *str /*, int flag*/)
7038 goto nometa; 7038 goto nometa;
7039 INT_OFF; 7039 INT_OFF;
7040 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); 7040 p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP);
7041 /* 7041// GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match
7042 * GLOB_NOMAGIC (GNU): if no *?[ chars in pattern, return it even if no match 7042// GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?)
7043 * TODO?: GLOB_NOCHECK: if no match, return unchanged pattern (sans \* escapes?) 7043//
7044 */ 7044// glibc 2.24.90 glob(GLOB_NOMAGIC) does not remove backslashes used for escaping:
7045 i = glob(p, GLOB_NOMAGIC, NULL, &pglob); 7045// if you pass it "file\?", it returns "file\?", not "file?", if no match.
7046// Which means you need to unescape the string, right? Not so fast:
7047// if there _is_ a file named "file\?" (with backslash), it is returned
7048// as "file\?" too (whichever pattern you used to find it, say, "file*").
7049// You DONT KNOW by looking at the result whether you need to unescape it.
7050//
7051// Worse, globbing of "file\?" in a directory with two files, "file?" and "file\?",
7052// returns "file\?" - which is WRONG: "file\?" pattern matches "file?" file.
7053// Without GLOB_NOMAGIC, this works correctly ("file?" is returned as a match).
7054// With GLOB_NOMAGIC | GLOB_NOCHECK, this also works correctly.
7055// i = glob(p, GLOB_NOMAGIC | GLOB_NOCHECK, NULL, &pglob);
7056// i = glob(p, GLOB_NOMAGIC, NULL, &pglob);
7057 i = glob(p, 0, NULL, &pglob);
7058 //bb_error_msg("glob('%s'):%d '%s'...", p, i, pglob.gl_pathv ? pglob.gl_pathv[0] : "-");
7046 if (p != str->text) 7059 if (p != str->text)
7047 free(p); 7060 free(p);
7048 switch (i) { 7061 switch (i) {
7049 case 0: 7062 case 0:
7063#if 0 // glibc 2.24.90 bug? Patterns like "*/file", when match, don't set GLOB_MAGCHAR
7050 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */ 7064 /* GLOB_MAGCHAR is set if *?[ chars were seen (GNU) */
7051 if (!(pglob.gl_flags & GLOB_MAGCHAR)) 7065 if (!(pglob.gl_flags & GLOB_MAGCHAR))
7052 goto nometa2; 7066 goto nometa2;
7067#endif
7053 addglob(&pglob); 7068 addglob(&pglob);
7054 globfree(&pglob); 7069 globfree(&pglob);
7055 INT_ON; 7070 INT_ON;
7056 break; 7071 break;
7057 case GLOB_NOMATCH: 7072 case GLOB_NOMATCH:
7058nometa2: 7073 //nometa2:
7059 globfree(&pglob); 7074 globfree(&pglob);
7060 INT_ON; 7075 INT_ON;
7061nometa: 7076 nometa:
7062 *exparg.lastp = str; 7077 *exparg.lastp = str;
7063 rmescapes(str->text, 0); 7078 rmescapes(str->text, 0);
7064 exparg.lastp = &str->next; 7079 exparg.lastp = &str->next;
diff --git a/shell/ash_test/ash-glob/glob_dir.right b/shell/ash_test/ash-glob/glob_dir.right
new file mode 100644
index 000000000..aa90514d5
--- /dev/null
+++ b/shell/ash_test/ash-glob/glob_dir.right
@@ -0,0 +1,19 @@
1dirtest/z.tmp
2dirtest/z.tmp
3dirtest/z.tmp
4dirtest/z.tmp
5dirtest/z.tmp
6dirtest/z.tmp
7dirtest/z.tmp
8dirtest/z.tmp
9dirtest/z.tmp
10
11*/z.tmp
12*/z.*
13*/?.*
14*/z*p
15d*r*e*t/z*p
16*\/z.tmp
17*/z.*
18*/z*p
19d*r*e*t/z*p
diff --git a/shell/ash_test/ash-glob/glob_dir.tests b/shell/ash_test/ash-glob/glob_dir.tests
new file mode 100755
index 000000000..dc4c4fdb5
--- /dev/null
+++ b/shell/ash_test/ash-glob/glob_dir.tests
@@ -0,0 +1,25 @@
1mkdir dirtest
2 >dirtest/z.tmp
3
4echo */z.tmp
5echo */z.*
6echo */?.*
7echo */z*p
8echo d*r*e*t/z*p
9echo *"/z.t"mp
10echo */z"."*
11echo *"/z"*"p"
12echo "d"*r*e*t"/"z*p
13echo
14echo \*/z.tmp
15echo "*"/z.*
16echo */"?".*
17echo */z"*p"
18echo d*r*e\*t/z*p
19echo *"\\/z.t"mp
20echo */z".*"
21echo *"/z"\*"p"
22echo "d*"r*e*t"/"z*p
23
24rm dirtest/z.tmp
25rmdir dirtest