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:
		| @@ -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 | ||||
|   | ||||
| @@ -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), | ||||
|   | ||||
| @@ -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; | ||||
| 	} | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user