From 4790e55f4e42f40f99e98809e732ddf7e2e78db5 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Thu, 23 Jul 2026 12:16:47 +1000 Subject: [PATCH] receiver: only reject unconfined partial basis when in-place partial is active The daemon rejection for a peer-selected FNAMECMP_PARTIAL_DIR basis that the confined open declined fired at every protocol. In-place partial updates are only negotiated at protocol 30+ (CF_INPLACE_PARTIAL_DIR); at protocol 29 no partial-basis redirect is possible, and the receiver already handled such a transfer safely by completing it with no basis. Gate the abort on inplace_partial so a pre-30 daemon falls back to the safe no-basis path instead of aborting a legitimate transfer with a protocol error. Fixes operator-path-partial-dir-daemon at protocol 29. --- receiver.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/receiver.c b/receiver.c index aeac9b94..212ba358 100644 --- a/receiver.c +++ b/receiver.c @@ -988,10 +988,12 @@ int recv_files(int f_in, int f_out, char *local_name) } if (fnamecmp_type == FNAMECMP_PARTIAL_DIR && fd1 == -1) { /* The sender may claim a partial basis even when the generator's - * confined lookup rejected it. Do not retain that path for direct - * output or post-transfer cleanup. A daemon rejects its unsafe - * peer option; a pull client can safely receive a no-basis update. */ - if (am_daemon) { + * confined lookup rejected it. Drop that path as the delta basis + * and in-place output target. A daemon that negotiated in-place + * partial updates rejects the unsafe peer option; otherwise (a pre-30 + * peer, where no in-place partial redirect is possible, or a pull + * client) fall back to a safe no-basis update. */ + if (am_daemon && inplace_partial) { rprintf(FERROR, "rsync: refusing unconfined partial basis for %s\n", fname); exit_cleanup(RERR_PROTOCOL);