pub mod mount; mod backup_file; mod inode; mod tarfile; mod backup; mod integrity; mod vacuum; mod metadata; mod layout; pub use self::backup::{BackupOptions, BackupError, DiffType, RepositoryBackupIO, PruneOptions}; pub use self::backup_file::{BackupFile, BackupFileError}; pub use self::inode::{Inode, FileData, FileType, InodeError}; pub use self::integrity::{InodeIntegrityError, RepositoryIntegrityIO, CheckOptions, IntegrityReport}; pub use self::layout::BackupRepositoryLayout; pub use self::metadata::RepositoryMetadataIO; pub use self::vacuum::RepositoryVacuumIO; pub use self::tarfile::RepositoryTarfileIO; use ::prelude::*; use std::path::{Path, PathBuf}; use std::collections::HashMap; use std::sync::Arc; use std::fs::{self, File}; use std::io::Write; const DEFAULT_EXCLUDES: &[u8] = include_bytes!("../../docs/excludes.default"); pub struct BackupRepository(Repository); impl BackupRepository { pub fn create, R: AsRef>(path: P, config: &Config, remote: R) -> Result { let layout: Arc = Arc::new(path.as_ref().to_owned()); try!(fs::create_dir(layout.base_path())); try!(File::create(layout.excludes_path()).and_then(|mut f| { f.write_all(DEFAULT_EXCLUDES) })); try!(fs::create_dir_all(layout.backups_path())); try!(fs::create_dir(layout.keys_path())); let crypto = Arc::new(try!(Crypto::open(layout.keys_path()))); Ok(BackupRepository(try!(Repository::create(layout, config, crypto, remote)))) } #[allow(unknown_lints, clippy::useless_let_if_seq)] pub fn open>(path: P, online: bool) -> Result { let layout: Arc = Arc::new(path.as_ref().to_owned()); let crypto = Arc::new(try!(Crypto::open(layout.keys_path()))); Ok(BackupRepository(try!(Repository::open(layout, crypto, online)))) } pub fn import, R: AsRef>(path: P, remote: R, key_files: Vec) -> Result { let config = Config::default(); let mut repo = try!(Self::create(&path, &config, remote)); for file in key_files { try!(repo.0.get_crypto().register_keyfile(file)); } repo = try!(Self::open(&path, true)); let mut backups: Vec<(String, BackupFile)> = try!(repo.0.get_all_backups()).into_iter().collect(); backups.sort_by_key(|&(_, ref b)| b.timestamp); if let Some((name, backup)) = backups.pop() { tr_info!("Taking configuration from the last backup '{}'", name); repo.0.set_config(backup.config); try!(repo.save_config()) } else { tr_warn!( "No backup found in the repository to take configuration from, please set the configuration manually." ); } Ok(repo) } #[inline] pub fn has_backup(&self, name: &str) -> bool { self.0.has_backup(name) } #[inline] pub fn get_backup(&self, name: &str) -> Result { self.0.get_backup(name) } #[inline] pub fn register_key(&mut self, public: PublicKey, secret: SecretKey) -> Result<(), RepositoryError> { try!(self.0.get_crypto().register_secret_key(public, secret)); Ok(()) } #[inline] pub fn save_config(&mut self) -> Result<(), RepositoryError> { self.0.localwrite_mode(|r, l| r.save_config(l)) } #[inline] pub fn set_encryption(&mut self, public: Option<&PublicKey>) { self.0.set_encryption(public) } #[inline] pub fn get_config(&self) -> &Config { self.0.get_config() } #[inline] pub fn set_config(&mut self, config: Config) { self.0.set_config(config); } #[inline] pub fn get_layout(&self) -> Arc { self.0.get_layout() } #[inline] pub fn info(&self) -> RepositoryInfo { self.0.info() } #[inline] pub fn statistics(&self) -> RepositoryStatistics { self.0.statistics() } #[inline] pub fn list_bundles(&self) -> Vec<&BundleInfo> { self.0.list_bundles() } #[inline] pub fn get_bundle(&self, bundle: &BundleId) -> Option<&StoredBundle> { self.0.get_bundle(bundle) } #[inline] pub fn get_all_backups(&self) -> Result, RepositoryError> { self.0.get_all_backups() } #[inline] pub fn get_backups>(&self, path: P) -> Result, RepositoryError> { self.0.get_backups(path) } #[inline] pub fn delete_backup(&mut self, name: &str) -> Result<(), RepositoryError> { self.0.backup_mode(|r, l| r.delete_backup(name, l)) } #[inline] pub fn save_backup(&mut self, backup: &BackupFile, name: &str) -> Result<(), RepositoryError> { self.0.backup_mode(|r, l| r.save_backup(backup, name, l)) } #[inline] pub fn prune_backups(&mut self, prefix: &str, options: &PruneOptions, force: bool) -> Result<(), RepositoryError> { self.0.backup_mode(|r, l| r.prune_backups(prefix, options, force, l)) } #[inline] pub fn get_root_inode(&mut self, backup: &BackupFile) -> Result { self.0.online_mode(|r, l| r.get_inode(&backup.root, l)) } #[inline] pub fn get_inode_children(&mut self, inode: &Inode) -> Result, RepositoryError> { self.0.online_mode(|r, l| r.get_inode_children(inode, l)) } #[inline] pub fn restore_inode_tree>(&mut self, backup: &BackupFile, inode: Inode, path: P) -> Result<(), RepositoryError> { self.0.online_mode(|r, l| r.restore_inode_tree(backup, inode, path, l)) } #[inline] pub fn create_backup>(&mut self, path: P, name: &str, reference: Option<&BackupFile>, options: &BackupOptions) -> Result { self.0.backup_mode(|r, l| r.create_backup(path, name, reference, options,l)) } #[inline] pub fn remove_backup_path>(&mut self, backup: &mut BackupFile, name: &str, path: P ) -> Result<(), RepositoryError> { self.0.backup_mode(|r, l| r.remove_backup_path(backup, name, path, l)) } #[inline] #[allow(dead_code)] pub fn get_backup_path>(&mut self, backup: &BackupFile, path: P) -> Result, RepositoryError> { self.0.online_mode(|r, l| r.get_backup_path(backup, path, l)) } #[inline] pub fn get_backup_inode>(&mut self, backup: &BackupFile, path: P) -> Result { self.0.online_mode(|r, l| r.get_backup_inode(backup, path, l)) } #[inline] pub fn find_differences(&mut self, inode1: &Inode, inode2: &Inode ) -> Result, RepositoryError> { self.0.online_mode(|r, l| r.find_differences(inode1, inode2, l)) } #[inline] pub fn find_versions>(&mut self, path: P ) -> Result, RepositoryError> { self.0.online_mode(|r, l| r.find_versions(path, l)) } #[inline] pub fn find_duplicates(&mut self, inode: &Inode, min_size: u64 ) -> Result, u64)>, RepositoryError> { self.0.online_mode(|r, l| r.find_duplicates(inode, min_size, l)) } #[inline] pub fn analyze_usage(&mut self) -> Result, RepositoryError> { self.0.online_mode(|r, l| r.analyze_usage(l)) } #[inline] pub fn vacuum(&mut self, ratio: f32, combine: bool, force: bool) -> Result<(), RepositoryError> { self.0.vacuum_mode(|r, l| r.vacuum(ratio, combine, force, l)) } pub fn mount_repository>(&mut self, path: Option<&str>, mountpoint: P) -> Result<(), RepositoryError> { self.0.online_mode(|r, l| { let fs = try!(FuseFilesystem::from_repository(r, l, path)); fs.mount(mountpoint) }) } pub fn mount_backup>(&mut self, backup: BackupFile, mountpoint: P) -> Result<(), RepositoryError> { self.0.online_mode(|r, l| { let fs = try!(FuseFilesystem::from_backup(r, l, backup)); fs.mount(mountpoint) }) } pub fn mount_inode>(&mut self, backup: BackupFile, inode: Inode, mountpoint: P) -> Result<(), RepositoryError> { self.0.online_mode(|r, l| { let fs = try!(FuseFilesystem::from_inode(r, l, backup, inode)); fs.mount(mountpoint) }) } pub fn check(&mut self, options: CheckOptions) -> Result { if options.get_repair() { self.0.vacuum_mode(|r, l| { r.check_and_repair(options, l) }) } else { self.0.online_mode(|r, l| { Ok(r.check(options, l)) }) } } #[inline] pub fn import_tarfile>(&mut self, tarfile: P) -> Result { self.0.backup_mode(|r, l| r.import_tarfile(tarfile, l)) } #[inline] pub fn export_tarfile>(&mut self, backup: &BackupFile, inode: Inode, tarfile: P ) -> Result<(), RepositoryError> { self.0.online_mode(|r, l| r.export_tarfile(backup, inode, tarfile, l)) } }