From 8c35d65c43216bb840326ac7476a180e2ae36fe9 Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Fri, 27 Oct 2006 23:42:25 +0000 Subject: recursive_action: add depth param chmod: match coreutils versus following links --- libbb/recursive_action.c | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) (limited to 'libbb/recursive_action.c') diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c index 0d6567dda..ddaf9b896 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,23 @@ * 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; } +/* + * 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 +59,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; @@ -88,14 +96,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; } -- cgit v1.2.3