use clap::{arg, value_parser, Command};
use std::path::PathBuf;
use bitbottle::{FileScanner, HashType, ScanState};
use bitbottle::cli::{ProgressLine, to_binary_si};
pub fn main() {
let args = Command::new("buzscan")
.version("1.0")
.author("Robey Pointer <robey@lag.net>")
.about(
"Scans and hashes a list of files and folders (recursively) to determine
how much of the data is unique and how much is duplicated."
)
.args([
arg!(-v --verbose "list each file's metadata at the end"),
arg!(--blake2 "use blake2 hashing instead of sha-256"),
arg!(--blake3 "use blake3 hashing instead of sha-256"),
arg!(<PATH> ... "path(s) to scan").required(true).value_parser(value_parser!(PathBuf)),
])
.get_matches();
let mut hash_type = HashType::SHA256;
if args.get_flag("blake2") {
hash_type = HashType::BLAKE2;
}
if args.get_flag("blake3") {
hash_type = HashType::BLAKE2;
}
let progress = ProgressLine::new().to_shared();
let mut file_scanner = FileScanner::new(hash_type, 18, 20, 22, 10, vec![0u8; 65536], |state| {
let mut progress = progress.borrow_mut();
match state {
ScanState::FileList { file_count, bytes, .. } => {
progress.show_bar = false;
progress.update(0f64, format!("Scanning files: {:>8} files, disk space: {:>5}",
file_count, to_binary_si(bytes as f64)));
},
ScanState::Blocks { file_count, bytes, total_bytes, unique_bytes, .. } => {
progress.show_bar = true;
let percent = bytes as f64 / total_bytes as f64;
progress.update(percent, format!("{:>8} files, {:>5}/{:>5}, {:>5} unique",
file_count, to_binary_si(bytes as f64), to_binary_si(total_bytes as f64),
to_binary_si(unique_bytes as f64)));
if bytes == total_bytes {
progress.force_update();
}
}
}
progress.display();
});
file_scanner.scan_paths(&args.get_many::<PathBuf>("PATH").unwrap().map(PathBuf::from).collect::<Vec<_>>()).unwrap();
let file_list = file_scanner.build_block_list(hash_type).unwrap();
if args.get_flag("verbose") {
for atlas in &file_list.files {
let atlas = atlas.borrow();
println!("{:>5} {:>3o} {:>8} {:>8} {:>64} {}",
if atlas.is_folder { "".to_string() } else { to_binary_si(atlas.size as f64) },
atlas.perms & 0x1ff,
atlas.user,
atlas.group,
if atlas.is_folder { "".to_string() } else { hex::encode(atlas.contents.hash) },
atlas.path.as_path().display()
);
}
}
}