hash_dir/
lib.rs

1use md5::{Digest, Md5};
2use std::collections::HashMap;
3use std::env;
4use std::fs::{self, File};
5use std::io;
6use std::path::{self, Path, PathBuf};
7
8#[derive(Debug)]
9pub struct Config {
10    pub dir: String,
11    pub output_file: String,
12}
13
14impl Config {
15    pub fn new(mut args: env::Args) -> Result<Config, &'static str> {
16        args.next();
17
18        let dir = match args.next() {
19            Some(arg) => arg,
20            None => return Err("no dir"),
21        };
22
23        let output_file = match args.next() {
24            Some(arg) => arg,
25            None => return Err("no output_file"),
26        };
27
28        Ok(Config { dir, output_file })
29    }
30}
31
32#[derive(Debug)]
33pub struct HashInfo {
34    pub path: PathBuf,
35    pub hash: String,
36}
37
38pub fn dir_files(dir: &Path) -> io::Result<HashMap<String, HashInfo>> {
39    let mut files: HashMap<String, HashInfo> = HashMap::new();
40    visit_dirs(dir, "", &mut |key, path: PathBuf| {
41        files.insert(
42            key,
43            HashInfo {
44                path,
45                hash: String::new(),
46            },
47        );
48    })?;
49    Ok(files)
50}
51
52fn visit_dirs(dir: &Path, prefix: &str, cb: &mut dyn FnMut(String, PathBuf)) -> io::Result<()> {
53    if dir.is_dir() {
54        for entry in fs::read_dir(dir)? {
55            let entry = entry?;
56            let path = entry.path();
57            let file_name = entry.file_name().into_string().unwrap();
58
59            if path.is_dir() {
60                let prefix = prefix.to_string() + &file_name + path::MAIN_SEPARATOR_STR;
61                visit_dirs(&path, &prefix, cb)?;
62            } else {
63                let key = format!("{}{}", prefix, &file_name);
64                cb(key, path);
65            }
66        }
67    }
68    Ok(())
69}
70
71pub fn md5_file<P>(path: P) -> io::Result<String>
72where
73    P: AsRef<Path>,
74{
75    let mut hasher = Md5::new();
76
77    let mut file: fs::File = File::open(path)?;
78    io::copy(&mut file, &mut hasher)?;
79    let hash = hasher.finalize();
80    Ok(hex::encode(hash))
81}
82
83pub fn sorted_hash_result(files: &HashMap<String, HashInfo>) -> String {
84    let mut keys: Vec<_> = files.keys().collect();
85    keys.sort();
86    let mut text = String::new();
87    for key in keys.into_iter() {
88        let hash = &files[key].hash;
89        text += &format!("{} {}\n", hash, key);
90    }
91    text
92}