From f099a6e20fcbe7b1ca1e349c391803efa886b5f5 Mon Sep 17 00:00:00 2001 From: TapTap Date: Sun, 6 Sep 2026 21:04:11 +0200 Subject: [PATCH] feat(config): add fuzzy flag and bump protocol to 2.9.0 -y/--fuzzy is receiver-side similar-file basis selection, so the receiver must learn the flag: add a bool to Config, serialize it as a trailing field on the config frame, and validate the received value. Because the config frame layout changed, PROTOCOL_VERSION moves to 2.9.0 (peers must match). --- src/shared/config.c | 23 ++++++++++++++++++----- src/shared/config.h | 10 +++++++++- 2 files changed, 27 insertions(+), 6 deletions(-) diff --git a/src/shared/config.c b/src/shared/config.c index b839744..7f8b625 100644 --- a/src/shared/config.c +++ b/src/shared/config.c @@ -46,6 +46,7 @@ static void config_set_defaults(Config* config) { config->size_only = false; config->use_delta = false; config->whole_file = false; + config->fuzzy = false; config->modify_window = 0; config->delta_block_size = DELTA_BLOCK_SIZE_DEFAULT; config->delta_max_file_size = DELTA_MAX_FILE_SIZE; @@ -152,9 +153,9 @@ static bool validate_received_config(const Config* config) { valid_wire_bool(config->use_delete) && valid_wire_bool(config->use_incremental) && valid_wire_bool(config->size_only) && valid_wire_bool(config->ignore_times) && valid_wire_bool(config->use_delta) && valid_wire_bool(config->backup) && - valid_wire_bool(config->remove_source_files) && valid_wire_bool(config->follow_symlinks) && - valid_wire_bool(config->copy_links) && valid_wire_bool(config->safe_links) && - valid_wire_bool(config->copy_unsafe_links) && + valid_wire_bool(config->fuzzy) && valid_wire_bool(config->remove_source_files) && + valid_wire_bool(config->follow_symlinks) && valid_wire_bool(config->copy_links) && + valid_wire_bool(config->safe_links) && valid_wire_bool(config->copy_unsafe_links) && valid_wire_bool(config->preserve_hard_links) && valid_wire_bool(config->preserve_acls) && valid_wire_bool(config->preserve_xattrs) && valid_wire_bool(config->preserve_devices) && valid_wire_bool(config->preserve_sparse) && valid_wire_bool(config->ignore_existing) && @@ -453,6 +454,12 @@ static bool send_basis_options(int fd, const Config* c) { return true; } +/* -y/--fuzzy (receiver-side similar-file basis selection). Trailing field on + * the config frame; protocol 2.9.0. */ +static bool send_fuzzy_option(int fd, const Config* c) { + return send_int(fd, c->fuzzy); +} + static bool receive_core_fields(int fd, Config* c) { int value; if (!receive_wire_bool(fd, &c->eight_bit_output)) @@ -624,12 +631,17 @@ static bool receive_basis_options(int fd, Config* c) { return true; } +static bool receive_fuzzy_option(int fd, Config* c) { + return receive_wire_bool(fd, &c->fuzzy); +} + bool config_send(int file_descriptor, const Config* config) { protocol_session_set_max_alloc(NULL, config->max_alloc); if (!send_core_fields(file_descriptor, config) || !send_delta_fields(file_descriptor, config) || !send_file_options(file_descriptor, config) || !send_selection_options(file_descriptor, config) || - !send_resume_options(file_descriptor, config) || !send_basis_options(file_descriptor, config)) + !send_resume_options(file_descriptor, config) || + !send_basis_options(file_descriptor, config) || !send_fuzzy_option(file_descriptor, config)) return false; Status status; if (!receive_status(file_descriptor, &status)) @@ -662,7 +674,8 @@ Config* config_receive(int file_descriptor) { !receive_file_options(file_descriptor, config) || !receive_selection_options(file_descriptor, config) || !receive_resume_options(file_descriptor, config) || - !receive_basis_options(file_descriptor, config)) + !receive_basis_options(file_descriptor, config) || + !receive_fuzzy_option(file_descriptor, config)) goto error; if (config->compress_choice[0] != '\0' && strcmp(config->compress_choice, "zstd") != 0 && strcmp(config->compress_choice, "none") != 0) { diff --git a/src/shared/config.h b/src/shared/config.h index 4ee1caa..7858f9b 100644 --- a/src/shared/config.h +++ b/src/shared/config.h @@ -63,6 +63,14 @@ typedef struct Config { bool size_only; bool use_delta; bool whole_file; + /* -y/--fuzzy: when a file must be transferred and the destination holds no + * usable file at the exact path, the receiver may reuse a SIMILAR-named + * existing regular file in the same destination directory as the delta + * basis so the sender transmits only the differences. Crosses the wire + * (the receiver performs the candidate search); the CLI implies + * --incremental + --delta because the similar-basis only matters on the + * receiver-driven delta path. Off by default. */ + bool fuzzy; int modify_window; uint32_t delta_block_size; unsigned long long delta_max_file_size; @@ -206,7 +214,7 @@ typedef struct Config { DelayUpdatesContext* delay_context; } Config; -#define PROTOCOL_VERSION "2.8.0" +#define PROTOCOL_VERSION "2.9.0" #define DEFAULT_CHUNK_SIZE (10 * 1024 * 1024) /* Upper bound on total basis-dir entries (rsync caps --link-dest at 20). */ #define MAX_BASIS_DIRS 64