fix(parity): receiver temp-dir confinement, server I/O floor, delete budget

Address review findings on feat/rsync-parity:
- confine --temp-dir below the receive root (reject absolute/.. like
  backup-dir/partial-dir); keep EXDEV non-atomic fallback
- floor server session I/O deadlines at SERVER_IO_TIMEOUT_SEC (60s) and
  install it on the socket layer at startup (slow-loris)
- charge each --delete-missing-args directory removal once and clamp the
  extras-walk remaining budget so it can never underflow past --max-delete
- normalize --compress-choice=auto to zstd client-side and accept it on
  receive so auto transfers no longer fail
- map received --max-alloc=0 to MAX_SERVER_ALLOC (receive path only)
- zero File.dest_state; include log-file-format in report_dest_info;
  add STATUS_DELETE_LIMIT name; recognize --skip-compress as a
  separate-value option; OOM-guard send_list_only root entry; drop the
  dead -M= branch; record the bare relative protected prefix for -R
  size-prunes in both scanners; refresh delete-manifest comment
- pin the rsync tarball sha256 and bump integrator image to v11

Tests: temp-dir rejection/relative/cross-device, server timeout floor,
delete-missing dir budget regression, compress-choice=auto e2e,
max-alloc=0 receive mapping, dest_state, report_dest_info modes,
skip-compress dash value, -M short forms, -R root size-prune mirror
protection (rsync 3.4.1 confirmed).
This commit is contained in:
2026-09-16 01:11:59 +02:00
parent 3f5b0250f4
commit 88bdfeeb58
18 changed files with 544 additions and 117 deletions
+13 -3
View File
@@ -522,10 +522,19 @@ static void test_data_create_starts_uncharged_and_unowned() {
data_destroy(reserved);
}
/* The server floors a client --timeout=0 at SERVER_IO_TIMEOUT_SEC so a silent
* peer can never hold a session slot forever (slow-loris). */
static void test_protocol_server_io_timeout_floor() {
EXPECT_EQ_INT(protocol_server_io_timeout_sec(0), SERVER_IO_TIMEOUT_SEC);
EXPECT_EQ_INT(protocol_server_io_timeout_sec(-7), SERVER_IO_TIMEOUT_SEC);
EXPECT_EQ_INT(protocol_server_io_timeout_sec(30), 30);
EXPECT_TRUE(SERVER_IO_TIMEOUT_SEC > 0);
}
static void test_protocol_session_io_timeout() {
/* Default is the built-in 60 s window; the setter stores exactly what it is
* given (<= 0 means "fall back to the default") so callers can propagate
* --timeout without special-casing 0. */
/* The default is the built-in 60 s window; the setter stores exactly what it
* is given (<= 0 disables the deadline, matching rsync's --timeout=0) so
* callers can propagate --timeout without special-casing 0. */
ProtocolSession session;
protocol_session_init(&session, -1, -1);
EXPECT_EQ_INT(session.io_timeout_sec, 60);
@@ -670,6 +679,7 @@ void test_protocol() {
test_send_receive_int();
test_send_receive_status();
test_protocol_session_io_timeout();
test_protocol_server_io_timeout_floor();
test_send_receive_status_timed();
test_receive_status_keepalive_skips_reply();
test_receive_status_keepalive_aborts();