duplicate_finder/
hashing.rs1use crate::{constants, file_info::FileInfo, output_msg::OutputMsg};
2use siphasher::sip128::Hasher128;
3use std::{fs::File, hash::Hasher, io::Read, path::PathBuf, sync::mpsc::Sender, sync::Arc};
4
5pub struct CalculateHash {
6 file: File,
7 hasher: siphasher::sip128::SipHasher,
8 path_buf: Arc<PathBuf>,
9 progress_in_bytes: u64,
10 size_in_bytes: u64,
11 sender: Sender<OutputMsg>,
12}
13
14impl CalculateHash {
15 pub fn new(path_buf: PathBuf, sender: Sender<OutputMsg>) -> Self {
16 let file = File::open(&path_buf).expect("can not read file");
17 let size_in_bytes = file.metadata().unwrap().len();
18
19 let path_buf = Arc::new(path_buf);
20
21 CalculateHash {
22 file,
23 hasher: siphasher::sip128::SipHasher::new(),
24 path_buf,
25 progress_in_bytes: 0,
26 size_in_bytes,
27 sender,
28 }
29 }
30
31 fn send_output_msg(&mut self, progress: OutputMsg) {
32 match self.sender.send(progress) {
33 Ok(_) => (),
34 Err(e) => panic!("Error sending data with mpsc : {}", e),
35 }
36 }
37
38 pub fn calculate(&mut self) -> FileInfo {
39 loop {
40 let mut chunk = Vec::with_capacity(constants::HASHING_CHUNK_SIZE);
41 let size = self
42 .file
43 .by_ref()
44 .take(constants::HASHING_CHUNK_SIZE as u64)
45 .read_to_end(&mut chunk)
46 .expect("Can't read chunk.");
47
48 if size == 0 {
49 let hash_128 = self.hasher.finish128();
50
51 let file_info = FileInfo {
52 path: self.path_buf.clone(),
53 hash: hash_128.into(),
54 };
55
56 self.send_output_msg(OutputMsg::Summary);
57
58 return file_info;
59 }
60
61 self.progress_in_bytes += size as u64;
62
63 self.send_output_msg(OutputMsg::FileProgress(
64 self.progress_in_bytes * 100 / self.size_in_bytes,
65 self.path_buf.clone(),
66 ));
67
68 self.hasher.write(&chunk);
69 }
70 }
71}