]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
ul_copy_file: use sendfile
authorEgor Chelak <egor.chelak@gmail.com>
Fri, 6 Nov 2020 09:15:11 +0000 (11:15 +0200)
committerEgor Chelak <egor.chelak@gmail.com>
Mon, 9 Nov 2020 05:18:49 +0000 (07:18 +0200)
Suggested-by: Karel Zak <kzak@redhat.com>
Reviewed-by: Sami Kerola <kerolasa@iki.fi>
Signed-off-by: Egor Chelak <egor.chelak@gmail.com>
lib/fileutils.c

index 9e0823d30eeeed8b18e2c8cadb538cffb1a4bd03..557fae0414a972e7b019dd7c394d0b593242a6ec 100644 (file)
@@ -6,10 +6,12 @@
  */
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 #include <sys/time.h>
 #include <sys/resource.h>
+#include <sys/sendfile.h>
 #include <string.h>
 
 #include "c.h"
@@ -248,8 +250,7 @@ char *stripoff_last_component(char *path)
        return p + 1;
 }
 
-/* Copies the contents of a file. Returns -1 on read error, -2 on write error. */
-int ul_copy_file(int from, int to)
+static int copy_file_simple(int from, int to)
 {
        ssize_t nr, nw, off;
        char buf[8 * 1024];
@@ -265,3 +266,28 @@ int ul_copy_file(int from, int to)
 #endif
        return 0;
 }
+
+/* Copies the contents of a file. Returns -1 on read error, -2 on write error. */
+int ul_copy_file(int from, int to)
+{
+       struct stat st;
+       ssize_t nw;
+       off_t left;
+
+       if (fstat(from, &st) == -1)
+               return -1;
+       if (!S_ISREG(st.st_mode))
+               return copy_file_simple(from, to);
+       for (left = st.st_size; left != 0; left -= nw) {
+               if ((nw = sendfile(to, from, NULL, left)) < 0)
+                       return copy_file_simple(from, to);
+               if (!nw)
+                       return 0;
+       }
+       /* For extra robustness, treat st_size as advisory and ensure that we
+        * actually get EOF. */
+       while ((nw = sendfile(to, from, NULL, 1024*1024)) != 0)
+               if (nw < 0)
+                       return copy_file_simple(from, to);
+       return 0;
+}