aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Matuska <mm@FreeBSD.org>2023-07-08 19:46:46 +0000
committerMartin Matuska <mm@FreeBSD.org>2023-07-08 19:51:21 +0000
commit5a50d52f112a86ebd0696da6564c7c7befa27f5d (patch)
tree960e7cf04b780d9fc6acd5fa61725828716123fb
parent8113cc827611a88540736c92ced7d3a7020a1723 (diff)
downloadsrc-5a50d52f112a86ebd0696da6564c7c7befa27f5d.tar.gz
src-5a50d52f112a86ebd0696da6564c7c7befa27f5d.zip
xinstall: use copy_file_range(2) with fallback to previous behavior
This allows to use special filesystem features like server-side copying on NFS 4.2 or block cloning on OpenZFS 2.2. Note: copy_file_range(2) is not used when a digest calculation is requested as this would require to read the input file twice. Reviewed by: asomers, imp, rmacklem Differential revision: https://reviews.freebsd.org/D40898
-rw-r--r--usr.bin/xinstall/xinstall.c21
1 files changed, 21 insertions, 0 deletions
diff --git a/usr.bin/xinstall/xinstall.c b/usr.bin/xinstall/xinstall.c
index b0e52453ca29..8dace862ef1e 100644
--- a/usr.bin/xinstall/xinstall.c
+++ b/usr.bin/xinstall/xinstall.c
@@ -1300,6 +1300,7 @@ copy(int from_fd, const char *from_name, int to_fd, const char *to_name,
static size_t bufsize;
int nr, nw;
int serrno;
+ ssize_t ret;
char *p;
int done_copy;
DIGEST_CTX ctx;
@@ -1310,6 +1311,26 @@ copy(int from_fd, const char *from_name, int to_fd, const char *to_name,
if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1)
err(EX_OSERR, "lseek: %s", to_name);
+ /* Try copy_file_range() if no digest is requested */
+ if (digesttype == DIGEST_NONE) {
+ ret = 1;
+ while (ret > 0) {
+ ret = copy_file_range(from_fd, NULL, to_fd, NULL,
+ SSIZE_MAX, 0);
+ }
+ if (ret == 0) {
+ /* DIGEST_NONE always returns NULL */
+ return (NULL);
+ }
+ if (errno != EINVAL) {
+ serrno = errno;
+ (void)unlink(to_name);
+ errno = serrno;
+ err(EX_OSERR, "%s", to_name);
+ }
+ /* Fall back */
+ }
+
digest_init(&ctx);
done_copy = 0;