diff --git a/src/archiver.rs b/src/archiver.rs index 3dc9ebd..ea84785 100644 --- a/src/archiver.rs +++ b/src/archiver.rs @@ -5,7 +5,7 @@ use std::io::{BufRead, BufReader}; use std::path::{Path, PathBuf}; use std::rc::Rc; -use anyhow::Result; +use anyhow::{anyhow, Result}; use crate::backend::DecryptWriteBackend; use crate::blob::{BlobType, Node, Packer, Tree}; @@ -19,8 +19,7 @@ pub type SharedIndexer = Rc>>; pub struct Archiver { path: PathBuf, tree: Tree, - names: Vec, - trees: Vec, + stack: Vec<(Node, Tree)>, size: u64, count: u64, be: BE, @@ -37,8 +36,7 @@ impl Archiver { Ok(Self { path: PathBuf::from("/"), tree: Tree::new(), - names: Vec::new(), - trees: Vec::new(), + stack: Vec::new(), size: 0, count: 0, index, @@ -54,7 +52,8 @@ impl Archiver { let basepath = if file_type.is_dir() { path } else { - path.parent().unwrap() + path.parent() + .ok_or(anyhow!("file path should have a parent!"))? }; self.finish_trees(&basepath)?; @@ -65,8 +64,8 @@ impl Archiver { for p in missing_dirs.iter() { // new subdir let tree = std::mem::replace(&mut self.tree, Tree::new()); - self.trees.push(tree); - self.names.push(p.to_os_string()); + let node = Node::new_tree(p.to_os_string())?; + self.stack.push((node, tree)); self.path.push(p); println!("add tree {:?}, path: {:?}", p, self.path); } @@ -87,10 +86,10 @@ impl Archiver { if !self.index.has(&id) { self.tree_packer.add(&chunk, &id, BlobType::Tree)?; } - self.tree = self.trees.pop().unwrap(); - let name = self.names.pop().unwrap(); + + let (mut node, name) = self.stack.pop().ok_or(anyhow!("tree stack empty??"))?; println!("finish: {:?}", name); - let node = Node::from_tree(name, id)?; + node.set_subtree(id); self.tree.add(node); self.path.pop(); @@ -135,7 +134,10 @@ impl Archiver { // save snapshot let snap = SnapshotFile::new( id, - vec![backup_path.to_str().unwrap().to_string()], + vec![backup_path + .to_str() + .ok_or(anyhow!("non-unicode path {:?}", backup_path))? + .to_string()], "host".to_string(), "user".to_string(), 0, diff --git a/src/backend/node.rs b/src/backend/node.rs index 71c6275..50ebcf0 100644 --- a/src/backend/node.rs +++ b/src/backend/node.rs @@ -76,4 +76,18 @@ impl Node { meta: Metadata::default(), }) } + + pub fn new_tree(name: OsString) -> Result { + Ok(Self { + name: name.to_str().expect("no unicode").to_string(), + node_type: NodeType::Dir, + content: Vec::new(), + subtree: None, + meta: Metadata::default(), + }) + } + + pub fn set_subtree(&mut self, id: Id) { + self.subtree = Some(id); + } } diff --git a/src/blob/tree.rs b/src/blob/tree.rs index 6cb18fa..c4ddaa6 100644 --- a/src/blob/tree.rs +++ b/src/blob/tree.rs @@ -38,16 +38,15 @@ impl Tree { } } +type TreeIterItem = Result<(PathBuf, Node)>; + /// tree_iterator creates an Iterator over the trees given by ids using the backend be and the index /// index pub fn tree_iterator( be: &impl IndexedBackend, ids: Vec, -) -> impl Iterator + '_ { - TreeIterator::new( - |i| Tree::from_backend(be, i).unwrap().nodes.into_iter(), - ids, - ) +) -> Result + '_> { + TreeIterator::new(|i| Ok(Tree::from_backend(be, i)?.nodes.into_iter()), ids) } /// tree_iterator_once creates an Iterator over the trees given by ids using the backend be and the index @@ -55,14 +54,14 @@ pub fn tree_iterator( pub fn tree_iterator_once( be: &impl IndexedBackend, ids: Vec, -) -> impl Iterator + '_ { +) -> Result + '_> { let mut visited = HashSet::new(); TreeIterator::new( move |i| { if visited.insert(*i) { - Tree::from_backend(be, i).unwrap().nodes.into_iter() + Ok(Tree::from_backend(be, i)?.nodes.into_iter()) } else { - Vec::new().into_iter() + Ok(Vec::new().into_iter()) } }, ids, @@ -74,7 +73,7 @@ pub fn tree_iterator_once( pub struct TreeIterator where IT: Iterator, - F: FnMut(&Id) -> IT, + F: FnMut(&Id) -> Result, { open_iterators: Vec, inner: IT, @@ -85,40 +84,40 @@ where impl TreeIterator where IT: Iterator, - F: FnMut(&Id) -> IT, + F: FnMut(&Id) -> Result, { - fn new(mut getter: F, ids: Vec) -> Self { + fn new(mut getter: F, ids: Vec) -> Result { // TODO: empty ids vector will panic here! - let mut iters = ids.iter().map(&mut getter).collect::>(); + let mut iters: Vec<_> = ids.iter().map(&mut getter).collect::>()?; iters.rotate_right(1); - Self { + Ok(Self { inner: iters.pop().unwrap(), open_iterators: iters, path: PathBuf::new(), getter, - } + }) } } impl Iterator for TreeIterator where IT: Iterator, - F: FnMut(&Id) -> IT, + F: FnMut(&Id) -> Result, { - type Item = (PathBuf, Node); + type Item = Result<(PathBuf, Node)>; fn next(&mut self) -> Option { loop { match self.inner.next() { Some(node) => { let path = self.path.join(node.name()); - if let Some(subtree) = node.subtree() { - let old_inner = mem::replace(&mut self.inner, (self.getter)(subtree)); + if let Some(id) = node.subtree() { + let old_inner = mem::replace(&mut self.inner, (self.getter)(id).unwrap()); self.open_iterators.push(old_inner); self.path.push(node.name()); } - return Some((path, node)); + return Some(Ok((path, node))); } None => match self.open_iterators.pop() { Some(it) => { diff --git a/src/chunker.rs b/src/chunker.rs index 3a86e04..0cfe583 100644 --- a/src/chunker.rs +++ b/src/chunker.rs @@ -46,7 +46,7 @@ impl Iterator for ChunkIter { let mut vec = Vec::new(); let size = match (&mut self.reader) - .take(self.min_size.try_into().unwrap()) + .take(self.min_size as u64) .read_to_end(&mut vec) { Ok(size) => size, diff --git a/src/commands/check.rs b/src/commands/check.rs index 5a6c6ea..43d902c 100644 --- a/src/commands/check.rs +++ b/src/commands/check.rs @@ -80,7 +80,8 @@ fn check_snapshots(index: &impl IndexedBackend) -> Result<()> { .map(|id| Ok(SnapshotFile::from_backend(index.be(), &id)?.tree)) .collect::>()?; - for (path, node) in tree_iterator_once(index, snap_ids) { + for item in tree_iterator_once(index, snap_ids)? { + let (path, node) = item?; match node.node_type() { NodeType::File => { for (i, id) in node.content().iter().enumerate() { diff --git a/src/commands/diff.rs b/src/commands/diff.rs index 35e64e6..25602e4 100644 --- a/src/commands/diff.rs +++ b/src/commands/diff.rs @@ -36,11 +36,10 @@ pub(super) fn execute(be: &impl DecryptReadBackend, opts: Opts) -> Result<()> { println!("reading index..."); let index = IndexBackend::new(be)?; + let iterator1 = tree_iterator(&index, vec![snap.tree])?.filter_map(Result::ok); + let iterator2 = tree_iterator(&index, vec![snap_with.tree])?.filter_map(Result::ok); - for file in tree_iterator(&index, vec![snap.tree]).merge_join_by( - tree_iterator(&index, vec![snap_with.tree]), - |(path1, _), (path2, _)| path1.cmp(path2), - ) { + for file in iterator1.merge_join_by(iterator2, |(path1, _), (path2, _)| path1.cmp(path2)) { match file { Left((path, _)) => println!("- {:?}", path), Right((path, _)) => println!("+ {:?}", path), diff --git a/src/commands/ls.rs b/src/commands/ls.rs index b8899f0..2310bc0 100644 --- a/src/commands/ls.rs +++ b/src/commands/ls.rs @@ -23,7 +23,8 @@ pub(super) fn execute(be: &impl DecryptReadBackend, opts: Opts) -> Result<()> { let snap = SnapshotFile::from_backend(be, &id)?; let index = IndexBackend::new(be)?; - for (path, _) in tree_iterator(&index, vec![snap.tree]) { + let tree_iter = tree_iterator(&index, vec![snap.tree])?.filter_map(Result::ok); + for (path, _) in tree_iter { println!("{:?} ", path); } diff --git a/src/commands/restore.rs b/src/commands/restore.rs index 392ecca..a238fdd 100644 --- a/src/commands/restore.rs +++ b/src/commands/restore.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::path::PathBuf; -use anyhow::Result; +use anyhow::{anyhow, Result}; use clap::Parser; use derive_getters::Dissolve; use itertools::{ @@ -68,10 +68,10 @@ fn allocate_and_collect( // collect dirs to delete as they need to be deleted in reverse order // let mut dirs_to_delete = Vec::new(); + let tree_iter = tree_iterator(index, vec![tree])?.filter_map(Result::ok); + // walk over tree in repository and compare with tree in dest - for file in - tree_iterator(index, vec![tree]).merge_join_by(dest.walker(), |(path, _), j| path.cmp(j)) - { + for file in tree_iter.merge_join_by(dest.walker(), |(path, _), j| path.cmp(j)) { match file { // node is only in snapshot Left((path, node)) => { @@ -81,7 +81,7 @@ fn allocate_and_collect( } NodeType::File => { // collect blobs needed for restoring - let size = file_infos.add_file(&node, path.clone(), index); + let size = file_infos.add_file(&node, path.clone(), index)?; // create the file if !opts.dry_run { dest.create_file(&path, size); @@ -148,7 +148,8 @@ fn restore_metadata( opts: &Opts, ) -> Result<()> { // walk over tree in repository and compare with tree in dest - for (path, node) in tree_iterator(index, vec![tree]) { + let tree_iter = tree_iterator(index, vec![tree])?.filter_map(Result::ok); + for (path, node) in tree_iter { if !opts.dry_run { if let NodeType::Symlink { linktarget } = node.node_type() { dest.create_symlink(&path, linktarget); @@ -194,13 +195,15 @@ impl FileInfos { /// Add the file to FilesInfos using index to get blob information. /// Returns the computed length of the file - fn add_file(&mut self, file: &Node, name: PathBuf, index: &impl IndexedBackend) -> u64 { + fn add_file(&mut self, file: &Node, name: PathBuf, index: &impl IndexedBackend) -> Result { let mut file_pos = 0; if !file.content().is_empty() { let file_idx = self.names.len(); self.names.push(name); for id in file.content().iter() { - let ie = index.get_id(id).unwrap(); + let ie = index + .get_id(id) + .ok_or(anyhow!("did not find id {} in index", id))?; let bl = BlobLocation { offset: *ie.offset(), length: *ie.length(), @@ -216,6 +219,6 @@ impl FileInfos { file_pos += *ie.length() as u64 - 32; // blob crypto overhead } } - file_pos + Ok(file_pos) } } diff --git a/src/repo/key.rs b/src/repo/key.rs index 402b644..ef4a7d9 100644 --- a/src/repo/key.rs +++ b/src/repo/key.rs @@ -63,9 +63,7 @@ const fn num_bits() -> usize { fn log_2(x: u32) -> u8 { assert!(x > 0); - (num_bits::() as u32 - x.leading_zeros() - 1) - .try_into() - .unwrap() + num_bits::() as u8 - x.leading_zeros() as u8 - 1 } #[derive(Debug, Deserialize)]