forked from WithAutonomi/self_encryption
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparallel_streaming_decryptor.rs
More file actions
120 lines (103 loc) · 3.47 KB
/
Copy pathparallel_streaming_decryptor.rs
File metadata and controls
120 lines (103 loc) · 3.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use bytes::Bytes;
use clap::Parser;
use rayon::prelude::*;
use self_encryption::{deserialize, streaming_decrypt, DataMap, Error, Result};
use std::{
fs::File,
io::{Read, Write},
path::Path,
};
use xor_name::XorName;
/// Parallel streaming decryptor for self-encrypted files
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
/// Path to the data map file
#[arg(short, long, required = true)]
data_map: String,
/// Directory containing the encrypted chunks
#[arg(short, long, required = true)]
chunks_dir: String,
/// Path where the decrypted file should be written
#[arg(short, long, required = true)]
output: String,
}
fn validate_paths(args: &Args) -> Result<()> {
if !Path::new(&args.data_map).exists() {
return Err(Error::Generic(format!(
"Data map file does not exist: {}",
args.data_map
)));
}
let chunks_dir = Path::new(&args.chunks_dir);
if !chunks_dir.exists() {
return Err(Error::Generic(format!(
"Chunks directory does not exist: {}",
args.chunks_dir
)));
}
if !chunks_dir.is_dir() {
return Err(Error::Generic(format!(
"Chunks path is not a directory: {}",
args.chunks_dir
)));
}
let output_path = Path::new(&args.output);
if let Some(parent) = output_path.parent() {
if !parent.exists() {
return Err(Error::Generic(format!(
"Output directory does not exist: {}",
parent.display()
)));
}
if !parent
.metadata()
.map(|m| m.permissions().readonly())
.unwrap_or(true)
{
return Err(Error::Generic(format!(
"Output directory is not writable: {}",
parent.display()
)));
}
}
Ok(())
}
fn main() -> Result<()> {
let args = Args::parse();
validate_paths(&args)?;
let data_map = load_data_map(&args.data_map)?;
let get_chunk_parallel = |hashes: &[(usize, XorName)]| -> Result<Vec<(usize, Bytes)>> {
hashes
.par_iter()
.map(|(i, hash)| {
let chunk_path = Path::new(&args.chunks_dir).join(hex::encode(hash));
let mut chunk_data = Vec::new();
File::open(&chunk_path)
.and_then(|mut file| file.read_to_end(&mut chunk_data))
.map_err(|e| Error::Generic(format!("Failed to read chunk: {e}")))?;
Ok((*i, Bytes::from(chunk_data)))
})
.collect()
};
// Use the streaming decryption iterator
let stream = streaming_decrypt(&data_map, get_chunk_parallel)?;
let mut output_file = File::create(&args.output)
.map_err(|e| Error::Generic(format!("Failed to create output file: {e}")))?;
for chunk_result in stream {
let chunk = chunk_result?;
output_file
.write_all(&chunk)
.map_err(|e| Error::Generic(format!("Failed to write output: {e}")))?;
}
println!("Successfully decrypted file to: {}", args.output);
Ok(())
}
fn load_data_map(path: &str) -> Result<DataMap> {
let mut file =
File::open(path).map_err(|e| Error::Generic(format!("Failed to open data map: {e}")))?;
let mut data = Vec::new();
file.read_to_end(&mut data)
.map_err(|e| Error::Generic(format!("Failed to read data map: {e}")))?;
deserialize(&data)
}