Compare commits
4 Commits
2da0ab11e5
...
read-poiso
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
952e796e28 | ||
|
|
9198193365 | ||
|
|
2df9e8e0f2 | ||
|
|
7537107144 |
5
Cargo.lock
generated
5
Cargo.lock
generated
@@ -125,15 +125,16 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"clap",
|
"clap",
|
||||||
|
"libc",
|
||||||
"ron",
|
"ron",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.177"
|
version = "0.2.178"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "kramer"
|
name = "kramer"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
libc = "0.2.178"
|
||||||
# NOTE:
|
# NOTE:
|
||||||
# = X.X.X is the version used in testing.
|
# = X.X.X is the version used in testing.
|
||||||
# Use this version for greatest compatibility.
|
# Use this version for greatest compatibility.
|
||||||
|
|||||||
29
src/io.rs
29
src/io.rs
@@ -1,5 +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::fd::{AsRawFd, FromRawFd, IntoRawFd};
|
||||||
|
|
||||||
use crate::cli::CONFIG;
|
use crate::cli::CONFIG;
|
||||||
|
|
||||||
@@ -19,11 +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;
|
||||||
.open(&CONFIG.input)
|
Ok(unsafe { File::from_raw_fd(libc::open(path.as_ptr(), flags)) })
|
||||||
.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> {
|
||||||
@@ -40,16 +53,10 @@ pub fn load_output() -> anyhow::Result<File> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_map_read() -> anyhow::Result<File> {
|
pub fn load_map_read() -> std::io::Result<File> {
|
||||||
OpenOptions::new()
|
OpenOptions::new()
|
||||||
.read(true)
|
.read(true)
|
||||||
.open(crate::path::MAP_PATH.clone())
|
.open(crate::path::MAP_PATH.clone())
|
||||||
.with_context(|| {
|
|
||||||
format!(
|
|
||||||
"Failed to open/create mapping file at: {}",
|
|
||||||
crate::path::MAP_PATH.display()
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_map_write() -> anyhow::Result<File> {
|
pub fn load_map_write() -> anyhow::Result<File> {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ 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::mapping::prelude::*;
|
use crate::mapping::prelude::*;
|
||||||
@@ -18,13 +18,16 @@ pub struct Recover {
|
|||||||
impl Recover {
|
impl Recover {
|
||||||
pub fn new() -> anyhow::Result<Self> {
|
pub fn new() -> anyhow::Result<Self> {
|
||||||
let input: File = crate::io::load_input()?;
|
let input: File = crate::io::load_input()?;
|
||||||
|
|
||||||
let output: File = crate::io::load_output()?;
|
let output: File = crate::io::load_output()?;
|
||||||
|
|
||||||
let map: MapFile = {
|
let map: MapFile = {
|
||||||
crate::io::load_map_read()?
|
if let Ok(f) = crate::io::load_map_read()
|
||||||
.try_into()
|
&& let Ok(map_file) = MapFile::try_from(f)
|
||||||
.unwrap_or(MapFile::new(CONFIG.sector_size))
|
{
|
||||||
|
map_file
|
||||||
|
} else {
|
||||||
|
MapFile::new(CONFIG.sector_size)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut r = Recover {
|
let mut r = Recover {
|
||||||
@@ -91,14 +94,18 @@ impl Recover {
|
|||||||
// 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;
|
||||||
let mut buf = vec![crate::FB_NULL_VALUE; buf_capacity];
|
|
||||||
|
|
||||||
|
dbg!(untested.domain);
|
||||||
read_position = untested.domain.start;
|
read_position = untested.domain.start;
|
||||||
|
|
||||||
while read_position < untested.domain.end {
|
while read_position < untested.domain.end {
|
||||||
dbg!(read_position);
|
dbg!(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 {
|
||||||
start: read_position,
|
start: read_position,
|
||||||
@@ -107,8 +114,6 @@ impl Recover {
|
|||||||
stage: Stage::Intact,
|
stage: Stage::Intact,
|
||||||
};
|
};
|
||||||
|
|
||||||
buf_capacity = buf_capacity.min(untested.domain.end - read_position);
|
|
||||||
|
|
||||||
if let Err(err) = self.input.read_exact(&mut buf) {
|
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
|
||||||
@@ -120,12 +125,15 @@ impl Recover {
|
|||||||
println!("Hit error: {:?}", err);
|
println!("Hit error: {:?}", err);
|
||||||
if CONFIG.reopen_on_error {
|
if CONFIG.reopen_on_error {
|
||||||
self.reload_input()
|
self.reload_input()
|
||||||
.context("Failed to reload input file after previous error.")?;
|
.context("Failed to reload input file after previous error")?;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.input
|
self.input
|
||||||
.seek_relative((read_position + buf_capacity) as i64)
|
.seek_relative(buf_capacity as i64)
|
||||||
.context("Failed to seek input by buf_capacity to skip previous error")?;
|
.context("Failed to seek input by buf_capacity to skip previous error")?;
|
||||||
|
self.output
|
||||||
|
.seek_relative(buf_capacity as i64)
|
||||||
|
.context("Failed to seek output by buf_capacity to skip previous error")?;
|
||||||
|
|
||||||
// I don't remember what level was for.
|
// I don't remember what level was for.
|
||||||
cluster.stage = Stage::ForIsolation { level: 1 };
|
cluster.stage = Stage::ForIsolation { level: 1 };
|
||||||
@@ -138,6 +146,7 @@ impl Recover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.map.update(cluster);
|
self.map.update(cluster);
|
||||||
|
self.map.write_to(&mut crate::io::load_map_write()?)?;
|
||||||
read_position += buf_capacity;
|
read_position += buf_capacity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user