find: fix handling of trailing slashes in -name PATTERN comparisons
No binary (build failed)
—
(log yok)
| @@ -502,26 +502,54 @@ static char *strcpy_upcase(char *dst, const char *src) | |
| ACTF(name) | |
| { | |
| + | int r; |
| const char *tmp = bb_basename(fileName); | |
| - | if (tmp != fileName && *tmp == '\0') { |
| - | /* "foo/bar/". Oh no... go back to 'b' */ |
| - | tmp--; |
| - | while (tmp != fileName && *--tmp != '/') |
| - | continue; |
| - | if (*tmp == '/') |
| - | tmp++; |
| + | /* GNU findutils: find DIR/ -name DIR |
| + | * prints "DIR/" (DIR// prints "DIR//" etc). |
| + | * Need to strip trailing "/". |
| + | * Such names can come only from top-level names, but |
| + | * we can't do this before recursive_action() call, |
| + | * since then "find FILE/ -name FILE" |
| + | * would also work (on non-directories), which is wrong. |
| + | */ |
| + | char *trunc_slash = NULL; |
| + | |
| + | if (*tmp == '\0') { |
| + | /* "foo/bar/[//...]" */ |
| + | while (tmp != fileName && tmp[-1] == '/') |
| + | tmp--; |
| + | if (tmp == fileName) { /* entire fileName is "//.."? */ |
| + | /* yes, convert "//..." to "/" |
| + | * Testcases: |
| + | * find / -maxdepth 1 -name /: prints / |
| + | * find // -maxdepth 1 -name /: prints // |
| + | * find / -maxdepth 1 -name //: prints nothing |
| + | * find // -maxdepth 1 -name //: prints nothing |
| + | */ |
| + | if (tmp[1]) |
| + | trunc_slash = (char*)tmp + 1; |
| + | } else { |
| + | /* no, it's "foo/bar/[//...]", go back to 'b' */ |
| + | trunc_slash = (char*)tmp; |
| + | while (tmp != fileName && tmp[-1] != '/') |
| + | tmp--; |
| + | } |
| } | |
| + | |
| /* Was using FNM_PERIOD flag too, | |
| * but somewhere between 4.1.20 and 4.4.0 GNU find stopped using it. | |
| * find -name '*foo' should match .foo too: | |
| */ | |
| + | if (trunc_slash) *trunc_slash = '\0'; |
| #if FNM_CASEFOLD | |
| - | return fnmatch(ap->pattern, tmp, (ap->iname ? FNM_CASEFOLD : 0)) == 0; |
| + | r = fnmatch(ap->pattern, tmp, (ap->iname ? FNM_CASEFOLD : 0)); |
| #else | |
| if (ap->iname) | |
| tmp = strcpy_upcase(alloca(strlen(tmp) + 1), tmp); | |
| - | return fnmatch(ap->pattern, tmp, 0) == 0; |
| + | r = fnmatch(ap->pattern, tmp, 0); |
| #endif | |
| + | if (trunc_slash) *trunc_slash = '/'; |
| + | return r == 0; |
| } | |
| #if ENABLE_FEATURE_FIND_PATH | |
| @@ -41,6 +41,33 @@ testing "find -exec exitcode 4" \ | |
| "1\n" \ | |
| "" "" | |
| SKIP= | |
| + | optional FEATURE_FIND_MAXDEPTH |
| + | testing "find / -maxdepth 0 -name /" \ |
| + | "find / -maxdepth 0 -name /" \ |
| + | "/\n" \ |
| + | "" "" |
| + | testing "find // -maxdepth 0 -name /" \ |
| + | "find // -maxdepth 0 -name /" \ |
| + | "//\n" \ |
| + | "" "" |
| + | testing "find / -maxdepth 0 -name //" \ |
| + | "find / -maxdepth 0 -name //" \ |
| + | "" \ |
| + | "" "" |
| + | testing "find // -maxdepth 0 -name //" \ |
| + | "find // -maxdepth 0 -name //" \ |
| + | "" \ |
| + | "" "" |
| + | SKIP= |
| + | |
| + | testing "find ./// -name ." \ |
| + | "find ./// -name ." \ |
| + | ".///\n" \ |
| + | "" "" |
| + | testing "find ./// -name .///" \ |
| + | "find ./// -name .///" \ |
| + | "" \ |
| + | "" "" |
| # testing "description" "command" "result" "infile" "stdin" | |