copy: change the various copy_xyz() calls to take a unified flags parameter

This adds a unified "copy_flags" parameter to all copy_xyz() function
calls, replacing the various boolean flags so far used. This should make
many invocations more readable as it is clear what behaviour is
precisely requested. This also prepares ground for adding support for
more modes later on.
This commit is contained in:
Lennart Poettering 2017-02-13 19:00:22 +01:00
parent 7026a775e6
commit 1c876927e4
17 changed files with 73 additions and 67 deletions

View File

@ -1737,7 +1737,7 @@ int btrfs_subvol_snapshot_fd(int old_fd, const char *new_path, BtrfsSnapshotFlag
} else if (r < 0)
return r;
r = copy_directory_fd(old_fd, new_path, true);
r = copy_directory_fd(old_fd, new_path, COPY_MERGE|COPY_REFLINK);
if (r < 0)
goto fallback_fail;

View File

@ -68,7 +68,7 @@ static ssize_t try_copy_file_range(int fd_in, loff_t *off_in,
return -errno;
}
int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags) {
bool try_cfr = true, try_sendfile = true, try_splice = true;
int r;
size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */
@ -77,7 +77,7 @@ int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
assert(fdt >= 0);
/* Try btrfs reflinks first. */
if (try_reflink &&
if ((copy_flags & COPY_REFLINK) &&
max_bytes == (uint64_t) -1 &&
lseek(fdf, 0, SEEK_CUR) == 0 &&
lseek(fdt, 0, SEEK_CUR) == 0) {
@ -197,7 +197,7 @@ static int fd_copy_symlink(int df, const char *from, const struct stat *st, int
return 0;
}
static int fd_copy_regular(int df, const char *from, const struct stat *st, int dt, const char *to) {
static int fd_copy_regular(int df, const char *from, const struct stat *st, int dt, const char *to, CopyFlags copy_flags) {
_cleanup_close_ int fdf = -1, fdt = -1;
struct timespec ts[2];
int r, q;
@ -214,7 +214,7 @@ static int fd_copy_regular(int df, const char *from, const struct stat *st, int
if (fdt < 0)
return -errno;
r = copy_bytes(fdf, fdt, (uint64_t) -1, true);
r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags);
if (r < 0) {
unlinkat(dt, to, 0);
return r;
@ -290,7 +290,7 @@ static int fd_copy_directory(
int dt,
const char *to,
dev_t original_device,
bool merge) {
CopyFlags copy_flags) {
_cleanup_close_ int fdf = -1, fdt = -1;
_cleanup_closedir_ DIR *d = NULL;
@ -316,7 +316,7 @@ static int fd_copy_directory(
r = mkdirat(dt, to, st->st_mode & 07777);
if (r >= 0)
created = true;
else if (errno == EEXIST && merge)
else if (errno == EEXIST && (copy_flags & COPY_MERGE))
created = false;
else
return -errno;
@ -343,9 +343,9 @@ static int fd_copy_directory(
continue;
if (S_ISREG(buf.st_mode))
q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name);
q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, copy_flags);
else if (S_ISDIR(buf.st_mode))
q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, merge);
q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, copy_flags);
else if (S_ISLNK(buf.st_mode))
q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name);
else if (S_ISFIFO(buf.st_mode))
@ -355,7 +355,7 @@ static int fd_copy_directory(
else
q = -EOPNOTSUPP;
if (q == -EEXIST && merge)
if (q == -EEXIST && (copy_flags & COPY_MERGE))
q = 0;
if (q < 0)
@ -381,7 +381,7 @@ static int fd_copy_directory(
return r;
}
int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge) {
int copy_tree_at(int fdf, const char *from, int fdt, const char *to, CopyFlags copy_flags) {
struct stat st;
assert(from);
@ -391,9 +391,9 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge)
return -errno;
if (S_ISREG(st.st_mode))
return fd_copy_regular(fdf, from, &st, fdt, to);
return fd_copy_regular(fdf, from, &st, fdt, to, copy_flags);
else if (S_ISDIR(st.st_mode))
return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, merge);
return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, copy_flags);
else if (S_ISLNK(st.st_mode))
return fd_copy_symlink(fdf, from, &st, fdt, to);
else if (S_ISFIFO(st.st_mode))
@ -404,11 +404,11 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge)
return -EOPNOTSUPP;
}
int copy_tree(const char *from, const char *to, bool merge) {
return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, merge);
int copy_tree(const char *from, const char *to, CopyFlags copy_flags) {
return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, copy_flags);
}
int copy_directory_fd(int dirfd, const char *to, bool merge) {
int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) {
struct stat st;
assert(dirfd >= 0);
@ -420,10 +420,10 @@ int copy_directory_fd(int dirfd, const char *to, bool merge) {
if (!S_ISDIR(st.st_mode))
return -ENOTDIR;
return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge);
return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, copy_flags);
}
int copy_directory(const char *from, const char *to, bool merge) {
int copy_directory(const char *from, const char *to, CopyFlags copy_flags) {
struct stat st;
assert(from);
@ -435,10 +435,10 @@ int copy_directory(const char *from, const char *to, bool merge) {
if (!S_ISDIR(st.st_mode))
return -ENOTDIR;
return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, merge);
return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, copy_flags);
}
int copy_file_fd(const char *from, int fdt, bool try_reflink) {
int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) {
_cleanup_close_ int fdf = -1;
int r;
@ -449,7 +449,7 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) {
if (fdf < 0)
return -errno;
r = copy_bytes(fdf, fdt, (uint64_t) -1, try_reflink);
r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags);
(void) copy_times(fdf, fdt);
(void) copy_xattr(fdf, fdt);
@ -457,7 +457,7 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) {
return r;
}
int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags) {
int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
int fdt = -1, r;
assert(from);
@ -472,7 +472,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned
if (chattr_flags != 0)
(void) chattr_fd(fdt, chattr_flags, (unsigned) -1);
r = copy_file_fd(from, fdt, true);
r = copy_file_fd(from, fdt, copy_flags);
if (r < 0) {
close(fdt);
unlink(to);
@ -487,7 +487,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned
return 0;
}
int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags) {
int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) {
_cleanup_free_ char *t = NULL;
int r;
@ -498,11 +498,11 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace
if (r < 0)
return r;
r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags);
r = copy_file(from, t, O_NOFOLLOW|O_EXCL, mode, chattr_flags, copy_flags);
if (r < 0)
return r;
if (replace) {
if (copy_flags & COPY_REPLACE) {
r = renameat(AT_FDCWD, t, AT_FDCWD, to);
if (r < 0)
r = -errno;

View File

@ -24,13 +24,19 @@
#include <stdint.h>
#include <sys/types.h>
int copy_file_fd(const char *from, int to, bool try_reflink);
int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags);
int copy_file_atomic(const char *from, const char *to, mode_t mode, bool replace, unsigned chattr_flags);
int copy_tree(const char *from, const char *to, bool merge);
int copy_tree_at(int fdf, const char *from, int fdt, const char *to, bool merge);
int copy_directory_fd(int dirfd, const char *to, bool merge);
int copy_directory(const char *from, const char *to, bool merge);
int copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink);
typedef enum CopyFlags {
COPY_REFLINK = 0x1, /* try to reflink */
COPY_MERGE = 0x2, /* merge existing trees with our new one to copy */
COPY_REPLACE = 0x4, /* replace an existing file if there's one */
} CopyFlags;
int copy_file_fd(const char *from, int to, CopyFlags copy_flags);
int copy_file(const char *from, const char *to, int open_flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags);
int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags);
int copy_tree(const char *from, const char *to, CopyFlags copy_flags);
int copy_tree_at(int fdf, const char *from, int fdt, const char *to, CopyFlags copy_flags);
int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags);
int copy_directory(const char *from, const char *to, CopyFlags copy_flags);
int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags copy_flags);
int copy_times(int fdf, int fdt);
int copy_xattr(int fdf, int fdt);

