2017-03-16 08:42:30 +00:00
|
|
|
use super::{Repository, Chunk, RepositoryError};
|
2017-03-15 20:53:05 +00:00
|
|
|
|
2017-03-16 08:42:30 +00:00
|
|
|
use ::util::*;
|
2017-03-15 20:53:05 +00:00
|
|
|
|
|
|
|
use std::fs::{self, File};
|
|
|
|
use std::path::Path;
|
|
|
|
|
|
|
|
|
|
|
|
#[derive(Default, Debug)]
|
|
|
|
pub struct Backup {
|
|
|
|
pub root: Vec<Chunk>,
|
|
|
|
pub total_data_size: u64,
|
|
|
|
pub changed_data_size: u64,
|
|
|
|
pub new_data_size: u64,
|
|
|
|
pub encoded_data_size: u64,
|
|
|
|
pub new_bundle_count: usize,
|
|
|
|
pub chunk_count: usize,
|
|
|
|
pub avg_chunk_size: f32,
|
|
|
|
pub date: i64,
|
|
|
|
pub duration: f32,
|
|
|
|
pub file_count: usize,
|
|
|
|
pub dir_count: usize
|
|
|
|
}
|
|
|
|
serde_impl!(Backup(u8) {
|
|
|
|
root: Vec<Chunk> => 0,
|
|
|
|
total_data_size: u64 => 1,
|
|
|
|
changed_data_size: u64 => 2,
|
|
|
|
new_data_size: u64 => 3,
|
|
|
|
encoded_data_size: u64 => 4,
|
|
|
|
new_bundle_count: usize => 5,
|
|
|
|
chunk_count: usize => 6,
|
|
|
|
avg_chunk_size: f32 => 7,
|
|
|
|
date: i64 => 8,
|
|
|
|
duration: f32 => 9,
|
|
|
|
file_count: usize => 10,
|
|
|
|
dir_count: usize => 11
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
impl Repository {
|
2017-03-16 08:42:30 +00:00
|
|
|
pub fn list_backups(&self) -> Result<Vec<String>, RepositoryError> {
|
2017-03-15 20:53:05 +00:00
|
|
|
let mut backups = Vec::new();
|
|
|
|
let mut paths = Vec::new();
|
|
|
|
let base_path = self.path.join("backups");
|
|
|
|
paths.push(base_path.clone());
|
|
|
|
while let Some(path) = paths.pop() {
|
2017-03-16 08:42:30 +00:00
|
|
|
for entry in try!(fs::read_dir(path)) {
|
|
|
|
let entry = try!(entry);
|
2017-03-15 20:53:05 +00:00
|
|
|
let path = entry.path();
|
|
|
|
if path.is_dir() {
|
|
|
|
paths.push(path);
|
|
|
|
} else {
|
2017-03-16 08:42:30 +00:00
|
|
|
let relpath = path.strip_prefix(&base_path).unwrap();
|
2017-03-15 20:53:05 +00:00
|
|
|
backups.push(relpath.to_string_lossy().to_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(backups)
|
|
|
|
}
|
|
|
|
|
2017-03-16 08:42:30 +00:00
|
|
|
pub fn get_backup(&self, name: &str) -> Result<Backup, RepositoryError> {
|
|
|
|
let mut file = try!(File::open(self.path.join("backups").join(name)));
|
|
|
|
Ok(try!(msgpack::decode_from_stream(&mut file)))
|
2017-03-15 20:53:05 +00:00
|
|
|
}
|
|
|
|
|
2017-03-16 08:42:30 +00:00
|
|
|
pub fn save_backup(&mut self, backup: &Backup, name: &str) -> Result<(), RepositoryError> {
|
|
|
|
let mut file = try!(File::create(self.path.join("backups").join(name)));
|
|
|
|
Ok(try!(msgpack::encode_to_stream(backup, &mut file)))
|
2017-03-15 20:53:05 +00:00
|
|
|
}
|
|
|
|
|
2017-03-16 08:42:30 +00:00
|
|
|
pub fn restore_backup<P: AsRef<Path>>(&mut self, backup: &Backup, path: P) -> Result<(), RepositoryError> {
|
2017-03-15 20:53:05 +00:00
|
|
|
let inode = try!(self.get_inode(&backup.root));
|
|
|
|
try!(self.save_inode_at(&inode, path));
|
|
|
|
Ok(())
|
|
|
|
}
|
2017-03-15 21:14:50 +00:00
|
|
|
|
2017-03-16 08:42:30 +00:00
|
|
|
pub fn create_full_backup<P: AsRef<Path>>(&mut self, path: P) -> Result<Backup, RepositoryError> {
|
2017-03-15 21:14:50 +00:00
|
|
|
// Maintain a stack of folders still todo
|
|
|
|
// Maintain a map of path->inode entries
|
|
|
|
// Work on topmost stack entry
|
|
|
|
// If it is a file, create inode for it and put it in the map
|
|
|
|
// If it is a folder, list contents and put entries not in the map on the stack, folders last
|
|
|
|
// If it is a folder with no missing entries, create a directory inode, add it to the map, and remove all children from the map
|
|
|
|
// If stack is empty create a backup with the last inode as root
|
|
|
|
unimplemented!()
|
|
|
|
}
|
2017-03-15 20:53:05 +00:00
|
|
|
}
|