X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=findutils%2Ffind.c;h=6407c6c5afd2c623ba532975932e17db23de6c14;hb=9b70f197b4dd5be47c5d0d4479525efe012964ee;hp=d71c697827079c7d12e3c627beae89c33e528377;hpb=47cfbf32fd66563f8c4e09ad6cced6abfbe2fad5;p=oweals%2Fbusybox.git diff --git a/findutils/find.c b/findutils/find.c index d71c69782..6407c6c5a 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -9,13 +9,12 @@ * * Licensed under GPLv2, see file LICENSE in this source tree. */ - /* findutils-4.1.20: * * # find file.txt -exec 'echo {}' '{} {}' ';' * find: echo file.txt: No such file or directory * # find file.txt -exec 'echo' '{} {}' '; ' - * find: missing argument to `-exec' + * find: missing argument to '-exec' * # find file.txt -exec 'echo {}' '{} {}' ';' junk * find: paths must precede expression * # find file.txt -exec 'echo {}' '{} {}' ';' junk ';' @@ -44,7 +43,6 @@ * # find t z t z '(' -name '*t*' -o -name '*z*' ')' -o -print * (no output) */ - /* Testing script * ./busybox find "$@" | tee /tmp/bb_find * echo ================== @@ -52,189 +50,186 @@ * echo ================== * diff -u /tmp/std_find /tmp/bb_find && echo Identical */ - //config:config FIND -//config: bool "find" +//config: bool "find (14 kb)" //config: default y //config: help -//config: find is used to search your system to find specified files. +//config: find is used to search your system to find specified files. //config: //config:config FEATURE_FIND_PRINT0 //config: bool "Enable -print0: NUL-terminated output" //config: default y //config: depends on FIND //config: help -//config: Causes output names to be separated by a NUL character -//config: rather than a newline. This allows names that contain -//config: newlines and other whitespace to be more easily -//config: interpreted by other programs. +//config: Causes output names to be separated by a NUL character +//config: rather than a newline. This allows names that contain +//config: newlines and other whitespace to be more easily +//config: interpreted by other programs. //config: //config:config FEATURE_FIND_MTIME //config: bool "Enable -mtime: modified time matching" //config: default y //config: depends on FIND //config: help -//config: Allow searching based on the modification time of -//config: files, in days. +//config: Allow searching based on the modification time of +//config: files, in days. //config: //config:config FEATURE_FIND_MMIN //config: bool "Enable -mmin: modified time matching by minutes" //config: default y //config: depends on FIND //config: help -//config: Allow searching based on the modification time of -//config: files, in minutes. +//config: Allow searching based on the modification time of +//config: files, in minutes. //config: //config:config FEATURE_FIND_PERM //config: bool "Enable -perm: permissions matching" //config: default y //config: depends on FIND -//config: help -//config: Enable searching based on file permissions. //config: //config:config FEATURE_FIND_TYPE //config: bool "Enable -type: file type matching (file/dir/link/...)" //config: default y //config: depends on FIND //config: help -//config: Enable searching based on file type (file, -//config: directory, socket, device, etc.). +//config: Enable searching based on file type (file, +//config: directory, socket, device, etc.). +//config: +//config:config FEATURE_FIND_EXECUTABLE +//config: bool "Enable -executable: file is executable" +//config: default y +//config: depends on FIND //config: //config:config FEATURE_FIND_XDEV //config: bool "Enable -xdev: 'stay in filesystem'" //config: default y //config: depends on FIND -//config: help -//config: This option allows find to restrict searches to a single filesystem. //config: //config:config FEATURE_FIND_MAXDEPTH //config: bool "Enable -mindepth N and -maxdepth N" //config: default y //config: depends on FIND -//config: help -//config: This option enables -mindepth N and -maxdepth N option. //config: //config:config FEATURE_FIND_NEWER //config: bool "Enable -newer: compare file modification times" //config: default y //config: depends on FIND //config: help -//config: Support the 'find -newer' option for finding any files which have -//config: modification time that is more recent than the specified FILE. +//config: Support the 'find -newer' option for finding any files which have +//config: modification time that is more recent than the specified FILE. //config: //config:config FEATURE_FIND_INUM //config: bool "Enable -inum: inode number matching" //config: default y //config: depends on FIND -//config: help -//config: Support the 'find -inum' option for searching by inode number. //config: //config:config FEATURE_FIND_EXEC //config: bool "Enable -exec: execute commands" //config: default y //config: depends on FIND //config: help -//config: Support the 'find -exec' option for executing commands based upon -//config: the files matched. +//config: Support the 'find -exec' option for executing commands based upon +//config: the files matched. //config: //config:config FEATURE_FIND_EXEC_PLUS //config: bool "Enable -exec ... {} +" //config: default y //config: depends on FEATURE_FIND_EXEC //config: help -//config: Support the 'find -exec ... {} +' option for executing commands -//config: for all matched files at once. -//config: Without this option, -exec + is a synonym for -exec ; -//config: (IOW: it works correctly, but without expected speedup) +//config: Support the 'find -exec ... {} +' option for executing commands +//config: for all matched files at once. +//config: Without this option, -exec + is a synonym for -exec ; +//config: (IOW: it works correctly, but without expected speedup) //config: //config:config FEATURE_FIND_USER //config: bool "Enable -user: username/uid matching" //config: default y //config: depends on FIND -//config: help -//config: Support the 'find -user' option for searching by username or uid. //config: //config:config FEATURE_FIND_GROUP //config: bool "Enable -group: group/gid matching" //config: default y //config: depends on FIND -//config: help -//config: Support the 'find -group' option for searching by group name or gid. //config: //config:config FEATURE_FIND_NOT //config: bool "Enable the 'not' (!) operator" //config: default y //config: depends on FIND //config: help -//config: Support the '!' operator to invert the test results. -//config: If 'Enable full-blown desktop' is enabled, then will also support -//config: the non-POSIX notation '-not'. +//config: Support the '!' operator to invert the test results. +//config: If 'Enable full-blown desktop' is enabled, then will also support +//config: the non-POSIX notation '-not'. //config: //config:config FEATURE_FIND_DEPTH //config: bool "Enable -depth" //config: default y //config: depends on FIND //config: help -//config: Process each directory's contents before the directory itself. +//config: Process each directory's contents before the directory itself. //config: //config:config FEATURE_FIND_PAREN //config: bool "Enable parens in options" //config: default y //config: depends on FIND //config: help -//config: Enable usage of parens '(' to specify logical order of arguments. +//config: Enable usage of parens '(' to specify logical order of arguments. //config: //config:config FEATURE_FIND_SIZE //config: bool "Enable -size: file size matching" //config: default y //config: depends on FIND -//config: help -//config: Support the 'find -size' option for searching by file size. //config: //config:config FEATURE_FIND_PRUNE //config: bool "Enable -prune: exclude subdirectories" //config: default y //config: depends on FIND //config: help -//config: If the file is a directory, dont descend into it. Useful for -//config: exclusion .svn and CVS directories. +//config: If the file is a directory, don't descend into it. Useful for +//config: exclusion .svn and CVS directories. +//config: +//config:config FEATURE_FIND_QUIT +//config: bool "Enable -quit: exit" +//config: default y +//config: depends on FIND +//config: help +//config: If this action is reached, 'find' exits. //config: //config:config FEATURE_FIND_DELETE //config: bool "Enable -delete: delete files/dirs" //config: default y //config: depends on FIND && FEATURE_FIND_DEPTH //config: help -//config: Support the 'find -delete' option for deleting files and directories. -//config: WARNING: This option can do much harm if used wrong. Busybox will not -//config: try to protect the user from doing stupid things. Use with care. +//config: Support the 'find -delete' option for deleting files and directories. +//config: WARNING: This option can do much harm if used wrong. Busybox will not +//config: try to protect the user from doing stupid things. Use with care. //config: //config:config FEATURE_FIND_PATH //config: bool "Enable -path: match pathname with shell pattern" //config: default y //config: depends on FIND //config: help -//config: The -path option matches whole pathname instead of just filename. +//config: The -path option matches whole pathname instead of just filename. //config: //config:config FEATURE_FIND_REGEX //config: bool "Enable -regex: match pathname with regex" //config: default y //config: depends on FIND //config: help -//config: The -regex option matches whole pathname against regular expression. +//config: The -regex option matches whole pathname against regular expression. //config: //config:config FEATURE_FIND_CONTEXT //config: bool "Enable -context: security context matching" //config: default n //config: depends on FIND && SELINUX //config: help -//config: Support the 'find -context' option for matching security context. +//config: Support the 'find -context' option for matching security context. //config: //config:config FEATURE_FIND_LINKS //config: bool "Enable -links: link count matching" //config: default y //config: depends on FIND //config: help -//config: Support the 'find -links' option for matching number of links. +//config: Support the 'find -links' option for matching number of links. //applet:IF_FIND(APPLET_NOEXEC(find, find, BB_DIR_USR_BIN, BB_SUID_DROP, find)) @@ -280,7 +275,10 @@ //usage: "\n -regex PATTERN Match path to regex PATTERN" //usage: ) //usage: IF_FEATURE_FIND_TYPE( -//usage: "\n -type X File type is X (one of: f,d,l,b,c,...)" +//usage: "\n -type X File type is X (one of: f,d,l,b,c,s,p)" +//usage: ) +//usage: IF_FEATURE_FIND_EXECUTABLE( +//usage: "\n -executable File is executable" //usage: ) //usage: IF_FEATURE_FIND_PERM( //usage: "\n -perm MASK At least one mask bit (+MASK), all bits (-MASK)," @@ -335,6 +333,9 @@ //usage: IF_FEATURE_FIND_DELETE( //usage: "\n -delete Delete current file/directory. Turns on -depth option" //usage: ) +//usage: IF_FEATURE_FIND_QUIT( +//usage: "\n -quit Exit" +//usage: ) //usage: //usage:#define find_example_usage //usage: "$ find / -name passwd\n" @@ -382,6 +383,7 @@ IF_FEATURE_FIND_PATH( ACTS(path, const char *pattern; bool ipath;)) IF_FEATURE_FIND_REGEX( ACTS(regex, regex_t compiled_pattern;)) IF_FEATURE_FIND_PRINT0( ACTS(print0)) IF_FEATURE_FIND_TYPE( ACTS(type, int type_mask;)) +IF_FEATURE_FIND_EXECUTABLE(ACTS(executable)) IF_FEATURE_FIND_PERM( ACTS(perm, char perm_char; mode_t perm_mask;)) IF_FEATURE_FIND_MTIME( ACTS(mtime, char mtime_char; unsigned mtime_days;)) IF_FEATURE_FIND_MMIN( ACTS(mmin, char mmin_char; unsigned mmin_mins;)) @@ -392,6 +394,7 @@ IF_FEATURE_FIND_SIZE( ACTS(size, char size_char; off_t size;)) IF_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;)) IF_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;)) IF_FEATURE_FIND_PRUNE( ACTS(prune)) +IF_FEATURE_FIND_QUIT( ACTS(quit)) IF_FEATURE_FIND_DELETE( ACTS(delete)) IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; /* -exec ARGS */ @@ -419,6 +422,7 @@ struct globals { action ***actions; smallint need_print; smallint xdev_on; + smalluint exitstatus; recurse_flags_t recurse_flags; IF_FEATURE_FIND_EXEC_PLUS(unsigned max_argv_len;) } FIX_ALIASING; @@ -502,26 +506,54 @@ static char *strcpy_upcase(char *dst, const char *src) ACTF(name) { + int r; const char *tmp = bb_basename(fileName); - if (tmp != fileName && *tmp == '\0') { - /* "foo/bar/". Oh no... go back to 'b' */ - tmp--; - while (tmp != fileName && *--tmp != '/') - continue; - if (*tmp == '/') - tmp++; + /* GNU findutils: find DIR/ -name DIR + * prints "DIR/" (DIR// prints "DIR//" etc). + * Need to strip trailing "/". + * Such names can come only from top-level names, but + * we can't do this before recursive_action() call, + * since then "find FILE/ -name FILE" + * would also work (on non-directories), which is wrong. + */ + char *trunc_slash = NULL; + + if (*tmp == '\0') { + /* "foo/bar/[//...]" */ + while (tmp != fileName && tmp[-1] == '/') + tmp--; + if (tmp == fileName) { /* entire fileName is "//.."? */ + /* yes, convert "//..." to "/" + * Testcases: + * find / -maxdepth 1 -name /: prints / + * find // -maxdepth 1 -name /: prints // + * find / -maxdepth 1 -name //: prints nothing + * find // -maxdepth 1 -name //: prints nothing + */ + if (tmp[1]) + trunc_slash = (char*)tmp + 1; + } else { + /* no, it's "foo/bar/[//...]", go back to 'b' */ + trunc_slash = (char*)tmp; + while (tmp != fileName && tmp[-1] != '/') + tmp--; + } } + /* Was using FNM_PERIOD flag too, * but somewhere between 4.1.20 and 4.4.0 GNU find stopped using it. * find -name '*foo' should match .foo too: */ + if (trunc_slash) *trunc_slash = '\0'; #if FNM_CASEFOLD - return fnmatch(ap->pattern, tmp, (ap->iname ? FNM_CASEFOLD : 0)) == 0; + r = fnmatch(ap->pattern, tmp, (ap->iname ? FNM_CASEFOLD : 0)); #else if (ap->iname) tmp = strcpy_upcase(alloca(strlen(tmp) + 1), tmp); - return fnmatch(ap->pattern, tmp, 0) == 0; + r = fnmatch(ap->pattern, tmp, 0); #endif + if (trunc_slash) *trunc_slash = '/'; + return r == 0; } #if ENABLE_FEATURE_FIND_PATH @@ -555,6 +587,12 @@ ACTF(type) return ((statbuf->st_mode & S_IFMT) == ap->type_mask); } #endif +#if ENABLE_FEATURE_FIND_EXECUTABLE +ACTF(executable) +{ + return access(fileName, X_OK) == 0; +} +#endif #if ENABLE_FEATURE_FIND_PERM ACTF(perm) { @@ -763,6 +801,12 @@ ACTF(prune) return SKIP + TRUE; } #endif +#if ENABLE_FEATURE_FIND_QUIT +ACTF(quit) +{ + exit(G.exitstatus); +} +#endif #if ENABLE_FEATURE_FIND_DELETE ACTF(delete) { @@ -943,8 +987,10 @@ static action*** parse_params(char **argv) PARM_print , IF_FEATURE_FIND_PRINT0( PARM_print0 ,) IF_FEATURE_FIND_PRUNE( PARM_prune ,) + IF_FEATURE_FIND_QUIT( PARM_quit ,) IF_FEATURE_FIND_DELETE( PARM_delete ,) IF_FEATURE_FIND_EXEC( PARM_exec ,) + IF_FEATURE_FIND_EXECUTABLE(PARM_executable,) IF_FEATURE_FIND_PAREN( PARM_char_brace,) /* All options/actions starting from here require argument */ PARM_name , @@ -986,8 +1032,10 @@ static action*** parse_params(char **argv) "-print\0" IF_FEATURE_FIND_PRINT0( "-print0\0" ) IF_FEATURE_FIND_PRUNE( "-prune\0" ) + IF_FEATURE_FIND_QUIT( "-quit\0" ) IF_FEATURE_FIND_DELETE( "-delete\0" ) IF_FEATURE_FIND_EXEC( "-exec\0" ) + IF_FEATURE_FIND_EXECUTABLE("-executable\0") IF_FEATURE_FIND_PAREN( "(\0" ) /* All options/actions starting from here require argument */ "-name\0" @@ -1141,6 +1189,12 @@ static action*** parse_params(char **argv) (void) ALLOC_ACTION(prune); } #endif +#if ENABLE_FEATURE_FIND_QUIT + else if (parm == PARM_quit) { + dbg("%d", __LINE__); + (void) ALLOC_ACTION(quit); + } +#endif #if ENABLE_FEATURE_FIND_DELETE else if (parm == PARM_delete) { dbg("%d", __LINE__); @@ -1251,6 +1305,11 @@ static action*** parse_params(char **argv) dbg("created:type mask:%x", ap->type_mask); } #endif +#if ENABLE_FEATURE_FIND_EXECUTABLE + else if (parm == PARM_executable) { + (void) ALLOC_ACTION(executable); + } +#endif #if ENABLE_FEATURE_FIND_PERM /* -perm BITS File's mode bits are exactly BITS (octal or symbolic). * Symbolic modes use mode 0 as a point of departure. @@ -1390,7 +1449,7 @@ static action*** parse_params(char **argv) int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int find_main(int argc UNUSED_PARAM, char **argv) { - int i, firstopt, status = EXIT_SUCCESS; + int i, firstopt; char **past_HLP, *saved; INIT_G(); @@ -1464,10 +1523,10 @@ int find_main(int argc UNUSED_PARAM, char **argv) NULL, /* user data */ 0) /* depth */ ) { - status |= EXIT_FAILURE; + G.exitstatus |= EXIT_FAILURE; } } - IF_FEATURE_FIND_EXEC_PLUS(status |= flush_exec_plus();) - return status; + IF_FEATURE_FIND_EXEC_PLUS(G.exitstatus |= flush_exec_plus();) + return G.exitstatus; }