1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::path::Path;
use crate::utils::{log, LogLevel};
use std::collections::HashMap;
use md5;

fn hash_u8(v: &[u8]) -> String {
    let digest = md5::compute(v);
    return format!("{:x}", digest);
}

fn hash_file(path: &str) -> String {
    let mut file = File::open(path).unwrap();
    let mut contents = Vec::new();
    file.read_to_end(&mut contents).unwrap();
    return hash_u8(&contents);
}

pub fn get_hash(path: &str, path_hash: &HashMap<String, String>) -> Option<String> {
    if path_hash.contains_key(path) {
        return Some(path_hash.get(path).unwrap().to_string());
    }
    return 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());
    }
    return 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();
    for (path, hash) in path_hash {
        let line = format!("{} {}\n", path, hash);
        file.write(line.as_bytes()).unwrap();
    }
    log(LogLevel::Debug, &format!("Saved hashes to file: {:?}", path_hash));
}

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);
    let result = hash != new_hash;
    if result {
        log(LogLevel::Debug, &format!("File changed, updating hash for file: {}", path));
        log(LogLevel::Debug, &format!("\tOld hash: {}", hash));
        log(LogLevel::Debug, &format!("\tNew hash: {}", new_hash));
    }
    result
}

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);
        return;
    }
}