From 470cb86bdf9515c844272b309be1e34e388ce4e4 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Sat, 25 Jul 2026 08:49:00 +1000 Subject: [PATCH] sender: honor the do_*() guards when removing a source file secure_remove_source_file() called unlinkat() directly, dropping the dry_run no-op and the read-only/list-only refusal that do_unlink() applies on the non-fd path. That is what let --only-write-batch (which implies dry_run) really delete the source files once a MSG_SUCCESS reached the sender. Use do_unlink_atfd(), which carries both guards. --- sender.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/sender.c b/sender.c index 1f91b0b3..ee689ebe 100644 --- a/sender.c +++ b/sender.c @@ -172,15 +172,12 @@ static int secure_sender_parent_fd(struct file_struct *file, const char *fname, #endif } +/* Go through the do_*() wrapper rather than a raw unlinkat(): it carries the + * dry_run no-op and the read-only/list-only refusal that do_unlink() applies + * on the non-fd path, plus the missing-AT_FDCWD fallback. */ static int secure_remove_source_file(int dfd, const char *bname) { -#ifdef AT_FDCWD - return unlinkat(dfd, bname, 0); -#else - (void)dfd; (void)bname; - errno = ENOSYS; - return -1; -#endif + return do_unlink_atfd(dfd, bname, 0); } /* Open `relpath` (relative to `anchor`: NULL=cwd, else an absolute trusted root)