From b0d998d2e04050dd3c65816b277cf0f91c9ca74c Mon Sep 17 00:00:00 2001
From: Paul Eggert
Date: Thu, 6 Jun 2019 15:44:33 -0700
Subject: [PATCH 1/2] copy-file-range: simplify into a stub
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Based on a comment by Florian Weimer in:
https://lists.gnu.org/r/bug-gnulib/2019-06/msg00007.html
It turns out that Emacs (which will use this module) won’t need an
emulation and I suspect other programs won’t either, because these
programs will need to fall back on read+write anyway. Perhaps I
am wrong and other programs will be able to use an emulation; if
so, this patch can be reverted.
* lib/copy-file-range.c (COPY_FILE_RANGE): Replace with a stub.
Just call it copy_file_range.
* m4/copy-file-range.m4 (gl_FUNC_COPY_FILE_RANGE):
Check via AC_LINK_IFELSE.
* modules/copy-file-range (Depends-on): Remove modules no longer used.
---
ChangeLog | 16 +++++
lib/copy-file-range.c | 152 +++-------------------------------------
m4/copy-file-range.m4 | 22 +++++-
modules/copy-file-range | 5 --
4 files changed, 46 insertions(+), 149 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index ac9a44652..5e51f2dbd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2019-06-06 Paul Eggert
+
+ copy-file-range: simplify into a stub
+ Based on a comment by Florian Weimer in:
+ https://lists.gnu.org/r/bug-gnulib/2019-06/msg00007.html
+ It turns out that Emacs (which will use this module) won’t need an
+ emulation and I suspect other programs won’t either, because these
+ programs will need to fall back on read+write anyway. Perhaps I
+ am wrong and other programs will be able to use an emulation; if
+ so, this patch can be reverted.
+ * lib/copy-file-range.c (COPY_FILE_RANGE): Replace with a stub.
+ Just call it copy_file_range.
+ * m4/copy-file-range.m4 (gl_FUNC_COPY_FILE_RANGE):
+ Check via AC_LINK_IFELSE.
+ * modules/copy-file-range (Depends-on): Remove modules no longer used.
+
2019-06-04 Paul Eggert
copy-file: prefer copy_file_range
diff --git a/lib/copy-file-range.c b/lib/copy-file-range.c
index a1448d0d9..39b5efbc1 100644
--- a/lib/copy-file-range.c
+++ b/lib/copy-file-range.c
@@ -1,5 +1,5 @@
-/* Emulation of copy_file_range.
- Copyright 2017-2019 Free Software Foundation, Inc.
+/* Stub for copy_file_range
+ Copyright 2019 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -14,152 +14,20 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see . */
-/* This file is adapted from glibc io/copy_file_range-compat.c, with a
- small number of changes to port to non-glibc platforms. */
+#include
-#include
-
-/* The following macros should be defined:
-
- COPY_FILE_RANGE_DECL Declaration specifiers for the function below.
- COPY_FILE_RANGE Name of the function to define. */
-
-#define COPY_FILE_RANGE_DECL
-#define COPY_FILE_RANGE copy_file_range
+#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
-COPY_FILE_RANGE_DECL
ssize_t
-COPY_FILE_RANGE (int infd, off_t *pinoff,
+copy_file_range (int infd, off_t *pinoff,
int outfd, off_t *poutoff,
size_t length, unsigned int flags)
{
- if (flags != 0)
- {
- __set_errno (EINVAL);
- return -1;
- }
-
- {
- struct stat instat;
- struct stat outstat;
- if (fstat (infd, &instat) != 0 || fstat (outfd, &outstat) != 0)
- return -1;
- if (S_ISDIR (instat.st_mode) || S_ISDIR (outstat.st_mode))
- {
- __set_errno (EISDIR);
- return -1;
- }
- if (!S_ISREG (instat.st_mode) || !S_ISREG (outstat.st_mode))
- {
- /* We need a regular input file so that the we can seek
- backwards in case of a write failure. */
- __set_errno (EINVAL);
- return -1;
- }
- if (instat.st_dev != outstat.st_dev)
- {
- /* Cross-device copies are not supported. */
- __set_errno (EXDEV);
- return -1;
- }
- }
-
- /* The output descriptor must not have O_APPEND set. */
- {
- int flags = fcntl (outfd, F_GETFL);
- if (flags & O_APPEND)
- {
- __set_errno (EBADF);
- return -1;
- }
- }
-
- /* Avoid an overflow in the result. */
- if (length > SSIZE_MAX)
- length = SSIZE_MAX;
-
- /* Main copying loop. The buffer size is arbitrary and is a
- trade-off between stack size consumption, cache usage, and
- amortization of system call overhead. */
- size_t copied = 0;
- char buf[8192];
- while (length > 0)
- {
- size_t to_read = length;
- if (to_read > sizeof (buf))
- to_read = sizeof (buf);
-
- /* Fill the buffer. */
- ssize_t read_count;
- if (pinoff == NULL)
- read_count = read (infd, buf, to_read);
- else
- read_count = pread (infd, buf, to_read, *pinoff);
- if (read_count == 0)
- /* End of file reached prematurely. */
- return copied;
- if (read_count < 0)
- {
- if (copied > 0)
- /* Report the number of bytes copied so far. */
- return copied;
- return -1;
- }
- if (pinoff != NULL)
- *pinoff += read_count;
-
- /* Write the buffer part which was read to the destination. */
- char *end = buf + read_count;
- for (char *p = buf; p < end; )
- {
- ssize_t write_count;
- if (poutoff == NULL)
- write_count = write (outfd, p, end - p);
- else
- write_count = pwrite (outfd, p, end - p, *poutoff);
- if (write_count < 0)
- {
- /* Adjust the input read position to match what we have
- written, so that the caller can pick up after the
- error. */
- size_t written = p - buf;
- /* NB: This needs to be signed so that we can form the
- negative value below. */
- ssize_t overread = read_count - written;
- if (pinoff == NULL)
- {
- if (overread > 0)
- {
- /* We are on an error recovery path, so we
- cannot deal with failure here. */
- int save_errno = errno;
- (void) lseek (infd, -overread, SEEK_CUR);
- __set_errno (save_errno);
- }
- }
- else /* pinoff != NULL */
- *pinoff -= overread;
-
- if (copied + written > 0)
- /* Report the number of bytes copied so far. */
- return copied + written;
- return -1;
- }
- p += write_count;
- if (poutoff != NULL)
- *poutoff += write_count;
- } /* Write loop. */
-
- copied += read_count;
- length -= read_count;
- }
- return copied;
+ /* There is little need to emulate copy_file_range with read+write,
+ since programs that use copy_file_range must fall back on
+ read+write anyway. */
+ errno = ENOSYS;
+ return -1;
}
diff --git a/m4/copy-file-range.m4 b/m4/copy-file-range.m4
index edd2c4aed..20fd05697 100644
--- a/m4/copy-file-range.m4
+++ b/m4/copy-file-range.m4
@@ -11,8 +11,26 @@ AC_DEFUN([gl_FUNC_COPY_FILE_RANGE],
dnl Persuade glibc to declare copy_file_range.
AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS])
- AC_CHECK_FUNCS_ONCE([copy_file_range])
- if test $ac_cv_func_copy_file_range != yes; then
+ dnl Use AC_LINK_IFELSE, rather than AC_CHECK_FUNCS or a variant,
+ dnl since we don't want AC_CHECK_FUNCS's checks for glibc stubs.
+ dnl Programs that use copy_file_range must fall back on read+write
+ dnl anyway, and there's little point to substituting the Gnulib stub
+ dnl for a glibc stub.
+ AC_CACHE_CHECK([for copy_file_range], [gl_cv_func_copy_file_range],
+ [AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM(
+ [[#include
+ ]],
+ [[ssize_t (*func) (int, off_t *, int, off_t, size_t, unsigned)
+ = copy_file_range;
+ return func (0, 0, 0, 0, 0, 0) & 127;
+ ]])
+ ],
+ [gl_cv_func_copy_file_range=yes],
+ [gl_cv_func_copy_file_range=no])
+ ])
+
+ if test "$gl_cv_func_copy_file_range" != yes; then
HAVE_COPY_FILE_RANGE=0
fi
])
diff --git a/modules/copy-file-range b/modules/copy-file-range
index 18742ef3b..42d6e6f31 100644
--- a/modules/copy-file-range
+++ b/modules/copy-file-range
@@ -6,12 +6,7 @@ lib/copy-file-range.c
m4/copy-file-range.m4
Depends-on:
-c99
-inttypes-incomplete [test $HAVE_COPY_FILE_RANGE = 0]
largefile
-libc-config [test $HAVE_COPY_FILE_RANGE = 0]
-pread [test $HAVE_COPY_FILE_RANGE = 0]
-pwrite [test $HAVE_COPY_FILE_RANGE = 0]
unistd
configure.ac:
--
2.17.1