From 09f159991e5f87b42f1ee6c1a4bac852072a2e39 Mon Sep 17 00:00:00 2001 From: link2xt Date: Sat, 6 Dec 2025 11:01:08 +0000 Subject: [PATCH] fix: use u64 to represent the number of bytes in backup files --- src/imex.rs | 25 ++++++++++++++----------- src/tools.rs | 20 ++++++++++++++++++++ 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/src/imex.rs b/src/imex.rs index f3afb4223..30b74ecff 100644 --- a/src/imex.rs +++ b/src/imex.rs @@ -25,7 +25,8 @@ use crate::pgp; use crate::qr::DCBACKUP_VERSION; use crate::sql; use crate::tools::{ - TempPathGuard, create_folder, delete_file, get_filesuffix_lc, read_file, time, write_file, + TempPathGuard, create_folder, delete_file, get_filesuffix_lc, read_file, time, usize_to_u64, + write_file, }; mod key_transfer; @@ -263,11 +264,11 @@ struct ProgressReader { inner: R, /// Number of bytes successfully read from the internal reader. - read: usize, + read: u64, /// Total size of the backup .tar file expected to be read from the reader. /// Used to calculate the progress. - file_size: usize, + file_size: u64, /// Last progress emitted to avoid emitting the same progress value twice. last_progress: usize, @@ -281,7 +282,7 @@ impl ProgressReader { Self { inner: r, read: 0, - file_size: file_size as usize, + file_size, last_progress: 1, context, } @@ -301,9 +302,11 @@ where let before = buf.filled().len(); let res = this.inner.poll_read(cx, buf); if let std::task::Poll::Ready(Ok(())) = res { - *this.read = this.read.saturating_add(buf.filled().len() - before); + *this.read = this + .read + .saturating_add(usize_to_u64(buf.filled().len() - before)); - let progress = std::cmp::min(1000 * *this.read / *this.file_size, 999); + let progress = std::cmp::min(1000 * *this.read / *this.file_size, 999) as usize; if progress > *this.last_progress { this.context.emit_event(EventType::ImexProgress(progress)); *this.last_progress = progress; @@ -490,11 +493,11 @@ struct ProgressWriter { inner: W, /// Number of bytes successfully written into the internal writer. - written: usize, + written: u64, /// Total size of the backup .tar file expected to be written into the writer. /// Used to calculate the progress. - file_size: usize, + file_size: u64, /// Last progress emitted to avoid emitting the same progress value twice. last_progress: usize, @@ -508,7 +511,7 @@ impl ProgressWriter { Self { inner: w, written: 0, - file_size: file_size as usize, + file_size, last_progress: 1, context, } @@ -527,9 +530,9 @@ where let this = self.project(); let res = this.inner.poll_write(cx, buf); if let std::task::Poll::Ready(Ok(written)) = res { - *this.written = this.written.saturating_add(written); + *this.written = this.written.saturating_add(usize_to_u64(written)); - let progress = std::cmp::min(1000 * *this.written / *this.file_size, 999); + let progress = std::cmp::min(1000 * *this.written / *this.file_size, 999) as usize; if progress > *this.last_progress { this.context.emit_event(EventType::ImexProgress(progress)); *this.last_progress = progress; diff --git a/src/tools.rs b/src/tools.rs index b9c1e1540..6ef3406df 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -798,6 +798,26 @@ pub(crate) fn inc_and_check( Ok(()) } +/// Converts usize to u64 without using `as`. +/// +/// This is needed for example to convert in-memory buffer sizes +/// to u64 type used for counting all the bytes written. +/// +/// On 32-bit systems it is possible to have files +/// larger than 4 GiB or write more than 4 GiB to network connection, +/// in which case we need a 64-bit total counter, +/// but use 32-bit usize for buffer sizes. +/// +/// This can only break if usize has more than 64 bits +/// and this is not the case as of 2025 and is +/// unlikely to change for general purpose computers. +/// See +/// and +/// and . +pub(crate) fn usize_to_u64(v: usize) -> u64 { + u64::try_from(v).unwrap_or(u64::MAX) +} + /// Returns early with an error if a condition is not satisfied. /// In non-optimized builds, panics instead if so. #[macro_export]