shelter_storage/filesystem/
mod.rs1use crate::SuperBlock;
2use crate::{vio, Crypto, CryptoUtil, SecretKey, Storage};
3use moka::sync::Cache;
4use std::fs::{remove_file, File};
5use std::io::prelude::*;
6use std::path::{Path, PathBuf};
7
8pub struct FileSystem<C: Crypto + serde::Serialize> {
9 base: PathBuf,
10 super_block: SuperBlock<C>,
11 master_key: Option<SecretKey>,
12 data_key: Option<SecretKey>,
13 cache: Cache<String, Vec<u8>>,
14}
15
16impl<C: Crypto> FileSystem<C>
17where
18 C: serde::de::DeserializeOwned,
19{
20 const SUPER_BLK_FILE_NAME: &'static str = "super_blk";
22
23 pub fn new(base: &Path, crypto: C, cache_size: u64) -> Self {
24 let super_block = SuperBlock::new(crypto);
25 let cache = Cache::new(cache_size);
26 Self {
27 base: base.to_path_buf(),
28 super_block,
29 master_key: None, data_key: None, cache,
32 }
33 }
34
35 #[inline]
36 fn get_data_key(&self) -> &SecretKey {
37 self.data_key
38 .as_ref()
39 .expect("init() need to be call first")
40 }
41
42 #[inline]
43 fn get_master_key(&self) -> &SecretKey {
44 self.master_key
45 .as_ref()
46 .expect("init() need to be call first")
47 }
48
49 #[inline]
50 fn save_super_block(&mut self) {
51 let master_key = self.get_master_key();
52 let data = self.super_block.serialize(master_key);
53 self.put_block(Self::SUPER_BLK_FILE_NAME, &data);
54 }
55
56 #[inline]
57 fn load_super_block(&mut self) {
58 let data: Vec<u8> = self.get_block(Self::SUPER_BLK_FILE_NAME);
59 let master_key = self.get_master_key();
60 self.super_block = SuperBlock::deserialize(&data, master_key);
61 }
62}
63
64impl<C: Crypto> Storage for FileSystem<C>
65where
66 C: serde::de::DeserializeOwned,
67{
68 #[inline]
69 fn connect(&mut self) {
70 unimplemented!();
71 }
72
73 #[inline]
74 fn open(&mut self, password: &[u8]) -> Vec<u8> {
75 self.load_super_block();
77
78 self.data_key = Some(self.super_block.get_data_key());
80 self.master_key = Some(self.super_block.get_master_key(password));
81
82 self.super_block.body.payload.clone()
86 }
87
88 #[inline]
89 fn init(&mut self, password: &[u8], payload: &[u8]) {
90 vio::create_dir_all(&self.base).expect("Failed to create base directory");
92
93 self.super_block.init();
95
96 let data_key: SecretKey = CryptoUtil::gen_secret_key();
98 self.super_block.set_data_key(&data_key);
99 self.data_key = Some(data_key);
100 self.master_key = Some(self.super_block.get_master_key(password));
101
102 self.save_payload(payload);
104 }
105
106 #[inline]
107 fn is_init(&self) -> bool {
108 self.is_exist(Self::SUPER_BLK_FILE_NAME)
109 }
110
111 #[inline]
112 fn save_payload(&mut self, payload: &[u8]) {
113 self.super_block.set_payload(payload);
114 self.save_super_block();
115 }
116
117 #[inline]
118 fn put_block(&mut self, cid: &str, data: &[u8]) {
119 let mut file = File::create(self.base.join(cid)).unwrap();
120 let ciphertext = self
121 .super_block
122 .head
123 .crypto
124 .encrypt_with_key(self.get_data_key(), data);
125 file.write_all(&ciphertext).unwrap();
126 file.sync_data().unwrap();
128 }
129
130 #[inline]
131 fn get_block(&self, cid: &str) -> Vec<u8> {
132 let buf = self.cache.get(&cid.to_owned()).unwrap_or_else(|| {
133 let mut buf = Vec::new();
134 let mut file = File::open(self.base.join(cid)).unwrap();
135 file.read_to_end(&mut buf).unwrap();
136 buf
137 });
138 self.super_block
139 .head
140 .crypto
141 .decrypt_with_key(self.get_data_key(), &buf)
142 }
143
144 #[inline]
145 fn del_block(&mut self, cid: &str) {
146 remove_file(cid).unwrap();
147 }
148
149 #[inline]
150 fn is_exist(&self, cid: &str) -> bool {
151 Path::new(cid).exists()
152 }
153
154 #[inline]
155 fn flush(&mut self) {
156 unimplemented!();
157 }
158
159 #[inline]
160 fn destroy(&mut self) {
161 vio::remove_dir(&self.base).expect("Failed to remove base directory");
162 }
163}