metadata times: -U/--atimes, -N/--crtimes, --open-noatime, -O/-J
CI / lint (pull_request) Successful in 52s
CI / sanitizers (address) (pull_request) Skipped
CI / sanitizers (undefined) (pull_request) Skipped
CI / fuzz-build (pull_request) Skipped
CI / coverage (pull_request) Skipped
CI / valgrind (pull_request) Skipped
CI / build-and-test (pull_request) Successful in 1m19s

Capture+transmit source atime (pre-read stat; O_NOATIME sender guard) and birth
time (statx STATX_BTIME); receiver restores atime with mtime (crtime not settable
portably -> transmitted, explicitly not applied). --open-noatime is client-only.
-O/-J documented as accepted no-ops (FastSync never preserves dir/symlink times).
Wire: metadata frame gains atime/crtime val+sec+nsec; PROTOCOL_VERSION
2.11.0->2.12.0. Review fixes: gate atime capture to Linux (no epoch clobber on
non-Linux), close fd on fdopen failure, honest -O/-J status (Compat no-op).
This commit is contained in:
2026-09-08 20:58:56 +02:00
parent cbb09e41ab
commit e80888ce7b
21 changed files with 767 additions and 28 deletions
+46
View File
@@ -911,6 +911,51 @@ static void test_config_receive_rejects_invalid_checksum_algo() {
/* The identity-mapping fields (--numeric-ids / --usermap / --groupmap /
--chown) cross the config wire unchanged: the receiver needs them to apply
ownership with the same policy the client requested. */
static void test_config_metadata_times_wire_roundtrip() {
if (is_running_under_valgrind())
return;
Config* send_cfg = config_create();
EXPECT_NOT_NULL(send_cfg);
send_cfg->send_directory = str_dup("/send/src");
send_cfg->receive_root_directory = str_dup("/send/dst");
send_cfg->preserve_atimes = true;
send_cfg->preserve_crtimes = true;
send_cfg->omit_dir_times = true;
send_cfg->omit_link_times = true;
/* --open-noatime is client-only and must NOT cross the wire. */
send_cfg->open_noatime = true;
int p[2];
EXPECT_EQ_INT(socketpair(AF_UNIX, SOCK_STREAM, 0, p), 0);
io_set_fds(p[0], p[1]);
io_set_bwlimit(0);
pid_t pid = fork();
if (pid == 0) {
close(p[1]);
io_set_fds(p[0], p[0]);
Config* recv = config_receive(p[0]);
bool ok = recv != NULL;
if (ok) {
ok = recv->preserve_atimes && recv->preserve_crtimes && recv->omit_dir_times &&
recv->omit_link_times && !recv->open_noatime;
}
config_delete(recv);
close(p[0]);
close(p[1]);
_exit(ok ? 0 : 1);
} else {
close(p[0]);
io_set_fds(p[1], p[1]);
bool sent = config_send(p[1], send_cfg);
int status;
waitpid(pid, &status, 0);
close(p[1]);
config_delete(send_cfg);
EXPECT_TRUE(sent);
EXPECT_TRUE(WIFEXITED(status) && WEXITSTATUS(status) == 0);
}
}
static void test_config_identity_wire_roundtrip() {
if (is_running_under_valgrind())
return;
@@ -1068,6 +1113,7 @@ void test_config() {
test_config_receive_rejects_invalid_checksum_algo();
test_config_identity_wire_roundtrip();
test_config_receive_rejects_invalid_identity();
test_config_metadata_times_wire_roundtrip();
test_config_preallocate_wire_roundtrip();
}
test_config_delete_timing_early_helper();