diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2021-01-27 15:27:56 -0500 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2021-01-28 17:13:26 -0500 |
commit | 9bf75cee19b8d60d2b4f6260a8c2322cc8ca11db (patch) | |
tree | 0bc819909cb616b05ff013fbf1144dae7a13ec23 /bftw.c | |
parent | 3fcd7b010fd4f477582997d688cc415f76e70411 (diff) |
dir: New DIR* facade
Diffstat (limited to 'bftw.c')
-rw-r--r-- | bftw.c | 188 |
1 files changed, 48 insertions, 140 deletions
@@ -33,13 +33,13 @@ */ #include "bftw.h" +#include "dir.h" #include "dstring.h" #include "mtab.h" #include "stat.h" #include "trie.h" #include "util.h" #include <assert.h> -#include <dirent.h> #include <errno.h> #include <fcntl.h> #include <stdbool.h> @@ -70,7 +70,7 @@ struct bftw_file { int fd; /** This file's type, if known. */ - enum bftw_type type; + enum bfs_type type; /** The device number, for cycle detection. */ dev_t dev; /** The inode number, for cycle detection. */ @@ -322,7 +322,7 @@ static struct bftw_file *bftw_file_new(struct bftw_cache *cache, struct bftw_fil file->refcount = 1; file->fd = -1; - file->type = BFTW_UNKNOWN; + file->type = BFS_UNKNOWN; file->dev = -1; file->ino = -1; @@ -433,7 +433,7 @@ static int bftw_file_open(struct bftw_cache *cache, struct bftw_file *file, cons } /** - * Open a DIR* for a bftw_file. + * Open a bftw_file as a directory. * * @param cache * The cache to hold the file. @@ -442,16 +442,16 @@ static int bftw_file_open(struct bftw_cache *cache, struct bftw_file *file, cons * @param path * The full path to the directory. * @return - * The opened DIR *, or NULL on error. + * The opened directory, or NULL on error. */ -static DIR *bftw_file_opendir(struct bftw_cache *cache, struct bftw_file *file, const char *path) { +static struct bfs_dir *bftw_file_opendir(struct bftw_cache *cache, struct bftw_file *file, const char *path) { int fd = bftw_file_open(cache, file, path); if (fd < 0) { return NULL; } // Now we dup() the fd and pass it to fdopendir(). This way we can - // close the DIR* as soon as we're done with it, reducing the memory + // close the bfs_dir as soon as we're done with it, reducing the memory // footprint significantly, while keeping the fd around for future // openat() calls. @@ -467,7 +467,7 @@ static DIR *bftw_file_opendir(struct bftw_cache *cache, struct bftw_file *file, return NULL; } - DIR *ret = fdopendir(dfd); + struct bfs_dir *ret = bfs_opendir(dfd, NULL); if (!ret) { int error = errno; close(dfd); @@ -618,9 +618,11 @@ struct bftw_state { struct bftw_file *previous; /** The currently open directory. */ - DIR *dir; + struct bfs_dir *dir; /** The current directory entry. */ - struct dirent *de; + struct bfs_dirent *de; + /** Storage for the directory entry. */ + struct bfs_dirent de_storage; /** Any error encountered while reading the directory. */ int direrror; @@ -645,7 +647,7 @@ static int bftw_state_init(struct bftw_state *state, const struct bftw_args *arg goto err; } - // Reserve 1 fd for the open DIR * + // Reserve 1 fd for the open bfs_dir if (bftw_cache_init(&state->cache, args->nopenfd - 1) != 0) { goto err; } @@ -673,103 +675,6 @@ err: return -1; } -enum bftw_type bftw_mode_to_type(mode_t mode) { - switch (mode & S_IFMT) { -#ifdef S_IFBLK - case S_IFBLK: - return BFTW_BLK; -#endif -#ifdef S_IFCHR - case S_IFCHR: - return BFTW_CHR; -#endif -#ifdef S_IFDIR - case S_IFDIR: - return BFTW_DIR; -#endif -#ifdef S_IFDOOR - case S_IFDOOR: - return BFTW_DOOR; -#endif -#ifdef S_IFIFO - case S_IFIFO: - return BFTW_FIFO; -#endif -#ifdef S_IFLNK - case S_IFLNK: - return BFTW_LNK; -#endif -#ifdef S_IFPORT - case S_IFPORT: - return BFTW_PORT; -#endif -#ifdef S_IFREG - case S_IFREG: - return BFTW_REG; -#endif -#ifdef S_IFSOCK - case S_IFSOCK: - return BFTW_SOCK; -#endif -#ifdef S_IFWHT - case S_IFWHT: - return BFTW_WHT; -#endif - - default: - return BFTW_UNKNOWN; - } -} - -static enum bftw_type bftw_dirent_type(const struct dirent *de) { -#if defined(_DIRENT_HAVE_D_TYPE) || defined(DT_UNKNOWN) - switch (de->d_type) { -#ifdef DT_BLK - case DT_BLK: - return BFTW_BLK; -#endif -#ifdef DT_CHR - case DT_CHR: - return BFTW_CHR; -#endif -#ifdef DT_DIR - case DT_DIR: - return BFTW_DIR; -#endif -#ifdef DT_DOOR - case DT_DOOR: - return BFTW_DOOR; -#endif -#ifdef DT_FIFO - case DT_FIFO: - return BFTW_FIFO; -#endif -#ifdef DT_LNK - case DT_LNK: - return BFTW_LNK; -#endif -#ifdef DT_PORT - case DT_PORT: - return BFTW_PORT; -#endif -#ifdef DT_REG - case DT_REG: - return BFTW_REG; -#endif -#ifdef DT_SOCK - case DT_SOCK: - return BFTW_SOCK; -#endif -#ifdef DT_WHT - case DT_WHT: - return BFTW_WHT; -#endif - } -#endif - - return BFTW_UNKNOWN; -} - /** Cached bfs_stat(). */ static const struct bfs_stat *bftw_stat_impl(struct BFTW *ftwbuf, struct bftw_stat *cache, enum bfs_stat_flags flags) { if (!cache->buf) { @@ -817,20 +722,20 @@ const struct bfs_stat *bftw_cached_stat(const struct BFTW *ftwbuf, enum bfs_stat } } -enum bftw_type bftw_type(const struct BFTW *ftwbuf, enum bfs_stat_flags flags) { +enum bfs_type bftw_type(const struct BFTW *ftwbuf, enum bfs_stat_flags flags) { if (ftwbuf->stat_flags & BFS_STAT_NOFOLLOW) { - if ((flags & BFS_STAT_NOFOLLOW) || ftwbuf->type != BFTW_LNK) { + if ((flags & BFS_STAT_NOFOLLOW) || ftwbuf->type != BFS_LNK) { return ftwbuf->type; } - } else if ((flags & (BFS_STAT_NOFOLLOW | BFS_STAT_TRYFOLLOW)) == BFS_STAT_TRYFOLLOW || ftwbuf->type == BFTW_LNK) { + } else if ((flags & (BFS_STAT_NOFOLLOW | BFS_STAT_TRYFOLLOW)) == BFS_STAT_TRYFOLLOW || ftwbuf->type == BFS_LNK) { return ftwbuf->type; } const struct bfs_stat *statbuf = bftw_stat(ftwbuf, flags); if (statbuf) { - return bftw_mode_to_type(statbuf->mode); + return bfs_mode_to_type(statbuf->mode); } else { - return BFTW_ERROR; + return BFS_ERROR; } } @@ -865,15 +770,15 @@ static bool bftw_need_stat(const struct bftw_state *state) { } const struct BFTW *ftwbuf = &state->ftwbuf; - if (ftwbuf->type == BFTW_UNKNOWN) { + if (ftwbuf->type == BFS_UNKNOWN) { return true; } - if (ftwbuf->type == BFTW_LNK && !(ftwbuf->stat_flags & BFS_STAT_NOFOLLOW)) { + if (ftwbuf->type == BFS_LNK && !(ftwbuf->stat_flags & BFS_STAT_NOFOLLOW)) { return true; } - if (ftwbuf->type == BFTW_DIR) { + if (ftwbuf->type == BFS_DIR) { if (state->flags & (BFTW_DETECT_CYCLES | BFTW_SKIP_MOUNTS | BFTW_PRUNE_MOUNTS)) { return true; } @@ -930,14 +835,14 @@ static int bftw_ensure_open(struct bftw_cache *cache, struct bftw_file *file, co */ static void bftw_init_ftwbuf(struct bftw_state *state, enum bftw_visit visit) { struct bftw_file *file = state->file; - const struct dirent *de = state->de; + const struct bfs_dirent *de = state->de; struct BFTW *ftwbuf = &state->ftwbuf; ftwbuf->path = state->path; ftwbuf->root = file ? file->root->name : ftwbuf->path; ftwbuf->depth = 0; ftwbuf->visit = visit; - ftwbuf->type = BFTW_UNKNOWN; + ftwbuf->type = BFS_UNKNOWN; ftwbuf->error = state->direrror; ftwbuf->at_fd = AT_FDCWD; ftwbuf->at_path = ftwbuf->path; @@ -949,7 +854,7 @@ static void bftw_init_ftwbuf(struct bftw_state *state, enum bftw_visit visit) { if (de) { parent = file; ftwbuf->depth = file->depth + 1; - ftwbuf->type = bftw_dirent_type(de); + ftwbuf->type = de->type; ftwbuf->nameoff = bftw_child_nameoff(file); } else if (file) { parent = file->parent; @@ -974,7 +879,7 @@ static void bftw_init_ftwbuf(struct bftw_state *state, enum bftw_visit visit) { } if (ftwbuf->error != 0) { - ftwbuf->type = BFTW_ERROR; + ftwbuf->type = BFS_ERROR; return; } @@ -991,18 +896,18 @@ static void bftw_init_ftwbuf(struct bftw_state *state, enum bftw_visit visit) { if (bftw_need_stat(state)) { statbuf = bftw_stat(ftwbuf, ftwbuf->stat_flags); if (statbuf) { - ftwbuf->type = bftw_mode_to_type(statbuf->mode); + ftwbuf->type = bfs_mode_to_type(statbuf->mode); } else { - ftwbuf->type = BFTW_ERROR; + ftwbuf->type = BFS_ERROR; ftwbuf->error = errno; return; } } - if (ftwbuf->type == BFTW_DIR && (state->flags & BFTW_DETECT_CYCLES)) { + if (ftwbuf->type == BFS_DIR && (state->flags & BFTW_DETECT_CYCLES)) { for (const struct bftw_file *ancestor = parent; ancestor; ancestor = ancestor->parent) { if (ancestor->dev == statbuf->dev && ancestor->ino == statbuf->ino) { - ftwbuf->type = BFTW_ERROR; + ftwbuf->type = BFS_ERROR; ftwbuf->error = ELOOP; return; } @@ -1051,8 +956,8 @@ static enum bftw_action bftw_visit(struct bftw_state *state, const char *name, e const struct BFTW *ftwbuf = &state->ftwbuf; bftw_init_ftwbuf(state, visit); - // Never give the callback BFTW_ERROR unless BFTW_RECOVER is specified - if (ftwbuf->type == BFTW_ERROR && !(state->flags & BFTW_RECOVER)) { + // Never give the callback BFS_ERROR unless BFTW_RECOVER is specified + if (ftwbuf->type == BFS_ERROR && !(state->flags & BFTW_RECOVER)) { state->error = ftwbuf->error; return BFTW_STOP; } @@ -1073,7 +978,7 @@ static enum bftw_action bftw_visit(struct bftw_state *state, const char *name, e return BFTW_STOP; } - if (visit != BFTW_PRE || ftwbuf->type != BFTW_DIR) { + if (visit != BFTW_PRE || ftwbuf->type != BFS_DIR) { ret = BFTW_PRUNE; goto done; } @@ -1103,7 +1008,7 @@ static int bftw_push(struct bftw_state *state, const char *name, bool fill_id) { } if (state->de) { - file->type = bftw_dirent_type(state->de); + file->type = state->de->type; } if (fill_id) { @@ -1190,14 +1095,17 @@ static int bftw_readdir(struct bftw_state *state) { return -1; } - if (xreaddir(state->dir, &state->de) != 0) { - state->direrror = errno; - return -1; - } else if (state->de) { - return 1; + int ret = bfs_readdir(state->dir, &state->de_storage); + if (ret > 0) { + state->de = &state->de_storage; + } else if (ret == 0) { + state->de = NULL; } else { - return 0; + state->de = NULL; + state->direrror = errno; } + + return ret; } /** @@ -1220,7 +1128,7 @@ enum bftw_release_flags { static enum bftw_action bftw_closedir(struct bftw_state *state, enum bftw_release_flags flags) { enum bftw_action ret = BFTW_CONTINUE; - if (state->dir && closedir(state->dir) != 0) { + if (state->dir && bfs_closedir(state->dir) != 0) { state->direrror = errno; } state->de = NULL; @@ -1352,7 +1260,7 @@ static int bftw_stream(const struct bftw_args *args) { bftw_batch_start(&state); while (bftw_readdir(&state) > 0) { - const char *name = state.de->d_name; + const char *name = state.de->name; switch (bftw_visit(&state, name, BFTW_PRE)) { case BFTW_CONTINUE: @@ -1415,7 +1323,7 @@ static int bftw_batch(const struct bftw_args *args) { bftw_batch_start(&state); while (bftw_readdir(&state) > 0) { - if (bftw_push(&state, state.de->d_name, false) != 0) { + if (bftw_push(&state, state.de->name, false) != 0) { goto done; } } @@ -1479,7 +1387,7 @@ static enum bftw_action bftw_ids_callback(const struct BFTW *ftwbuf, void *ptr) mutbuf->visit = state->visit; } - if (ftwbuf->type == BFTW_ERROR) { + if (ftwbuf->type == BFS_ERROR) { if (ftwbuf->depth + 1 >= state->min_depth) { return state->delegate(ftwbuf, state->ptr); } else { @@ -1506,13 +1414,13 @@ static enum bftw_action bftw_ids_callback(const struct BFTW *ftwbuf, void *ptr) switch (ret) { case BFTW_CONTINUE: - if (ftwbuf->type == BFTW_DIR && ftwbuf->depth + 1 >= state->max_depth) { + if (ftwbuf->type == BFS_DIR && ftwbuf->depth + 1 >= state->max_depth) { state->bottom = false; ret = BFTW_PRUNE; } break; case BFTW_PRUNE: - if (ftwbuf->type == BFTW_DIR) { + if (ftwbuf->type == BFS_DIR) { if (!trie_insert_str(&state->pruned, ftwbuf->path)) { state->error = errno; state->quit = true; |