diff --git a/src/basic/recurse-dir.c b/src/basic/recurse-dir.c index 9eef4e1d8c..f7f8e4a7ab 100644 --- a/src/basic/recurse-dir.c +++ b/src/basic/recurse-dir.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include "alloc-util.h" #include "dirent-util.h" @@ -433,30 +434,25 @@ int recurse_dir( i, statx_mask != 0 ? &sx : NULL, /* only pass sx if user asked for it */ userdata); - if (r == RECURSE_DIR_LEAVE_DIRECTORY) - break; - if (r == RECURSE_DIR_SKIP_ENTRY) - continue; - if (r != RECURSE_DIR_CONTINUE) - return r; + if (r == RECURSE_DIR_CONTINUE) { + r = recurse_dir(subdir_fd, + p, + statx_mask, + n_depth_max - 1, + flags & ~RECURSE_DIR_TOPLEVEL, /* we already called the callback for this entry */ + func, + userdata); + if (r != 0) + return r; - r = recurse_dir(subdir_fd, - p, - statx_mask, - n_depth_max - 1, - flags & ~RECURSE_DIR_TOPLEVEL, /* we already called the callback for this entry */ - func, - userdata); - if (r != 0) - return r; - - r = func(RECURSE_DIR_LEAVE, - p, - dir_fd, - subdir_fd, - i, - statx_mask != 0 ? &sx : NULL, /* only pass sx if user asked for it */ - userdata); + r = func(RECURSE_DIR_LEAVE, + p, + dir_fd, + subdir_fd, + i, + statx_mask != 0 ? &sx : NULL, /* only pass sx if user asked for it */ + userdata); + } } else /* Non-directory inode */ r = func(RECURSE_DIR_ENTRY, @@ -469,7 +465,21 @@ int recurse_dir( if (r == RECURSE_DIR_LEAVE_DIRECTORY) break; - if (!IN_SET(r, RECURSE_DIR_SKIP_ENTRY, RECURSE_DIR_CONTINUE)) + + if (IN_SET(r, RECURSE_DIR_UNLINK, RECURSE_DIR_UNLINK_GRACEFUL)) { + int f = subdir_fd >= 0 ? AT_REMOVEDIR : 0; + + /* Close inodes before we try to delete them */ + subdir_fd = safe_close(subdir_fd); + inode_fd = safe_close(inode_fd); + + if (unlinkat(dir_fd, i->d_name, f) < 0) { + if (r != RECURSE_DIR_UNLINK_GRACEFUL) + return -errno; + + log_debug_errno(errno, "Unable to remove '%s', ignoring: %m", p); + } + } else if (!IN_SET(r, RECURSE_DIR_SKIP_ENTRY, RECURSE_DIR_CONTINUE)) return r; } diff --git a/src/basic/recurse-dir.h b/src/basic/recurse-dir.h index 68abb279f4..af33c239f7 100644 --- a/src/basic/recurse-dir.h +++ b/src/basic/recurse-dir.h @@ -53,6 +53,8 @@ typedef enum RecurseDirEvent { #define RECURSE_DIR_CONTINUE 0 #define RECURSE_DIR_LEAVE_DIRECTORY INT_MIN #define RECURSE_DIR_SKIP_ENTRY (INT_MIN+1) +#define RECURSE_DIR_UNLINK (INT_MIN+2) +#define RECURSE_DIR_UNLINK_GRACEFUL (INT_MIN+3) /* Make sure that the negative errno range and these two special returns don't overlap */ assert_cc(RECURSE_DIR_LEAVE_DIRECTORY < -ERRNO_MAX);