diff --git a/src/backups/mod.rs b/src/backups/mod.rs index 33d1fd2..5b1709e 100644 --- a/src/backups/mod.rs +++ b/src/backups/mod.rs @@ -4,29 +4,37 @@ use ::prelude::*; use std::path::{Path, PathBuf}; use std::collections::HashMap; +use std::sync::Arc; pub struct BackupRepository { + layout: Arc, repo: Repository } impl BackupRepository { pub fn create, R: AsRef>(path: P, config: &Config, remote: R) -> Result { + let layout = Arc::new(RepositoryLayout::new(path.as_ref())); Ok(BackupRepository { - repo: try!(Repository::create(path, config, remote)) + layout: layout.clone(), + repo: try!(Repository::create(layout, config, remote)) }) } #[allow(unknown_lints, useless_let_if_seq)] pub fn open>(path: P, online: bool) -> Result { + let layout = Arc::new(RepositoryLayout::new(path.as_ref())); Ok(BackupRepository { - repo: try!(Repository::open(path, online)) + layout: layout.clone(), + repo: try!(Repository::open(layout, online)) }) } pub fn import, R: AsRef>(path: P, remote: R, key_files: Vec) -> Result { + let layout = Arc::new(RepositoryLayout::new(path.as_ref())); Ok(BackupRepository { - repo: try!(Repository::import(path, remote, key_files)) + layout: layout.clone(), + repo: try!(Repository::import(layout, remote, key_files)) }) } @@ -77,7 +85,7 @@ impl BackupRepository { } pub fn get_layout(&self) -> &RepositoryLayout { - &self.repo.layout + &self.layout } pub fn create_backup_recursively>(&mut self, path: P, reference: Option<&Backup>, options: &BackupOptions) -> Result { diff --git a/src/prelude.rs b/src/prelude.rs index 26772cf..324fac2 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -5,7 +5,7 @@ pub use repository::chunking::{ChunkerType, Chunker, ChunkerStatus, ChunkerError pub use repository::{Repository, Backup, Config, RepositoryError, RepositoryInfo, Inode, FileType, IntegrityError, BackupFileError, BackupError, BackupOptions, BundleAnalysis, FileData, DiffType, InodeError, RepositoryLayout, Location, - RepositoryStatistics}; + RepositoryStatistics, ChunkRepositoryLayout}; pub use repository::index::{Index, IndexError, IndexStatistics}; pub use backups::mount::FuseFilesystem; pub use translation::CowStr; diff --git a/src/repository/bundledb/db.rs b/src/repository/bundledb/db.rs index 9879ff9..9ebb258 100644 --- a/src/repository/bundledb/db.rs +++ b/src/repository/bundledb/db.rs @@ -117,7 +117,7 @@ fn load_bundles( pub struct BundleDb { - pub layout: RepositoryLayout, + pub layout: Arc, uploader: Option>, crypto: Arc>, local_bundles: HashMap, @@ -127,7 +127,7 @@ pub struct BundleDb { impl BundleDb { - fn new(layout: RepositoryLayout, crypto: Arc>) -> Self { + fn new(layout: Arc, crypto: Arc>) -> Self { BundleDb { layout, crypto, @@ -239,7 +239,7 @@ impl BundleDb { } pub fn open( - layout: RepositoryLayout, + layout: Arc, crypto: Arc>, online: bool ) -> Result<(Self, Vec, Vec), BundleDbError> { @@ -251,7 +251,7 @@ impl BundleDb { Ok((self_, new, gone)) } - pub fn create(layout: &RepositoryLayout) -> Result<(), BundleDbError> { + pub fn create(layout: Arc) -> Result<(), BundleDbError> { try!(fs::create_dir_all(layout.remote_bundles_path()).context( &layout.remote_bundles_path() as &Path @@ -332,11 +332,14 @@ impl BundleDb { fn copy_remote_bundle_to_cache(&mut self, bundle: &StoredBundle) -> Result<(), BundleDbError> { let id = bundle.id(); - let (folder, filename) = self.layout.local_bundle_path(&id, self.local_bundles.len()); - try!(fs::create_dir_all(&folder).context(&folder as &Path)); + let dst_path = self.layout.local_bundle_path(&id, self.local_bundles.len()); + { + let folder = dst_path.parent().unwrap(); + try!(fs::create_dir_all(folder).context(folder as &Path)); + } let bundle = try!(bundle.copy_to( self.layout.base_path(), - folder.join(filename) + dst_path )); self.local_bundles.insert(id, bundle); Ok(()) @@ -347,8 +350,7 @@ impl BundleDb { if bundle.info.mode == BundleMode::Meta { try!(self.copy_remote_bundle_to_cache(&bundle)) } - let (folder, filename) = self.layout.remote_bundle_path(self.remote_bundles.len()); - let dst_path = folder.join(filename); + let dst_path = self.layout.remote_bundle_path(&bundle.id(),self.remote_bundles.len()); let src_path = self.layout.base_path().join(bundle.path); bundle.path = dst_path .strip_prefix(self.layout.base_path()) diff --git a/src/repository/layout.rs b/src/repository/layout.rs index def996f..a2d3692 100644 --- a/src/repository/layout.rs +++ b/src/repository/layout.rs @@ -2,6 +2,35 @@ use prelude::*; use std::path::{Path, PathBuf}; +pub trait ChunkRepositoryLayout { + fn base_path(&self) -> &Path; + + fn index_path(&self) -> PathBuf; + fn bundle_map_path(&self) -> PathBuf; + fn local_locks_path(&self) -> PathBuf; + fn remote_path(&self) -> PathBuf; + fn remote_exists(&self) -> bool; + fn remote_locks_path(&self) -> PathBuf; + fn remote_bundles_path(&self) -> PathBuf; + fn local_bundles_path(&self) -> PathBuf; + fn remote_bundle_path(&self, bundle: &BundleId, count: usize) -> PathBuf; + fn local_bundle_path(&self, bundle: &BundleId, count: usize) -> PathBuf; + fn temp_bundles_path(&self) -> PathBuf; + fn temp_bundle_path(&self) -> PathBuf; + fn local_bundle_cache_path(&self) -> PathBuf; + fn remote_bundle_cache_path(&self) -> PathBuf; + fn dirtyfile_path(&self) -> PathBuf; + + + fn config_path(&self) -> PathBuf; + fn keys_path(&self) -> PathBuf; + fn excludes_path(&self) -> PathBuf; + fn backups_path(&self) -> PathBuf; + fn backup_path(&self, name: &str) -> PathBuf; + fn remote_readme_path(&self) -> PathBuf; +} + + #[derive(Clone)] pub struct RepositoryLayout(PathBuf); @@ -10,39 +39,19 @@ impl RepositoryLayout { RepositoryLayout(path.as_ref().to_path_buf()) } - #[inline] - pub fn base_path(&self) -> &Path { - &self.0 - } - #[inline] pub fn config_path(&self) -> PathBuf { self.0.join("config.yaml") } - #[inline] - pub fn excludes_path(&self) -> PathBuf { - self.0.join("excludes") - } - - #[inline] - pub fn index_path(&self) -> PathBuf { - self.0.join("index") - } - #[inline] pub fn keys_path(&self) -> PathBuf { self.0.join("keys") } #[inline] - pub fn bundle_map_path(&self) -> PathBuf { - self.0.join("bundles.map") - } - - #[inline] - pub fn local_locks_path(&self) -> PathBuf { - self.0.join("locks") + pub fn excludes_path(&self) -> PathBuf { + self.0.join("excludes") } #[inline] @@ -55,11 +64,6 @@ impl RepositoryLayout { self.backups_path().join(format!("{}.backup", name)) } - #[inline] - pub fn remote_path(&self) -> PathBuf { - self.0.join("remote") - } - #[inline] pub fn remote_exists(&self) -> bool { self.remote_bundles_path().exists() && self.backups_path().exists() && @@ -71,27 +75,7 @@ impl RepositoryLayout { self.0.join("remote/README.md") } - #[inline] - pub fn remote_locks_path(&self) -> PathBuf { - self.0.join("remote/locks") - } - - #[inline] - pub fn remote_bundles_path(&self) -> PathBuf { - self.0.join("remote/bundles") - } - - #[inline] - pub fn local_bundles_path(&self) -> PathBuf { - self.0.join("bundles/cached") - } - - fn bundle_path( - &self, - bundle: &BundleId, - mut folder: PathBuf, - mut count: usize, - ) -> (PathBuf, PathBuf) { + fn bundle_path(&self, bundle: &BundleId, mut folder: PathBuf, mut count: usize) -> PathBuf { let file = bundle.to_string().to_owned() + ".bundle"; { let mut rest = &file as &str; @@ -104,44 +88,123 @@ impl RepositoryLayout { count /= 250; } } - (folder, file.into()) + folder.join(Path::new(&file)) + } + +} + + +impl ChunkRepositoryLayout for RepositoryLayout { + #[inline] + fn base_path(&self) -> &Path { + &self.0 } #[inline] - pub fn remote_bundle_path(&self, count: usize) -> (PathBuf, PathBuf) { + fn remote_exists(&self) -> bool { + self.remote_bundles_path().exists() && self.remote_locks_path().exists() + } + + #[inline] + fn index_path(&self) -> PathBuf { + self.0.join("index") + } + + #[inline] + fn bundle_map_path(&self) -> PathBuf { + self.0.join("bundles.map") + } + + #[inline] + fn local_locks_path(&self) -> PathBuf { + self.0.join("locks") + } + + #[inline] + fn remote_path(&self) -> PathBuf { + self.0.join("remote") + } + + #[inline] + fn remote_locks_path(&self) -> PathBuf { + self.0.join("remote/locks") + } + + #[inline] + fn remote_bundles_path(&self) -> PathBuf { + self.0.join("remote/bundles") + } + + #[inline] + fn local_bundles_path(&self) -> PathBuf { + self.0.join("bundles/cached") + } + + #[inline] + fn remote_bundle_path(&self, _bundle: &BundleId, count: usize) -> PathBuf { self.bundle_path(&BundleId::random(), self.remote_bundles_path(), count) } #[inline] - pub fn local_bundle_path(&self, bundle: &BundleId, count: usize) -> (PathBuf, PathBuf) { + fn local_bundle_path(&self, bundle: &BundleId, count: usize) -> PathBuf { self.bundle_path(bundle, self.local_bundles_path(), count) } #[inline] - pub fn temp_bundles_path(&self) -> PathBuf { + fn temp_bundles_path(&self) -> PathBuf { self.0.join("bundles/temp") } #[inline] - pub fn temp_bundle_path(&self) -> PathBuf { - self.temp_bundles_path().join( - BundleId::random().to_string().to_owned() + - ".bundle" - ) + fn temp_bundle_path(&self) -> PathBuf { + self.temp_bundles_path().join(BundleId::random().to_string().to_owned() + ".bundle") } #[inline] - pub fn local_bundle_cache_path(&self) -> PathBuf { + fn local_bundle_cache_path(&self) -> PathBuf { self.0.join("bundles/local.cache") } #[inline] - pub fn remote_bundle_cache_path(&self) -> PathBuf { + fn remote_bundle_cache_path(&self) -> PathBuf { self.0.join("bundles/remote.cache") } #[inline] - pub fn dirtyfile_path(&self) -> PathBuf { + fn dirtyfile_path(&self) -> PathBuf { self.0.join("dirty") } -} + + + + #[inline] + fn config_path(&self) -> PathBuf { + self.0.join("config.yaml") + } + + #[inline] + fn keys_path(&self) -> PathBuf { + self.0.join("keys") + } + + #[inline] + fn excludes_path(&self) -> PathBuf { + self.0.join("excludes") + } + + #[inline] + fn backups_path(&self) -> PathBuf { + self.0.join("remote/backups") + } + + #[inline] + fn backup_path(&self, name: &str) -> PathBuf { + self.backups_path().join(format!("{}.backup", name)) + } + + #[inline] + fn remote_readme_path(&self) -> PathBuf { + self.0.join("remote/README.md") + } + +} \ No newline at end of file diff --git a/src/repository/mod.rs b/src/repository/mod.rs index e385f9d..dcd793f 100644 --- a/src/repository/mod.rs +++ b/src/repository/mod.rs @@ -31,7 +31,7 @@ pub use self::backup::{BackupError, BackupOptions, DiffType}; pub use self::backup_file::{Backup, BackupFileError}; pub use self::integrity::IntegrityError; pub use self::info::{RepositoryInfo, BundleAnalysis, RepositoryStatistics}; -pub use self::layout::RepositoryLayout; +pub use self::layout::{RepositoryLayout, ChunkRepositoryLayout}; use self::bundle_map::BundleMap; @@ -74,7 +74,7 @@ impl index::Key for Hash { } pub struct Repository { - pub layout: RepositoryLayout, + pub layout: Arc, pub config: Config, index: Index, crypto: Arc>, @@ -93,12 +93,11 @@ pub struct Repository { impl Repository { - pub fn create, R: AsRef>( - path: P, + pub fn create>( + layout: Arc, config: &Config, remote: R, ) -> Result { - let layout = RepositoryLayout::new(path.as_ref().to_path_buf()); try!(fs::create_dir(layout.base_path())); try!(File::create(layout.excludes_path()).and_then(|mut f| { f.write_all(DEFAULT_EXCLUDES) @@ -113,7 +112,7 @@ impl Repository { )); try!(fs::create_dir_all(layout.remote_locks_path())); try!(config.save(layout.config_path())); - try!(BundleDb::create(&layout)); + try!(BundleDb::create(layout.clone())); try!(Index::::create( layout.index_path(), &INDEX_MAGIC, @@ -121,12 +120,11 @@ impl Repository { )); try!(BundleMap::create().save(layout.bundle_map_path())); try!(fs::create_dir_all(layout.backups_path())); - Self::open(path, true) + Self::open(layout, true) } #[allow(unknown_lints, useless_let_if_seq)] - pub fn open>(path: P, online: bool) -> Result { - let layout = RepositoryLayout::new(path.as_ref().to_path_buf()); + pub fn open(layout: Arc, online: bool) -> Result { if !layout.remote_exists() { return Err(RepositoryError::NoRemote); } @@ -220,17 +218,16 @@ impl Repository { Ok(repo) } - pub fn import, R: AsRef>( - path: P, + pub fn import>( + layout: Arc, remote: R, key_files: Vec, ) -> Result { - let path = path.as_ref(); - let mut repo = try!(Repository::create(path, &Config::default(), remote)); + let mut repo = try!(Repository::create(layout.clone(), &Config::default(), remote)); for file in key_files { try!(repo.crypto.lock().unwrap().register_keyfile(file)); } - repo = try!(Repository::open(path, true)); + repo = try!(Repository::open(layout, true)); let mut backups: Vec<(String, Backup)> = try!(repo.get_all_backups()).into_iter().collect(); backups.sort_by_key(|&(_, ref b)| b.timestamp); if let Some((name, backup)) = backups.pop() {