logo

utils-std

Collection of commonly available Unix tools
commit: ee3a29fbf94556f9ea83d486578797d5b9cbabf7
parent 55ecff146288046783aba44af4f8dbe135ca633b
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Mon,  6 May 2024 03:04:58 +0200

cmd/install: Fallback to manual read-write on EXDEV

Diffstat:

Mcmd/install.c97++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
Mconfigure.d/copy_file_range.c2+-
2 files changed, 55 insertions(+), 44 deletions(-)

diff --git a/cmd/install.c b/cmd/install.c @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MPL-2.0 // For copy_file_range -#define _GNU_SOURCE // musl, glibc +#define _GNU_SOURCE // musl, glibc #define _DEFAULT_SOURCE // FreeBSD #include "../lib/mkdir.h" @@ -32,6 +32,50 @@ uid_t user = (uid_t)-1; gid_t group = (gid_t)-1; char *argv0 = "install"; +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +static int +manual_file_copy(int fd_in, int fd_out, off_t len, int flags) +{ + do + { + char buf[BUFSIZ]; + + ssize_t nread = read(fd_in, buf, MIN(BUFSIZ, len)); + if(nread < 0) return nread; + + ssize_t nwrite = write(fd_out, buf, (size_t)nread); + if(nwrite < 0) return nwrite; + + len -= nwrite; + } while(len > 0); + + return 0; +} + +#ifdef HAS_COPY_FILE_RANGE +static int +auto_file_copy(int fd_in, int fd_out, off_t len, int flags) +{ + off_t ret = -1; + do + { + ret = copy_file_range(fd_in, NULL, fd_out, NULL, len, 0); + if(ret < 0) + { + if(errno == EXDEV) return manual_file_copy(fd_in, fd_out, len, flags); + + return ret; + } + len -= ret; + } while(len > 0 && ret > 0); + + return 0; +} +#else +#define auto_file_copy manual_file_copy +#endif + static int do_install(char *src, char *dest, bool is_dir) { @@ -125,49 +169,16 @@ do_install(char *src, char *dest, bool is_dir) return -1; } -#ifdef HAS_COPY_FILE_RANGE - off_t len = src_stat.st_size; - off_t ret = -1; - do + if(auto_file_copy(src_fd, dest_fd, src_stat.st_size, 0) < 0) { - ret = copy_file_range(src_fd, NULL, dest_fd, NULL, len, 0); - if(ret == -1) - { - fprintf(stderr, - "%s: Error: Failed copying data from '%s' to '%s': %s\n", - argv0, - src, - dest_path, - strerror(errno)); - return -1; - } - len -= ret; - } while(len > 0 && ret > 0); -#else -#undef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) - off_t len = src_stat.st_size; - do - { - char buf[BUFSIZ]; - ssize_t nread = read(src_fd, buf, MIN(BUFSIZ, len)); - if(nread < 0) - { - fprintf(stderr, "install: Error reading from '%s': %s\n", src, strerror(errno)); - errno = 0; - return -1; - } - - ssize_t nwrite = write(dest_fd, buf, (size_t)nread); - if(nwrite < 0) - { - fprintf(stderr, "install: Error writing to '%s': %s\n", dest_path, strerror(errno)); - errno = 0; - return -1; - } - len -= nwrite; - } while(len > 0); -#endif + fprintf(stderr, + "%s: Error: Failed copying data from '%s' to '%s': %s\n", + argv0, + src, + dest_path, + strerror(errno)); + return -1; + } assert(errno == 0); diff --git a/configure.d/copy_file_range.c b/configure.d/copy_file_range.c @@ -3,7 +3,7 @@ // SPDX-License-Identifier: MPL-2.0 // For copy_file_range -#define _GNU_SOURCE // musl, glibc +#define _GNU_SOURCE // musl, glibc #define _DEFAULT_SOURCE // FreeBSD #include <stdint.h> // SIZE_MAX