diff options
author | Martin Matuska <mm@FreeBSD.org> | 2023-07-08 19:46:46 +0000 |
---|---|---|
committer | Martin Matuska <mm@FreeBSD.org> | 2023-07-08 19:51:21 +0000 |
commit | 5a50d52f112a86ebd0696da6564c7c7befa27f5d (patch) | |
tree | 960e7cf04b780d9fc6acd5fa61725828716123fb | |
parent | 8113cc827611a88540736c92ced7d3a7020a1723 (diff) | |
download | src-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.c | 21 |
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; |