]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/basic/copy.c
util-lib: split our string related calls from util.[ch] into its own file string...
[thirdparty/systemd.git] / src / basic / copy.c
index e2d356d67656197ac2daa9df5d4a636fe1ba6045..7702d906c778edce41efa37e819d6e65b7d0726c 100644 (file)
 #include <sys/sendfile.h>
 #include <sys/xattr.h>
 
-#include "util.h"
 #include "btrfs-util.h"
+#include "string-util.h"
 #include "strv.h"
+#include "util.h"
 #include "copy.h"
 
 #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 copy_bytes(int fdf, int fdt, uint64_t max_bytes, bool try_reflink) {
+        bool try_sendfile = true, try_splice = true;
         int r;
 
         assert(fdf >= 0);
         assert(fdt >= 0);
 
         /* Try btrfs reflinks first. */
-        if (try_reflink && max_bytes == (off_t) -1) {
+        if (try_reflink &&
+            max_bytes == (uint64_t) -1 &&
+            lseek(fdf, 0, SEEK_CUR) == 0 &&
+            lseek(fdt, 0, SEEK_CUR) == 0) {
+
                 r = btrfs_reflink(fdf, fdt);
                 if (r >= 0)
-                        return r;
+                        return 0; /* we copied the whole thing, hence hit EOF, return 0 */
         }
 
         for (;;) {
                 size_t m = COPY_BUFFER_SIZE;
                 ssize_t n;
 
-                if (max_bytes != (off_t) -1) {
+                if (max_bytes != (uint64_t) -1) {
 
                         if (max_bytes <= 0)
-                                return -EFBIG;
+                                return 1; /* return > 0 if we hit the max_bytes limit */
 
-                        if ((off_t) m > max_bytes)
+                        if ((uint64_t) m > max_bytes)
                                 m = (size_t) max_bytes;
                 }
 
@@ -69,13 +74,29 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) {
                         } else if (n == 0) /* EOF */
                                 break;
                         else if (n > 0)
-                                /* Succcess! */
+                                /* Success! */
+                                goto next;
+                }
+
+                /* The try splice, unless we already tried */
+                if (try_splice) {
+                        n = splice(fdf, NULL, fdt, NULL, m, 0);
+                        if (n < 0) {
+                                if (errno != EINVAL && errno != ENOSYS)
+                                        return -errno;
+
+                                try_splice = false;
+                                /* use fallback below */
+                        } else if (n == 0) /* EOF */
+                                break;
+                        else if (n > 0)
+                                /* Success! */
                                 goto next;
                 }
 
                 /* As a fallback just copy bits by hand */
                 {
-                        char buf[m];
+                        uint8_t buf[m];
 
                         n = read(fdf, buf, m);
                         if (n < 0)
@@ -89,13 +110,13 @@ int copy_bytes(int fdf, int fdt, off_t max_bytes, bool try_reflink) {
                 }
 
         next:
-                if (max_bytes != (off_t) -1) {
-                        assert(max_bytes >= n);
+                if (max_bytes != (uint64_t) -1) {
+                        assert(max_bytes >= (uint64_t) n);
                         max_bytes -= n;
                 }
         }
 
-        return 0;
+        return 0; /* return 0 if we hit EOF earlier than the size limit */
 }
 
 static int fd_copy_symlink(int df, const char *from, const struct stat *st, int dt, const char *to) {
@@ -136,7 +157,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, true);
+        r = copy_bytes(fdf, fdt, (uint64_t) -1, true);
         if (r < 0) {
                 unlinkat(dt, to, 0);
                 return r;
@@ -355,7 +376,7 @@ int copy_file_fd(const char *from, int fdt, bool try_reflink) {
         if (fdf < 0)
                 return -errno;
 
-        r = copy_bytes(fdf, fdt, (off_t) -1, try_reflink);
+        r = copy_bytes(fdf, fdt, (uint64_t) -1, try_reflink);
 
         (void) copy_times(fdf, fdt);
         (void) copy_xattr(fdf, fdt);
@@ -467,8 +488,7 @@ int copy_xattr(int fdf, int fdt) {
 
                 sza *= 2;
 
-                free(bufa);
-                bufa = NULL;
+                bufa = mfree(bufa);
         }
 
         p = bufa;
@@ -491,8 +511,7 @@ int copy_xattr(int fdf, int fdt) {
                         if (m < 0) {
                                 if (errno == ERANGE) {
                                         szb *= 2;
-                                        free(bufb);
-                                        bufb = NULL;
+                                        bufb = mfree(bufb);
                                         continue;
                                 }