Also results in a binary size shrink by sharing more code :)

Without this a process having write access to a directory could trick
a more privilidged rm -r call to delete any file that the rm process
has access to.
From 6591d36bb46222489737a8384b51bfefc381d837 Mon Sep 17 00:00:00 2001
From: Sertonix <[email protected]>
Date: Tue, 9 Dec 2025 15:12:14 +0100
Subject: [PATCH 1/7] recursive_action: prevent file type confusion when files
 changed

It could for example unintentionally follow symlinks when a directory
is replaced with a symlink after the type check. Callers need to use
state->dirfd and state->baseName in some cases to make this effective.

function                                             old     new   delta
recursive_action1                                    418     721    +303
recursive_action                                     108     157     +49
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 352/0)             Total: 352 bytes
---
 include/libbb.h          |  2 ++
 libbb/recursive_action.c | 66 +++++++++++++++++++++++++++-------------
 2 files changed, 47 insertions(+), 21 deletions(-)

diff --git a/include/libbb.h b/include/libbb.h
index 17c9bc785..957f549de 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -536,6 +536,8 @@ typedef struct recursive_state {
 	unsigned flags;
 	unsigned depth;
 	void *userData;
+	char *fileName, *baseName;
+	int dirfd;
 	int FAST_FUNC (*fileAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf);
 	int FAST_FUNC  (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf);
 } recursive_state_t;
diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c
index b1c4bfad7..f168001be 100644
--- a/libbb/recursive_action.c
+++ b/libbb/recursive_action.c
@@ -15,10 +15,8 @@
  * location, and do something (something specified
  * by the fileAction and dirAction function pointers).
  *
