void *userdata) {
_cleanup_close_ int fdf_opened = -EBADF, fdt_opened = -EBADF;
- bool try_cfr = true, try_sendfile = true, try_splice = true, copied_something = false;
+ bool try_cfr = true, try_sendfile = true, try_splice = true;
+ uint64_t copied_total = 0;
int r, nonblock_pipe = -1;
- size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */
assert(fdf >= 0);
assert(fdt >= 0);
for (;;) {
ssize_t n;
+ size_t m;
if (max_bytes <= 0)
break;
if (r < 0)
return r;
+ /* sendfile() accepts at most SSIZE_MAX-offset bytes to copy, hence let's subtract how much
+ * copied so far from SSIZE_MAX as maximum of what we want to copy. */
+ if (try_sendfile) {
+ assert(copied_total < SSIZE_MAX);
+ m = (uint64_t) SSIZE_MAX - copied_total;
+ } else
+ m = SSIZE_MAX;
+
if (max_bytes != UINT64_MAX && m > max_bytes)
m = max_bytes;
/* use fallback below */
} else if (n == 0) { /* likely EOF */
- if (copied_something)
+ if (copied_total > 0)
break;
/* So, we hit EOF immediately, without having copied a single byte. This
/* use fallback below */
} else if (n == 0) { /* likely EOF */
- if (copied_something)
+ if (copied_total > 0)
break;
try_sendfile = try_splice = false; /* same logic as above for copy_file_range() */
/* use fallback below */
} else if (n == 0) { /* likely EOF */
- if (copied_something)
+ if (copied_total > 0)
break;
try_splice = false; /* same logic as above for copy_file_range() + sendfile() */
}
next:
+ copied_total += n;
+
+ /* Disable sendfile() in case we are getting too close to it's SSIZE_MAX-offset limit */
+ if (copied_total > SSIZE_MAX - COPY_BUFFER_SIZE)
+ try_sendfile = false;
+
if (progress) {
r = progress(n, userdata);
if (r < 0)
assert(max_bytes >= (uint64_t) n);
max_bytes -= n;
}
-
- /* sendfile accepts at most SSIZE_MAX-offset bytes to copy, so reduce our maximum by the
- * amount we already copied, but don't go below our copy buffer size, unless we are close the
- * limit of bytes we are allowed to copy. */
- m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n);
-
- copied_something = true;
}
if (FLAGS_SET(copy_flags, COPY_VERIFY_LINKED)) {