From 9fc70ea0fb0cb1641dd41228bf02e724986c106b Mon Sep 17 00:00:00 2001 From: Dennis Schwerdel Date: Thu, 16 Mar 2017 13:59:57 +0100 Subject: [PATCH] Restore and list --- src/main.rs | 15 +++++++++++++++ src/repository/backup.rs | 38 +++++++++++++++++++++++++++++++------- src/repository/error.rs | 5 +++++ src/repository/metadata.rs | 8 ++++++++ 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/main.rs b/src/main.rs index f3da830..f1e976e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -34,6 +34,7 @@ Usage: zvault check [--full] zvault backups zvault info + zvault list zvault stats zvault bundles zvault algotest @@ -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 } } diff --git a/src/repository/backup.rs b/src/repository/backup.rs index 59ab761..ad8aa6c 100644 --- a/src/repository/backup.rs +++ b/src/repository/backup.rs @@ -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, pub total_data_size: u64, // Sum of all raw sizes of all entities @@ -73,9 +73,18 @@ impl Repository { } pub fn restore_backup>(&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>(&mut self, backup: &Backup, path: P) -> Result { + 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) + } } diff --git a/src/repository/error.rs b/src/repository/error.rs index dbdd6da..e71015b 100644 --- a/src/repository/error.rs +++ b/src/repository/error.rs @@ -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) + } } } diff --git a/src/repository/metadata.rs b/src/repository/metadata.rs index 58eced1..3c9720b 100644 --- a/src/repository/metadata.rs +++ b/src/repository/metadata.rs @@ -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()), + } + } }