find: -follow should not error out on dandling links
authorDenys Vlasenko <vda.linux@googlemail.com>
Tue, 29 Sep 2009 09:07:04 +0000 (11:07 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Tue, 29 Sep 2009 09:07:04 +0000 (11:07 +0200)
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>
findutils/find.c
include/libbb.h
libbb/recursive_action.c

index bd92e22818bbe2ca8e5e8ae9f96e9cdd376ffef3..6f7be4fc250563a82fd2f3c321e81693afa075c3 100644 (file)
@@ -62,9 +62,6 @@
 /* This is a NOEXEC applet. Be very careful! */
 
 
-IF_FEATURE_FIND_XDEV(static dev_t *xdev_dev;)
-IF_FEATURE_FIND_XDEV(static int xdev_count;)
-
 typedef int (*action_fp)(const char *fileName, const struct stat *statbuf, void *) FAST_FUNC;
 
 typedef struct {
@@ -100,9 +97,21 @@ IF_FEATURE_FIND_DELETE( ACTS(delete))
 IF_FEATURE_FIND_EXEC(   ACTS(exec,  char **exec_argv; unsigned *subst_count; int exec_argc;))
 IF_FEATURE_FIND_GROUP(  ACTS(group, gid_t gid;))
 
-static action ***actions;
-static bool need_print = 1;
-static int recurse_flags = ACTION_RECURSE;
+struct globals {
+       IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;)
+       IF_FEATURE_FIND_XDEV(int xdev_count;)
+       action ***actions;
+       bool need_print;
+       recurse_flags_t recurse_flags;
+};
+#define G (*(struct globals*)&bb_common_bufsiz1)
+#define INIT_G() do { \
+       struct G_sizecheck { \
+               char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \
+       }; \
+       G.need_print = 1; \
+       G.recurse_flags = ACTION_RECURSE; \
+} while (0)
 
 #if ENABLE_FEATURE_FIND_EXEC
 static unsigned count_subst(const char *str)
@@ -367,7 +376,7 @@ ACTF(context)
        security_context_t con;
        int rc;
 
