summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2022-04-15 14:34:45 -0400
committerTavian Barnes <tavianator@tavianator.com>2022-04-15 14:34:45 -0400
commit33b477d90dbad8664d7393d65f8df4e73882cb66 (patch)
tree8f6d5ec49ba69d5771f7229ca677adf128cb7db5
parentacf934993a8112023f111ae1dfedc90f40e1d496 (diff)
downloadbfs-33b477d90dbad8664d7393d65f8df4e73882cb66.tar.xz
eval: Use BFTW_BUFFER when deleting files on FreeBSD
Works around #67.
-rw-r--r--eval.c35
1 files changed, 35 insertions, 0 deletions
diff --git a/eval.c b/eval.c
index 527c42e..1d0a6f2 100644
--- a/eval.c
+++ b/eval.c
@@ -1512,6 +1512,7 @@ static void dump_bftw_flags(enum bftw_flags flags) {
DEBUG_FLAG(flags, BFTW_SKIP_MOUNTS);
DEBUG_FLAG(flags, BFTW_PRUNE_MOUNTS);
DEBUG_FLAG(flags, BFTW_SORT);
+ DEBUG_FLAG(flags, BFTW_BUFFER);
assert(!flags);
}
@@ -1529,6 +1530,36 @@ static const char *dump_bftw_strategy(enum bftw_strategy strategy) {
return strategies[strategy];
}
+/** Check if we need to enable BFTW_BUFFER. */
+static bool eval_must_buffer(const struct bfs_expr *expr) {
+#if __FreeBSD__
+ // FreeBSD doesn't properly handle adding/removing directory entries
+ // during readdir() on NFS mounts. Work around it by passing BFTW_BUFFER
+ // whenever we could be mutating the directory ourselves through -delete
+ // or -exec. We don't attempt to handle concurrent modification by other
+ // processes, which are racey anyway.
+ //
+ // https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=57696
+ // https://github.com/tavianator/bfs/issues/67
+
+ if (expr->eval_fn == eval_delete || expr->eval_fn == eval_exec) {
+ return true;
+ }
+
+ if (bfs_expr_has_children(expr)) {
+ if (expr->lhs && eval_must_buffer(expr->lhs)) {
+ return true;
+ }
+
+ if (expr->rhs && eval_must_buffer(expr->rhs)) {
+ return true;
+ }
+ }
+#endif // __FreeBSD__
+
+ return false;
+}
+
int bfs_eval(const struct bfs_ctx *ctx) {
if (!ctx->expr) {
return EXIT_SUCCESS;
@@ -1566,6 +1597,10 @@ int bfs_eval(const struct bfs_ctx *ctx) {
.mtab = bfs_ctx_mtab(ctx),
};
+ if (eval_must_buffer(ctx->expr)) {
+ bftw_args.flags |= BFTW_BUFFER;
+ }
+
if (bfs_debug(ctx, DEBUG_SEARCH, "bftw({\n")) {
fprintf(stderr, "\t.paths = {\n");
for (size_t i = 0; i < bftw_args.npaths; ++i) {