shrupl/src/file/mod.rs

84 lines
2.1 KiB
Rust
Raw Normal View History

mod checked;
mod chunk;
mod uploading;
2025-05-27 00:42:43 +00:00
2025-06-26 09:56:29 +00:00
use std::{ffi::OsStr, fs, io::Read, path::Path};
use base64ct::{Base64, Encoding};
use blake2b_simd::Params as Blake2b;
pub use checked::Checked;
pub use chunk::Chunk;
2025-06-26 09:56:29 +00:00
use log::{debug, warn};
pub use uploading::Uploading;
2025-05-27 00:42:43 +00:00
2025-06-26 09:56:29 +00:00
2025-06-27 01:55:43 +00:00
fn compute_file_hash(path: &Path, size: u64, on_progress: impl Fn(u64)) -> crate::Result<String> {
let mut file = fs::File::open(path)?;
let mut hasher = Blake2b::new().hash_length(64).to_state();
let mut buf = vec![0u8; 4 * 1024 * 1024];
let mut bytes_read = 0;
loop {
let n = file.read(&mut buf)?;
if n == 0 {
break;
}
hasher.update(&buf[..n]);
bytes_read += n as u64;
on_progress(n as u64);
}
if bytes_read != size {
2025-06-27 01:55:43 +00:00
return Err(crate::Error::mismatch(size, bytes_read));
}
let result = Base64::encode_string(hasher.finalize().as_bytes());
debug!("hashed {:?}: {result:?}", path.display());
Ok(result)
}
fn check_file_hash(
path: &Path,
size: u64,
hash: Option<&String>,
on_progress: impl Fn(u64),
2025-06-27 01:55:43 +00:00
) -> crate::Result<()> {
2025-06-26 09:56:29 +00:00
let Some(expected) = hash else {
2025-06-27 01:55:43 +00:00
return Err(crate::Error::mismatch("hash", path.display()));
};
2025-06-26 09:56:29 +00:00
let actual = &compute_file_hash(path, size, on_progress)?;
if expected == actual {
debug!("hash matches {expected:?}");
Ok(())
} else {
warn!("hash mismatch for file {:?}", path.display());
2025-06-27 01:55:43 +00:00
Err(crate::Error::mismatch(expected, actual))
2025-06-26 09:56:29 +00:00
}
}
pub trait FileTrait<'t> {
/// extract the filename part of a `Path` reference
///
/// # Panics
///
/// Expects `path::Path::file_name` and `ffi::OsStr::to_str` to succeed on the given path
fn extract_file_name(p: &'t Path) -> &'t str {
p.file_name()
.and_then(OsStr::to_str)
.expect("bad file name")
}
/// get a reference to the file's name
fn get_name(&'t self) -> &'t str;
/// get the file's size
fn get_size(&self) -> u64;
2025-06-27 01:55:43 +00:00
fn check_hash(&self, on_progress: impl Fn(u64)) -> crate::Result<()>;
}