]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
ul_copy_file: handle EAGAIN and EINTR
authorEgor Chelak <egor.chelak@gmail.com>
Fri, 6 Nov 2020 18:33:46 +0000 (20:33 +0200)
committerEgor Chelak <egor.chelak@gmail.com>
Mon, 9 Nov 2020 05:19:39 +0000 (07:19 +0200)
I did this by implementing a function called sendfile_all() similar to
read_all()/write_all().

The manpage for sendfile doesn't mention EINTR, but I decided to check
it anyway, just in case.

Suggested-by: Karel Zak <kzak@redhat.com>
Reviewed-by: Sami Kerola <kerolasa@iki.fi>
Signed-off-by: Egor Chelak <egor.chelak@gmail.com>
include/all-io.h
lib/fileutils.c

index 8ffa9cfb110722d48493404b9035df3732c360e4..98745802c9089cd62d1d8691d038e5f8d1e8a436 100644 (file)
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
+#include <sys/types.h>
+#ifdef HAVE_SENDFILE
+#include <sys/sendfile.h>
+#endif
 
 #include "c.h"
 
@@ -78,4 +82,32 @@ static inline ssize_t read_all(int fd, char *buf, size_t count)
        return c;
 }
 
+static inline ssize_t sendfile_all(int out, int in, off_t *off, size_t count)
+{
+#ifdef HAVE_SENDFILE
+       ssize_t ret;
+       ssize_t c = 0;
+       int tries = 0;
+       while (count) {
+               ret = sendfile(out, in, off, count);
+               if (ret < 0) {
+                       if ((errno == EAGAIN || errno == EINTR) && (tries++ < 5)) {
+                               xusleep(250000);
+                               continue;
+                       }
+                       return c ? c : -1;
+               }
+               if (ret == 0)
+                       return c;
+               tries = 0;
+               count -= ret;
+               c += ret;
+       }
+       return c;
+#else
+       errno = ENOSYS;
+       return -1;
+#endif
+}
+
 #endif /* UTIL_LINUX_ALL_IO_H */
index 61304c77ea5f842da525233e3e4d1f33f515084e..a9c0e61c0fae713cef241b9587522a661e6eebfd 100644 (file)
@@ -11,9 +11,6 @@
 #include <unistd.h>
 #include <sys/time.h>
 #include <sys/resource.h>
-#ifdef HAVE_SENDFILE
-#include <sys/sendfile.h>
-#endif
 #include <string.h>
 
 #include "c.h"
@@ -275,21 +272,15 @@ int ul_copy_file(int from, int to)
 #ifdef HAVE_SENDFILE
        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 (sendfile_all(to, from, NULL, st.st_size) < 0)
+               return copy_file_simple(from, to);
+       /* ensure we either get an EOF or an error */
+       while ((nw = sendfile_all(to, from, NULL, 16*1024*1024)) != 0)
                if (nw < 0)
                        return copy_file_simple(from, to);
        return 0;