recursedir: introduce new RECURSE_DIR_UNLINK callback return value
This introduces RECURSE_DIR_UNLINK + RECURSE_DIR_UNLINK_GRACEFUL as new return values for recurse_dir() callbacks. If either is returned the inode currently processed will be removed and iteration continues with the next item. This is useful to have in the recurse_dir() mechanism itself (rather than implement in the callback itself), due to ordering: we want to pin the inodes via an fd while calling the callbacks, but we have to close it before removal of the inodes. By moving this into the recurse_dir() infra, we can implement this easily.
This commit is contained in:
+34
-24
@@ -1,6 +1,7 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user