summaryrefslogtreecommitdiff
path: root/lib/copy-file-range.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2019-06-06 15:44:33 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2019-06-06 15:46:20 -0700
commitb0d998d2e04050dd3c65816b277cf0f91c9ca74c (patch)
treed38b87aaa26d3e7ff94c484b4ca34d689be564c9 /lib/copy-file-range.c
parenta1beabcb14cde661c36f7a3c7c17b5871704003e (diff)
downloadgnulib-b0d998d2e04050dd3c65816b277cf0f91c9ca74c.tar.gz
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.
Diffstat (limited to 'lib/copy-file-range.c')
-rw-r--r--lib/copy-file-range.c152
1 files changed, 10 insertions, 142 deletions
diff --git a/lib/copy-file-range.c b/lib/copy-file-range.c
index a1448d0d98..39b5efbc1c 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 <https://www.gnu.org/licenses/>. */
-/* 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 <config.h>
-#include <libc-config.h>
-
-/* 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 <unistd.h>
#include <errno.h>
-#include <fcntl.h>
-#include <inttypes.h>
-#include <limits.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-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;
}