From: Paul Eggert Date: Fri, 26 Jun 2020 00:34:23 +0000 (-0700) Subject: cp: use copy_file_range if available X-Git-Tag: v9.0~227 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4b04a0c3b792d27909670a81d21f2a3b3e0ea563;p=thirdparty%2Fcoreutils.git cp: use copy_file_range if available * NEWS: Mention this. * bootstrap.conf (gnulib_modules): Add copy-file-range. * src/copy.c (sparse_copy): Try copy_file_range if not looking for holes. --- diff --git a/NEWS b/NEWS index 63cb47d105..1c3f6378d6 100644 --- a/NEWS +++ b/NEWS @@ -17,8 +17,9 @@ GNU coreutils NEWS -*- outline -*- cp and install now default to copy-on-write (COW) if available. - cp, install and mv now prefer lseek+SEEK_HOLE to ioctl+FS_IOC_FIEMAP - on sparse files, as lseek is simpler and more portable. + cp, install and mv now use the copy_file_range syscall if available. + Also, they prefer lseek+SEEK_HOLE to ioctl+FS_IOC_FIEMAP on sparse + files, as lseek is simpler and more portable. On GNU/Linux systems, ls no longer issues an error message on a directory merely because it was removed. This reverts a change diff --git a/bootstrap.conf b/bootstrap.conf index 12e2d831a3..2506f0db47 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -54,6 +54,7 @@ gnulib_modules=" closeout config-h configmake + copy-file-range crypto/md5 crypto/sha1 crypto/sha256 diff --git a/src/copy.c b/src/copy.c index d88f8cf930..4050f69536 100644 --- a/src/copy.c +++ b/src/copy.c @@ -265,6 +265,46 @@ sparse_copy (int src_fd, int dest_fd, char *buf, size_t buf_size, { *last_write_made_hole = false; *total_n_read = 0; + + /* If not looking for holes, use copy_file_range if available. */ + if (!hole_size) + while (max_n_read) + { + /* Copy at most COPY_MAX bytes at a time; this is min + (PTRDIFF_MAX, SIZE_MAX) truncated to a value that is + surely aligned well. */ + ssize_t ssize_max = TYPE_MAXIMUM (ssize_t); + ptrdiff_t copy_max = MIN (ssize_max, SIZE_MAX) >> 30 << 30; + ssize_t n_copied = copy_file_range (src_fd, NULL, dest_fd, NULL, + MIN (max_n_read, copy_max), 0); + if (n_copied == 0) + { + /* copy_file_range incorrectly returns 0 when reading from + the proc file system on the Linux kernel through at + least 5.6.19 (2020), so fall back on 'read' if the + input file seems empty. */ + if (*total_n_read == 0) + break; + return true; + } + if (n_copied < 0) + { + if (errno == ENOSYS || errno == EINVAL + || errno == EBADF || errno == EXDEV) + break; + if (errno == EINTR) + n_copied = 0; + else + { + error (0, errno, _("error copying %s to %s"), + quoteaf_n (0, src_name), quoteaf_n (1, dst_name)); + return false; + } + } + max_n_read -= n_copied; + *total_n_read += n_copied; + } + bool make_hole = false; off_t psize = 0;