Restore and list

pull/10/head
Dennis Schwerdel 2017-03-16 13:59:57 +01:00
parent ba68fc2fda
commit 9fc70ea0fb
4 changed files with 59 additions and 7 deletions

View File

@ -34,6 +34,7 @@ Usage:
zvault check [--full] <repo>
zvault backups <repo>
zvault info <backup>
zvault list <backup> <path>
zvault stats <repo>
zvault bundles <repo>
zvault algotest <path>
@ -57,6 +58,7 @@ struct Args {
cmd_backups: bool,
cmd_info: bool,
cmd_list: bool,
cmd_stats: bool,
cmd_bundles: bool,
@ -187,5 +189,18 @@ fn main() {
if args.cmd_restore {
repo.restore_backup(&backup, &args.arg_path.unwrap()).unwrap();
return
}
if args.cmd_list {
let inode = repo.get_backup_inode(&backup, &args.arg_path.unwrap()).unwrap();
println!("{}", inode.format_one_line());
if let Some(children) = inode.children {
for chunks in children.values() {
let inode = repo.get_inode(&chunks).unwrap();
println!("- {}", inode.format_one_line());
}
}
return
}
}

View File

@ -1,16 +1,16 @@
use super::{Repository, Chunk, RepositoryError};
use super::metadata::FileType;
use super::metadata::{FileType, Inode};
use ::util::*;
use std::fs::{self, File};
use std::path::Path;
use std::collections::HashMap;
use std::path::{self, Path};
use std::collections::{HashMap, VecDeque};
use chrono::prelude::*;
#[derive(Default, Debug)]
#[derive(Default, Debug, Clone)]
pub struct Backup {
pub root: Vec<Chunk>,
pub total_data_size: u64, // Sum of all raw sizes of all entities
@ -73,9 +73,18 @@ impl Repository {
}
pub fn restore_backup<P: AsRef<Path>>(&mut self, backup: &Backup, path: P) -> Result<(), RepositoryError> {
let inode = try!(self.get_inode(&backup.root));
try!(self.save_inode_at(&inode, path));
//FIXME: recurse
let mut queue = VecDeque::new();
queue.push_back((path.as_ref().to_owned(), try!(self.get_inode(&backup.root))));
while let Some((path, inode)) = queue.pop_front() {
try!(self.save_inode_at(&inode, &path));
if inode.file_type == FileType::Directory {
let path = path.join(inode.name);
for chunks in inode.children.unwrap().values() {
let inode = try!(self.get_inode(&chunks));
queue.push_back((path.clone(), inode));
}
}
}
Ok(())
}
@ -147,4 +156,19 @@ impl Repository {
backup.avg_chunk_size = backup.deduplicated_data_size as f32 / backup.chunk_count as f32;
Ok(backup)
}
pub fn get_backup_inode<P: AsRef<Path>>(&mut self, backup: &Backup, path: P) -> Result<Inode, RepositoryError> {
let mut inode = try!(self.get_inode(&backup.root));
for c in path.as_ref().components() {
if let path::Component::Normal(name) = c {
let name = name.to_string_lossy();
if let Some(chunks) = inode.children.as_mut().and_then(|c| c.remove(&name as &str)) {
inode = try!(self.get_inode(&chunks));
} else {
return Err(RepositoryError::NoSuchFileInBackup(backup.clone(), path.as_ref().to_owned()));
}
}
}
Ok(inode)
}
}

View File

@ -1,6 +1,7 @@
use std::io;
use std::path::PathBuf;
use super::backup::Backup;
use super::bundle_map::BundleMapError;
use super::config::ConfigError;
use super::integrity::RepositoryIntegrityError;
@ -62,5 +63,9 @@ quick_error!{
description("Invalid file type")
display("{:?} has an invalid file type", path)
}
NoSuchFileInBackup(backup: Backup, path: PathBuf) {
description("No such file in backup")
display("The backup does not contain the file {:?}", path)
}
}
}

View File

@ -143,6 +143,14 @@ impl Inode {
// https://crates.io/crates/filetime
Ok(file)
}
pub fn format_one_line(&self) -> String {
match self.file_type {
FileType::Directory => format!("{:25}\t{} entries", format!("{}/", self.name), self.children.as_ref().unwrap().len()),
FileType::File => format!("{:25}\t{}", self.name, to_file_size(self.size)),
FileType::Symlink => format!("{:25}\t -> {}", self.name, self.symlink_target.as_ref().unwrap()),
}
}
}