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
87
88
89
use std::path::{Path, PathBuf};
use std::time::{SystemTime, UNIX_EPOCH};
use anyhow::{anyhow, Result};
use crate::data::{File, GeneralHash};

pub trait LexicalAbsolute {
    fn to_lexical_absolute(&self) -> std::io::Result<PathBuf>;
}

impl LexicalAbsolute for PathBuf {
    fn to_lexical_absolute(&self) -> std::io::Result<PathBuf> {
        let mut absolute = if self.is_absolute() {
            PathBuf::new()
        } else {
            std::env::current_dir()?
        };
        for component in self.components() {
            match component {
                std::path::Component::CurDir => {},
                std::path::Component::ParentDir => { absolute.pop(); },
                component @ _ => absolute.push(component.as_os_str()),
            }
        }
        Ok(absolute)
    }
}

pub fn hash_file<T>(mut reader: T, hash: &mut GeneralHash) -> Result<u64>
where T: std::io::Read {

    let mut hasher = hash.hasher();
    let mut buffer = [0; 4096];
    let mut content_size = 0;

    loop {
        let bytes_read = reader.read(&mut buffer)?;
        content_size += bytes_read as u64;
        if bytes_read == 0 {
            break;
        }
        hasher.update(&buffer[..bytes_read]);
    }

    *hash = hasher.finalize();

    Ok(content_size)
}

pub fn hash_directory<'a>(children: impl Iterator<Item = &'a File>, hash: &mut GeneralHash) -> Result<u64> {
    let mut hasher = hash.hasher();

    let mut content_size = 0;

    for child in children {
        content_size += 1;
        hasher.update(child.get_content_hash().as_bytes());
    }

    *hash = hasher.finalize();

    Ok(content_size)
}

pub fn hash_path(path: &Path, hash: &mut GeneralHash) -> Result<()> {
    let mut hasher = hash.hasher();

    hasher.update(path.as_os_str().as_encoded_bytes());

    *hash = hasher.finalize();

    Ok(())
}

pub fn decode_hex(s: &str) -> Result<Vec<u8>> {
    if s.len() % 2 != 0 {
        return Err(anyhow!("Invalid hex length"));
    }
    (0..s.len())
        .step_by(2)
        .map(|i| u8::from_str_radix(&s[i..i + 2], 16)
            .map_err(|e| anyhow!("Failed to parse hex: {}", e)))
        .collect()
}

pub fn get_time() -> u64 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .map(|d| d.as_secs()).unwrap_or(0)
}