>From 81849f05b94068f873299bd9fc01b4eebdb31f64 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 25 Jun 2020 17:34:23 -0700 Subject: [PATCH 5/5] 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. --- NEWS | 5 +++-- bootstrap.conf | 1 + src/copy.c | 40 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 63cb47d10..1c3f6378d 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 12e2d831a..2506f0db4 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 d88f8cf93..4050f6953 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; -- 2.25.4