]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
copy: drop COPY_REFLINK
authorDaan De Meyer <daan@amutable.com>
Sun, 12 Jul 2026 19:50:42 +0000 (21:50 +0200)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Wed, 15 Jul 2026 10:12:40 +0000 (12:12 +0200)
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 <daan@amutable.com>
28 files changed:
src/analyze/analyze-verify.c
src/bootctl/bootctl-install.c
src/bootctl/bootctl-link.c
src/core/exec-invoke.c
src/dissect/dissect.c
src/firstboot/firstboot.c
src/import/import-fs.c
src/import/pull-raw.c
src/import/pull-tar.c
src/machine/machine-dbus.c
src/machine/machine-varlink.c
src/nspawn/nspawn.c
src/portable/portable.c
src/repart/repart.c
src/sbsign/sbsign.c
src/shared/btrfs-util.c
src/shared/copy.c
src/shared/copy.h
src/shared/data-fd-util.c
src/shared/discover-image.c
src/shared/dissect-image.c
src/shared/edit-util.c
src/sysusers/sysusers.c
src/test/test-copy.c
src/test/test-fs-util.c
src/tmpfiles/tmpfiles.c
src/userdb/userdbctl.c
src/vmspawn/vmspawn.c

index 3369f6c3b96a121a79562ab21e23e5ab5a33be42..86add95ebb3efcae779365c92f667264300f7f8a 100644 (file)
@@ -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;
 
index 3453609792ea62a96aea383261dbf0d2a3663dc2..d75b4f67bbb89839c53d50db04031c6df1e9ebf3 100644 (file)
@@ -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);
 
index ed1753af99e51b73c5b2f970caaee70c718cec98..4b806ba516383377a05a4ae5d13e1588725f7bbf 100644 (file)
@@ -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);
 
index 0faedf3dc1c5d349e551290ce04f2277ed4f1a82..bdd98e4a71fef1a49ac681113eaebedb73a5d50f 100644 (file)
@@ -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",
index 352d7ffa919872bd5051423621f56f0b6d375f64..602306d9b9a8501db4a1cc22b9a6533e25658bd4 100644 (file)
@@ -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);
 
index 55b4f922c1b0e02b682e7f0487c505ac0a6acf7f..f3ea57ec929e962dc7ff5f6700a3f57d0eeee6d5 100644 (file)
@@ -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");
index fd54faefc025a7092b8c5d6ba5a51bf17ebdda8e..72d6fef877f32807738cd5acdf85b6f3499aa0b4 100644 (file)
@@ -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|
index 900be21f59fc39f2b075b2df410c742b90cccbd5..6a61a3896017fd54be7f1663e6d1a281b06ae058 100644 (file)
@@ -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");
 
index 6518c28d72918a363f8bd464c73aa5655bd46b60..6325ee71959a9d3f07c63e47816e8996206213c7 100644 (file)
@@ -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
index cf1d3d6bdbc305bca8cd76925bef0af3c03606a2..09872b53bbbc0a9e8626f86c7adece4a61dfd53b 100644 (file)
@@ -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;
index a801978fafd0a10ac4c0fae4ba55d611d4a99732..7dd6df016262755c8e71ca77dcb21acabb8db10f 100644 (file)
@@ -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;
index a2e0d31de7dfb664f30f1e23b5f02cbcec154a40..f44a61db3fcd2d9b938c6b074b6f27e7974ecb89 100644 (file)
@@ -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);
index d49c8a76b5e3c65a91b6ee9052e5fe0f68ae93da..c2691b6ff9e2cab03bb7ce1020106b26fe348005 100644 (file)
@@ -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)
index e3dd9ab3f62a39ecf1e02b03d9bb65e94f054c5d..7eadfe4a6afb292882ec4d5f381dc8f5443ba610 100644 (file)
@@ -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);
                 }
index 0d86f8544f326b0e8f4b1a10373bbc7b793f2833..d7eb9a6f2100e16e5d4d57028a31bf7394e4b886 100644 (file)
@@ -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);
 
index 4833149005f15bfc1833f232c2a25c6736d117dc..780c1be349675afc7f681824dbe1c31d146753c1 100644 (file)
@@ -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|
index 527022dcca9b22d55a8a5c5ca73a9e6ea04cc523..7a87842a344bb58529a59cf189a773ba714911e8 100644 (file)
@@ -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)
index 56732498bcf9af10d7042b2d7e27db7cd75698cc..c5ced00bc9ce0c61460febd331f0332be5ebac4a 100644 (file)
@@ -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 {
index c91d05614972bce74c4f1d9b5b025555295a5d46..4e6ca04aa4d337bfd2d9c6d6525b4ce7617094f0 100644 (file)
@@ -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;
 
index 9994ff5da451e781ce881ba12005584fc27336e8..07d0ff128f8200999c21beda8a85a65707581031 100644 (file)
@@ -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;
         }
 
index af19a48eeac06ac8a269a5b72288160ba932faff..1bfb2492922429cc51a302f75498de08f1a8cabf 100644 (file)
@@ -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) {
index 4180d2a6f7df5103e94b489eb0178106a1b21b90..f5d46f8d1562715b4d24998dc67f717090239557 100644 (file)
@@ -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);
 
index c32fb72d5e867fed7358c65b46a77f9e04091a42..0970b76de23a03ff0b23429e7604bd00c5f4c69f 100644 (file)
@@ -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;
 
index 8465d6cc99fbab62278cf4b0ea63b690caccb48c..e3e93f3642d6bb2382fc28a685cea43573f9334f 100644 (file)
@@ -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;
 }
index 6fea526d67f7373b589703f6547353d11b0df2cf..0ccd555e7e133a52308d243996877b5e28bdc733 100644 (file)
@@ -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);
 
index 0667b5b71f86b7501b7f147603eba1b339a3ba57..582c6f8a4ef0c01568e8e40e291ea2a23956f0b7 100644 (file)
@@ -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);
index e4fd5a9e8d695f90f91104022909d1595f14f13b..14c3675ea2f099716677c221ece1b06a976d3780 100644 (file)
@@ -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);
                 }
index 460219c1445fe6c60dc3b90784402db52be1ff34..1e1283c3271d259e232462daf09113936ad3e314 100644 (file)
@@ -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);