View File

@ -1340,11 +1340,11 @@ static int usbffs_write_descs(int fd, Service *s) {
if (!s->usb_function_descriptors || !s->usb_function_strings)
return -EINVAL;
r = copy_file_fd(s->usb_function_descriptors, fd, false);
r = copy_file_fd(s->usb_function_descriptors, fd, 0);
if (r < 0)
return r;
return copy_file_fd(s->usb_function_strings, fd, false);
return copy_file_fd(s->usb_function_strings, fd, 0);
}
static int usbffs_select_ep(const struct dirent *d) {

View File

@ -352,7 +352,7 @@ static int save_external_coredump(
if (fd < 0)
return log_error_errno(fd, "Failed to create temporary file for coredump %s: %m", fn);
r = copy_bytes(input_fd, fd, max_size, false);
r = copy_bytes(input_fd, fd, max_size, 0);
if (r < 0) {
log_error_errno(r, "Cannot store coredump of %s (%s): %m", context[CONTEXT_PID], context[CONTEXT_COMM]);
goto fail;

View File

@ -252,7 +252,7 @@ static int process_locale(void) {
if (arg_copy_locale && arg_root) {
mkdir_parents(etc_localeconf, 0755);
r = copy_file("/etc/locale.conf", etc_localeconf, 0, 0644, 0);
r = copy_file("/etc/locale.conf", etc_localeconf, 0, 0644, 0, COPY_REFLINK);
if (r != -ENOENT) {
if (r < 0)
return log_error_errno(r, "Failed to copy %s: %m", etc_localeconf);

View File

@ -315,7 +315,7 @@ static int raw_pull_copy_auxiliary_file(
local = strjoina(i->image_root, "/", i->local, suffix);
r = copy_file_atomic(*path, local, 0644, i->force_local, 0);
r = copy_file_atomic(*path, local, 0644, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0));
if (r == -EEXIST)
log_warning_errno(r, "File %s already exists, not replacing.", local);
else if (r == -ENOENT)
@ -378,7 +378,7 @@ static int raw_pull_make_local_copy(RawPull *i) {
if (r < 0)
log_warning_errno(r, "Failed to set file attributes on %s: %m", tp);
r = copy_bytes(i->raw_job->disk_fd, dfd, (uint64_t) -1, true);
r = copy_bytes(i->raw_job->disk_fd, dfd, (uint64_t) -1, COPY_REFLINK);
if (r < 0) {
unlink(tp);
return log_error_errno(r, "Failed to make writable copy of image: %m");

View File

@ -256,7 +256,7 @@ static int tar_pull_make_local_copy(TarPull *i) {
local_settings = strjoina(i->image_root, "/", i->local, ".nspawn");
r = copy_file_atomic(i->settings_path, local_settings, 0664, i->force_local, 0);
r = copy_file_atomic(i->settings_path, local_settings, 0664, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0));
if (r == -EEXIST)
log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings);
else if (r == -ENOENT)

View File

@ -374,7 +374,7 @@ static int raw_image_get_os_release(Image *image, char ***ret, sd_bus_error *err
if (fd < 0)
_exit(EXIT_FAILURE);
r = copy_bytes(fd, pair[1], (uint64_t) -1, false);
r = copy_bytes(fd, pair[1], (uint64_t) -1, 0);
if (r < 0)
_exit(EXIT_FAILURE);

View File

@ -411,7 +411,7 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
if (fd < 0)
_exit(EXIT_FAILURE);
r = copy_bytes(fd, pair[1], (uint64_t) -1, false);
r = copy_bytes(fd, pair[1], (uint64_t) -1, 0);
if (r < 0)
_exit(EXIT_FAILURE);
@ -1152,9 +1152,9 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
}
if (copy_from)
r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, COPY_REFLINK|COPY_MERGE);
else
r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, COPY_REFLINK|COPY_MERGE);
hostfd = safe_close(hostfd);
containerfd = safe_close(containerfd);

View File

@ -1364,7 +1364,7 @@ static int setup_resolv_conf(const char *dest) {
}
/* If that didn't work, let's copy the file */
r = copy_file("/etc/resolv.conf", where, O_TRUNC|O_NOFOLLOW, 0644, 0);
r = copy_file("/etc/resolv.conf", where, O_TRUNC|O_NOFOLLOW, 0644, 0, COPY_REFLINK);
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.
@ -3700,7 +3700,7 @@ int main(int argc, char *argv[]) {
goto finish;
}
r = copy_file(arg_image, np, O_EXCL, arg_read_only ? 0400 : 0600, FS_NOCOW_FL);
r = copy_file(arg_image, np, O_EXCL, arg_read_only ? 0400 : 0600, FS_NOCOW_FL, COPY_REFLINK);
if (r < 0) {
r = log_error_errno(r, "Failed to copy image file: %m");
goto finish;
@ -3856,7 +3856,7 @@ finish:
/* Try to flush whatever is still queued in the pty */
if (master >= 0) {
(void) copy_bytes(master, STDOUT_FILENO, (uint64_t) -1, false);
(void) copy_bytes(master, STDOUT_FILENO, (uint64_t) -1, 0);
master = safe_close(master);
}

View File

@ -594,7 +594,7 @@ static int clone_auxiliary_file(const char *path, const char *new_name, const ch
if (!rs)
return -ENOMEM;
return copy_file_atomic(path, rs, 0664, false, 0);
return copy_file_atomic(path, rs, 0664, 0, COPY_REFLINK);
}
int image_clone(Image *i, const char *new_name, bool read_only) {
@ -656,7 +656,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
case IMAGE_RAW:
new_path = strjoina("/var/lib/machines/", new_name, ".raw");
r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, false, FS_NOCOW_FL);
r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, FS_NOCOW_FL, COPY_REFLINK);
break;
default:

View File

@ -44,7 +44,7 @@ static pid_t pager_pid = 0;
noreturn static void pager_fallback(void) {
int r;
r = copy_bytes(STDIN_FILENO, STDOUT_FILENO, (uint64_t) -1, false);
r = copy_bytes(STDIN_FILENO, STDOUT_FILENO, (uint64_t) -1, 0);
if (r < 0) {
log_error_errno(r, "Internal pager failed: %m");
_exit(EXIT_FAILURE);

View File

@ -5300,7 +5300,7 @@ static int cat_file(const char *filename, bool newline) {
ansi_normal());
fflush(stdout);
return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, false);
return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, 0);
}
static int cat(int argc, char *argv[], void *userdata) {
@ -6582,7 +6582,7 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
if (r < 0)
return log_error_errno(r, "Failed to create directories for \"%s\": %m", new_path);
r = copy_file(original_path, t, 0, 0644, 0);
r = copy_file(original_path, t, 0, 0644, 0, COPY_REFLINK);
if (r == -ENOENT) {
r = touch(t);

View File

@ -211,7 +211,7 @@ static int make_backup(const char *target, const char *x) {
if (r < 0)
return r;
r = copy_bytes(src, fileno(dst), (uint64_t) -1, true);
r = copy_bytes(src, fileno(dst), (uint64_t) -1, COPY_REFLINK);
if (r < 0)
goto fail;

View File

@ -52,7 +52,7 @@ static void test_copy_file(void) {
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, 0) == 0);
assert_se(copy_file(fn, fn_copy, 0, 0644, 0, COPY_REFLINK) == 0);
assert_se(read_full_file(fn_copy, &buf, &sz) == 0);
assert_se(streq(buf, "foo bar bar bar foo\n"));
@ -77,8 +77,8 @@ static void test_copy_file_fd(void) {
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, true) < 0);
assert_se(copy_file_fd(in_fn, out_fd, true) >= 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(lseek(out_fd, SEEK_SET, 0) == 0);
assert_se(read(out_fd, buf, sizeof(buf)) == sizeof(text) - 1);
@ -125,7 +125,7 @@ static void test_copy_tree(void) {
unixsockp = strjoina(original_dir, "unixsock");
assert_se(mknod(unixsockp, S_IFSOCK|0644, 0) >= 0);
assert_se(copy_tree(original_dir, copy_dir, true) == 0);
assert_se(copy_tree(original_dir, copy_dir, COPY_REFLINK|COPY_MERGE) == 0);
STRV_FOREACH(p, files) {
_cleanup_free_ char *buf = NULL, *f;
@ -152,8 +152,8 @@ static void test_copy_tree(void) {
assert_se(stat(unixsockp, &st) >= 0);
assert_se(S_ISSOCK(st.st_mode));
assert_se(copy_tree(original_dir, copy_dir, false) < 0);
assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, false) < 0);
assert_se(copy_tree(original_dir, copy_dir, COPY_REFLINK) < 0);
assert_se(copy_tree("/tmp/inexistent/foo/bar/fsdoi", copy_dir, COPY_REFLINK) < 0);
(void) rm_rf(copy_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
(void) rm_rf(original_dir, REMOVE_ROOT|REMOVE_PHYSICAL);
@ -172,7 +172,7 @@ static void test_copy_bytes(void) {
assert_se(pipe2(pipefd, O_CLOEXEC) == 0);
r = copy_bytes(infd, pipefd[1], (uint64_t) -1, false);
r = copy_bytes(infd, pipefd[1], (uint64_t) -1, 0);
assert_se(r == 0);
r = read(pipefd[0], buf, sizeof(buf));
@ -185,13 +185,13 @@ static void test_copy_bytes(void) {
assert_se(strneq(buf, buf2, r));
/* test copy_bytes with invalid descriptors */
r = copy_bytes(pipefd[0], pipefd[0], 1, false);
r = copy_bytes(pipefd[0], pipefd[0], 1, 0);
assert_se(r == -EBADF);
r = copy_bytes(pipefd[1], pipefd[1], 1, false);
r = copy_bytes(pipefd[1], pipefd[1], 1, 0);
assert_se(r == -EBADF);
r = copy_bytes(pipefd[1], infd, 1, false);
r = copy_bytes(pipefd[1], infd, 1, 0);
assert_se(r == -EBADF);
}
@ -213,7 +213,7 @@ static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint
fd3 = mkostemp_safe(fn3);
assert_se(fd3 >= 0);
r = copy_bytes(fd, fd2, max_bytes, try_reflink);
r = copy_bytes(fd, fd2, max_bytes, try_reflink ? COPY_REFLINK : 0);
if (max_bytes == (uint64_t) -1)
assert_se(r == 0);
else
@ -221,7 +221,7 @@ static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint
assert_se(lseek(fd2, 0, SEEK_SET) == 0);
r = copy_bytes(fd2, fd3, max_bytes, try_reflink);
r = copy_bytes(fd2, fd3, max_bytes, try_reflink ? COPY_REFLINK : 0);
if (max_bytes == (uint64_t) -1)
assert_se(r == 0);
else

View File

@ -1170,7 +1170,7 @@ static int create_item(Item *i) {
return log_error_errno(r, "Failed to substitute specifiers in copy source %s: %m", i->argument);
log_debug("Copying tree \"%s\" to \"%s\".", resolved, i->path);
r = copy_tree(resolved, i->path, false);
r = copy_tree(resolved, i->path, COPY_REFLINK);
if (r == -EROFS && stat(i->path, &st) == 0)
r = -EEXIST;