fix(parity): actual-removal delete-delay counts, rsync-accurate stats/progress/%C
- --delete-delay: count/track only entries actually removed; a directory refilled before commit (ENOTEMPTY) no longer inflates Number of deleted files or the --max-delete budget (unit + integration + rsync differential). - --stats: per-type Number of files breakdown; only stored regular files count as transferred; transferred/literal byte totals and Total file size (symlink target lengths) now match rsync for whole-file transfers. - --progress: print the leading ./ root line and include the root entry in the to-chk denominator (single-file output byte-identical to rsync). - --out-format %C: use the selected transfer checksum and render every algorithm exactly like rsync; checksum_digest_file gains md4/sha1/none. Reclassify --out-format to Divergent (protocol-specific %b/delta-%c). - Docs: RSYNC_COMPAT tally 107/25/24, HANDOFF update. No wire change.
This commit is contained in:
@@ -412,6 +412,11 @@ struct DeletePlanSession {
|
||||
bool dry_run;
|
||||
size_t max_delete;
|
||||
size_t deleted;
|
||||
/* Removals charged against --max-delete. In --delete-delay mode a path is
|
||||
planned (and the budget consumed) while scanning, but `deleted` advances
|
||||
only when the commit actually unlinks it, so an entry that survives the
|
||||
commit (a directory refilled mid-transfer -> ENOTEMPTY) is not reported. */
|
||||
size_t planned;
|
||||
size_t skipped;
|
||||
bool limit_hit;
|
||||
bool limit_logged;
|
||||
@@ -565,7 +570,7 @@ static bool build_plan_skips(const Config* config, const DeletePlanSession* sess
|
||||
}
|
||||
|
||||
static bool budget_available(const DeletePlanSession* session) {
|
||||
return session->deleted < session->max_delete;
|
||||
return session->planned < session->max_delete;
|
||||
}
|
||||
|
||||
static void note_skipped(DeletePlanSession* session) {
|
||||
@@ -579,7 +584,9 @@ static void log_deleted(const char* rel) {
|
||||
free(escaped);
|
||||
}
|
||||
|
||||
/* Append a snapshot path for --delete-delay. */
|
||||
/* Append a snapshot path for --delete-delay. The budget is charged here, but
|
||||
* `deleted` is not: the path counts only once apply_deferred_path truly
|
||||
* unlinks it. */
|
||||
static bool defer_add(DeletePlanSession* session, const char* rel) {
|
||||
char* copy = str_dup(rel);
|
||||
if (!copy)
|
||||
@@ -588,7 +595,7 @@ static bool defer_add(DeletePlanSession* session, const char* rel) {
|
||||
free(copy);
|
||||
return false;
|
||||
}
|
||||
session->deleted++;
|
||||
session->planned++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -633,6 +640,7 @@ static bool process_extra_dir(int dirfd, const char* name, const char* child_rel
|
||||
}
|
||||
if (unlinkat(dirfd, name, AT_REMOVEDIR) == 0) {
|
||||
session->deleted++;
|
||||
session->planned++;
|
||||
log_deleted(child_rel);
|
||||
*removed = true;
|
||||
return true;
|
||||
@@ -657,6 +665,7 @@ static bool process_extra_file(int dirfd, const char* name, const char* child_re
|
||||
}
|
||||
if (unlinkat(dirfd, name, 0) == 0) {
|
||||
session->deleted++;
|
||||
session->planned++;
|
||||
log_deleted(child_rel);
|
||||
} else if (errno != ENOENT) {
|
||||
return false;
|
||||
@@ -768,13 +777,14 @@ static bool apply_missing(DeletePlanSession* session, const Config* config) {
|
||||
return true;
|
||||
DeleteManifest manifest = {
|
||||
.keeps = NULL, .protected = NULL, .missing = session->missing, .dirs = NULL};
|
||||
size_t remaining = budget_available(session) ? session->max_delete - session->deleted : 0;
|
||||
size_t remaining = budget_available(session) ? session->max_delete - session->planned : 0;
|
||||
size_t deleted = 0;
|
||||
size_t skipped = 0;
|
||||
bool limit = false;
|
||||
bool ok = manifest_delete_missing_args_limited(config, &manifest, remaining, &deleted, &skipped,
|
||||
&limit);
|
||||
session->deleted += deleted;
|
||||
session->planned += deleted;
|
||||
session->skipped += skipped;
|
||||
if (limit)
|
||||
session->limit_hit = true;
|
||||
@@ -839,7 +849,6 @@ int delete_plan_session_receive(DeletePlanSession* session, const Config* config
|
||||
/* Apply one snapshotted --delete-delay path (post-order: children precede their
|
||||
* parent directory). */
|
||||
static bool apply_deferred_path(DeletePlanSession* session, const Config* config, const char* rel) {
|
||||
(void)session;
|
||||
char* full = path_cat(config->receive_root_directory, rel);
|
||||
if (!full)
|
||||
return false;
|
||||
@@ -863,8 +872,10 @@ static bool apply_deferred_path(DeletePlanSession* session, const Config* config
|
||||
else
|
||||
rc = unlinkat(parent_fd, leaf, 0);
|
||||
bool ok = rc == 0 || errno == ENOENT || errno == ENOTEMPTY || errno == EEXIST;
|
||||
if (rc == 0)
|
||||
if (rc == 0) {
|
||||
session->deleted++;
|
||||
log_deleted(rel);
|
||||
}
|
||||
close(parent_fd);
|
||||
free(leaf);
|
||||
return ok;
|
||||
|
||||
Reference in New Issue
Block a user