1
#![allow(unused_variables)]
2
use super::Result;
3
use crate::repository::backend::common::sync_backend::{
4
    BackendHandle, SyncBackend, SyncIndex, SyncManifest,
5
};
6
use crate::repository::backend::{
7
    Chunk, ChunkID, ChunkSettings, DateTime, EncryptedKey, FixedOffset, SegmentDescriptor,
8
    StoredArchive,
9
};
10
use crate::repository::Key;
11

12
use semver::Version;
13
use uuid::Uuid;
14

15
use std::collections::HashSet;
16
use std::fs::{File, OpenOptions};
17
use std::path::Path;
18

19
pub use super::common::generic_flatfile::GenericFlatFile;
20

21
#[repr(transparent)]
22
#[derive(Debug)]
23
pub struct FlatFile(GenericFlatFile<File>);
24

25
impl FlatFile {
26
    /// Constructs a flatfile and wraps it
27
    ///
28
    /// See the documentation for `GenericFlatFile::new_raw` for further details
29 1
    pub fn new(
30
        repository_path: impl AsRef<Path>,
31
        settings: Option<ChunkSettings>,
32
        enc_key: Option<EncryptedKey>,
33
        key: Key,
34
        queue_depth: usize,
35
    ) -> Result<BackendHandle<FlatFile>> {
36 1
        let path = repository_path.as_ref().to_owned();
37 1
        let file = OpenOptions::new()
38
            .read(true)
39
            .write(true)
40
            .create(true)
41 1
            .open(&path)?;
42 1
        let flat_file = GenericFlatFile::new_raw(file, path, settings, key, enc_key)?;
43 1
        Ok(BackendHandle::new(queue_depth, move || FlatFile(flat_file)))
44
    }
45

46
    /// Attempts to read the key from the flatfile repo at a given path
47 0
    pub fn load_encrypted_key(repository_path: impl AsRef<Path>) -> Result<EncryptedKey> {
48 0
        let path = repository_path.as_ref().to_owned();
49 0
        let file = OpenOptions::new().read(true).open(&path)?;
50 0
        GenericFlatFile::load_encrypted_key(file)
51
    }
52
}
53

54
impl SyncManifest for FlatFile {
55
    type Iterator = std::vec::IntoIter<StoredArchive>;
56 0
    fn last_modification(&mut self) -> Result<DateTime<FixedOffset>> {
57 0
        self.0.last_modification()
58
    }
59 0
    fn chunk_settings(&mut self) -> ChunkSettings {
60 0
        self.0.chunk_settings()
61
    }
62 1
    fn archive_iterator(&mut self) -> Self::Iterator {
63 1
        self.0.archive_iterator()
64
    }
65 0
    fn write_chunk_settings(&mut self, settings: ChunkSettings) -> Result<()> {
66 0
        self.0.write_chunk_settings(settings)
67
    }
68 1
    fn write_archive(&mut self, archive: StoredArchive) -> Result<()> {
69 1
        self.0.write_archive(archive)
70
    }
71 0
    fn touch(&mut self) -> Result<()> {
72 0
        self.0.touch()
73
    }
74 0
    fn seen_versions(&mut self) -> HashSet<(Version, Uuid)> {
75 0
        self.0.seen_versions()
76
    }
77
}
78

79
impl SyncIndex for FlatFile {
80 1
    fn lookup_chunk(&mut self, id: ChunkID) -> Option<SegmentDescriptor> {
81 1
        self.0.lookup_chunk(id)
82
    }
83 1
    fn set_chunk(&mut self, id: ChunkID, location: SegmentDescriptor) -> Result<()> {
84 1
        self.0.set_chunk(id, location)
85
    }
86 0
    fn known_chunks(&mut self) -> HashSet<ChunkID> {
87 0
        self.0.known_chunks()
88
    }
89 1
    fn commit_index(&mut self) -> Result<()> {
90 1
        self.0.commit_index()
91
    }
92 0
    fn chunk_count(&mut self) -> usize {
93 0
        self.0.chunk_count()
94
    }
95
}
96

97
impl SyncBackend for FlatFile {
98
    type SyncManifest = Self;
99
    type SyncIndex = Self;
100 1
    fn get_index(&mut self) -> &mut Self::SyncIndex {
101 0
        self
102
    }
103 1
    fn get_manifest(&mut self) -> &mut Self::SyncManifest {
104 0
        self
105
    }
106 0
    fn write_key(&mut self, key: EncryptedKey) -> Result<()> {
107 0
        self.0.write_key(key)
108
    }
109 1
    fn read_key(&mut self) -> Result<EncryptedKey> {
110 1
        self.0.read_key()
111
    }
112 1
    fn read_chunk(&mut self, location: SegmentDescriptor) -> Result<Chunk> {
113 1
        self.0.read_chunk(location)
114
    }
115 1
    fn write_chunk(&mut self, chunk: Chunk) -> Result<SegmentDescriptor> {
116 1
        self.0.write_chunk(chunk)
117
    }
118
}
119

120
#[cfg(test)]
121
mod tests {
122
    use super::*;
123
    use crate::repository::backend::Backend;
124
    use crate::repository::{Encryption, Key};
125
    use tempfile::tempdir;
126

127
    fn setup() -> (Key, EncryptedKey, ChunkSettings) {
128
        let key = Key::random(32);
129
        let pass = b"A Very strong password";
130
        let enc_key = EncryptedKey::encrypt(&key, 512, 1, Encryption::new_aes256ctr(), pass);
131
        (key, enc_key, ChunkSettings::lightweight())
132
    }
133

134
    // Create a new flatfile with a key and some settings, drop it, reload it, and check to see if
135
    // the key we read back is the same
136
    #[test]
137
    fn key_store_load() {
138
        smol::block_on(async {
139
            let (key, enc_key, settings) = setup();
140
            let directory = tempdir().unwrap();
141
            let file = directory.path().join("temp.asuran");
142
            // Generate the flatfile, close it, and drop it
143
            let mut flatfile =
144
                FlatFile::new(&file, Some(settings), Some(enc_key), key.clone(), 4).unwrap();
145
            flatfile.close().await;
146
            // Load it back up
147
            let flatfile = FlatFile::new(&file, None, None, key.clone(), 4).unwrap();
148
            // get the key
149
            let new_key = flatfile
150
                .read_key()
151
                .await
152
                .expect("Could not read key")
153
                .decrypt(b"A Very strong password")
154
                .expect("Could not decrypt key");
155

156
            assert_eq!(key, new_key);
157
        });
158
    }
159
}

Read our documentation on viewing source code .

Loading