Huge refactor. Introduce anyhow for error handling.

This commit is contained in:
Cutieguwu
2025-12-29 15:31:01 -05:00
parent e98383d9e5
commit 4b5460f754
13 changed files with 411 additions and 746 deletions

View File

@@ -1,87 +1,49 @@
mod cli;
mod io;
mod mapping;
mod recovery;
use std::fs::{File, OpenOptions};
use std::path::{Path, PathBuf};
use clap::Parser;
use mapping::MapFile;
use cli::Args;
use mapping::prelude::*;
use recovery::Recover;
use anyhow::{self, Context};
use clap::Parser;
const FB_SECTOR_SIZE: u16 = 2048;
const FB_PAD_VALUE: u8 = 0;
#[derive(Parser, Debug)]
struct Args {
/// Path to source file or block device
#[arg(short, long, value_hint = clap::ValueHint::DirPath)]
input: PathBuf,
/// Path to output file. Defaults to {input}.iso
#[arg(short, long, value_hint = clap::ValueHint::DirPath)]
output: Option<PathBuf>,
/// Path to rescue map. Defaults to {input}.map
#[arg(short, long, value_hint = clap::ValueHint::DirPath)]
map: Option<PathBuf>,
/// Max number of consecutive sectors to test as a group
#[arg(short, long, default_value_t = 128)]
cluster_length: u16,
/// Number of brute force read passes
#[arg(short, long, default_value_t = 2)]
brute_passes: usize,
/// Sector size
#[arg(short, long, default_value_t = FB_SECTOR_SIZE)]
sector_size: u16,
}
fn main() {
fn main() -> anyhow::Result<()> {
let config = Args::parse();
// Live with it, prefer to use expect() here.
// I'm lazy and don't want to mess around with comparing error types.
// Thus, any error in I/O here should be treated as fatal.
let mut input: File = OpenOptions::new()
.read(true)
.open(&config.input.as_path())
.expect("Failed to open input file");
let mut input: File = {
let input_path = &config.input.as_path();
OpenOptions::new()
.read(true)
.open(&input_path)
.with_context(move || format!("Failed to open input file: {}", input_path.display()))?
};
let output: File = {
// Keep this clean, make a short-lived binding.
let path = get_path(&config.output, &config.input.to_str().unwrap(), "iso");
let path = crate::io::get_path(&config.output, &config.input, "iso")
.context("Failed to generate output path.")?;
OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(path)
.expect("Failed to open/create output file")
.open(&path)
.with_context(|| format!("Failed to open/create output file at: {}", path.display()))?
};
// Check if output file is shorter than input.
// If so, autoextend the output file.
//
// Is this actually needed? I don't think I need to preallocate the space.
/*
{
let input_len =
get_stream_length(&mut input).expect("Failed to get the length of the input data.");
let output_len =
get_stream_length(&mut output).expect("Failed to get the length of the output file.");
if output_len < input_len {
output
.set_len(input_len)
.expect("Failed to autofill output file.")
}
}
*/
/*
let map: MapFile = {
let path = get_path(
@@ -107,49 +69,16 @@ fn main() {
};
*/
let buf_capacity =
crate::io::get_stream_length(&mut input).expect("Failed to get buffer capacity from input");
let mut recover_tool = {
let buf_capacity = crate::io::get_stream_length(&mut input)
.context("Failed to get buffer capacity from input")?;
let mut recover_tool = Recover::new(config, input, output, MapFile::default(), buf_capacity);
Recover::new(&config, input, output, MapFile::default(), buf_capacity)
};
recover_tool.run();
//todo!("Recovery, Map saving, and closure of all files.");
/*
let mut buf: Vec<u8> = Vec::with_capacity(
get_stream_length(&mut input).expect("Failed to get the length of the input data.")
as usize,
);
println!(
"Read {} bytes",
input
.read_to_end(&mut buf)
.expect("Failed to read complete input stream.")
);
println!("Wrote {} bytes", {
output
.write_all(&buf)
.expect("Failed to write complete output stream.");
&buf.len()
});
*/
}
/// Generates a file path if one not provided.
/// source_name for fallback name.
fn get_path<P>(file_path: &Option<P>, source_name: &str, extension: &str) -> PathBuf
where
P: AsRef<Path>,
{
if let Some(f) = file_path {
f.as_ref().to_path_buf()
} else {
PathBuf::from(format!("{:?}.{}", source_name, extension))
.as_path()
.to_owned()
}
Ok(())
}
#[cfg(test)]