better error handling

This commit is contained in:
Alexander Weiss 2022-02-22 16:01:51 +01:00
parent 6c62fa5c00
commit 68e99447d8
9 changed files with 67 additions and 50 deletions

View File

@ -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<BE> = Rc<RefCell<Indexer<BE>>>;
pub struct Archiver<BE: DecryptWriteBackend, I: ReadIndex> {
path: PathBuf,
tree: Tree,
names: Vec<OsString>,
trees: Vec<Tree>,
stack: Vec<(Node, Tree)>,
size: u64,
count: u64,
be: BE,
@ -37,8 +36,7 @@ impl<BE: DecryptWriteBackend, I: ReadIndex> Archiver<BE, I> {
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<BE: DecryptWriteBackend, I: ReadIndex> Archiver<BE, I> {
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<BE: DecryptWriteBackend, I: ReadIndex> Archiver<BE, I> {
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<BE: DecryptWriteBackend, I: ReadIndex> Archiver<BE, I> {
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<BE: DecryptWriteBackend, I: ReadIndex> Archiver<BE, I> {
// 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,

View File

@ -76,4 +76,18 @@ impl Node {
meta: Metadata::default(),
})
}
pub fn new_tree(name: OsString) -> Result<Self> {
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);
}
}

View File

@ -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<Id>,
) -> impl Iterator<Item = (PathBuf, Node)> + '_ {
TreeIterator::new(
|i| Tree::from_backend(be, i).unwrap().nodes.into_iter(),
ids,
)
) -> Result<impl Iterator<Item = TreeIterItem> + '_> {
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<Id>,
) -> impl Iterator<Item = (PathBuf, Node)> + '_ {
) -> Result<impl Iterator<Item = TreeIterItem> + '_> {
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<IT, F>
where
IT: Iterator<Item = Node>,
F: FnMut(&Id) -> IT,
F: FnMut(&Id) -> Result<IT>,
{
open_iterators: Vec<IT>,
inner: IT,
@ -85,40 +84,40 @@ where
impl<IT, F> TreeIterator<IT, F>
where
IT: Iterator<Item = Node>,
F: FnMut(&Id) -> IT,
F: FnMut(&Id) -> Result<IT>,
{
fn new(mut getter: F, ids: Vec<Id>) -> Self {
fn new(mut getter: F, ids: Vec<Id>) -> Result<Self> {
// TODO: empty ids vector will panic here!
let mut iters = ids.iter().map(&mut getter).collect::<Vec<_>>();
let mut iters: Vec<_> = ids.iter().map(&mut getter).collect::<Result<_>>()?;
iters.rotate_right(1);
Self {
Ok(Self {
inner: iters.pop().unwrap(),
open_iterators: iters,
path: PathBuf::new(),
getter,
}
})
}
}
impl<IT, F> Iterator for TreeIterator<IT, F>
where
IT: Iterator<Item = Node>,
F: FnMut(&Id) -> IT,
F: FnMut(&Id) -> Result<IT>,
{
type Item = (PathBuf, Node);
type Item = Result<(PathBuf, Node)>;
fn next(&mut self) -> Option<Self::Item> {
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) => {

View File

@ -46,7 +46,7 @@ impl<R: Read> Iterator for ChunkIter<R> {
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,

View File

@ -80,7 +80,8 @@ fn check_snapshots(index: &impl IndexedBackend) -> Result<()> {
.map(|id| Ok(SnapshotFile::from_backend(index.be(), &id)?.tree))
.collect::<Result<_>>()?;
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() {

View File

@ -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),

View File

@ -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);
}

View File

@ -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<u64> {
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)
}
}

View File

@ -63,9 +63,7 @@ const fn num_bits<T>() -> usize {
fn log_2(x: u32) -> u8 {
assert!(x > 0);
(num_bits::<u32>() as u32 - x.leading_zeros() - 1)
.try_into()
.unwrap()
num_bits::<u32>() as u8 - x.leading_zeros() as u8 - 1
}
#[derive(Debug, Deserialize)]