Release v2.26.0 #284

Merged
TapTap merged 210 commits from dev into main 2026-09-18 19:05:52 +02:00
Showing only changes of commit 2b5aaef409 - Show all commits
+21 -14
View File
@@ -40,19 +40,27 @@ static bool write_all(int fd, const void* data, unsigned long long size) {
} }
/* Preallocate `size` bytes on `fd` before any data is written (--preallocate). /* Preallocate `size` bytes on `fd` before any data is written (--preallocate).
* posix_fallocate reserves real disk blocks, so an out-of-space condition * fallocate(2) reserves real disk blocks, so an out-of-space condition
* (ENOSPC/EDQUOT) surfaces up front instead of partway through a transfer; * (ENOSPC/EDQUOT) surfaces up front instead of partway through a transfer;
* unavoidable fragmentation of a streamed file is also reduced. Some * unavoidable fragmentation of a streamed file is also reduced. rsync favors
* filesystems (e.g. tmpfs, ZFS) do not support it and return EOPNOTSUPP/ENOSYS, * the syscall over glibc posix_fallocate (whose emulation can be subtly
* where we fall back to ftruncate, which still extends the logical size so the * different), so try fallocate(2) first and only fall back to posix_fallocate,
* fail-fast/contiguity intent degrades gracefully but never fails. Genuine * then to ftruncate on filesystems (e.g. tmpfs, ZFS) that support neither. The
* allocation failures are propagated as the error code (caller fails the write). * logical size is always extended, so the fail-fast/contiguity intent degrades
* posix_fallocate leaves the fd's file offset unchanged, so the subsequent * gracefully but never fails on an unsupported filesystem; genuine allocation
* write_all at offset 0 is unaffected. Returns 0 on success (including the * failures are propagated as the error code (caller fails the write). Neither
* fallback) or a nonzero error code. */ * leaves the fd's file offset guaranteed, so the caller seeks back to 0 before
* writing. Returns 0 on success (including the fallback) or a nonzero error
* code. */
static int preallocate_fd(int fd, unsigned long long size) { static int preallocate_fd(int fd, unsigned long long size) {
if (size == 0) if (size == 0)
return 0; return 0;
#ifdef __linux__
if (fallocate(fd, 0, 0, (off_t)size) == 0)
return 0;
if (errno != EOPNOTSUPP && errno != ENOSYS && errno != EINVAL)
return errno;
#endif
int rc = posix_fallocate(fd, 0, (off_t)size); int rc = posix_fallocate(fd, 0, (off_t)size);
if (rc == EOPNOTSUPP || rc == ENOSYS) { if (rc == EOPNOTSUPP || rc == ENOSYS) {
if (ftruncate(fd, (off_t)size) == 0) if (ftruncate(fd, (off_t)size) == 0)
@@ -1066,11 +1074,10 @@ static bool file_to_disk_secure_impl(const char* path, const void* data,
} else { } else {
/* Preallocate the expected payload size before writing so an /* Preallocate the expected payload size before writing so an
out-of-space condition fails cleanly up front (--preallocate). out-of-space condition fails cleanly up front (--preallocate).
--sparse takes precedence: posix_fallocate would allocate every rsync lets --preallocate win over --sparse (the reserved blocks
block, defeating the holes the sparse writer would create, so the survive the sparse writer's seeks), so both flags can be active. */
two never combine here (the ftruncate presize below stays). */
int prealloc_rc = 0; int prealloc_rc = 0;
if (preallocate && !sparse && data_size > 0) { if (preallocate && data_size > 0) {
prealloc_rc = preallocate_fd(fd, data_size); prealloc_rc = preallocate_fd(fd, data_size);
if (prealloc_rc != 0) { if (prealloc_rc != 0) {
char* escaped_path = output_escape(path, log_get_8_bit_output()); char* escaped_path = output_escape(path, log_get_8_bit_output());
@@ -1196,7 +1203,7 @@ static bool file_to_disk_secure_impl(const char* path, const void* data,
if (fd < 0) if (fd < 0)
continue; /* EEXIST (or a transient open error): try a fresh name. */ continue; /* EEXIST (or a transient open error): try a fresh name. */
int prealloc_rc = 0; int prealloc_rc = 0;
if (preallocate && !sparse && data_size > 0) { if (preallocate && data_size > 0) {
prealloc_rc = preallocate_fd(fd, data_size); prealloc_rc = preallocate_fd(fd, data_size);
if (prealloc_rc != 0) { if (prealloc_rc != 0) {
char* escaped_path = output_escape(path, log_get_8_bit_output()); char* escaped_path = output_escape(path, log_get_8_bit_output());