fix: --delay-updates delete/backup collisions, publish-failure test, staging lock
Review fixes for --delay-updates: - --delete no longer deletes the staged files: the delete walker gains a skip_root_child parameter and receive_manifest passes DELAY_UPDATES_STAGING_DIR when delay_updates is active, so deletion removes genuine extras while the staging dir (a direct child of the receive root) is left for publication in both single and -m modes. - --backup-dir is rejected when it collides with the reserved internal staging name .fastsync-stage (trailing slash normalized), in client validation and in the received-config wire validation, preventing old backups from being silently installed as new files. - Staging dir is now held under an exclusive advisory flock for the whole transfer (context lifetime): two simultaneous delayed transfers to one destination root no longer share/destroy each other's staged data - the second fails cleanly. Cleanup only touches the staging dir when this context owns the lock, so a lock-contention failure cannot wipe a live session. - Post-publish staging cleanup now returns/logs instead of discarding failures (warning when the staging dir cannot be fully removed). - Reworked the publish-failure integration test to exercise real mid-publish semantics (top-level file published, nested rename fails, no rollback, sources retained under --remove-source-files) and added integration tests for --delete + --delay-updates ordering and reserved --backup-dir rejection. - RSYNC_COMPAT note documents delete ordering, the reserved-name hazard, and the concurrency guard.
This commit is contained in:
@@ -1287,6 +1287,27 @@ static void test_validate_config_delay_updates_rejects_inplace() {
|
||||
config_delete(cfg);
|
||||
}
|
||||
|
||||
/* --backup-dir may not collide with the internal --delay-updates staging
|
||||
directory (with or without a trailing slash), or old backups would silently
|
||||
be installed as the "new" file. */
|
||||
static void test_validate_config_delay_updates_rejects_reserved_backup_dir() {
|
||||
static const char* const reserved[] = {".fastsync-stage", ".fastsync-stage/"};
|
||||
for (size_t i = 0; i < sizeof(reserved) / sizeof(reserved[0]); i++) {
|
||||
Config* cfg = valid_client_config();
|
||||
cfg->delay_updates = true;
|
||||
cfg->backup_dir = str_dup(reserved[i]);
|
||||
EXPECT_FALSE(validate_config(cfg));
|
||||
config_delete(cfg);
|
||||
}
|
||||
|
||||
/* A non-colliding backup dir is fine alongside --delay-updates. */
|
||||
Config* ok = valid_client_config();
|
||||
ok->delay_updates = true;
|
||||
ok->backup_dir = str_dup("backups");
|
||||
EXPECT_TRUE(validate_config(ok));
|
||||
config_delete(ok);
|
||||
}
|
||||
|
||||
void test_client_cli() {
|
||||
test_validate_config_required_paths();
|
||||
test_validate_config_incompatible_options();
|
||||
@@ -1368,4 +1389,5 @@ void test_client_cli() {
|
||||
test_parse_args_temp_dir();
|
||||
test_parse_args_delay_updates();
|
||||
test_validate_config_delay_updates_rejects_inplace();
|
||||
test_validate_config_delay_updates_rejects_reserved_backup_dir();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user