btrfs-ioerror-deleter/src/main.rs

92 lines
2.7 KiB
Rust

use std::io::Read;
use std::io::Write;
use std::os::unix::fs::FileTypeExt;
use std::path::PathBuf;
fn main() {
let args: Vec<_> = std::env::args().collect();
match args.len() {
2 => {
travess_for_ioerrors(args[1].clone().into());
print!("\r\x1B[0K");
std::io::stdout().flush().unwrap();
}
_ => println!("Usage:\n {} BTRFS_MOUNT_POINT", args[0]),
}
}
fn travess_for_ioerrors(path: PathBuf) {
match path.metadata() {
Ok(metadata) => {
let ft = metadata.file_type();
if ft.is_block_device()
|| ft.is_char_device()
|| ft.is_fifo()
|| ft.is_socket()
|| ft.is_symlink()
{
// Ignore non-content files
} else if ft.is_dir() {
for subpath in path.read_dir().unwrap() {
// handle corrupt file listing instead of blindly unwrapping
travess_for_ioerrors(subpath.unwrap().path()); // handle corrupt file entry instead of blindly unwrapping
}
} else if ft.is_file() {
deal_with_file(path);
} else {
// Skip unexpected file
}
}
Err(_) => {
eprintln!("\r{}\x1B[0K", path.to_string_lossy());
std::io::stdout().flush().unwrap();
// handle corrupt metadata
}
}
}
fn deal_with_file(path: PathBuf) {
print!("\r{}\x1B[0K", path.to_string_lossy());
std::io::stdout().flush().unwrap();
let mut file = std::fs::File::open(&path).unwrap();
let mut list_of_chunks = Vec::new();
let chunk_size = 0x4000;
loop {
let mut chunk = Vec::with_capacity(chunk_size);
let rn = std::io::Read::by_ref(&mut file)
.take(chunk_size as u64)
.read_to_end(&mut chunk);
match rn {
Ok(n) => {
if n == 0 {
break;
}
list_of_chunks.push(chunk);
if n < chunk_size {
break;
}
}
Err(e) => {
if Some(5) == e.raw_os_error() {
print!("[x]");
std::io::stdout().flush().unwrap();
deal_with_bad_files(path);
println!("[v]");
std::io::stdout().flush().unwrap();
}
break;
}
}
}
}
fn deal_with_bad_files(path: PathBuf) {
if path.is_dir() {
std::fs::remove_dir_all(path).unwrap_or(());
} else {
std::fs::remove_file(path).unwrap_or(());
}
}