find: fix handling of trailing slashes in -name PATTERN comparisons
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		| @@ -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" | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user