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 <daan@amutable.com>
This commit is contained in:
Daan De Meyer
2026-07-15 12:12:40 +02:00
committed by Zbigniew Jędrzejewski-Szmek
parent 28b1e4ea16
commit 5a12005c83
28 changed files with 191 additions and 173 deletions
+1 -1
View 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;
+1 -1
View 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);
+1 -1
View 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);
+1 -1
View 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",
+7 -7
View 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);
+2 -2
View 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");
-1
View 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|
+1 -2
View 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");
+1 -2
View 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
+1 -1
View 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;
+1 -1
View 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;
+4 -4
View 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);
+3 -3
View 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)
+13 -5
View 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);
}
+1 -1
View 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);
-1
View 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|
+68 -71
View 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)
+24 -25
View 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 {
+6 -6
View 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;
+2 -2
View 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;
}
+1 -1
View 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) {
+2 -2
View 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);
+1 -1
View 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;
+44 -26
View 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;
}
+1 -1
View 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);
+1 -1
View 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);
+1 -1
View 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);
}
+2 -2
View 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);