From 49301273123d23c94b31bdd8c84ff5424eaa11a0 Mon Sep 17 00:00:00 2001 From: TapTap Date: Thu, 10 Sep 2026 21:14:30 +0200 Subject: [PATCH] feat(p6-batch): CLI/config plumbing for --write-batch/--only-write-batch/--read-batch --- src/client/client_cli.c | 8 ++++++++ src/client/usage.c | 6 ++++++ src/shared/config.c | 6 ++++++ src/shared/config.h | 13 +++++++++++++ 4 files changed, 33 insertions(+) diff --git a/src/client/client_cli.c b/src/client/client_cli.c index 20bebfd..0d64428 100644 --- a/src/client/client_cli.c +++ b/src/client/client_cli.c @@ -604,6 +604,14 @@ static const OptionEntry OPTION_TABLE[] = { * any network I/O. Client-only: the server does not negotiate, it just * enforces an exact match. */ {"--protocol", NULL, OPT_STRING, offsetof(Config, version)}, + /* Phase 6 residual-batch (client-only): --write-batch=FILE runs the normal + * live transfer AND also emits the self-contained batch FILE; + * --only-write-batch=FILE emits FILE only (no destination, no server); + * --read-batch=FILE applies FILE to the destination (no source, no server). + * All three are LOCAL driver flags and never cross the wire. */ + {"--write-batch", NULL, OPT_STRING, offsetof(Config, write_batch)}, + {"--only-write-batch", NULL, OPT_STRING, offsetof(Config, only_write_batch)}, + {"--read-batch", NULL, OPT_STRING, offsetof(Config, read_batch)}, {"--delete-before", NULL, OPT_FLAG, offsetof(Config, delete_before)}, {"--delete-during", "--del", OPT_FLAG, offsetof(Config, delete_during)}, {"--delete-delay", NULL, OPT_FLAG, offsetof(Config, delete_delay)}, diff --git a/src/client/usage.c b/src/client/usage.c index 3c6759b..83f463b 100644 --- a/src/client/usage.c +++ b/src/client/usage.c @@ -44,6 +44,12 @@ void print_usage(void) { printf(" --protocol=NUM Force the wire protocol version (must equal the current\n"); printf(" PROTOCOL_VERSION; FastSync cannot speak older/virtual\n"); printf(" wire formats)\n"); + printf(" --write-batch=FILE Run the normal live transfer AND also emit a\n"); + printf(" self-contained batch file of the whole source tree\n"); + printf(" --only-write-batch=FILE\n"); + printf(" Emit the batch file only (no destination, no server)\n"); + printf(" --read-batch=FILE Apply the batch file to the destination (no source, no\n"); + printf(" server); takes only the destination as an argument\n"); printf(" --delete Delete files on receiver not in source\n"); printf(" (default timing: delete only after the whole\n"); printf(" transfer has succeeded)\n"); diff --git a/src/shared/config.c b/src/shared/config.c index d8f01ba..896f07c 100644 --- a/src/shared/config.c +++ b/src/shared/config.c @@ -181,6 +181,9 @@ static void config_set_defaults(Config* config) { config->stop_after_mins = 0; config->stop_at = 0; config->stop_at_set = false; + config->write_batch = NULL; + config->only_write_batch = NULL; + config->read_batch = NULL; } static bool valid_wire_bool(int value) { @@ -631,6 +634,9 @@ void config_delete(Config* config) { free(config->auth_password_hash); free(config->password_file); free(config->iconv_spec); + free(config->write_batch); + free(config->only_write_batch); + free(config->read_batch); free(config->fastsync_server_path); for (int i = 0; i < config->exclude_count; i++) free(config->exclude_patterns[i]); diff --git a/src/shared/config.h b/src/shared/config.h index 0440de5..3415770 100644 --- a/src/shared/config.h +++ b/src/shared/config.h @@ -470,6 +470,19 @@ typedef struct Config { int stop_after_mins; /* --stop-after=MINS minutes; 0 when unset */ time_t stop_at; /* --stop-at=... absolute wall-clock deadline */ bool stop_at_set; /* true when --stop-at was given */ + + // Phase 6: --write-batch / --only-write-batch / --read-batch + /* Client-only residual-batch paths. A residual batch is a self-contained + * single-file record of the whole source tree (full file images using the + * chunk codec), independent of any live server. --write-batch=FILE runs the + * normal live transfer AND additionally emits the batch FILE; + * --only-write-batch=FILE emits FILE only (no destination, no server); + * --read-batch=FILE applies FILE to the destination (no source, no server). + * All three are LOCAL to the driving process and are NEVER serialized into + * the config frame (the batch paths bypass the transport entirely). */ + char* write_batch; /* --write-batch=FILE path, or NULL */ + char* only_write_batch; /* --only-write-batch=FILE path, or NULL */ + char* read_batch; /* --read-batch=FILE path, or NULL */ } Config; /* Phase 5 (remote-option wave): 2.13.0 -> 2.14.0.