Compare commits
2 Commits
53d773e2ea
...
read-poiso
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
952e796e28 | ||
|
|
9198193365 |
38
src/io.rs
38
src/io.rs
@@ -1,6 +1,7 @@
|
|||||||
|
use std::ffi::CString;
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::io::{self, Seek, SeekFrom};
|
use std::io::{self, Seek, SeekFrom};
|
||||||
use std::os::unix::fs::OpenOptionsExt;
|
use std::os::fd::{AsRawFd, FromRawFd, IntoRawFd};
|
||||||
|
|
||||||
use crate::cli::CONFIG;
|
use crate::cli::CONFIG;
|
||||||
|
|
||||||
@@ -20,12 +21,22 @@ pub fn get_stream_length<S: Seek>(stream: &mut S) -> io::Result<u64> {
|
|||||||
len
|
len
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IO Error Poisoning:
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Attempt 1:
|
||||||
|
*
|
||||||
|
* Wrap C calls w/ `ffi`. Most importantly, execute the `close()` through C.
|
||||||
|
*
|
||||||
|
* I cannot seem to execute `close()`... one hopes that reassigning will drop
|
||||||
|
* calling `close()` on the old fd, but I don't know.
|
||||||
|
*/
|
||||||
|
|
||||||
pub fn load_input() -> anyhow::Result<File> {
|
pub fn load_input() -> anyhow::Result<File> {
|
||||||
OpenOptions::new()
|
let path = CString::new(CONFIG.input.to_str().unwrap().to_owned())?;
|
||||||
.read(true)
|
let flags = libc::O_RDONLY | libc::O_DIRECT;
|
||||||
.custom_flags(libc::O_DIRECT)
|
Ok(unsafe { File::from_raw_fd(libc::open(path.as_ptr(), flags)) })
|
||||||
.open(&CONFIG.input)
|
|
||||||
.with_context(|| format!("Failed to open input file: {}", &CONFIG.input.display()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_output() -> anyhow::Result<File> {
|
pub fn load_output() -> anyhow::Result<File> {
|
||||||
@@ -61,18 +72,3 @@ pub fn load_map_write() -> anyhow::Result<File> {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, align(512))]
|
|
||||||
pub struct DirectIOBuffer(pub [u8; crate::MAX_BUFFER_SIZE]);
|
|
||||||
|
|
||||||
impl Default for DirectIOBuffer {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self([crate::FB_NULL_VALUE; _])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<[u8; crate::MAX_BUFFER_SIZE]> for DirectIOBuffer {
|
|
||||||
fn from(value: [u8; crate::MAX_BUFFER_SIZE]) -> Self {
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -11,8 +11,6 @@ use anyhow;
|
|||||||
const FB_SECTOR_SIZE: usize = 2048;
|
const FB_SECTOR_SIZE: usize = 2048;
|
||||||
const FB_NULL_VALUE: u8 = 0;
|
const FB_NULL_VALUE: u8 = 0;
|
||||||
|
|
||||||
const MAX_BUFFER_SIZE: usize = FB_SECTOR_SIZE * 16;
|
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
let mut recover_tool = Recover::new()?;
|
let mut recover_tool = Recover::new()?;
|
||||||
recover_tool.run()?;
|
recover_tool.run()?;
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ impl Default for Cluster {
|
|||||||
impl Cluster {
|
impl Cluster {
|
||||||
/// Breaks apart into a vec of clusters,
|
/// Breaks apart into a vec of clusters,
|
||||||
/// each of cluster_size, excepting last.
|
/// each of cluster_size, excepting last.
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn subdivide(&mut self, cluster_len: usize) -> Vec<Cluster> {
|
pub fn subdivide(&mut self, cluster_len: usize) -> Vec<Cluster> {
|
||||||
let domain_len = self.domain.len();
|
let domain_len = self.domain.len();
|
||||||
let mut start = self.domain.start;
|
let mut start = self.domain.start;
|
||||||
@@ -50,8 +49,6 @@ impl Cluster {
|
|||||||
clusters
|
clusters
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is used in unit tests at present. Ideally it probably shouldn't exist.
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn set_stage(&mut self, stage: Stage) -> &mut Self {
|
pub fn set_stage(&mut self, stage: Stage) -> &mut Self {
|
||||||
self.stage = stage;
|
self.stage = stage;
|
||||||
self
|
self
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ impl Default for Domain {
|
|||||||
|
|
||||||
impl Domain {
|
impl Domain {
|
||||||
/// Return length of domain in sectors.
|
/// Return length of domain in sectors.
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn len(self) -> usize {
|
pub fn len(self) -> usize {
|
||||||
self.end - self.start
|
self.end - self.start
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ use std::fs::File;
|
|||||||
use std::io::{BufWriter, Read, Seek, SeekFrom, Write};
|
use std::io::{BufWriter, Read, Seek, SeekFrom, Write};
|
||||||
use std::usize;
|
use std::usize;
|
||||||
|
|
||||||
use anyhow::Context;
|
use anyhow::{Context, anyhow};
|
||||||
|
|
||||||
use crate::cli::CONFIG;
|
use crate::cli::CONFIG;
|
||||||
use crate::io::DirectIOBuffer;
|
|
||||||
use crate::mapping::prelude::*;
|
use crate::mapping::prelude::*;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
#[allow(dead_code)]
|
||||||
pub struct Recover {
|
pub struct Recover {
|
||||||
input: File,
|
input: File,
|
||||||
output: BufWriter<File>,
|
output: BufWriter<File>,
|
||||||
@@ -90,12 +90,11 @@ impl Recover {
|
|||||||
|
|
||||||
/// Attempt to copy all untested blocks.
|
/// Attempt to copy all untested blocks.
|
||||||
fn copy_untested(&mut self) -> anyhow::Result<()> {
|
fn copy_untested(&mut self) -> anyhow::Result<()> {
|
||||||
let mut buf = DirectIOBuffer::default();
|
|
||||||
|
|
||||||
for untested in self.map.get_clusters(Stage::Untested) {
|
for untested in self.map.get_clusters(Stage::Untested) {
|
||||||
// Caching.
|
// Caching.
|
||||||
let mut read_position: usize;
|
let mut read_position: usize;
|
||||||
let mut cluster: Cluster;
|
let mut cluster: Cluster;
|
||||||
|
let mut buf: Vec<u8>;
|
||||||
let mut buf_capacity = self.get_buf_capacity() as usize;
|
let mut buf_capacity = self.get_buf_capacity() as usize;
|
||||||
|
|
||||||
dbg!(untested.domain);
|
dbg!(untested.domain);
|
||||||
@@ -105,6 +104,7 @@ impl Recover {
|
|||||||
dbg!(read_position);
|
dbg!(read_position);
|
||||||
|
|
||||||
buf_capacity = buf_capacity.min(untested.domain.end - read_position);
|
buf_capacity = buf_capacity.min(untested.domain.end - read_position);
|
||||||
|
buf = vec![crate::FB_NULL_VALUE; buf_capacity];
|
||||||
|
|
||||||
cluster = Cluster {
|
cluster = Cluster {
|
||||||
domain: Domain {
|
domain: Domain {
|
||||||
@@ -114,7 +114,7 @@ impl Recover {
|
|||||||
stage: Stage::Intact,
|
stage: Stage::Intact,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(err) = self.input.read_exact(&mut buf.0) {
|
if let Err(err) = self.input.read_exact(&mut buf) {
|
||||||
// If buf were zeroed out before every read, one could theoretically recover
|
// If buf were zeroed out before every read, one could theoretically recover
|
||||||
// part of that read given the assumption that all null values from the end to
|
// part of that read given the assumption that all null values from the end to
|
||||||
// the first non-null value are unread, and some further padding from the last
|
// the first non-null value are unread, and some further padding from the last
|
||||||
@@ -141,7 +141,7 @@ impl Recover {
|
|||||||
|
|
||||||
if cluster.stage == Stage::Intact {
|
if cluster.stage == Stage::Intact {
|
||||||
self.output
|
self.output
|
||||||
.write_all(&buf.0[0..buf_capacity])
|
.write_all(&buf[0..buf_capacity])
|
||||||
.context("Failed to write data to output file")?;
|
.context("Failed to write data to output file")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,8 +151,6 @@ impl Recover {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
drop(buf);
|
|
||||||
|
|
||||||
self.map.write_to(&mut crate::io::load_map_write()?)?;
|
self.map.write_to(&mut crate::io::load_map_write()?)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -161,7 +159,7 @@ impl Recover {
|
|||||||
/// Set buffer capacity as cluster length in bytes.
|
/// Set buffer capacity as cluster length in bytes.
|
||||||
/// Varies depending on the recovery stage.
|
/// Varies depending on the recovery stage.
|
||||||
fn get_buf_capacity(&mut self) -> u64 {
|
fn get_buf_capacity(&mut self) -> u64 {
|
||||||
crate::MAX_BUFFER_SIZE.min(CONFIG.sector_size * CONFIG.cluster_length) as u64
|
CONFIG.sector_size as u64 * CONFIG.cluster_length as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reloads the input and restores the seek position.
|
/// Reloads the input and restores the seek position.
|
||||||
|
|||||||
Reference in New Issue
Block a user