chiark / gitweb /
nspawn: allow spawning ephemeral nspawn containers based on the root file system...
[elogind.git] / src / shared / copy.c
index f22a9409918a84c0eb3fb28f94db26077b844615..b4a85c7bff0a12f76835a7cce3f867be37951b30 100644 (file)
 #include "btrfs-util.h"
 #include "copy.h"
 
-int copy_bytes(int fdf, int fdt, off_t max_bytes) {
+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;
                 ssize_t n;
@@ -64,7 +72,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 +79,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 +131,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;
@@ -312,7 +318,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 +328,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 +341,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);