summaryrefslogtreecommitdiffstats
path: root/bftw.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2015-09-02 11:34:46 -0400
committerTavian Barnes <tavianator@tavianator.com>2015-09-02 11:34:46 -0400
commit2199c8b55dcd34334ef71f12707e17704f1b3d10 (patch)
treeda3c847cde3e4e0ab458539515a462b3ca020bad /bftw.c
parent75377a9db6f9c4e00b9d39828d955ec4443f2ce2 (diff)
downloadbfs-2199c8b55dcd34334ef71f12707e17704f1b3d10.tar.xz
Print the root file/directory too.
Diffstat (limited to 'bftw.c')
-rw-r--r--bftw.c214
1 files changed, 130 insertions, 84 deletions
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;