From: Denys Vlasenko Date: Fri, 25 Nov 2016 19:14:33 +0000 (+0100) Subject: find: fix handling of trailing slashes in -name PATTERN comparisons X-Git-Tag: 1_26_0~29 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=ccc9985c455753298a8799a4d12d5f531c67ae81;p=oweals%2Fbusybox.git find: fix handling of trailing slashes in -name PATTERN comparisons Signed-off-by: Denys Vlasenko --- diff --git a/findutils/find.c b/findutils/find.c index d71c69782..27698e537 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -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 diff --git a/testsuite/find.tests b/testsuite/find.tests index 78dfa1230..138236c81 100755 --- a/testsuite/find.tests +++ b/testsuite/find.tests @@ -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"