From e7581fca45585661f1eb1d727a8853264ac34c80 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 12 Jul 2018 00:36:16 -0400 Subject: eval: Share the statbuf across multiple -xtype's --- eval.c | 49 +++++++++++++++++++++++++++++++------------------ 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/eval.c b/eval.c index 26f4ca7..029ded5 100644 --- a/eval.c +++ b/eval.c @@ -53,6 +53,8 @@ struct eval_state { bool *quit; /** A bfs_stat() buffer, if necessary. */ struct bfs_stat statbuf; + /** A bfs_stat() buffer for -xtype style tests. */ + struct bfs_stat xstatbuf; }; /** @@ -89,6 +91,21 @@ static const struct bfs_stat *eval_stat(struct eval_state *state) { return ftwbuf->statbuf; } +/** + * Perform a bfs_stat() call for tests that flip the follow flag, like -xtype. + */ +static const struct bfs_stat *eval_xstat(struct eval_state *state) { + struct BFTW *ftwbuf = state->ftwbuf; + struct bfs_stat *statbuf = &state->xstatbuf; + if (!statbuf->mask) { + int at_flags = ftwbuf->at_flags ^ AT_SYMLINK_NOFOLLOW; + if (bfs_stat(ftwbuf->at_fd, ftwbuf->at_path, at_flags, 0, statbuf) != 0) { + return NULL; + } + } + return statbuf; +} + /** * Get the difference (in seconds) between two struct timespecs. */ @@ -279,11 +296,11 @@ bool eval_delete(const struct expr *expr, struct eval_state *state) { if (ftwbuf->typeflag == BFTW_DIR) { flag |= AT_REMOVEDIR; } - } else { + } else if (ftwbuf->typeflag != BFTW_LNK) { // We need to know the actual type of the path, not what it points to - struct bfs_stat sb; - if (bfs_stat(ftwbuf->at_fd, ftwbuf->at_path, ftwbuf->at_flags | AT_SYMLINK_NOFOLLOW, 0, &sb) == 0) { - if (S_ISDIR(sb.mode)) { + const struct bfs_stat *statbuf = eval_xstat(state); + if (statbuf) { + if (S_ISDIR(statbuf->mode)) { flag |= AT_REMOVEDIR; } } else { @@ -848,21 +865,16 @@ bool eval_xtype(const struct expr *expr, struct eval_state *state) { return eval_type(expr, state); } - // -xtype does the opposite of everything else - int at_flags = ftwbuf->at_flags ^ AT_SYMLINK_NOFOLLOW; - - struct bfs_stat sb; - if (bfs_stat(ftwbuf->at_fd, ftwbuf->at_path, at_flags, 0, &sb) != 0) { - if (!follow && is_nonexistence_error(errno)) { - // Broken symlink - return eval_type(expr, state); - } else { - eval_error(state); - return false; - } + const struct bfs_stat *statbuf = eval_xstat(state); + if (statbuf) { + return mode_to_typeflag(statbuf->mode) & expr->idata; + } else if (!follow && is_nonexistence_error(errno)) { + // Broken symlink + return eval_type(expr, state); + } else { + eval_error(state); + return false; } - - return mode_to_typeflag(sb.mode) & expr->idata; } #if _POSIX_MONOTONIC_CLOCK > 0 @@ -1094,6 +1106,7 @@ static enum bftw_action cmdline_callback(struct BFTW *ftwbuf, void *ptr) { state.action = BFTW_CONTINUE; state.ret = &args->ret; state.quit = &args->quit; + state.xstatbuf.mask = 0; if (ftwbuf->typeflag == BFTW_ERROR) { if (!eval_should_ignore(&state, ftwbuf->error)) { -- cgit v1.2.3