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.
This commit is contained in:
Andrew Tridgell committed 2026-07-24 16:40:48 +10:00
1 parent 9a1415c46f
commit 4790e55f4e
1 file changed
+6 -4
+6 -4
View File
@@ -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);