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;
* 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);
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);
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",
/* 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);
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)
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);
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);
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
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)
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);
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");
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");
AT_FDCWD, dest,
/* override_uid= */ UID_INVALID,
/* override_gid= */ GID_INVALID,
- COPY_REFLINK|
COPY_SAME_MOUNT|
COPY_HARDLINKS|
COPY_SIGINT|
*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
* 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");
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");
}
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
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;
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;
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);
}
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.
{
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);
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;
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);
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)
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;
"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 {
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);
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);
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);
}
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);
/* override_uid= */ UID_INVALID,
/* override_gid= */ GID_INVALID,
COPY_MERGE_EMPTY|
- COPY_REFLINK|
COPY_SAME_MOUNT|
COPY_HARDLINKS|
COPY_ALL_XATTRS|
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,
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)
#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.
*
* 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 {
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;
/* 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)
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;
}
/* 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;
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;
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(
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;
}
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) {
}
}
} 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",
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);
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;
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");
/* 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"));
}
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"));
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));
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;
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);
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);
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
/* 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
}
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) {
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);
}
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");
/* 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;
}
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);
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);
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);
}
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);
}
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);