X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fshared%2Fcopy.c;h=0c2cdc8d9490793d94730904621eae0ad412736f;hb=540d8581834442ca1c8f79fa35e4b91c0ab51567;hp=f22a9409918a84c0eb3fb28f94db26077b844615;hpb=d7c7c334f56edab8cfc102b657366277a65738cf;p=elogind.git diff --git a/src/shared/copy.c b/src/shared/copy.c index f22a94099..0c2cdc8d9 100644 --- a/src/shared/copy.c +++ b/src/shared/copy.c @@ -25,14 +25,24 @@ #include "btrfs-util.h" #include "copy.h" -int copy_bytes(int fdf, int fdt, off_t max_bytes) { +#define COPY_BUFFER_SIZE (16*1024) + +int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) { bool try_sendfile = true; + int r; assert(fdf >= 0); assert(fdt >= 0); + /* Try btrfs reflinks first. */ + if (try_reflink && max_bytes == (off_t) -1) { + r = btrfs_reflink(fdf, fdt); + if (r >= 0) + return r; + } + for (;;) { - size_t m = PIPE_BUF; + size_t m = COPY_BUFFER_SIZE; ssize_t n; if (max_bytes != (off_t) -1) { @@ -64,7 +74,6 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes) { /* As a fallback just copy bits by hand */ { char buf[m]; - int r; n = read(fdf, buf, m); if (n < 0) @@ -72,10 +81,9 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes) { if (n == 0) /* EOF */ break; - r = loop_write(fdt, buf, n, false); + r = loop_write(fdt, buf, (size_t) n, false); if (r < 0) return r; - } next: @@ -125,7 +133,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, (off_t) -1); + r = copy_bytes(fdf, fdt, (off_t) -1, true); if (r < 0) { unlinkat(dt, to, 0); return r; @@ -273,30 +281,34 @@ static int fd_copy_directory( return r; } -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) { struct stat st; assert(from); assert(to); - if (lstat(from, &st) < 0) + if (fstatat(fdf, from, &st, AT_SYMLINK_NOFOLLOW) < 0) return -errno; if (S_ISREG(st.st_mode)) - return fd_copy_regular(AT_FDCWD, from, &st, AT_FDCWD, to); + return fd_copy_regular(fdf, from, &st, fdt, to); else if (S_ISDIR(st.st_mode)) - return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, merge); + return fd_copy_directory(fdf, from, &st, fdt, to, st.st_dev, merge); else if (S_ISLNK(st.st_mode)) - return fd_copy_symlink(AT_FDCWD, from, &st, AT_FDCWD, to); + return fd_copy_symlink(fdf, from, &st, fdt, to); else if (S_ISFIFO(st.st_mode)) - return fd_copy_fifo(AT_FDCWD, from, &st, AT_FDCWD, to); + return fd_copy_fifo(fdf, from, &st, fdt, to); else if (S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode)) - return fd_copy_node(AT_FDCWD, from, &st, AT_FDCWD, to); + return fd_copy_node(fdf, from, &st, fdt, to); else return -ENOTSUP; } -int copy_tree_fd(int dirfd, const char *to, bool merge) { +int copy_tree(const char *from, const char *to, bool merge) { + return copy_tree_at(AT_FDCWD, from, AT_FDCWD, to, merge); +} + +int copy_directory_fd(int dirfd, const char *to, bool merge) { struct stat st; @@ -312,7 +324,7 @@ int copy_tree_fd(int dirfd, const char *to, bool merge) { return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, merge); } -int copy_file_fd(const char *from, int fdt) { +int copy_file_fd(const char *from, int fdt, bool try_reflink) { _cleanup_close_ int fdf = -1; assert(from); @@ -322,7 +334,7 @@ int copy_file_fd(const char *from, int fdt) { if (fdf < 0) return -errno; - return copy_bytes(fdf, fdt, (off_t) -1); + return copy_bytes(fdf, fdt, (off_t) -1, try_reflink); } int copy_file(const char *from, const char *to, int flags, mode_t mode) { @@ -335,7 +347,7 @@ int copy_file(const char *from, const char *to, int flags, mode_t mode) { if (fdt < 0) return -errno; - r = copy_file_fd(from, fdt); + r = copy_file_fd(from, fdt, true); if (r < 0) { close(fdt); unlink(to);