2018-03-08 22:41:56 +00:00
|
|
|
pub mod mount;
|
2018-03-10 15:35:40 +00:00
|
|
|
mod backup_file;
|
|
|
|
mod inode;
|
|
|
|
mod tarfile;
|
|
|
|
mod backup;
|
|
|
|
mod integrity;
|
|
|
|
mod vacuum;
|
2018-03-11 22:32:54 +00:00
|
|
|
mod metadata;
|
2018-03-10 15:35:40 +00:00
|
|
|
|
|
|
|
pub use self::backup::{BackupOptions, BackupError, DiffType};
|
|
|
|
pub use self::backup_file::{BackupFile, BackupFileError};
|
|
|
|
pub use self::inode::{Inode, FileData, FileType, InodeError};
|
|
|
|
pub use self::integrity::InodeIntegrityError;
|
2018-03-08 22:41:56 +00:00
|
|
|
|
|
|
|
use ::prelude::*;
|
|
|
|
|
2018-03-10 15:35:40 +00:00
|
|
|
use std::path::Path;
|
2018-03-08 22:41:56 +00:00
|
|
|
use std::collections::HashMap;
|
2018-03-09 22:31:20 +00:00
|
|
|
use std::sync::Arc;
|
2018-03-10 15:35:40 +00:00
|
|
|
use std::fs::{self, File};
|
|
|
|
use std::io::Write;
|
|
|
|
|
|
|
|
|
|
|
|
const DEFAULT_EXCLUDES: &[u8] = include_bytes!("../../docs/excludes.default");
|
|
|
|
|
2018-03-08 22:41:56 +00:00
|
|
|
|
|
|
|
|
|
|
|
pub struct BackupRepository {
|
2018-03-09 22:31:20 +00:00
|
|
|
layout: Arc<RepositoryLayout>,
|
2018-03-10 15:35:40 +00:00
|
|
|
crypto: Arc<Crypto>,
|
2018-05-15 20:14:30 +00:00
|
|
|
repo: RepositoryInner
|
2018-03-08 22:41:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl BackupRepository {
|
|
|
|
pub fn create<P: AsRef<Path>, R: AsRef<Path>>(path: P, config: &Config, remote: R) -> Result<Self, RepositoryError> {
|
2018-03-09 22:31:20 +00:00
|
|
|
let layout = Arc::new(RepositoryLayout::new(path.as_ref()));
|
2018-03-10 15:35:40 +00:00
|
|
|
try!(fs::create_dir(layout.base_path()));
|
|
|
|
try!(File::create(layout.excludes_path()).and_then(|mut f| {
|
|
|
|
f.write_all(DEFAULT_EXCLUDES)
|
|
|
|
}));
|
2018-03-11 22:32:54 +00:00
|
|
|
try!(fs::create_dir_all(layout.backups_path()));
|
2018-03-10 15:35:40 +00:00
|
|
|
try!(fs::create_dir(layout.keys_path()));
|
|
|
|
let crypto = Arc::new(try!(Crypto::open(layout.keys_path())));
|
2018-03-08 22:41:56 +00:00
|
|
|
Ok(BackupRepository {
|
2018-03-10 15:35:40 +00:00
|
|
|
crypto: crypto.clone(),
|
2018-03-09 22:31:20 +00:00
|
|
|
layout: layout.clone(),
|
2018-05-15 20:14:30 +00:00
|
|
|
repo: try!(RepositoryInner::create(layout, config, crypto, remote))
|
2018-03-08 22:41:56 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(unknown_lints, useless_let_if_seq)]
|
|
|
|
pub fn open<P: AsRef<Path>>(path: P, online: bool) -> Result<Self, RepositoryError> {
|
2018-03-09 22:31:20 +00:00
|
|
|
let layout = Arc::new(RepositoryLayout::new(path.as_ref()));
|
2018-03-10 15:35:40 +00:00
|
|
|
let crypto = Arc::new(try!(Crypto::open(layout.keys_path())));
|
2018-03-08 22:41:56 +00:00
|
|
|
Ok(BackupRepository {
|
2018-03-10 15:35:40 +00:00
|
|
|
crypto: crypto.clone(),
|
2018-03-09 22:31:20 +00:00
|
|
|
layout: layout.clone(),
|
2018-05-15 20:14:30 +00:00
|
|
|
repo: try!(RepositoryInner::open(layout, crypto, online))
|
2018-03-08 22:41:56 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn import<P: AsRef<Path>, R: AsRef<Path>>(path: P, remote: R, key_files: Vec<String>) -> Result<Self, RepositoryError> {
|
2018-03-10 15:35:40 +00:00
|
|
|
let config = Config::default();
|
|
|
|
let mut repo = try!(Self::create(&path, &config, remote));
|
|
|
|
for file in key_files {
|
|
|
|
try!(repo.crypto.register_keyfile(file));
|
|
|
|
}
|
|
|
|
repo = try!(Self::open(&path, true));
|
|
|
|
let mut backups: Vec<(String, BackupFile)> = try!(repo.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.repo.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)
|
2018-03-08 22:41:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn register_key(&mut self, public: PublicKey, secret: SecretKey) -> Result<(), RepositoryError> {
|
2018-03-10 15:35:40 +00:00
|
|
|
try!(self.repo.write_mode());
|
|
|
|
try!(self.crypto.register_secret_key(public, secret));
|
|
|
|
Ok(())
|
2018-03-08 22:41:56 +00:00
|
|
|
}
|
|
|
|
|
2018-03-10 15:35:40 +00:00
|
|
|
|
2018-03-08 22:41:56 +00:00
|
|
|
#[inline]
|
|
|
|
pub fn save_config(&mut self) -> Result<(), RepositoryError> {
|
|
|
|
self.repo.save_config()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn set_encryption(&mut self, public: Option<&PublicKey>) {
|
|
|
|
self.repo.set_encryption(public)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_config(&self) -> &Config {
|
2018-03-10 11:09:04 +00:00
|
|
|
self.repo.get_config()
|
2018-03-08 22:41:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn set_config(&mut self, config: Config) {
|
2018-03-10 11:09:04 +00:00
|
|
|
self.repo.set_config(config);
|
2018-03-08 22:41:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_layout(&self) -> &RepositoryLayout {
|
2018-03-09 22:31:20 +00:00
|
|
|
&self.layout
|
2018-03-08 22:41:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn info(&self) -> RepositoryInfo {
|
|
|
|
self.repo.info()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn check_index(&mut self, repair: bool) -> Result<(), RepositoryError> {
|
|
|
|
self.repo.check_index(repair)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn set_clean(&mut self) {
|
|
|
|
self.repo.set_clean()
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn statistics(&self) -> RepositoryStatistics {
|
|
|
|
self.repo.statistics()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn list_bundles(&self) -> Vec<&BundleInfo> {
|
|
|
|
self.repo.list_bundles()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
pub fn get_bundle(&self, bundle: &BundleId) -> Option<&StoredBundle> {
|
|
|
|
self.repo.get_bundle(bundle)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_chunk(&mut self, hash: Hash) -> Result<Option<Vec<u8>>, RepositoryError> {
|
|
|
|
self.repo.get_chunk(hash)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_data(&mut self, chunks: &[Chunk]) -> Result<Vec<u8>, RepositoryError> {
|
|
|
|
self.repo.get_data(chunks)
|
|
|
|
}
|
|
|
|
}
|