Merge branch 'feat/parity-leftovers' into feat/parity-completion
# Conflicts: # src/client/scanner.c # src/client/scanner.h
This commit is contained in:
+34
-10
@@ -329,10 +329,10 @@ static int config_add_remote_option(Config* config, const char* value, const cha
|
||||
}
|
||||
|
||||
/* Validate and append one --compare-dest/--copy-dest/--link-dest directory.
|
||||
* The path is interpreted on the receiver relative to the destination root,
|
||||
* so it must be a non-empty relative path with no "." / ".." components (an
|
||||
* absolute or escaping path is rejected up front instead of failing on the
|
||||
* server). Returns 0 on success, -1 on error. */
|
||||
* A relative path is interpreted on the receiver below the destination root; an
|
||||
* absolute path is used verbatim on the receiver (matching rsync), still subject
|
||||
* to the receiver's authorized-root confinement. Either way the path must be
|
||||
* non-empty and traversal-free (no ".."). Returns 0 on success, -1 on error. */
|
||||
static int set_basis_dest_option(Config* config, BasisDestType type, const char* value,
|
||||
const char* option_name) {
|
||||
if (!value || !value[0]) {
|
||||
@@ -341,8 +341,9 @@ static int set_basis_dest_option(Config* config, BasisDestType type, const char*
|
||||
}
|
||||
if (config_basis_append(config, type, value) != 0) {
|
||||
log_message(LOG_LEVEL_ERROR,
|
||||
"%s requires a non-empty relative directory name with no '.', '..', or absolute "
|
||||
"path (resolved below the destination root)",
|
||||
"%s requires a non-empty directory name with no '..' component "
|
||||
"(relative paths resolve below the destination root; absolute paths are used "
|
||||
"verbatim)",
|
||||
option_name);
|
||||
return -1;
|
||||
}
|
||||
@@ -657,16 +658,25 @@ static int config_add_pattern(char*** patterns, int* count, const char* value,
|
||||
|
||||
/* Validate and append one --filter=RULE string. Returns 0 on success, -1 on error. */
|
||||
static int config_add_filter(Config* config, const char* rule) {
|
||||
char err[160];
|
||||
FilterRule* parsed = filter_rule_parse(rule, err, sizeof(err));
|
||||
if (!parsed) {
|
||||
char err[256];
|
||||
/* Validate through the full list parser so clear/merge/dir-merge and the rule
|
||||
modifiers are accepted (and a merge file is readable) at parse time. */
|
||||
FilterParseOptions opts = {.delete_excluded = config->delete_excluded,
|
||||
.cvs_exclude = config->cvs_exclude};
|
||||
FilterRuleList* probe = filter_rule_list_create();
|
||||
if (!probe) {
|
||||
log_message(LOG_LEVEL_ERROR, "memory allocation failed for --filter");
|
||||
return -1;
|
||||
}
|
||||
bool ok = filter_rule_list_parse_append(probe, rule, &opts, NULL, err, sizeof(err));
|
||||
filter_rule_list_free(probe);
|
||||
if (!ok) {
|
||||
char* escaped = output_escape(rule, log_get_8_bit_output());
|
||||
log_message(LOG_LEVEL_ERROR, "invalid --filter rule '%s': %s",
|
||||
escaped ? escaped : "<allocation failed>", err);
|
||||
free(escaped);
|
||||
return -1;
|
||||
}
|
||||
filter_rule_free(parsed);
|
||||
if (!config->filters) {
|
||||
config->filters = array_list_create(free);
|
||||
if (!config->filters) {
|
||||
@@ -1365,6 +1375,11 @@ static bool cli_handle_table_option(CliParseCtx* ctx) {
|
||||
}
|
||||
if (entry->offset == offsetof(Config, eight_bit_output))
|
||||
protocol_set_8_bit_output(true);
|
||||
/* -F is repeatable: rsync's single -F transfers .rsync-filter files, a
|
||||
repeated -FF excludes them. Count the occurrences so the scanner can
|
||||
distinguish the two. */
|
||||
if (entry->offset == offsetof(Config, per_dir_filter) && config->per_dir_filter_count < INT_MAX)
|
||||
config->per_dir_filter_count++;
|
||||
/* A delete-timing flag selects when --delete removes extras, so it
|
||||
implies --delete exactly like the rsync options do. */
|
||||
if (entry->offset == offsetof(Config, delete_before) ||
|
||||
@@ -2397,6 +2412,15 @@ static int cli_finalize_config(Config* config, bool verbose, bool no_delta, bool
|
||||
config->preserve_times = true;
|
||||
}
|
||||
|
||||
/* --ignore-existing is a receiver-side existence policy: the receiver must
|
||||
* answer "skip" BEFORE the sender transmits any payload, which only the
|
||||
* per-file STATUS_CHECK handshake provides. Imply --incremental here (after
|
||||
* the auto-preserve capture above, so a bare --ignore-existing does not gain
|
||||
* -p/-t, which rsync likewise does not imply) so an existing destination is
|
||||
* skipped on the wire instead of being streamed and discarded. */
|
||||
if (config->ignore_existing)
|
||||
config->use_incremental = true;
|
||||
|
||||
/* Derive the transport bit from the FINAL parsed flags. Every
|
||||
* preservation/ownership option that needs the metadata frame (per-attribute
|
||||
* perms/times/owner/group, atimes/crtimes, executability, xattrs/acls,
|
||||
|
||||
Reference in New Issue
Block a user