diff options
| author | Denys Vlasenko <vda.linux@googlemail.com> | 2009-09-29 11:07:04 +0200 |
|---|---|---|
| committer | Denys Vlasenko <vda.linux@googlemail.com> | 2009-09-29 11:07:04 +0200 |
| commit | 8f7a6d294fd0940e531bb8fef197b1b74fe2a842 (patch) | |
| tree | 50e60d97d4d5922db6924fa8b423807a9559a06b | |
| parent | 2f3f09c287f43dcad50b740793c2b467f166c058 (diff) | |
| download | busybox-w32-8f7a6d294fd0940e531bb8fef197b1b74fe2a842.tar.gz busybox-w32-8f7a6d294fd0940e531bb8fef197b1b74fe2a842.tar.bz2 busybox-w32-8f7a6d294fd0940e531bb8fef197b1b74fe2a842.zip | |
find: -follow should not error out on dandling links
function old new delta
recursive_action 425 465 +40
find_main 436 465 +29
test_main 247 253 +6
need_print 1 - -1
doCommands 2523 2521 -2
compare_keys 737 735 -2
xdev_dev 4 - -4
xdev_count 4 - -4
recurse_flags 4 - -4
mkfs_vfat_main 1609 1605 -4
actions 4 - -4
fileAction 588 583 -5
------------------------------------------------------------------------------
(add/remove: 0/5 grow/shrink: 3/4 up/down: 75/-30) Total: 45 bytes
text data bss dec hex filename
822711 450 7684 830845 cad7d busybox_old
822773 445 7668 830886 cada6 busybox_unstripped
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
| -rw-r--r-- | findutils/find.c | 79 | ||||
| -rw-r--r-- | include/libbb.h | 2 | ||||
| -rw-r--r-- | libbb/recursive_action.c | 19 |
3 files changed, 61 insertions, 39 deletions
diff --git a/findutils/find.c b/findutils/find.c index bd92e2281..6f7be4fc2 100644 --- a/findutils/find.c +++ b/findutils/find.c | |||
| @@ -62,9 +62,6 @@ | |||
| 62 | /* This is a NOEXEC applet. Be very careful! */ | 62 | /* This is a NOEXEC applet. Be very careful! */ |
| 63 | 63 | ||
| 64 | 64 | ||
| 65 | IF_FEATURE_FIND_XDEV(static dev_t *xdev_dev;) | ||
| 66 | IF_FEATURE_FIND_XDEV(static int xdev_count;) | ||
| 67 | |||
| 68 | typedef int (*action_fp)(const char *fileName, const struct stat *statbuf, void *) FAST_FUNC; | 65 | typedef int (*action_fp)(const char *fileName, const struct stat *statbuf, void *) FAST_FUNC; |
| 69 | 66 | ||
| 70 | typedef struct { | 67 | typedef struct { |
| @@ -100,9 +97,21 @@ IF_FEATURE_FIND_DELETE( ACTS(delete)) | |||
| 100 | IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;)) | 97 | IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;)) |
| 101 | IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;)) | 98 | IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;)) |
| 102 | 99 | ||
| 103 | static action ***actions; | 100 | struct globals { |
| 104 | static bool need_print = 1; | 101 | IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;) |
| 105 | static int recurse_flags = ACTION_RECURSE; | 102 | IF_FEATURE_FIND_XDEV(int xdev_count;) |
| 103 | action ***actions; | ||
| 104 | bool need_print; | ||
| 105 | recurse_flags_t recurse_flags; | ||
| 106 | }; | ||
| 107 | #define G (*(struct globals*)&bb_common_bufsiz1) | ||
| 108 | #define INIT_G() do { \ | ||
| 109 | struct G_sizecheck { \ | ||
| 110 | char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \ | ||
| 111 | }; \ | ||
| 112 | G.need_print = 1; \ | ||
| 113 | G.recurse_flags = ACTION_RECURSE; \ | ||
| 114 | } while (0) | ||
| 106 | 115 | ||
| 107 | #if ENABLE_FEATURE_FIND_EXEC | 116 | #if ENABLE_FEATURE_FIND_EXEC |
| 108 | static unsigned count_subst(const char *str) | 117 | static unsigned count_subst(const char *str) |
| @@ -367,7 +376,7 @@ ACTF(context) | |||
| 367 | security_context_t con; | 376 | security_context_t con; |
| 368 | int rc; | 377 | int rc; |
| 369 | 378 | ||
| 370 | if (recurse_flags & ACTION_FOLLOWLINKS) { | 379 | if (G.recurse_flags & ACTION_FOLLOWLINKS) { |
| 371 | rc = getfilecon(fileName, &con); | 380 | rc = getfilecon(fileName, &con); |
| 372 | } else { | 381 | } else { |
| 373 | rc = lgetfilecon(fileName, &con); | 382 | rc = lgetfilecon(fileName, &con); |
| @@ -396,9 +405,9 @@ static int FAST_FUNC fileAction(const char *fileName, | |||
| 396 | 405 | ||
| 397 | #if ENABLE_FEATURE_FIND_XDEV | 406 | #if ENABLE_FEATURE_FIND_XDEV |
| 398 | if (S_ISDIR(statbuf->st_mode)) { | 407 | if (S_ISDIR(statbuf->st_mode)) { |
| 399 | if (xdev_count) { | 408 | if (G.xdev_count) { |
| 400 | for (i = 0; i < xdev_count; i++) { | 409 | for (i = 0; i < G.xdev_count; i++) { |
| 401 | if (xdev_dev[i] == statbuf->st_dev) | 410 | if (G.xdev_dev[i] == statbuf->st_dev) |
| 402 | goto found; | 411 | goto found; |
| 403 | } | 412 | } |
| 404 | return SKIP; | 413 | return SKIP; |
| @@ -406,9 +415,9 @@ static int FAST_FUNC fileAction(const char *fileName, | |||
| 406 | } | 415 | } |
| 407 | } | 416 | } |
| 408 | #endif | 417 | #endif |
| 409 | i = exec_actions(actions, fileName, statbuf); | 418 | i = exec_actions(G.actions, fileName, statbuf); |
| 410 | /* Had no explicit -print[0] or -exec? then print */ | 419 | /* Had no explicit -print[0] or -exec? then print */ |
| 411 | if ((i & TRUE) && need_print) | 420 | if ((i & TRUE) && G.need_print) |
| 412 | puts(fileName); | 421 | puts(fileName); |
| 413 | 422 | ||
| 414 | #if ENABLE_FEATURE_FIND_MAXDEPTH | 423 | #if ENABLE_FEATURE_FIND_MAXDEPTH |
| @@ -443,7 +452,7 @@ static int find_type(const char *type) | |||
| 443 | else if (*type == 's') | 452 | else if (*type == 's') |
| 444 | mask = S_IFSOCK; | 453 | mask = S_IFSOCK; |
| 445 | 454 | ||
| 446 | if (mask == 0 || *(type + 1) != '\0') | 455 | if (mask == 0 || type[1] != '\0') |
| 447 | bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type"); | 456 | bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type"); |
| 448 | 457 | ||
| 449 | return mask; | 458 | return mask; |
| @@ -464,15 +473,15 @@ static const char* plus_minus_num(const char* str) | |||
| 464 | static action*** parse_params(char **argv) | 473 | static action*** parse_params(char **argv) |
| 465 | { | 474 | { |
| 466 | enum { | 475 | enum { |
| 467 | PARM_a , | 476 | PARM_a , |
| 468 | PARM_o , | 477 | PARM_o , |
| 469 | IF_FEATURE_FIND_NOT( PARM_char_not ,) | 478 | IF_FEATURE_FIND_NOT( PARM_char_not ,) |
| 470 | #if ENABLE_DESKTOP | 479 | #if ENABLE_DESKTOP |
| 471 | PARM_and , | 480 | PARM_and , |
| 472 | PARM_or , | 481 | PARM_or , |
| 473 | IF_FEATURE_FIND_NOT( PARM_not ,) | 482 | IF_FEATURE_FIND_NOT( PARM_not ,) |
| 474 | #endif | 483 | #endif |
| 475 | PARM_print , | 484 | PARM_print , |
| 476 | IF_FEATURE_FIND_PRINT0( PARM_print0 ,) | 485 | IF_FEATURE_FIND_PRINT0( PARM_print0 ,) |
| 477 | IF_FEATURE_FIND_DEPTH( PARM_depth ,) | 486 | IF_FEATURE_FIND_DEPTH( PARM_depth ,) |
| 478 | IF_FEATURE_FIND_PRUNE( PARM_prune ,) | 487 | IF_FEATURE_FIND_PRUNE( PARM_prune ,) |
| @@ -480,8 +489,8 @@ static action*** parse_params(char **argv) | |||
| 480 | IF_FEATURE_FIND_EXEC( PARM_exec ,) | 489 | IF_FEATURE_FIND_EXEC( PARM_exec ,) |
| 481 | IF_FEATURE_FIND_PAREN( PARM_char_brace,) | 490 | IF_FEATURE_FIND_PAREN( PARM_char_brace,) |
| 482 | /* All options starting from here require argument */ | 491 | /* All options starting from here require argument */ |
| 483 | PARM_name , | 492 | PARM_name , |
| 484 | PARM_iname , | 493 | PARM_iname , |
| 485 | IF_FEATURE_FIND_PATH( PARM_path ,) | 494 | IF_FEATURE_FIND_PATH( PARM_path ,) |
| 486 | IF_FEATURE_FIND_REGEX( PARM_regex ,) | 495 | IF_FEATURE_FIND_REGEX( PARM_regex ,) |
| 487 | IF_FEATURE_FIND_TYPE( PARM_type ,) | 496 | IF_FEATURE_FIND_TYPE( PARM_type ,) |
| @@ -604,21 +613,21 @@ static action*** parse_params(char **argv) | |||
| 604 | 613 | ||
| 605 | /* --- Tests and actions --- */ | 614 | /* --- Tests and actions --- */ |
| 606 | else if (parm == PARM_print) { | 615 | else if (parm == PARM_print) { |
| 607 | need_print = 0; | 616 | G.need_print = 0; |
| 608 | /* GNU find ignores '!' here: "find ! -print" */ | 617 | /* GNU find ignores '!' here: "find ! -print" */ |
| 609 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) | 618 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) |
| 610 | (void) ALLOC_ACTION(print); | 619 | (void) ALLOC_ACTION(print); |
| 611 | } | 620 | } |
| 612 | #if ENABLE_FEATURE_FIND_PRINT0 | 621 | #if ENABLE_FEATURE_FIND_PRINT0 |
| 613 | else if (parm == PARM_print0) { | 622 | else if (parm == PARM_print0) { |
| 614 | need_print = 0; | 623 | G.need_print = 0; |
| 615 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) | 624 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) |
| 616 | (void) ALLOC_ACTION(print0); | 625 | (void) ALLOC_ACTION(print0); |
| 617 | } | 626 | } |
| 618 | #endif | 627 | #endif |
| 619 | #if ENABLE_FEATURE_FIND_DEPTH | 628 | #if ENABLE_FEATURE_FIND_DEPTH |
| 620 | else if (parm == PARM_depth) { | 629 | else if (parm == PARM_depth) { |
| 621 | recurse_flags |= ACTION_DEPTHFIRST; | 630 | G.recurse_flags |= ACTION_DEPTHFIRST; |
| 622 | } | 631 | } |
| 623 | #endif | 632 | #endif |
| 624 | #if ENABLE_FEATURE_FIND_PRUNE | 633 | #if ENABLE_FEATURE_FIND_PRUNE |
| @@ -629,8 +638,8 @@ static action*** parse_params(char **argv) | |||
| 629 | #endif | 638 | #endif |
| 630 | #if ENABLE_FEATURE_FIND_DELETE | 639 | #if ENABLE_FEATURE_FIND_DELETE |
| 631 | else if (parm == PARM_delete) { | 640 | else if (parm == PARM_delete) { |
| 632 | need_print = 0; | 641 | G.need_print = 0; |
| 633 | recurse_flags |= ACTION_DEPTHFIRST; | 642 | G.recurse_flags |= ACTION_DEPTHFIRST; |
| 634 | (void) ALLOC_ACTION(delete); | 643 | (void) ALLOC_ACTION(delete); |
| 635 | } | 644 | } |
| 636 | #endif | 645 | #endif |
| @@ -638,7 +647,7 @@ static action*** parse_params(char **argv) | |||
| 638 | else if (parm == PARM_exec) { | 647 | else if (parm == PARM_exec) { |
| 639 | int i; | 648 | int i; |
| 640 | action_exec *ap; | 649 | action_exec *ap; |
| 641 | need_print = 0; | 650 | G.need_print = 0; |
| 642 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) | 651 | IF_FEATURE_FIND_NOT( invert_flag = 0; ) |
| 643 | ap = ALLOC_ACTION(exec); | 652 | ap = ALLOC_ACTION(exec); |
| 644 | ap->exec_argv = ++argv; /* first arg after -exec */ | 653 | ap->exec_argv = ++argv; /* first arg after -exec */ |
| @@ -846,6 +855,8 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) | |||
| 846 | #define minmaxdepth NULL | 855 | #define minmaxdepth NULL |
| 847 | #endif | 856 | #endif |
| 848 | 857 | ||
| 858 | INIT_G(); | ||
| 859 | |||
| 849 | for (firstopt = 1; firstopt < argc; firstopt++) { | 860 | for (firstopt = 1; firstopt < argc; firstopt++) { |
| 850 | if (argv[firstopt][0] == '-') | 861 | if (argv[firstopt][0] == '-') |
| 851 | break; | 862 | break; |
| @@ -873,21 +884,21 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) | |||
| 873 | while ((arg = argp[0])) { | 884 | while ((arg = argp[0])) { |
| 874 | int opt = index_in_strings(options, arg); | 885 | int opt = index_in_strings(options, arg); |
| 875 | if (opt == OPT_FOLLOW) { | 886 | if (opt == OPT_FOLLOW) { |
| 876 | recurse_flags |= ACTION_FOLLOWLINKS; | 887 | G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK; |
| 877 | argp[0] = (char*)"-a"; | 888 | argp[0] = (char*)"-a"; |
| 878 | } | 889 | } |
| 879 | #if ENABLE_FEATURE_FIND_XDEV | 890 | #if ENABLE_FEATURE_FIND_XDEV |
| 880 | if (opt == OPT_XDEV) { | 891 | if (opt == OPT_XDEV) { |
| 881 | struct stat stbuf; | 892 | struct stat stbuf; |
| 882 | if (!xdev_count) { | 893 | if (!G.xdev_count) { |
| 883 | xdev_count = firstopt - 1; | 894 | G.xdev_count = firstopt - 1; |
| 884 | xdev_dev = xmalloc(xdev_count * sizeof(dev_t)); | 895 | G.xdev_dev = xmalloc(G.xdev_count * sizeof(dev_t)); |
| 885 | for (i = 1; i < firstopt; i++) { | 896 | for (i = 1; i < firstopt; i++) { |
| 886 | /* not xstat(): shouldn't bomb out on | 897 | /* not xstat(): shouldn't bomb out on |
| 887 | * "find not_exist exist -xdev" */ | 898 | * "find not_exist exist -xdev" */ |
| 888 | if (stat(argv[i], &stbuf)) | 899 | if (stat(argv[i], &stbuf)) |
| 889 | stbuf.st_dev = -1L; | 900 | stbuf.st_dev = -1L; |
| 890 | xdev_dev[i-1] = stbuf.st_dev; | 901 | G.xdev_dev[i-1] = stbuf.st_dev; |
| 891 | } | 902 | } |
| 892 | } | 903 | } |
| 893 | argp[0] = (char*)"-a"; | 904 | argp[0] = (char*)"-a"; |
| @@ -906,11 +917,11 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) | |||
| 906 | argp++; | 917 | argp++; |
| 907 | } | 918 | } |
| 908 | 919 | ||
| 909 | actions = parse_params(&argv[firstopt]); | 920 | G.actions = parse_params(&argv[firstopt]); |
| 910 | 921 | ||
| 911 | for (i = 1; i < firstopt; i++) { | 922 | for (i = 1; i < firstopt; i++) { |
| 912 | if (!recursive_action(argv[i], | 923 | if (!recursive_action(argv[i], |
| 913 | recurse_flags, /* flags */ | 924 | G.recurse_flags,/* flags */ |
| 914 | fileAction, /* file action */ | 925 | fileAction, /* file action */ |
| 915 | fileAction, /* dir action */ | 926 | fileAction, /* dir action */ |
| 916 | #if ENABLE_FEATURE_FIND_MAXDEPTH | 927 | #if ENABLE_FEATURE_FIND_MAXDEPTH |
diff --git a/include/libbb.h b/include/libbb.h index 8ecde5b4b..a02355cc5 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
| @@ -286,7 +286,9 @@ enum { | |||
| 286 | ACTION_DEPTHFIRST = (1 << 3), | 286 | ACTION_DEPTHFIRST = (1 << 3), |
| 287 | /*ACTION_REVERSE = (1 << 4), - unused */ | 287 | /*ACTION_REVERSE = (1 << 4), - unused */ |
| 288 | ACTION_QUIET = (1 << 5), | 288 | ACTION_QUIET = (1 << 5), |
| 289 | ACTION_DANGLING_OK = (1 << 6), | ||
| 289 | }; | 290 | }; |
| 291 | typedef uint8_t recurse_flags_t; | ||
| 290 | extern int recursive_action(const char *fileName, unsigned flags, | 292 | extern int recursive_action(const char *fileName, unsigned flags, |
| 291 | int FAST_FUNC (*fileAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), | 293 | int FAST_FUNC (*fileAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), |
| 292 | int FAST_FUNC (*dirAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), | 294 | int FAST_FUNC (*dirAction)(const char *fileName, struct stat* statbuf, void* userData, int depth), |
diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c index 3ec596a35..57262cd43 100644 --- a/libbb/recursive_action.c +++ b/libbb/recursive_action.c | |||
| @@ -48,7 +48,7 @@ static int FAST_FUNC true_action(const char *fileName UNUSED_PARAM, | |||
| 48 | * into that directory, instead recursive_action() returns 0 (if FALSE) | 48 | * into that directory, instead recursive_action() returns 0 (if FALSE) |
| 49 | * or 1 (if SKIP) | 49 | * or 1 (if SKIP) |
| 50 | * | 50 | * |
| 51 | * followLinks=0/1 differs mainly in handling of links to dirs. | 51 | * ACTION_FOLLOWLINKS mainly controls handling of links to dirs. |
| 52 | * 0: lstat(statbuf). Calls fileAction on link name even if points to dir. | 52 | * 0: lstat(statbuf). Calls fileAction on link name even if points to dir. |
| 53 | * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir. | 53 | * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir. |
| 54 | */ | 54 | */ |
| @@ -61,6 +61,7 @@ int FAST_FUNC recursive_action(const char *fileName, | |||
| 61 | unsigned depth) | 61 | unsigned depth) |
| 62 | { | 62 | { |
| 63 | struct stat statbuf; | 63 | struct stat statbuf; |
| 64 | unsigned follow; | ||
| 64 | int status; | 65 | int status; |
| 65 | DIR *dir; | 66 | DIR *dir; |
| 66 | struct dirent *next; | 67 | struct dirent *next; |
| @@ -68,14 +69,22 @@ int FAST_FUNC recursive_action(const char *fileName, | |||
| 68 | if (!fileAction) fileAction = true_action; | 69 | if (!fileAction) fileAction = true_action; |
| 69 | if (!dirAction) dirAction = true_action; | 70 | if (!dirAction) dirAction = true_action; |
| 70 | 71 | ||
| 71 | status = ACTION_FOLLOWLINKS; /* hijack a variable for bitmask... */ | 72 | follow = ACTION_FOLLOWLINKS; |
| 72 | if (!depth) | 73 | if (depth == 0) |
| 73 | status = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0; | 74 | follow = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0; |
| 74 | status = ((flags & status) ? stat : lstat)(fileName, &statbuf); | 75 | follow &= flags; |
| 76 | status = (follow ? stat : lstat)(fileName, &statbuf); | ||
| 75 | if (status < 0) { | 77 | if (status < 0) { |
| 76 | #ifdef DEBUG_RECURS_ACTION | 78 | #ifdef DEBUG_RECURS_ACTION |
| 77 | bb_error_msg("status=%d flags=%x", status, flags); | 79 | bb_error_msg("status=%d flags=%x", status, flags); |
| 78 | #endif | 80 | #endif |
| 81 | if ((flags & ACTION_DANGLING_OK) | ||
| 82 | && errno == ENOENT | ||
| 83 | && lstat(fileName, &statbuf) == 0 | ||
| 84 | ) { | ||
| 85 | /* Dangling link */ | ||
| 86 | return fileAction(fileName, &statbuf, userData, depth); | ||
| 87 | } | ||
| 79 | goto done_nak_warn; | 88 | goto done_nak_warn; |
| 80 | } | 89 | } |
| 81 | 90 | ||
