diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-02 15:17:15 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-10-02 15:17:15 +0200 |
| commit | 8e2c9cc2fcfe23625e1c5845f99dfc93e022fc9b (patch) | |
| tree | cc2a99f8b7840b57adcf0998d7e3916a337644dc /shell | |
| parent | 37dc08b874d6a24bd5e4b6aff62577ecc1364275 (diff) | |
| download | busybox-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.c | 29 | ||||
| -rw-r--r-- | shell/ash_test/ash-glob/glob_dir.right | 19 | ||||
| -rwxr-xr-x | shell/ash_test/ash-glob/glob_dir.tests | 25 |
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: |
| 7058 | nometa2: | 7073 | //nometa2: |
| 7059 | globfree(&pglob); | 7074 | globfree(&pglob); |
| 7060 | INT_ON; | 7075 | INT_ON; |
| 7061 | nometa: | 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 @@ | |||
| 1 | dirtest/z.tmp | ||
| 2 | dirtest/z.tmp | ||
| 3 | dirtest/z.tmp | ||
| 4 | dirtest/z.tmp | ||
| 5 | dirtest/z.tmp | ||
| 6 | dirtest/z.tmp | ||
| 7 | dirtest/z.tmp | ||
| 8 | dirtest/z.tmp | ||
| 9 | dirtest/z.tmp | ||
| 10 | |||
| 11 | */z.tmp | ||
| 12 | */z.* | ||
| 13 | */?.* | ||
| 14 | */z*p | ||
| 15 | d*r*e*t/z*p | ||
| 16 | *\/z.tmp | ||
| 17 | */z.* | ||
| 18 | */z*p | ||
| 19 | d*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 @@ | |||
| 1 | mkdir dirtest | ||
| 2 | >dirtest/z.tmp | ||
| 3 | |||
| 4 | echo */z.tmp | ||
| 5 | echo */z.* | ||
| 6 | echo */?.* | ||
| 7 | echo */z*p | ||
| 8 | echo d*r*e*t/z*p | ||
| 9 | echo *"/z.t"mp | ||
| 10 | echo */z"."* | ||
| 11 | echo *"/z"*"p" | ||
| 12 | echo "d"*r*e*t"/"z*p | ||
| 13 | echo | ||
| 14 | echo \*/z.tmp | ||
| 15 | echo "*"/z.* | ||
| 16 | echo */"?".* | ||
| 17 | echo */z"*p" | ||
| 18 | echo d*r*e\*t/z*p | ||
| 19 | echo *"\\/z.t"mp | ||
| 20 | echo */z".*" | ||
| 21 | echo *"/z"\*"p" | ||
| 22 | echo "d*"r*e*t"/"z*p | ||
| 23 | |||
| 24 | rm dirtest/z.tmp | ||
| 25 | rmdir dirtest | ||
