[wip] documentation for file module

This commit is contained in:
Jörn-Michael Miehe 2025-07-03 18:27:41 +00:00
parent 61d62d731e
commit 5a34a8d791
3 changed files with 55 additions and 18 deletions

View file

@ -54,6 +54,12 @@ impl Checked {
} }
} }
/// calculate and store hash for this file
///
/// # Errors
///
/// - from `file::compute_hash`
/// - Mismatch if file already hashed
pub fn hash(&mut self, f: impl Fn(u64)) -> crate::Result<()> { pub fn hash(&mut self, f: impl Fn(u64)) -> crate::Result<()> {
if self.hash.is_some() { if self.hash.is_some() {
return Err(crate::Error::mismatch("unhashed file", self.path.display())); return Err(crate::Error::mismatch("unhashed file", self.path.display()));
@ -64,15 +70,14 @@ impl Checked {
Ok(()) Ok(())
} }
/// start uploading this file /// starts uploading this file
/// ///
/// - tries to create a new entry in a share /// - tries to create a new file using the client
/// - expects endpoint like `{base_uri}/alias/upload/{share_id}/files/tus`
/// - consumes `self` into a `file::Uploading` struct /// - consumes `self` into a `file::Uploading` struct
/// ///
/// # Errors /// # Errors
/// ///
/// TODO documentation after `ClientError` rework /// - from `sharry::Client::file_create`
pub fn start_upload( pub fn start_upload(
self, self,
client: &impl sharry::Client, client: &impl sharry::Client,
@ -87,19 +92,15 @@ impl Checked {
} }
impl<'t> FileTrait<'t> for Checked { impl<'t> FileTrait<'t> for Checked {
/// get a reference to the file's name
///
/// Uses `SharryFile::extract_file_name`, which may **panic**!
fn get_name(&'t self) -> &'t str { fn get_name(&'t self) -> &'t str {
<Self as FileTrait>::extract_file_name(&self.path) <Self as FileTrait>::extract_file_name(&self.path)
} }
/// get the file's size
fn get_size(&self) -> u64 { fn get_size(&self) -> u64 {
self.size self.size
} }
fn check_hash(&self, on_progress: impl Fn(u64)) -> crate::Result<()> { fn check_hash(&self, on_progress: impl FnMut(u64)) -> crate::Result<()> {
super::check_hash( super::check_hash(
&self.path, &self.path,
self.size, self.size,

View file

@ -12,22 +12,38 @@ pub use chunk::Chunk;
use log::{debug, warn}; use log::{debug, warn};
pub use uploading::Uploading; pub use uploading::Uploading;
/// how many bytes to hash at once (default: 4 MiB)
const HASH_CHUNK_SIZE: usize = 4 * 1024 * 1024;
/// compute hash for a file given its path.
/// Hash function: BLAKE2b, 512 bit
///
/// # Params
///
/// - `path` to the file to hash
/// - `size` of that file
/// - `on_progress` will be called for each processed chunk (max. `HASH_CHUNK_SIZE`)
///
/// # Errors
///
/// - from `fs::File::open` and `fs::File::read`
/// - Mismatch if given `size` does not match the file's size
fn compute_hash(path: &Path, size: u64, mut on_progress: impl FnMut(u64)) -> crate::Result<String> { fn compute_hash(path: &Path, size: u64, mut on_progress: impl FnMut(u64)) -> crate::Result<String> {
let mut file = fs::File::open(path)?; let mut file = fs::File::open(path)?;
// Blake2b-512 hasher (64 * 8 bit) // Blake2b-512 hasher (64 * 8 bit)
let mut hasher = Blake2b::new().hash_length(64).to_state(); let mut hasher = Blake2b::new().hash_length(64).to_state();
// buffer (4 MiB) // buffer
let mut buf = vec![0; 4 * 1024 * 1024]; let mut buffer = vec![0; HASH_CHUNK_SIZE];
let mut bytes_read = 0; let mut bytes_read = 0;
loop { loop {
let n = file.read(&mut buf)?; let n = file.read(&mut buffer)?;
if n == 0 { if n == 0 {
break; break;
} }
hasher.update(&buf[..n]); hasher.update(&buffer[..n]);
// `buf` size must be < 2 EiB // `buf` size must be < 2 EiB
bytes_read += n as u64; bytes_read += n as u64;
@ -43,16 +59,32 @@ fn compute_hash(path: &Path, size: u64, mut on_progress: impl FnMut(u64)) -> cra
Ok(result) Ok(result)
} }
/// check hash for a file given its path, return Ok(()) on success
///
/// # Params
///
/// - `path` to the file to hash
/// - `size` of that file
/// - optional known `hash`
/// - `on_progress` will be called for each processed chunk (max. `HASH_CHUNK_SIZE`)
///
/// # Errors
///
/// - from `file::compute_hash`
/// - Mismatch if `hash` is `None`
/// - Mismatch if given `hash` does not match the computed hash
fn check_hash( fn check_hash(
path: &Path, path: &Path,
size: u64, size: u64,
hash: Option<&str>, hash: Option<&str>,
on_progress: impl FnMut(u64), on_progress: impl FnMut(u64),
) -> crate::Result<()> { ) -> crate::Result<()> {
// check if hash is None
let Some(expected) = hash else { let Some(expected) = hash else {
return Err(crate::Error::mismatch("hash", path.display())); return Err(crate::Error::mismatch("hash", path.display()));
}; };
// compute and check new hash
let actual = &compute_hash(path, size, on_progress)?; let actual = &compute_hash(path, size, on_progress)?;
if expected == actual { if expected == actual {
@ -77,12 +109,19 @@ pub trait FileTrait<'t> {
} }
/// get a reference to the file's name /// get a reference to the file's name
///
/// Uses `file::FileTrait::extract_file_name`, which may **panic**!
fn get_name(&'t self) -> &'t str; fn get_name(&'t self) -> &'t str;
/// get the file's size /// get the file's size
fn get_size(&self) -> u64; fn get_size(&self) -> u64;
fn check_hash(&self, on_progress: impl Fn(u64)) -> crate::Result<()>; /// check this file's hash, return Ok(()) on success
///
/// # Errors
///
/// - from `file::check_hash`
fn check_hash(&self, on_progress: impl FnMut(u64)) -> crate::Result<()>;
} }
#[cfg(test)] #[cfg(test)]

View file

@ -95,9 +95,6 @@ impl Uploading {
} }
impl<'t> FileTrait<'t> for Uploading { impl<'t> FileTrait<'t> for Uploading {
/// get a reference to the file's name
///
/// Uses `SharryFile::extract_file_name`, which may **panic**!
fn get_name(&'t self) -> &'t str { fn get_name(&'t self) -> &'t str {
<Self as FileTrait>::extract_file_name(&self.path) <Self as FileTrait>::extract_file_name(&self.path)
} }
@ -106,7 +103,7 @@ impl<'t> FileTrait<'t> for Uploading {
self.size self.size
} }
fn check_hash(&self, on_progress: impl Fn(u64)) -> crate::Result<()> { fn check_hash(&self, on_progress: impl FnMut(u64)) -> crate::Result<()> {
super::check_hash( super::check_hash(
&self.path, &self.path,
self.size, self.size,