bug-gnulib@gnu.org mirror (unofficial)
 help / color / mirror / Atom feed
From: Paul Eggert <eggert@cs.ucla.edu>
To: bug-gnulib@gnu.org
Cc: Paul Eggert <eggert@cs.ucla.edu>
Subject: [PATCH 2/2] copy-file: prefer copy_file_range
Date: Tue,  4 Jun 2019 23:09:17 -0700	[thread overview]
Message-ID: <20190605060917.18349-2-eggert@cs.ucla.edu> (raw)
In-Reply-To: <20190605060917.18349-1-eggert@cs.ucla.edu>

* 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  <eggert@cs.ucla.edu>
 
+	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	other threads:[~2019-06-05  6:09 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-06-05  6:09 [PATCH 1/2] copy-file-range: new module Paul Eggert
2019-06-05  6:09 ` Paul Eggert [this message]
2019-06-05 13:54 ` Florian Weimer
2019-06-06  0:45   ` Bruno Haible
2019-06-07  8:04     ` Paul Eggert
2019-06-28 18:56       ` Pádraig Brady
2019-06-28 19:30         ` Bruno Haible
2019-06-28 20:18           ` Florian Weimer
2019-06-28 22:46             ` Bruno Haible

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://lists.gnu.org/mailman/listinfo/bug-gnulib

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20190605060917.18349-2-eggert@cs.ucla.edu \
    --to=eggert@cs.ucla.edu \
    --cc=bug-gnulib@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).