diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2016-11-25 20:14:33 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2016-11-25 20:14:33 +0100 |
commit | ccc9985c455753298a8799a4d12d5f531c67ae81 (patch) | |
tree | 78d6082132ec226ba81ccb797c6defe927d67b42 /findutils | |
parent | 4b89d512b1215e7b9d619af03496540d30cbbd1a (diff) | |
download | busybox-w32-ccc9985c455753298a8799a4d12d5f531c67ae81.tar.gz busybox-w32-ccc9985c455753298a8799a4d12d5f531c67ae81.tar.bz2 busybox-w32-ccc9985c455753298a8799a4d12d5f531c67ae81.zip |
find: fix handling of trailing slashes in -name PATTERN comparisons
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'findutils')
-rw-r--r-- | findutils/find.c | 46 |
1 files changed, 37 insertions, 9 deletions
diff --git a/findutils/find.c b/findutils/find.c index d71c69782..27698e537 100644 --- a/findutils/find.c +++ b/findutils/find.c | |||
@@ -502,26 +502,54 @@ static char *strcpy_upcase(char *dst, const char *src) | |||
502 | 502 | ||
503 | ACTF(name) | 503 | ACTF(name) |
504 | { | 504 | { |
505 | int r; | ||
505 | const char *tmp = bb_basename(fileName); | 506 | const char *tmp = bb_basename(fileName); |
506 | if (tmp != fileName && *tmp == '\0') { | 507 | /* GNU findutils: find DIR/ -name DIR |
507 | /* "foo/bar/". Oh no... go back to 'b' */ | 508 | * prints "DIR/" (DIR// prints "DIR//" etc). |
508 | tmp--; | 509 | * Need to strip trailing "/". |
509 | while (tmp != fileName && *--tmp != '/') | 510 | * Such names can come only from top-level names, but |
510 | continue; | 511 | * we can't do this before recursive_action() call, |
511 | if (*tmp == '/') | 512 | * since then "find FILE/ -name FILE" |
512 | tmp++; | 513 | * would also work (on non-directories), which is wrong. |
514 | */ | ||
515 | char *trunc_slash = NULL; | ||
516 | |||
517 | if (*tmp == '\0') { | ||
518 | /* "foo/bar/[//...]" */ | ||
519 | while (tmp != fileName && tmp[-1] == '/') | ||
520 | tmp--; | ||
521 | if (tmp == fileName) { /* entire fileName is "//.."? */ | ||
522 | /* yes, convert "//..." to "/" | ||
523 | * Testcases: | ||
524 | * find / -maxdepth 1 -name /: prints / | ||
525 | * find // -maxdepth 1 -name /: prints // | ||
526 | * find / -maxdepth 1 -name //: prints nothing | ||
527 | * find // -maxdepth 1 -name //: prints nothing | ||
528 | */ | ||
529 | if (tmp[1]) | ||
530 | trunc_slash = (char*)tmp + 1; | ||
531 | } else { | ||
532 | /* no, it's "foo/bar/[//...]", go back to 'b' */ | ||
533 | trunc_slash = (char*)tmp; | ||
534 | while (tmp != fileName && tmp[-1] != '/') | ||
535 | tmp--; | ||
536 | } | ||
513 | } | 537 | } |
538 | |||
514 | /* Was using FNM_PERIOD flag too, | 539 | /* Was using FNM_PERIOD flag too, |
515 | * but somewhere between 4.1.20 and 4.4.0 GNU find stopped using it. | 540 | * but somewhere between 4.1.20 and 4.4.0 GNU find stopped using it. |
516 | * find -name '*foo' should match .foo too: | 541 | * find -name '*foo' should match .foo too: |
517 | */ | 542 | */ |
543 | if (trunc_slash) *trunc_slash = '\0'; | ||
518 | #if FNM_CASEFOLD | 544 | #if FNM_CASEFOLD |
519 | return fnmatch(ap->pattern, tmp, (ap->iname ? FNM_CASEFOLD : 0)) == 0; | 545 | r = fnmatch(ap->pattern, tmp, (ap->iname ? FNM_CASEFOLD : 0)); |
520 | #else | 546 | #else |
521 | if (ap->iname) | 547 | if (ap->iname) |
522 | tmp = strcpy_upcase(alloca(strlen(tmp) + 1), tmp); | 548 | tmp = strcpy_upcase(alloca(strlen(tmp) + 1), tmp); |
523 | return fnmatch(ap->pattern, tmp, 0) == 0; | 549 | r = fnmatch(ap->pattern, tmp, 0); |
524 | #endif | 550 | #endif |
551 | if (trunc_slash) *trunc_slash = '/'; | ||
552 | return r == 0; | ||
525 | } | 553 | } |
526 | 554 | ||
527 | #if ENABLE_FEATURE_FIND_PATH | 555 | #if ENABLE_FEATURE_FIND_PATH |