use std::fs::{File, OpenOptions}; use std::io::{BufWriter, Read, Seek, SeekFrom, Write}; use std::ptr::read; use crate::mapping::{Cluster, Domain, MapFile, Stage}; use crate::Args; #[derive(Debug)] #[allow(dead_code)] pub struct Recover { /// Buffer capacity in bytes. buf_capacity: u64, config: Args, input: File, output: BufWriter, map: MapFile, stage: Stage, } impl Recover { pub fn new(config: Args, input: File, output: File, map: MapFile, buf_capacity: u64) -> Self { let stage = map.get_stage(); let mut r = Recover { buf_capacity, config, input: input, output: BufWriter::with_capacity(buf_capacity as usize, output), map, stage: stage, }; // Ensure that buffer capacity is adjusted based on progress. r.set_buf_capacity(); r } /// Recover media. pub fn run(&mut self) -> () { self.copy_untested(); /* let mut is_finished = false; while !is_finished { match self.map.get_stage() { Stage::Untested => { self.copy_untested(); } Stage::ForIsolation(level) => { self.copy_isolate(level); } Stage::Damaged => { println!("Cannot recover further."); is_finished = true } } } */ // return recovered_bytes } /// Attempt to copy all untested blocks. fn copy_untested(&mut self) -> &mut Self { let mut buf = vec![crate::FB_PAD_VALUE; self.buf_capacity as usize]; // Purely caching. let mut read_position = 0_u64; let last_read_position = crate::io::get_stream_length(&mut self.input) .expect("Failed to get length of input stream") - self.buf_capacity; while read_position < last_read_position { dbg!(read_position); if let Err(err) = self.input.read_exact(&mut buf) { println!("Hit error: {:?}", err); self.input .seek_relative(self.buf_capacity as i64) .expect("Failed to seek input by buf_capacity to skip previous error"); } else { self.output .write_all(buf.as_slice()) .expect("Failed to write data to output file"); self.map.update(Cluster { domain: Domain { start: read_position as usize, end: (read_position + self.buf_capacity) as usize, }, stage: Stage::Intact, }); } read_position += self.buf_capacity; } crate::mapping::map::write_map_to_file( OpenOptions::new() .create(true) .write(true) .open(crate::get_path( &self.config.map, self.config.input.to_str().unwrap(), "map", )) .expect("Failed to open map file"), &self.map, ) .expect("Failed to write map file"); /* let mut untested: Vec = vec![]; for cluster in self.map.get_clusters(Stage::Untested).iter_mut() { untested.append(&mut cluster.subdivide(self.map.sector_size as usize)); } todo!("Read and save data."); */ self } /// Attempt to copy blocks via isolation at pass level. fn copy_isolate(&mut self, level: u8) -> &mut Self { todo!(); self } /// Set buffer capacities as cluster length in bytes. /// Varies depending on the recovery stage. fn set_buf_capacity(&mut self) -> &mut Self { self.buf_capacity = self.config.sector_size as u64 * self.config.cluster_length as u64; self } } #[cfg(test)] #[allow(unused)] mod tests { use super::*; // Test for Recover::set_buf_capacity }