summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--bftw.c188
-rw-r--r--bftw.h40
-rw-r--r--color.c25
-rw-r--r--dir.c200
-rw-r--r--dir.h124
-rw-r--r--eval.c108
-rw-r--r--fsade.c19
-rw-r--r--parse.c21
-rw-r--r--printf.c25
-rw-r--r--util.c18
-rw-r--r--util.h6
12 files changed, 473 insertions, 302 deletions
diff --git a/Makefile b/Makefile
index 5df2812..e78605e 100644
--- a/Makefile
+++ b/Makefile
@@ -142,6 +142,7 @@ bfs: \
ctx.o \
darray.o \
diag.o \
+ dir.o \
dstring.o \
eval.o \
exec.o \
diff --git a/bftw.c b/bftw.c
index aac6799..2e35594 100644
--- a/bftw.c
+++ b/bftw.c
@@ -33,13 +33,13 @@
*/
#include "bftw.h"
+#include "dir.h"
#include "dstring.h"
#include "mtab.h"
#include "stat.h"
#include "trie.h"
#include "util.h"
#include <assert.h>
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdbool.h>
@@ -70,7 +70,7 @@ struct bftw_file {
int fd;
/** This file's type, if known. */
- enum bftw_type type;
+ enum bfs_type type;
/** The device number, for cycle detection. */
dev_t dev;
/** The inode number, for cycle detection. */
@@ -322,7 +322,7 @@ static struct bftw_file *bftw_file_new(struct bftw_cache *cache, struct bftw_fil
file->refcount = 1;
file->fd = -1;
- file->type = BFTW_UNKNOWN;
+ file->type = BFS_UNKNOWN;
file->dev = -1;
file->ino = -1;
@@ -433,7 +433,7 @@ static int bftw_file_open(struct bftw_cache *cache, struct bftw_file *file, cons
}
/**
- * Open a DIR* for a bftw_file.
+ * Open a bftw_file as a directory.
*
* @param cache
* The cache to hold the file.
@@ -442,16 +442,16 @@ static int bftw_file_open(struct bftw_cache *cache, struct bftw_file *file, cons
* @param path
* The full path to the directory.
* @return
- * The opened DIR *, or NULL on error.
+ * The opened directory, or NULL on error.
*/
-static DIR *bftw_file_opendir(struct bftw_cache *cache, struct bftw_file *file, const char *path) {
+static struct bfs_dir *bftw_file_opendir(struct bftw_cache *cache, struct bftw_file *file, const char *path) {
int fd = bftw_file_open(cache, file, path);
if (fd < 0) {
return NULL;
}
// Now we dup() the fd and pass it to fdopendir(). This way we can
- // close the DIR* as soon as we're done with it, reducing the memory
+ // close the bfs_dir as soon as we're done with it, reducing the memory
// footprint significantly, while keeping the fd around for future
// openat() calls.
@@ -467,7 +467,7 @@ static DIR *bftw_file_opendir(struct bftw_cache *cache, struct bftw_file *file,
return NULL;
}
- DIR *ret = fdopendir(dfd);
+ struct bfs_dir *ret = bfs_opendir(dfd, NULL);
if (!ret) {
int error = errno;
close(dfd);
@@ -618,9 +618,11 @@ struct bftw_state {
struct bftw_file *previous;
/** The currently open directory. */
- DIR *dir;
+ struct bfs_dir *dir;
/** The current directory entry. */
- struct dirent *de;
+ struct bfs_dirent *de;
+ /** Storage for the directory entry. */
+ struct bfs_dirent de_storage;
/** Any error encountered while reading the directory. */
int direrror;
@@ -645,7 +647,7 @@ static int bftw_state_init(struct bftw_state *state, const struct bftw_args *arg
goto err;
}
- // Reserve 1 fd for the open DIR *
+ // Reserve 1 fd for the open bfs_dir
if (bftw_cache_init(&state->cache, args->nopenfd - 1) != 0) {
goto err;
}
@@ -673,103 +675,6 @@ err:
return -1;
}
-enum bftw_type bftw_mode_to_type(mode_t mode) {
- switch (mode & S_IFMT) {
-#ifdef S_IFBLK
- case S_IFBLK:
- return BFTW_BLK;
-#endif
-#ifdef S_IFCHR
- case S_IFCHR:
- return BFTW_CHR;
-#endif
-#ifdef S_IFDIR
- case S_IFDIR:
- return BFTW_DIR;
-#endif
-#ifdef S_IFDOOR
- case S_IFDOOR:
- return BFTW_DOOR;
-#endif
-#ifdef S_IFIFO
- case S_IFIFO:
- return BFTW_FIFO;
-#endif
-#ifdef S_IFLNK
- case S_IFLNK:
- return BFTW_LNK;
-#endif
-#ifdef S_IFPORT
- case S_IFPORT:
- return BFTW_PORT;
-#endif
-#ifdef S_IFREG
- case S_IFREG:
- return BFTW_REG;
-#endif
-#ifdef S_IFSOCK
- case S_IFSOCK:
- return BFTW_SOCK;
-#endif
-#ifdef S_IFWHT
- case S_IFWHT:
- return BFTW_WHT;
-#endif
-
- default:
- return BFTW_UNKNOWN;
- }
-}
-
-static enum bftw_type bftw_dirent_type(const struct dirent *de) {
-#if defined(_DIRENT_HAVE_D_TYPE) || defined(DT_UNKNOWN)
- switch (de->d_type) {
-#ifdef DT_BLK
- case DT_BLK:
- return BFTW_BLK;
-#endif
-#ifdef DT_CHR
- case DT_CHR:
- return BFTW_CHR;
-#endif
-#ifdef DT_DIR
- case DT_DIR:
- return BFTW_DIR;
-#endif
-#ifdef DT_DOOR
- case DT_DOOR:
- return BFTW_DOOR;
-#endif
-#ifdef DT_FIFO
- case DT_FIFO:
- return BFTW_FIFO;
-#endif
-#ifdef DT_LNK
- case DT_LNK:
- return BFTW_LNK;
-#endif
-#ifdef DT_PORT
- case DT_PORT:
- return BFTW_PORT;
-#endif
-#ifdef DT_REG
- case DT_REG:
- return BFTW_REG;
-#endif
-#ifdef DT_SOCK
- case DT_SOCK:
- return BFTW_SOCK;
-#endif
-#ifdef DT_WHT
- case DT_WHT:
- return BFTW_WHT;
-#endif
- }
-#endif
-
- return BFTW_UNKNOWN;
-}
-
/** Cached bfs_stat(). */
static const struct bfs_stat *bftw_stat_impl(struct BFTW *ftwbuf, struct bftw_stat *cache, enum bfs_stat_flags flags) {
if (!cache->buf) {
@@ -817,20 +722,20 @@ const struct bfs_stat *bftw_cached_stat(const struct BFTW *ftwbuf, enum bfs_stat
}
}
-enum bftw_type bftw_type(const struct BFTW *ftwbuf, enum bfs_stat_flags flags) {
+enum bfs_type bftw_type(const struct BFTW *ftwbuf, enum bfs_stat_flags flags) {
if (ftwbuf->stat_flags & BFS_STAT_NOFOLLOW) {
- if ((flags & BFS_STAT_NOFOLLOW) || ftwbuf->type != BFTW_LNK) {
+ if ((flags & BFS_STAT_NOFOLLOW) || ftwbuf->type != BFS_LNK) {
return ftwbuf->type;
}
- } else if ((flags & (BFS_STAT_NOFOLLOW | BFS_STAT_TRYFOLLOW)) == BFS_STAT_TRYFOLLOW || ftwbuf->type == BFTW_LNK) {
+ } else if ((flags & (BFS_STAT_NOFOLLOW | BFS_STAT_TRYFOLLOW)) == BFS_STAT_TRYFOLLOW || ftwbuf->type == BFS_LNK) {
return ftwbuf->type;
}
const struct bfs_stat *statbuf = bftw_stat(ftwbuf, flags);
if (statbuf) {
- return bftw_mode_to_type(statbuf->mode);
+ return bfs_mode_to_type(statbuf->mode);
} else {
- return BFTW_ERROR;
+ return BFS_ERROR;
}
}
@@ -865,15 +770,15 @@ static bool bftw_need_stat(const struct bftw_state *state) {
}
const struct BFTW *ftwbuf = &state->ftwbuf;
- if (ftwbuf->type == BFTW_UNKNOWN) {
+ if (ftwbuf->type == BFS_UNKNOWN) {
return true;
}
- if (ftwbuf->type == BFTW_LNK && !(ftwbuf->stat_flags & BFS_STAT_NOFOLLOW)) {
+ if (ftwbuf->type == BFS_LNK && !(ftwbuf->stat_flags & BFS_STAT_NOFOLLOW)) {
return true;
}
- if (ftwbuf->type == BFTW_DIR) {
+ if (ftwbuf->type == BFS_DIR) {
if (state->flags & (BFTW_DETECT_CYCLES | BFTW_SKIP_MOUNTS | BFTW_PRUNE_MOUNTS)) {
return true;
}
@@ -930,14 +835,14 @@ static int bftw_ensure_open(struct bftw_cache *cache, struct bftw_file *file, co
*/
static void bftw_init_ftwbuf(struct bftw_state *state, enum bftw_visit visit) {
struct bftw_file *file = state->file;
- const struct dirent *de = state->de;
+ const struct bfs_dirent *de = state->de;
struct BFTW *ftwbuf = &state->ftwbuf;
ftwbuf->path = state->path;
ftwbuf->root = file ? file->root->name : ftwbuf->path;
ftwbuf->depth = 0;
ftwbuf->visit = visit;
- ftwbuf->type = BFTW_UNKNOWN;
+ ftwbuf->type = BFS_UNKNOWN;
ftwbuf->error = state->direrror;
ftwbuf->at_fd = AT_FDCWD;
ftwbuf->at_path = ftwbuf->path;
@@ -949,7 +854,7 @@ static void bftw_init_ftwbuf(struct bftw_state *state, enum bftw_visit visit) {
if (de) {
parent = file;
ftwbuf->depth = file->depth + 1;
- ftwbuf->type = bftw_dirent_type(de);
+ ftwbuf->type = de->type;
ftwbuf->nameoff = bftw_child_nameoff(file);
} else if (file) {
parent = file->parent;
@@ -974,7 +879,7 @@ static void bftw_init_ftwbuf(struct bftw_state *state, enum bftw_visit visit) {
}
if (ftwbuf->error != 0) {
- ftwbuf->type = BFTW_ERROR;
+ ftwbuf->type = BFS_ERROR;
return;
}
@@ -991,18 +896,18 @@ static void bftw_init_ftwbuf(struct bftw_state *state, enum bftw_visit visit) {
if (bftw_need_stat(state)) {
statbuf = bftw_stat(ftwbuf, ftwbuf->stat_flags);
if (statbuf) {
- ftwbuf->type = bftw_mode_to_type(statbuf->mode);
+ ftwbuf->type = bfs_mode_to_type(statbuf->mode);
} else {
- ftwbuf->type = BFTW_ERROR;
+ ftwbuf->type = BFS_ERROR;
ftwbuf->error = errno;
return;
}
}
- if (ftwbuf->type == BFTW_DIR && (state->flags & BFTW_DETECT_CYCLES)) {
+ if (ftwbuf->type == BFS_DIR && (state->flags & BFTW_DETECT_CYCLES)) {
for (const struct bftw_file *ancestor = parent; ancestor; ancestor = ancestor->parent) {
if (ancestor->dev == statbuf->dev && ancestor->ino == statbuf->ino) {
- ftwbuf->type = BFTW_ERROR;
+ ftwbuf->type = BFS_ERROR;
ftwbuf->error = ELOOP;
return;
}
@@ -1051,8 +956,8 @@ static enum bftw_action bftw_visit(struct bftw_state *state, const char *name, e
const struct BFTW *ftwbuf = &state->ftwbuf;
bftw_init_ftwbuf(state, visit);
- // Never give the callback BFTW_ERROR unless BFTW_RECOVER is specified
- if (ftwbuf->type == BFTW_ERROR && !(state->flags & BFTW_RECOVER)) {
+ // Never give the callback BFS_ERROR unless BFTW_RECOVER is specified
+ if (ftwbuf->type == BFS_ERROR && !(state->flags & BFTW_RECOVER)) {
state->error = ftwbuf->error;
return BFTW_STOP;
}
@@ -1073,7 +978,7 @@ static enum bftw_action bftw_visit(struct bftw_state *state, const char *name, e
return BFTW_STOP;
}
- if (visit != BFTW_PRE || ftwbuf->type != BFTW_DIR) {
+ if (visit != BFTW_PRE || ftwbuf->type != BFS_DIR) {
ret = BFTW_PRUNE;
goto done;
}
@@ -1103,7 +1008,7 @@ static int bftw_push(struct bftw_state *state, const char *name, bool fill_id) {
}
if (state->de) {
- file->type = bftw_dirent_type(state->de);
+ file->type = state->de->type;
}
if (fill_id) {
@@ -1190,14 +1095,17 @@ static int bftw_readdir(struct bftw_state *state) {
return -1;
}
- if (xreaddir(state->dir, &state->de) != 0) {
- state->direrror = errno;
- return -1;
- } else if (state->de) {
- return 1;
+ int ret = bfs_readdir(state->dir, &state->de_storage);
+ if (ret > 0) {
+ state->de = &state->de_storage;
+ } else if (ret == 0) {
+ state->de = NULL;
} else {
- return 0;
+ state->de = NULL;
+ state->direrror = errno;
}
+
+ return ret;
}
/**
@@ -1220,7 +1128,7 @@ enum bftw_release_flags {
static enum bftw_action bftw_closedir(struct bftw_state *state, enum bftw_release_flags flags) {
enum bftw_action ret = BFTW_CONTINUE;
- if (state->dir && closedir(state->dir) != 0) {
+ if (state->dir && bfs_closedir(state->dir) != 0) {
state->direrror = errno;
}
state->de = NULL;
@@ -1352,7 +1260,7 @@ static int bftw_stream(const struct bftw_args *args) {
bftw_batch_start(&state);
while (bftw_readdir(&state) > 0) {
- const char *name = state.de->d_name;
+ const char *name = state.de->name;
switch (bftw_visit(&state, name, BFTW_PRE)) {
case BFTW_CONTINUE:
@@ -1415,7 +1323,7 @@ static int bftw_batch(const struct bftw_args *args) {
bftw_batch_start(&state);
while (bftw_readdir(&state) > 0) {
- if (bftw_push(&state, state.de->d_name, false) != 0) {
+ if (bftw_push(&state, state.de->name, false) != 0) {
goto done;
}
}
@@ -1479,7 +1387,7 @@ static enum bftw_action bftw_ids_callback(const struct BFTW *ftwbuf, void *ptr)
mutbuf->visit = state->visit;
}
- if (ftwbuf->type == BFTW_ERROR) {
+ if (ftwbuf->type == BFS_ERROR) {
if (ftwbuf->depth + 1 >= state->min_depth) {
return state->delegate(ftwbuf, state->ptr);
} else {
@@ -1506,13 +1414,13 @@ static enum bftw_action bftw_ids_callback(const struct BFTW *ftwbuf, void *ptr)
switch (ret) {
case BFTW_CONTINUE:
- if (ftwbuf->type == BFTW_DIR && ftwbuf->depth + 1 >= state->max_depth) {
+ if (ftwbuf->type == BFS_DIR && ftwbuf->depth + 1 >= state->max_depth) {
state->bottom = false;
ret = BFTW_PRUNE;
}
break;
case BFTW_PRUNE:
- if (ftwbuf->type == BFTW_DIR) {
+ if (ftwbuf->type == BFS_DIR) {
if (!trie_insert_str(&state->pruned, ftwbuf->path)) {
state->error = errno;
state->quit = true;
diff --git a/bftw.h b/bftw.h
index 098d12c..30fb39b 100644
--- a/bftw.h
+++ b/bftw.h
@@ -21,46 +21,12 @@
#ifndef BFS_BFTW_H
#define BFS_BFTW_H
+#include "dir.h"
#include "stat.h"
#include <stddef.h>
#include <sys/types.h>
/**
- * Possible file types.
- */
-enum bftw_type {
- /** An error occurred for this file. */
- BFTW_ERROR = -1,
- /** Unknown type. */
- BFTW_UNKNOWN,
- /** Block device. */
- BFTW_BLK,
- /** Character device. */
- BFTW_CHR,
- /** Directory. */
- BFTW_DIR,
- /** Solaris door. */
- BFTW_DOOR,
- /** Pipe. */
- BFTW_FIFO,
- /** Symbolic link. */
- BFTW_LNK,
- /** Solaris event port. */
- BFTW_PORT,
- /** Regular file. */
- BFTW_REG,
- /** Socket. */
- BFTW_SOCK,
- /** BSD whiteout. */
- BFTW_WHT,
-};
-
-/**
- * Convert a bfs_stat() mode to a bftw_type.
- */
-enum bftw_type bftw_mode_to_type(mode_t mode);
-
-/**
* Possible visit occurrences.
*/
enum bftw_visit {
@@ -99,7 +65,7 @@ struct BFTW {
enum bftw_visit visit;
/** The file type. */
- enum bftw_type type;
+ enum bfs_type type;
/** The errno that occurred, if type == BFTW_ERROR. */
int error;
@@ -154,7 +120,7 @@ const struct bfs_stat *bftw_cached_stat(const struct BFTW *ftwbuf, enum bfs_stat
* @return
* The type of the file, or BFTW_ERROR if an error occurred.
*/
-enum bftw_type bftw_type(const struct BFTW *ftwbuf, enum bfs_stat_flags flags);
+enum bfs_type bftw_type(const struct BFTW *ftwbuf, enum bfs_stat_flags flags);
/**
* Walk actions returned by the bftw() callback.
diff --git a/color.c b/color.c
index 1d06e51..cfedba1 100644
--- a/color.c
+++ b/color.c
@@ -16,6 +16,7 @@
#include "color.h"
#include "bftw.h"
+#include "dir.h"
#include "dstring.h"
#include "expr.h"
#include "fsade.h"
@@ -581,8 +582,8 @@ static bool is_link_broken(const struct BFTW *ftwbuf) {
/** Get the color for a file. */
static const char *file_color(const struct colors *colors, const char *filename, const struct BFTW *ftwbuf, enum bfs_stat_flags flags) {
- enum bftw_type type = bftw_type(ftwbuf, flags);
- if (type == BFTW_ERROR) {
+ enum bfs_type type = bftw_type(ftwbuf, flags);
+ if (type == BFS_ERROR) {
goto error;
}
@@ -590,7 +591,7 @@ static const char *file_color(const struct colors *colors, const char *filename,
const char *color = NULL;
switch (type) {
- case BFTW_REG:
+ case BFS_REG:
if (colors->setuid || colors->setgid || colors->executable || colors->multi_hard) {
statbuf = bftw_stat(ftwbuf, flags);
if (!statbuf) {
@@ -620,7 +621,7 @@ static const char *file_color(const struct colors *colors, const char *filename,
break;
- case BFTW_DIR:
+ case BFS_DIR:
if (colors->sticky_other_writable || colors->other_writable || colors->sticky) {
statbuf = bftw_stat(ftwbuf, flags);
if (!statbuf) {
@@ -640,7 +641,7 @@ static const char *file_color(const struct colors *colors, const char *filename,
break;
- case BFTW_LNK:
+ case BFS_LNK:
if (colors->orphan && is_link_broken(ftwbuf)) {
color = colors->orphan;
} else {
@@ -648,19 +649,19 @@ static const char *file_color(const struct colors *colors, const char *filename,
}
break;
- case BFTW_BLK:
+ case BFS_BLK:
color = colors->blockdev;
break;
- case BFTW_CHR:
+ case BFS_CHR:
color = colors->chardev;
break;
- case BFTW_FIFO:
+ case BFS_FIFO:
color = colors->pipe;
break;
- case BFTW_SOCK:
+ case BFS_SOCK:
color = colors->socket;
break;
- case BFTW_DOOR:
+ case BFS_DOOR:
color = colors->door;
break;
@@ -733,7 +734,7 @@ static int print_colored(CFILE *cfile, const char *esc, const char *str, size_t
static ssize_t first_broken_offset(const char *path, const struct BFTW *ftwbuf, enum bfs_stat_flags flags, size_t max) {
ssize_t ret = max;
- if (bftw_type(ftwbuf, flags) != BFTW_ERROR) {
+ if (bftw_type(ftwbuf, flags) != BFS_ERROR) {
goto out;
}
@@ -840,7 +841,7 @@ static int print_path(CFILE *cfile, const struct BFTW *ftwbuf) {
}
enum bfs_stat_flags flags = ftwbuf->stat_flags;
- if (colors && colors->link_as_target && ftwbuf->type == BFTW_LNK) {
+ if (colors && colors->link_as_target && ftwbuf->type == BFS_LNK) {
flags = BFS_STAT_TRYFOLLOW;
}
diff --git a/dir.c b/dir.c
new file mode 100644
index 0000000..23aa62d
--- /dev/null
+++ b/dir.c
@@ -0,0 +1,200 @@
+/****************************************************************************
+ * bfs *
+ * Copyright (C) 2021 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+#include "dir.h"
+#include "util.h"
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+enum bfs_type bfs_mode_to_type(mode_t mode) {
+ switch (mode & S_IFMT) {
+#ifdef S_IFBLK
+ case S_IFBLK:
+ return BFS_BLK;
+#endif
+#ifdef S_IFCHR
+ case S_IFCHR:
+ return BFS_CHR;
+#endif
+#ifdef S_IFDIR
+ case S_IFDIR:
+ return BFS_DIR;
+#endif
+#ifdef S_IFDOOR
+ case S_IFDOOR:
+ return BFS_DOOR;
+#endif
+#ifdef S_IFIFO
+ case S_IFIFO:
+ return BFS_FIFO;
+#endif
+#ifdef S_IFLNK
+ case S_IFLNK:
+ return BFS_LNK;
+#endif
+#ifdef S_IFPORT
+ case S_IFPORT:
+ return BFS_PORT;
+#endif
+#ifdef S_IFREG
+ case S_IFREG:
+ return BFS_REG;
+#endif
+#ifdef S_IFSOCK
+ case S_IFSOCK:
+ return BFS_SOCK;
+#endif
+#ifdef S_IFWHT
+ case S_IFWHT:
+ return BFS_WHT;
+#endif
+
+ default:
+ return BFS_UNKNOWN;
+ }
+}
+
+struct bfs_dir {
+ DIR *dir;
+ struct dirent *ent;
+};
+
+struct bfs_dir *bfs_opendir(int at_fd, const char *at_path) {
+ struct bfs_dir *dir = malloc(sizeof(*dir));
+ if (!dir) {
+ return NULL;
+ }
+
+ int fd;
+ if (at_path) {
+ fd = openat(at_fd, at_path, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
+ } else if (at_fd >= 0) {
+ fd = at_fd;
+ } else {
+ free(dir);
+ errno = EBADF;
+ return NULL;
+ }
+
+ if (fd < 0) {
+ free(dir);
+ return NULL;
+ }
+
+ dir->dir = fdopendir(fd);
+ if (!dir->dir) {
+ int error = errno;
+ close(fd);
+ free(dir);
+ errno = error;
+ return NULL;
+ }
+
+ dir->ent = NULL;
+
+ return dir;
+}
+
+int bfs_dirfd(const struct bfs_dir *dir) {
+ return dirfd(dir->dir);
+}
+
+static enum bfs_type dirent_type(const struct dirent *de) {
+#if defined(_DIRENT_HAVE_D_TYPE) || defined(DT_UNKNOWN)
+ switch (de->d_type) {
+#ifdef DT_BLK
+ case DT_BLK:
+ return BFS_BLK;
+#endif
+#ifdef DT_CHR
+ case DT_CHR:
+ return BFS_CHR;
+#endif
+#ifdef DT_DIR
+ case DT_DIR:
+ return BFS_DIR;
+#endif
+#ifdef DT_DOOR
+ case DT_DOOR:
+ return BFS_DOOR;
+#endif
+#ifdef DT_FIFO
+ case DT_FIFO:
+ return BFS_FIFO;
+#endif
+#ifdef DT_LNK
+ case DT_LNK:
+ return BFS_LNK;
+#endif
+#ifdef DT_PORT
+ case DT_PORT:
+ return BFS_PORT;
+#endif
+#ifdef DT_REG
+ case DT_REG:
+ return BFS_REG;
+#endif
+#ifdef DT_SOCK
+ case DT_SOCK:
+ return BFS_SOCK;
+#endif
+#ifdef DT_WHT
+ case DT_WHT:
+ return BFS_WHT;
+#endif
+ }
+#endif
+
+ return BFS_UNKNOWN;
+}
+
+int bfs_readdir(struct bfs_dir *dir, struct bfs_dirent *dirent) {
+ while (true) {
+ errno = 0;
+ dir->ent = readdir(dir->dir);
+ if (dir->ent) {
+ const char *name = dir->ent->d_name;
+ if (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))) {
+ continue;
+ }
+ if (dirent) {
+ dirent->type = dirent_type(dir->ent);
+ dirent->name = name;
+ }
+ return 1;
+ } else if (errno != 0) {
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+}
+
+int bfs_closedir(struct bfs_dir *dir) {
+ int ret = closedir(dir->dir);
+ free(dir);
+ return ret;
+}
+
+int bfs_freedir(struct bfs_dir *dir) {
+ int ret = dup_cloexec(dirfd(dir->dir));
+ bfs_closedir(dir);
+ return ret;
+}
diff --git a/dir.h b/dir.h
new file mode 100644
index 0000000..5817013
--- /dev/null
+++ b/dir.h
@@ -0,0 +1,124 @@
+/****************************************************************************
+ * bfs *
+ * Copyright (C) 2021 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * Permission to use, copy, modify, and/or distribute this software for any *
+ * purpose with or without fee is hereby granted. *
+ * *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES *
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF *
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR *
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES *
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN *
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF *
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
+ ****************************************************************************/
+
+/**
+ * Directories and their contents.
+ */
+
+#ifndef BFS_DIR_H
+#define BFS_DIR_H
+
+#include <sys/types.h>
+
+/**
+ * A directory.
+ */
+struct bfs_dir;
+
+/**
+ * File types.
+ */
+enum bfs_type {
+ /** An error occurred for this file. */
+ BFS_ERROR = -1,
+ /** Unknown type. */
+ BFS_UNKNOWN,
+ /** Block device. */
+ BFS_BLK,
+ /** Character device. */
+ BFS_CHR,
+ /** Directory. */
+ BFS_DIR,
+ /** Solaris door. */
+ BFS_DOOR,
+ /** Pipe. */
+ BFS_FIFO,
+ /** Symbolic link. */
+ BFS_LNK,
+ /** Solaris event port. */
+ BFS_PORT,
+ /** Regular file. */
+ BFS_REG,
+ /** Socket. */
+ BFS_SOCK,
+ /** BSD whiteout. */
+ BFS_WHT,
+};
+
+/**
+ * Convert a bfs_stat() mode to a bfs_type.
+ */
+enum bfs_type bfs_mode_to_type(mode_t mode);
+
+/**
+ * A directory entry.
+ */
+struct bfs_dirent {
+ /** The type of this file (possibly unknown). */
+ enum bfs_type type;
+ /** The name of this file. */
+ const char *name;
+};
+
+/**
+ * Open a directory.
+ *
+ * @param at_fd
+ * The base directory for path resolution.
+ * @param at_path
+ * The path of the directory to open, relative to at_fd. Pass NULL to
+ * open at_fd itself.
+ * @return
+ * The opened directory, or NULL on failure.
+ */
+struct bfs_dir *bfs_opendir(int at_fd, const char *at_path);
+
+/**
+ * Get the file descriptor for a directory.
+ */
+int bfs_dirfd(const struct bfs_dir *dir);
+
+/**
+ * Read a directory entry.
+ *
+ * @param dir
+ * The directory to read.
+ * @param[out] dirent
+ * The directory entry to populate.
+ * @return
+ * 1 on success, 0 on EOF, or -1 on failure.
+ */
+int bfs_readdir(struct bfs_dir *dir, struct bfs_dirent *dirent);
+
+/**
+ * Close a directory.
+ *
+ * @return
+ * 0 on success, -1 on failure.
+ */
+int bfs_closedir(struct bfs_dir *dir);
+
+/**
+ * Free a directory, keeping an open file descriptor to it.
+ *
+ * @param dir
+ * The directory to free.
+ * @return
+ * The file descriptor on success, or -1 on failure.
+ */
+int bfs_freedir(struct bfs_dir *dir);
+
+#endif // BFS_DIR_H
diff --git a/eval.c b/eval.c
index 2bcfa8a..9e8b0b6 100644
--- a/eval.c
+++ b/eval.c
@@ -25,6 +25,7 @@
#include "ctx.h"
#include "darray.h"
#include "diag.h"
+#include "dir.h"
#include "dstring.h"
#include "exec.h"
#include "expr.h"
@@ -37,7 +38,6 @@
#include "trie.h"
#include "util.h"
#include <assert.h>
-#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
@@ -345,10 +345,10 @@ bool eval_delete(const struct expr *expr, struct eval_state *state) {
int flag = 0;
// We need to know the actual type of the path, not what it points to
- enum bftw_type type = bftw_type(ftwbuf, BFS_STAT_NOFOLLOW);
- if (type == BFTW_DIR) {
+ enum bfs_type type = bftw_type(ftwbuf, BFS_STAT_NOFOLLOW);
+ if (type == BFS_DIR) {
flag |= AT_REMOVEDIR;
- } else if (type == BFTW_ERROR) {
+ } else if (type == BFS_ERROR) {
eval_report_error(state);
return false;
}
@@ -415,29 +415,22 @@ bool eval_empty(const struct expr *expr, struct eval_state *state) {
bool ret = false;
const struct BFTW *ftwbuf = state->ftwbuf;
- if (ftwbuf->type == BFTW_DIR) {
- int dfd = openat(ftwbuf->at_fd, ftwbuf->at_path, O_RDONLY | O_CLOEXEC | O_DIRECTORY);
- if (dfd < 0) {
- eval_report_error(state);
- goto done;
- }
-
- DIR *dir = fdopendir(dfd);
+ if (ftwbuf->type == BFS_DIR) {
+ struct bfs_dir *dir = bfs_opendir(ftwbuf->at_fd, ftwbuf->at_path);
if (!dir) {
eval_report_error(state);
- close(dfd);
goto done;
}
- struct dirent *de;
- if (xreaddir(dir, &de) == 0) {
- ret = !de;
- } else {
+ int did_read = bfs_readdir(dir, NULL);
+ if (did_read < 0) {
eval_report_error(state);
+ } else {
+ ret = !did_read;
}
- closedir(dir);
- } else if (ftwbuf->type == BFTW_REG) {
+ bfs_closedir(dir);
+ } else if (ftwbuf->type == BFS_REG) {
const struct bfs_stat *statbuf = eval_stat(state);
if (statbuf) {
ret = statbuf->size == 0;
@@ -514,7 +507,7 @@ bool eval_lname(const struct expr *expr, struct eval_state *state) {
char *name = NULL;
const struct BFTW *ftwbuf = state->ftwbuf;
- if (ftwbuf->type != BFTW_LNK) {
+ if (ftwbuf->type != BFS_LNK) {
goto done;
}
@@ -580,7 +573,7 @@ bool eval_perm(const struct expr *expr, struct eval_state *state) {
mode_t mode = statbuf->mode;
mode_t target;
- if (state->ftwbuf->type == BFTW_DIR) {
+ if (state->ftwbuf->type == BFS_DIR) {
target = expr->dir_mode;
} else {
target = expr->file_mode;
@@ -648,7 +641,7 @@ bool eval_fls(const struct expr *expr, struct eval_state *state) {
}
}
- if (ftwbuf->type == BFTW_BLK || ftwbuf->type == BFTW_CHR) {
+ if (ftwbuf->type == BFS_BLK || ftwbuf->type == BFS_CHR) {
int ma = bfs_major(statbuf->rdev);
int mi = bfs_minor(statbuf->rdev);
if (fprintf(file, " %3d, %3d", ma, mi) < 0) {
@@ -686,7 +679,7 @@ bool eval_fls(const struct expr *expr, struct eval_state *state) {
goto error;
}
- if (ftwbuf->type == BFTW_LNK) {
+ if (ftwbuf->type == BFS_LNK) {
if (cfprintf(cfile, " -> %pL", ftwbuf) < 0) {
goto error;
}
@@ -914,8 +907,8 @@ bool eval_xattrname(const struct expr *expr, struct eval_state *state) {
bool eval_xtype(const struct expr *expr, struct eval_state *state) {
const struct BFTW *ftwbuf = state->ftwbuf;
enum bfs_stat_flags flags = ftwbuf->stat_flags ^ (BFS_STAT_NOFOLLOW | BFS_STAT_TRYFOLLOW);
- enum bftw_type type = bftw_type(ftwbuf, flags);
- if (type == BFTW_ERROR) {
+ enum bfs_type type = bftw_type(ftwbuf, flags);
+ if (type == BFS_ERROR) {
eval_report_error(state);
return false;
} else {
@@ -1236,28 +1229,28 @@ static void debug_stats(const struct bfs_ctx *ctx, const struct BFTW *ftwbuf) {
}
}
-#define DUMP_BFTW_MAP(value) [value] = #value
+#define DUMP_MAP(value) [value] = #value
/**
- * Dump the bftw_type for -D search.
+ * Dump the bfs_type for -D search.
*/
-static const char *dump_bftw_type(enum bftw_type type) {
+static const char *dump_bfs_type(enum bfs_type type) {
static const char *types[] = {
- DUMP_BFTW_MAP(BFTW_UNKNOWN),
- DUMP_BFTW_MAP(BFTW_BLK),
- DUMP_BFTW_MAP(BFTW_CHR),
- DUMP_BFTW_MAP(BFTW_DIR),
- DUMP_BFTW_MAP(BFTW_DOOR),
- DUMP_BFTW_MAP(BFTW_FIFO),
- DUMP_BFTW_MAP(BFTW_LNK),
- DUMP_BFTW_MAP(BFTW_PORT),
- DUMP_BFTW_MAP(BFTW_REG),
- DUMP_BFTW_MAP(BFTW_SOCK),
- DUMP_BFTW_MAP(BFTW_WHT),
+ DUMP_MAP(BFS_UNKNOWN),
+ DUMP_MAP(BFS_BLK),
+ DUMP_MAP(BFS_CHR),
+ DUMP_MAP(BFS_DIR),
+ DUMP_MAP(BFS_DOOR),
+ DUMP_MAP(BFS_FIFO),
+ DUMP_MAP(BFS_LNK),
+ DUMP_MAP(BFS_PORT),
+ DUMP_MAP(BFS_REG),
+ DUMP_MAP(BFS_SOCK),
+ DUMP_MAP(BFS_WHT),
};
- if (type == BFTW_ERROR) {
- return "BFTW_ERROR";
+ if (type == BFS_ERROR) {
+ return "BFS_ERROR";
} else {
return types[type];
}
@@ -1268,8 +1261,8 @@ static const char *dump_bftw_type(enum bftw_type type) {
*/
static const char *dump_bftw_visit(enum bftw_visit visit) {
static const char *visits[] = {
- DUMP_BFTW_MAP(BFTW_PRE),
- DUMP_BFTW_MAP(BFTW_POST),
+ DUMP_MAP(BFTW_PRE),
+ DUMP_MAP(BFTW_POST),
};
return visits[visit];
}
@@ -1279,9 +1272,9 @@ static const char *dump_bftw_visit(enum bftw_visit visit) {
*/
static const char *dump_bftw_action(enum bftw_action action) {
static const char *actions[] = {
- DUMP_BFTW_MAP(BFTW_CONTINUE),
- DUMP_BFTW_MAP(BFTW_PRUNE),
- DUMP_BFTW_MAP(BFTW_STOP),
+ DUMP_MAP(BFTW_CONTINUE),
+ DUMP_MAP(BFTW_PRUNE),
+ DUMP_MAP(BFTW_STOP),
};
return actions[action];
}
@@ -1327,7 +1320,7 @@ static enum bftw_action eval_callback(const struct BFTW *ftwbuf, void *ptr) {
eval_status(&state, args->bar, &args->last_status, args->count);
}
- if (ftwbuf->type == BFTW_ERROR) {
+ if (ftwbuf->type == BFS_ERROR) {
if (!eval_should_ignore(&state, ftwbuf->error)) {
args->ret = EXIT_FAILURE;
eval_error(&state, "%s.\n", strerror(ftwbuf->error));
@@ -1361,7 +1354,7 @@ static enum bftw_action eval_callback(const struct BFTW *ftwbuf, void *ptr) {
// In -depth mode, only handle directories on the BFTW_POST visit
enum bftw_visit expected_visit = BFTW_PRE;
if ((ctx->flags & BFTW_POST_ORDER)
- && (ctx->strategy == BFTW_IDS || ftwbuf->type == BFTW_DIR)
+ && (ctx->strategy == BFTW_IDS || ftwbuf->type == BFS_DIR)
&& ftwbuf->depth < (size_t)ctx->maxdepth) {
expected_visit = BFTW_POST;
}
@@ -1380,7 +1373,7 @@ done:
fprintf(stderr, "\t.root = \"%s\",\n", ftwbuf->root);
fprintf(stderr, "\t.depth = %zu,\n", ftwbuf->depth);
fprintf(stderr, "\t.visit = %s,\n", dump_bftw_visit(ftwbuf->visit));
- fprintf(stderr, "\t.type = %s,\n", dump_bftw_type(ftwbuf->type));
+ fprintf(stderr, "\t.type = %s,\n", dump_bfs_type(ftwbuf->type));
fprintf(stderr, "\t.error = %d,\n", ftwbuf->error);
fprintf(stderr, "}) == %s\n", dump_bftw_action(state.action));
}
@@ -1406,20 +1399,19 @@ static int infer_fdlimit(const struct bfs_ctx *ctx) {
// Check /proc/self/fd for the current number of open fds, if possible
// (we may have inherited more than just the standard ones)
- DIR *dir = opendir("/proc/self/fd");
+ struct bfs_dir *dir = bfs_opendir(AT_FDCWD, "/proc/self/fd");
if (!dir) {
- dir = opendir("/dev/fd");
+ dir = bfs_opendir(AT_FDCWD, "/dev/fd");
}
if (dir) {
// Account for 'dir' itself
nopen = -1;
- struct dirent *de;
- while (xreaddir(dir, &de) == 0 && de) {
+ while (bfs_readdir(dir, NULL) > 0) {
++nopen;
}
- closedir(dir);
+ bfs_closedir(dir);
}
ret -= nopen;
@@ -1457,10 +1449,10 @@ static void dump_bftw_flags(enum bftw_flags flags) {
*/
static const char *dump_bftw_strategy(enum bftw_strategy strategy) {
static const char *strategies[] = {
- DUMP_BFTW_MAP(BFTW_BFS),
- DUMP_BFTW_MAP(BFTW_DFS),
- DUMP_BFTW_MAP(BFTW_IDS),
- DUMP_BFTW_MAP(BFTW_EDS),
+ DUMP_MAP(BFTW_BFS),
+ DUMP_MAP(BFTW_DFS),
+ DUMP_MAP(BFTW_IDS),
+ DUMP_MAP(BFTW_EDS),
};
return strategies[strategy];
}
diff --git a/fsade.c b/fsade.c
index b56a11d..5c5f090 100644
--- a/fsade.c
+++ b/fsade.c
@@ -16,6 +16,7 @@
#include "fsade.h"
#include "bftw.h"
+#include "dir.h"
#include "dstring.h"
#include "util.h"
#include <errno.h>
@@ -200,7 +201,7 @@ int bfs_check_acl(const struct BFTW *ftwbuf) {
};
static const size_t n_acl_types = sizeof(acl_types)/sizeof(acl_types[0]);
- if (ftwbuf->type == BFTW_LNK) {
+ if (ftwbuf->type == BFS_LNK) {
return 0;
}
@@ -210,7 +211,7 @@ int bfs_check_acl(const struct BFTW *ftwbuf) {
for (size_t i = 0; i < n_acl_types && ret <= 0; ++i) {
acl_type_t type = acl_types[i];
- if (type == ACL_TYPE_DEFAULT && ftwbuf->type != BFTW_DIR) {
+ if (type == ACL_TYPE_DEFAULT && ftwbuf->type != BFS_DIR) {
// ACL_TYPE_DEFAULT is supported only for directories,
// otherwise acl_get_file() gives EACCESS
continue;
@@ -247,7 +248,7 @@ int bfs_check_acl(const struct BFTW *ftwbuf) {
#if BFS_CAN_CHECK_CAPABILITIES
int bfs_check_capabilities(const struct BFTW *ftwbuf) {
- if (ftwbuf->type == BFTW_LNK) {
+ if (ftwbuf->type == BFS_LNK) {
return 0;
}
@@ -298,17 +299,17 @@ int bfs_check_xattrs(const struct BFTW *ftwbuf) {
#if BFS_HAS_SYS_EXTATTR
ssize_t (*extattr_list)(const char *, int, void*, size_t) =
- ftwbuf->type == BFTW_LNK ? extattr_list_link : extattr_list_file;
+ ftwbuf->type == BFS_LNK ? extattr_list_link : extattr_list_file;
len = extattr_list(path, EXTATTR_NAMESPACE_SYSTEM, NULL, 0);
if (len <= 0) {
len = extattr_list(path, EXTATTR_NAMESPACE_USER, NULL, 0);
}
#elif __APPLE__
- int options = ftwbuf->type == BFTW_LNK ? XATTR_NOFOLLOW : 0;
+ int options = ftwbuf->type == BFS_LNK ? XATTR_NOFOLLOW : 0;
len = listxattr(path, NULL, 0, options);
#else
- if (ftwbuf->type == BFTW_LNK) {
+ if (ftwbuf->type == BFS_LNK) {
len = llistxattr(path, NULL, 0);
} else {
len = listxattr(path, NULL, 0);
@@ -337,17 +338,17 @@ int bfs_check_xattr_named(const struct BFTW *ftwbuf, const char *name) {
#if BFS_HAS_SYS_EXTATTR
ssize_t (*extattr_get)(const char *, int, const char *, void*, size_t) =
- ftwbuf->type == BFTW_LNK ? extattr_get_link : extattr_get_file;
+ ftwbuf->type == BFS_LNK ? extattr_get_link : extattr_get_file;
len = extattr_get(path, EXTATTR_NAMESPACE_SYSTEM, name, NULL, 0);
if (len < 0) {
len = extattr_get(path, EXTATTR_NAMESPACE_USER, name, NULL, 0);
}
#elif __APPLE__
- int options = ftwbuf->type == BFTW_LNK ? XATTR_NOFOLLOW : 0;
+ int options = ftwbuf->type == BFS_LNK ? XATTR_NOFOLLOW : 0;
len = getxattr(path, name, NULL, 0, 0, options);
#else
- if (ftwbuf->type == BFTW_LNK) {
+ if (ftwbuf->type == BFS_LNK) {
len = lgetxattr(path, name, NULL, 0);
} else {
len = getxattr(path, name, NULL, 0);
diff --git a/parse.c b/parse.c
index b018e75..0d20991 100644
--- a/parse.c
+++ b/parse.c
@@ -28,6 +28,7 @@
#include "ctx.h"
#include "darray.h"
#include "diag.h"
+#include "dir.h"
#include "eval.h"
#include "exec.h"
#include "expr.h"
@@ -2314,44 +2315,44 @@ static struct expr *parse_type(struct parser_state *state, int x, int arg2) {
const char *c = expr->sdata;
while (true) {
- enum bftw_type type;
+ enum bfs_type type;
double type_prob;
switch (*c) {
case 'b':
- type = BFTW_BLK;
+ type = BFS_BLK;
type_prob = 0.00000721183;
break;
case 'c':
- type = BFTW_CHR;
+ type = BFS_CHR;
type_prob = 0.0000499855;
break;
case 'd':
- type = BFTW_DIR;
+ type = BFS_DIR;
type_prob = 0.114475;
break;
case 'D':
- type = BFTW_DOOR;
+ type = BFS_DOOR;
type_prob = 0.000001;
break;
case 'p':
- type = BFTW_FIFO;
+ type = BFS_FIFO;
type_prob = 0.00000248684;
break;
case 'f':
- type = BFTW_REG;
+ type = BFS_REG;
type_prob = 0.859772;
break;
case 'l':
- type = BFTW_LNK;
+ type = BFS_LNK;
type_prob = 0.0256816;
break;
case 's':
- type = BFTW_SOCK;
+ type = BFS_SOCK;
type_prob = 0.0000116881;
break;
case 'w':
- type = BFTW_WHT;
+ type = BFS_WHT;
type_prob = 0.000001;
break;
diff --git a/printf.c b/printf.c
index 5f04ad3..4b18f04 100644
--- a/printf.c
+++ b/printf.c
@@ -18,6 +18,7 @@
#include "bftw.h"
#include "ctx.h"
#include "diag.h"
+#include "dir.h"
#include "dstring.h"
#include "mtab.h"
#include "pwcache.h"
@@ -309,7 +310,7 @@ static int bfs_printf_l(FILE *file, const struct bfs_printf *directive, const st
char *buf = NULL;
const char *target = "";
- if (ftwbuf->type == BFTW_LNK) {
+ if (ftwbuf->type == BFS_LNK) {
const struct bfs_stat *statbuf = bftw_cached_stat(ftwbuf, BFS_STAT_NOFOLLOW);
size_t len = statbuf ? statbuf->size : 0;
@@ -425,23 +426,23 @@ static int bfs_printf_u(FILE *file, const struct bfs_printf *directive, const st
return fprintf(file, directive->str, pwd->pw_name);
}
-static const char *bfs_printf_type(enum bftw_type type) {
+static const char *bfs_printf_type(enum bfs_type type) {
switch (type) {
- case BFTW_BLK:
+ case BFS_BLK:
return "b";
- case BFTW_CHR:
+ case BFS_CHR:
return "c";
- case BFTW_DIR:
+ case BFS_DIR:
return "d";
- case BFTW_DOOR:
+ case BFS_DOOR:
return "D";
- case BFTW_FIFO:
+ case BFS_FIFO:
return "p";
- case BFTW_LNK:
+ case BFS_LNK:
return "l";
- case BFTW_REG:
+ case BFS_REG:
return "f";
- case BFTW_SOCK:
+ case BFS_SOCK:
return "s";
default:
return "U";
@@ -458,7 +459,7 @@ static int bfs_printf_y(FILE *file, const struct bfs_printf *directive, const st
static int bfs_printf_Y(FILE *file, const struct bfs_printf *directive, const struct BFTW *ftwbuf) {
int error = 0;
- if (ftwbuf->type != BFTW_LNK) {
+ if (ftwbuf->type != BFS_LNK) {
return bfs_printf_y(file, directive, ftwbuf);
}
@@ -466,7 +467,7 @@ static int bfs_printf_Y(FILE *file, const struct bfs_printf *directive, const st
const struct bfs_stat *statbuf = bftw_stat(ftwbuf, BFS_STAT_FOLLOW);
if (statbuf) {
- type = bfs_printf_type(bftw_mode_to_type(statbuf->mode));
+ type = bfs_printf_type(bfs_mode_to_type(statbuf->mode));
} else {
switch (errno) {
case ELOOP:
diff --git a/util.c b/util.c
index 3ba8053..32d8c76 100644
--- a/util.c
+++ b/util.c
@@ -39,24 +39,6 @@
# include <sys/mkdev.h>
#endif
-int xreaddir(DIR *dir, struct dirent **de) {
- while (true) {
- errno = 0;
- *de = readdir(dir);
-
- if (*de) {
- const char *name = (*de)->d_name;
- if (name[0] != '.' || (name[1] != '\0' && (name[1] != '.' || name[2] != '\0'))) {
- return 0;
- }
- } else if (errno != 0) {
- return -1;
- } else {
- return 0;
- }
- }
-}
-
char *xreadlinkat(int fd, const char *path, size_t size) {
ssize_t len;
char *name = NULL;
diff --git a/util.h b/util.h
index 15e983f..be696b6 100644
--- a/util.h
+++ b/util.h
@@ -21,7 +21,6 @@
#ifndef BFS_UTIL_H
#define BFS_UTIL_H
-#include <dirent.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <regex.h>
@@ -115,11 +114,6 @@
: BFS_FLEX_MAX(sizeof(type), BFS_FLEX_LB(type, member, length)))
/**
- * readdir() wrapper that makes error handling cleaner.
- */
-int xreaddir(DIR *dir, struct dirent **de);
-
-/**
* readlinkat() wrapper that dynamically allocates the result.
*
* @param fd