[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
- [PATCH 1/2] copy-file-range: new module, Paul Eggert, 2019/06/05
- [PATCH 2/2] copy-file: prefer copy_file_range,
Paul Eggert <=
- Re: [PATCH 1/2] copy-file-range: new module, Florian Weimer, 2019/06/05
- Re: [PATCH 1/2] copy-file-range: new module, Bruno Haible, 2019/06/05
- Re: [PATCH 1/2] copy-file-range: new module, Paul Eggert, 2019/06/07
- Re: [PATCH 1/2] copy-file-range: new module, Pádraig Brady, 2019/06/28
- Re: [PATCH 1/2] copy-file-range: new module, Bruno Haible, 2019/06/28
- Re: [PATCH 1/2] copy-file-range: new module, Florian Weimer, 2019/06/28
- Re: [PATCH 1/2] copy-file-range: new module, Bruno Haible, 2019/06/28