Last push of ditched initial design.
This is only getting pushed for reference' sake. I don't even know how functional this version is.
This commit is contained in:
Generated
+1382
-5
File diff suppressed because it is too large
Load Diff
+3
-1
@@ -8,6 +8,8 @@ license = "MIT"
|
|||||||
publish = false
|
publish = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
num-traits = "0.2.19"
|
||||||
|
ratatui = "0.30"
|
||||||
ron = ">=0.8, <0.13"
|
ron = ">=0.8, <0.13"
|
||||||
#rust-i18n = "3.1.3"
|
#rust-i18n = "3.1.3"
|
||||||
|
|
||||||
@@ -28,6 +30,6 @@ features = ["derive"]
|
|||||||
# with unsafe ffi disasters trying to solve problems.
|
# with unsafe ffi disasters trying to solve problems.
|
||||||
#
|
#
|
||||||
# And yes, I spent time tracking down the first release with that constant.
|
# And yes, I spent time tracking down the first release with that constant.
|
||||||
# v0.2.25 is almost 9 years old as of writing this comment
|
# v0.2.25 is almost 9 years old as of writing this comment.
|
||||||
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies]
|
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies]
|
||||||
libc = "~0.2.25"
|
libc = "~0.2.25"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use clap::{ArgAction, Parser};
|
|||||||
pub static CONFIG: LazyLock<Args> = LazyLock::new(|| Args::parse());
|
pub static CONFIG: LazyLock<Args> = LazyLock::new(|| Args::parse());
|
||||||
|
|
||||||
#[derive(Parser, Debug, Clone)]
|
#[derive(Parser, Debug, Clone)]
|
||||||
|
#[clap(author, version, about)]
|
||||||
pub struct Args {
|
pub 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)]
|
||||||
@@ -50,4 +51,8 @@ pub struct Args {
|
|||||||
#[cfg(all(unix, not(target_os = "macos")))]
|
#[cfg(all(unix, not(target_os = "macos")))]
|
||||||
#[arg(short = 'd', long = "no-direct", action = ArgAction::SetFalse)]
|
#[arg(short = 'd', long = "no-direct", action = ArgAction::SetFalse)]
|
||||||
pub direct_io: bool,
|
pub direct_io: bool,
|
||||||
|
|
||||||
|
/// Disable the TUI in favour of a classic CLI experience.
|
||||||
|
#[arg(short = 't', long = "no-tui", action = ArgAction::SetFalse)]
|
||||||
|
pub tui: bool,
|
||||||
}
|
}
|
||||||
|
|||||||
+33
@@ -3,8 +3,14 @@ mod io;
|
|||||||
mod mapping;
|
mod mapping;
|
||||||
mod path;
|
mod path;
|
||||||
mod recovery;
|
mod recovery;
|
||||||
|
mod tui;
|
||||||
|
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
use cli::CONFIG;
|
||||||
use recovery::Recover;
|
use recovery::Recover;
|
||||||
|
use tui::Tui;
|
||||||
|
|
||||||
use anyhow;
|
use anyhow;
|
||||||
|
|
||||||
@@ -18,5 +24,32 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let mut recover_tool = Recover::new()?;
|
let mut recover_tool = Recover::new()?;
|
||||||
recover_tool.run()?;
|
recover_tool.run()?;
|
||||||
|
|
||||||
|
if CONFIG.tui {
|
||||||
|
run_tui()?;
|
||||||
|
} else {
|
||||||
|
run_cli();
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn run_cli() {}
|
||||||
|
|
||||||
|
fn run_tui() -> std::io::Result<()> {
|
||||||
|
let mut tui = Tui::new();
|
||||||
|
|
||||||
|
// Enter Raw terminal mode.
|
||||||
|
let mut terminal = ratatui::init();
|
||||||
|
|
||||||
|
let (tx, rx) = mpsc::channel::<crate::tui::Event>();
|
||||||
|
|
||||||
|
let tx_input_fetcher = tx.clone();
|
||||||
|
thread::spawn(move || tui::input_fetcher(tx_input_fetcher));
|
||||||
|
|
||||||
|
let tui_result = tui.run(&mut terminal, rx);
|
||||||
|
|
||||||
|
// Exit Raw terminal mode.
|
||||||
|
ratatui::restore();
|
||||||
|
|
||||||
|
tui_result
|
||||||
|
}
|
||||||
|
|||||||
+4
-10
@@ -7,14 +7,14 @@ use serde::{Deserialize, Serialize};
|
|||||||
// Use `sort_by_key()` to be safe.
|
// Use `sort_by_key()` to be safe.
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Cluster {
|
pub struct Cluster {
|
||||||
pub domain: Domain,
|
domain: Domain<usize>,
|
||||||
pub stage: Stage,
|
pub stage: Stage,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Cluster {
|
impl Default for Cluster {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain::default(),
|
domain: Domain::from(0..1),
|
||||||
stage: Stage::default(),
|
stage: Stage::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -31,10 +31,7 @@ impl Cluster {
|
|||||||
|
|
||||||
for _ in 0..(domain_len / cluster_len) {
|
for _ in 0..(domain_len / cluster_len) {
|
||||||
clusters.push(Cluster {
|
clusters.push(Cluster {
|
||||||
domain: Domain {
|
domain: Domain::from(start..start + cluster_len),
|
||||||
start,
|
|
||||||
end: start + cluster_len,
|
|
||||||
},
|
|
||||||
stage: self.stage,
|
stage: self.stage,
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -42,10 +39,7 @@ impl Cluster {
|
|||||||
}
|
}
|
||||||
|
|
||||||
clusters.push(Cluster {
|
clusters.push(Cluster {
|
||||||
domain: Domain {
|
domain: Domain::from(start..self.domain.end),
|
||||||
start,
|
|
||||||
end: self.domain.end,
|
|
||||||
},
|
|
||||||
stage: self.stage,
|
stage: self.stage,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
+31
-19
@@ -1,28 +1,20 @@
|
|||||||
|
use std::ops::{Deref, DerefMut, Range};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
/// Domain, in sectors.
|
/// Domain, in sectors.
|
||||||
/// Requires sector_size to be provided elsewhere for conversion to bytes.
|
/// Requires sector_size to be provided elsewhere for conversion to bytes.
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Domain {
|
pub struct Domain<Idx>(Range<Idx>)
|
||||||
pub start: usize,
|
where
|
||||||
pub end: usize,
|
Idx: PartialEq + Eq + PartialOrd + Ord;
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Domain {
|
|
||||||
fn default() -> Self {
|
|
||||||
Domain { start: 0, end: 1 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Domain {
|
|
||||||
/// Return length of domain in sectors.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn len(self) -> usize {
|
|
||||||
self.end - self.start
|
|
||||||
}
|
|
||||||
|
|
||||||
|
impl<Idx> Domain<Idx>
|
||||||
|
where
|
||||||
|
Idx: PartialEq + PartialOrd + Ord,
|
||||||
|
{
|
||||||
/// Returns the type of overlap between this domain and another.
|
/// Returns the type of overlap between this domain and another.
|
||||||
pub fn overlap(&self, other: Domain) -> DomainOverlap {
|
pub fn overlap(&self, other: Self) -> DomainOverlap {
|
||||||
if self.end <= other.start || other.end <= self.start {
|
if self.end <= other.start || other.end <= self.start {
|
||||||
// Cases 7, 8, 12, and 13 of map::tests::test_update
|
// Cases 7, 8, 12, and 13 of map::tests::test_update
|
||||||
DomainOverlap::None
|
DomainOverlap::None
|
||||||
@@ -42,6 +34,26 @@ impl Domain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<Idx> Deref for Domain<Idx> {
|
||||||
|
type Target = Range<Idx>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Idx> DerefMut for Domain<Idx> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Idx> From<Range<Idx>> for Domain<Idx> {
|
||||||
|
fn from(value: Range<Idx>) -> Self {
|
||||||
|
Self(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub enum DomainOverlap {
|
pub enum DomainOverlap {
|
||||||
None,
|
None,
|
||||||
SelfEngulfsOther,
|
SelfEngulfsOther,
|
||||||
|
|||||||
+75
-81
@@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize};
|
|||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
pub struct MapFile {
|
pub struct MapFile {
|
||||||
pub sector_size: usize,
|
pub sector_size: usize,
|
||||||
pub domain: Domain,
|
pub domain: Domain<usize>,
|
||||||
pub map: Vec<Cluster>,
|
pub map: Vec<Cluster>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,9 +29,9 @@ impl Default for MapFile {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
MapFile {
|
MapFile {
|
||||||
sector_size: crate::FB_SECTOR_SIZE,
|
sector_size: crate::FB_SECTOR_SIZE,
|
||||||
domain: Domain::default(),
|
domain: Domain::from(0..1),
|
||||||
map: vec![Cluster {
|
map: vec![Cluster {
|
||||||
domain: Domain::default(),
|
domain: Domain::from(0..1),
|
||||||
stage: Stage::Patchwork { depth: 0 },
|
stage: Stage::Patchwork { depth: 0 },
|
||||||
}],
|
}],
|
||||||
}
|
}
|
||||||
@@ -136,7 +136,7 @@ impl MapFile {
|
|||||||
/// Extend the domain of the MapFile.
|
/// Extend the domain of the MapFile.
|
||||||
/// Returns None if the domain cannot be changed or is unchanged.
|
/// Returns None if the domain cannot be changed or is unchanged.
|
||||||
/// Returns the delta of the previous domain end and the new end.
|
/// Returns the delta of the previous domain end and the new end.
|
||||||
pub fn extend(&mut self, end: usize) -> Option<usize> {
|
pub fn extend(&mut self..usize) -> Option<usize> {
|
||||||
if end <= self.domain.end {
|
if end <= self.domain.end {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -147,10 +147,7 @@ impl MapFile {
|
|||||||
|
|
||||||
// Add new data as untested.
|
// Add new data as untested.
|
||||||
self.update(Cluster {
|
self.update(Cluster {
|
||||||
domain: Domain {
|
domain: Domain::from(old_end..self.domain.end),
|
||||||
start: old_end,
|
|
||||||
end: self.domain.end,
|
|
||||||
},
|
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
Some(delta)
|
Some(delta)
|
||||||
@@ -189,10 +186,7 @@ fn other_engulfs_self_update(new: Cluster, old: &mut Cluster, map: &mut Vec<Clus
|
|||||||
if new.domain.end != old_end {
|
if new.domain.end != old_end {
|
||||||
// Case 10 of map::tests::test_update
|
// Case 10 of map::tests::test_update
|
||||||
map.push(Cluster {
|
map.push(Cluster {
|
||||||
domain: Domain {
|
domain: Domain::from(new.domain.end..old_end),
|
||||||
start: new.domain.end,
|
|
||||||
end: old_end,
|
|
||||||
},
|
|
||||||
stage: old.stage,
|
stage: old.stage,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -217,14 +211,14 @@ mod tests {
|
|||||||
|
|
||||||
let mut map = MapFile {
|
let mut map = MapFile {
|
||||||
map: vec![Cluster {
|
map: vec![Cluster {
|
||||||
domain: Domain { start: 1, end: 3 },
|
domain: Domain::from(1..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
map.update(Cluster {
|
map.update(Cluster {
|
||||||
domain: Domain { start: 0, end: 2 },
|
domain: Domain::from(0..2),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
map.map.sort();
|
map.map.sort();
|
||||||
@@ -233,11 +227,11 @@ mod tests {
|
|||||||
map.map,
|
map.map,
|
||||||
vec![
|
vec![
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 0, end: 2 },
|
domain: Domain::from(0..2),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 2, end: 3 },
|
domain: Domain::from(2..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -256,14 +250,14 @@ mod tests {
|
|||||||
|
|
||||||
let mut map = MapFile {
|
let mut map = MapFile {
|
||||||
map: vec![Cluster {
|
map: vec![Cluster {
|
||||||
domain: Domain { start: 0, end: 2 },
|
domain: Domain::from(0..2),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
map.update(Cluster {
|
map.update(Cluster {
|
||||||
domain: Domain { start: 1, end: 3 },
|
domain: Domain::from(1..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
map.map.sort();
|
map.map.sort();
|
||||||
@@ -272,11 +266,11 @@ mod tests {
|
|||||||
map.map,
|
map.map,
|
||||||
vec![
|
vec![
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 0, end: 1 },
|
domain: Domain::from(0..1),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 1, end: 3 },
|
domain: Domain::from(1..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -294,14 +288,14 @@ mod tests {
|
|||||||
|
|
||||||
let mut map = MapFile {
|
let mut map = MapFile {
|
||||||
map: vec![Cluster {
|
map: vec![Cluster {
|
||||||
domain: Domain { start: 1, end: 3 },
|
domain: Domain::from(1..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
map.update(Cluster {
|
map.update(Cluster {
|
||||||
domain: Domain { start: 0, end: 3 },
|
domain: Domain::from(0..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
map.map.sort();
|
map.map.sort();
|
||||||
@@ -309,7 +303,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
map.map,
|
map.map,
|
||||||
vec![Cluster {
|
vec![Cluster {
|
||||||
domain: Domain { start: 0, end: 3 },
|
domain: Domain::from(0..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
@@ -327,14 +321,14 @@ mod tests {
|
|||||||
|
|
||||||
let mut map = MapFile {
|
let mut map = MapFile {
|
||||||
map: vec![Cluster {
|
map: vec![Cluster {
|
||||||
domain: Domain { start: 0, end: 3 },
|
domain: Domain::from(0..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
map.update(Cluster {
|
map.update(Cluster {
|
||||||
domain: Domain { start: 1, end: 3 },
|
domain: Domain::from(1..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
map.map.sort();
|
map.map.sort();
|
||||||
@@ -343,11 +337,11 @@ mod tests {
|
|||||||
map.map,
|
map.map,
|
||||||
vec![
|
vec![
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 0, end: 1 },
|
domain: Domain::from(0..1),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 1, end: 3 },
|
domain: Domain::from(1..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -365,14 +359,14 @@ mod tests {
|
|||||||
|
|
||||||
let mut map = MapFile {
|
let mut map = MapFile {
|
||||||
map: vec![Cluster {
|
map: vec![Cluster {
|
||||||
domain: Domain { start: 0, end: 2 },
|
domain: Domain::from(0..2),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
map.update(Cluster {
|
map.update(Cluster {
|
||||||
domain: Domain { start: 0, end: 3 },
|
domain: Domain::from(0..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
map.map.sort();
|
map.map.sort();
|
||||||
@@ -380,7 +374,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
map.map,
|
map.map,
|
||||||
vec![Cluster {
|
vec![Cluster {
|
||||||
domain: Domain { start: 0, end: 3 },
|
domain: Domain::from(0..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
@@ -398,14 +392,14 @@ mod tests {
|
|||||||
|
|
||||||
let mut map = MapFile {
|
let mut map = MapFile {
|
||||||
map: vec![Cluster {
|
map: vec![Cluster {
|
||||||
domain: Domain { start: 0, end: 3 },
|
domain: Domain::from(0..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
map.update(Cluster {
|
map.update(Cluster {
|
||||||
domain: Domain { start: 0, end: 2 },
|
domain: Domain::from(0..2),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
map.map.sort();
|
map.map.sort();
|
||||||
@@ -414,11 +408,11 @@ mod tests {
|
|||||||
map.map,
|
map.map,
|
||||||
vec![
|
vec![
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 0, end: 2 },
|
domain: Domain::from(0..2),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 2, end: 3 },
|
domain: Domain::from(2..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -436,14 +430,14 @@ mod tests {
|
|||||||
|
|
||||||
let mut map = MapFile {
|
let mut map = MapFile {
|
||||||
map: vec![Cluster {
|
map: vec![Cluster {
|
||||||
domain: Domain { start: 2, end: 3 },
|
domain: Domain::from(2..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
map.update(Cluster {
|
map.update(Cluster {
|
||||||
domain: Domain { start: 0, end: 2 },
|
domain: Domain::from(0..2),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
map.map.sort();
|
map.map.sort();
|
||||||
@@ -452,11 +446,11 @@ mod tests {
|
|||||||
map.map,
|
map.map,
|
||||||
vec![
|
vec![
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 0, end: 2 },
|
domain: Domain::from(0..2),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 2, end: 3 },
|
domain: Domain::from(2..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -473,14 +467,14 @@ mod tests {
|
|||||||
|
|
||||||
let mut map = MapFile {
|
let mut map = MapFile {
|
||||||
map: vec![Cluster {
|
map: vec![Cluster {
|
||||||
domain: Domain { start: 0, end: 2 },
|
domain: Domain::from(0..2),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
map.update(Cluster {
|
map.update(Cluster {
|
||||||
domain: Domain { start: 2, end: 3 },
|
domain: Domain::from(2..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
map.map.sort();
|
map.map.sort();
|
||||||
@@ -489,11 +483,11 @@ mod tests {
|
|||||||
map.map,
|
map.map,
|
||||||
vec![
|
vec![
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 0, end: 2 },
|
domain: Domain::from(0..2),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 2, end: 3 },
|
domain: Domain::from(2..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -511,14 +505,14 @@ mod tests {
|
|||||||
|
|
||||||
let mut map = MapFile {
|
let mut map = MapFile {
|
||||||
map: vec![Cluster {
|
map: vec![Cluster {
|
||||||
domain: Domain { start: 1, end: 2 },
|
domain: Domain::from(1..2),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
map.update(Cluster {
|
map.update(Cluster {
|
||||||
domain: Domain { start: 0, end: 3 },
|
domain: Domain::from(0..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
map.map.sort();
|
map.map.sort();
|
||||||
@@ -526,7 +520,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
map.map,
|
map.map,
|
||||||
vec![Cluster {
|
vec![Cluster {
|
||||||
domain: Domain { start: 0, end: 3 },
|
domain: Domain::from(0..3 ),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
@@ -548,14 +542,14 @@ mod tests {
|
|||||||
|
|
||||||
let mut map = MapFile {
|
let mut map = MapFile {
|
||||||
map: vec![Cluster {
|
map: vec![Cluster {
|
||||||
domain: Domain { start: 0, end: 3 },
|
domain: Domain::from(0..3),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
map.update(Cluster {
|
map.update(Cluster {
|
||||||
domain: Domain { start: 1, end: 2 },
|
domain: Domain::from(1..2 ),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
map.map.sort();
|
map.map.sort();
|
||||||
@@ -564,15 +558,15 @@ mod tests {
|
|||||||
map.map,
|
map.map,
|
||||||
vec![
|
vec![
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 0, end: 1 },
|
domain: Domain::from(0..1 ),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 1, end: 2 },
|
domain: Domain::from(1..2 ),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 2, end: 3 },
|
domain: Domain::from(2..3 ),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -590,14 +584,14 @@ mod tests {
|
|||||||
|
|
||||||
let mut map = MapFile {
|
let mut map = MapFile {
|
||||||
map: vec![Cluster {
|
map: vec![Cluster {
|
||||||
domain: Domain { start: 0, end: 3 },
|
domain: Domain::from(0..3 ),
|
||||||
stage: Stage::Patchwork { depth: 0 },
|
stage: Stage::Patchwork { depth: 0 },
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
map.update(Cluster {
|
map.update(Cluster {
|
||||||
domain: Domain { start: 0, end: 3 },
|
domain: Domain::from(0..3 ),
|
||||||
stage: Stage::Intact,
|
stage: Stage::Intact,
|
||||||
});
|
});
|
||||||
map.map.sort();
|
map.map.sort();
|
||||||
@@ -605,7 +599,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
map.map,
|
map.map,
|
||||||
vec![Cluster {
|
vec![Cluster {
|
||||||
domain: Domain { start: 0, end: 3 },
|
domain: Domain::from(0..3 ),
|
||||||
stage: Stage::Intact
|
stage: Stage::Intact
|
||||||
}]
|
}]
|
||||||
);
|
);
|
||||||
@@ -622,14 +616,14 @@ mod tests {
|
|||||||
|
|
||||||
let mut map = MapFile {
|
let mut map = MapFile {
|
||||||
map: vec![Cluster {
|
map: vec![Cluster {
|
||||||
domain: Domain { start: 2, end: 3 },
|
domain: Domain::from(2..3 ),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
map.update(Cluster {
|
map.update(Cluster {
|
||||||
domain: Domain { start: 0, end: 1 },
|
domain: Domain::from(0..1 ),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
map.map.sort();
|
map.map.sort();
|
||||||
@@ -638,11 +632,11 @@ mod tests {
|
|||||||
map.map,
|
map.map,
|
||||||
vec![
|
vec![
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 0, end: 1 },
|
domain: Domain::from(0..1 ),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 2, end: 3 },
|
domain: Domain::from(2..3 ),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -660,14 +654,14 @@ mod tests {
|
|||||||
|
|
||||||
let mut map = MapFile {
|
let mut map = MapFile {
|
||||||
map: vec![Cluster {
|
map: vec![Cluster {
|
||||||
domain: Domain { start: 0, end: 1 },
|
domain: Domain::from(0..1 ),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}],
|
}],
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
map.update(Cluster {
|
map.update(Cluster {
|
||||||
domain: Domain { start: 2, end: 3 },
|
domain: Domain::from(2..3 ),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
map.map.sort();
|
map.map.sort();
|
||||||
@@ -676,11 +670,11 @@ mod tests {
|
|||||||
map.map,
|
map.map,
|
||||||
vec![
|
vec![
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 0, end: 1 },
|
domain: Domain::from(0..1 ),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 2, end: 3 },
|
domain: Domain::from(2..3 ),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -696,7 +690,7 @@ mod tests {
|
|||||||
// If this fails here, there's something SERIOUSLY wrong.
|
// If this fails here, there's something SERIOUSLY wrong.
|
||||||
assert!(
|
assert!(
|
||||||
mf_stage == Stage::Patchwork { depth: 0 },
|
mf_stage == Stage::Patchwork { depth: 0 },
|
||||||
"Determined stage to be {:?}, when {:?} was expeccted.",
|
"Determined stage to be {:?}, when {:?} was expected.",
|
||||||
mf_stage,
|
mf_stage,
|
||||||
Stage::Patchwork { depth: 0 }
|
Stage::Patchwork { depth: 0 }
|
||||||
);
|
);
|
||||||
@@ -764,50 +758,50 @@ mod tests {
|
|||||||
fn defrag() {
|
fn defrag() {
|
||||||
let mut mf = MapFile {
|
let mut mf = MapFile {
|
||||||
sector_size: 1,
|
sector_size: 1,
|
||||||
domain: Domain { start: 0, end: 8 },
|
domain: Domain::from(0..8 ),
|
||||||
map: vec![
|
map: vec![
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 0, end: 1 },
|
domain: Domain::from(0..1 ),
|
||||||
stage: Stage::Patchwork { depth: 0 },
|
stage: Stage::Patchwork { depth: 0 },
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 1, end: 2 },
|
domain: Domain::from(1..1 ),
|
||||||
stage: Stage::Patchwork { depth: 0 },
|
stage: Stage::Patchwork { depth: 0 },
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 2, end: 3 },
|
domain: Domain::from(2..3 ),
|
||||||
stage: Stage::Patchwork { depth: 0 },
|
stage: Stage::Patchwork { depth: 0 },
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 3, end: 4 },
|
domain: Domain::from(3..4 ),
|
||||||
stage: Stage::Isolate,
|
stage: Stage::Isolate,
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 4, end: 5 },
|
domain: Domain::from(4..5 ),
|
||||||
stage: Stage::Isolate,
|
stage: Stage::Isolate,
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 5, end: 6 },
|
domain: Domain::from(5..6 ),
|
||||||
stage: Stage::Patchwork { depth: 1 },
|
stage: Stage::Patchwork { depth: 1 },
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 6, end: 7 },
|
domain: Domain::from(6..7 ),
|
||||||
stage: Stage::Patchwork { depth: 0 },
|
stage: Stage::Patchwork { depth: 0 },
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 7, end: 8 },
|
domain: Domain::from(7..8 ),
|
||||||
stage: Stage::Damaged,
|
stage: Stage::Damaged,
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 8, end: 10 },
|
domain: Domain::from(8..10 ),
|
||||||
stage: Stage::Intact,
|
stage: Stage::Intact,
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 10, end: 11 },
|
domain: Domain::from(10..10 ),
|
||||||
stage: Stage::BruteForceAndDesperation,
|
stage: Stage::BruteForceAndDesperation,
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 11, end: 12 },
|
domain: Domain::from(11..12 ),
|
||||||
stage: Stage::BruteForceAndDesperation,
|
stage: Stage::BruteForceAndDesperation,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@@ -815,31 +809,31 @@ mod tests {
|
|||||||
|
|
||||||
let expected = vec![
|
let expected = vec![
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 0, end: 3 },
|
domain: Domain::from(0..3 ),
|
||||||
stage: Stage::Patchwork { depth: 0 },
|
stage: Stage::Patchwork { depth: 0 },
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 3, end: 5 },
|
domain: Domain::from(3..5 ),
|
||||||
stage: Stage::Isolate,
|
stage: Stage::Isolate,
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 5, end: 6 },
|
domain: Domain::from(5..6 ),
|
||||||
stage: Stage::Patchwork { depth: 1 },
|
stage: Stage::Patchwork { depth: 1 },
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 6, end: 7 },
|
domain: Domain::from(6..7 ),
|
||||||
stage: Stage::Patchwork { depth: 0 },
|
stage: Stage::Patchwork { depth: 0 },
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 7, end: 8 },
|
domain: Domain::from(7..8 ),
|
||||||
stage: Stage::Damaged,
|
stage: Stage::Damaged,
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 8, end: 10 },
|
domain: Domain::from(8..10 ),
|
||||||
stage: Stage::Intact,
|
stage: Stage::Intact,
|
||||||
},
|
},
|
||||||
Cluster {
|
Cluster {
|
||||||
domain: Domain { start: 10, end: 12 },
|
domain: Domain::from(10..12 ),
|
||||||
stage: Stage::BruteForceAndDesperation,
|
stage: Stage::BruteForceAndDesperation,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
+5
-2
@@ -91,12 +91,13 @@ impl Recover {
|
|||||||
|
|
||||||
while self.map.get_stage() == (Stage::Patchwork { depth }) {
|
while self.map.get_stage() == (Stage::Patchwork { depth }) {
|
||||||
// Order of these two expressions matters, stupid.
|
// Order of these two expressions matters, stupid.
|
||||||
buf_capacity /= depth;
|
buf_capacity /= depth + 1;
|
||||||
depth += 1;
|
|
||||||
|
|
||||||
for cluster in self.map.get_clusters(Stage::Patchwork { depth }) {
|
for cluster in self.map.get_clusters(Stage::Patchwork { depth }) {
|
||||||
self.read_domain(buf.as_mut(), cluster.domain, buf_capacity, Stage::Isolate)?;
|
self.read_domain(buf.as_mut(), cluster.domain, buf_capacity, Stage::Isolate)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
depth += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -123,6 +124,8 @@ impl Recover {
|
|||||||
stage: Stage::Intact,
|
stage: Stage::Intact,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
dbg!(cluster.domain);
|
||||||
|
|
||||||
match self.read_sectors(buf.as_mut()) {
|
match self.read_sectors(buf.as_mut()) {
|
||||||
Ok(bytes) => {
|
Ok(bytes) => {
|
||||||
self.output
|
self.output
|
||||||
|
|||||||
+83
@@ -0,0 +1,83 @@
|
|||||||
|
use std::io;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
|
||||||
|
use ratatui::crossterm;
|
||||||
|
use ratatui::layout::{Constraint, Layout};
|
||||||
|
use ratatui::symbols::border;
|
||||||
|
use ratatui::widgets::{Block, Widget};
|
||||||
|
use ratatui::{DefaultTerminal, Frame};
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct Tui {
|
||||||
|
// bool::default() -> false
|
||||||
|
exit: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Tui {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(
|
||||||
|
&mut self,
|
||||||
|
terminal: &mut DefaultTerminal,
|
||||||
|
rx: mpsc::Receiver<Event>,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
while !self.exit {
|
||||||
|
// Render frame.
|
||||||
|
terminal.draw(|frame| self.draw(frame))?;
|
||||||
|
|
||||||
|
// Event handler
|
||||||
|
// unwraps, bc what could go wrong?
|
||||||
|
match rx.recv().unwrap() {
|
||||||
|
Event::Input(key_event) => self.handle_key_event(key_event)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn draw(&self, frame: &mut Frame) {
|
||||||
|
frame.render_widget(self, frame.area());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_key_event(&mut self, key_event: crossterm::event::KeyEvent) -> io::Result<()> {
|
||||||
|
if key_event.kind == crossterm::event::KeyEventKind::Press
|
||||||
|
&& key_event.code == crossterm::event::KeyCode::Char('q')
|
||||||
|
{
|
||||||
|
self.exit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// impl on reference to avoid accidentally mutating.
|
||||||
|
impl Widget for &Tui {
|
||||||
|
fn render(self, area: ratatui::prelude::Rect, buf: &mut ratatui::prelude::Buffer)
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let [main_area, _info_area] =
|
||||||
|
Layout::vertical([Constraint::Percentage(75), Constraint::Fill(1)]).areas(area);
|
||||||
|
|
||||||
|
let main_block = Block::bordered()
|
||||||
|
.title(" Viewer ")
|
||||||
|
.border_set(border::THICK);
|
||||||
|
main_block.render(main_area, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Event {
|
||||||
|
Input(crossterm::event::KeyEvent),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn input_fetcher(tx: mpsc::Sender<Event>) {
|
||||||
|
loop {
|
||||||
|
// unwraps, bc what could go wrong?
|
||||||
|
match crossterm::event::read().unwrap() {
|
||||||
|
crossterm::event::Event::Key(key_event) => tx.send(Event::Input(key_event)).unwrap(),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user