diff options
author | Denys Vlasenko | 2016-11-25 20:14:33 +0100 |
---|---|---|
committer | Denys Vlasenko | 2016-11-25 20:14:33 +0100 |
commit | ccc9985c455753298a8799a4d12d5f531c67ae81 (patch) | |
tree | 78d6082132ec226ba81ccb797c6defe927d67b42 | |
parent | 4b89d512b1215e7b9d619af03496540d30cbbd1a (diff) | |
download | busybox-ccc9985c455753298a8799a4d12d5f531c67ae81.zip busybox-ccc9985c455753298a8799a4d12d5f531c67ae81.tar.gz |
find: fix handling of trailing slashes in -name PATTERN comparisons
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | findutils/find.c | 46 | ||||
-rwxr-xr-x | testsuite/find.tests | 27 |
2 files changed, 64 insertions, 9 deletions
diff --git a/findutils/find.c b/findutils/find.c index d71c697..27698e5 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 78dfa12..138236c 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" |