From 309c9a29e32edc07cb06e329669be7e30f8d9ed5 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Wed, 16 Sep 2015 12:25:53 -0400 Subject: bftw() interface improvements: - Use enums instead of ints where it makes sense - Move the file path inside struct BFTW - Expose a fd and relative path for *at() calls --- bftw.c | 90 ++++++++++++++++++++++++++++-------------------------------------- 1 file changed, 38 insertions(+), 52 deletions(-) (limited to 'bftw.c') diff --git a/bftw.c b/bftw.c index 834ffca..0bc49e1 100644 --- a/bftw.c +++ b/bftw.c @@ -274,33 +274,25 @@ static int dircache_entry_path(const dircache_entry *entry, dynstr *path) { * The cache containing the entry. * @param entry * The entry being accessed. - * @param[out] fd + * @param[out] at_fd * Will hold the appropriate file descriptor to use. - * @param[in,out] relpath + * @param[in,out] at_path * Will hold the appropriate path to use. * @return The closest open ancestor entry. */ -static dircache_entry *dircache_entry_base(dircache *cache, dircache_entry *entry, int *fd, const char **relpath) { - size_t nameoff = entry->namelen + entry->nameoff; +static dircache_entry *dircache_entry_base(dircache *cache, dircache_entry *entry, int *at_fd, const char **at_path) { dircache_entry *base = entry; - while (base && !base->dir) { - nameoff = base->nameoff; + do { base = base->parent; - } + } while (base && !base->dir); if (base) { dircache_lru_remove(cache, base); dircache_lru_add(cache, base); - *fd = dirfd(base->dir); - *relpath += nameoff; - - // fstatat(fd, "") doesn't stat() fd itself, but - // fstatat(fd, ".") does, at least for directories - if (!**relpath) { - *relpath = "."; - } + *at_fd = dirfd(base->dir); + *at_path += base->nameoff + base->namelen; } return base; @@ -325,11 +317,11 @@ static DIR *dircache_entry_open(dircache *cache, dircache_entry *entry, const ch dircache_entry_close(cache, cache->lru_tail); } - int fd = AT_FDCWD; - const char *relpath = path; - dircache_entry *base = dircache_entry_base(cache, entry, &fd, &relpath); + int at_fd = AT_FDCWD; + const char *at_path = path; + dircache_entry *base = dircache_entry_base(cache, entry, &at_fd, &at_path); - DIR *dir = opendirat(fd, relpath); + DIR *dir = opendirat(at_fd, at_path); if (!dir && errno == EMFILE @@ -338,7 +330,7 @@ static DIR *dircache_entry_open(dircache *cache, dircache_entry *entry, const ch // Too many open files, shrink the LRU cache dircache_entry_close(cache, cache->lru_tail); --cache->lru_remaining; - dir = opendirat(fd, relpath); + dir = opendirat(at_fd, at_path); } if (dir) { @@ -445,14 +437,6 @@ static dircache_entry *dirqueue_pop(dirqueue *queue) { return entry; } -static void ftwbuf_init(struct BFTW *ftwbuf, int base, int level) { - ftwbuf->statbuf = NULL; - ftwbuf->typeflag = BFTW_UNKNOWN; - ftwbuf->base = base; - ftwbuf->level = level; - ftwbuf->error = 0; -} - static void ftwbuf_set_error(struct BFTW *ftwbuf, int error) { ftwbuf->typeflag = BFTW_ERROR; ftwbuf->error = error; @@ -486,8 +470,8 @@ static void ftwbuf_use_dirent(struct BFTW *ftwbuf, const struct dirent *de) { #endif } -static int ftwbuf_stat(struct BFTW *ftwbuf, struct stat *sb, int fd, const char *path) { - int ret = fstatat(fd, path, sb, AT_SYMLINK_NOFOLLOW); +static int ftwbuf_stat(struct BFTW *ftwbuf, struct stat *sb) { + int ret = fstatat(ftwbuf->at_fd, ftwbuf->at_path, sb, AT_SYMLINK_NOFOLLOW); if (ret != 0) { return ret; } @@ -604,45 +588,47 @@ static int bftw_path_concat(bftw_state *state, const char *subpath) { * Initialize the buffers with data about the current path. */ static void bftw_init_buffers(bftw_state *state, const struct dirent *de) { - size_t base = 0; - size_t level = 0; + struct BFTW *ftwbuf = &state->ftwbuf; + ftwbuf->path = state->path.str; + ftwbuf->nameoff = 0; + ftwbuf->error = 0; + ftwbuf->depth = 0; + ftwbuf->statbuf = NULL; + ftwbuf->at_fd = AT_FDCWD; + ftwbuf->at_path = ftwbuf->path; dircache_entry *current = state->current; if (current) { - base = current->nameoff; - level = current->depth; + ftwbuf->nameoff = current->nameoff; + ftwbuf->depth = current->depth; if (state->status == BFTW_CHILD) { - base += current->namelen; - ++level; + ftwbuf->nameoff += current->namelen; + ++ftwbuf->depth; } - } - ftwbuf_init(&state->ftwbuf, base, level); + dircache_entry_base(&state->cache, current, &ftwbuf->at_fd, &ftwbuf->at_path); + } if (de) { - ftwbuf_use_dirent(&state->ftwbuf, de); + ftwbuf_use_dirent(ftwbuf, de); } else if (state->status != BFTW_CHILD) { - state->ftwbuf.typeflag = BFTW_DIR; + ftwbuf->typeflag = BFTW_DIR; + } else { + ftwbuf->typeflag = BFTW_UNKNOWN; } // In BFTW_DEPTH mode, defer the stat() call for directories if ((state->flags & BFTW_DEPTH) - && state->ftwbuf.typeflag == BFTW_DIR + && ftwbuf->typeflag == BFTW_DIR && state->status == BFTW_CHILD) { return; } - if ((state->flags & BFTW_STAT) || state->ftwbuf.typeflag == BFTW_UNKNOWN) { - int fd = AT_FDCWD; - const char *relpath = state->path.str; - if (current) { - dircache_entry_base(&state->cache, current, &fd, &relpath); - } - - if (ftwbuf_stat(&state->ftwbuf, &state->statbuf, fd, relpath) != 0) { + if ((state->flags & BFTW_STAT) || ftwbuf->typeflag == BFTW_UNKNOWN) { + if (ftwbuf_stat(ftwbuf, &state->statbuf) != 0) { state->error = errno; - ftwbuf_set_error(&state->ftwbuf, state->error); + ftwbuf_set_error(ftwbuf, state->error); } } } @@ -666,7 +652,7 @@ static int bftw_handle_path(bftw_state *state) { return BFTW_CONTINUE; } - int action = state->fn(state->path.str, &state->ftwbuf, state->ptr); + bftw_action action = state->fn(&state->ftwbuf, state->ptr); switch (action) { case BFTW_CONTINUE: case BFTW_SKIP_SIBLINGS: @@ -766,7 +752,7 @@ static void bftw_state_free(bftw_state *state) { dynstr_free(&state->path); } -int bftw(const char *path, bftw_fn *fn, int nopenfd, int flags, void *ptr) { +int bftw(const char *path, bftw_fn *fn, int nopenfd, bftw_flags flags, void *ptr) { int ret = -1; bftw_state state; -- cgit v1.2.3