diff --git a/src/basic/recurse-dir.c b/src/basic/recurse-dir.c index d16ca98f67..908e833501 100644 --- a/src/basic/recurse-dir.c +++ b/src/basic/recurse-dir.c @@ -126,6 +126,7 @@ int recurse_dir( void *userdata) { _cleanup_free_ DirectoryEntries *de = NULL; + STRUCT_STATX_DEFINE(root_sx); int r; assert(dir_fd >= 0); @@ -139,6 +140,26 @@ int recurse_dir( if (n_depth_max == UINT_MAX) /* special marker for "default" */ n_depth_max = DEFAULT_RECURSION_MAX; + if (FLAGS_SET(flags, RECURSE_DIR_TOPLEVEL)) { + if (statx_mask != 0) { + r = statx_fallback(dir_fd, "", AT_EMPTY_PATH, statx_mask, &root_sx); + if (r < 0) + return r; + } + + r = func(RECURSE_DIR_ENTER, + path, + -1, /* we have no parent fd */ + dir_fd, + NULL, /* we have no dirent */ + statx_mask != 0 ? &root_sx : NULL, + userdata); + if (IN_SET(r, RECURSE_DIR_LEAVE_DIRECTORY, RECURSE_DIR_SKIP_ENTRY)) + return 0; + if (r != RECURSE_DIR_CONTINUE) + return r; + } + r = readdir_all(dir_fd, flags, &de); if (r < 0) return r; @@ -397,7 +418,7 @@ int recurse_dir( p, statx_mask, n_depth_max - 1, - flags, + flags &~ RECURSE_DIR_TOPLEVEL, /* we already called the callback for this entry */ func, userdata); if (r != 0) @@ -427,6 +448,19 @@ int recurse_dir( return r; } + if (FLAGS_SET(flags, RECURSE_DIR_TOPLEVEL)) { + + r = func(RECURSE_DIR_LEAVE, + path, + -1, + dir_fd, + NULL, + statx_mask != 0 ? &root_sx : NULL, + userdata); + if (!IN_SET(r, RECURSE_DIR_LEAVE_DIRECTORY, RECURSE_DIR_SKIP_ENTRY, RECURSE_DIR_CONTINUE)) + return r; + } + return 0; } diff --git a/src/basic/recurse-dir.h b/src/basic/recurse-dir.h index 779c91e905..c10c8ddc9d 100644 --- a/src/basic/recurse-dir.h +++ b/src/basic/recurse-dir.h @@ -65,6 +65,7 @@ typedef enum RecurseDirFlags { RECURSE_DIR_ENSURE_TYPE = 1 << 2, /* guarantees that 'd_type' field of 'de' is not DT_UNKNOWN */ RECURSE_DIR_SAME_MOUNT = 1 << 3, /* skips over subdirectories that are submounts */ RECURSE_DIR_INODE_FD = 1 << 4, /* passes an opened inode fd (O_DIRECTORY fd in case of dirs, O_PATH otherwise) */ + RECURSE_DIR_TOPLEVEL = 1 << 5, /* call RECURSE_DIR_ENTER/RECURSE_DIR_LEAVE once for top-level dir, too, with dir_fd=-1 and NULL dirent */ } RecurseDirFlags; typedef struct DirectoryEntries {