diff options
Diffstat (limited to 'src/basic/copy.c')
-rw-r--r-- | src/basic/copy.c | 128 |
1 files changed, 99 insertions, 29 deletions
diff --git a/src/basic/copy.c b/src/basic/copy.c index e06a503a29..34e01ea1cf 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -19,15 +19,15 @@ #include "copy.h" #include "dirent-util.h" #include "fd-util.h" -#include "fileio.h" #include "fs-util.h" #include "io-util.h" #include "macro.h" #include "missing.h" -#include "mount-util.h" +#include "mountpoint-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" +#include "tmpfile-util.h" #include "umask-util.h" #include "user-util.h" #include "xattr-util.h" @@ -43,7 +43,7 @@ static ssize_t try_copy_file_range( int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, size_t len, - unsigned int flags) { + unsigned flags) { static int have = -1; ssize_t r; @@ -90,7 +90,9 @@ int copy_bytes_full( uint64_t max_bytes, CopyFlags copy_flags, void **ret_remains, - size_t *ret_remains_size) { + size_t *ret_remains_size, + copy_progress_bytes_t progress, + void *userdata) { bool try_cfr = true, try_sendfile = true, try_splice = true; int r, nonblock_pipe = -1; @@ -161,8 +163,6 @@ int copy_bytes_full( return 1; /* we copied only some number of bytes, which worked, but this means we didn't hit EOF, return 1 */ } } - - log_debug_errno(r, "Reflinking didn't work, falling back to non-reflink copying: %m"); } } } @@ -308,10 +308,17 @@ int copy_bytes_full( } next: + if (progress) { + r = progress(n, userdata); + if (r < 0) + return r; + } + if (max_bytes != (uint64_t) -1) { assert(max_bytes >= (uint64_t) n); max_bytes -= n; } + /* sendfile accepts at most SSIZE_MAX-offset bytes to copy, * so reduce our maximum by the amount we already copied, * but don't go below our copy buffer size, unless we are @@ -363,7 +370,9 @@ static int fd_copy_regular( const char *to, uid_t override_uid, gid_t override_gid, - CopyFlags copy_flags) { + CopyFlags copy_flags, + copy_progress_bytes_t progress, + void *userdata) { _cleanup_close_ int fdf = -1, fdt = -1; struct timespec ts[2]; @@ -381,7 +390,7 @@ static int fd_copy_regular( if (fdt < 0) return -errno; - r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags); + r = copy_bytes_full(fdf, fdt, (uint64_t) -1, copy_flags, NULL, NULL, progress, userdata); if (r < 0) { (void) unlinkat(dt, to, 0); return r; @@ -483,7 +492,11 @@ static int fd_copy_directory( unsigned depth_left, uid_t override_uid, gid_t override_gid, - CopyFlags copy_flags) { + CopyFlags copy_flags, + const char *display_path, + copy_progress_path_t progress_path, + copy_progress_bytes_t progress_bytes, + void *userdata) { _cleanup_close_ int fdf = -1, fdt = -1; _cleanup_closedir_ DIR *d = NULL; @@ -524,6 +537,8 @@ static int fd_copy_directory( r = 0; FOREACH_DIRENT_ALL(de, d, return -errno) { + const char *child_display_path = NULL; + _cleanup_free_ char *dp = NULL; struct stat buf; int q; @@ -535,6 +550,17 @@ static int fd_copy_directory( continue; } + if (progress_path) { + if (display_path) + child_display_path = dp = strjoin(display_path, "/", de->d_name); + else + child_display_path = de->d_name; + + r = progress_path(child_display_path, &buf, userdata); + if (r < 0) + return r; + } + if (S_ISDIR(buf.st_mode)) { /* * Don't descend into directories on other file systems, if this is requested. We do a simple @@ -566,9 +592,9 @@ static int fd_copy_directory( continue; } - q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, depth_left-1, override_uid, override_gid, copy_flags); + q = fd_copy_directory(dirfd(d), de->d_name, &buf, fdt, de->d_name, original_device, depth_left-1, override_uid, override_gid, copy_flags, child_display_path, progress_path, progress_bytes, userdata); } else if (S_ISREG(buf.st_mode)) - q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); + q = fd_copy_regular(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags, progress_bytes, userdata); else if (S_ISLNK(buf.st_mode)) q = fd_copy_symlink(dirfd(d), de->d_name, &buf, fdt, de->d_name, override_uid, override_gid, copy_flags); else if (S_ISFIFO(buf.st_mode)) @@ -606,7 +632,18 @@ static int fd_copy_directory( return r; } -int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) { +int copy_tree_at_full( + int fdf, + const char *from, + int fdt, + const char *to, + uid_t override_uid, + gid_t override_gid, + CopyFlags copy_flags, + copy_progress_path_t progress_path, + copy_progress_bytes_t progress_bytes, + void *userdata) { + struct stat st; assert(from); @@ -616,9 +653,9 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t overr return -errno; if (S_ISREG(st.st_mode)) - return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); + return fd_copy_regular(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags, progress_bytes, userdata); else if (S_ISDIR(st.st_mode)) - return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags); + return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, COPY_DEPTH_MAX, override_uid, override_gid, copy_flags, NULL, progress_path, progress_bytes, userdata); else if (S_ISLNK(st.st_mode)) return fd_copy_symlink(fdf, from, &st, fdt, to, override_uid, override_gid, copy_flags); else if (S_ISFIFO(st.st_mode)) @@ -629,11 +666,14 @@ int copy_tree_at(int fdf, const char *from, int fdt, const char *to, uid_t overr return -EOPNOTSUPP; } -int copy_tree(const char *from, const char *to, uid_t override_uid, gid_t override_gid, CopyFlags copy_flags) { - return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, override_uid, override_gid, copy_flags); -} +int copy_directory_fd_full( + int dirfd, + const char *to, + CopyFlags copy_flags, + copy_progress_path_t progress_path, + copy_progress_bytes_t progress_bytes, + void *userdata) { -int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) { struct stat st; assert(dirfd >= 0); @@ -645,10 +685,17 @@ int copy_directory_fd(int dirfd, const char *to, CopyFlags copy_flags) { if (!S_ISDIR(st.st_mode)) return -ENOTDIR; - return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags); + return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, progress_path, progress_bytes, userdata); } -int copy_directory(const char *from, const char *to, CopyFlags copy_flags) { +int copy_directory_full( + const char *from, + const char *to, + CopyFlags copy_flags, + copy_progress_path_t progress_path, + copy_progress_bytes_t progress_bytes, + void *userdata) { + struct stat st; assert(from); @@ -660,10 +707,16 @@ int copy_directory(const char *from, const char *to, CopyFlags copy_flags) { if (!S_ISDIR(st.st_mode)) return -ENOTDIR; - return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags); + return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, progress_path, progress_bytes, userdata); } -int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) { +int copy_file_fd_full( + const char *from, + int fdt, + CopyFlags copy_flags, + copy_progress_bytes_t progress_bytes, + void *userdata) { + _cleanup_close_ int fdf = -1; int r; @@ -674,7 +727,7 @@ int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) { if (fdf < 0) return -errno; - r = copy_bytes(fdf, fdt, (uint64_t) -1, copy_flags); + r = copy_bytes_full(fdf, fdt, (uint64_t) -1, copy_flags, NULL, NULL, progress_bytes, userdata); (void) copy_times(fdf, fdt); (void) copy_xattr(fdf, fdt); @@ -682,7 +735,16 @@ int copy_file_fd(const char *from, int fdt, CopyFlags copy_flags) { return r; } -int copy_file(const char *from, const char *to, int flags, mode_t mode, unsigned chattr_flags, CopyFlags copy_flags) { +int copy_file_full( + const char *from, + const char *to, + int flags, + mode_t mode, + unsigned chattr_flags, + CopyFlags copy_flags, + copy_progress_bytes_t progress_bytes, + void *userdata) { + int fdt = -1, r; assert(from); @@ -695,9 +757,9 @@ 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); + (void) chattr_fd(fdt, chattr_flags, (unsigned) -1, NULL); - r = copy_file_fd(from, fdt, copy_flags); + r = copy_file_fd_full(from, fdt, copy_flags, progress_bytes, userdata); if (r < 0) { close(fdt); (void) unlink(to); @@ -712,7 +774,15 @@ 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, unsigned chattr_flags, CopyFlags copy_flags) { +int copy_file_atomic_full( + const char *from, + const char *to, + mode_t mode, + unsigned chattr_flags, + CopyFlags copy_flags, + copy_progress_bytes_t progress_bytes, + void *userdata) { + _cleanup_(unlink_and_freep) char *t = NULL; _cleanup_close_ int fdt = -1; int r; @@ -743,9 +813,9 @@ int copy_file_atomic(const char *from, const char *to, mode_t mode, unsigned cha } if (chattr_flags != 0) - (void) chattr_fd(fdt, chattr_flags, (unsigned) -1); + (void) chattr_fd(fdt, chattr_flags, (unsigned) -1, NULL); - r = copy_file_fd(from, fdt, copy_flags); + r = copy_file_fd_full(from, fdt, copy_flags, progress_bytes, userdata); if (r < 0) return r; |