diff options
-rw-r--r-- | bfs.c | 2 | ||||
-rw-r--r-- | bftw.c | 214 | ||||
-rw-r--r-- | bftw.h | 4 | ||||
-rw-r--r-- | color.c | 15 | ||||
-rw-r--r-- | color.h | 7 |
5 files changed, 142 insertions, 100 deletions
@@ -285,7 +285,7 @@ static bool eval_name(const expression *expr, eval_state *state) { * -print action. */ static bool eval_print(const expression *expr, eval_state *state) { - pretty_print(state->cl->colors, state->fpath, state->ftwbuf->statbuf); + pretty_print(state->cl->colors, state->fpath, state->ftwbuf); return true; } @@ -420,30 +420,139 @@ static dircache_entry *dirqueue_pop(dirqueue *queue) { return entry; } -int bftw(const char *dirpath, bftw_fn *fn, int nopenfd, int flags, void *ptr) { +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; +} + +static void ftwbuf_use_dirent(struct BFTW *ftwbuf, const struct dirent *de) { +#if defined(_DIRENT_HAVE_D_TYPE) || defined(DT_DIR) + switch (de->d_type) { + case DT_BLK: + ftwbuf->typeflag = BFTW_BLK; + break; + case DT_CHR: + ftwbuf->typeflag = BFTW_CHR; + break; + case DT_DIR: + ftwbuf->typeflag = BFTW_DIR; + break; + case DT_FIFO: + ftwbuf->typeflag = BFTW_FIFO; + break; + case DT_LNK: + ftwbuf->typeflag = BFTW_LNK; + break; + case DT_REG: + ftwbuf->typeflag = BFTW_REG; + break; + case DT_SOCK: + ftwbuf->typeflag = BFTW_SOCK; + break; + } +#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); + if (ret != 0) { + return ret; + } + + ftwbuf->statbuf = sb; + + switch (sb->st_mode & S_IFMT) { + case S_IFBLK: + ftwbuf->typeflag = BFTW_BLK; + break; + case S_IFCHR: + ftwbuf->typeflag = BFTW_CHR; + break; + case S_IFDIR: + ftwbuf->typeflag = BFTW_DIR; + break; + case S_IFIFO: + ftwbuf->typeflag = BFTW_FIFO; + break; + case S_IFLNK: + ftwbuf->typeflag = BFTW_LNK; + break; + case S_IFREG: + ftwbuf->typeflag = BFTW_REG; + break; + case S_IFSOCK: + ftwbuf->typeflag = BFTW_SOCK; + break; + } + + return 0; +} + +int bftw(const char *path, bftw_fn *fn, int nopenfd, int flags, void *ptr) { int ret = -1, err = 0; dircache cache; dircache_init(&cache, nopenfd); + dircache_entry *current = NULL; + dirqueue queue; dirqueue_init(&queue); - dynstr path; - dynstr_init(&path); + dynstr dynpath; + dynstr_init(&dynpath); + + struct BFTW ftwbuf; + ftwbuf_init(&ftwbuf, 0, 0); + + struct stat sb; + if (ftwbuf_stat(&ftwbuf, &sb, AT_FDCWD, path) != 0) { + if (!(flags & BFTW_RECOVER)) { + goto fail; + } + + err = errno; + ftwbuf_set_error(&ftwbuf, err); + } + + switch (fn(path, &ftwbuf, ptr)) { + case BFTW_CONTINUE: + case BFTW_SKIP_SIBLINGS: + break; + + case BFTW_SKIP_SUBTREE: + case BFTW_STOP: + goto done; + + default: + err = EINVAL; + goto fail; + } + + if (err != 0 || ftwbuf.typeflag != BFTW_DIR) { + goto done; + } - dircache_entry *current = dircache_add(&cache, NULL, dirpath); + current = dircache_add(&cache, NULL, path); if (!current) { goto fail; } do { - if (dircache_entry_path(current, &path) != 0) { + if (dircache_entry_path(current, &dynpath) != 0) { goto fail; } - size_t pathlen = path.length; + size_t pathlen = dynpath.length; - DIR *dir = dircache_entry_open(&cache, current, path.str); + DIR *dir = dircache_entry_open(&cache, current, dynpath.str); if (!dir) { if (!(flags & BFTW_RECOVER)) { goto fail; @@ -451,17 +560,10 @@ int bftw(const char *dirpath, bftw_fn *fn, int nopenfd, int flags, void *ptr) { err = errno; - struct BFTW ftwbuf = { - .statbuf = NULL, - .typeflag = BFTW_ERROR, - .base = current->nameoff, - .level = current->depth, - .error = err, - }; - - int action = fn(path.str, &ftwbuf, ptr); + ftwbuf_init(&ftwbuf, current->nameoff, current->depth); + ftwbuf_set_error(&ftwbuf, err); - switch (action) { + switch (fn(dynpath.str, &ftwbuf, ptr)) { case BFTW_CONTINUE: case BFTW_SKIP_SIBLINGS: case BFTW_SKIP_SUBTREE: @@ -474,8 +576,6 @@ int bftw(const char *dirpath, bftw_fn *fn, int nopenfd, int flags, void *ptr) { err = EINVAL; goto fail; } - - goto next; } struct dirent *de; @@ -484,79 +584,25 @@ int bftw(const char *dirpath, bftw_fn *fn, int nopenfd, int flags, void *ptr) { continue; } - if (dynstr_concat(&path, pathlen, de->d_name) != 0) { + if (dynstr_concat(&dynpath, pathlen, de->d_name) != 0) { goto fail; } - struct BFTW ftwbuf = { - .statbuf = NULL, - .typeflag = BFTW_UNKNOWN, - .base = pathlen, - .level = current->depth + 1, - .error = 0, - }; - -#if defined(_DIRENT_HAVE_D_TYPE) || defined(DT_DIR) - switch (de->d_type) { - case DT_BLK: - ftwbuf.typeflag = BFTW_BLK; - break; - case DT_CHR: - ftwbuf.typeflag = BFTW_CHR; - break; - case DT_DIR: - ftwbuf.typeflag = BFTW_DIR; - break; - case DT_FIFO: - ftwbuf.typeflag = BFTW_FIFO; - break; - case DT_LNK: - ftwbuf.typeflag = BFTW_LNK; - break; - case DT_REG: - ftwbuf.typeflag = BFTW_REG; - break; - case DT_SOCK: - ftwbuf.typeflag = BFTW_SOCK; - break; - } -#endif - - struct stat sb; + ftwbuf_init(&ftwbuf, pathlen, current->depth + 1); + ftwbuf_use_dirent(&ftwbuf, de); if ((flags & BFTW_STAT) || ftwbuf.typeflag == BFTW_UNKNOWN) { - if (fstatat(dirfd(dir), de->d_name, &sb, AT_SYMLINK_NOFOLLOW) == 0) { - ftwbuf.statbuf = &sb; - - switch (sb.st_mode & S_IFMT) { - case S_IFBLK: - ftwbuf.typeflag = BFTW_BLK; - break; - case S_IFCHR: - ftwbuf.typeflag = BFTW_CHR; - break; - case S_IFDIR: - ftwbuf.typeflag = BFTW_DIR; - break; - case S_IFIFO: - ftwbuf.typeflag = BFTW_FIFO; - break; - case S_IFLNK: - ftwbuf.typeflag = BFTW_LNK; - break; - case S_IFREG: - ftwbuf.typeflag = BFTW_REG; - break; - case S_IFSOCK: - ftwbuf.typeflag = BFTW_SOCK; - break; + if (ftwbuf_stat(&ftwbuf, &sb, dirfd(dir), de->d_name) != 0) { + if (!(flags & BFTW_RECOVER)) { + goto fail; } + + err = errno; + ftwbuf_set_error(&ftwbuf, err); } } - int action = fn(path.str, &ftwbuf, ptr); - - switch (action) { + switch (fn(dynpath.str, &ftwbuf, ptr)) { case BFTW_CONTINUE: if (ftwbuf.typeflag == BFTW_DIR) { dircache_entry *next = dircache_add(&cache, current, de->d_name); @@ -605,7 +651,7 @@ fail: current = dirqueue_pop(&queue); } - dynstr_free(&path); + dynstr_free(&dynpath); errno = err; return ret; @@ -51,7 +51,7 @@ typedef int bftw_fn(const char *fpath, const struct BFTW *ftwbuf, void *ptr); * and invokes a callback for each path it encounters. However, bftw() operates * breadth-first. * - * @param dirpath + * @param path * The starting path. * @param fn * The callback to invoke. @@ -64,7 +64,7 @@ typedef int bftw_fn(const char *fpath, const struct BFTW *ftwbuf, void *ptr); * @return * 0 on success, or -1 on failure. */ -int bftw(const char *dirpath, bftw_fn *fn, int nopenfd, int flags, void *ptr); +int bftw(const char *path, bftw_fn *fn, int nopenfd, int flags, void *ptr); /** typeflag: Block device. */ #define BFTW_BLK 0 @@ -10,11 +10,13 @@ *********************************************************************/ #include "color.h" +#include "bftw.h" #include <stdarg.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h> typedef struct ext_color ext_color; @@ -280,28 +282,23 @@ static void print_esc(const char *esc, FILE *file) { fputs("m", file); } -void pretty_print(const color_table *colors, const char *fpath, const struct stat *sb) { +void pretty_print(const color_table *colors, const char *fpath, const struct BFTW *ftwbuf) { if (!colors) { puts(fpath); return; } - const char *filename = strrchr(fpath, '/'); - if (filename) { - ++filename; - } else { - filename = fpath + strlen(fpath); - } + const char *filename = fpath + ftwbuf->base; if (colors->dir) { print_esc(colors->dir, stdout); } - fwrite(fpath, 1, filename - fpath, stdout); + fwrite(fpath, 1, ftwbuf->base, stdout); if (colors->dir) { print_esc(colors->reset, stdout); } - const char *color = file_color(colors, filename, sb); + const char *color = file_color(colors, filename, ftwbuf->statbuf); if (color) { print_esc(color, stdout); } @@ -13,7 +13,6 @@ #define BFS_COLOR_H #include "bftw.h" -#include <sys/stat.h> /** * A lookup table for colors. @@ -36,10 +35,10 @@ color_table *parse_colors(char *ls_colors); * The color table to use. * @param fpath * The file path to print. - * @param sb - * A stat() buffer for fpath. + * @param ftwbuf + * The bftw() data for fpath. */ -void pretty_print(const color_table *colors, const char *fpath, const struct stat *sb); +void pretty_print(const color_table *colors, const char *fpath, const struct BFTW *ftwbuf); /** * Pretty-print an error. |