summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bfs.c2
-rw-r--r--bftw.c214
-rw-r--r--bftw.h4
-rw-r--r--color.c15
-rw-r--r--color.h7
5 files changed, 142 insertions, 100 deletions
diff --git a/bfs.c b/bfs.c
index 4e9671a..7090817 100644
--- a/bfs.c
+++ b/bfs.c
@@ -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;
}
diff --git a/bftw.c b/bftw.c
index b7b5da6..ade7dfb 100644
--- a/bftw.c
+++ b/bftw.c
@@ -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;
diff --git a/bftw.h b/bftw.h
index 0946054..a7c14d9 100644
--- a/bftw.h
+++ b/bftw.h
@@ -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
diff --git a/color.c b/color.c
index 521fd09..d994d17 100644
--- a/color.c
+++ b/color.c
@@ -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);
}
diff --git a/color.h b/color.h
index 1432072..ad2b53c 100644
--- a/color.h
+++ b/color.h
@@ -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.