[git commit] find: fix handling of trailing slashes in -name PATTERN comparisons

Denys Vlasenko vda.linux at googlemail.com
Fri Nov 25 19:14:33 UTC 2016


commit: https://git.busybox.net/busybox/commit/?id=ccc9985c455753298a8799a4d12d5f531c67ae81
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 findutils/find.c     | 46 +++++++++++++++++++++++++++++++++++++---------
 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"
 


More information about the busybox-cvs mailing list