refactor(config): group CLI-parse state; drop old_args field

This commit is contained in:
2026-09-22 14:03:10 +02:00
parent 1ffd4744c6
commit b549887138
9 changed files with 126 additions and 113 deletions
+11 -12
View File
@@ -20,9 +20,9 @@
static void config_set_defaults(Config* config) {
config->scanner_threads = 0;
config->metadata_explicitly_disabled = false;
config->preserve_perms_explicit_off = false;
config->preserve_times_explicit_off = false;
config->cli.preserve_perms_explicit_off = false;
config->cli.preserve_times_explicit_off = false;
config->cli.metadata_explicitly_disabled = false;
config->show_progress = false;
config->compression_threads = 0;
config->ssh_port = 22;
@@ -44,8 +44,8 @@ static void config_set_defaults(Config* config) {
config->tls_ca = NULL;
config->server_host = str_dup("127.0.0.1");
config->server_port = 8080;
config->server_port_set = false;
config->server_host_set = false;
config->cli.server_port_set = false;
config->cli.server_host_set = false;
/* rsync defaults: --timeout=0 (I/O timeouts disabled) and --contimeout=60.
* A value of 0 disables the client's own deadline on both the socket layer
* (tcp_set_timeouts) and the protocol layer
@@ -68,10 +68,10 @@ static void config_set_defaults(Config* config) {
config->human_readable = false;
config->ignore_errors = false;
config->ignore_missing_args = false;
config->checksum_transfer_algo = CHECKSUM_ALGO_DEFAULT;
config->cli_exit_code = 0;
config->compression_level_set = false;
config->checksum_choice_set = false;
config->cli.checksum_transfer_algo = CHECKSUM_ALGO_DEFAULT;
config->cli.cli_exit_code = 0;
config->cli.compression_level_set = false;
config->cli.checksum_choice_set = false;
config->filters = NULL;
config->files_from = NULL;
config->files_from_set = NULL;
@@ -85,7 +85,6 @@ static void config_set_defaults(Config* config) {
config->rsh_command = NULL;
config->blocking_io = false;
config->outbuf = OUTBUF_BLOCK;
config->old_args = false;
config->remote_options = NULL;
config->remote_option_count = 0;
config->address = NULL;
@@ -101,7 +100,7 @@ static void config_set_defaults(Config* config) {
config->trust_sender = false;
config->stop_after_mins = 0;
config->stop_at = 0;
config->stop_at_set = false;
config->cli.stop_at_set = false;
config->write_batch = NULL;
config->only_write_batch = NULL;
config->read_batch = NULL;
@@ -342,7 +341,7 @@ bool config_derived_use_metadata(const Config* config) {
config->chown_uid_set || config->chown_gid_set || config->usermap_count > 0 ||
config->groupmap_count > 0 || config->update)
return true;
return (config->use_incremental || config->use_delta) && !config->metadata_explicitly_disabled;
return (config->use_incremental || config->use_delta) && !config->cli.metadata_explicitly_disabled;
}
bool config_has_basis(const Config* config) {
+48 -40
View File
@@ -342,22 +342,60 @@ typedef enum SuperMode { SUPER_MODE_AUTO = 0, SUPER_MODE_ON = 1, SUPER_MODE_OFF
CONFIG_WIRE_CODEC_FIELDS(X) \
CONFIG_WIRE_PROTECT_FIELDS(X)
/* Client-only, CLI-parse bookkeeping (never serialized). These members exist
* only so the client command-line parser can record HOW an option was
* specified (explicitly set, explicitly negated, or a parser-requested exit
* code); no other module and no wire peer ever needs them. Grouping them in
* one nested member keeps the public Config free of client-CLI-only state. */
typedef struct {
/* Set when the user explicitly turned an attribute off with --no-perms /
* --no-times (long or short form). --incremental/--delta historically
* auto-enabled mode and mtime preservation; these flags let
* cli_finalize_config restore that behavior while still honoring the
* explicit per-attribute negation. A later -p/-t re-enables the attribute
* directly, so the flag only prevents the incremental/delta implication,
* never a POSITIVE request. */
bool preserve_perms_explicit_off;
bool preserve_times_explicit_off;
/* Set by --no-preserve, the explicit opt-out of the whole preservation
* bundle, so the --incremental/--delta auto-preserve implication stays off. */
bool metadata_explicitly_disabled;
/* True when --server-port/--port was explicitly given. --dry-run uses it to
* decide whether a real server handshake was requested, so a plain local
* destination (no explicit port) keeps the existing client-side dry-run
* behavior instead of dialing the default 127.0.0.1:8080. */
bool server_port_set;
/* True when --server-host was explicitly given, and distinct from the
* "127.0.0.1" default: --dry-run uses it to route an explicit remote target
* to the server so it reports receiver state exactly like a real run,
* instead of silently running the client-side manifest. */
bool server_host_set;
/* Codec-negotiation CLI state. The effective pre-transfer checksum is
* Config->checksum_algo (serialized); checksum_transfer_algo is the rsync
* "transfer" half of a two-name --checksum-choice form (validated and used
* only to mirror rsync's whole-file forcing, since FastSync's per-block
* strong hash is fixed). cli_exit_code carries a parser-requested process
* exit status (rsync uses 4 for an unsupported checksum/compress algorithm)
* so main() can mirror it. */
int checksum_transfer_algo;
int cli_exit_code;
/* "The user explicitly chose" bits. They let the per-codec default level /
* checksum list be applied only when the corresponding rsync option was
* omitted (an explicit --compress-level / --checksum-choice always wins). */
bool compression_level_set;
bool checksum_choice_set;
/* True when --stop-at was given. */
bool stop_at_set;
} ConfigCliParse;
typedef struct Config {
/* -j/--threads=N: number of parallel scanner worker threads for the -m
* pipeline. 0 (the default, also set by bare -j/--threads) means "use the
* scanner's built-in default" (4). CLIENT-ONLY: it is a local scheduling
* concern and is NEVER serialized into the wire config frame. */
int scanner_threads;
bool metadata_explicitly_disabled;
/* CLIENT-ONLY (never serialized; not in CONFIG_WIRE_FIELDS). Set when the
* user explicitly turned an attribute off with --no-perms / --no-times (long
* or short form). --incremental/--delta historically auto-enabled mode and
* mtime preservation; these flags let cli_finalize_config restore that
* behavior while still honoring the explicit per-attribute negation. A
* later -p/-t re-enables the attribute directly, so the flag only prevents
* the incremental/delta implication, never a POSITIVE request. */
bool preserve_perms_explicit_off;
bool preserve_times_explicit_off;
/* Client-only CLI-parse bookkeeping (never serialized). See ConfigCliParse. */
ConfigCliParse cli;
bool show_progress;
int compression_threads;
int ssh_port;
@@ -378,18 +416,6 @@ typedef struct Config {
bool use_tls;
char* server_host;
int server_port;
/* True when --server-port/--port was explicitly given. CLIENT-ONLY (never
* serialized): --dry-run uses it to decide whether a real server handshake
* was requested, so a plain local destination (no explicit port) keeps the
* existing client-side dry-run behavior instead of dialing the default
* 127.0.0.1:8080. */
bool server_port_set;
/* True when --server-host was explicitly given. CLIENT-ONLY (never
* serialized), and distinct from the "127.0.0.1" default: --dry-run uses it
* to route an explicit remote target to the server so it reports receiver
* state exactly like a real run, instead of silently running the client-side
* manifest. */
bool server_host_set;
char* tls_cert;
char* tls_key;
char* tls_ca;
@@ -435,22 +461,6 @@ typedef struct Config {
* enters the keep-set. Implied by --delete-missing-args. */
bool ignore_missing_args;
/* Codec-negotiation CLI state (all client-only, never serialized). The
* effective pre-transfer checksum is Config->checksum_algo (serialized);
* checksum_transfer_algo is the rsync "transfer" half of a two-name
* --checksum-choice form (validated and used only to mirror rsync's
* whole-file forcing, since FastSync's per-block strong hash is fixed).
* cli_exit_code carries a parser-requested process exit status (rsync uses 4
* for an unsupported checksum/compress algorithm) so main() can mirror it. */
int checksum_transfer_algo;
int cli_exit_code;
/* Client-only "the user explicitly chose" bits. They let the per-codec
* default level / checksum list be applied only when the corresponding
* rsync option was omitted (an explicit --compress-level / --checksum-choice
* always wins). Never serialized. */
bool compression_level_set;
bool checksum_choice_set;
// Issue #129: Advanced file selection. These fields are CLIENT-ONLY: they are
// never serialized to the wire (the receiver must not learn them).
ArrayList* filters; /* --filter=RULE rule strings, in order */
@@ -486,7 +496,6 @@ typedef struct Config {
/* --outbuf mode (OutbufMode): stdout/stderr buffering. Client-only launch
* concern: NEVER crosses the wire. */
int outbuf;
bool old_args;
/* --remote-option=OPT (Phase 5, long form only): one or more extra command-line
* options to append to the REMOTE server invocation over SSH. CLIENT-ONLY:
* they are composed into the remote command line by ssh_build_remote_command()
@@ -556,7 +565,6 @@ typedef struct Config {
* process and are NEVER serialized into the config frame. */
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 */
/* 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