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 @@ /* 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 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 { 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), 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, * 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; }