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:
parent
2f3f09c287
commit
8f7a6d294f
@ -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
|
||||||
|
@ -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),
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user