Merge branch 'feat/parity-output' into feat/rsync-parity
# Conflicts: # src/shared/config.h # src/shared/protocol.h # tests/test_config.c
This commit is contained in:
+45
-11
@@ -367,7 +367,8 @@ static void apply_output_buffering(const Config* config) {
|
||||
}
|
||||
#endif
|
||||
|
||||
static int read_patterns_from_file(const char* filepath, char*** patterns, int* count);
|
||||
static int read_patterns_from_file(const char* filepath, char*** patterns, int* count,
|
||||
Config* config, char sign, const char* optname);
|
||||
|
||||
static int parse_debug_flags(const char* value, Config* config) {
|
||||
if (!value || value[0] == '\0' || value[0] == ',' || value[strlen(value) - 1] == ',' ||
|
||||
@@ -597,6 +598,27 @@ static int config_add_filter(Config* config, const char* rule) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compile one --exclude/--include pattern into the SAME ordered filter rule
|
||||
* list used by --filter/-f: `--exclude P` becomes the rule "- P" and
|
||||
* `--include P` becomes "+ P", appended in command-line order. This is what
|
||||
* makes rsync's first-match-wins semantics hold across a mixed sequence such as
|
||||
* `--include='*.txt' --exclude='*'`. Returns 0 on success, -1 on error. */
|
||||
static int config_add_selection_rule(Config* config, char sign, const char* pattern,
|
||||
const char* optname) {
|
||||
size_t len = strlen(pattern);
|
||||
char* rule = malloc(len + 3);
|
||||
if (!rule) {
|
||||
log_message(LOG_LEVEL_ERROR, "memory allocation failed for %s", optname);
|
||||
return -1;
|
||||
}
|
||||
rule[0] = sign;
|
||||
rule[1] = ' ';
|
||||
memcpy(rule + 2, pattern, len + 1);
|
||||
int rc = config_add_filter(config, rule);
|
||||
free(rule);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int parse_skip_compress(Config* config, const char* value) {
|
||||
char* list = str_dup(value);
|
||||
if (!list)
|
||||
@@ -1378,7 +1400,8 @@ static bool cli_handle_ssh_and_pattern_options(CliParseCtx* ctx) {
|
||||
}
|
||||
if (strncmp(arg, "--exclude=", 10) == 0) {
|
||||
if (config_add_pattern(&config->exclude_patterns, &config->exclude_count, arg + 10,
|
||||
"--exclude") != 0)
|
||||
"--exclude") != 0 ||
|
||||
config_add_selection_rule(config, '-', arg + 10, "--exclude") != 0)
|
||||
ctx->exit_code = -1;
|
||||
return true;
|
||||
}
|
||||
@@ -1389,13 +1412,15 @@ static bool cli_handle_ssh_and_pattern_options(CliParseCtx* ctx) {
|
||||
return true;
|
||||
}
|
||||
if (config_add_pattern(&config->exclude_patterns, &config->exclude_count, ctx->argv[++ctx->i],
|
||||
"--exclude") != 0)
|
||||
"--exclude") != 0 ||
|
||||
config_add_selection_rule(config, '-', ctx->argv[ctx->i], "--exclude") != 0)
|
||||
ctx->exit_code = -1;
|
||||
return true;
|
||||
}
|
||||
if (strncmp(arg, "--include=", 10) == 0) {
|
||||
if (config_add_pattern(&config->include_patterns, &config->include_count, arg + 10,
|
||||
"--include") != 0)
|
||||
"--include") != 0 ||
|
||||
config_add_selection_rule(config, '+', arg + 10, "--include") != 0)
|
||||
ctx->exit_code = -1;
|
||||
return true;
|
||||
}
|
||||
@@ -1406,7 +1431,8 @@ static bool cli_handle_ssh_and_pattern_options(CliParseCtx* ctx) {
|
||||
return true;
|
||||
}
|
||||
if (config_add_pattern(&config->include_patterns, &config->include_count, ctx->argv[++ctx->i],
|
||||
"--include") != 0)
|
||||
"--include") != 0 ||
|
||||
config_add_selection_rule(config, '+', ctx->argv[ctx->i], "--include") != 0)
|
||||
ctx->exit_code = -1;
|
||||
return true;
|
||||
}
|
||||
@@ -1689,7 +1715,8 @@ static bool cli_handle_filter_options(CliParseCtx* ctx) {
|
||||
Config* config = ctx->config;
|
||||
const char* arg = ctx->argv[ctx->i];
|
||||
if (strncmp(arg, "--exclude-from=", 15) == 0) {
|
||||
if (read_patterns_from_file(arg + 15, &config->exclude_patterns, &config->exclude_count) != 0)
|
||||
if (read_patterns_from_file(arg + 15, &config->exclude_patterns, &config->exclude_count, config,
|
||||
'-', "--exclude-from") != 0)
|
||||
ctx->exit_code = -1;
|
||||
return true;
|
||||
}
|
||||
@@ -1700,12 +1727,13 @@ static bool cli_handle_filter_options(CliParseCtx* ctx) {
|
||||
return true;
|
||||
}
|
||||
if (read_patterns_from_file(ctx->argv[++ctx->i], &config->exclude_patterns,
|
||||
&config->exclude_count) != 0)
|
||||
&config->exclude_count, config, '-', "--exclude-from") != 0)
|
||||
ctx->exit_code = -1;
|
||||
return true;
|
||||
}
|
||||
if (strncmp(arg, "--include-from=", 15) == 0) {
|
||||
if (read_patterns_from_file(arg + 15, &config->include_patterns, &config->include_count) != 0)
|
||||
if (read_patterns_from_file(arg + 15, &config->include_patterns, &config->include_count, config,
|
||||
'+', "--include-from") != 0)
|
||||
ctx->exit_code = -1;
|
||||
return true;
|
||||
}
|
||||
@@ -1716,7 +1744,7 @@ static bool cli_handle_filter_options(CliParseCtx* ctx) {
|
||||
return true;
|
||||
}
|
||||
if (read_patterns_from_file(ctx->argv[++ctx->i], &config->include_patterns,
|
||||
&config->include_count) != 0)
|
||||
&config->include_count, config, '+', "--include-from") != 0)
|
||||
ctx->exit_code = -1;
|
||||
return true;
|
||||
}
|
||||
@@ -2243,6 +2271,10 @@ static int cli_finalize_config(Config* config, bool verbose, bool no_delta, bool
|
||||
* --no-xattrs/--no-acls negation) so the sender's wire gate always matches
|
||||
* the flags the receiver will recompute from the received config. */
|
||||
config->use_xattrs = config->preserve_acls || config->preserve_xattrs;
|
||||
/* Output parity: -i/--itemize-changes and --out-format need the pre-transfer
|
||||
* destination snapshot (new vs modified and which attributes differ), so ask
|
||||
* the receiver to report it on every per-file check. This is a wire field. */
|
||||
config->report_dest_info = config->itemize_changes || config->out_format != NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2439,7 +2471,8 @@ done:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int read_patterns_from_file(const char* filepath, char*** patterns, int* count) {
|
||||
static int read_patterns_from_file(const char* filepath, char*** patterns, int* count,
|
||||
Config* config, char sign, const char* optname) {
|
||||
FILE* fp = fopen(filepath, "r");
|
||||
if (!fp) {
|
||||
char* escaped = output_escape(filepath, false);
|
||||
@@ -2481,7 +2514,8 @@ static int read_patterns_from_file(const char* filepath, char*** patterns, int*
|
||||
p[--len] = '\0';
|
||||
if (len == 0)
|
||||
continue;
|
||||
if (config_add_pattern(patterns, count, p, "pattern file") != 0) {
|
||||
if (config_add_pattern(patterns, count, p, "pattern file") != 0 ||
|
||||
config_add_selection_rule(config, sign, p, optname) != 0) {
|
||||
free(line);
|
||||
fclose(fp);
|
||||
return -1;
|
||||
|
||||
Reference in New Issue
Block a user