feat: implement -R/--relative, --no-implied-dirs, --dirs/-d, --mkpath
CI / lint (pull_request) Successful in 26s
CI / sanitizers (address) (pull_request) Failing after 41s
CI / sanitizers (undefined) (pull_request) Successful in 40s
CI / fuzz-build (pull_request) Successful in 18s
CI / coverage (pull_request) Successful in 35s
CI / valgrind (pull_request) Failing after 37s
CI / build-and-test (pull_request) Failing after 2m35s
CI / lint (pull_request) Successful in 26s
CI / sanitizers (address) (pull_request) Failing after 41s
CI / sanitizers (undefined) (pull_request) Successful in 40s
CI / fuzz-build (pull_request) Successful in 18s
CI / coverage (pull_request) Successful in 35s
CI / valgrind (pull_request) Failing after 37s
CI / build-and-test (pull_request) Failing after 2m35s
RSYNC_COMPAT Phase-2 row M: path-list construction and destination directory creation while preserving traversal safety. - -R/--relative with --files-from: transmit each listed entry under its bare relative destination path (no source-root mirror). Files keep an absolute local read path plus a separate wire/dest path (File.send_path); manifest, incremental quick-check and change output follow the wire path, so --delete and --remove-source-files stay consistent. -R without --files-from is unchanged (full mirror). - --no-implied-dirs: client-only, only meaningful with -R + --files-from. A listed file whose parent dir is not itself (or via an ancestor) explicitly listed cannot be placed; the run fails up front with a clear error. No effect otherwise. - --dirs/-d + --old-dirs/--old-d aliases: -d <dir> transmits the source root as an explicit empty directory entry (STATUS_MKDIR frame); with --files-from listed dirs are created empty and listed files transferred, never descending. Works single-threaded, -m (sequential scanner in the -m scan thread) and chunk-serialization (per-file type marker). Directory entries appear in the delete manifest. - --mkpath: new wire bool; server creates the destination root (and missing leading components under its authorized root) at connection start. A missing destination root is now rejected by default. - Protocol bumped to 2.7.0 (mkpath wire field + STATUS_MKDIR + chunk type marker). All receive paths funnel through file_save_to_disk_full which creates directories via the secure confined mkdir engine; dir entries are excluded from --remove-source-files outcome acknowledgements on both ends. - Unit coverage: CLI parse (relative/dirs aliases/mkpath/no-implied-dirs), config round-trip (relative + mkpath), scanner --dirs non-recursion and -R send_path (sequential + parallel), receiver dir-entry save. - Integration coverage: TestRelativeFilesFrom, TestNoImpliedDirs, TestDirs, TestMkpath (single and -m). - RSYNC_COMPAT: 4 rows move to Implemented (Summary 67/3/5/1/71 = 147).
This commit is contained in:
+14
-5
@@ -425,8 +425,12 @@ static const OptionEntry OPTION_TABLE[] = {
|
||||
{"--ignore-existing", NULL, OPT_FLAG, offsetof(Config, ignore_existing)},
|
||||
{"--delay-updates", NULL, OPT_FLAG, offsetof(Config, delay_updates)},
|
||||
{"--chmod", NULL, OPT_STRING, offsetof(Config, chmod_spec)},
|
||||
{"--dirs", "--old-dirs", OPT_UNSUPPORTED, 0},
|
||||
{"--old-d", NULL, OPT_UNSUPPORTED, 0},
|
||||
{"--dirs", "-d", OPT_FLAG, offsetof(Config, dirs)},
|
||||
{"--old-dirs", NULL, OPT_FLAG, offsetof(Config, dirs)},
|
||||
{"--old-d", NULL, OPT_FLAG, offsetof(Config, dirs)},
|
||||
{"--relative", "-R", OPT_FLAG, offsetof(Config, relative)},
|
||||
{"--no-implied-dirs", NULL, OPT_FLAG, offsetof(Config, no_implied_dirs)},
|
||||
{"--mkpath", NULL, OPT_FLAG, offsetof(Config, mkpath)},
|
||||
{"--delete-during", "--del", OPT_UNSUPPORTED, 0},
|
||||
|
||||
{"--source-dir", NULL, OPT_STRING, offsetof(Config, send_directory)},
|
||||
@@ -576,9 +580,7 @@ static int apply_table_option(Config* config, const OptionEntry* entry, const ch
|
||||
return 0;
|
||||
}
|
||||
case OPT_UNSUPPORTED: {
|
||||
const char* reason = "directory-only transfer is not implemented";
|
||||
if (strcmp(entry->name, "--delete-during") == 0)
|
||||
reason = "delete-during is not implemented";
|
||||
const char* reason = "delete-during is not implemented";
|
||||
log_message(LOG_LEVEL_ERROR, "%s: %s; refusing to ignore option", option_name, reason);
|
||||
return -1;
|
||||
}
|
||||
@@ -611,6 +613,13 @@ int parse_args(Config* config, int argc, char* argv[], int* positional_args,
|
||||
config->show_progress = true;
|
||||
continue;
|
||||
}
|
||||
/* "--no-implied-dirs" is a real rsync option name, not a negation of
|
||||
* "--implied-dirs", so it must be handled before the generic --no-*
|
||||
* negation branch. */
|
||||
if (strcmp(argv[i], "--no-implied-dirs") == 0) {
|
||||
config->no_implied_dirs = true;
|
||||
continue;
|
||||
}
|
||||
if (strncmp(argv[i], "--no-", strlen("--no-")) == 0) {
|
||||
if (apply_negation(config, argv[i]) != 0)
|
||||
return -1;
|
||||
|
||||
Reference in New Issue
Block a user