add check command

This commit is contained in:
Alexander Weiss 2022-02-09 08:49:20 +01:00
parent 648b5830ee
commit 5101ead24c
3 changed files with 120 additions and 0 deletions

111
src/commands/check.rs Normal file
View File

@ -0,0 +1,111 @@
use anyhow::Result;
use clap::Parser;
use std::collections::HashMap;
use crate::backend::{FileType, ReadBackend};
use crate::blob::tree_iterator_once;
use crate::index::{AllIndexFiles, BoomIndex, ReadIndex};
use crate::repo::{IndexBlob, SnapshotFile};
#[derive(Parser)]
pub(super) struct Opts {
/// read all data blobs
#[clap(long)]
read_data: bool,
}
pub(super) fn execute(be: &impl ReadBackend, opts: Opts) -> Result<()> {
println!("checking packs...");
check_packs(be)?;
println!("loading index...");
let index = BoomIndex::from_iter(AllIndexFiles::new(be.clone()).into_iter());
println!("checking snapshots and trees...");
check_snapshots(be, &index)?;
if opts.read_data {
unimplemented!()
}
Ok(())
}
// calculate the pack size from the contained blobs
fn pack_size(blobs: &[IndexBlob]) -> u32 {
let mut size = 4 + 32; // 4 + crypto overhead
for blob in blobs {
size += blob.length() + 37 // 37 = length of blob description
}
size
}
// check if packs correspond to index
fn check_packs(be: &impl ReadBackend) -> Result<()> {
let mut packs = AllIndexFiles::new(be.clone())
.into_iter()
.map(|p| (*p.id(), pack_size(p.blobs())))
.collect::<HashMap<_, _>>();
for (id, size) in be.list_with_size(FileType::Pack)? {
match packs.remove(&id) {
None => println!("pack {} not contained in index", id.to_hex()),
Some(index_size) if index_size != size => println!(
"pack {}: size computed by index: {}, actual size: {}",
id.to_hex(),
index_size,
size
),
_ => {} //everything ok
}
}
for (id, _) in packs {
println!(
"pack {} is referenced by the index but not presend!",
id.to_hex()
);
}
Ok(())
}
// check if all snapshots and contained trees can be loaded and contents exist in the index
fn check_snapshots(be: &impl ReadBackend, index: &impl ReadIndex) -> Result<()> {
let snap_ids = be
.list(FileType::Snapshot)?
.into_iter()
.map(|id| SnapshotFile::from_backend(be, id).unwrap().tree)
.collect();
for path_node in tree_iterator_once(be, index, snap_ids) {
let fullname = path_node.path().join(path_node.node().name());
let node = path_node.node();
match node.tpe() as &str {
"file" => {
for (i, id) in node.content().iter().enumerate() {
if id.is_null() {
println!("file {:?} blob {} has null ID", fullname, i);
}
if index.get_id(id).is_none() {
println!("file {:?} blob {} is missig in index", fullname, id);
}
}
}
"dir" => {
if node.subtree().is_null() {
println!("dir {:?} subtree has null ID", fullname);
}
}
"symlink" | "socket" | "chardev" | "dev" | "fifo" => {} // nothing to check
tpe => println!("file {:?} unkown type {}", fullname, tpe),
}
}
Ok(())
}

View File

@ -7,6 +7,7 @@ use crate::backend::{DecryptBackend, LocalBackend};
use crate::repo;
mod cat;
mod check;
mod list;
mod ls;
mod snapshots;
@ -39,6 +40,9 @@ enum Command {
/// ls snapshots
Ls(ls::Opts),
/// check repository
Check(check::Opts),
}
pub fn execute() -> Result<()> {
@ -54,5 +58,6 @@ pub fn execute() -> Result<()> {
Command::Cat(opts) => cat::execute(&be, &dbe, opts),
Command::Snapshots(opts) => snapshots::execute(&dbe, opts),
Command::Ls(opts) => ls::execute(&dbe, opts),
Command::Check(opts) => check::execute(&dbe, opts),
}
}

View File

@ -33,4 +33,8 @@ impl Id {
pub fn to_hex(self) -> String {
hex::encode(self.0)
}
pub fn is_null(self) -> bool {
self == Id::default()
}
}