use crate::errors::ClineupError;
use sha2::{Digest, Sha256};
use std::{collections::HashMap, fs::File, io::Read, path::PathBuf};
pub fn get_hash_of_file(mut open_file: &File) -> Result<String, ClineupError> {
let mut hasher = Sha256::new();
let mut buffer = [0u8; 1024];
loop {
match open_file.read(&mut buffer) {
Ok(0) => break, Ok(bytes_read) => {
hasher.update(&buffer[..bytes_read]);
}
Err(_) => {
return Err(ClineupError::HashError(
"Something went wrong reading buffer of file".to_string(),
))
}
}
}
let result = hasher.finalize();
Ok(format!("{:x}", result))
}
pub struct DuplicatesFinder {
_duplicates: HashMap<u64, Vec<String>>,
}
impl DuplicatesFinder {
pub fn new() -> Self {
DuplicatesFinder {
_duplicates: HashMap::new(),
}
}
}
impl Default for DuplicatesFinder {
fn default() -> Self {
Self::new()
}
}
impl DuplicatesFinder {
pub fn is_duplicate(&mut self, path: &PathBuf) -> Result<bool, ClineupError> {
let metadata = std::fs::metadata(path)?;
if metadata.is_dir() {
return Ok(false);
}
if metadata.len() == 0 {
return Ok(false);
}
let open_file = File::open(path)?;
let hash_of_file = get_hash_of_file(&open_file)?;
if let std::collections::hash_map::Entry::Vacant(e) = self._duplicates.entry(metadata.len())
{
e.insert(vec![hash_of_file]);
return Ok(false);
}
if let Some(duplicates) = self._duplicates.get_mut(&metadata.len()) {
if !duplicates.contains(&hash_of_file) {
duplicates.push(hash_of_file);
return Ok(false);
}
} else {
return Ok(false);
}
Ok(true)
}
}