diff options
Diffstat (limited to 'include/io/dir_iterator.h')
-rw-r--r-- | include/io/dir_iterator.h | 191 |
1 files changed, 188 insertions, 3 deletions
diff --git a/include/io/dir_iterator.h b/include/io/dir_iterator.h index 7080d65..74027f5 100644 --- a/include/io/dir_iterator.h +++ b/include/io/dir_iterator.h @@ -9,36 +9,221 @@ #include "sqfs/predef.h" +/** + * @struct dir_entry_t + * + * @brief A directory entry returned by a @ref dir_iterator_t + */ typedef struct { + /** + * @brief Unix time stamp when the entry was last modified. + * + * If necessary, the OS native time stamp is converted to Unix time. + */ sqfs_s64 mtime; + + /** + * @brief Device number where the entry is stored on. + * + * On Windows and other non-Unix OSes, a dummy value is stored here. + */ sqfs_u64 dev; + + /** + * @brief Device number for device special files. + * + * On Windows and other non-Unix OSes, a dummy value is stored here. + */ sqfs_u64 rdev; + + /** + * @brief ID of the user that owns the entry. + * + * On Windows and other non-Unix OSes, this always reports user 0. + */ sqfs_u32 uid; + + /** + * @brief ID of the group that owns the entry. + * + * On Windows and other non-Unix OSes, this always reports group 0. + */ sqfs_u32 gid; + + /** + * @brief Unix style permissions and entry type. + * + * On Windows and other non-Unix OSes, this is synthesized from the + * Unix-like file type, default 0755 permissions for directories or + * 0644 for files. + */ sqfs_u16 mode; + /** + * @brief Name of the entry + * + * On Unix-like OSes, the name is returned as-is. On systems like + * Windows with encoding-aware APIs, the name is converted to UTF-8. + */ char name[]; } dir_entry_t; +/** + * @interface dir_iterator_t + * + * @brief An iterator over entries in a filesystem directory. + */ typedef struct dir_iterator_t { sqfs_object_t obj; + /** + * @brief A device number for detecting mount points and hard links. + * + * On Unix-like systems this exposes the underlying device number + * backing this directory. Each entry returned by the iterator also + * has a device number and if it is different, you found a mount point. + * + * The device number, combined with inode number, are also needed to + * detect hard links. Entries with same device and inode number point + * to the same file. + */ sqfs_u64 dev; - int (*next)(struct dir_iterator_t *it, - dir_entry_t **out); + /** + * @brief Read the next entry and update internal state relating to it + * + * @param it A pointer to the iterator itself + * @param out Returns a pointer to an entry on success + * + * @return Zero on success, postivie value if the end of the list was + * reached, negative @ref SQFS_ERROR value on failure. + */ + int (*next)(struct dir_iterator_t *it, dir_entry_t **out); + /** + * @brief If the last entry was a symlink, extract the target path + * + * @param it A pointer to the iterator itself. + * @param out Returns a pointer to a string on success. Has to be + * released with free(). + * + * @return Zero on success, negative @ref SQFS_ERROR value on failure. + */ int (*read_link)(struct dir_iterator_t *it, char **out); + /** + * @brief If the last entry was a directory, open it. + * + * If next() returned a directory, this can be used to create a brand + * new dir_iterator_t for it, that is independent of the current one + * and returns the sub-directories entries. + * + * @param it A pointer to the iterator itself. + * @param out Returns a pointer to a directory iterator on success. + * + * @return Zero on success, negative @ref SQFS_ERROR value on failure. + */ int (*open_subdir)(struct dir_iterator_t *it, struct dir_iterator_t **out); } dir_iterator_t; +enum { + DIR_SCAN_NO_SOCK = 0x0001, + DIR_SCAN_NO_SLINK = 0x0002, + DIR_SCAN_NO_FILE = 0x0004, + DIR_SCAN_NO_BLK = 0x0008, + DIR_SCAN_NO_DIR = 0x0010, + DIR_SCAN_NO_CHR = 0x0020, + DIR_SCAN_NO_FIFO = 0x0040, + + DIR_SCAN_KEEP_TIME = 0x0100, + DIR_SCAN_KEEP_UID = 0x0200, + DIR_SCAN_KEEP_GID = 0x0400, + DIR_SCAN_KEEP_MODE = 0x0800, + + DIR_SCAN_ONE_FILESYSTEM = 0x1000, + DIR_SCAN_NO_RECURSION = 0x2000, + DIR_SCAN_MATCH_FULL_PATH = 0x4000, +}; + +typedef struct { + sqfs_u32 flags; + sqfs_u32 def_uid; + sqfs_u32 def_gid; + sqfs_u32 def_mode; + sqfs_s64 def_mtime; + + /** + * @brief A prefix to attach to all returend paths + * + * If not null, this string and an additional "/" are prepended to + * all entries returned by the iterator. + */ + const char *prefix; + + /** + * @brief A glob pattern that either the name must match + * + * If this is not NULL, only paths that match this globbing pattern + * are returned. If the flag DIR_SCAN_MATCH_FULL_PATH is set, the + * entire path must match, slashes cannot match wild card characters. + * If not set, only the last part of the path is tested. The iterator + * still recurses into directories, it simply doesn't report them if + * they don't match. + */ + const char *name_pattern; +} dir_tree_cfg_t; + #ifdef __cplusplus extern "C" { #endif -dir_iterator_t *dir_iterator_create(const char *path); +/** + * @brief Construct a simple directory iterator given a path + * + * On systems with encoding aware file I/O (like Windows), the path is + * interpreted to be UTF-8 encoded and converted to the native system API + * encoding to open the directory. For each directory entry, the name in + * the native encoding is converted back to UTF-8 when reading. + * + * The implementation returned by this is simple, non-recursive, reporting + * directory contents as returned by the OS native API, i.e. not sorted, + * and including the "." and ".." entries. + * + * @param path A path to a directory on the file system. + * + * @return A pointer to a dir_iterator_t implementation on success, + * NULL on error (message is printed to stderr). + */ +SQFS_INTERNAL dir_iterator_t *dir_iterator_create(const char *path); + +/** + * @brief Create a stacked, recursive directory tree iterator + * + * The underlying implementation automatically recurses into sub directories + * and returns a flattened list of entries, where each entry represents a full + * path. Advanced filtering, path pre-fixing et cetera can be configured. + * The typical "." and ".." entries are filtered out as well. + * + * @param path A path to a directory on the file system. + * @param cfg A @ref dir_tree_cfg_t filtering configuration. + * + * @return A pointer to a dir_iterator_t implementation on success, + * NULL on error (message is printed to stderr). + */ +SQFS_INTERNAL +dir_iterator_t *dir_tree_iterator_create(const char *path, + const dir_tree_cfg_t *cfg); + +/** + * @brief Skip a sub-hierarchy on a stacked iterator + * + * For an iterator returned by @ref dir_tree_iterator_create, if the last entry + * was a directory, do not recurse, but instead skip across the netire sub-tree. + * + * @param it A pointer to an iterator returned by @ref dir_tree_iterator_create + */ +SQFS_INTERNAL void dir_tree_iterator_skip(dir_iterator_t *it); #ifdef __cplusplus } |