diff --git a/usr.bin/xinstall/xinstall.c b/usr.bin/xinstall/xinstall.c --- a/usr.bin/xinstall/xinstall.c +++ b/usr.bin/xinstall/xinstall.c @@ -1298,7 +1298,8 @@ { static char *buf = NULL; static size_t bufsize; - int nr, nw; + ssize_t bytes; + int nr, nw, ret; int serrno; char *p; int done_copy; @@ -1310,6 +1311,39 @@ if (lseek(to_fd, (off_t)0, SEEK_SET) == (off_t)-1) err(EX_OSERR, "lseek: %s", to_name); + /* Try copy_file_range() first */ + ret = 1; + while (ret > 0) + ret = copy_file_range(from_fd, NULL, to_fd, NULL, SSIZE_MAX, 0); + if (ret == 0) { + if (digesttype == DIGEST_NONE) + return (NULL); + /* We need to read the source file and calculage a digest */ + digest_init(&ctx); + if (lseek(from_fd, (off_t)0, SEEK_SET) == (off_t)-1) + err(EX_OSERR, "lseek: %s", from_name); + if (buf == NULL) { + if (sysconf(_SC_PHYS_PAGES) > + PHYSPAGES_THRESHOLD) + bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8); + else + bufsize = BUFSIZE_SMALL; + buf = malloc(bufsize); + if (buf == NULL) + err(1, "Not enough memory"); + } + while(1) { + bytes = read(from_fd, buf, bufsize); + if (bytes == 0) + break; + else if (bytes == -1) + err(EX_OSERR, "read: %s", from_name); + digest_update(&ctx, p, bytes); + } + return (digest_end(&ctx, NULL)); + } + + /* Fall back if copy_file_range() fails */ digest_init(&ctx); done_copy = 0;