Changeset 3621 in MondoRescue for branches/3.3/mindi-busybox/findutils/find.c
- Timestamp:
- Dec 20, 2016, 4:07:32 PM (7 years ago)
- Location:
- branches/3.3
- Files:
-
- 1 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
branches/3.3/mindi-busybox/findutils/find.c
r3232 r3621 138 138 //config: the files matched. 139 139 //config: 140 //config:config FEATURE_FIND_EXEC_PLUS 141 //config: bool "Enable -exec ... {} +" 142 //config: default y 143 //config: depends on FEATURE_FIND_EXEC 144 //config: help 145 //config: Support the 'find -exec ... {} +' option for executing commands 146 //config: for all matched files at once. 147 //config: Without this option, -exec + is a synonym for -exec ; 148 //config: (IOW: it works correctly, but without expected speedup) 149 //config: 140 150 //config:config FEATURE_FIND_USER 141 151 //config: bool "Enable -user: username/uid matching" … … 232 242 233 243 //usage:#define find_trivial_usage 234 //usage: "[ PATH]... [OPTIONS] [ACTIONS]"244 //usage: "[-HL] [PATH]... [OPTIONS] [ACTIONS]" 235 245 //usage:#define find_full_usage "\n\n" 236 246 //usage: "Search for files and perform actions on them.\n" 237 247 //usage: "First failed action stops processing of current file.\n" 238 248 //usage: "Defaults: PATH is current directory, action is '-print'\n" 239 //usage: "\n -follow Follow symlinks" 249 //usage: "\n -L,-follow Follow symlinks" 250 //usage: "\n -H ...on command line only" 240 251 //usage: IF_FEATURE_FIND_XDEV( 241 252 //usage: "\n -xdev Don't descend directories on other filesystems" … … 319 330 //usage: "\n file name. Fails if CMD exits with nonzero" 320 331 //usage: ) 332 //usage: IF_FEATURE_FIND_EXEC_PLUS( 333 //usage: "\n -exec CMD ARG + Run CMD with {} replaced by list of file names" 334 //usage: ) 321 335 //usage: IF_FEATURE_FIND_DELETE( 322 336 //usage: "\n -delete Delete current file/directory. Turns on -depth option" … … 329 343 #include <fnmatch.h> 330 344 #include "libbb.h" 345 #include "common_bufsiz.h" 331 346 #if ENABLE_FEATURE_FIND_REGEX 332 347 # include "xregex.h" … … 337 352 #endif 338 353 339 #define dbg(...) ((void)0) 340 /* #define dbg(...) bb_error_msg(__VA_ARGS__) */ 354 #if 1 355 # define dbg(...) ((void)0) 356 #else 357 # define dbg(...) bb_error_msg(__VA_ARGS__) 358 #endif 359 341 360 342 361 /* This is a NOEXEC applet. Be very careful! */ … … 375 394 IF_FEATURE_FIND_PRUNE( ACTS(prune)) 376 395 IF_FEATURE_FIND_DELETE( ACTS(delete)) 377 IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;)) 396 IF_FEATURE_FIND_EXEC( ACTS(exec, 397 char **exec_argv; /* -exec ARGS */ 398 unsigned *subst_count; 399 int exec_argc; /* count of ARGS */ 400 IF_FEATURE_FIND_EXEC_PLUS( 401 /* 402 * filelist is NULL if "exec ;" 403 * non-NULL if "exec +" 404 */ 405 char **filelist; 406 int filelist_idx; 407 int file_len; 408 ) 409 )) 378 410 IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;)) 379 411 IF_FEATURE_FIND_LINKS( ACTS(links, char links_char; int links_count;)) … … 389 421 smallint xdev_on; 390 422 recurse_flags_t recurse_flags; 423 IF_FEATURE_FIND_EXEC_PLUS(unsigned max_argv_len;) 391 424 } FIX_ALIASING; 392 #define G (*(struct globals*) &bb_common_bufsiz1)425 #define G (*(struct globals*)bb_common_bufsiz1) 393 426 #define INIT_G() do { \ 394 struct G_sizecheck { \ 395 char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \ 396 }; \ 427 setup_common_bufsiz(); \ 428 BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \ 397 429 /* we have to zero it out because of NOEXEC */ \ 398 430 memset(&G, 0, sizeof(G)); \ 399 431 IF_FEATURE_FIND_MAXDEPTH(G.minmaxdepth[1] = INT_MAX;) \ 432 IF_FEATURE_FIND_EXEC_PLUS(G.max_argv_len = bb_arg_max() - 2048;) \ 400 433 G.need_print = 1; \ 401 434 G.recurse_flags = ACTION_RECURSE; \ 402 435 } while (0) 403 404 #if ENABLE_FEATURE_FIND_EXEC405 static unsigned count_subst(const char *str)406 {407 unsigned count = 0;408 while ((str = strstr(str, "{}")) != NULL) {409 count++;410 str++;411 }412 return count;413 }414 415 416 static char* subst(const char *src, unsigned count, const char* filename)417 {418 char *buf, *dst, *end;419 size_t flen = strlen(filename);420 /* we replace each '{}' with filename: growth by strlen-2 */421 buf = dst = xmalloc(strlen(src) + count*(flen-2) + 1);422 while ((end = strstr(src, "{}"))) {423 memcpy(dst, src, end - src);424 dst += end - src;425 src = end + 2;426 memcpy(dst, filename, flen);427 dst += flen;428 }429 strcpy(dst, src);430 return buf;431 }432 #endif433 436 434 437 /* Return values of ACTFs ('action functions') are a bit mask: … … 482 485 } 483 486 484 485 487 #if !FNM_CASEFOLD 486 488 static char *strcpy_upcase(char *dst, const char *src) … … 557 559 ACTF(perm) 558 560 { 559 /* -perm +mode: at least one of perm_mask bits are set */560 if (ap->perm_char == '+' )561 /* -perm [+/]mode: at least one of perm_mask bits are set */ 562 if (ap->perm_char == '+' || ap->perm_char == '/') 561 563 return (statbuf->st_mode & ap->perm_mask) != 0; 562 564 /* -perm -mode: all of perm_mask are set */ … … 606 608 #endif 607 609 #if ENABLE_FEATURE_FIND_EXEC 608 ACTF(exec)610 static int do_exec(action_exec *ap, const char *fileName) 609 611 { 610 612 int i, rc; 611 #if ENABLE_USE_PORTABLE_CODE 612 char **argv = alloca(sizeof(char*) * (ap->exec_argc + 1)); 613 #else /* gcc 4.3.1 generates smaller code: */ 614 char *argv[ap->exec_argc + 1]; 615 #endif 616 for (i = 0; i < ap->exec_argc; i++) 617 argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName); 618 argv[i] = NULL; /* terminate the list */ 613 # if ENABLE_FEATURE_FIND_EXEC_PLUS 614 int size = ap->exec_argc + ap->filelist_idx + 1; 615 # else 616 int size = ap->exec_argc + 1; 617 # endif 618 # if ENABLE_USE_PORTABLE_CODE 619 char **argv = alloca(sizeof(char*) * size); 620 # else /* gcc 4.3.1 generates smaller code: */ 621 char *argv[size]; 622 # endif 623 char **pp = argv; 624 625 for (i = 0; i < ap->exec_argc; i++) { 626 const char *arg = ap->exec_argv[i]; 627 628 # if ENABLE_FEATURE_FIND_EXEC_PLUS 629 if (ap->filelist) { 630 /* Handling "-exec +" 631 * Only one exec_argv[i] has substitution in it. 632 * Expand that one exec_argv[i] into file list. 633 */ 634 if (ap->subst_count[i] == 0) { 635 *pp++ = xstrdup(arg); 636 } else { 637 int j = 0; 638 while (ap->filelist[j]) { 639 /* 2nd arg here should be ap->subst_count[i], but it is always 1: */ 640 *pp++ = xmalloc_substitute_string(arg, 1, "{}", ap->filelist[j]); 641 free(ap->filelist[j]); 642 j++; 643 } 644 } 645 } else 646 # endif 647 { 648 /* Handling "-exec ;" */ 649 *pp++ = xmalloc_substitute_string(arg, ap->subst_count[i], "{}", fileName); 650 } 651 } 652 *pp = NULL; /* terminate the list */ 653 654 # if ENABLE_FEATURE_FIND_EXEC_PLUS 655 if (ap->filelist) { 656 ap->filelist[0] = NULL; 657 ap->filelist_idx = 0; 658 ap->file_len = 0; 659 } 660 # endif 619 661 620 662 rc = spawn_and_wait(argv); … … 627 669 return rc == 0; /* return 1 if exitcode 0 */ 628 670 } 671 ACTF(exec) 672 { 673 # if ENABLE_FEATURE_FIND_EXEC_PLUS 674 if (ap->filelist) { 675 int rc; 676 677 ap->filelist = xrealloc_vector(ap->filelist, 8, ap->filelist_idx); 678 ap->filelist[ap->filelist_idx++] = xstrdup(fileName); 679 ap->file_len += strlen(fileName) + sizeof(char*) + 1; 680 /* If we have lots of files already, exec the command */ 681 rc = 1; 682 if (ap->file_len >= G.max_argv_len) 683 rc = do_exec(ap, NULL); 684 return rc; 685 } 686 # endif 687 return do_exec(ap, fileName); 688 } 689 # if ENABLE_FEATURE_FIND_EXEC_PLUS 690 static int flush_exec_plus(void) 691 { 692 action *ap; 693 action **app; 694 action ***appp = G.actions; 695 while ((app = *appp++) != NULL) { 696 while ((ap = *app++) != NULL) { 697 if (ap->f == (action_fp)func_exec) { 698 action_exec *ae = (void*)ap; 699 if (ae->filelist_idx != 0) { 700 int rc = do_exec(ae, NULL); 701 # if ENABLE_FEATURE_FIND_NOT 702 if (ap->invert) rc = !rc; 703 # endif 704 if (rc == 0) 705 return 1; 706 } 707 } 708 } 709 } 710 return 0; 711 } 712 # endif 629 713 #endif 630 714 #if ENABLE_FEATURE_FIND_USER … … 685 769 int rc; 686 770 if (S_ISDIR(statbuf->st_mode)) { 687 rc = rmdir(fileName); 771 /* "find . -delete" skips rmdir(".") */ 772 rc = 0; 773 if (NOT_LONE_CHAR(fileName, '.')) 774 rc = rmdir(fileName); 688 775 } else { 689 776 rc = unlink(fileName); … … 798 885 799 886 if (mask == 0 || type[1] != '\0') 800 bb_error_msg_and_die(bb_msg_invalid_arg , type, "-type");887 bb_error_msg_and_die(bb_msg_invalid_arg_to, type, "-type"); 801 888 802 889 return mask; … … 812 899 str++; 813 900 return str; 901 } 902 #endif 903 904 /* Say no to GCCism */ 905 #define USE_NESTED_FUNCTION 0 906 907 #if !USE_NESTED_FUNCTION 908 struct pp_locals { 909 action*** appp; 910 unsigned cur_group; 911 unsigned cur_action; 912 IF_FEATURE_FIND_NOT( bool invert_flag; ) 913 }; 914 static action* alloc_action(struct pp_locals *ppl, int sizeof_struct, action_fp f) 915 { 916 action *ap = xzalloc(sizeof_struct); 917 action **app; 918 action ***group = &ppl->appp[ppl->cur_group]; 919 *group = app = xrealloc(*group, (ppl->cur_action+2) * sizeof(ppl->appp[0][0])); 920 app[ppl->cur_action++] = ap; 921 app[ppl->cur_action] = NULL; 922 ap->f = f; 923 IF_FEATURE_FIND_NOT( ap->invert = ppl->invert_flag; ) 924 IF_FEATURE_FIND_NOT( ppl->invert_flag = 0; ) 925 return ap; 814 926 } 815 927 #endif … … 901 1013 ; 902 1014 1015 #if !USE_NESTED_FUNCTION 1016 struct pp_locals ppl; 1017 #define appp (ppl.appp ) 1018 #define cur_group (ppl.cur_group ) 1019 #define cur_action (ppl.cur_action ) 1020 #define invert_flag (ppl.invert_flag) 1021 #define ALLOC_ACTION(name) (action_##name*)alloc_action(&ppl, sizeof(action_##name), (action_fp) func_##name) 1022 #else 903 1023 action*** appp; 904 unsigned cur_group = 0;905 unsigned cur_action = 0;906 IF_FEATURE_FIND_NOT( bool invert_flag = 0; )1024 unsigned cur_group; 1025 unsigned cur_action; 1026 IF_FEATURE_FIND_NOT( bool invert_flag; ) 907 1027 908 1028 /* This is the only place in busybox where we use nested function. … … 913 1033 { 914 1034 action *ap; 915 appp[cur_group] = xrealloc(appp[cur_group], (cur_action+2) * sizeof( *appp));1035 appp[cur_group] = xrealloc(appp[cur_group], (cur_action+2) * sizeof(appp[0][0])); 916 1036 appp[cur_group][cur_action++] = ap = xzalloc(sizeof_struct); 917 1037 appp[cur_group][cur_action] = NULL; … … 921 1041 return ap; 922 1042 } 923 924 1043 #define ALLOC_ACTION(name) (action_##name*)alloc_action(sizeof(action_##name), (action_fp) func_##name) 925 1044 #endif 1045 1046 cur_group = 0; 1047 cur_action = 0; 1048 IF_FEATURE_FIND_NOT( invert_flag = 0; ) 926 1049 appp = xzalloc(2 * sizeof(appp[0])); /* appp[0],[1] == NULL */ 927 1050 … … 949 1072 /* Options */ 950 1073 if (parm == OPT_FOLLOW) { 951 952 1074 dbg("follow enabled: %d", __LINE__); 1075 G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK; 953 1076 } 954 1077 #if ENABLE_FEATURE_FIND_XDEV … … 988 1111 /* start new OR group */ 989 1112 cur_group++; 990 appp = xrealloc(appp, (cur_group+2) * sizeof( *appp));1113 appp = xrealloc(appp, (cur_group+2) * sizeof(appp[0])); 991 1114 /*appp[cur_group] = NULL; - already NULL */ 992 1115 appp[cur_group+1] = NULL; … … 1031 1154 int i; 1032 1155 action_exec *ap; 1156 IF_FEATURE_FIND_EXEC_PLUS(int all_subst = 0;) 1033 1157 dbg("%d", __LINE__); 1034 1158 G.need_print = 0; … … 1043 1167 // find -exec echo Foo ">{}<" "+" 1044 1168 // executes "echo Foo FILENAME1 FILENAME2 FILENAME3...". 1045 // TODO (so far we treat "+" just like ";")1046 1169 if ((argv[0][0] == ';' || argv[0][0] == '+') 1047 1170 && argv[0][1] == '\0' 1048 1171 ) { 1172 # if ENABLE_FEATURE_FIND_EXEC_PLUS 1173 if (argv[0][0] == '+') 1174 ap->filelist = xzalloc(sizeof(ap->filelist[0])); 1175 # endif 1049 1176 break; 1050 1177 } … … 1056 1183 ap->subst_count = xmalloc(ap->exec_argc * sizeof(int)); 1057 1184 i = ap->exec_argc; 1058 while (i--) 1059 ap->subst_count[i] = count_subst(ap->exec_argv[i]); 1185 while (i--) { 1186 ap->subst_count[i] = count_strstr(ap->exec_argv[i], "{}"); 1187 IF_FEATURE_FIND_EXEC_PLUS(all_subst += ap->subst_count[i];) 1188 } 1189 # if ENABLE_FEATURE_FIND_EXEC_PLUS 1190 /* 1191 * coreutils expects {} to appear only once in "-exec +" 1192 */ 1193 if (all_subst != 1 && ap->filelist) 1194 bb_error_msg_and_die("only one '{}' allowed for -exec +"); 1195 # endif 1060 1196 } 1061 1197 #endif … … 1120 1256 * Symbolic modes use mode 0 as a point of departure. 1121 1257 * -perm -BITS All of the BITS are set in file's mode. 1122 * -perm +BITS At least one of the BITS is set in file's mode.1258 * -perm [+/]BITS At least one of the BITS is set in file's mode. 1123 1259 */ 1124 1260 else if (parm == PARM_perm) { … … 1127 1263 ap = ALLOC_ACTION(perm); 1128 1264 ap->perm_char = arg1[0]; 1129 arg1 = plus_minus_num(arg1);1265 arg1 = (arg1[0] == '/' ? arg1+1 : plus_minus_num(arg1)); 1130 1266 /*ap->perm_mask = 0; - ALLOC_ACTION did it */ 1131 if (!bb_parse_mode(arg1, &ap->perm_mask)) 1267 ap->perm_mask = bb_parse_mode(arg1, ap->perm_mask); 1268 if (ap->perm_mask == (mode_t)-1) 1132 1269 bb_error_msg_and_die("invalid mode '%s'", arg1); 1133 1270 } … … 1246 1383 return appp; 1247 1384 #undef ALLOC_ACTION 1385 #undef appp 1386 #undef cur_action 1387 #undef invert_flag 1248 1388 } 1249 1389 … … 1252 1392 { 1253 1393 int i, firstopt, status = EXIT_SUCCESS; 1394 char **past_HLP, *saved; 1254 1395 1255 1396 INIT_G(); 1256 1397 1257 argv++; 1398 /* "find -type f" + getopt("+HLP") => disaster. 1399 * Need to avoid getopt running into a non-HLP option. 1400 * Do this by temporarily storing NULL there: 1401 */ 1402 past_HLP = argv; 1403 for (;;) { 1404 saved = *++past_HLP; 1405 if (!saved) 1406 break; 1407 if (saved[0] != '-') 1408 break; 1409 if (!saved[1]) 1410 break; /* it is "-" */ 1411 if ((saved+1)[strspn(saved+1, "HLP")] != '\0') 1412 break; 1413 } 1414 *past_HLP = NULL; 1415 /* "+": stop on first non-option */ 1416 i = getopt32(argv, "+HLP"); 1417 if (i & (1<<0)) 1418 G.recurse_flags |= ACTION_FOLLOWLINKS_L0 | ACTION_DANGLING_OK; 1419 if (i & (1<<1)) 1420 G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK; 1421 /* -P is default and is ignored */ 1422 argv = past_HLP; /* same result as "argv += optind;" */ 1423 *past_HLP = saved; 1424 1258 1425 for (firstopt = 0; argv[firstopt]; firstopt++) { 1259 1426 if (argv[firstopt][0] == '-') … … 1298 1465 0) /* depth */ 1299 1466 ) { 1300 status = EXIT_FAILURE; 1301 } 1302 } 1303 1467 status |= EXIT_FAILURE; 1468 } 1469 } 1470 1471 IF_FEATURE_FIND_EXEC_PLUS(status |= flush_exec_plus();) 1304 1472 return status; 1305 1473 }
Note:
See TracChangeset
for help on using the changeset viewer.