use std::fs;
use std::fs::File;
use std::io;
use std::io::Read;
use std::path::Path;
use sha1::Digest;
use sha1::Sha1;
use super::listing::ListedFile;
pub(super) fn intact(pointer: &Path, file: &ListedFile) -> io::Result<bool> {
let metadata = match fs::metadata(pointer) {
Ok(metadata) => metadata,
Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(false),
Err(error) => return Err(error),
};
if !metadata.is_file() || metadata.len() != file.size {
return Ok(false);
}
Ok(!file.in_git || git_blob_id(pointer, file.size)?.eq_ignore_ascii_case(&file.oid))
}
pub(super) fn remove(pointer: &Path) -> io::Result<()> {
match fs::remove_file(pointer) {
Err(error) if error.kind() != io::ErrorKind::NotFound => Err(error),
_ => Ok(()),
}
}
pub(super) fn git_blob_id(path: &Path, size: u64) -> io::Result<String> {
let mut hasher = Sha1::new();
hasher.update(format!("blob {size}\0"));
let mut file = File::open(path)?;
let mut buffer = vec![0; 1 << 16];
loop {
match file.read(&mut buffer)? {
0 => break,
read => hasher.update(&buffer[..read]),
}
}
Ok(hex(&hasher.finalize()))
}
pub(super) fn hex(digest: &[u8]) -> String {
digest.iter().map(|byte| format!("{byte:02x}")).collect()
}