summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bfs.c46
-rw-r--r--bftw.c90
-rw-r--r--bftw.h118
-rw-r--r--color.c14
-rw-r--r--color.h10
5 files changed, 141 insertions, 137 deletions
diff --git a/bfs.c b/bfs.c
index 359df63..d640068 100644
--- a/bfs.c
+++ b/bfs.c
@@ -36,14 +36,12 @@ typedef struct cmdline cmdline;
* Ephemeral state for evaluating an expression.
*/
typedef struct {
- /** The path to the encountered file. */
- const char *fpath;
- /** Additional data about the current file. */
+ /** Data about the current file. */
const struct BFTW *ftwbuf;
/** The parsed command line. */
const cmdline *cl;
/** The bftw() callback return value. */
- int ret;
+ bftw_action action;
} eval_state;
/**
@@ -288,15 +286,16 @@ static const char *skip_paths(parser_state *state) {
* -delete action.
*/
static bool eval_delete(const expression *expr, eval_state *state) {
+ const struct BFTW *ftwbuf = state->ftwbuf;
+
int flag = 0;
- if (state->ftwbuf->typeflag == BFTW_DIR) {
+ if (ftwbuf->typeflag == BFTW_DIR) {
flag |= AT_REMOVEDIR;
}
- // TODO: Have bftw() tell us a better base fd to use
- if (unlinkat(AT_FDCWD, state->fpath, flag) != 0) {
- print_error(state->cl->colors, state->fpath, errno);
- state->ret = BFTW_STOP;
+ if (unlinkat(ftwbuf->at_fd, ftwbuf->at_path, flag) != 0) {
+ print_error(state->cl->colors, ftwbuf->path, errno);
+ state->action = BFTW_STOP;
}
return true;
@@ -306,7 +305,7 @@ static bool eval_delete(const expression *expr, eval_state *state) {
* -prune action.
*/
static bool eval_prune(const expression *expr, eval_state *state) {
- state->ret = BFTW_SKIP_SUBTREE;
+ state->action = BFTW_SKIP_SUBTREE;
return true;
}
@@ -314,8 +313,8 @@ static bool eval_prune(const expression *expr, eval_state *state) {
* -hidden test.
*/
static bool eval_hidden(const expression *expr, eval_state *state) {
- size_t base = state->ftwbuf->base;
- return base > 0 && state->fpath[base] == '.';
+ const struct BFTW *ftwbuf = state->ftwbuf;
+ return ftwbuf->nameoff > 0 && ftwbuf->path[ftwbuf->nameoff] == '.';
}
/**
@@ -334,14 +333,15 @@ static bool eval_nohidden(const expression *expr, eval_state *state) {
* -name test.
*/
static bool eval_name(const expression *expr, eval_state *state) {
- return fnmatch(expr->sdata, state->fpath + state->ftwbuf->base, 0) == 0;
+ const struct BFTW *ftwbuf = state->ftwbuf;
+ return fnmatch(expr->sdata, ftwbuf->path + ftwbuf->nameoff, 0) == 0;
}
/**
* -print action.
*/
static bool eval_print(const expression *expr, eval_state *state) {
- pretty_print(state->cl->colors, state->fpath, state->ftwbuf);
+ pretty_print(state->cl->colors, state->ftwbuf);
return true;
}
@@ -349,7 +349,8 @@ static bool eval_print(const expression *expr, eval_state *state) {
* -print0 action.
*/
static bool eval_print0(const expression *expr, eval_state *state) {
- fwrite(state->fpath, 1, strlen(state->fpath) + 1, stdout);
+ const char *path = state->ftwbuf->path;
+ fwrite(path, 1, strlen(path) + 1, stdout);
return true;
}
@@ -854,30 +855,29 @@ static int infer_nopenfd() {
/**
* bftw() callback.
*/
-static int cmdline_callback(const char *fpath, const struct BFTW *ftwbuf, void *ptr) {
+static bftw_action cmdline_callback(const struct BFTW *ftwbuf, void *ptr) {
const cmdline *cl = ptr;
if (ftwbuf->typeflag == BFTW_ERROR) {
- print_error(cl->colors, fpath, ftwbuf->error);
+ print_error(cl->colors, ftwbuf->path, ftwbuf->error);
return BFTW_SKIP_SUBTREE;
}
eval_state state = {
- .fpath = fpath,
.ftwbuf = ftwbuf,
.cl = cl,
- .ret = BFTW_CONTINUE,
+ .action = BFTW_CONTINUE,
};
- if (ftwbuf->level >= cl->maxdepth) {
- state.ret = BFTW_SKIP_SUBTREE;
+ if (ftwbuf->depth >= cl->maxdepth) {
+ state.action = BFTW_SKIP_SUBTREE;
}
- if (ftwbuf->level >= cl->mindepth && ftwbuf->level <= cl->maxdepth) {
+ if (ftwbuf->depth >= cl->mindepth && ftwbuf->depth <= cl->maxdepth) {
cl->expr->eval(cl->expr, &state);
}
- return state.ret;
+ return state.action;
}
/**
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;
diff --git a/bftw.h b/bftw.h
index a368777..14055ac 100644
--- a/bftw.h
+++ b/bftw.h
@@ -12,37 +12,90 @@
#ifndef BFS_BFTW_H
#define BFS_BFTW_H
+#include <stddef.h>
#include <sys/stat.h>
/**
+ * Possible file types.
+ */
+typedef enum {
+ /** Unknown type. */
+ BFTW_UNKNOWN,
+ /** Block device. */
+ BFTW_BLK,
+ /** Character device. */
+ BFTW_CHR,
+ /** Directory. */
+ BFTW_DIR,
+ /** Pipe. */
+ BFTW_FIFO,
+ /** Symbolic link. */
+ BFTW_LNK,
+ /** Regular file. */
+ BFTW_REG,
+ /** Socket. */
+ BFTW_SOCK,
+ /** An error occurred for this file. */
+ BFTW_ERROR,
+} bftw_typeflag;
+
+/**
* 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;
+ /** The path to the file. */
+ const char *path;
+ /** The string offset of the filename. */
+ size_t nameoff;
+
+ /** The depth of this file in the traversal. */
+ size_t depth;
+
+ /** The file type. */
+ bftw_typeflag typeflag;
/** The errno that occurred, if typeflag == BFTW_ERROR. */
int error;
+
+ /** A stat() buffer; may be NULL if no stat() call was needed. */
+ const struct stat *statbuf;
+
+ /** A parent file descriptor for the *at() family of calls. */
+ int at_fd;
+ /** The path relative to atfd for the *at() family of calls. */
+ const char *at_path;
};
+typedef enum {
+ /** Keep walking. */
+ BFTW_CONTINUE,
+ /** Skip this path's siblings. */
+ BFTW_SKIP_SIBLINGS,
+ /** Skip this path's children. */
+ BFTW_SKIP_SUBTREE,
+ /** Stop walking. */
+ BFTW_STOP,
+} bftw_action;
+
/**
* Callback function type for bftw().
*
- * @param fpath
- * The path to the encountered file.
* @param ftwbuf
- * Additional data about the current file.
+ * Data about the current file.
* @param ptr
* The pointer passed to bftw().
* @return
- * An action value (see below).
+ * An action value.
*/
-typedef int bftw_fn(const char *fpath, const struct BFTW *ftwbuf, void *ptr);
+typedef bftw_action bftw_fn(const struct BFTW *ftwbuf, void *ptr);
+
+typedef enum {
+ /** stat() each encountered file. */
+ BFTW_STAT = 1 << 0,
+ /** Attempt to recover from encountered errors. */
+ BFTW_RECOVER = 1 << 1,
+ /** Visit all of a directory's descendants before the directory itself. */
+ BFTW_DEPTH = 1 << 2,
+} bftw_flags;
/**
* Breadth First Tree Walk (or Better File Tree Walk).
@@ -58,47 +111,12 @@ typedef int bftw_fn(const char *fpath, const struct BFTW *ftwbuf, void *ptr);
* @param nopenfd
* The maximum number of file descriptors to keep open.
* @param flags
- * Flags that control bftw() behavior (see below).
+ * Flags that control bftw() behavior.
* @param ptr
* A generic pointer which is passed to fn().
* @return
* 0 on success, or -1 on failure.
*/
-int bftw(const char *path, bftw_fn *fn, int nopenfd, int flags, void *ptr);
-
-/** typeflag: Block device. */
-#define BFTW_BLK 0
-/** typeflag: Character device. */
-#define BFTW_CHR 1
-/** typeflag: Directory. */
-#define BFTW_DIR 2
-/** typeflag: Pipe. */
-#define BFTW_FIFO 3
-/** typeflag: Symbolic link. */
-#define BFTW_LNK 4
-/** typeflag: Regular file. */
-#define BFTW_REG 5
-/** typeflag: Socket. */
-#define BFTW_SOCK 6
-/** typeflag: Unknown type. */
-#define BFTW_UNKNOWN 7
-/** typeflag: An error occurred for this file. */
-#define BFTW_ERROR 8
-
-/** action: Keep walking. */
-#define BFTW_CONTINUE 0
-/** action: Skip this path's siblings. */
-#define BFTW_SKIP_SIBLINGS 1
-/** action: Skip this path's children. */
-#define BFTW_SKIP_SUBTREE 2
-/** action: Stop walking. */
-#define BFTW_STOP 3
-
-/** flag: stat() each encountered file. */
-#define BFTW_STAT (1 << 0)
-/** flag: Attempt to recover from encountered errors. */
-#define BFTW_RECOVER (1 << 1)
-/** flag: Visit all of a directory's descendants before the directory itself. */
-#define BFTW_DEPTH (1 << 2)
+int bftw(const char *path, bftw_fn *fn, int nopenfd, bftw_flags flags, void *ptr);
#endif // BFS_BFTW_H
diff --git a/color.c b/color.c
index 2928fe2..b67d6a4 100644
--- a/color.c
+++ b/color.c
@@ -282,18 +282,20 @@ static void print_esc(const char *esc, FILE *file) {
fputs("m", file);
}
-void pretty_print(const color_table *colors, const char *fpath, const struct BFTW *ftwbuf) {
+void pretty_print(const color_table *colors, const struct BFTW *ftwbuf) {
+ const char *path = ftwbuf->path;
+
if (!colors) {
- puts(fpath);
+ puts(path);
return;
}
- const char *filename = fpath + ftwbuf->base;
+ const char *filename = path + ftwbuf->nameoff;
if (colors->dir) {
print_esc(colors->dir, stdout);
}
- fwrite(fpath, 1, ftwbuf->base, stdout);
+ fwrite(path, 1, ftwbuf->nameoff, stdout);
if (colors->dir) {
print_esc(colors->reset, stdout);
}
@@ -309,7 +311,7 @@ void pretty_print(const color_table *colors, const char *fpath, const struct BFT
fputs("\n", stdout);
}
-void print_error(const color_table *colors, const char *fpath, int error) {
+void print_error(const color_table *colors, const char *path, int error) {
const char *color = NULL;
if (colors) {
color = colors->orphan;
@@ -318,7 +320,7 @@ void print_error(const color_table *colors, const char *fpath, int error) {
if (color) {
print_esc(color, stderr);
}
- fprintf(stderr, "Error at %s: %s\n", fpath, strerror(error));
+ fprintf(stderr, "Error at %s: %s\n", path, strerror(error));
if (color) {
print_esc(colors->reset, stderr);
}
diff --git a/color.h b/color.h
index 25523de..e8d984c 100644
--- a/color.h
+++ b/color.h
@@ -33,24 +33,22 @@ color_table *parse_colors(char *ls_colors);
*
* @param colors
* The color table to use.
- * @param fpath
- * The file path to print.
* @param ftwbuf
- * The bftw() data for fpath.
+ * The bftw() data for the current path.
*/
-void pretty_print(const color_table *colors, const char *fpath, const struct BFTW *ftwbuf);
+void pretty_print(const color_table *colors, const struct BFTW *ftwbuf);
/**
* Pretty-print an error.
*
* @param colors
* The color table to use.
- * @param fpath
+ * @param path
* The file path in error.
* @param error
* The error code that occurred.
*/
-void print_error(const color_table *colors, const char *fpath, int error);
+void print_error(const color_table *colors, const char *path, int error);
/**
* Free a color table.