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>
This commit is contained in:
Denys Vlasenko 2009-09-29 11:07:04 +02:00
parent 2f3f09c287
commit 8f7a6d294f
3 changed files with 61 additions and 39 deletions

View File

@ -62,9 +62,6 @@
/* This is a NOEXEC applet. Be very careful! */ /* 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 int (*action_fp)(const char *fileName, const struct stat *statbuf, void *) FAST_FUNC;
typedef struct { 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_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;))
IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;)) IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;))
static action ***actions; struct globals {
static bool need_print = 1; IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;)
static int recurse_flags = ACTION_RECURSE; 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 #if ENABLE_FEATURE_FIND_EXEC
static unsigned count_subst(const char *str) static unsigned count_subst(const char *str)
@ -367,7 +376,7 @@ ACTF(context)
security_context_t con; security_context_t con;
int rc; int rc;
if (recurse_flags & ACTION_FOLLOWLINKS) { if (G.recurse_flags & ACTION_FOLLOWLINKS) {
rc = getfilecon(fileName, &con); rc = getfilecon(fileName, &con);
} else { } else {
rc = lgetfilecon(fileName, &con); rc = lgetfilecon(fileName, &con);
@ -396,9 +405,9 @@ static int FAST_FUNC fileAction(const char *fileName,
#if ENABLE_FEATURE_FIND_XDEV #if ENABLE_FEATURE_FIND_XDEV
if (S_ISDIR(statbuf->st_mode)) { if (S_ISDIR(statbuf->st_mode)) {
if (xdev_count) { if (G.xdev_count) {
for (i = 0; i < xdev_count; i++) { for (i = 0; i < G.xdev_count; i++) {
if (xdev_dev[i] == statbuf->st_dev) if (G.xdev_dev[i] == statbuf->st_dev)
goto found; goto found;
} }
return SKIP; return SKIP;
@ -406,9 +415,9 @@ static int FAST_FUNC fileAction(const char *fileName,
} }
} }
#endif #endif
i = exec_actions(actions, fileName, statbuf); i = exec_actions(G.actions, fileName, statbuf);
/* Had no explicit -print[0] or -exec? then print */ /* Had no explicit -print[0] or -exec? then print */
if ((i & TRUE) && need_print) if ((i & TRUE) && G.need_print)
puts(fileName); puts(fileName);
#if ENABLE_FEATURE_FIND_MAXDEPTH #if ENABLE_FEATURE_FIND_MAXDEPTH
@ -443,7 +452,7 @@ static int find_type(const char *type)
else if (*type == 's') else if (*type == 's')
mask = S_IFSOCK; 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"); bb_error_msg_and_die(bb_msg_invalid_arg, type, "-type");
return mask; return mask;
@ -464,15 +473,15 @@ static const char* plus_minus_num(const char* str)
static action*** parse_params(char **argv) static action*** parse_params(char **argv)
{ {
enum { enum {
PARM_a , PARM_a ,
PARM_o , PARM_o ,
IF_FEATURE_FIND_NOT( PARM_char_not ,) IF_FEATURE_FIND_NOT( PARM_char_not ,)
#if ENABLE_DESKTOP #if ENABLE_DESKTOP
PARM_and , PARM_and ,
PARM_or , PARM_or ,
IF_FEATURE_FIND_NOT( PARM_not ,) IF_FEATURE_FIND_NOT( PARM_not ,)
#endif #endif
PARM_print , PARM_print ,
IF_FEATURE_FIND_PRINT0( PARM_print0 ,) IF_FEATURE_FIND_PRINT0( PARM_print0 ,)
IF_FEATURE_FIND_DEPTH( PARM_depth ,) IF_FEATURE_FIND_DEPTH( PARM_depth ,)
IF_FEATURE_FIND_PRUNE( PARM_prune ,) 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_EXEC( PARM_exec ,)
IF_FEATURE_FIND_PAREN( PARM_char_brace,) IF_FEATURE_FIND_PAREN( PARM_char_brace,)
/* All options starting from here require argument */ /* All options starting from here require argument */
PARM_name , PARM_name ,
PARM_iname , PARM_iname ,
IF_FEATURE_FIND_PATH( PARM_path ,) IF_FEATURE_FIND_PATH( PARM_path ,)
IF_FEATURE_FIND_REGEX( PARM_regex ,) IF_FEATURE_FIND_REGEX( PARM_regex ,)
IF_FEATURE_FIND_TYPE( PARM_type ,) IF_FEATURE_FIND_TYPE( PARM_type ,)
@ -604,21 +613,21 @@ static action*** parse_params(char **argv)
/* --- Tests and actions --- */ /* --- Tests and actions --- */
else if (parm == PARM_print) { else if (parm == PARM_print) {
need_print = 0; G.need_print = 0;
/* GNU find ignores '!' here: "find ! -print" */ /* GNU find ignores '!' here: "find ! -print" */
IF_FEATURE_FIND_NOT( invert_flag = 0; ) IF_FEATURE_FIND_NOT( invert_flag = 0; )
(void) ALLOC_ACTION(print); (void) ALLOC_ACTION(print);
} }
#if ENABLE_FEATURE_FIND_PRINT0 #if ENABLE_FEATURE_FIND_PRINT0
else if (parm == PARM_print0) { else if (parm == PARM_print0) {
need_print = 0; G.need_print = 0;
IF_FEATURE_FIND_NOT( invert_flag = 0; ) IF_FEATURE_FIND_NOT( invert_flag = 0; )
(void) ALLOC_ACTION(print0); (void) ALLOC_ACTION(print0);
} }
#endif #endif
#if ENABLE_FEATURE_FIND_DEPTH #if ENABLE_FEATURE_FIND_DEPTH
else if (parm == PARM_depth) { else if (parm == PARM_depth) {
recurse_flags |= ACTION_DEPTHFIRST; G.recurse_flags |= ACTION_DEPTHFIRST;
} }
#endif #endif
#if ENABLE_FEATURE_FIND_PRUNE #if ENABLE_FEATURE_FIND_PRUNE
@ -629,8 +638,8 @@ static action*** parse_params(char **argv)
#endif #endif
#if ENABLE_FEATURE_FIND_DELETE #if ENABLE_FEATURE_FIND_DELETE
else if (parm == PARM_delete) { else if (parm == PARM_delete) {
need_print = 0; G.need_print = 0;
recurse_flags |= ACTION_DEPTHFIRST; G.recurse_flags |= ACTION_DEPTHFIRST;
(void) ALLOC_ACTION(delete); (void) ALLOC_ACTION(delete);
} }
#endif #endif
@ -638,7 +647,7 @@ static action*** parse_params(char **argv)
else if (parm == PARM_exec) { else if (parm == PARM_exec) {
int i; int i;
action_exec *ap; action_exec *ap;
need_print = 0; G.need_print = 0;
IF_FEATURE_FIND_NOT( invert_flag = 0; ) IF_FEATURE_FIND_NOT( invert_flag = 0; )
ap = ALLOC_ACTION(exec); ap = ALLOC_ACTION(exec);
ap->exec_argv = ++argv; /* first arg after -exec */ ap->exec_argv = ++argv; /* first arg after -exec */
@ -846,6 +855,8 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,)
#define minmaxdepth NULL #define minmaxdepth NULL
#endif #endif
INIT_G();
for (firstopt = 1; firstopt < argc; firstopt++) { for (firstopt = 1; firstopt < argc; firstopt++) {
if (argv[firstopt][0] == '-') if (argv[firstopt][0] == '-')
break; break;
@ -873,21 +884,21 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,)
while ((arg = argp[0])) { while ((arg = argp[0])) {
int opt = index_in_strings(options, arg); int opt = index_in_strings(options, arg);
if (opt == OPT_FOLLOW) { if (opt == OPT_FOLLOW) {
recurse_flags |= ACTION_FOLLOWLINKS; G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK;
argp[0] = (char*)"-a"; argp[0] = (char*)"-a";
} }
#if ENABLE_FEATURE_FIND_XDEV #if ENABLE_FEATURE_FIND_XDEV
if (opt == OPT_XDEV) { if (opt == OPT_XDEV) {
struct stat stbuf; struct stat stbuf;
if (!xdev_count) { if (!G.xdev_count) {
xdev_count = firstopt - 1; G.xdev_count = firstopt - 1;
xdev_dev = xmalloc(xdev_count * sizeof(dev_t)); G.xdev_dev = xmalloc(G.xdev_count * sizeof(dev_t));
for (i = 1; i < firstopt; i++) { for (i = 1; i < firstopt; i++) {
/* not xstat(): shouldn't bomb out on /* not xstat(): shouldn't bomb out on
* "find not_exist exist -xdev" */ * "find not_exist exist -xdev" */
if (stat(argv[i], &stbuf)) if (stat(argv[i], &stbuf))
stbuf.st_dev = -1L; stbuf.st_dev = -1L;
xdev_dev[i-1] = stbuf.st_dev; G.xdev_dev[i-1] = stbuf.st_dev;
} }
} }
argp[0] = (char*)"-a"; argp[0] = (char*)"-a";
@ -906,11 +917,11 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,)
argp++; argp++;
} }
actions = parse_params(&argv[firstopt]); G.actions = parse_params(&argv[firstopt]);
for (i = 1; i < firstopt; i++) { for (i = 1; i < firstopt; i++) {
if (!recursive_action(argv[i], if (!recursive_action(argv[i],
recurse_flags, /* flags */ G.recurse_flags,/* flags */
fileAction, /* file action */ fileAction, /* file action */
fileAction, /* dir action */ fileAction, /* dir action */
#if ENABLE_FEATURE_FIND_MAXDEPTH #if ENABLE_FEATURE_FIND_MAXDEPTH

View File

@ -286,7 +286,9 @@ enum {
ACTION_DEPTHFIRST = (1 << 3), ACTION_DEPTHFIRST = (1 << 3),
/*ACTION_REVERSE = (1 << 4), - unused */ /*ACTION_REVERSE = (1 << 4), - unused */
ACTION_QUIET = (1 << 5), ACTION_QUIET = (1 << 5),
ACTION_DANGLING_OK = (1 << 6),
}; };
typedef uint8_t recurse_flags_t;
extern int recursive_action(const char *fileName, unsigned flags, 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 (*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), int FAST_FUNC (*dirAction)(const char *fileName, struct stat* statbuf, void* userData, int depth),

View 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) * into that directory, instead recursive_action() returns 0 (if FALSE)
* or 1 (if SKIP) * 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. * 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. * 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) unsigned depth)
{ {
struct stat statbuf; struct stat statbuf;
unsigned follow;
int status; int status;
DIR *dir; DIR *dir;
struct dirent *next; struct dirent *next;
@ -68,14 +69,22 @@ int FAST_FUNC recursive_action(const char *fileName,
if (!fileAction) fileAction = true_action; if (!fileAction) fileAction = true_action;
if (!dirAction) dirAction = true_action; if (!dirAction) dirAction = true_action;
status = ACTION_FOLLOWLINKS; /* hijack a variable for bitmask... */ follow = ACTION_FOLLOWLINKS;
if (!depth) if (depth == 0)
status = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0; follow = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0;
status = ((flags & status) ? stat : lstat)(fileName, &statbuf); follow &= flags;
status = (follow ? stat : lstat)(fileName, &statbuf);
if (status < 0) { if (status < 0) {
#ifdef DEBUG_RECURS_ACTION #ifdef DEBUG_RECURS_ACTION
bb_error_msg("status=%d flags=%x", status, flags); bb_error_msg("status=%d flags=%x", status, flags);
#endif #endif
if ((flags & ACTION_DANGLING_OK)
&& errno == ENOENT
&& lstat(fileName, &statbuf) == 0
) {
/* Dangling link */
return fileAction(fileName, &statbuf, userData, depth);
}
goto done_nak_warn; goto done_nak_warn;
} }