mirror of
https://github.com/rustic-rs/rustic.git
synced 2025-10-26 11:18:51 +00:00
add check command
This commit is contained in:
parent
648b5830ee
commit
5101ead24c
111
src/commands/check.rs
Normal file
111
src/commands/check.rs
Normal 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(())
|
||||
}
|
||||
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user