diff --git a/kitty/fast-file-copy.c b/kitty/fast-file-copy.c index eabb786a3..dec635286 100644 --- a/kitty/fast-file-copy.c +++ b/kitty/fast-file-copy.c @@ -5,39 +5,20 @@ * Distributed under terms of the GPL3 license. */ +#if __linux__ +#define _GNU_SOURCE 1 +#endif #include "fast-file-copy.h" #if __linux__ #define HAS_SENDFILE #include +#include #endif -#ifdef HAS_SENDFILE static bool -copy_with_sendfile(int infd, int outfd, off_t in_pos, size_t len) { - unsigned num_of_consecutive_zero_returns = 128; - while (len) { - off_t r = in_pos; - ssize_t n = sendfile(outfd, infd, &r, len); - if (n < 0) { - if (errno != EAGAIN) return false; - continue; - } - if (n == 0) { - // happens if input file is truncated - if (!--num_of_consecutive_zero_returns) return false; - continue; - }; - num_of_consecutive_zero_returns = 128; - in_pos += n; len -= n; - } - return true; -} -#endif - -static inline bool copy_with_buffer(int infd, int outfd, off_t in_pos, size_t len, FastFileCopyBuffer *fcb) { if (!fcb->buf) { - fcb->sz = 16 * 1024; + fcb->sz = 32 * 1024; fcb->buf = malloc(fcb->sz); if (!fcb->buf) return false; } @@ -69,14 +50,64 @@ copy_with_buffer(int infd, int outfd, off_t in_pos, size_t len, FastFileCopyBuff } } return true; -#undef bufsz } +#ifdef HAS_SENDFILE +static bool +copy_with_sendfile(int infd, int outfd, off_t in_pos, size_t len, FastFileCopyBuffer *fcb) { + unsigned num_of_consecutive_zero_returns = 128; + while (len) { + off_t r = in_pos; + ssize_t n = sendfile(outfd, infd, &r, len); + if (n < 0) { + if (errno != EAGAIN) return false; + if (errno == ENOSYS || errno == EPERM) return copy_with_buffer(infd, outfd, in_pos, len, fcb); + continue; + } + if (n == 0) { + // happens if input file is truncated + if (!--num_of_consecutive_zero_returns) return false; + continue; + }; + num_of_consecutive_zero_returns = 128; + in_pos += n; len -= n; + } + return true; +} + +static bool +copy_with_file_range(int infd, int outfd, off_t in_pos, size_t len, FastFileCopyBuffer *fcb) { +#ifdef HAS_COPY_FILE_RANGE + unsigned num_of_consecutive_zero_returns = 128; + while (len) { + off64_t r = in_pos; + ssize_t n = copy_file_range(infd, &r, outfd, NULL, len, 0); + if (n < 0) { + if (errno != EAGAIN) return false; + if (errno == ENOSYS || errno == EPERM) return copy_with_sendfile(infd, outfd, in_pos, len, fcb); + continue; + } + if (n == 0) { + // happens if input file is truncated + if (!--num_of_consecutive_zero_returns) return false; + continue; + }; + num_of_consecutive_zero_returns = 128; + in_pos += n; len -= n; + } + return true; +#else + return copy_with_sendfile(infd, outfd, in_pos, len, fcb); +#endif +} + + +#endif + bool copy_between_files(int infd, int outfd, off_t in_pos, size_t len, FastFileCopyBuffer *fcb) { #ifdef HAS_SENDFILE - (void)fcb; - return copy_with_sendfile(infd, outfd, in_pos, len); + return copy_with_file_range(infd, outfd, in_pos, len, fcb); #else return copy_with_buffer(infd, outfd, in_pos, len, fcb); #endif diff --git a/setup.py b/setup.py index 2e311ddd0..98873dc60 100755 --- a/setup.py +++ b/setup.py @@ -326,6 +326,9 @@ def init_env( cppflags = shlex.split(cppflags_) for el in extra_logging: cppflags.append('-DDEBUG_{}'.format(el.upper().replace('-', '_'))) + has_copy_file_range = test_compile(cc, src='#define _GNU_SOURCE 1\n#include \nint main() { copy_file_range(1, NULL, 2, NULL, 0, 0); return 0; }') + if has_copy_file_range: + cppflags.append('-DHAS_COPY_FILE_RANGE') werror = '' if ignore_compiler_warnings else '-pedantic-errors -Werror' std = '' if is_openbsd else '-std=c11' sanitize_flag = ' '.join(sanitize_args)