- * Unfortunately, while nftw(3) could replace this and reduce
- * code size a bit, nftw() wasn't supported before GNU libc 2.1,
- * and so isn't sufficiently portable to take over since glibc2.1
- * is so stinking huge.
+ * Unfortunately, while nftw(3) works very similar it does not expose
+ * the file descriptors to allow safe usage.
  */
 
 static int FAST_FUNC true_action(struct recursive_state *state UNUSED_PARAM,
@@ -64,11 +62,11 @@ static int FAST_FUNC true_action(struct recursive_state *state UNUSED_PARAM,
  * 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir.
  */
 
-static int recursive_action1(recursive_state_t *state, const char *fileName)
+static int recursive_action1(recursive_state_t *state)
 {
 	struct stat statbuf;
 	unsigned follow;
-	int status;
+	int status, olddirfd = state->dirfd;
 	DIR *dir;
 	struct dirent *next;
 
@@ -76,17 +74,17 @@ static int recursive_action1(recursive_state_t *state, const char *fileName)
 	if (state->depth == 0)
 		follow = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0;
 	follow &= state->flags;
-	status = (follow ? stat : lstat)(fileName, &statbuf);
+	status = fstatat(state->dirfd, state->baseName, &statbuf, follow ? 0 : AT_SYMLINK_NOFOLLOW);
 	if (status < 0) {
 #ifdef DEBUG_RECURS_ACTION
 		bb_error_msg("status=%d flags=%x", status, state->flags);
 #endif
 		if ((state->flags & ACTION_DANGLING_OK)
 		 && errno == ENOENT
-		 && lstat(fileName, &statbuf) == 0
+		 && fstatat(state->dirfd, state->baseName, &statbuf, AT_SYMLINK_NOFOLLOW) == 0
 		) {
 			/* Dangling link */
-			return state->fileAction(state, fileName, &statbuf);
+			return state->fileAction(state, state->fileName, &statbuf);
 		}
 		goto done_nak_warn;
 	}
@@ -97,57 +95,75 @@ static int recursive_action1(recursive_state_t *state, const char *fileName)
 	if ( /* (!(state->flags & ACTION_FOLLOWLINKS) && S_ISLNK(statbuf.st_mode)) || */
 	 !S_ISDIR(statbuf.st_mode)
 	) {
-		return state->fileAction(state, fileName, &statbuf);
+		return state->fileAction(state, state->fileName, &statbuf);
 	}
 
 	/* It's a directory (or a link to one, and followLinks is set) */
 
 	if (!(state->flags & ACTION_RECURSE)) {
-		return state->dirAction(state, fileName, &statbuf);
+		return state->dirAction(state, state->fileName, &statbuf);
 	}
 
 	if (!(state->flags & ACTION_DEPTHFIRST)) {
-		status = state->dirAction(state, fileName, &statbuf);
+		status = state->dirAction(state, state->fileName, &statbuf);
 		if (status == FALSE)
 			goto done_nak_warn;
 		if (status == SKIP)
 			return TRUE;
 	}
 
-	dir = opendir(fileName);
+	state->dirfd = openat(olddirfd, state->baseName, O_RDONLY | O_DIRECTORY | (follow ? 0 : O_NOFOLLOW));
+	if (state->dirfd < 0)
+		goto done_nak_warn;
+	dir = fdopendir(state->dirfd);
 	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 {} \;" */
 		goto done_nak_warn;
 	}
+	state->dirfd = dirfd(dir);
 	status = TRUE;
 	while ((next = readdir(dir)) != NULL) {
-		char *nextFile;
+		size_t n1, n2, n3;
 		int s;
 
-		nextFile = concat_subpath_file(fileName, next->d_name);
-		if (nextFile == NULL)
+		if (DOT_OR_DOTDOT(next->d_name))
 			continue;
 
+		n1 = strlen(state->fileName);
+		n2 = (state->fileName[n1 - 1] != '/'); /* 1: "path has no trailing slash" */
+		n3 = strlen(next->d_name) + 1;
+
+		state->fileName = xrealloc(state->fileName, n1 + n2 + n3);
+		if (n2)
+			state->fileName[n1] = '/';
+		state->baseName = &state->fileName[n1+n2];
+		memcpy(state->baseName, next->d_name, n3);
+
 		/* process every file (NB: ACTION_RECURSE is set in flags) */
 		state->depth++;
-		s = recursive_action1(state, nextFile);
+		s = recursive_action1(state);
 		if (s == FALSE)
 			status = FALSE;
-		free(nextFile);
 		state->depth--;
 
+		state->fileName = xrealloc(state->fileName, n1 + 1);
+		state->fileName[n1] = '\0';
+		state->baseName = strrchr(state->fileName, '/');
+		state->baseName = state->baseName ? state->baseName + 1 : state->fileName;
+
 //#define RECURSE_RESULT_ABORT -1
 //		if (s == RECURSE_RESULT_ABORT) {
 //			closedir(dir);
 //			return s;
 //		}
 	}
+	state->dirfd = olddirfd;
 	closedir(dir);
 
 	if (state->flags & ACTION_DEPTHFIRST) {
-		if (!state->dirAction(state, fileName, &statbuf))
+		if (!state->dirAction(state, state->fileName, &statbuf))
 			goto done_nak_warn;
 	}
 
@@ -155,7 +171,9 @@ static int recursive_action1(recursive_state_t *state, const char *fileName)
 
  done_nak_warn:
 	if (!(state->flags & ACTION_QUIET))
-		bb_simple_perror_msg(fileName);
+		bb_simple_perror_msg(state->fileName);
+
+	state->dirfd = olddirfd;
 	return FALSE;
 }
 
@@ -165,6 +183,7 @@ int FAST_FUNC recursive_action(const char *fileName,
 		int FAST_FUNC  (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf),
 		void *userData)
 {
+	int ret;
 	/* Keeping a part of variables of recusive descent in a "state structure"
 	 * instead of passing ALL of them down as parameters of recursive_action1()
 	 * relieves register pressure, both in recursive_action1()
@@ -174,8 +193,13 @@ int FAST_FUNC recursive_action(const char *fileName,
 	state.flags = flags;
 	state.depth = 0;
 	state.userData = userData;
+	state.fileName = xstrdup(fileName);
+	state.baseName = state.fileName;
+	state.dirfd = xopen(".", O_RDONLY|O_DIRECTORY);
 	state.fileAction = fileAction ? fileAction : true_action;
 	state.dirAction  =  dirAction ?  dirAction : true_action;
 
-	return recursive_action1(&state, fileName);
+	ret = recursive_action1(&state);
+	free(state.fileName);
+	return ret;
 }
-- 
2.52.0

From ed4ebd243e8ea2e688a9ecb8f6a37bcc07200056 Mon Sep 17 00:00:00 2001
From: Sertonix <[email protected]>
Date: Tue, 9 Dec 2025 15:17:50 +0100
Subject: [PATCH 2/7] remove_file: switch to using recursive_action

Prevents recursive deletion to follow symlinks

function                                             old     new   delta
fileAction                                           200     337    +137
recursive_action                                     157     178     +21
recursive_action1                                    721     737     +16
.rodata                                           100908  100875     -33
remove_file                                          694      47    -647
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/2 up/down: 174/-680)         Total: -506 bytes
---
 coreutils/chown.c        |   2 +-
 findutils/find.c         |   4 +-
 findutils/grep.c         |   2 +-
 include/libbb.h          |   9 ++--
 libbb/recursive_action.c |  13 +++--
 libbb/remove_file.c      | 109 ++++++++++++---------------------------
 6 files changed, 49 insertions(+), 90 deletions(-)

diff --git a/coreutils/chown.c b/coreutils/chown.c
index 528a2a05a..c32812b8a 100644
--- a/coreutils/chown.c
+++ b/coreutils/chown.c
@@ -147,7 +147,7 @@ int chown_main(int argc UNUSED_PARAM, char **argv)
 		param.chown_func = lchown;
 	}
 
-	flags = ACTION_DEPTHFIRST; /* match coreutils order */
+	flags = ACTION_DEPTH_POST; /* match coreutils order */
 	if (OPT_RECURSE)
 		flags |= ACTION_RECURSE;
 	if (OPT_TRAVERSE_TOP)
diff --git a/findutils/find.c b/findutils/find.c
index 31c996988..582bc83bb 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -1307,7 +1307,7 @@ static action*** parse_params(char **argv)
 #if ENABLE_FEATURE_FIND_DEPTH
 		else if (parm == OPT_DEPTH) {
 			dbg("%d", __LINE__);
-			G.recurse_flags |= ACTION_DEPTHFIRST;
+			G.recurse_flags |= ACTION_DEPTH_POST;
 		}
 #endif
 /* Actions are grouped by operators
@@ -1369,7 +1369,7 @@ static action*** parse_params(char **argv)
 		else if (parm == PARM_delete) {
 			dbg("%d", __LINE__);
 			G.need_print = 0;
-			G.recurse_flags |= ACTION_DEPTHFIRST;
+			G.recurse_flags |= ACTION_DEPTH_POST;
 			(void) ALLOC_ACTION(delete);
 		}
 #endif
diff --git a/findutils/grep.c b/findutils/grep.c
index 0bd4898bc..e21bec885 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -697,7 +697,7 @@ static int grep_dir(const char *dir)
 		| ACTION_RECURSE
 		| ((option_mask32 & OPT_R) ? ACTION_FOLLOWLINKS : 0)
 		| ACTION_FOLLOWLINKS_L0 /* grep -r ... SYMLINK follows it */
-		| ACTION_DEPTHFIRST
+		| ACTION_DEPTH_POST
 		| 0,
 		/* fileAction= */ file_action_grep,
 		/* dirAction= */ NULL,
diff --git a/include/libbb.h b/include/libbb.h
index 957f549de..71199f1e2 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -527,9 +527,10 @@ enum {
 	ACTION_RECURSE        = (1 << 0),
 	ACTION_FOLLOWLINKS    = (1 << 1),
 	ACTION_FOLLOWLINKS_L0 = (1 << 2),
-	ACTION_DEPTHFIRST     = (1 << 3),
-	ACTION_QUIET          = (1 << 4),
-	ACTION_DANGLING_OK    = (1 << 5),
+	ACTION_DEPTH_PRE      = (1 << 3),
+	ACTION_DEPTH_POST     = (1 << 4),
+	ACTION_QUIET          = (1 << 5),
+	ACTION_DANGLING_OK    = (1 << 6),
 };
 typedef uint8_t recurse_flags_t;
 typedef struct recursive_state {
@@ -537,7 +538,7 @@ typedef struct recursive_state {
 	unsigned depth;
 	void *userData;
 	char *fileName, *baseName;
-	int dirfd;
+	int dirfd, state;
 	int FAST_FUNC (*fileAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf);
 	int FAST_FUNC  (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf);
 } recursive_state_t;
diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c
index f168001be..48182ded2 100644
--- a/libbb/recursive_action.c
+++ b/libbb/recursive_action.c
@@ -48,13 +48,13 @@ static int FAST_FUNC true_action(struct recursive_state *state UNUSED_PARAM,
  * on each file/subdirectory.
  * If any one of these calls returns 0, current recursive_action() returns 0.
  *
- * If !ACTION_DEPTHFIRST, dirAction is called before recurse.
+ * If ACTION_DEPTH_PRE, dirAction is called before recurse.
  * Return value of 0 (FALSE) is an error: prevents recursion,
  * the warning is printed (unless ACTION_QUIET) and recursive_action() returns 0.
  * Return value of 2 (SKIP) prevents recursion, instead recursive_action()
  * returns 1 (TRUE, no error).
  *
- * If ACTION_DEPTHFIRST, dirAction is called after recurse.
+ * If ACTION_DEPTH_POST, dirAction is called after recurse.
  * If it returns 0, the warning is printed and recursive_action() returns 0.
  *
  * ACTION_FOLLOWLINKS mainly controls handling of links to dirs.
@@ -104,7 +104,8 @@ static int recursive_action1(recursive_state_t *state)
 		return state->dirAction(state, state->fileName, &statbuf);
 	}
 
-	if (!(state->flags & ACTION_DEPTHFIRST)) {
+	if (state->flags & ACTION_DEPTH_PRE) {
+		state->state = ACTION_DEPTH_PRE;
 		status = state->dirAction(state, state->fileName, &statbuf);
 		if (status == FALSE)
 			goto done_nak_warn;
@@ -162,7 +163,8 @@ static int recursive_action1(recursive_state_t *state)
 	state->dirfd = olddirfd;
 	closedir(dir);
 
-	if (state->flags & ACTION_DEPTHFIRST) {
+	if (state->flags & ACTION_DEPTH_POST) {
+		state->state = ACTION_DEPTH_POST;
 		if (!state->dirAction(state, state->fileName, &statbuf))
 			goto done_nak_warn;
 	}
@@ -190,12 +192,13 @@ int FAST_FUNC recursive_action(const char *fileName,
 	 * and in every file/dirAction().
 	 */
 	recursive_state_t state;
-	state.flags = flags;
+	state.flags = flags | ((flags & (ACTION_DEPTH_PRE|ACTION_DEPTH_POST)) ? 0 : ACTION_DEPTH_PRE);
 	state.depth = 0;
 	state.userData = userData;
 	state.fileName = xstrdup(fileName);
 	state.baseName = state.fileName;
 	state.dirfd = xopen(".", O_RDONLY|O_DIRECTORY);
+	state.state = 0;
 	state.fileAction = fileAction ? fileAction : true_action;
 	state.dirAction  =  dirAction ?  dirAction : true_action;
 
diff --git a/libbb/remove_file.c b/libbb/remove_file.c
index 1505e6218..8721a1ea0 100644
--- a/libbb/remove_file.c
+++ b/libbb/remove_file.c
@@ -10,97 +10,52 @@
 
 /* Used from NOFORK applets. Must not allocate anything */
 
-int FAST_FUNC remove_file(const char *path, int flags)
+static int FAST_FUNC fileAction(struct recursive_state *state,
+		const char *fileName,
+		struct stat *statbuf)
 {
-	struct stat path_stat;
-
-	if (lstat(path, &path_stat) < 0) {
-		if (errno != ENOENT) {
-			bb_perror_msg("can't stat '%s'", path);
-			return -1;
-		}
-		if (!(flags & FILEUTILS_FORCE)) {
-			bb_perror_msg("can't remove '%s'", path);
-			return -1;
-		}
-		return 0;
-	}
-
-	if (S_ISDIR(path_stat.st_mode)) {
-		DIR *dp;
-		struct dirent *d;
-		int status = 0;
+	int flags = *((int*)state->userData);
+	int isdir = S_ISDIR(statbuf->st_mode);
 
-		if (!(flags & FILEUTILS_RECUR)) {
-			bb_error_msg("'%s' is a directory", path);
-			return -1;
+	if (!isdir || (state->state & ACTION_DEPTH_PRE)) {
+		if (isdir && !(flags & FILEUTILS_RECUR)) {
+			bb_error_msg("'%s' is a directory", fileName);
+			return FALSE;
 		}
 
-		if ((!(flags & FILEUTILS_FORCE) && access(path, W_OK) < 0 && isatty(0))
+		if ((!(flags & FILEUTILS_FORCE)
+		     && faccessat(state->dirfd, state->baseName, W_OK, 0) < 0
+		     && !S_ISLNK(statbuf->st_mode)
+		     && isatty(0))
 		 || (flags & FILEUTILS_INTERACTIVE)
 		) {
-			fprintf(stderr, "%s: descend into directory '%s'? ",
-					applet_name, path);
-			if (!bb_ask_y_confirmation())
-				return 0;
-		}
-
-		dp = opendir(path);
-		if (dp == NULL) {
-			return -1;
-		}
-
-		while ((d = readdir(dp)) != NULL) {
-			char *new_path;
-
-			new_path = concat_subpath_file(path, d->d_name);
-			if (new_path == NULL)
-				continue;
-			if (remove_file(new_path, flags) < 0)
-				status = -1;
-			free(new_path);
-		}
-		closedir(dp);
-
-		if (flags & FILEUTILS_INTERACTIVE) {
-			fprintf(stderr, "%s: remove directory '%s'? ",
-					applet_name, path);
+			fprintf(stderr, "%s: %s '%s'? ", isdir ? "remove" : "descend into directory", applet_name, state->fileName);
 			if (!bb_ask_y_confirmation())
-				return status;
-		}
-
-		if (status == 0 && rmdir(path) < 0) {
-			bb_perror_msg("can't remove '%s'", path);
-			return -1;
-		}
-
-		if (flags & FILEUTILS_VERBOSE) {
-			printf("removed directory: '%s'\n", path);
+				return isdir ? SKIP : TRUE;
 		}
 
-		return status;
+		if (isdir)
+			return TRUE;
 	}
 
-	/* !ISDIR */
-	if ((!(flags & FILEUTILS_FORCE)
-	     && access(path, W_OK) < 0
-	     && !S_ISLNK(path_stat.st_mode)
-	     && isatty(0))
-	 || (flags & FILEUTILS_INTERACTIVE)
-	) {
-		fprintf(stderr, "%s: remove '%s'? ", applet_name, path);
-		if (!bb_ask_y_confirmation())
-			return 0;
-	}
-
-	if (unlink(path) < 0) {
-		bb_perror_msg("can't remove '%s'", path);
-		return -1;
+	// FIXME isdir && status == 0
+	if (unlinkat(state->dirfd, state->baseName, isdir ? AT_REMOVEDIR : 0) < 0) {
+		bb_perror_msg("can't remove '%s'", fileName);
+		return FALSE;
 	}
 
 	if (flags & FILEUTILS_VERBOSE) {
-		printf("removed '%s'\n", path);
+		printf("removed %s'%s'\n", isdir ? "directory: " : "", fileName);
 	}
 
-	return 0;
+	return TRUE;
+}
+
+int FAST_FUNC remove_file(const char *path, int flags)
+{
+	int ret = recursive_action(path,
+		ACTION_QUIET|ACTION_DEPTH_PRE|ACTION_DEPTH_POST | ((flags & FILEUTILS_RECUR) ? ACTION_RECURSE : 0),
+		fileAction, fileAction, &flags
+	);
+	return ret == FALSE ? -1 : 0;
 }
-- 
2.52.0

From 21568dc0094669b1f90531a45a0afc97466333d5 Mon Sep 17 00:00:00 2001
From: Sertonix <[email protected]>
Date: Tue, 9 Dec 2025 14:30:54 +0100
Subject: [PATCH 3/7] archival/tar: use dirfd of recursive_action

function                                             old     new   delta
writeFileToTarball                                   497     542     +45
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 45/0)               Total: 45 bytes
---
 archival/tar.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/archival/tar.c b/archival/tar.c
index e7a74a547..9dca211f6 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -533,8 +533,9 @@ static int FAST_FUNC writeFileToTarball(struct recursive_state *state,
 	/* Is this a regular file? */
 	if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) {
 		/* open the file we want to archive, and make sure all is well */
-		inputFileFd = open_or_warn(fileName, O_RDONLY);
+		inputFileFd = openat(state->dirfd, state->baseName, O_RDONLY);
 		if (inputFileFd < 0) {
+			bb_perror_msg("can't open '%s'", fileName);
 			return FALSE; /* make recursive_action() return FALSE */
 		}
 	}
-- 
2.52.0

From 555282b5a48ed235435c27e20f20064d4e6c02fa Mon Sep 17 00:00:00 2001
From: Sertonix <[email protected]>
Date: Tue, 9 Dec 2025 14:39:48 +0100
Subject: [PATCH 4/7] chmod: use dirfd from recursive_action

function                                             old     new   delta
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/0 up/down: 0/0)                 Total: 0 bytes
---
 coreutils/chmod.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/coreutils/chmod.c b/coreutils/chmod.c
index 5832cc51b..5714ae595 100644
--- a/coreutils/chmod.c
+++ b/coreutils/chmod.c
@@ -75,7 +75,7 @@ static int FAST_FUNC fileAction(struct recursive_state *state,
 	/* match coreutils behavior */
 	if (state->depth == 0) {
 		/* statbuf holds lstat result, but we need stat (follow link) */
-		if (stat(fileName, statbuf))
+		if (fstatat(state->dirfd, state->baseName, statbuf, 0))
 			goto err;
 	} else { /* depth > 0: skip links */
 		if (S_ISLNK(statbuf->st_mode))
@@ -86,7 +86,7 @@ static int FAST_FUNC fileAction(struct recursive_state *state,
 	if (newmode == (mode_t)-1)
 		bb_error_msg_and_die("invalid mode '%s'", (char *)state->userData);
 
-	if (chmod(fileName, newmode) == 0) {
+	if (fchmodat(state->dirfd, state->baseName, newmode, AT_SYMLINK_NOFOLLOW) == 0) {
 		if (OPT_VERBOSE
 		 || (OPT_CHANGED
 		     && (statbuf->st_mode & 07777) != (newmode & 07777))
-- 
2.52.0

From 649cf83c8ccfa108feac68a4bad2af3a18342280 Mon Sep 17 00:00:00 2001
From: Sertonix <[email protected]>
Date: Tue, 9 Dec 2025 14:39:57 +0100
Subject: [PATCH 5/7] chown: use dirfd from recursive_action

function                                             old     new   delta
chown_main                                           220     215      -5
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-5)               Total: -5 bytes
---
 coreutils/chown.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/coreutils/chown.c b/coreutils/chown.c
index c32812b8a..11ee4693e 100644
--- a/coreutils/chown.c
+++ b/coreutils/chown.c
@@ -94,14 +94,12 @@ static const char chown_longopts[] ALIGN1 =
 	;
 #endif
 
-typedef int (*chown_fptr)(const char *, uid_t, gid_t);
-
 struct param_t {
 	struct bb_uidgid_t ugid;
-	chown_fptr chown_func;
+	int chown_flag;
 };
 
-static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM,
+static int FAST_FUNC fileAction(struct recursive_state *state,
 		const char *fileName, struct stat *statbuf)
 {
 #define param  (*(struct param_t*)state->userData)
@@ -109,7 +107,7 @@ static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM,
 	uid_t u = (param.ugid.uid == (uid_t)-1L) ? statbuf->st_uid : param.ugid.uid;
 	gid_t g = (param.ugid.gid == (gid_t)-1L) ? statbuf->st_gid : param.ugid.gid;
 
-	if (param.chown_func(fileName, u, g) == 0) {
+	if (fchownat(state->dirfd, state->baseName, u, g, param.chown_flag) == 0) {
 		if (OPT_VERBOSE
 		 || (OPT_CHANGED && (statbuf->st_uid != u || statbuf->st_gid != g))
 		) {
@@ -139,12 +137,12 @@ int chown_main(int argc UNUSED_PARAM, char **argv)
 	argv += optind;
 
 	/* This matches coreutils behavior (almost - see below) */
-	param.chown_func = chown;
+	param.chown_flag = 0;
 	if (OPT_NODEREF
 	/* || (OPT_RECURSE && !OPT_TRAVERSE_TOP): */
 	IF_DESKTOP( || (opt & (BIT_RECURSE|BIT_TRAVERSE_TOP)) == BIT_RECURSE)
 	) {
-		param.chown_func = lchown;
+		param.chown_flag = AT_SYMLINK_NOFOLLOW;
 	}
 
 	flags = ACTION_DEPTH_POST; /* match coreutils order */
-- 
2.52.0

From f9950912bc8053c27da27b5a0e6652daa0c58177 Mon Sep 17 00:00:00 2001
From: Sertonix <[email protected]>
Date: Tue, 9 Dec 2025 14:42:26 +0100
Subject: [PATCH 6/7] run_parts: use dirfd from recursive_action

function                                             old     new   delta
act                                                  218     226      +8
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/0 up/down: 8/0)                 Total: 8 bytes
---
 debianutils/run_parts.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c
index 780df3e96..cff7a0390 100644
--- a/debianutils/run_parts.c
+++ b/debianutils/run_parts.c
@@ -151,7 +151,7 @@ static int FAST_FUNC act(struct recursive_state *state,
 	if (state->depth == 1
 	 && (  !(statbuf->st_mode & (S_IFREG | S_IFLNK))
 	    || invalid_name(file)
-	    || (!(option_mask32 & OPT_l) && access(file, X_OK) != 0))
+	    || (!(option_mask32 & OPT_l) && faccessat(state->dirfd, state->baseName, W_OK, 0) != 0))
 	) {
 		return SKIP;
 	}
-- 
2.52.0

From 9fd9c723ba0fd96f3de96c49b297cc1b4b0afef5 Mon Sep 17 00:00:00 2001
From: Sertonix <[email protected]>
Date: Tue, 9 Dec 2025 17:24:43 +0100
Subject: [PATCH 7/7] recursive_action: remove fileName argument from
 fileAction/dirAction

function                                             old     new   delta
skip_dir                                             176     180      +4
uuidcache_check_device                               112     114      +2
fileAction                                           337     338      +1
dir_act                                              275     276      +1
add_to_prg_cache_if_socket                           276     277      +1
add_to_dirlist                                        77      78      +1
act                                                  226     221      -5
writeFileToTarball                                   542     528     -14
recursive_action1                                    737     721     -16
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 6/3 up/down: 10/-35)            Total: -25 bytes
---
 archival/tar.c                     | 15 +++++++--------
 coreutils/chmod.c                  |  5 ++---
 coreutils/chown.c                  |  6 +++---
 debianutils/run_parts.c            |  6 +++---
 editors/diff.c                     |  8 +++-----
 findutils/find.c                   |  7 +++----
 findutils/grep.c                   | 13 ++++++-------
 include/libbb.h                    |  8 ++++----
 libbb/recursive_action.c           | 15 +++++++--------
 libbb/remove_file.c                |  7 +++----
 modutils/depmod.c                  |  9 ++++-----
 modutils/modprobe-small.c          |  3 +--
 modutils/modprobe.c                |  5 ++---
 networking/netstat.c               |  8 +++-----
 selinux/chcon.c                    | 19 +++++++++----------
 selinux/setfiles.c                 |  5 ++---
 util-linux/lspci.c                 |  5 ++---
 util-linux/lsusb.c                 |  9 ++++-----
 util-linux/mdev.c                  |  8 +++-----
 util-linux/volume_id/get_devname.c |  7 +++----
 20 files changed, 74 insertions(+), 94 deletions(-)

diff --git a/archival/tar.c b/archival/tar.c
index 9dca211f6..30298e5d7 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -472,17 +472,16 @@ static int exclude_file(const llist_t *excluded_files, const char *file)
 # endif
 
 static int FAST_FUNC writeFileToTarball(struct recursive_state *state,
-		const char *fileName,
 		struct stat *statbuf)
 {
 	struct TarBallInfo *tbInfo = (struct TarBallInfo *) state->userData;
 	const char *header_name;
 	int inputFileFd = -1;
 
-	DBG("writeFileToTarball('%s')", fileName);
+	DBG("writeFileToTarball('%s')", state->fileName);
 
 	/* Strip leading '/' and such (must be before memorizing hardlink's name) */
-	header_name = skip_unsafe_prefix(fileName);
+	header_name = skip_unsafe_prefix(state->fileName);
 
 	if (header_name[0] == '\0')
 		return TRUE;
@@ -492,7 +491,7 @@ static int FAST_FUNC writeFileToTarball(struct recursive_state *state,
 
 	/* It is against the rules to archive a socket */
 	if (S_ISSOCK(statbuf->st_mode)) {
-		bb_error_msg("%s: socket ignored", fileName);
+		bb_error_msg("%s: socket ignored", state->fileName);
 		return TRUE;
 	}
 
@@ -519,7 +518,7 @@ static int FAST_FUNC writeFileToTarball(struct recursive_state *state,
 	if (tbInfo->tarFileStatBuf.st_dev == statbuf->st_dev
 	 && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino
 	) {
-		bb_error_msg("%s: file is the archive; skipping", fileName);
+		bb_error_msg("%s: file is the archive; skipping", state->fileName);
 		return TRUE;
 	}
 
@@ -535,13 +534,13 @@ static int FAST_FUNC writeFileToTarball(struct recursive_state *state,
 		/* open the file we want to archive, and make sure all is well */
 		inputFileFd = openat(state->dirfd, state->baseName, O_RDONLY);
 		if (inputFileFd < 0) {
-			bb_perror_msg("can't open '%s'", fileName);
+			bb_perror_msg("can't open '%s'", state->fileName);
 			return FALSE; /* make recursive_action() return FALSE */
 		}
 	}
 
 	/* Add an entry to the tarball */
-	if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) {
+	if (writeTarHeader(tbInfo, header_name, state->fileName, statbuf) == FALSE) {
 		return FALSE; /* make recursive_action() return FALSE */
 	}
 
@@ -558,7 +557,7 @@ static int FAST_FUNC writeFileToTarball(struct recursive_state *state,
 		////off_t readSize;
 		////readSize = bb_copyfd_size(inputFileFd, tbInfo->tarFd, statbuf->st_size);
 		////if (readSize != statbuf->st_size && readSize >= 0) {
-		////	bb_error_msg_and_die("short read from %s, aborting", fileName);
+		////	bb_error_msg_and_die("short read from %s, aborting", state->fileName);
 		////}
 
 		/* Check that file did not grow in between? */
diff --git a/coreutils/chmod.c b/coreutils/chmod.c
index 5714ae595..c2a4961f2 100644
--- a/coreutils/chmod.c
+++ b/coreutils/chmod.c
@@ -67,7 +67,6 @@
  */
 
 static int FAST_FUNC fileAction(struct recursive_state *state,
-		const char *fileName,
 		struct stat *statbuf)
 {
 	mode_t newmode;
@@ -92,14 +91,14 @@ static int FAST_FUNC fileAction(struct recursive_state *state,
 		     && (statbuf->st_mode & 07777) != (newmode & 07777))
 		) {
 			char modestr[12];
-			printf("mode of '%s' changed to %04o (%s)\n", fileName,
+			printf("mode of '%s' changed to %04o (%s)\n", state->fileName,
 				newmode & 07777, bb_mode_string(modestr, newmode)+1);
 		}
 		return TRUE;
 	}
  err:
 	if (!OPT_QUIET)
-		bb_simple_perror_msg(fileName);
+		bb_simple_perror_msg(state->fileName);
 	return FALSE;
 }
 
diff --git a/coreutils/chown.c b/coreutils/chown.c
index 11ee4693e..720364383 100644
--- a/coreutils/chown.c
+++ b/coreutils/chown.c
@@ -100,7 +100,7 @@ struct param_t {
 };
 
 static int FAST_FUNC fileAction(struct recursive_state *state,
-		const char *fileName, struct stat *statbuf)
+		struct stat *statbuf)
 {
 #define param  (*(struct param_t*)state->userData)
 #define opt option_mask32
@@ -112,12 +112,12 @@ static int FAST_FUNC fileAction(struct recursive_state *state,
 		 || (OPT_CHANGED && (statbuf->st_uid != u || statbuf->st_gid != g))
 		) {
 			printf("changed ownership of '%s' to %u:%u\n",
-					fileName, (unsigned)u, (unsigned)g);
+					state->fileName, (unsigned)u, (unsigned)g);
 		}
 		return TRUE;
 	}
 	if (!OPT_QUIET)
-		bb_simple_perror_msg(fileName);
+		bb_simple_perror_msg(state->fileName);
 	return FALSE;
 #undef opt
 #undef param
diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c
index cff7a0390..edb06e050 100644
--- a/debianutils/run_parts.c
+++ b/debianutils/run_parts.c
@@ -143,21 +143,21 @@ static int bb_alphasort(const void *p1, const void *p2)
 }
 
 static int FAST_FUNC act(struct recursive_state *state,
-		const char *file, struct stat *statbuf)
+		struct stat *statbuf)
 {
 	if (state->depth == 0)
 		return TRUE;
 
 	if (state->depth == 1
 	 && (  !(statbuf->st_mode & (S_IFREG | S_IFLNK))
-	    || invalid_name(file)
+	    || invalid_name(state->fileName)
 	    || (!(option_mask32 & OPT_l) && faccessat(state->dirfd, state->baseName, W_OK, 0) != 0))
 	) {
 		return SKIP;
 	}
 
 	names = xrealloc_vector(names, 4, cur);
-	names[cur++] = xstrdup(file);
+	names[cur++] = xstrdup(state->fileName);
 	/*names[cur] = NULL; - xrealloc_vector did it */
 
 	return TRUE;
diff --git a/editors/diff.c b/editors/diff.c
index 6f4ed9712..862e132b8 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -804,11 +804,10 @@ struct dlist {
 
 /* This function adds a filename to dl, the directory listing. */
 static int FAST_FUNC add_to_dirlist(struct recursive_state *state,
-		const char *filename,
 		struct stat *sb UNUSED_PARAM)
 {
 	struct dlist *const l = state->userData;
-	const char *file = filename + l->len;
+	const char *file = state->fileName + l->len;
 	while (*file == '/')
 		file++;
 	l->dl = xrealloc_vector(l->dl, 6, l->e);
@@ -821,11 +820,10 @@ static int FAST_FUNC add_to_dirlist(struct recursive_state *state,
  * to the list and prevents recursive_action from recursing into it.
  */
 static int FAST_FUNC skip_dir(struct recursive_state *state,
-		const char *filename,
 		struct stat *sb)
 {
 	if (!(option_mask32 & FLAG(r)) && state->depth) {
-		add_to_dirlist(state, filename, sb);
+		add_to_dirlist(state, sb);
 		return SKIP;
 	}
 	if (!(option_mask32 & FLAG(N))) {
@@ -834,7 +832,7 @@ static int FAST_FUNC skip_dir(struct recursive_state *state,
 		 * Testcase: diff -r /tmp /
 		 * (it would recurse deep into /proc without this code) */
 		struct dlist *const l = state->userData;
-		filename += l->len;
+		char *filename = state->fileName + l->len;
 		if (filename[0]) {
 			struct stat osb;
 			char *othername = concat_path_file(G.other_dir, filename);
diff --git a/findutils/find.c b/findutils/find.c
index 582bc83bb..443b02849 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -1011,7 +1011,6 @@ ACTF(links)
 
 static int FAST_FUNC fileAction(
 		struct recursive_state *state IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM),
-		const char *fileName,
 		struct stat *statbuf)
 {
 	int r;
@@ -1024,7 +1023,7 @@ static int FAST_FUNC fileAction(
 			if (G.xdev_dev[i] == statbuf->st_dev)
 				goto found;
 		}
-		//bb_error_msg("'%s': not same fs", fileName);
+		//bb_error_msg("'%s': not same fs", state->fileName);
 		same_fs = 0;
  found: ;
 	}
@@ -1040,10 +1039,10 @@ static int FAST_FUNC fileAction(
 		return SKIP; /* stop recursing */
 #endif
 
-	r = exec_actions(G.actions, fileName, statbuf);
+	r = exec_actions(G.actions, state->fileName, statbuf);
 	/* Had no explicit -print[0] or -exec? then print */
 	if ((r & TRUE) && G.need_print)
-		puts(fileName);
+		puts(state->fileName);
 
 #if ENABLE_FEATURE_FIND_MAXDEPTH
 	if (S_ISDIR(statbuf->st_mode)) {
diff --git a/findutils/grep.c b/findutils/grep.c
index e21bec885..6545040fb 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -654,8 +654,7 @@ static void load_pattern_list(llist_t **lst, char *pattern)
 		llist_add_to(lst, new_grep_list_data(p, 0));
 }
 
-static int FAST_FUNC file_action_grep(struct recursive_state *state UNUSED_PARAM,
-		const char *filename,
+static int FAST_FUNC file_action_grep(struct recursive_state *state,
 		struct stat *statbuf)
 {
 	FILE *file;
@@ -668,23 +667,23 @@ static int FAST_FUNC file_action_grep(struct recursive_state *state UNUSED_PARAM
 		struct stat sb;
 		if (!(option_mask32 & OPT_R))
 			return 0;
-		if (stat(filename, &sb) != 0) {
+		if (stat(state->fileName, &sb) != 0) {
 			if (!SUPPRESS_ERR_MSGS)
-				bb_simple_perror_msg(filename);
+				bb_simple_perror_msg(state->fileName);
 			return 0;
 		}
 		if (S_ISDIR(sb.st_mode))
 			return 1;
 	}
 
-	file = fopen_for_read(filename);
+	file = fopen_for_read(state->fileName);
 	if (file == NULL) {
 		if (!SUPPRESS_ERR_MSGS)
-			bb_simple_perror_msg(filename);
+			bb_simple_perror_msg(state->fileName);
 		open_errors = 1;
 		return 0;
 	}
-	cur_file = filename;
+	cur_file = state->fileName;
 	*(int*)state->userData |= grep_file(file);
 	fclose(file);
 	return 1;
diff --git a/include/libbb.h b/include/libbb.h
index 71199f1e2..40043dfb3 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -539,12 +539,12 @@ typedef struct recursive_state {
 	void *userData;
 	char *fileName, *baseName;
 	int dirfd, state;
-	int FAST_FUNC (*fileAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf);
-	int FAST_FUNC  (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf);
+	int FAST_FUNC (*fileAction)(struct recursive_state *state, struct stat* statbuf);
+	int FAST_FUNC  (*dirAction)(struct recursive_state *state, struct stat* statbuf);
 } recursive_state_t;
 int recursive_action(const char *fileName, unsigned flags,
-	int FAST_FUNC (*fileAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf),
-	int FAST_FUNC  (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf),
+	int FAST_FUNC (*fileAction)(struct recursive_state *state, struct stat* statbuf),
+	int FAST_FUNC  (*dirAction)(struct recursive_state *state, struct stat* statbuf),
 	void *userData
 ) FAST_FUNC;
 
diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c
index 48182ded2..f4034121b 100644
--- a/libbb/recursive_action.c
+++ b/libbb/recursive_action.c
@@ -20,7 +20,6 @@
  */
 
 static int FAST_FUNC true_action(struct recursive_state *state UNUSED_PARAM,
-		const char *fileName UNUSED_PARAM,
 		struct stat *statbuf UNUSED_PARAM)
 {
 	return TRUE;
@@ -84,7 +83,7 @@ static int recursive_action1(recursive_state_t *state)
 		 && fstatat(state->dirfd, state->baseName, &statbuf, AT_SYMLINK_NOFOLLOW) == 0
 		) {
 			/* Dangling link */
-			return state->fileAction(state, state->fileName, &statbuf);
+			return state->fileAction(state, &statbuf);
 		}
 		goto done_nak_warn;
 	}
@@ -95,18 +94,18 @@ static int recursive_action1(recursive_state_t *state)
 	if ( /* (!(state->flags & ACTION_FOLLOWLINKS) && S_ISLNK(statbuf.st_mode)) || */
 	 !S_ISDIR(statbuf.st_mode)
 	) {
-		return state->fileAction(state, state->fileName, &statbuf);
+		return state->fileAction(state, &statbuf);
 	}
 
 	/* It's a directory (or a link to one, and followLinks is set) */
 
 	if (!(state->flags & ACTION_RECURSE)) {
-		return state->dirAction(state, state->fileName, &statbuf);
+		return state->dirAction(state, &statbuf);
 	}
 
 	if (state->flags & ACTION_DEPTH_PRE) {
 		state->state = ACTION_DEPTH_PRE;
-		status = state->dirAction(state, state->fileName, &statbuf);
+		status = state->dirAction(state, &statbuf);
 		if (status == FALSE)
 			goto done_nak_warn;
 		if (status == SKIP)
@@ -165,7 +164,7 @@ static int recursive_action1(recursive_state_t *state)
 
 	if (state->flags & ACTION_DEPTH_POST) {
 		state->state = ACTION_DEPTH_POST;
-		if (!state->dirAction(state, state->fileName, &statbuf))
+		if (!state->dirAction(state, &statbuf))
 			goto done_nak_warn;
 	}
 
@@ -181,8 +180,8 @@ static int recursive_action1(recursive_state_t *state)
 
 int FAST_FUNC recursive_action(const char *fileName,
 		unsigned flags,
-		int FAST_FUNC (*fileAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf),
-		int FAST_FUNC  (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf),
+		int FAST_FUNC (*fileAction)(struct recursive_state *state, struct stat* statbuf),
+		int FAST_FUNC  (*dirAction)(struct recursive_state *state, struct stat* statbuf),
 		void *userData)
 {
 	int ret;
diff --git a/libbb/remove_file.c b/libbb/remove_file.c
index 8721a1ea0..8a8d3b939 100644
--- a/libbb/remove_file.c
+++ b/libbb/remove_file.c
@@ -11,7 +11,6 @@
 /* Used from NOFORK applets. Must not allocate anything */
 
 static int FAST_FUNC fileAction(struct recursive_state *state,
-		const char *fileName,
 		struct stat *statbuf)
 {
 	int flags = *((int*)state->userData);
@@ -19,7 +18,7 @@ static int FAST_FUNC fileAction(struct recursive_state *state,
 
 	if (!isdir || (state->state & ACTION_DEPTH_PRE)) {
 		if (isdir && !(flags & FILEUTILS_RECUR)) {
-			bb_error_msg("'%s' is a directory", fileName);
+			bb_error_msg("'%s' is a directory", state->fileName);
 			return FALSE;
 		}
 
@@ -40,12 +39,12 @@ static int FAST_FUNC fileAction(struct recursive_state *state,
 
 	// FIXME isdir && status == 0
 	if (unlinkat(state->dirfd, state->baseName, isdir ? AT_REMOVEDIR : 0) < 0) {
-		bb_perror_msg("can't remove '%s'", fileName);
+		bb_perror_msg("can't remove '%s'", state->fileName);
 		return FALSE;
 	}
 
 	if (flags & FILEUTILS_VERBOSE) {
-		printf("removed %s'%s'\n", isdir ? "directory: " : "", fileName);
+		printf("removed %s'%s'\n", isdir ? "directory: " : "", state->fileName);
 	}
 
 	return TRUE;
diff --git a/modutils/depmod.c b/modutils/depmod.c
index bb42bbefe..4118dc215 100644
--- a/modutils/depmod.c
+++ b/modutils/depmod.c
@@ -33,7 +33,6 @@
  */
 
 static int FAST_FUNC parse_module(struct recursive_state *state,
-		const char *fname,
 		struct stat *sb UNUSED_PARAM)
 {
 	module_db *modules = state->userData;
@@ -43,13 +42,13 @@ static int FAST_FUNC parse_module(struct recursive_state *state,
 	/* Arbitrary. Was sb->st_size, but that breaks .gz etc */
 	size_t len = (64*1024*1024 - 4096);
 
-	if (strrstr(fname, ".ko") == NULL)
+	if (strrstr(state->fileName, ".ko") == NULL)
 		return TRUE;
 
-	image = xmalloc_open_zipped_read_close(fname, &len);
+	image = xmalloc_open_zipped_read_close(state->fileName, &len);
 
-	e = moddb_get_or_create(modules, bb_get_last_path_component_nostrip(fname));
-	e->name = xstrdup(fname + 2); /* skip "./" */
+	e = moddb_get_or_create(modules, bb_get_last_path_component_nostrip(state->fileName));
+	e->name = xstrdup(state->fileName + 2); /* skip "./" */
 
 	for (ptr = image; ptr < image + len - 10; ptr++) {
 		if (is_prefixed_with(ptr, "depends=")) {
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c
index 31a215a29..2928985d0 100644
--- a/modutils/modprobe-small.c
+++ b/modutils/modprobe-small.c
@@ -379,7 +379,6 @@ static int parse_module(module_info *info, const char *pathname)
 }
 
 static FAST_FUNC int fileAction(struct recursive_state *state,
-		const char *pathname,
 		struct stat *sb UNUSED_PARAM)
 {
 	const char *modname_to_match = state->userData;
@@ -388,7 +387,7 @@ static FAST_FUNC int fileAction(struct recursive_state *state,
 	bool is_remove = (ENABLE_RMMOD && ONLY_APPLET)
 		|| ((ENABLE_RMMOD || ENABLE_MODPROBE) && (option_mask32 & OPT_r));
 
-	pathname += 2; /* skip "./" */
+	char *pathname = state->fileName + 2; /* skip "./" */
 	fname = bb_get_last_path_component_nostrip(pathname);
 	if (!strrstr(fname, ".ko")) {
 		dbg1_error_msg("'%s' is not a module", pathname);
diff --git a/modutils/modprobe.c b/modutils/modprobe.c
index f890abe53..f9cec8241 100644
--- a/modutils/modprobe.c
+++ b/modutils/modprobe.c
@@ -236,7 +236,6 @@ static void add_probe(const char *name)
 }
 
 static int FAST_FUNC config_file_action(struct recursive_state *state,
-		const char *filename,
 		struct stat *statbuf UNUSED_PARAM)
 {
 	char *tokens[3];
@@ -246,7 +245,7 @@ static int FAST_FUNC config_file_action(struct recursive_state *state,
 	const char *base;
 
 	/* Skip files that begin with a "." */
-	base = bb_basename(filename);
+	base = bb_basename(state->fileName);
 	if (base[0] == '.')
 		goto error;
 
@@ -268,7 +267,7 @@ static int FAST_FUNC config_file_action(struct recursive_state *state,
 			goto error;
 	}
 
-	p = config_open2(filename, fopen_for_read);
+	p = config_open2(state->fileName, fopen_for_read);
 	if (p == NULL) {
 		rc = FALSE;
 		goto error;
diff --git a/networking/netstat.c b/networking/netstat.c
index 807800a62..f6dbff1ca 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -273,13 +273,12 @@ static long extract_socket_inode(const char *lname)
 }
 
 static int FAST_FUNC add_to_prg_cache_if_socket(struct recursive_state *state,
-		const char *fileName,
 		struct stat *statbuf UNUSED_PARAM)
 {
 	char *linkname;
 	long inode;
 
-	linkname = xmalloc_readlink(fileName);
+	linkname = xmalloc_readlink(state->fileName);
 	if (linkname != NULL) {
 		inode = extract_socket_inode(linkname);
 		free(linkname);
@@ -292,7 +291,6 @@ static int FAST_FUNC add_to_prg_cache_if_socket(struct recursive_state *state,
 }
 
 static int FAST_FUNC dir_act(struct recursive_state *state,
-		const char *fileName,
 		struct stat *statbuf UNUSED_PARAM)
 {
 	const char *pid;
@@ -304,11 +302,11 @@ static int FAST_FUNC dir_act(struct recursive_state *state,
 	if (state->depth == 0) /* "/proc" itself */
 		return TRUE; /* continue looking one level below /proc */
 
-	pid = fileName + sizeof("/proc/")-1; /* point after "/proc/" */
+	pid = state->fileName + sizeof("/proc/")-1; /* point after "/proc/" */
 	if (!isdigit(pid[0])) /* skip /proc entries which aren't processes */
 		return SKIP;
 
-	len = snprintf(proc_pid_fname, sizeof(proc_pid_fname), "%s/cmdline", fileName);
+	len = snprintf(proc_pid_fname, sizeof(proc_pid_fname), "%s/cmdline", state->fileName);
 	n = open_read_close(proc_pid_fname, cmdline_buf, sizeof(cmdline_buf) - 1);
 	if (n < 0)
 		return FALSE;
diff --git a/selinux/chcon.c b/selinux/chcon.c
index e1778a36a..39b362847 100644
--- a/selinux/chcon.c
+++ b/selinux/chcon.c
@@ -63,7 +63,6 @@ static char *range = NULL;
 static char *specified_context = NULL;
 
 static int FAST_FUNC change_filedir_context(struct recursive_state *state UNUSED_PARAM,
-		const char *fname,
 		struct stat *stbuf UNUSED_PARAM)
 {
 	context_t context = NULL;
@@ -73,18 +72,18 @@ static int FAST_FUNC change_filedir_context(struct recursive_state *state UNUSED
 	int status = 0;
 
 	if (option_mask32 & OPT_NODEREFERENCE) {
-		status = lgetfilecon(fname, &file_context);
+		status = lgetfilecon(state->fileName, &file_context);
 	} else {
-		status = getfilecon(fname, &file_context);
+		status = getfilecon(state->fileName, &file_context);
 	}
 	if (status < 0 && errno != ENODATA) {
 		if ((option_mask32 & OPT_QUIET) == 0)
-			bb_error_msg("can't obtain security context: %s", fname);
+			bb_error_msg("can't obtain security context: %s", state->fileName);
 		goto skip;
 	}
 
 	if (file_context == NULL && specified_context == NULL) {
-		bb_error_msg("can't apply partial context to unlabeled file %s", fname);
+		bb_error_msg("can't apply partial context to unlabeled file %s", state->fileName);
 		goto skip;
 	}
 
@@ -113,25 +112,25 @@ static int FAST_FUNC change_filedir_context(struct recursive_state *state UNUSED
 		int fail;
 
 		if (option_mask32 & OPT_NODEREFERENCE) {
-			fail = lsetfilecon(fname, context_string);
+			fail = lsetfilecon(state->fileName, context_string);
 		} else {
-			fail = setfilecon(fname, context_string);
+			fail = setfilecon(state->fileName, context_string);
 		}
 		if ((option_mask32 & OPT_VERBOSE) || ((option_mask32 & OPT_CHANHES) && !fail)) {
 			printf(!fail
 				? "context of %s changed to %s\n"
 				: "can't change context of %s to %s\n",
-				fname, context_string);
+				state->fileName, context_string);
 		}
 		if (!fail) {
 			rc = TRUE;
 		} else if ((option_mask32 & OPT_QUIET) == 0) {
 			bb_error_msg("can't change context of %s to %s",
-					fname, context_string);
+					state->fileName, context_string);
 		}
 	} else {
 		if (option_mask32 & OPT_VERBOSE) {
-			printf("context of %s retained as %s\n", fname, context_string);
+			printf("context of %s retained as %s\n", state->fileName, context_string);
 		}
 		rc = TRUE;
 	}
diff --git a/selinux/setfiles.c b/selinux/setfiles.c
index 70e68a666..a43e06bfd 100644
--- a/selinux/setfiles.c
+++ b/selinux/setfiles.c
@@ -463,8 +463,7 @@ static int restore(const char *file)
  * This function is called by recursive_action on each file during
  * the directory traversal.
  */
-static int FAST_FUNC apply_spec(struct recursive_state *state UNUSED_PARAM,
-		const char *file,
+static int FAST_FUNC apply_spec(struct recursive_state *state,
 		struct stat *sb)
 {
 	if (!follow_mounts) {
@@ -473,7 +472,7 @@ static int FAST_FUNC apply_spec(struct recursive_state *state UNUSED_PARAM,
 			return SKIP;
 		}
 	}
-	errors |= restore(file);
+	errors |= restore(state->file);
 	if (abort_on_error && errors)
 		return FALSE;
 	return TRUE;
diff --git a/util-linux/lspci.c b/util-linux/lspci.c
index 25be23a01..cc8d677bf 100644
--- a/util-linux/lspci.c
+++ b/util-linux/lspci.c
@@ -37,8 +37,7 @@ enum {
 /*
  * PCI_SLOT_NAME PCI_CLASS: PCI_VID:PCI_DID [PCI_SUBSYS_VID:PCI_SUBSYS_DID] [DRIVER]
  */
-static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM,
-		const char *fileName,
+static int FAST_FUNC fileAction(struct recursive_state *state,
 		struct stat *statbuf UNUSED_PARAM)
 {
 	parser_t *parser;
@@ -47,7 +46,7 @@ static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM,
 	int pci_class = 0, pci_vid = 0, pci_did = 0;
 	int pci_subsys_vid = 0, pci_subsys_did = 0;
 
-	char *uevent_filename = concat_path_file(fileName, "uevent");
+	char *uevent_filename = concat_path_file(state->fileName, "uevent");
 	parser = config_open2(uevent_filename, fopen_for_read);
 	free(uevent_filename);
 
diff --git a/util-linux/lsusb.c b/util-linux/lsusb.c
index f7d0de32d..f5823c17d 100644
--- a/util-linux/lsusb.c
+++ b/util-linux/lsusb.c
@@ -42,15 +42,14 @@ static char * FAST_FUNC add_sysfs_prop(const char *dir, const char *suffix,
 	return trim(buf);
 }
 
-static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM,
-		const char *fileName,
+static int FAST_FUNC fileAction(struct recursive_state *state,
 		struct stat *statbuf UNUSED_PARAM)
 {
 	parser_t *parser;
 	char *tokens[4];
 	char *busnum = NULL, *devnum = NULL;
 	int product_vid = 0, product_did = 0;
-	char *uevent_filename = concat_path_file(fileName, "uevent");
+	char *uevent_filename = concat_path_file(state->fileName, "uevent");
 
 	parser = config_open2(uevent_filename, fopen_for_read);
 	free(uevent_filename);
@@ -81,10 +80,10 @@ static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM,
 	if (busnum) {
 		char name[256], *p;
 
-		p = add_sysfs_prop(fileName, "/manufacturer", name, sizeof(name) - 1);
+		p = add_sysfs_prop(state->fileName, "/manufacturer", name, sizeof(name) - 1);
 		if (p != name)
 			p = stpcpy(p, " ");
-		add_sysfs_prop(fileName, "/product", p, name + sizeof(name) - p);
+		add_sysfs_prop(state->fileName, "/product", p, name + sizeof(name) - p);
 
 		printf("Bus %s Device %s: ID %04x:%04x %s\n", busnum, devnum,
 		       product_vid, product_did, name);
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index e98d46743..230f6b133 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -845,19 +845,18 @@ static ssize_t readlink2(char *buf, size_t bufsize)
  * We act only on "/sys/.../dev" (pseudo)file
  */
 static int FAST_FUNC fileAction(struct recursive_state *state,
-		const char *fileName,
 		struct stat *statbuf UNUSED_PARAM)
 {
-	size_t len = strlen(fileName) - 4; /* can't underflow */
+	size_t len = strlen(state->fileName) - 4; /* can't underflow */
 	char *path = state->userData;	/* char array[PATH_MAX + SCRATCH_SIZE] */
 	char subsys[PATH_MAX];
 	int res;
 
 	/* Is it a ".../dev" file? (len check is for paranoid reasons) */
-	if (strcmp(fileName + len, "/dev") != 0 || len >= PATH_MAX - 32)
+	if (strcmp(state->fileName + len, "/dev") != 0 || len >= PATH_MAX - 32)
 		return FALSE; /* not .../dev */
 
-	strcpy(path, fileName);
+	strcpy(path, state->fileName);
 	path[len] = '\0';
 
 	/* Read ".../subsystem" symlink in the same directory where ".../dev" is */
@@ -887,7 +886,6 @@ static int FAST_FUNC fileAction(struct recursive_state *state,
 
 /* Directory callback for /sys/ traversal */
 static int FAST_FUNC dirAction(struct recursive_state *state,
-		const char *fileName UNUSED_PARAM,
 		struct stat *statbuf UNUSED_PARAM)
 {
 	return (state->depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE);
diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c
index 00cfb2826..4a227781e 100644
--- a/util-linux/volume_id/get_devname.c
+++ b/util-linux/volume_id/get_devname.c
@@ -102,14 +102,13 @@ uuidcache_addentry(char *device, /*int major, int minor,*/ char *label, char *uu
  * add a cache entry for this device.
  * If device node does not exist, it will be temporarily created. */
 static int FAST_FUNC
-uuidcache_check_device(struct recursive_state *state UNUSED_PARAM,
-		const char *device,
+uuidcache_check_device(struct recursive_state *state,
 		struct stat *statbuf)
 {
 	/* note: this check rejects links to devices, among other nodes */
 	if (!S_ISBLK(statbuf->st_mode)
 #if ENABLE_FEATURE_VOLUMEID_UBIFS
-	 && !(S_ISCHR(statbuf->st_mode) && strncmp(bb_basename(device), "ubi", 3) == 0)
+	 && !(S_ISCHR(statbuf->st_mode) && strncmp(bb_basename(state->fileName), "ubi", 3) == 0)
 #endif
 	)
 		return TRUE;
@@ -122,7 +121,7 @@ uuidcache_check_device(struct recursive_state *state UNUSED_PARAM,
 	if (major(statbuf->st_rdev) == 2)
 		return TRUE;
 
-	add_to_uuid_cache(device);
+	add_to_uuid_cache(state->fileName);
 
 	return TRUE;
 }
-- 
2.52.0

_______________________________________________
busybox mailing list
[email protected]
https://lists.busybox.net/mailman/listinfo/busybox

Reply via email to