fix(delete): guard the per-directory delete commit against dry-run
delete_plan_session_commit() lacked the central no-mutation guard that manifest_delete_all() has, so a server-contacting -n run (or a hostile plan frame) could still remove --delete-missing-args mirrors on the per-directory timing path. Return DELETE_COMMIT_OK immediately when the session is a dry-run, and gate the receiver/server commit call sites too. Add a unit test that streams a plan naming an existing destination file and asserts it survives.
This commit is contained in:
@@ -489,6 +489,10 @@ int receiver_process_pending(Config* config, int file_descriptor, const Receiver
|
||||
if (pending_plans) {
|
||||
*pending_plans = plan_session;
|
||||
plan_session = NULL;
|
||||
} else if (config->dry_run) {
|
||||
/* Central dry-run no-op: never commit a deletion for a -n run. */
|
||||
delete_plan_session_destroy(plan_session);
|
||||
plan_session = NULL;
|
||||
} else {
|
||||
DeleteCommitResult deletion = delete_plan_session_commit(plan_session, config);
|
||||
bool limit = delete_plan_session_limit_reached(plan_session);
|
||||
|
||||
+5
-1
@@ -970,7 +970,11 @@ void handler(int file_descriptor) {
|
||||
arrived; with the disk writer drained, commit the deferred removals.
|
||||
--delete-during already applied its plans on the receive thread. */
|
||||
if (context->deferred_plans) {
|
||||
DeleteCommitResult deletion = delete_plan_session_commit(context->deferred_plans, config);
|
||||
/* Defence in depth (the enclosing block already excludes dry-run): a
|
||||
-n run never commits a deletion. */
|
||||
DeleteCommitResult deletion = config->dry_run ? DELETE_COMMIT_OK
|
||||
: delete_plan_session_commit(
|
||||
context->deferred_plans, config);
|
||||
if (deletion == DELETE_COMMIT_ERROR) {
|
||||
transfer_ok = false;
|
||||
} else if (deletion == DELETE_COMMIT_LIMIT_REACHED) {
|
||||
|
||||
Reference in New Issue
Block a user