shelter_storage/filesystem/
mod.rs

1use 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    // super block file name
21    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, // used to encrypt super block
30            data_key: None,   // used to encrypt data block
31            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        // Load super block
76        self.load_super_block();
77
78        // Init crypto
79        self.data_key = Some(self.super_block.get_data_key());
80        self.master_key = Some(self.super_block.get_master_key(password));
81
82        // Check base directory
83
84        // Return payload
85        self.super_block.body.payload.clone()
86    }
87
88    #[inline]
89    fn init(&mut self, password: &[u8], payload: &[u8]) {
90        // Create base directory
91        vio::create_dir_all(&self.base).expect("Failed to create base directory");
92
93        // Init super block (salt)
94        self.super_block.init();
95
96        // Init crypto
97        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        // Save super block with payload
103        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.write_all(&data).unwrap();
127        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}