feat: add delta transfer for incremental sync
CI / build-and-test (push) Successful in 28s
CI / build-and-test (pull_request) Successful in 28s

Implement rsync-style delta transfer using rolling checksums (Adler-32 +
xxHash32). When a file exists on both sides but has changed, only the
changed blocks are transmitted instead of the entire file.

- New status codes: STATUS_DELTA_SIGNATURE, STATUS_DELTA_DATA
- Protocol version bumped to 1.2.0
- Server generates block signature, client computes delta
- Auto-fallback to whole-file when delta >= 70% of file size
- Works with zstd compression on delta stream
- Configurable block size (default 8KB, --delta-block flag)
- 13 unit tests covering hashing, signature roundtrip, delta compute/apply,
  file growth/shrink, and decision logic
This commit is contained in:
2026-07-18 20:00:15 +02:00
parent 43ba149ad5
commit e16db56580
13 changed files with 8628 additions and 19 deletions
+9
View File
@@ -1,4 +1,5 @@
#include "config.h"
#include "delta.h"
#include "log.h"
#include "protocol.h"
#include "utils.h"
@@ -39,6 +40,8 @@ Config *config_create(char *version, char *send_directory,
config->max_size = 0;
config->min_size = 0;
config->use_incremental = false;
config->use_delta = false;
config->delta_block_size = DELTA_BLOCK_SIZE_DEFAULT;
config->use_tls = false;
config->tls_cert = NULL;
config->tls_key = NULL;
@@ -98,6 +101,8 @@ bool config_send(int file_descriptor, Config *config) {
if (!send_int(file_descriptor, config->use_sendfile)) return false;
if (!send_int(file_descriptor, config->use_delete)) return false;
if (!send_int(file_descriptor, config->use_incremental)) return false;
if (!send_int(file_descriptor, config->use_delta)) return false;
if (!send_int(file_descriptor, (int)config->delta_block_size)) return false;
Status status;
if (!receive_status(file_descriptor, &status)) return false;
if (status != STATUS_OK) {
@@ -145,6 +150,10 @@ Config *config_receive(int file_descriptor) {
config->use_delete = tmp;
if (!receive_int(file_descriptor, &tmp)) goto error;
config->use_incremental = tmp;
if (!receive_int(file_descriptor, &tmp)) goto error;
config->use_delta = tmp;
if (!receive_int(file_descriptor, &tmp)) goto error;
config->delta_block_size = (uint32_t)tmp;
config->show_progress = false;
config->dry_run = false;
config->ssh_port = 22;