summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko2016-11-25 20:14:33 +0100
committerDenys Vlasenko2016-11-25 20:14:33 +0100
commitccc9985c455753298a8799a4d12d5f531c67ae81 (patch)
tree78d6082132ec226ba81ccb797c6defe927d67b42
parent4b89d512b1215e7b9d619af03496540d30cbbd1a (diff)
downloadbusybox-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.c46
-rwxr-xr-xtestsuite/find.tests27
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"