summaryrefslogtreecommitdiffstats
path: root/eval.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2018-07-12 00:36:16 -0400
committerTavian Barnes <tavianator@tavianator.com>2018-07-12 00:36:52 -0400
commite7581fca45585661f1eb1d727a8853264ac34c80 (patch)
tree6ebf2edd6063c66b7260f4507d9fa794eb6e7d26 /eval.c
parentbff43c109060889d2573ae10ebff1d4bad7c16a0 (diff)
downloadbfs-e7581fca45585661f1eb1d727a8853264ac34c80.tar.xz
eval: Share the statbuf across multiple -xtype's
Diffstat (limited to 'eval.c')
-rw-r--r--eval.c49
1 files 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;
};
/**
@@ -90,6 +92,21 @@ static const struct bfs_stat *eval_stat(struct eval_state *state) {
}
/**
+ * 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.
*/
static time_t timespec_diff(const struct timespec *lhs, const struct timespec *rhs) {
@@ -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)) {