-       if (recurse_flags & ACTION_FOLLOWLINKS) {
+       if (G.recurse_flags & ACTION_FOLLOWLINKS) {
                rc = getfilecon(fileName, &con);
        } else {
                rc = lgetfilecon(fileName, &con);
@@ -396,9 +405,9 @@ static int FAST_FUNC fileAction(const char *fileName,
 
 #if ENABLE_FEATURE_FIND_XDEV
        if (S_ISDIR(statbuf->st_mode)) {
-               if (xdev_count) {
-                       for (i = 0; i < xdev_count; i++) {
-                               if (xdev_dev[i] == statbuf->st_dev)
+               if (G.xdev_count) {
+                       for (i = 0; i < G.xdev_count; i++) {
+                               if (G.xdev_dev[i] == statbuf->st_dev)
                                        goto found;
                        }
                        return SKIP;
@@ -406,9 +415,9 @@ static int FAST_FUNC fileAction(const char *fileName,
                }
        }
 #endif
-       i = exec_actions(actions, fileName, statbuf);
+       i = exec_actions(G.actions, fileName, statbuf);
        /* Had no explicit -print[0] or -exec? then print */
-       if ((i & TRUE) && need_print)
+       if ((i & TRUE) && G.need_print)
                puts(fileName);
 
 #if ENABLE_FEATURE_FIND_MAXDEPTH
@@ -443,7 +452,7 @@ static int find_type(const char *type)
        else if (*type == 's')
                mask = S_IFSOCK;
 
-       if (mask == 0 || *(type + 1) != '\0')
+       if (mask == 0 || type[1] != '\0')
                bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type");
 
        return mask;
@@ -464,15 +473,15 @@ static const char* plus_minus_num(const char* str)
 static action*** parse_params(char **argv)
 {
        enum {
-                                PARM_a         ,
-                                PARM_o         ,
-       IF_FEATURE_FIND_NOT(     PARM_char_not  ,)
+                               PARM_a         ,
+                               PARM_o         ,
+       IF_FEATURE_FIND_NOT(    PARM_char_not  ,)
 #if ENABLE_DESKTOP
-                                PARM_and       ,
-                                PARM_or        ,
+                               PARM_and       ,
+                               PARM_or        ,
        IF_FEATURE_FIND_NOT(    PARM_not       ,)
 #endif
-                                PARM_print     ,
+                               PARM_print     ,
        IF_FEATURE_FIND_PRINT0( PARM_print0    ,)
        IF_FEATURE_FIND_DEPTH(  PARM_depth     ,)
        IF_FEATURE_FIND_PRUNE(  PARM_prune     ,)
@@ -480,8 +489,8 @@ static action*** parse_params(char **argv)
        IF_FEATURE_FIND_EXEC(   PARM_exec      ,)
        IF_FEATURE_FIND_PAREN(  PARM_char_brace,)
        /* All options starting from here require argument */
-                                PARM_name      ,
-                                PARM_iname     ,
+                               PARM_name      ,
+                               PARM_iname     ,
        IF_FEATURE_FIND_PATH(   PARM_path      ,)
        IF_FEATURE_FIND_REGEX(  PARM_regex     ,)
        IF_FEATURE_FIND_TYPE(   PARM_type      ,)
@@ -604,21 +613,21 @@ static action*** parse_params(char **argv)
 
        /* --- Tests and actions --- */
                else if (parm == PARM_print) {
-                       need_print = 0;
+                       G.need_print = 0;
                        /* GNU find ignores '!' here: "find ! -print" */
                        IF_FEATURE_FIND_NOT( invert_flag = 0; )
                        (void) ALLOC_ACTION(print);
                }
 #if ENABLE_FEATURE_FIND_PRINT0
                else if (parm == PARM_print0) {
-                       need_print = 0;
+                       G.need_print = 0;
                        IF_FEATURE_FIND_NOT( invert_flag = 0; )
                        (void) ALLOC_ACTION(print0);
                }
 #endif
 #if ENABLE_FEATURE_FIND_DEPTH
                else if (parm == PARM_depth) {
-                       recurse_flags |= ACTION_DEPTHFIRST;
+                       G.recurse_flags |= ACTION_DEPTHFIRST;
                }
 #endif
 #if ENABLE_FEATURE_FIND_PRUNE
@@ -629,8 +638,8 @@ static action*** parse_params(char **argv)
 #endif
 #if ENABLE_FEATURE_FIND_DELETE
                else if (parm == PARM_delete) {
-                       need_print = 0;
-                       recurse_flags |= ACTION_DEPTHFIRST;
+                       G.need_print = 0;
+                       G.recurse_flags |= ACTION_DEPTHFIRST;
                        (void) ALLOC_ACTION(delete);
                }
 #endif
@@ -638,7 +647,7 @@ static action*** parse_params(char **argv)
                else if (parm == PARM_exec) {
                        int i;
                        action_exec *ap;
-                       need_print = 0;
+                       G.need_print = 0;
                        IF_FEATURE_FIND_NOT( invert_flag = 0; )
                        ap = ALLOC_ACTION(exec);
                        ap->exec_argv = ++argv; /* first arg after -exec */
@@ -846,6 +855,8 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,)
 #define minmaxdepth NULL
 #endif
 
+       INIT_G();
+
        for (firstopt = 1; firstopt < argc; firstopt++) {
                if (argv[firstopt][0] == '-')
                        break;
@@ -873,21 +884,21 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,)
        while ((arg = argp[0])) {
                int opt = index_in_strings(options, arg);
                if (opt == OPT_FOLLOW) {
-                       recurse_flags |= ACTION_FOLLOWLINKS;
+                       G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK;
                        argp[0] = (char*)"-a";
                }
 #if ENABLE_FEATURE_FIND_XDEV
                if (opt == OPT_XDEV) {
                        struct stat stbuf;
-                       if (!xdev_count) {
-                               xdev_count = firstopt - 1;
-                               xdev_dev = xmalloc(xdev_count * sizeof(dev_t));
+                       if (!G.xdev_count) {
+                               G.xdev_count = firstopt - 1;
+                               G.xdev_dev = xmalloc(G.xdev_count * sizeof(dev_t));
                                for (i = 1; i < firstopt; i++) {
                                        /* not xstat(): shouldn't bomb out on
                                         * "find not_exist exist -xdev" */
                                        if (stat(argv[i], &stbuf))
                                                stbuf.st_dev = -1L;
-                                       xdev_dev[i-1] = stbuf.st_dev;
+                                       G.xdev_dev[i-1] = stbuf.st_dev;
                                }
                        }
                        argp[0] = (char*)"-a";
@@ -906,11 +917,11 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,)
                argp++;
        }
 
-       actions = parse_params(&argv[firstopt]);
+       G.actions = parse_params(&argv[firstopt]);
 
        for (i = 1; i < firstopt; i++) {
                if (!recursive_action(argv[i],
-                               recurse_flags,  /* flags */
+                               G.recurse_flags,/* flags */
                                fileAction,     /* file action */
                                fileAction,     /* dir action */
 #if ENABLE_FEATURE_FIND_MAXDEPTH
index 8ecde5b4b603a48f3611db06c0a48cd8f9c76efe..a02355cc5854f9d2d9eca9321c1c96814d1fa82b 100644 (file)
@@ -286,7 +286,9 @@ enum {
        ACTION_DEPTHFIRST     = (1 << 3),
        /*ACTION_REVERSE      = (1 << 4), - unused */
        ACTION_QUIET          = (1 << 5),
+       ACTION_DANGLING_OK    = (1 << 6),
 };
+typedef uint8_t recurse_flags_t;
 extern int recursive_action(const char *fileName, unsigned flags,
        int FAST_FUNC (*fileAction)(const char *fileName, struct stat* statbuf, void* userData, int depth),
        int FAST_FUNC (*dirAction)(const char *fileName, struct stat* statbuf, void* userData, int depth),
index 3ec596a35772d99bd677612080499ab44381f3bd..57262cd439cbf9920394efebdd69292440cf8178 100644 (file)
@@ -48,7 +48,7 @@ static int FAST_FUNC true_action(const char *fileName UNUSED_PARAM,
  * into that directory, instead recursive_action() returns 0 (if FALSE)
  * or 1 (if SKIP)
  *
- * followLinks=0/1 differs mainly in handling of links to dirs.
+ * ACTION_FOLLOWLINKS mainly controls handling of links to dirs.
  * 0: lstat(statbuf). Calls fileAction on link name even if points to dir.
  * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir.
  */
@@ -61,6 +61,7 @@ int FAST_FUNC recursive_action(const char *fileName,
                unsigned depth)
 {
        struct stat statbuf;
+       unsigned follow;
        int status;
        DIR *dir;
        struct dirent *next;
@@ -68,14 +69,22 @@ int FAST_FUNC recursive_action(const char *fileName,
        if (!fileAction) fileAction = true_action;
        if (!dirAction) dirAction = true_action;
 
-       status = ACTION_FOLLOWLINKS; /* hijack a variable for bitmask... */
-       if (!depth)
-               status = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0;
-       status = ((flags & status) ? stat : lstat)(fileName, &statbuf);
+       follow = ACTION_FOLLOWLINKS;
+       if (depth == 0)
+               follow = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0;
+       follow &= flags;
+       status = (follow ? stat : lstat)(fileName, &statbuf);
        if (status < 0) {
 #ifdef DEBUG_RECURS_ACTION
                bb_error_msg("status=%d flags=%x", status, flags);
 #endif
+               if ((flags & ACTION_DANGLING_OK)
+                && errno == ENOENT
+                && lstat(fileName, &statbuf) == 0
+               ) {
+                       /* Dangling link */
+                       return fileAction(fileName, &statbuf, userData, depth);
+               }
                goto done_nak_warn;
        }