diff options
author | Tavian Barnes <tavianator@tavianator.com> | 2016-02-04 23:12:08 -0500 |
---|---|---|
committer | Tavian Barnes <tavianator@tavianator.com> | 2016-02-04 23:12:08 -0500 |
commit | 0f91c5861cacaeb17729b7727d07260273345393 (patch) | |
tree | 8348044cc4697e2576a401fe81c2d5bca7dbc0eb | |
parent | c9905877cb06f71c4523e4f4875bf549b6b54060 (diff) | |
download | bfs-0f91c5861cacaeb17729b7727d07260273345393.tar.xz |
Implement -P and -H.
-rw-r--r-- | bftw.c | 18 | ||||
-rw-r--r-- | bftw.h | 8 | ||||
-rw-r--r-- | parse.c | 20 | ||||
-rwxr-xr-x | tests.sh | 20 |
4 files changed, 57 insertions, 9 deletions
@@ -471,8 +471,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 ret = fstatat(ftwbuf->at_fd, ftwbuf->at_path, sb, AT_SYMLINK_NOFOLLOW); +static int ftwbuf_stat(struct BFTW *ftwbuf, struct stat *sb, int flags) { + int ret = fstatat(ftwbuf->at_fd, ftwbuf->at_path, sb, flags); if (ret != 0) { return ret; } @@ -620,8 +620,18 @@ static void bftw_init_buffers(struct bftw_state *state, const struct dirent *de) ftwbuf->typeflag = BFTW_UNKNOWN; } - if ((state->flags & BFTW_STAT) || ftwbuf->typeflag == BFTW_UNKNOWN) { - if (ftwbuf_stat(ftwbuf, &state->statbuf) != 0) { + bool follow; + if (state->flags & BFTW_FOLLOW_ROOT) { + follow = !state->current; + } else { + follow = false; + } + + if ((state->flags & BFTW_STAT) + || ftwbuf->typeflag == BFTW_UNKNOWN + || (ftwbuf->typeflag == BFTW_LNK && follow)) { + int flags = follow ? 0 : AT_SYMLINK_NOFOLLOW; + if (ftwbuf_stat(ftwbuf, &state->statbuf, flags) != 0) { state->error = errno; ftwbuf_set_error(ftwbuf, state->error); } @@ -105,11 +105,13 @@ typedef enum bftw_action bftw_fn(struct BFTW *ftwbuf, void *ptr); */ enum bftw_flags { /** stat() each encountered file. */ - BFTW_STAT = 1 << 0, + BFTW_STAT = 1 << 0, /** Attempt to recover from encountered errors. */ - BFTW_RECOVER = 1 << 1, + BFTW_RECOVER = 1 << 1, /** Visit directories in post-order as well as pre-order. */ - BFTW_DEPTH = 1 << 2, + BFTW_DEPTH = 1 << 2, + /** If the initial path is a symbolic link, follow it. */ + BFTW_FOLLOW_ROOT = 1 << 3, }; /** @@ -344,7 +344,11 @@ static struct expr *parse_acnewer(struct parser_state *state, const char *option } struct stat sb; - if (fstatat(AT_FDCWD, expr->sdata, &sb, AT_SYMLINK_NOFOLLOW) != 0) { + + bool follow = state->cl->flags & BFTW_FOLLOW_ROOT; + int flags = follow ? 0 : AT_SYMLINK_NOFOLLOW; + + if (fstatat(AT_FDCWD, expr->sdata, &sb, flags) != 0) { print_error(NULL, expr->sdata, errno); free_expr(expr); return NULL; @@ -465,6 +469,20 @@ static struct expr *parse_literal(struct parser_state *state) { } switch (arg[1]) { + case 'P': + if (strcmp(arg, "-P") == 0) { + state->cl->flags &= ~BFTW_FOLLOW_ROOT; + return new_option(state, arg); + } + break; + + case 'H': + if (strcmp(arg, "-H") == 0) { + state->cl->flags |= BFTW_FOLLOW_ROOT; + return new_option(state, arg); + } + break; + case 'a': if (strcmp(arg, "-amin") == 0) { return parse_acmtime(state, arg, ATIME, MINUTES); @@ -35,6 +35,7 @@ function links_structure() { ln "$1/a" "$1/c" mkdir -p "$1/d/e" ln -s ../../d "$1/d/e/f" + touchp "$1/d/e/g" } # Checks for any (order-independent) differences between bfs and find @@ -150,7 +151,24 @@ function test_0020() { find_diff "$1" -links +1 } -for i in {1..20}; do +function test_0021() { + links_structure "$1" + find_diff -P "$1/d/e/f" && \ + find_diff -P "$1/d/e/f/" +} + +function test_0022() { + links_structure "$1" + find_diff -H "$1/d/e/f" && \ + find_diff -H "$1/d/e/f/" +} + +function test_0023() { + links_structure "$1" + find_diff -H "$1" -newer "$1/d/e/f" +} + +for i in {1..23}; do dir="$(mktemp -d "${TMPDIR:-/tmp}"/bfs.XXXXXXXXXX)" test="test_$(printf '%04d' $i)" "$test" "$dir" |