fencryption_lib/commands/
decrypt_file.rs1use std::{fs, iter::zip, path::PathBuf, sync::mpsc::channel, time};
4
5use threadpool::ThreadPool;
6
7use crate::{
8 commands::{logic, Command, Error, ErrorBuilder, Result},
9 crypto::Crypto,
10 walk_dir::walk_dir,
11};
12
13pub fn execute(
15 key: &String,
16 paths: &Vec<PathBuf>,
17 output_path: &Option<PathBuf>,
18 overwrite: &bool,
19 delete_original: &bool,
20) -> Result<(
21 u32,
22 Vec<(PathBuf, Error)>,
23 Vec<(PathBuf, Error)>,
24 time::Duration,
25)> {
26 let timer = time::SystemTime::now();
27
28 let output_paths = logic::get_output_paths(&paths, &output_path, Command::DecryptFile);
29
30 logic::checks(&paths, &output_path)?;
31 logic::overwrite(&output_paths, *overwrite)?;
32
33 let mut success: u32 = 0;
34 let mut failures: Vec<(PathBuf, Error)> = Vec::new();
35 let mut skips: Vec<(PathBuf, Error)> = Vec::new();
36
37 let crypto = Crypto::new(key).map_err(|e| {
38 ErrorBuilder::new()
39 .message("Failed to initialize encryption utils")
40 .error(e)
41 .build()
42 })?;
43
44 for (main_input_path, main_output_path) in zip(paths.to_owned(), output_paths) {
45 match main_input_path.to_owned() {
46 dir_path if dir_path.is_dir() => {
47 fs::create_dir(&main_output_path).map_err(|e| {
48 ErrorBuilder::new()
49 .message("Failed to create output directory")
50 .error(e)
51 .build()
52 })?;
53
54 let walk_dir = walk_dir(&dir_path).map_err(|e| {
55 ErrorBuilder::new()
56 .message("Failed to read directory")
57 .error(e)
58 .build()
59 })?;
60
61 let threadpool = ThreadPool::new(8);
62 let (tx, rx) = channel();
63 let mut tries_n = 0;
64
65 for dir_entry in walk_dir {
66 let entry = dir_entry.map_err(|e| {
67 ErrorBuilder::new()
68 .message("Failed to read directory entry")
69 .error(e)
70 .build()
71 })?;
72 let input_path = entry.path();
73
74 match input_path {
75 input_path if input_path.is_file() => {
76 tries_n += 1;
77
78 let crypto = crypto.clone();
79 let tx = tx.clone();
80 let output_dir_path = main_output_path.clone();
81
82 threadpool.execute(move || {
83 let result = logic::decrypt_file(
84 crypto,
85 &input_path,
86 logic::OutputDecPath::Parent(output_dir_path),
87 );
88 tx.send((input_path.to_owned(), result)).unwrap();
89 });
90 }
91 input_path => {
92 if !input_path.is_dir() {
93 skips.push((
94 input_path,
95 ErrorBuilder::new().message("Unknown entry type").build(),
96 ));
97 }
98 }
99 }
100 }
101
102 threadpool.join();
103 rx.iter()
104 .take(tries_n)
105 .for_each(|(path, result)| match result {
106 Ok(_) => success += 1,
107 Err(e) => failures.push((path, e)),
108 })
109 }
110 path if path.is_file() => {
111 match logic::decrypt_file(
112 crypto.to_owned(),
113 &path,
114 logic::OutputDecPath::Direct(main_output_path.to_owned()),
115 ) {
116 Ok(_) => success += 1,
117 Err(e) => failures.push((path, e)),
118 };
119 }
120 path => skips.push((
121 path,
122 ErrorBuilder::new().message("Unknown entry type").build(),
123 )),
124 }
125
126 logic::delete_original(&main_input_path, *delete_original)?;
127 }
128
129 Ok((
130 success,
131 failures,
132 skips,
133 timer.elapsed().map_err(|e| {
134 ErrorBuilder::new()
135 .message("Failed to get elapsed time")
136 .error(e)
137 .build()
138 })?,
139 ))
140}