From 0f91c5861cacaeb17729b7727d07260273345393 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 4 Feb 2016 23:12:08 -0500 Subject: Implement -P and -H. --- bftw.c | 18 ++++++++++++++---- bftw.h | 8 +++++--- parse.c | 20 +++++++++++++++++++- tests.sh | 20 +++++++++++++++++++- 4 files changed, 57 insertions(+), 9 deletions(-) diff --git a/bftw.c b/bftw.c index 99e26e1..a49cbed 100644 --- a/bftw.c +++ b/bftw.c @@ -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); } diff --git a/bftw.h b/bftw.h index 1375594..4b81123 100644 --- a/bftw.h +++ b/bftw.h @@ -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, }; /** diff --git a/parse.c b/parse.c index 413282a..93657c8 100644 --- a/parse.c +++ b/parse.c @@ -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); diff --git a/tests.sh b/tests.sh index ffb110d..0a2f60a 100755 --- a/tests.sh +++ b/tests.sh @@ -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" -- cgit v1.2.3