chiark / gitweb /
machinectl: add new commands for copying files from/to containers
[elogind.git] / src / shared / copy.c
index 4c41f2fdd4c24bb7dcf57ac300d7bfc88f23a84f..0c2cdc8d9490793d94730904621eae0ad412736f 100644 (file)
@@ -25,7 +25,9 @@
 #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;
 
@@ -33,14 +35,14 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes) {
         assert(fdt >= 0);
 
         /* Try btrfs reflinks first. */
-        if (max_bytes == (off_t) -1) {
+        if (try_reflink && max_bytes == (off_t) -1) {
                 r = btrfs_reflink(fdf, fdt);
                 if (r >= 0)
-                        return 0;
+                        return r;
         }
 
         for (;;) {
-                size_t m = PIPE_BUF;
+                size_t m = COPY_BUFFER_SIZE;
                 ssize_t n;
 
                 if (max_bytes != (off_t) -1) {
@@ -82,7 +84,6 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes) {
                         r = loop_write(fdt, buf, (size_t) n, false);
                         if (r < 0)
                                 return r;
-
                 }
 
         next:
@@ -132,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;
@@ -280,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;
 
@@ -319,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);
@@ -329,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) {
@@ -342,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);