From: Daan De Meyer Date: Sun, 12 Jul 2026 19:50:42 +0000 (+0200) Subject: copy: drop COPY_REFLINK X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5a12005c834eab92d7c76d61c7090aa78b61cdfb;p=thirdparty%2Fsystemd.git copy: drop COPY_REFLINK Reflinking is a safe optimization whenever the source and destination are regular, seekable files on a filesystem that supports cloning. Requiring each caller to opt in through COPY_REFLINK adds flag plumbing without changing the necessary fallback behavior. Drop COPY_REFLINK, renumber the remaining flags, and have copy_bytes_full() unconditionally try FICLONE or FICLONERANGE before entering its normal copy loop. Isolate the clone attempt and its file-offset bookkeeping in a helper so copy_bytes_full() only has to handle its cloned, unavailable, and error results. A successful clone therefore completes in one operation, while an unsupported or rejected clone falls back to progress-limited copy_file_range(), sendfile(), or buffered copying. Keep the public reflink helpers for operations that specifically require clone semantics. Existing test-copy coverage exercises both bounded and unbounded regular-file copies through copy_bytes_full(). Signed-off-by: Daan De Meyer --- diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c index 3369f6c3b96..86add95ebb3 100644 --- a/src/analyze/analyze-verify.c +++ b/src/analyze/analyze-verify.c @@ -46,7 +46,7 @@ static int process_aliases(char *argv[], char *tempdir, char ***ret) { if (!dst) return -ENOMEM; - r = copy_file(src, dst, 0, 0644, COPY_REFLINK); + r = copy_file(src, dst, 0, 0644, /* copy_flags= */ 0); if (r < 0) return r; diff --git a/src/bootctl/bootctl-install.c b/src/bootctl/bootctl-install.c index 3453609792e..d75b4f67bbb 100644 --- a/src/bootctl/bootctl-install.c +++ b/src/bootctl/bootctl-install.c @@ -523,7 +523,7 @@ static int copy_file_with_version_check( * might be left at the end of the file. (Resetting before rather than after a copy attempt is safer * because a previous attempt might have failed half-way, leaving the file offset at some undefined * place.) */ - r = copy_bytes(source_fd, write_fd, UINT64_MAX, COPY_REFLINK|COPY_SEEK0_SOURCE); + r = copy_bytes(source_fd, write_fd, UINT64_MAX, COPY_SEEK0_SOURCE); if (r < 0) return log_error_errno(r, "Failed to copy data from \"%s\" to \"%s\": %m", source_path, dest_path); diff --git a/src/bootctl/bootctl-link.c b/src/bootctl/bootctl-link.c index ed1753af99e..4b806ba5163 100644 --- a/src/bootctl/bootctl-link.c +++ b/src/bootctl/bootctl-link.c @@ -453,7 +453,7 @@ static int begin_copy_file( CLEANUP_TMPFILE_AT(target_dir_fd, t); if (source_fd >= 0) { - r = copy_bytes(source_fd, write_fd, UINT64_MAX, COPY_REFLINK|COPY_SEEK0_SOURCE); + r = copy_bytes(source_fd, write_fd, UINT64_MAX, COPY_SEEK0_SOURCE); if (r < 0) return log_error_errno(r, "Failed to copy data into '%s': %m", filename); diff --git a/src/core/exec-invoke.c b/src/core/exec-invoke.c index 0faedf3dc1c..bdd98e4a71f 100644 --- a/src/core/exec-invoke.c +++ b/src/core/exec-invoke.c @@ -3594,7 +3594,7 @@ static int setup_ephemeral( log_debug("Making ephemeral copy of %s to %s", rootfs->image, new_root); fd = copy_file(rootfs->image, new_root, O_EXCL, 0600, - COPY_LOCK_BSD|COPY_REFLINK|COPY_CRTIME|COPY_NOCOW_AFTER); + COPY_LOCK_BSD|COPY_CRTIME|COPY_NOCOW_AFTER); if (fd < 0) { *reterr_path = strdup(rootfs->image); return log_debug_errno(fd, "Failed to copy image %s to %s: %m", diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index 352d7ffa919..602306d9b9a 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -1402,7 +1402,7 @@ static int action_list_or_mtree_or_copy_or_make_archive(DissectedImage *m, LoopD /* Copying to stdout? */ if (streq(arg_target, "-")) { - r = copy_bytes(source_fd, STDOUT_FILENO, UINT64_MAX, COPY_REFLINK); + r = copy_bytes(source_fd, STDOUT_FILENO, UINT64_MAX, /* copy_flags= */ 0); if (r < 0) return log_error_errno(r, "Failed to copy bytes from %s in mage '%s' to stdout: %m", arg_source, arg_image); @@ -1416,7 +1416,7 @@ static int action_list_or_mtree_or_copy_or_make_archive(DissectedImage *m, LoopD AT_FDCWD, arg_target, arg_copy_ownership == 0 ? getuid() : UID_INVALID, arg_copy_ownership == 0 ? getgid() : GID_INVALID, - COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS); + COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS); if (r >= 0) return 0; if (r != -ENOTDIR) @@ -1433,7 +1433,7 @@ static int action_list_or_mtree_or_copy_or_make_archive(DissectedImage *m, LoopD if (target_fd < 0) return log_error_errno(errno, "Failed to create regular file at target path '%s': %m", arg_target); - r = copy_bytes(source_fd, target_fd, UINT64_MAX, COPY_REFLINK); + r = copy_bytes(source_fd, target_fd, UINT64_MAX, /* copy_flags= */ 0); if (r < 0) return log_error_errno(r, "Failed to copy bytes from %s in mage '%s' to '%s': %m", arg_source, arg_image, arg_target); @@ -1472,7 +1472,7 @@ static int action_list_or_mtree_or_copy_or_make_archive(DissectedImage *m, LoopD if (target_fd < 0) return log_error_errno(errno, "Failed to open target file '%s': %m", arg_target); - r = copy_bytes(STDIN_FILENO, target_fd, UINT64_MAX, COPY_REFLINK); + r = copy_bytes(STDIN_FILENO, target_fd, UINT64_MAX, /* copy_flags= */ 0); if (r < 0) return log_error_errno(r, "Failed to copy bytes from stdin to '%s' in image '%s': %m", arg_target, arg_image); @@ -1505,7 +1505,7 @@ static int action_list_or_mtree_or_copy_or_make_archive(DissectedImage *m, LoopD dfd, bn, arg_copy_ownership == 0 ? getuid() : UID_INVALID, arg_copy_ownership == 0 ? getgid() : GID_INVALID, - COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, + COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, /* denylist= */ NULL, /* subvolumes= */ NULL); } else @@ -1514,7 +1514,7 @@ static int action_list_or_mtree_or_copy_or_make_archive(DissectedImage *m, LoopD target_fd, ".", arg_copy_ownership == 0 ? getuid() : UID_INVALID, arg_copy_ownership == 0 ? getgid() : GID_INVALID, - COPY_REFLINK|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, + COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS, /* denylist= */ NULL, /* subvolumes= */ NULL); if (r < 0) @@ -1531,7 +1531,7 @@ static int action_list_or_mtree_or_copy_or_make_archive(DissectedImage *m, LoopD if (target_fd < 0) return log_error_errno(errno, "Failed to open target file '%s': %m", arg_target); - r = copy_bytes(source_fd, target_fd, UINT64_MAX, COPY_REFLINK); + r = copy_bytes(source_fd, target_fd, UINT64_MAX, /* copy_flags= */ 0); if (r < 0) return log_error_errno(r, "Failed to copy bytes from '%s' to '%s' in image '%s': %m", arg_source, arg_target, arg_image); diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 55b4f922c1b..f3ea57ec929 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -384,7 +384,7 @@ static int process_locale(int rfd, sd_varlink **mute_console_link) { return log_error_errno(r, "Failed to check if directory file descriptor is root: %m"); if (arg_copy_locale && r == 0) { - r = copy_file_atomic_at(AT_FDCWD, etc_locale_conf(), pfd, f, 0644, COPY_REFLINK); + r = copy_file_atomic_at(AT_FDCWD, etc_locale_conf(), pfd, f, 0644, /* copy_flags= */ 0); if (r != -ENOENT) { if (r < 0) return log_error_errno(r, "Failed to copy host's /etc/locale.conf: %m"); @@ -526,7 +526,7 @@ static int process_keymap(int rfd, sd_varlink **mute_console_link) { return log_error_errno(r, "Failed to check if directory file descriptor is root: %m"); if (arg_copy_keymap && r == 0) { - r = copy_file_atomic_at(AT_FDCWD, etc_vconsole_conf(), pfd, f, 0644, COPY_REFLINK); + r = copy_file_atomic_at(AT_FDCWD, etc_vconsole_conf(), pfd, f, 0644, /* copy_flags= */ 0); if (r != -ENOENT) { if (r < 0) return log_error_errno(r, "Failed to copy host's /etc/vconsole.conf: %m"); diff --git a/src/import/import-fs.c b/src/import/import-fs.c index fd54faefc02..72d6fef877f 100644 --- a/src/import/import-fs.c +++ b/src/import/import-fs.c @@ -229,7 +229,6 @@ static int verb_import_fs(int argc, char *argv[], uintptr_t _data, void *userdat AT_FDCWD, dest, /* override_uid= */ UID_INVALID, /* override_gid= */ GID_INVALID, - COPY_REFLINK| COPY_SAME_MOUNT| COPY_HARDLINKS| COPY_SIGINT| diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c index 900be21f59f..6a61a389601 100644 --- a/src/import/pull-raw.c +++ b/src/import/pull-raw.c @@ -319,7 +319,6 @@ static int raw_pull_copy_auxiliary_file( *path, local, 0644, - COPY_REFLINK | (FLAGS_SET(p->flags, IMPORT_FORCE) ? COPY_REPLACE : 0) | (FLAGS_SET(p->flags, IMPORT_SYNC) ? COPY_FSYNC_FULL : 0)); else @@ -392,7 +391,7 @@ static int raw_pull_make_local_copy(RawPull *p) { * since it reduces fragmentation caused by not allowing in-place writes. */ (void) import_set_nocow_and_log(dfd, tp); - r = copy_bytes(p->raw_job->disk_fd, dfd, UINT64_MAX, COPY_REFLINK); + r = copy_bytes(p->raw_job->disk_fd, dfd, UINT64_MAX, /* copy_flags= */ 0); if (r < 0) return log_error_errno(r, "Failed to make writable copy of image: %m"); diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index 6518c28d729..6325ee71959 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -343,7 +343,7 @@ static int tar_pull_make_local_copy(TarPull *p) { BTRFS_SNAPSHOT_FALLBACK_DIRECTORY| BTRFS_SNAPSHOT_RECURSIVE); else - r = copy_tree(p->final_path, t, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_HARDLINKS, NULL, NULL); + r = copy_tree(p->final_path, t, UID_INVALID, GID_INVALID, COPY_HARDLINKS, NULL, NULL); if (r < 0) return log_error_errno(r, "Failed to create original download image: %m"); } @@ -382,7 +382,6 @@ static int tar_pull_make_local_copy(TarPull *p) { p->settings_path, local_settings, 0664, - COPY_REFLINK | (FLAGS_SET(p->flags, IMPORT_FORCE) ? COPY_REPLACE : 0) | (FLAGS_SET(p->flags, IMPORT_SYNC) ? COPY_FSYNC_FULL : 0)); else diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index cf1d3d6bdbc..09872b53bbb 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -567,7 +567,7 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) { const char *src, *dest, *host_path, *container_path; - CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS; + CopyFlags copy_flags = COPY_MERGE|COPY_HARDLINKS; Machine *m = ASSERT_PTR(userdata); Manager *manager = m->manager; bool copy_from; diff --git a/src/machine/machine-varlink.c b/src/machine/machine-varlink.c index a801978fafd..7dd6df01626 100644 --- a/src/machine/machine-varlink.c +++ b/src/machine/machine-varlink.c @@ -966,7 +966,7 @@ int vl_method_copy_internal(sd_varlink *link, sd_json_variant *parameters, sd_va const char *dest = p.dest ?: p.src; const char *container_path = copy_from ? p.src : dest; const char *host_path = copy_from ? dest : p.src; - CopyFlags copy_flags = COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS; + CopyFlags copy_flags = COPY_MERGE|COPY_HARDLINKS; copy_flags |= p.replace ? COPY_REPLACE : 0; Machine *machine; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index a2e0d31de7d..f44a61db3fc 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -1877,7 +1877,7 @@ static int setup_timezone(const char *dest) { case TIMEZONE_COPY: /* If mounting failed, try to copy */ - r = copy_file_atomic("/etc/localtime", where, 0644, COPY_REFLINK|COPY_REPLACE); + r = copy_file_atomic("/etc/localtime", where, 0644, COPY_REPLACE); if (r < 0) { log_full_errno(ERRNO_IS_NEG_FS_WRITE_REFUSED(r) ? LOG_DEBUG : LOG_WARNING, r, "Failed to copy /etc/localtime to %s, ignoring: %m", where); @@ -2005,9 +2005,9 @@ static int setup_resolv_conf(const char *dest) { } if (IN_SET(m, RESOLV_CONF_REPLACE_HOST, RESOLV_CONF_REPLACE_STATIC, RESOLV_CONF_REPLACE_UPLINK, RESOLV_CONF_REPLACE_STUB)) - r = copy_file_atomic(what, where, 0644, COPY_REFLINK|COPY_REPLACE); + r = copy_file_atomic(what, where, 0644, COPY_REPLACE); else - r = copy_file(what, where, O_TRUNC|O_NOFOLLOW, 0644, COPY_REFLINK); + r = copy_file(what, where, O_TRUNC|O_NOFOLLOW, 0644, /* copy_flags= */ 0); if (r < 0) { /* If the file already exists as symlink, let's suppress the warning, under the assumption that * resolved or something similar runs inside and the symlink points there. @@ -6474,7 +6474,7 @@ static int run(int argc, char *argv[]) { { BLOCK_SIGNALS(SIGINT); r = copy_file(arg_image, np, O_EXCL, arg_read_only ? 0400 : 0600, - COPY_REFLINK|COPY_CRTIME|COPY_SIGINT|COPY_NOCOW_AFTER); + COPY_CRTIME|COPY_SIGINT|COPY_NOCOW_AFTER); } if (r == -EINTR) { log_error_errno(r, "Interrupted while copying image file to %s, removed again.", np); diff --git a/src/portable/portable.c b/src/portable/portable.c index d49c8a76b5e..c2691b6ff9e 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -1610,7 +1610,7 @@ static int install_profile_dropin( return -ENOMEM; if (flags & PORTABLE_PREFER_COPY) { - CopyFlags copy_flags = COPY_REFLINK|COPY_FSYNC; + CopyFlags copy_flags = COPY_FSYNC; if (flags & PORTABLE_FORCE_ATTACH) copy_flags |= COPY_REPLACE; @@ -1754,7 +1754,7 @@ static int attach_unit_file( if (fd < 0) return log_debug_errno(fd, "Failed to create unit file '%s': %m", path); - r = copy_bytes(m->fd, fd, UINT64_MAX, COPY_REFLINK); + r = copy_bytes(m->fd, fd, UINT64_MAX, /* copy_flags= */ 0); if (r < 0) return log_debug_errno(r, "Failed to copy unit file '%s': %m", path); @@ -1883,7 +1883,7 @@ static int install_image( target, UID_INVALID, GID_INVALID, - COPY_REFLINK | COPY_FSYNC | COPY_FSYNC_FULL | COPY_SYNCFS, + COPY_FSYNC | COPY_FSYNC_FULL | COPY_SYNCFS, /* denylist= */ NULL, /* subvolumes= */ NULL); if (r < 0) diff --git a/src/repart/repart.c b/src/repart/repart.c index e3dd9ab3f62..7eadfe4a6af 100644 --- a/src/repart/repart.c +++ b/src/repart/repart.c @@ -2129,7 +2129,7 @@ static int config_parse_copy_files( if (!isempty(p)) return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), "Too many arguments: %s", rvalue); - CopyFlags flags = COPY_REFLINK|COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_TRUNCATE|COPY_RESTORE_DIRECTORY_TIMESTAMPS; + CopyFlags flags = COPY_HOLES|COPY_MERGE|COPY_REPLACE|COPY_SIGINT|COPY_HARDLINKS|COPY_ALL_XATTRS|COPY_GRACEFUL_WARN|COPY_TRUNCATE|COPY_RESTORE_DIRECTORY_TIMESTAMPS; for (const char *opts = options;;) { _cleanup_free_ char *word = NULL; const char *val; @@ -5382,7 +5382,7 @@ static int partition_target_sync(Context *context, Partition *p, PartitionTarget "Partition %" PRIu64 "'s contents (%s) don't fit in the partition (%s).", p->partno, FORMAT_BYTES(st.st_size), FORMAT_BYTES(p->new_size)); - r = copy_bytes(t->fd, whole_fd, UINT64_MAX, COPY_REFLINK|COPY_HOLES|COPY_FSYNC|COPY_SEEK0_SOURCE); + r = copy_bytes(t->fd, whole_fd, UINT64_MAX, COPY_HOLES|COPY_FSYNC|COPY_SEEK0_SOURCE); if (r < 0) return log_error_errno(r, "Failed to copy bytes to partition: %m"); } else { @@ -6371,7 +6371,15 @@ static int context_copy_blocks(Context *context) { return log_error_errno(errno, "Failed to seek to copy blocks offset in %s: %m", p->copy_blocks_path); } - r = copy_bytes_full(p->copy_blocks_fd, partition_target_fd(t), p->copy_blocks_size, COPY_REFLINK, /* ret_remains= */ NULL, /* ret_remains_size= */ NULL, progress_bytes, p); + r = copy_bytes_full( + p->copy_blocks_fd, + partition_target_fd(t), + p->copy_blocks_size, + /* copy_flags= */ 0, + /* ret_remains= */ NULL, + /* ret_remains_size= */ NULL, + progress_bytes, + p); clear_progress_bar(/* prefix= */ NULL); if (r < 0) return log_error_errno(r, "Failed to copy in data from '%s': %m", p->copy_blocks_path); @@ -6895,7 +6903,7 @@ static int do_copy_files(Context *context, Partition *p, const char *root) { if (tfd < 0) return log_error_errno(errno, "Failed to create target file '%s': %m", line->target); - r = copy_bytes(sfd, tfd, UINT64_MAX, COPY_REFLINK|COPY_HOLES|COPY_SIGINT|COPY_TRUNCATE); + r = copy_bytes(sfd, tfd, UINT64_MAX, COPY_HOLES|COPY_SIGINT|COPY_TRUNCATE); if (r < 0) return log_error_errno(r, "Failed to copy '%s' to '%s%s': %m", line->source, strempty(arg_copy_source), line->target); @@ -8168,7 +8176,7 @@ static int context_split(Context *context) { if (r < 0) return log_error_errno(r, "Failed to write to split partition %s: %m", p->split_path); } else { - r = copy_bytes(fd, fdt, p->new_size, COPY_REFLINK|COPY_HOLES|COPY_TRUNCATE); + r = copy_bytes(fd, fdt, p->new_size, COPY_HOLES|COPY_TRUNCATE); if (r < 0) return log_error_errno(r, "Failed to copy to split partition %s: %m", p->split_path); } diff --git a/src/sbsign/sbsign.c b/src/sbsign/sbsign.c index 0d86f8544f3..d7eb9a6f210 100644 --- a/src/sbsign/sbsign.c +++ b/src/sbsign/sbsign.c @@ -608,7 +608,7 @@ static int verb_sign(int argc, char *argv[], uintptr_t _data, void *userdata) { if (!certificate_table) return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "File lacks certificate table."); - r = copy_bytes(srcfd, dstfd, UINT64_MAX, COPY_REFLINK); + r = copy_bytes(srcfd, dstfd, UINT64_MAX, /* copy_flags= */ 0); if (r < 0) return log_error_errno(r, "Failed to copy %s to %s: %m", argv[1], tmp); diff --git a/src/shared/btrfs-util.c b/src/shared/btrfs-util.c index 4833149005f..780c1be3496 100644 --- a/src/shared/btrfs-util.c +++ b/src/shared/btrfs-util.c @@ -1471,7 +1471,6 @@ int btrfs_subvol_snapshot_at_full( /* override_uid= */ UID_INVALID, /* override_gid= */ GID_INVALID, COPY_MERGE_EMPTY| - COPY_REFLINK| COPY_SAME_MOUNT| COPY_HARDLINKS| COPY_ALL_XATTRS| diff --git a/src/shared/copy.c b/src/shared/copy.c index 527022dcca9..7a87842a344 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -130,6 +130,68 @@ static int create_hole(int fd, off_t size) { return 0; } +/* Returns positive if the range was cloned, zero if cloning is unavailable, and negative if finalizing a + * successful clone failed. If the range was cloned, returns the copy_bytes_full() result in ret_copy_result. */ +static int try_reflink_copy_bytes( + int fdf, + int fdt, + uint64_t max_bytes, + CopyFlags copy_flags, + int *ret_copy_result) { + + off_t foffset, toffset; + int r; + + assert(fdf >= 0); + assert(fdt >= 0); + assert(ret_copy_result); + + if (max_bytes == 0) + return 0; + + foffset = FLAGS_SET(copy_flags, COPY_SEEK0_SOURCE) ? 0 : lseek(fdf, 0, SEEK_CUR); + if (foffset < 0) + return 0; + + toffset = FLAGS_SET(copy_flags, COPY_SEEK0_TARGET) ? 0 : lseek(fdt, 0, SEEK_CUR); + if (toffset < 0) + return 0; + + r = reflink_range(fdf, foffset, fdt, toffset, max_bytes == UINT64_MAX ? 0 : max_bytes); + if (r < 0) + return 0; + + if (max_bytes == UINT64_MAX) { + off_t end; + + end = lseek(fdf, 0, SEEK_END); + if (end < 0) + return -errno; + if (end < foffset) + return -ESPIPE; + + if (lseek(fdt, toffset + (end - foffset), SEEK_SET) < 0) + return -errno; + + *ret_copy_result = 0; /* We copied to EOF. */ + } else { + if (lseek(fdf, foffset + max_bytes, SEEK_SET) < 0) + return -errno; + if (lseek(fdt, toffset + max_bytes, SEEK_SET) < 0) + return -errno; + + *ret_copy_result = 1; /* We copied the requested range. */ + } + + if (FLAGS_SET(copy_flags, COPY_VERIFY_LINKED)) { + r = fd_verify_linked(fdf); + if (r < 0) + return r; + } + + return 1; +} + int copy_bytes_full( int fdf, int fdt, uint64_t max_bytes, @@ -177,77 +239,12 @@ int copy_bytes_full( lseek(fdt, 0, SEEK_SET) < 0) return -errno; - /* Try btrfs reflinks first. This only works on regular, seekable files, hence let's check the file offsets of - * source and destination first. */ - if ((copy_flags & COPY_REFLINK)) { - off_t foffset; - - /* In reflink mode, we need to know the current file offset, unless we already sought to 0 anyway. */ - foffset = FLAGS_SET(copy_flags, COPY_SEEK0_SOURCE) ? 0 : lseek(fdf, 0, SEEK_CUR); - if (foffset >= 0) { - off_t toffset; - - toffset = FLAGS_SET(copy_flags, COPY_SEEK0_TARGET) ? 0 : lseek(fdt, 0, SEEK_CUR); - if (toffset >= 0) { - - if (foffset == 0 && toffset == 0 && max_bytes == UINT64_MAX) - r = reflink(fdf, fdt); /* full file reflink */ - else - r = reflink_range(fdf, foffset, fdt, toffset, max_bytes == UINT64_MAX ? 0 : max_bytes); /* partial reflink */ - if (r >= 0) { - off_t t; - int ret; - - /* This worked, yay! Now — to be fully correct — let's adjust the file pointers */ - if (max_bytes == UINT64_MAX) { - - /* We cloned to the end of the source file, let's position the read - * pointer there, and query it at the same time. */ - t = lseek(fdf, 0, SEEK_END); - if (t < 0) - return -errno; - if (t < foffset) - return -ESPIPE; - - /* Let's adjust the destination file write pointer by the same number - * of bytes. */ - t = lseek(fdt, toffset + (t - foffset), SEEK_SET); - if (t < 0) - return -errno; - - if (FLAGS_SET(copy_flags, COPY_VERIFY_LINKED)) { - r = fd_verify_linked(fdf); - if (r < 0) - return r; - } - - /* We copied the whole thing, hence hit EOF, return 0. */ - ret = 0; - } else { - t = lseek(fdf, foffset + max_bytes, SEEK_SET); - if (t < 0) - return -errno; - - t = lseek(fdt, toffset + max_bytes, SEEK_SET); - if (t < 0) - return -errno; - - /* We copied only some number of bytes, which worked, but - * this means we didn't hit EOF, return 1. */ - ret = 1; - } - - if (FLAGS_SET(copy_flags, COPY_VERIFY_LINKED)) { - r = fd_verify_linked(fdf); - if (r < 0) - return r; - } - - return ret; - } - } - } - } + int reflink_result = 0; + r = try_reflink_copy_bytes(fdf, fdt, max_bytes, copy_flags, &reflink_result); + if (r < 0) + return r; + if (r > 0) + return reflink_result; usec_t start_timestamp = USEC_INFINITY; if (progress) diff --git a/src/shared/copy.h b/src/shared/copy.h index 56732498bcf..c5ced00bc9c 100644 --- a/src/shared/copy.h +++ b/src/shared/copy.h @@ -4,26 +4,25 @@ #include "forward.h" typedef enum CopyFlags { - COPY_REFLINK = 1 << 0, /* Try to reflink */ - COPY_MERGE = 1 << 1, /* Merge existing trees with our new one to copy */ - COPY_REPLACE = 1 << 2, /* Replace an existing file if there's one */ - COPY_SAME_MOUNT = 1 << 3, /* Don't descend recursively into other file systems, across mount point boundaries */ - COPY_MERGE_EMPTY = 1 << 4, /* Merge an existing, empty directory with our new tree to copy */ - COPY_CRTIME = 1 << 5, /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */ - COPY_SIGINT = 1 << 6, /* Check for SIGINT regularly and return EINTR if seen (caller needs to block SIGINT) */ - COPY_SIGTERM = 1 << 7, /* ditto, but for SIGTERM */ - COPY_MAC_CREATE = 1 << 8, /* Create files with the correct MAC label (currently SELinux only) */ - COPY_HARDLINKS = 1 << 9, /* Try to reproduce hard links */ - COPY_FSYNC = 1 << 10, /* fsync() after we are done */ - COPY_FSYNC_FULL = 1 << 11, /* fsync_full() after we are done */ - COPY_SYNCFS = 1 << 12, /* syncfs() the *top-level* dir after we are done */ - COPY_ALL_XATTRS = 1 << 13, /* Preserve all xattrs when copying, not just those in the user namespace */ - COPY_HOLES = 1 << 14, /* Copy holes */ - COPY_GRACEFUL_WARN = 1 << 15, /* Skip copying file types that aren't supported by the target filesystem */ - COPY_TRUNCATE = 1 << 16, /* Truncate to current file offset after copying */ - COPY_LOCK_BSD = 1 << 17, /* Return a BSD exclusively locked file descriptor referring to the copied image/directory. */ - COPY_VERIFY_LINKED = 1 << 18, /* Check the source file is still linked after copying. */ - COPY_RESTORE_DIRECTORY_TIMESTAMPS = 1 << 19, /* Make sure existing directory timestamps don't change during copying. */ + COPY_MERGE = 1 << 0, /* Merge existing trees with our new one to copy */ + COPY_REPLACE = 1 << 1, /* Replace an existing file if there's one */ + COPY_SAME_MOUNT = 1 << 2, /* Don't descend recursively into other file systems, across mount point boundaries */ + COPY_MERGE_EMPTY = 1 << 3, /* Merge an existing, empty directory with our new tree to copy */ + COPY_CRTIME = 1 << 4, /* Generate a user.crtime_usec xattr off the source crtime if there is one, on copying */ + COPY_SIGINT = 1 << 5, /* Check for SIGINT regularly and return EINTR if seen (caller needs to block SIGINT) */ + COPY_SIGTERM = 1 << 6, /* ditto, but for SIGTERM */ + COPY_MAC_CREATE = 1 << 7, /* Create files with the correct MAC label (currently SELinux only) */ + COPY_HARDLINKS = 1 << 8, /* Try to reproduce hard links */ + COPY_FSYNC = 1 << 9, /* fsync() after we are done */ + COPY_FSYNC_FULL = 1 << 10, /* fsync_full() after we are done */ + COPY_SYNCFS = 1 << 11, /* syncfs() the *top-level* dir after we are done */ + COPY_ALL_XATTRS = 1 << 12, /* Preserve all xattrs when copying, not just those in the user namespace */ + COPY_HOLES = 1 << 13, /* Copy holes */ + COPY_GRACEFUL_WARN = 1 << 14, /* Skip copying file types that aren't supported by the target filesystem */ + COPY_TRUNCATE = 1 << 15, /* Truncate to current file offset after copying */ + COPY_LOCK_BSD = 1 << 16, /* Return a BSD exclusively locked file descriptor referring to the copied image/directory. */ + COPY_VERIFY_LINKED = 1 << 17, /* Check the source file is still linked after copying. */ + COPY_RESTORE_DIRECTORY_TIMESTAMPS = 1 << 18, /* Make sure existing directory timestamps don't change during copying. */ /* A root image might be subject to lots of random writes so we provide a flag to try to disable COW * on a copied file which tends to not perform well in combination with lots of random writes. * @@ -31,11 +30,11 @@ typedef enum CopyFlags { * least makes the intention clear. We don't want to unconditionally set the flag before doing the * copy because reflinking from COW to NOCOW files is not supported. */ - COPY_NOCOW_AFTER = 1 << 20, - COPY_PRESERVE_FS_VERITY = 1 << 21, /* Preserve fs-verity when copying. */ - COPY_MERGE_APPLY_STAT = 1 << 22, /* When we reuse an existing directory inode, apply source ownership/mode/xattrs/timestamps */ - COPY_SEEK0_SOURCE = 1 << 23, /* Seek back to start of source file before copying */ - COPY_SEEK0_TARGET = 1 << 24, /* Seek back to start of target file before copying */ + COPY_NOCOW_AFTER = 1 << 19, + COPY_PRESERVE_FS_VERITY = 1 << 20, /* Preserve fs-verity when copying. */ + COPY_MERGE_APPLY_STAT = 1 << 21, /* When we reuse an existing directory inode, apply source ownership/mode/xattrs/timestamps */ + COPY_SEEK0_SOURCE = 1 << 22, /* Seek back to start of source file before copying */ + COPY_SEEK0_TARGET = 1 << 23, /* Seek back to start of target file before copying */ } CopyFlags; typedef enum DenyType { diff --git a/src/shared/data-fd-util.c b/src/shared/data-fd-util.c index c91d0561497..4e6ca04aa4d 100644 --- a/src/shared/data-fd-util.c +++ b/src/shared/data-fd-util.c @@ -50,7 +50,7 @@ int copy_data_fd(int fd) { if (copy_fd < 0) return copy_fd; - r = copy_bytes(fd, copy_fd, DATA_FD_MEMORY_LIMIT, COPY_REFLINK); + r = copy_bytes(fd, copy_fd, DATA_FD_MEMORY_LIMIT, /* copy_flags= */ 0); if (r < 0) return r; @@ -80,14 +80,14 @@ int copy_data_fd(int fd) { /* If we tried a memfd first and it ended up being too large, then copy this into the * temporary file first. */ - r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, COPY_REFLINK); + r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, /* copy_flags= */ 0); if (r < 0) return r; assert(r == 0); } - r = copy_bytes(fd, tmp_fd, DATA_FD_TMP_LIMIT - DATA_FD_MEMORY_LIMIT, COPY_REFLINK); + r = copy_bytes(fd, tmp_fd, DATA_FD_TMP_LIMIT - DATA_FD_MEMORY_LIMIT, /* copy_flags= */ 0); if (r < 0) return r; if (r == 0) @@ -115,7 +115,7 @@ int copy_data_fd(int fd) { if (copy_fd >= 0) { /* If we tried a memfd first, or a file in /tmp/, and it ended up being too large, than copy this * into the temporary file first. */ - r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, COPY_REFLINK); + r = copy_bytes(copy_fd, tmp_fd, UINT64_MAX, /* copy_flags= */ 0); if (r < 0) return r; @@ -123,7 +123,7 @@ int copy_data_fd(int fd) { } /* Copy in the rest */ - r = copy_bytes(fd, tmp_fd, UINT64_MAX, COPY_REFLINK); + r = copy_bytes(fd, tmp_fd, UINT64_MAX, /* copy_flags= */ 0); if (r < 0) return r; @@ -164,7 +164,7 @@ int memfd_clone_fd(int fd, const char *name, int mode) { if (mfd < 0) return mfd; - r = copy_bytes(fd, mfd, UINT64_MAX, COPY_REFLINK); + r = copy_bytes(fd, mfd, UINT64_MAX, /* copy_flags= */ 0); if (r < 0) return r; diff --git a/src/shared/discover-image.c b/src/shared/discover-image.c index 9994ff5da45..07d0ff128f8 100644 --- a/src/shared/discover-image.c +++ b/src/shared/discover-image.c @@ -1625,7 +1625,7 @@ static int clone_auxiliary_file(const char *path, const char *new_name, const ch if (r < 0) return r; - return copy_file_atomic(path, rs, 0664, COPY_REFLINK); + return copy_file_atomic(path, rs, 0664, /* copy_flags= */ 0); } static int get_pool_directory( @@ -1805,7 +1805,7 @@ int image_clone(Image *i, const char *new_name, bool read_only, RuntimeScope sco return r; r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, - COPY_REFLINK|COPY_CRTIME|COPY_NOCOW_AFTER); + COPY_CRTIME|COPY_NOCOW_AFTER); break; } diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index af19a48eeac..1bfb2492922 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -5611,7 +5611,7 @@ int copy_tree_at_foreign(int source_fd, int target_fd, int userns_fd) { target_fd, /* to= */ NULL, /* override_uid= */ UID_INVALID, /* override_gid= */ GID_INVALID, - COPY_REFLINK|COPY_HARDLINKS|COPY_MERGE_EMPTY|COPY_MERGE_APPLY_STAT|COPY_SAME_MOUNT|COPY_ALL_XATTRS, + COPY_HARDLINKS|COPY_MERGE_EMPTY|COPY_MERGE_APPLY_STAT|COPY_SAME_MOUNT|COPY_ALL_XATTRS, /* denylist= */ NULL, /* subvolumes= */ NULL); if (r < 0) { diff --git a/src/shared/edit-util.c b/src/shared/edit-util.c index 4180d2a6f7d..f5d46f8d156 100644 --- a/src/shared/edit-util.c +++ b/src/shared/edit-util.c @@ -183,7 +183,7 @@ static int populate_edit_temp_file(EditFile *e, FILE *f, const char *filename) { } } } else if (source) { - r = copy_file_fd(source, fileno(f), COPY_REFLINK); + r = copy_file_fd(source, fileno(f), /* copy_flags= */ 0); if (r < 0) { assert(r != -ENOENT); return log_error_errno(r, "Failed to copy file '%s' to temporary file '%s': %m", @@ -444,7 +444,7 @@ static int edit_file_install_one_stdin(EditFile *e, const char *contents, size_t if (r < 0) return log_error_errno(r, "Failed to create parent directories for '%s': %m", e->path); - r = copy_file_atomic_at(*fd, NULL, AT_FDCWD, e->path, 0644, COPY_REFLINK|COPY_REPLACE|COPY_MAC_CREATE); + r = copy_file_atomic_at(*fd, NULL, AT_FDCWD, e->path, 0644, COPY_REPLACE|COPY_MAC_CREATE); if (r < 0) return log_error_errno(r, "Failed to copy stdin contents to '%s': %m", e->path); diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index c32fb72d5e8..0970b76de23 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -333,7 +333,7 @@ static int make_backup(const char *target, const char *x) { if (r < 0) return r; - r = copy_bytes(src, fileno(dst), UINT64_MAX, COPY_REFLINK); + r = copy_bytes(src, fileno(dst), UINT64_MAX, /* copy_flags= */ 0); if (r < 0) return r; diff --git a/src/test/test-copy.c b/src/test/test-copy.c index 8465d6cc99f..e3e93f3642d 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -46,7 +46,7 @@ TEST(copy_file) { assert_se(write_string_file(fn, "foo bar bar bar foo", WRITE_STRING_FILE_CREATE) == 0); - assert_se(copy_file(fn, fn_copy, 0, 0644, COPY_REFLINK) == 0); + assert_se(copy_file(fn, fn_copy, 0, 0644, /* copy_flags= */ 0) == 0); assert_se(read_full_file(fn_copy, &buf, &sz) == 0); ASSERT_STREQ(buf, "foo bar bar bar foo\n"); @@ -71,11 +71,11 @@ TEST(copy_tree_replace_file) { /* The file exists- now overwrite original contents, and test the COPY_REPLACE flag. */ - assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK, NULL, NULL) == -EEXIST); + assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, /* copy_flags= */ 0, NULL, NULL) == -EEXIST); assert_se(read_file_at_and_streq(AT_FDCWD, dst, "foo foo foo\n")); - assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE, NULL, NULL) == 0); + assert_se(copy_tree(src, dst, UID_INVALID, GID_INVALID, COPY_REPLACE, NULL, NULL) == 0); assert_se(read_file_at_and_streq(AT_FDCWD, dst, "bar bar\n")); } @@ -96,14 +96,21 @@ TEST(copy_tree_replace_dirs) { assert_se(write_string_file_at(dst, "bar", "dest file 2", WRITE_STRING_FILE_CREATE) == 0); /* Copying without COPY_REPLACE should fail because the destination file already exists. */ - assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK, NULL, NULL) == -EEXIST); + assert_se(copy_tree_at( + src, ".", + dst, ".", + UID_INVALID, + GID_INVALID, + /* copy_flags= */ 0, + /* denylist= */ NULL, + /* subvolumes= */ NULL) == -EEXIST); assert_se(read_file_at_and_streq(src, "foo", "src file 1\n")); assert_se(read_file_at_and_streq(src, "bar", "src file 2\n")); assert_se(read_file_at_and_streq(dst, "foo", "dest file 1\n")); assert_se(read_file_at_and_streq(dst, "bar", "dest file 2\n")); - assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE, NULL, NULL) == 0); + assert_se(copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REPLACE|COPY_MERGE, NULL, NULL) == 0); assert_se(read_file_at_and_streq(src, "foo", "src file 1\n")); assert_se(read_file_at_and_streq(src, "bar", "src file 2\n")); @@ -124,8 +131,8 @@ TEST(copy_file_fd) { assert_se(out_fd >= 0); assert_se(write_string_file(in_fn, text, WRITE_STRING_FILE_CREATE) == 0); - assert_se(copy_file_fd("/a/file/which/does/not/exist/i/guess", out_fd, COPY_REFLINK) < 0); - assert_se(copy_file_fd(in_fn, out_fd, COPY_REFLINK) >= 0); + assert_se(copy_file_fd("/a/file/which/does/not/exist/i/guess", out_fd, /* copy_flags= */ 0) < 0); + assert_se(copy_file_fd(in_fn, out_fd, /* copy_flags= */ 0) >= 0); assert_se(lseek(out_fd, 0, SEEK_SET) == 0); assert_se(read(out_fd, buf, sizeof buf) == (ssize_t) strlen(text)); @@ -203,7 +210,7 @@ TEST(copy_tree) { assert_se(hashmap_ensure_put(&denylist, &inode_hash_ops, cp, INT_TO_PTR(DENY_CONTENTS)) >= 0); TAKE_PTR(cp); - assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_MERGE|COPY_HARDLINKS, denylist, NULL) == 0); + assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_MERGE|COPY_HARDLINKS, denylist, NULL) == 0); STRV_FOREACH(p, files) { _cleanup_free_ char *buf = NULL, *f = NULL, *c = NULL; @@ -255,8 +262,22 @@ TEST(copy_tree) { assert_se(stat(unixsockp, &st) >= 0); assert_se(S_ISSOCK(st.st_mode)); - assert_se(copy_tree(original_dir, copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK, denylist, NULL) < 0); - assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, UID_INVALID, GID_INVALID, COPY_REFLINK, denylist, NULL) < 0); + assert_se(copy_tree( + original_dir, + copy_dir, + UID_INVALID, + GID_INVALID, + /* copy_flags= */ 0, + denylist, + /* subvolumes= */ NULL) < 0); + assert_se(copy_tree( + "/tmp/inexistent/foo/bar/fsdoi", + copy_dir, + UID_INVALID, + GID_INVALID, + /* copy_flags= */ 0, + denylist, + /* subvolumes= */ NULL) < 0); ignorep = strjoina(copy_dir, "ignore/file"); assert_se(RET_NERRNO(access(ignorep, F_OK)) == -ENOENT); @@ -411,14 +432,14 @@ TEST_RET(copy_bytes) { return 0; } -static void test_copy_bytes_regular_file_one(const char *src, bool try_reflink, uint64_t max_bytes) { +static void test_copy_bytes_regular_file_one(const char *src, uint64_t max_bytes) { _cleanup_(unlink_tempfilep) char fn2[] = "/tmp/test-copy-file-XXXXXX"; _cleanup_(unlink_tempfilep) char fn3[] = "/tmp/test-copy-file-XXXXXX"; _cleanup_close_ int fd = -EBADF, fd2 = -EBADF, fd3 = -EBADF; int r; struct stat buf, buf2, buf3; - log_info("%s try_reflink=%s max_bytes=%" PRIu64, __func__, yes_no(try_reflink), max_bytes); + log_info("%s max_bytes=%" PRIu64, __func__, max_bytes); fd = open(src, O_CLOEXEC | O_PATH); assert_se(fd >= 0); @@ -429,7 +450,7 @@ static void test_copy_bytes_regular_file_one(const char *src, bool try_reflink, fd3 = mkostemp_safe(fn3); assert_se(fd3 >= 0); - r = copy_bytes(fd, fd2, max_bytes, try_reflink ? COPY_REFLINK : 0); + r = copy_bytes(fd, fd2, max_bytes, /* copy_flags= */ 0); if (max_bytes == UINT64_MAX) assert_se(r == 0); else @@ -443,7 +464,7 @@ static void test_copy_bytes_regular_file_one(const char *src, bool try_reflink, /* Make sure the file is now higher than max_bytes */ assert_se(ftruncate(fd2, max_bytes + 1) == 0); - r = copy_bytes(fd2, fd3, max_bytes, COPY_SEEK0_SOURCE | (try_reflink ? COPY_REFLINK : 0)); + r = copy_bytes(fd2, fd3, max_bytes, COPY_SEEK0_SOURCE); if (max_bytes == UINT64_MAX) assert_se(r == 0); else @@ -463,12 +484,9 @@ static void test_copy_bytes_regular_file_one(const char *src, bool try_reflink, } TEST(copy_bytes_regular_file) { - test_copy_bytes_regular_file_one(saved_argv[0], false, UINT64_MAX); - test_copy_bytes_regular_file_one(saved_argv[0], true, UINT64_MAX); - test_copy_bytes_regular_file_one(saved_argv[0], false, 1000); /* smaller than copy buffer size */ - test_copy_bytes_regular_file_one(saved_argv[0], true, 1000); - test_copy_bytes_regular_file_one(saved_argv[0], false, 32000); /* larger than copy buffer size */ - test_copy_bytes_regular_file_one(saved_argv[0], true, 32000); + test_copy_bytes_regular_file_one(saved_argv[0], UINT64_MAX); + test_copy_bytes_regular_file_one(saved_argv[0], 1000); /* smaller than copy buffer size */ + test_copy_bytes_regular_file_one(saved_argv[0], 32000); /* larger than copy buffer size */ } TEST(copy_atomic) { @@ -480,11 +498,11 @@ TEST(copy_atomic) { q = strjoina(p, "/fstab"); - r = copy_file_atomic("/etc/fstab", q, 0644, COPY_REFLINK); + r = copy_file_atomic("/etc/fstab", q, 0644, /* copy_flags= */ 0); if (r == -ENOENT || ERRNO_IS_PRIVILEGE(r)) return; - assert_se(copy_file_atomic("/etc/fstab", q, 0644, COPY_REFLINK) == -EEXIST); + assert_se(copy_file_atomic("/etc/fstab", q, 0644, /* copy_flags= */ 0) == -EEXIST); assert_se(copy_file_atomic("/etc/fstab", q, 0644, COPY_REPLACE) >= 0); } @@ -746,7 +764,7 @@ TEST_RET(copy_with_verity) { assert_no_fsverity(dst, *file); /* Copy *with* fs-verity enabled and make sure it works properly */ - int r = copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL); + int r = copy_tree_at(src, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL); if (r == -ESOCKTNOSUPPORT) /* This can happen on some versions of btrfs, for example */ return log_tests_skipped_errno(errno, "/var/tmp: fs-verity supported, but not reading metadata"); @@ -768,14 +786,14 @@ TEST_RET(copy_with_verity) { /* Copy from our non-verity filesystem into dst, requesting verity and making sure we notice that * we failed to read verity from the source. */ - ASSERT_ERROR(copy_tree_at(badsrc, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ESOCKTNOSUPPORT); + ASSERT_ERROR(copy_tree_at(badsrc, ".", dst, ".", UID_INVALID, GID_INVALID, COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ESOCKTNOSUPPORT); /* Copy from our verity filesystem into our baddst, requesting verity and making sure we notice that * we failed to set verity on the destination. */ - ASSERT_ERROR(copy_tree_at(src, ".", baddst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ESOCKTNOSUPPORT); + ASSERT_ERROR(copy_tree_at(src, ".", baddst, ".", UID_INVALID, GID_INVALID, COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ESOCKTNOSUPPORT); /* Of course this should fail too... */ - ASSERT_ERROR(copy_tree_at(badsrc, ".", baddst, ".", UID_INVALID, GID_INVALID, COPY_REFLINK|COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ESOCKTNOSUPPORT); + ASSERT_ERROR(copy_tree_at(badsrc, ".", baddst, ".", UID_INVALID, GID_INVALID, COPY_REPLACE|COPY_MERGE|COPY_PRESERVE_FS_VERITY, NULL, NULL), ESOCKTNOSUPPORT); return 0; } diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index 6fea526d67f..0ccd555e7e1 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -434,7 +434,7 @@ TEST(conservative_rename) { assert_se(access(q, F_OK) < 0 && errno == ENOENT); /* Check that a manual copy is detected */ - assert_se(copy_file(p, q, 0, MODE_INVALID, COPY_REFLINK) >= 0); + assert_se(copy_file(p, q, 0, MODE_INVALID, /* copy_flags= */ 0) >= 0); assert_se(conservative_renameat(AT_FDCWD, q, AT_FDCWD, p) == 0); assert_se(access(q, F_OK) < 0 && errno == ENOENT); diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 0667b5b71f8..582c6f8a4ef 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -2236,7 +2236,7 @@ static int copy_files(Context *c, Item *i) { dfd, bn, i->uid_set ? i->uid : UID_INVALID, i->gid_set ? i->gid : GID_INVALID, - COPY_REFLINK | ((i->append_or_force) ? COPY_MERGE : COPY_MERGE_EMPTY) | COPY_MAC_CREATE | COPY_HARDLINKS, + ((i->append_or_force) ? COPY_MERGE : COPY_MERGE_EMPTY) | COPY_MAC_CREATE | COPY_HARDLINKS, NULL, NULL); fd = openat(dfd, bn, O_NOFOLLOW|O_CLOEXEC|O_PATH); diff --git a/src/userdb/userdbctl.c b/src/userdb/userdbctl.c index e4fd5a9e8d6..14c3675ea2f 100644 --- a/src/userdb/userdbctl.c +++ b/src/userdb/userdbctl.c @@ -1505,7 +1505,7 @@ static int load_credential_one( return log_error_errno(errno, "Failed to chown %s: %m", hd); r = copy_tree(user_record_skeleton_directory(ur), hd, ur->uid, user_record_gid(ur), - COPY_REFLINK|COPY_MERGE, /* denylist= */ NULL, /* subvolumes= */ NULL); + COPY_MERGE, /* denylist= */ NULL, /* subvolumes= */ NULL); if (r < 0 && r != -ENOENT) return log_error_errno(r, "Failed to copy skeleton directory to %s: %m", hd); } diff --git a/src/vmspawn/vmspawn.c b/src/vmspawn/vmspawn.c index 460219c1445..1e1283c3271 100644 --- a/src/vmspawn/vmspawn.c +++ b/src/vmspawn/vmspawn.c @@ -2025,7 +2025,7 @@ static int merge_initrds(char **ret) { if (ifd < 0) return log_error_errno(errno, "Failed to open %s: %m", *i); - r = copy_bytes(ifd, ofd, UINT64_MAX, COPY_REFLINK); + r = copy_bytes(ifd, ofd, UINT64_MAX, /* copy_flags= */ 0); if (r < 0) return log_error_errno(r, "Failed to copy bytes from %s to %s: %m", *i, merged_initrd); } @@ -2254,7 +2254,7 @@ static int cmdline_add_ovmf(FILE *config_file, const OvmfConfig *ovmf_config, ch if (source_fd < 0) return log_error_errno(errno, "Failed to open OVMF vars file %s: %m", vars_source); - r = copy_bytes(source_fd, target_fd, UINT64_MAX, COPY_REFLINK); + r = copy_bytes(source_fd, target_fd, UINT64_MAX, /* copy_flags= */ 0); if (r < 0) return log_error_errno(r, "Failed to copy bytes from %s to %s: %m", vars_source, state);