From b031e73ab0efa56749dcbe66109d973d20269ff5 Mon Sep 17 00:00:00 2001 From: TapTap Date: Sun, 6 Sep 2026 23:10:27 +0200 Subject: [PATCH] fix: treat an unreadable source root as fatal even under --ignore-errors A sequential scanner records an opendir failure of its seed/root directory as a skippable io_error and would complete an EMPTY scan, whose keep-set manifest would then delete every destination entry. The seed directory that maps to the transfer root (relative path "") is now fatal regardless of --ignore-errors; only subdirectories discovered during an otherwise-successful root scan are skippable. The -m path never had this hole (its root open failure aborts scanner creation), so sequential and -m now agree. --- src/client/scanner.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/client/scanner.c b/src/client/scanner.c index d007071..f72f5b0 100644 --- a/src/client/scanner.c +++ b/src/client/scanner.c @@ -502,11 +502,20 @@ static int open_next_directory(DirectoryScanner* scanner) { if (scanner->current_dir == NULL) { scanner->io_error = true; log_perror("Could not open directory"); + /* The transfer ROOT (a sequential scanner's seed directory) must be + readable even under --ignore-errors: an unreadable root would produce + an empty scan whose keep-set would delete the whole destination. Only + subdirectories discovered during an otherwise-successful root scan are + skippable. (The parallel scanner never reaches this for the root: its + root open failure aborts scanner creation; worker seeds are assigned + subdirectories with a non-empty relative path and stay skippable.) */ + bool is_root_seed = scanner->current_rel != NULL && scanner->current_rel[0] == '\0' && + scanner->current_depth == 0; free(scanner->current_rel); scanner->current_rel = NULL; free(scanner->current_path); scanner->current_path = NULL; - if (!scanner->ignore_io_errors) { + if (!scanner->ignore_io_errors || is_root_seed) { scanner->failed = true; return -1; }