use crate::utils::log::{log, LogLevel};
use sha1::{Digest, Sha1};
use std::collections::HashMap;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::path::Path;
fn hash_file(path: &str) -> String {
let mut file = File::open(path).unwrap();
const CHUNK_SIZE: usize = 1024 * 1024;
let mut limit = file
.metadata()
.unwrap_or_else(|why| {
log(
LogLevel::Error,
&format!("Failed to get length for file: {}", path),
);
log(LogLevel::Error, &format!("Error: {}", why));
std::process::exit(1);
})
.len();
let mut buffer = [0; CHUNK_SIZE];
let mut hasher = Sha1::new();
while limit > 0 {
let read_size = if limit < CHUNK_SIZE as u64 {
limit as usize
} else {
CHUNK_SIZE
};
let read = file.read(&mut buffer[0..read_size]).unwrap();
if read == 0 {
break;
}
limit -= read as u64;
hasher.update(&buffer[0..read]);
}
let result = hasher.finalize();
let mut hash = String::new();
for byte in result {
hash.push_str(&format!("{:02x}", byte));
}
hash
}
pub fn get_hash(path: &str, path_hash: &HashMap<String, String>) -> Option<String> {
if path_hash.contains_key(path) {
Some(path_hash.get(path).unwrap().to_string())
} else {
None
}
}
pub fn load_hashes_from_file(path: &str) -> HashMap<String, String> {
let mut path_hash: HashMap<String, String> = HashMap::new();
let path = Path::new(path);
if !path.exists() {
return path_hash;
}
let mut file = OpenOptions::new().read(true).open(path).unwrap();
let mut contents = String::new();
file.read_to_string(&mut contents).unwrap();
for line in contents.lines() {
if line.is_empty() {
continue;
}
let mut split = line.split(' ');
let path = split.next().unwrap();
let hash = split.next().unwrap();
path_hash.insert(path.to_string(), hash.to_string());
}
path_hash
}
pub fn save_hashes_to_file(path: &str, path_hash: &HashMap<String, String>) {
let mut file = OpenOptions::new()
.write(true)
.create(true)
.open(path)
.unwrap_or_else(|_| {
log(LogLevel::Error, &format!("Failed to open file: {}", path));
std::process::exit(1);
});
for (path, hash) in path_hash {
let line = format!("{} {}\n", path, hash);
file.write_all(line.as_bytes()).unwrap();
}
}
pub fn is_file_changed(path: &str, path_hash: &HashMap<String, String>) -> bool {
let hash = get_hash(path, path_hash);
if hash.is_none() {
return true;
}
let hash = hash.unwrap();
let new_hash = hash_file(path);
hash != new_hash
}
pub fn save_hash(path: &str, path_hash: &mut HashMap<String, String>) {
let new_hash = hash_file(path);
let hash = get_hash(path, path_hash);
if hash.is_none() {
path_hash.insert(path.to_string(), new_hash);
return;
}
let hash = hash.unwrap();
if hash != new_hash {
log(
LogLevel::Info,
&format!("File changed, updating hash for file: {}", path),
);
path_hash.insert(path.to_string(), new_hash);
}
}