summaryrefslogtreecommitdiff
path: root/aports/busybox/0033-find-fix-xdev-depth-and-delete.patch
diff options
context:
space:
mode:
Diffstat (limited to 'aports/busybox/0033-find-fix-xdev-depth-and-delete.patch')
-rw-r--r--aports/busybox/0033-find-fix-xdev-depth-and-delete.patch230
1 files changed, 230 insertions, 0 deletions
diff --git a/aports/busybox/0033-find-fix-xdev-depth-and-delete.patch b/aports/busybox/0033-find-fix-xdev-depth-and-delete.patch
new file mode 100644
index 0000000..4cd8d9b
--- /dev/null
+++ b/aports/busybox/0033-find-fix-xdev-depth-and-delete.patch
@@ -0,0 +1,230 @@
+From e49db109bba7ff0b84fe7ba4f1f08405a6b72419 Mon Sep 17 00:00:00 2001
+From: Dominique Martinet <dominique.martinet@atmark-techno.com>
+Date: Fri, 27 Oct 2023 06:42:35 +0900
+Subject: [PATCH] find: fix -xdev -depth (and -delete)
+
+find -xdev with -depth would check for same_fs after the subdirectory
+has been processed (because the check is done in the file/dir action,
+which is evaluated too late in the -depth case)
+This renders `find -xdev -delete` useless, as reported in 2012 here:
+https://bugs.busybox.net/show_bug.cgi?id=5756
+
+The bug report suggested adding an extra hook, which would be required
+if we were to keep the current xdev approach that allows all filesystems
+given in argument, but GNU findutils and OpenBSD find actually stop on
+the first filesystem boundary e.g. for the following tree:
+
+$ find test -exec stat --format "%d %n" {} +
+27 test
+27 test/file
+59 test/tmpfs
+27 test/tmpfs/bind
+27 test/tmpfs/bind/file
+59 test/tmpfs/file
+(Where 'test/tmpfs' is a tmpfs, and 'test/tmpfs/bind' is a bind mount
+to a neighboring directory in the same filesystem as 'test' -- also
+tested with a symlink and -follow for openbsd which has no bind mount)
+
+Then `find test test/tmpfs -xdev` does not print test/tmpfs/bind/file.
+
+This makes the implementation much simpler (although it's a bit ugly to
+carry the parent st_dev as an argument to the function) and smaller
+code, and would allow for easy addition of rm/cp --one-file-system if
+we want to do that later.
+
+Note: this also no longer stores the stat result in 'status' in
+recursive_action1 as that was not used and doing this saves 10 bytes
+
+function old new delta
+recursive_action1 361 385 +24
+parse_params 1503 1510 +7
+recursive_action 63 65 +2
+fileAction 206 127 -79
+find_main 520 417 -103
+------------------------------------------------------------------------------
+(add/remove: 0/0 grow/shrink: 3/2 up/down: 33/-182) Total: -149 bytes
+ text data bss dec hex filename
+ 78267 1582 1552 81401 13df9 busybox_old
+ 78118 1582 1552 81252 13d64 busybox_unstripped
+---
+ findutils/find.c | 44 ++--------------------------------------
+ include/libbb.h | 1 +
+ libbb/recursive_action.c | 19 ++++++++++-------
+ 3 files changed, 15 insertions(+), 49 deletions(-)
+
+diff --git a/findutils/find.c b/findutils/find.c
+index bb6ad31e5edc..e88fbd3ba3bf 100644
+--- a/findutils/find.c
++++ b/findutils/find.c
+@@ -488,7 +488,6 @@ struct globals {
+ #endif
+ action ***actions;
+ smallint need_print;
+- smallint xdev_on;
+ smalluint exitstatus;
+ recurse_flags_t recurse_flags;
+ IF_FEATURE_FIND_EXEC_PLUS(unsigned max_argv_len;)
+@@ -988,26 +987,10 @@ static int FAST_FUNC fileAction(
+ struct stat *statbuf)
+ {
+ int r;
+- int same_fs = 1;
+-
+-#if ENABLE_FEATURE_FIND_XDEV
+- if (S_ISDIR(statbuf->st_mode) && G.xdev_count) {
+- int i;
+- for (i = 0; i < G.xdev_count; i++) {
+- if (G.xdev_dev[i] == statbuf->st_dev)
+- goto found;
+- }
+- //bb_error_msg("'%s': not same fs", fileName);
+- same_fs = 0;
+- found: ;
+- }
+-#endif
+
+ #if ENABLE_FEATURE_FIND_MAXDEPTH
+ if (state->depth < G.minmaxdepth[0]) {
+- if (same_fs)
+- return TRUE; /* skip this, continue recursing */
+- return SKIP; /* stop recursing */
++ return TRUE; /* skip this, continue recursing */
+ }
+ if (state->depth > G.minmaxdepth[1])
+ return SKIP; /* stop recursing */
+@@ -1024,11 +1007,6 @@ static int FAST_FUNC fileAction(
+ return SKIP;
+ }
+ #endif
+- /* -xdev stops on mountpoints, but AFTER mountpoit itself
+- * is processed as usual */
+- if (!same_fs) {
+- return SKIP;
+- }
+
+ /* Cannot return 0: our caller, recursive_action(),
+ * will perror() and skip dirs (if called on dir) */
+@@ -1266,7 +1244,7 @@ static action*** parse_params(char **argv)
+ #if ENABLE_FEATURE_FIND_XDEV
+ else if (parm == OPT_XDEV) {
+ dbg("%d", __LINE__);
+- G.xdev_on = 1;
++ G.recurse_flags |= ACTION_XDEV;
+ }
+ #endif
+ #if ENABLE_FEATURE_FIND_MAXDEPTH
+@@ -1685,24 +1663,6 @@ int find_main(int argc UNUSED_PARAM, char **argv)
+ G.actions = parse_params(&argv[firstopt]);
+ argv[firstopt] = NULL;
+
+-#if ENABLE_FEATURE_FIND_XDEV
+- if (G.xdev_on) {
+- struct stat stbuf;
+-
+- G.xdev_count = firstopt;
+- G.xdev_dev = xzalloc(G.xdev_count * sizeof(G.xdev_dev[0]));
+- for (i = 0; argv[i]; i++) {
+- /* not xstat(): shouldn't bomb out on
+- * "find not_exist exist -xdev" */
+- if (stat(argv[i], &stbuf) == 0)
+- G.xdev_dev[i] = stbuf.st_dev;
+- /* else G.xdev_dev[i] stays 0 and
+- * won't match any real device dev_t
+- */
+- }
+- }
+-#endif
+-
+ for (i = 0; argv[i]; i++) {
+ if (!recursive_action(argv[i],
+ G.recurse_flags,/* flags */
+diff --git a/include/libbb.h b/include/libbb.h
+index 5d0fe924eed1..d903330cccb0 100644
+--- a/include/libbb.h
++++ b/include/libbb.h
+@@ -512,6 +512,7 @@ enum {
+ ACTION_DEPTHFIRST = (1 << 3),
+ ACTION_QUIET = (1 << 4),
+ ACTION_DANGLING_OK = (1 << 5),
++ ACTION_XDEV = (1 << 6),
+ };
+ typedef uint8_t recurse_flags_t;
+ typedef struct recursive_state {
+diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c
+index b1c4bfad7ccf..d4b40afdead3 100644
+--- a/libbb/recursive_action.c
++++ b/libbb/recursive_action.c
+@@ -62,13 +62,15 @@ static int FAST_FUNC true_action(struct recursive_state *state UNUSED_PARAM,
+ * ACTION_FOLLOWLINKS mainly controls 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.
++ *
++ * If ACTION_XDEV, stop on different filesystem _after_ it has been processed
+ */
+
+-static int recursive_action1(recursive_state_t *state, const char *fileName)
++static int recursive_action1(recursive_state_t *state, const char *fileName, dev_t parentDev)
+ {
+ struct stat statbuf;
+ unsigned follow;
+- int status;
++ int status = TRUE;
+ DIR *dir;
+ struct dirent *next;
+
+@@ -76,8 +78,7 @@ 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);
+- if (status < 0) {
++ if ((follow ? stat : lstat)(fileName, &statbuf) < 0) {
+ #ifdef DEBUG_RECURS_ACTION
+ bb_error_msg("status=%d flags=%x", status, state->flags);
+ #endif
+@@ -114,6 +115,10 @@ static int recursive_action1(recursive_state_t *state, const char *fileName)
+ return TRUE;
+ }
+
++ /* skip cross devices -- we still need to process action */
++ if ((state->flags & ACTION_XDEV) && parentDev != 0 && statbuf.st_dev != parentDev)
++ goto skip_recurse;
++
+ dir = opendir(fileName);
+ if (!dir) {
+ /* findutils-4.1.20 reports this */
+@@ -121,7 +126,6 @@ static int recursive_action1(recursive_state_t *state, const char *fileName)
+ /* To trigger: "find -exec rm -rf {} \;" */
+ goto done_nak_warn;
+ }
+- status = TRUE;
+ while ((next = readdir(dir)) != NULL) {
+ char *nextFile;
+ int s;
+@@ -132,7 +136,7 @@ static int recursive_action1(recursive_state_t *state, const char *fileName)
+
+ /* process every file (NB: ACTION_RECURSE is set in flags) */
+ state->depth++;
+- s = recursive_action1(state, nextFile);
++ s = recursive_action1(state, nextFile, statbuf.st_dev);
+ if (s == FALSE)
+ status = FALSE;
+ free(nextFile);
+@@ -146,6 +150,7 @@ static int recursive_action1(recursive_state_t *state, const char *fileName)
+ }
+ closedir(dir);
+
++skip_recurse:
+ if (state->flags & ACTION_DEPTHFIRST) {
+ if (!state->dirAction(state, fileName, &statbuf))
+ goto done_nak_warn;
+@@ -177,5 +182,5 @@ int FAST_FUNC recursive_action(const char *fileName,
+ state.fileAction = fileAction ? fileAction : true_action;
+ state.dirAction = dirAction ? dirAction : true_action;
+
+- return recursive_action1(&state, fileName);
++ return recursive_action1(&state, fileName, 0);
+ }
+--
+2.39.2
+