Cleanup and renaming of bindings.
This commit is contained in:
42
src/main.rs
42
src/main.rs
@@ -20,15 +20,15 @@ const FB_SECTOR_SIZE: u16 = 2048;
|
|||||||
struct Args {
|
struct Args {
|
||||||
/// Path to source file or block device
|
/// Path to source file or block device
|
||||||
#[arg(short, long, value_hint = clap::ValueHint::DirPath)]
|
#[arg(short, long, value_hint = clap::ValueHint::DirPath)]
|
||||||
input_file: PathBuf,
|
input: PathBuf,
|
||||||
|
|
||||||
/// Path to output file. Defaults to {input_file}.iso
|
/// Path to output file. Defaults to {input}.iso
|
||||||
#[arg(short, long, value_hint = clap::ValueHint::DirPath)]
|
#[arg(short, long, value_hint = clap::ValueHint::DirPath)]
|
||||||
output_file: Option<PathBuf>,
|
output: Option<PathBuf>,
|
||||||
|
|
||||||
/// Path to rescue map. Defaults to {input_file}.map
|
/// Path to rescue map. Defaults to {input}.map
|
||||||
#[arg(short, long, value_hint = clap::ValueHint::DirPath)]
|
#[arg(short, long, value_hint = clap::ValueHint::DirPath)]
|
||||||
map_file: Option<PathBuf>,
|
map: Option<PathBuf>,
|
||||||
|
|
||||||
/// Max number of consecutive sectors to test as a group
|
/// Max number of consecutive sectors to test as a group
|
||||||
#[arg(short, long, default_value_t = 128)]
|
#[arg(short, long, default_value_t = 128)]
|
||||||
@@ -51,25 +51,25 @@ fn main() {
|
|||||||
// I'm lazy and don't want to mess around with comparing error types.
|
// 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.
|
// Thus, any error in I/O here should be treated as fatal.
|
||||||
|
|
||||||
let mut input_file: File = {
|
let mut input: File = {
|
||||||
match OpenOptions::new()
|
match OpenOptions::new()
|
||||||
.custom_flags(O_DIRECT)
|
.custom_flags(O_DIRECT)
|
||||||
.read(true)
|
.read(true)
|
||||||
.write(false)
|
.write(false)
|
||||||
.append(false)
|
.append(false)
|
||||||
.create(false)
|
.create(false)
|
||||||
.open(&config.input_file.as_path())
|
.open(&config.input.as_path())
|
||||||
{
|
{
|
||||||
Ok(f) => f,
|
Ok(f) => f,
|
||||||
Err(err) => panic!("Failed to open input file: {:?}", err)
|
Err(err) => panic!("Failed to open input file: {:?}", err)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut output_file: File = {
|
let mut output: File = {
|
||||||
// Keep this clean, make a short-lived binding.
|
// Keep this clean, make a short-lived binding.
|
||||||
let path = get_path(
|
let path = get_path(
|
||||||
&config.output_file,
|
&config.output,
|
||||||
&config.input_file.to_str().unwrap(),
|
&config.input.to_str().unwrap(),
|
||||||
"iso"
|
"iso"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -88,21 +88,21 @@ fn main() {
|
|||||||
// Check if output file is shorter than input.
|
// Check if output file is shorter than input.
|
||||||
// If so, autoextend the output file.
|
// If so, autoextend the output file.
|
||||||
{
|
{
|
||||||
let input_len = get_stream_length(&mut input_file)
|
let input_len = get_stream_length(&mut input)
|
||||||
.expect("Failed to get the length of the input data.");
|
.expect("Failed to get the length of the input data.");
|
||||||
let output_len = get_stream_length(&mut output_file)
|
let output_len = get_stream_length(&mut output)
|
||||||
.expect("Failed to get the length of the output file.");
|
.expect("Failed to get the length of the output file.");
|
||||||
|
|
||||||
if output_len < input_len {
|
if output_len < input_len {
|
||||||
output_file.set_len(input_len)
|
output.set_len(input_len)
|
||||||
.expect("Failed to autofill output file.")
|
.expect("Failed to autofill output file.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let map: MapFile = {
|
let map: MapFile = {
|
||||||
let path = get_path(
|
let path = get_path(
|
||||||
&config.output_file,
|
&config.output,
|
||||||
&config.input_file.to_str().unwrap(),
|
&config.input.to_str().unwrap(),
|
||||||
"map"
|
"map"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -122,7 +122,7 @@ fn main() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let recover_tool = Recover::new(config, input_file, output_file, map);
|
let recover_tool = Recover::new(config, input, output, map);
|
||||||
|
|
||||||
recover_tool.run_full();
|
recover_tool.run_full();
|
||||||
|
|
||||||
@@ -130,18 +130,18 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Generates a file path if one not provided.
|
/// Generates a file path if one not provided.
|
||||||
/// source_file for fallback name.
|
/// source_name for fallback name.
|
||||||
fn get_path(
|
fn get_path(
|
||||||
output_file: &Option<PathBuf>,
|
output: &Option<PathBuf>,
|
||||||
source_file: &str,
|
source_name: &str,
|
||||||
extention: &str
|
extention: &str
|
||||||
) -> PathBuf {
|
) -> PathBuf {
|
||||||
if let Some(f) = output_file {
|
if let Some(f) = output {
|
||||||
f.to_owned()
|
f.to_owned()
|
||||||
} else {
|
} else {
|
||||||
PathBuf::from(format!(
|
PathBuf::from(format!(
|
||||||
"{:?}.{}",
|
"{:?}.{}",
|
||||||
source_file,
|
source_name,
|
||||||
extention,
|
extention,
|
||||||
))
|
))
|
||||||
.as_path()
|
.as_path()
|
||||||
|
|||||||
@@ -27,12 +27,11 @@ impl Domain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A map for data stored in memory for processing and saving to disk.
|
/// A map for data stored in memory for processing and saving to disk.
|
||||||
#[allow(unused)]
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
pub struct Cluster {
|
pub struct Cluster {
|
||||||
data: Option<Vec<u8>>,
|
data: Option<Vec<u8>>,
|
||||||
domain: Domain,
|
domain: Domain,
|
||||||
status: Status,
|
stage: Stage,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Cluster {
|
impl Default for Cluster {
|
||||||
@@ -40,7 +39,7 @@ impl Default for Cluster {
|
|||||||
Cluster {
|
Cluster {
|
||||||
data: None,
|
data: None,
|
||||||
domain: Domain::default(),
|
domain: Domain::default(),
|
||||||
status: Status::default()
|
stage: Stage::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,12 +51,12 @@ impl Default for Cluster {
|
|||||||
#[derive(Clone, Copy, Debug, Deserialize)]
|
#[derive(Clone, Copy, Debug, Deserialize)]
|
||||||
pub struct MapCluster {
|
pub struct MapCluster {
|
||||||
pub domain: Domain,
|
pub domain: Domain,
|
||||||
pub status: Status,
|
pub stage: Stage,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MapCluster {
|
impl Default for MapCluster {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
MapCluster { domain: Domain::default(), status: Status::default() }
|
MapCluster { domain: Domain::default(), stage: Stage::default() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,27 +64,26 @@ impl From<Cluster> for MapCluster {
|
|||||||
fn from(cluster: Cluster) -> Self {
|
fn from(cluster: Cluster) -> Self {
|
||||||
MapCluster {
|
MapCluster {
|
||||||
domain: cluster.domain,
|
domain: cluster.domain,
|
||||||
status: cluster.status,
|
stage: cluster.stage,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd)]
|
#[derive(Clone, Copy, Debug, Deserialize, PartialEq, PartialOrd)]
|
||||||
pub enum Status {
|
pub enum Stage {
|
||||||
Untested,
|
Untested,
|
||||||
ForIsolation(u8),
|
ForIsolation(u8),
|
||||||
Damaged,
|
Damaged,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Status {
|
impl Default for Stage {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Status::Untested
|
Stage::Untested
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
#[derive(Clone, Debug, Deserialize)]
|
#[derive(Clone, Debug, Deserialize)]
|
||||||
pub struct MapFile {
|
pub struct MapFile {
|
||||||
pub sector_size: u16,
|
pub sector_size: u16,
|
||||||
@@ -108,13 +106,12 @@ impl Default for MapFile {
|
|||||||
domain: Domain::default(),
|
domain: Domain::default(),
|
||||||
map: vec![MapCluster {
|
map: vec![MapCluster {
|
||||||
domain: Domain::default(),
|
domain: Domain::default(),
|
||||||
status: Status::Untested,
|
stage: Stage::Untested,
|
||||||
}],
|
}],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
impl MapFile {
|
impl MapFile {
|
||||||
pub fn new(sector_size: u16) -> Self {
|
pub fn new(sector_size: u16) -> Self {
|
||||||
MapFile::default()
|
MapFile::default()
|
||||||
@@ -128,13 +125,13 @@ impl MapFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Recalculate cluster mappings.
|
/// Recalculate cluster mappings.
|
||||||
fn update(self, new_cluster: Cluster) {
|
fn update(&mut self, new_cluster: Cluster) {
|
||||||
let mut new_map: Vec<MapCluster> = vec![MapCluster::from(new_cluster.to_owned())];
|
let mut new_map: Vec<MapCluster> = vec![MapCluster::from(new_cluster.to_owned())];
|
||||||
|
|
||||||
for map_cluster in self.map.iter() {
|
for map_cluster in self.map.iter() {
|
||||||
let mut map_cluster = *map_cluster;
|
let mut map_cluster = *map_cluster;
|
||||||
|
|
||||||
// If new_cluster doesn't start ahead and end short, map_cluster is forgotten.
|
// If new_cluster doesn't start ahead and ends short, map_cluster is forgotten.
|
||||||
if new_cluster.domain.start < map_cluster.domain.start
|
if new_cluster.domain.start < map_cluster.domain.start
|
||||||
&& new_cluster.domain.end < map_cluster.domain.end {
|
&& new_cluster.domain.end < map_cluster.domain.end {
|
||||||
/*
|
/*
|
||||||
@@ -173,7 +170,7 @@ impl MapFile {
|
|||||||
start: new_cluster.domain.end,
|
start: new_cluster.domain.end,
|
||||||
end: domain_end,
|
end: domain_end,
|
||||||
},
|
},
|
||||||
status: map_cluster.status.to_owned()
|
stage: map_cluster.stage.to_owned()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -186,44 +183,46 @@ impl MapFile {
|
|||||||
new_map.push(map_cluster);
|
new_map.push(map_cluster);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.map = new_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get current recovery status.
|
/// Get current recovery stage.
|
||||||
pub fn get_state(self) -> Status {
|
pub fn get_stage(&self) -> Stage {
|
||||||
let mut recover_status = Status::Damaged;
|
let mut recover_stage = Stage::Damaged;
|
||||||
|
|
||||||
for cluster in self.map {
|
for cluster in self.map.iter() {
|
||||||
match cluster.status {
|
match cluster.stage {
|
||||||
Status::Untested => return Status::Untested,
|
Stage::Untested => return Stage::Untested,
|
||||||
Status::ForIsolation(_) => {
|
Stage::ForIsolation(_) => {
|
||||||
if recover_status == Status::Damaged
|
if recover_stage == Stage::Damaged
|
||||||
|| cluster.status < recover_status {
|
|| cluster.stage < recover_stage {
|
||||||
// Note that recover_status after first condition is
|
// Note that recover_stage after first condition is
|
||||||
// only ever Status::ForIsolation(_), thus PartialEq,
|
// only ever Stage::ForIsolation(_), thus PartialEq,
|
||||||
// PartialOrd are useful for comparing the internal value.
|
// PartialOrd are useful for comparing the internal value.
|
||||||
recover_status = cluster.status
|
recover_stage = cluster.stage
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Status::Damaged => (),
|
Stage::Damaged => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
recover_status
|
recover_stage
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get clusters of common status.
|
/// Get clusters of common stage.
|
||||||
pub fn get_clusters(self, state: Status) -> Vec<MapCluster> {
|
pub fn get_clusters(self, stage: Stage) -> Vec<MapCluster> {
|
||||||
self.map.iter()
|
self.map.iter()
|
||||||
.filter_map(|mc| {
|
.filter_map(|mc| {
|
||||||
if mc.status == state { Some(mc.to_owned()) } else { None }
|
if mc.stage == stage { Some(mc.to_owned()) } else { None }
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Defragments cluster groups.
|
/// Defragments cluster groups.
|
||||||
/// I.E. check forwards every cluster from current until status changes,
|
/// I.E. check forwards every cluster from current until stage changes,
|
||||||
/// then group at once.
|
/// then group at once.
|
||||||
fn defrag(&mut self) {
|
fn defrag(&mut self) -> &mut Self {
|
||||||
let mut new_map: Vec<MapCluster> = vec![];
|
let mut new_map: Vec<MapCluster> = vec![];
|
||||||
|
|
||||||
let mut pos: usize = 0;
|
let mut pos: usize = 0;
|
||||||
@@ -237,33 +236,34 @@ impl MapFile {
|
|||||||
let mut end_cluster = MapCluster::default();
|
let mut end_cluster = MapCluster::default();
|
||||||
let mut new_cluster: MapCluster;
|
let mut new_cluster: MapCluster;
|
||||||
|
|
||||||
let mut status_common: bool;
|
let mut stage_common: bool;
|
||||||
|
|
||||||
while pos < self.domain.end {
|
while pos < self.domain.end {
|
||||||
status_common = true;
|
stage_common = true;
|
||||||
|
|
||||||
// Start a new cluster based on the cluster following
|
// Start a new cluster based on the cluster following
|
||||||
// the end of last new_cluster.
|
// the end of last new_cluster.
|
||||||
new_cluster = start_cluster;
|
new_cluster = start_cluster;
|
||||||
|
|
||||||
// While status is common, find each trailing cluster.
|
// While stage is common, find each trailing cluster.
|
||||||
while status_common {
|
while stage_common {
|
||||||
// start_cluster was of common status to end_cluster.
|
// start_cluster was of common stage to end_cluster.
|
||||||
end_cluster = start_cluster;
|
end_cluster = start_cluster;
|
||||||
|
|
||||||
start_cluster = *self.map.iter()
|
start_cluster = *self.map.iter()
|
||||||
.find(|c| end_cluster.domain.end == c.domain.start)
|
.find(|c| end_cluster.domain.end == c.domain.start)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
status_common = new_cluster.status == start_cluster.status
|
stage_common = new_cluster.stage == start_cluster.stage
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the new ending, encapsulating any clusters of common status.
|
// Set the new ending, encapsulating any clusters of common stage.
|
||||||
new_cluster.domain.end = end_cluster.domain.end;
|
new_cluster.domain.end = end_cluster.domain.end;
|
||||||
pos = new_cluster.domain.end;
|
pos = new_cluster.domain.end;
|
||||||
new_map.push(new_cluster);
|
new_map.push(new_cluster);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.map = new_map;
|
self.map = new_map;
|
||||||
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5,11 +5,10 @@ use std::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
Args,
|
Args,
|
||||||
mapping::{MapFile, Status},
|
mapping::{MapFile, Stage},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Recover {
|
pub struct Recover {
|
||||||
buf_capacity: usize,
|
buf_capacity: usize,
|
||||||
@@ -17,12 +16,13 @@ pub struct Recover {
|
|||||||
input: BufReader<File>,
|
input: BufReader<File>,
|
||||||
output: BufWriter<File>,
|
output: BufWriter<File>,
|
||||||
map: MapFile,
|
map: MapFile,
|
||||||
stage: Status,
|
stage: Stage,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
impl Recover {
|
impl Recover {
|
||||||
pub fn new(config: Args, input: File, output: File, map: MapFile) -> Self {
|
pub fn new(config: Args, input: File, output: File, map: MapFile) -> Self {
|
||||||
|
let stage = map.get_stage();
|
||||||
|
|
||||||
// Temporarily make buffer length one sector.
|
// Temporarily make buffer length one sector.
|
||||||
let buf_capacity = config.sector_size as usize;
|
let buf_capacity = config.sector_size as usize;
|
||||||
let mut r = Recover {
|
let mut r = Recover {
|
||||||
@@ -37,7 +37,7 @@ impl Recover {
|
|||||||
output,
|
output,
|
||||||
),
|
),
|
||||||
map,
|
map,
|
||||||
stage: Status::Untested,
|
stage: stage,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Ensure that buffer capacity is adjusted based on progress.
|
// Ensure that buffer capacity is adjusted based on progress.
|
||||||
|
|||||||
Reference in New Issue
Block a user