find: fix handling of trailing slashes in -name PATTERN comparisons
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
4b89d512b1
commit
ccc9985c45
@ -502,26 +502,54 @@ static char *strcpy_upcase(char *dst, const char *src)
|
|||||||
|
|
||||||
ACTF(name)
|
ACTF(name)
|
||||||
{
|
{
|
||||||
|
int r;
|
||||||
const char *tmp = bb_basename(fileName);
|
const char *tmp = bb_basename(fileName);
|
||||||
if (tmp != fileName && *tmp == '\0') {
|
/* GNU findutils: find DIR/ -name DIR
|
||||||
/* "foo/bar/". Oh no... go back to 'b' */
|
* prints "DIR/" (DIR// prints "DIR//" etc).
|
||||||
tmp--;
|
* Need to strip trailing "/".
|
||||||
while (tmp != fileName && *--tmp != '/')
|
* Such names can come only from top-level names, but
|
||||||
continue;
|
* we can't do this before recursive_action() call,
|
||||||
if (*tmp == '/')
|
* since then "find FILE/ -name FILE"
|
||||||
tmp++;
|
* 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,
|
/* Was using FNM_PERIOD flag too,
|
||||||
* but somewhere between 4.1.20 and 4.4.0 GNU find stopped using it.
|
* but somewhere between 4.1.20 and 4.4.0 GNU find stopped using it.
|
||||||
* find -name '*foo' should match .foo too:
|
* find -name '*foo' should match .foo too:
|
||||||
*/
|
*/
|
||||||
|
if (trunc_slash) *trunc_slash = '\0';
|
||||||
#if FNM_CASEFOLD
|
#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
|
#else
|
||||||
if (ap->iname)
|
if (ap->iname)
|
||||||
tmp = strcpy_upcase(alloca(strlen(tmp) + 1), tmp);
|
tmp = strcpy_upcase(alloca(strlen(tmp) + 1), tmp);
|
||||||
return fnmatch(ap->pattern, tmp, 0) == 0;
|
r = fnmatch(ap->pattern, tmp, 0);
|
||||||
#endif
|
#endif
|
||||||
|
if (trunc_slash) *trunc_slash = '/';
|
||||||
|
return r == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ENABLE_FEATURE_FIND_PATH
|
#if ENABLE_FEATURE_FIND_PATH
|
||||||
|
@ -41,6 +41,33 @@ testing "find -exec exitcode 4" \
|
|||||||
"1\n" \
|
"1\n" \
|
||||||
"" ""
|
"" ""
|
||||||
SKIP=
|
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"
|
# testing "description" "command" "result" "infile" "stdin"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user