X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;ds=sidebyside;f=libbb%2Frecursive_action.c;h=25a87b88e451a48b560d2d01d1c7c6bbf96188b8;hb=21b080daa8c180a43d10d6b3dee47134ef21e581;hp=0d6567ddab6a9e1865cbd0babf55d8778046669f;hpb=3b8fc1c582884d356df04b4984db3963bc129c48;p=oweals%2Fbusybox.git diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c index 0d6567dda..25a87b88e 100644 --- a/libbb/recursive_action.c +++ b/libbb/recursive_action.c @@ -11,7 +11,6 @@ #undef DEBUG_RECURS_ACTION - /* * Walk down all the directories under the specified * location, and do something (something specified @@ -23,16 +22,30 @@ * is so stinking huge. */ -static int true_action(const char *fileName, struct stat *statbuf, void* userData) +static int true_action(const char *fileName, struct stat *statbuf, void* userData, int depth) { return TRUE; } +/* fileAction return value of 0 on any file in directory will make + * recursive_action() return 0, but it doesn't stop directory traversal + * (fileAction/dirAction will be called on each file). + * + * if !depthFirst, dirAction return value of 0 (FALSE) or 2 (SKIP) + * prevents recursion 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. + * 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. + */ + int recursive_action(const char *fileName, int recurse, int followLinks, int depthFirst, - int (*fileAction) (const char *fileName, struct stat * statbuf, void* userData), - int (*dirAction) (const char *fileName, struct stat * statbuf, void* userData), - void* userData) + int (*fileAction)(const char *fileName, struct stat *statbuf, void* userData, int depth), + int (*dirAction)(const char *fileName, struct stat *statbuf, void* userData, int depth), + void* userData, + int depth) { struct stat statbuf; int status; @@ -53,21 +66,23 @@ int recursive_action(const char *fileName, return FALSE; } - if (!followLinks && (S_ISLNK(statbuf.st_mode))) { - return fileAction(fileName, &statbuf, userData); + /* If S_ISLNK(m), then we know that !S_ISDIR(m). + * Then we can skip checking first part: if it is true, then + * (!dir) is also true! */ + if ( /* (!followLinks && S_ISLNK(statbuf.st_mode)) || */ + !S_ISDIR(statbuf.st_mode) + ) { + return fileAction(fileName, &statbuf, userData, depth); } + /* It's a directory (or a link to one, and followLinks is set) */ + if (!recurse) { - if (S_ISDIR(statbuf.st_mode)) { - return dirAction(fileName, &statbuf, userData); - } + return dirAction(fileName, &statbuf, userData, depth); } - if (!S_ISDIR(statbuf.st_mode)) - return fileAction(fileName, &statbuf, userData); - if (!depthFirst) { - status = dirAction(fileName, &statbuf, userData); + status = dirAction(fileName, &statbuf, userData, depth); if (!status) { bb_perror_msg("%s", fileName); return FALSE; @@ -78,6 +93,10 @@ int recursive_action(const char *fileName, dir = opendir(fileName); if (!dir) { + /* findutils-4.1.20 reports this */ + /* (i.e. it doesn't silently return with exit code 1) */ + /* To trigger: "find -exec rm -rf {} \;" */ + bb_perror_msg("%s", fileName); return FALSE; } status = TRUE; @@ -88,14 +107,14 @@ int recursive_action(const char *fileName, if (nextFile == NULL) continue; if (!recursive_action(nextFile, TRUE, followLinks, depthFirst, - fileAction, dirAction, userData)) { + fileAction, dirAction, userData, depth+1)) { status = FALSE; } free(nextFile); } closedir(dir); if (depthFirst) { - if (!dirAction(fileName, &statbuf, userData)) { + if (!dirAction(fileName, &statbuf, userData, depth)) { bb_perror_msg("%s", fileName); return FALSE; }