1 /* SPDX-License-Identifier: LGPL-2.1-or-later */ 2 #pragma once 3 4 #include <dirent.h> 5 #include <limits.h> 6 7 #include "errno-list.h" 8 #include "stat-util.h" 9 #include "macro.h" 10 11 typedef enum RecurseDirEvent { 12 RECURSE_DIR_ENTER, /* only for dir inodes */ 13 RECURSE_DIR_LEAVE, /* only for dir inodes */ 14 RECURSE_DIR_ENTRY, /* only for non-dir inodes */ 15 RECURSE_DIR_SKIP_MOUNT, /* only for dir inodes: when we don't descent into submounts */ 16 RECURSE_DIR_SKIP_DEPTH, /* only for dir inodes: when we reached the max depth */ 17 18 /* If we hit an error opening/stating an entry, then we'll fire a 19 * 'RECURSE_DIR_SKIP_{OPEN_DIR|OPEN_INODE|STAT_INODE}_ERROR_BASE + errno' event. In this case 'de' 20 * will be valid, but the statx data NULL and the inode fd -1. */ 21 RECURSE_DIR_SKIP_OPEN_DIR_ERROR_BASE, 22 RECURSE_DIR_SKIP_OPEN_DIR_ERROR_MAX = RECURSE_DIR_SKIP_OPEN_DIR_ERROR_BASE + ERRNO_MAX, 23 24 RECURSE_DIR_SKIP_OPEN_INODE_ERROR_BASE, 25 RECURSE_DIR_SKIP_OPEN_INODE_ERROR_MAX = RECURSE_DIR_SKIP_OPEN_INODE_ERROR_BASE + ERRNO_MAX, 26 27 RECURSE_DIR_SKIP_STAT_INODE_ERROR_BASE, 28 RECURSE_DIR_SKIP_STAT_INODE_ERROR_MAX = RECURSE_DIR_SKIP_STAT_INODE_ERROR_BASE + ERRNO_MAX, 29 30 _RECURSE_DIR_EVENT_MAX, 31 _RECURSE_DIR_EVENT_INVALID = -EINVAL, 32 } RecurseDirEvent; 33 34 #define RECURSE_DIR_CONTINUE 0 35 #define RECURSE_DIR_LEAVE_DIRECTORY INT_MIN 36 #define RECURSE_DIR_SKIP_ENTRY (INT_MIN+1) 37 38 /* Make sure that the negative errno range and these two special returns don't overlap */ 39 assert_cc(RECURSE_DIR_LEAVE_DIRECTORY < -ERRNO_MAX); 40 assert_cc(RECURSE_DIR_SKIP_ENTRY < -ERRNO_MAX); 41 42 /* Prototype for the callback function that is called whenever we enter or leave a dir inode, or find another dir entry. Return values are: 43 * 44 * RECURSE_DIR_CONTINUE (i.e. 0) → continue with next entry 45 * RECURSE_DIR_LEAVE_DIRECTORY → leave current directory immediately, don't process further siblings 46 * RECURSE_DIR_SKIP_ENTRY → skip this entry otherwise (only makes sense on RECURSE_DIR_ENTER) 47 * others → terminate iteration entirely, return the specified value (idea is that 48 * < 0 indicates errors and > 0 indicates various forms of success) 49 */ 50 typedef int (*recurse_dir_func_t)( 51 RecurseDirEvent event, 52 const char *path, /* Full non-normalized path, i.e. the path specified during recurise_dir() with what we found appended */ 53 int dir_fd, /* fd of the current dir */ 54 int inode_fd, /* fd of the current entry in the current dir (O_DIRECTORY if directory, and O_PATH otherwise, but only if RECURSE_DIR_INODE_FD was set) */ 55 const struct dirent *de, /* directory entry (always valid) */ 56 const struct statx *sx, /* statx data (only if statx_mask was non-zero) */ 57 void *userdata); 58 59 typedef enum RecurseDirFlags { 60 /* Interpreted by readdir_all() */ 61 RECURSE_DIR_SORT = 1 << 0, /* sort file directory entries before processing them */ 62 RECURSE_DIR_IGNORE_DOT = 1 << 1, /* ignore all dot files ("." and ".." are always ignored) */ 63 64 /* Interpreted by recurse_dir() */ 65 RECURSE_DIR_ENSURE_TYPE = 1 << 2, /* guarantees that 'd_type' field of 'de' is not DT_UNKNOWN */ 66 RECURSE_DIR_SAME_MOUNT = 1 << 3, /* skips over subdirectories that are submounts */ 67 RECURSE_DIR_INODE_FD = 1 << 4, /* passes an opened inode fd (O_DIRECTORY fd in case of dirs, O_PATH otherwise) */ 68 } RecurseDirFlags; 69 70 typedef struct DirectoryEntries { 71 size_t n_entries; 72 struct dirent** entries; 73 size_t buffer_size; 74 struct dirent buffer[]; 75 } DirectoryEntries; 76 77 int readdir_all(int dir_fd, RecurseDirFlags flags, DirectoryEntries **ret); 78 79 int recurse_dir(int dir_fd, const char *path, unsigned statx_mask, unsigned n_depth_max, RecurseDirFlags flags, recurse_dir_func_t func, void *userdata); 80 int recurse_dir_at(int atfd, const char *path, unsigned statx_mask, unsigned n_depth_max, RecurseDirFlags flags, recurse_dir_func_t func, void *userdata); 81