doctor_diff_core/
utils.rs1use 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}