doctor_diff_core/
utils.rs

1use crate::hash::HashValue;
2use ring::digest::{Context, SHA256};
3use std::{
4    collections::HashMap,
5    fs::{read_dir, File},
6    io::Read,
7    io::Result,
8    path::{Path, PathBuf},
9};
10
11pub fn hash_directory<P>(path: P) -> Result<HashMap<PathBuf, HashValue>>
12where
13    P: AsRef<Path>,
14{
15    let mut result = HashMap::new();
16    hash_directory_inner(Path::new("").as_ref(), path.as_ref(), &mut result)?;
17    Ok(result)
18}
19
20fn hash_directory_inner<P>(root: P, path: P, result: &mut HashMap<PathBuf, HashValue>) -> Result<()>
21where
22    P: AsRef<Path>,
23{
24    let root = root.as_ref();
25    let path = path.as_ref();
26    if path.is_dir() {
27        for entry in read_dir(path)? {
28            let entry = entry?;
29            let root = root.join(entry.file_name());
30            let path = path.join(entry.file_name());
31            if path.is_dir() {
32                hash_directory_inner(root, path, result)?;
33            } else {
34                let hash = sha256_stream(File::open(&path)?)?;
35                result.insert(root.to_owned(), hash);
36            }
37        }
38    }
39    Ok(())
40}
41
42pub fn sha256_stream<R>(mut reader: R) -> Result<HashValue>
43where
44    R: Read,
45{
46    let mut context = Context::new(&SHA256);
47    let mut buffer = [0; 1024];
48    loop {
49        let count = reader.read(&mut buffer)?;
50        if count == 0 {
51            break;
52        }
53        context.update(&buffer[..count]);
54    }
55    Ok(HashValue(context.finish().as_ref().to_vec()))
56}