diff options
-rw-r--r-- | bfs.c | 7 | ||||
-rw-r--r-- | bftw.c | 49 | ||||
-rw-r--r-- | bftw.h | 22 |
3 files changed, 47 insertions, 31 deletions
@@ -23,17 +23,16 @@ typedef struct { bool hidden; } options; -static int callback(const char *fpath, const struct stat *sb, int typeflag, void *ptr) { +static int callback(const char *fpath, const struct BFTW* ftwbuf, void *ptr) { const options *opts = ptr; if (!opts->hidden) { - const char *filename = strrchr(fpath, '/'); - if (filename && filename[1] == '.') { + if (ftwbuf->base > 0 && fpath[ftwbuf->base] == '.') { return BFTW_SKIP_SUBTREE; } } - pretty_print(opts->colors, fpath, sb); + pretty_print(opts->colors, fpath, ftwbuf->statbuf); return BFTW_CONTINUE; } @@ -91,6 +91,8 @@ typedef struct dircache_entry dircache_entry; struct dircache_entry { /** The parent entry, if any. */ dircache_entry *parent; + /** This directory's depth in the walk. */ + size_t depth; /** Previous node in the LRU list. */ dircache_entry *lru_prev; @@ -134,6 +136,7 @@ static dircache_entry *dircache_add(dircache *cache, dircache_entry *parent, con dircache_entry *entry = malloc(sizeof(dircache_entry) + pathsize); if (entry) { entry->parent = parent; + entry->depth = parent ? parent->depth + 1 : 0; entry->lru_prev = entry->lru_next = NULL; entry->dir = NULL; entry->refcount = 1; @@ -422,62 +425,64 @@ int bftw(const char *dirpath, bftw_fn *fn, int nopenfd, int flags, void *ptr) { continue; } + struct BFTW ftwbuf = { + .statbuf = NULL, + .typeflag = BFTW_UNKNOWN, + .base = pathlen, + .level = current->depth + 1, + }; + if (dynstr_concat(&path, pathlen, de->d_name) != 0) { goto done; } - int typeflag = BFTW_UNKNOWN; - #if defined(_DIRENT_HAVE_D_TYPE) || defined(DT_DIR) switch (de->d_type) { case DT_DIR: - typeflag = BFTW_D; + ftwbuf.typeflag = BFTW_D; break; case DT_REG: - typeflag = BFTW_R; + ftwbuf.typeflag = BFTW_R; break; case DT_LNK: - typeflag = BFTW_SL; + ftwbuf.typeflag = BFTW_SL; break; } #endif struct stat sb; - struct stat *sp = NULL; - if ((flags & BFTW_STAT) || typeflag == BFTW_UNKNOWN) { + if ((flags & BFTW_STAT) || ftwbuf.typeflag == BFTW_UNKNOWN) { if (fstatat(dirfd(dir), de->d_name, &sb, AT_SYMLINK_NOFOLLOW) == 0) { - sp = &sb; + ftwbuf.statbuf = &sb; switch (sb.st_mode & S_IFMT) { case S_IFDIR: - typeflag = BFTW_D; + ftwbuf.typeflag = BFTW_D; break; case S_IFREG: - typeflag = BFTW_R; + ftwbuf.typeflag = BFTW_R; break; case S_IFLNK: - typeflag = BFTW_SL; + ftwbuf.typeflag = BFTW_SL; break; } } } - int action = fn(path.str, sp, typeflag, ptr); + int action = fn(path.str, &ftwbuf, ptr); switch (action) { case BFTW_CONTINUE: - if (typeflag != BFTW_D) { - break; - } - - dircache_entry *next = dircache_add(&cache, current, de->d_name); - if (!next) { - goto done; - } + if (ftwbuf.typeflag == BFTW_D) { + dircache_entry *next = dircache_add(&cache, current, de->d_name); + if (!next) { + goto done; + } - if (dirqueue_push(&queue, next) != 0) { - goto done; + if (dirqueue_push(&queue, next) != 0) { + goto done; + } } break; @@ -12,20 +12,32 @@ #include <sys/stat.h> /** + * Data about the current file for the bftw() callback. + */ +struct BFTW { + /** A stat() buffer; may be NULL if no stat() call was needed. */ + const struct stat *statbuf; + /** A typeflag value (see below). */ + int typeflag; + /** The string offset of the filename in the path. */ + int base; + /** The depth of this file in the walk. */ + int level; +}; + +/** * Callback function type for bftw(). * * @param fpath * The path to the encountered file. - * @param sb - * A stat() buffer; may be NULL if no stat() call was needed. - * @param typeflag - * A typeflag value (see below). + * @param ftwbuf + * Additional data about the current file. * @param ptr * The pointer passed to bftw(). * @return * An action value (see below). */ -typedef int bftw_fn(const char *fpath, const struct stat *sb, int typeflag, void *ptr); +typedef int bftw_fn(const char *fpath, const struct BFTW *ftwbuf, void *ptr); /** * Breadth First Tree Walk (or Better File Tree Walk). |