symlink-trust: -k/--copy-dirlinks, -K/--keep-dirlinks, --munge-links (+real -l/--links)
CI / lint (pull_request) Successful in 1m1s
CI / sanitizers (address) (pull_request) Skipped
CI / sanitizers (undefined) (pull_request) Skipped
CI / fuzz-build (pull_request) Skipped
CI / coverage (pull_request) Skipped
CI / valgrind (pull_request) Skipped
CI / build-and-test (pull_request) Successful in 1m19s
CI / lint (pull_request) Successful in 1m1s
CI / sanitizers (address) (pull_request) Skipped
CI / sanitizers (undefined) (pull_request) Skipped
CI / fuzz-build (pull_request) Skipped
CI / coverage (pull_request) Skipped
CI / valgrind (pull_request) Skipped
CI / build-and-test (pull_request) Successful in 1m19s
Adds symlink-target transmission (File is_symlink+symlink_target, STATUS_SYMLINK frame, chunk type 2), munge-links sender containment + receiver-side symmetric target containment, keep-dirlinks confined dir-symlink following (O_NOFOLLOW realpath-rechecked), and fixes -l to copy symlinks as symlinks. munge_links + keep_dirlinks cross the wire; copy_dirlinks client-only. PROTOCOL_VERSION 2.12.0->2.13.0. Review fixes: receiver rejects absolute/.. targets, gated unmunge, -K O_NOFOLLOW+re-fstat, keep_dirlinks set once at config-accept, rel_buf overflow fails the walk.
This commit is contained in:
@@ -102,6 +102,8 @@ static bool prepare_scanner(const Config* config, int num_threads, PreparedScann
|
||||
options->copy_links = config->copy_links;
|
||||
options->safe_links = config->safe_links;
|
||||
options->copy_unsafe_links = config->copy_unsafe_links;
|
||||
options->copy_dirlinks = config->copy_dirlinks;
|
||||
options->munge_links = config->munge_links;
|
||||
options->checksum = config->checksum;
|
||||
options->one_file_system = config->one_file_system;
|
||||
options->file_list = (const FileListSet*)config->files_from_set;
|
||||
@@ -1067,6 +1069,20 @@ static bool send_directory_entry(Client* client, File* file) {
|
||||
return send_str(client->file_descriptor, file_wire_path(file));
|
||||
}
|
||||
|
||||
/* Transmit one symlink entry: a STATUS_SYMLINK frame carrying the destination
|
||||
* path, the (sender-munged, if --munge-links) target string, and metadata when
|
||||
* negotiated. The receiver unmunges the target and creates the symlink beneath
|
||||
* its root. Symlinks never need an incremental check or data payload. */
|
||||
static bool send_symlink_entry(const Client* client, File* file, const Config* config) {
|
||||
if (!file || !file_wire_path(file) || !file->symlink_target)
|
||||
return false;
|
||||
int fd = client->file_descriptor;
|
||||
if (!send_status(fd, STATUS_SYMLINK) || !send_str(fd, file_wire_path(file)) ||
|
||||
!send_str(fd, file->symlink_target))
|
||||
return false;
|
||||
return !config->use_metadata || metadata_send(fd, file->metadata);
|
||||
}
|
||||
|
||||
// Send a single file directly via sendfile (non-incremental path).
|
||||
static bool send_file_direct_sendfile(File* file, int fd, bool use_metadata, const Config* config) {
|
||||
if (!send_status(fd, STATUS_NEXT))
|
||||
@@ -1248,6 +1264,13 @@ static int send_chunk_with_removal(Client* client, Chunk* chunk, Config* config,
|
||||
change_emit_file_sent(config, f);
|
||||
continue;
|
||||
}
|
||||
/* Symlink entry (-l / -k keep-as-symlink): only the target rides the wire. */
|
||||
if (f->is_symlink) {
|
||||
if (!send_symlink_entry(client, f, config))
|
||||
return -1;
|
||||
change_emit_file_sent(config, f);
|
||||
continue;
|
||||
}
|
||||
bool stream = f->data->data == NULL && f->data->size > 0;
|
||||
bool use_sendfile =
|
||||
(config->use_sendfile && !config->use_compression) || (stream && !config->use_compression);
|
||||
|
||||
Reference in New Issue
Block a user