bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 2/2] copy-file: prefer copy_file_range


From: Paul Eggert
Subject: [PATCH 2/2] copy-file: prefer copy_file_range
Date: Tue, 4 Jun 2019 23:09:17 -0700

* lib/copy-file.c: Do not include xalloc.h.
(qcopy_file_preserving): Allocate a buffer only if
copy_file_range does not suffice.  If the allocation fails
don't give up; just use a small stack-based buffer.
Prefer copy_file_range if it works.
* modules/copy-file (Depends-on): Add copy-file-range.
Remove xalloc.
---
 ChangeLog         |  9 ++++++
 lib/copy-file.c   | 76 ++++++++++++++++++++++++++++-------------------
 modules/copy-file |  2 +-
 3 files changed, 56 insertions(+), 31 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 9ff35e9c1..ac9a44652 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2019-06-04  Paul Eggert  <address@hidden>
 
+       copy-file: prefer copy_file_range
+       * lib/copy-file.c: Do not include xalloc.h.
+       (qcopy_file_preserving): Allocate a buffer only if
+       copy_file_range does not suffice.  If the allocation fails
+       don't give up; just use a small stack-based buffer.
+       Prefer copy_file_range if it works.
+       * modules/copy-file (Depends-on): Add copy-file-range.
+       Remove xalloc.
+
        copy-file-range: new module
        * MODULES.html.sh: Add copy-file-range.
        * lib/copy-file-range.c, m4/copy-file-range.m4:
diff --git a/lib/copy-file.c b/lib/copy-file.c
index 2ba344b97..092a040d7 100644
--- a/lib/copy-file.c
+++ b/lib/copy-file.c
@@ -38,7 +38,6 @@
 #include "binary-io.h"
 #include "quote.h"
 #include "gettext.h"
-#include "xalloc.h"
 
 #define _(str) gettext (str)
 
@@ -52,14 +51,10 @@ qcopy_file_preserving (const char *src_filename, const char 
*dest_filename)
   struct stat statbuf;
   int mode;
   int dest_fd;
-  char *buf = xmalloc (IO_SIZE);
 
   src_fd = open (src_filename, O_RDONLY | O_BINARY);
   if (src_fd < 0)
-    {
-      err = GL_COPY_ERR_OPEN_READ;
-      goto error;
-    }
+    return GL_COPY_ERR_OPEN_READ;
   if (fstat (src_fd, &statbuf) < 0)
     {
       err = GL_COPY_ERR_OPEN_READ;
@@ -67,6 +62,8 @@ qcopy_file_preserving (const char *src_filename, const char 
*dest_filename)
     }
 
   mode = statbuf.st_mode & 07777;
+  off_t inbytes = S_ISREG (statbuf.st_mode) ? statbuf.st_size : -1;
+  bool empty_regular_file = inbytes == 0;
 
   dest_fd = open (dest_filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 
0600);
   if (dest_fd < 0)
@@ -75,27 +72,53 @@ qcopy_file_preserving (const char *src_filename, const char 
*dest_filename)
       goto error_src;
     }
 
-  /* Copy the file contents.  */
-  for (;;)
+  /* Copy the file contents.  FIXME: Do not copy holes.  */
+  while (0 < inbytes)
     {
-      size_t n_read = safe_read (src_fd, buf, IO_SIZE);
-      if (n_read == SAFE_READ_ERROR)
-        {
-          err = GL_COPY_ERR_READ;
-          goto error_src_dest;
-        }
-      if (n_read == 0)
+      size_t copy_max = -1;
+      copy_max -= copy_max % IO_SIZE;
+      size_t len = inbytes < copy_max ? inbytes : copy_max;
+      ssize_t copied = copy_file_range (src_fd, NULL, dest_fd, NULL, len, 0);
+      if (copied <= 0)
         break;
+      inbytes -= copied;
+    }
+
+  /* Finish up with read/write, in case the file was not a regular
+     file, or the file shrank or had I/O errors (in which case find
+     whether it was a read or write error).  Read empty regular files
+     since they might be in /proc with their true sizes unknown until
+     they are read.  */
+  if (inbytes != 0 || empty_regular_file)
+    {
+      char smallbuf[1024];
+      int bufsize = IO_SIZE;
+      char *buf = malloc (bufsize);
+      if (!buf)
+        buf = smallbuf, bufsize = sizeof smallbuf;
 
-      if (full_write (dest_fd, buf, n_read) < n_read)
+      while (true)
         {
-          err = GL_COPY_ERR_WRITE;
-          goto error_src_dest;
+          size_t n_read = safe_read (src_fd, buf, bufsize);
+          if (n_read == 0)
+            break;
+          if (n_read == SAFE_READ_ERROR)
+            {
+              err = GL_COPY_ERR_READ;
+              break;
+            }
+          if (full_write (dest_fd, buf, n_read) < n_read)
+            {
+              err = GL_COPY_ERR_WRITE;
+              break;
+            }
         }
-    }
 
-  free (buf);
-  buf = NULL; /* To avoid double free in error case.  */
+      if (buf != smallbuf)
+        free (buf);
+      if (err)
+        goto error_src_dest;
+    }
 
 #if !USE_ACL
   if (close (dest_fd) < 0)
@@ -104,10 +127,7 @@ qcopy_file_preserving (const char *src_filename, const 
char *dest_filename)
       goto error_src;
     }
   if (close (src_fd) < 0)
-    {
-      err = GL_COPY_ERR_AFTER_READ;
-      goto error;
-    }
+    return GL_COPY_ERR_AFTER_READ;
 #endif
 
   /* Preserve the access and modification times.  */
@@ -146,10 +166,7 @@ qcopy_file_preserving (const char *src_filename, const 
char *dest_filename)
       goto error_src;
     }
   if (close (src_fd) < 0)
-    {
-      err = GL_COPY_ERR_AFTER_READ;
-      goto error;
-    }
+    return GL_COPY_ERR_AFTER_READ;
 #endif
 
   return 0;
@@ -159,7 +176,6 @@ qcopy_file_preserving (const char *src_filename, const char 
*dest_filename)
  error_src:
   close (src_fd);
  error:
-  free (buf);
   return err;
 }
 
diff --git a/modules/copy-file b/modules/copy-file
index e1bda4973..bc1527757 100644
--- a/modules/copy-file
+++ b/modules/copy-file
@@ -10,6 +10,7 @@ Depends-on:
 acl
 binary-io
 close
+copy-file-range
 error
 fstat
 full-write
@@ -22,7 +23,6 @@ stat-time
 stdlib
 unistd
 utimens
-xalloc
 
 configure.ac:
 gl_COPY_FILE
-- 
2.17.1




reply via email to

[Prev in Thread] Current Thread [Next in Thread]