use std::io::SeekFrom; pub use crate::superblock::{SUPERBLOCK_SIZE, Superblock}; pub use crate::utils::group_has_superblock; mod group_descriptor; mod mmp; mod superblock; mod utils; pub trait FileLike { fn read_at_offset(&mut self, offset: u64, buf: &mut [u8]) -> anyhow::Result<()>; fn write_at_offset(&mut self, offset: u64, bytes: &[u8]) -> anyhow::Result<()>; fn read_at_offset_const(&mut self, offset: u64) -> anyhow::Result<[u8; N]> { let mut buf = [0; N]; self.read_at_offset(offset, &mut buf)?; Ok(buf) } } impl FileLike for F { fn read_at_offset(&mut self, offset: u64, buf: &mut [u8]) -> anyhow::Result<()> { self.seek(SeekFrom::Start(offset))?; self.read_exact(buf)?; Ok(()) } fn write_at_offset(&mut self, offset: u64, bytes: &[u8]) -> anyhow::Result<()> { self.seek(SeekFrom::Start(offset))?; self.write_all(bytes)?; Ok(()) } } // impl FileLike for &mut [u8] { // fn read_at_offset(&mut self, offset: u64, buf: &mut [u8]) -> anyhow::Result<()> { // anyhow::ensure!( // offset as usize + buf.len() <= self.len(), // "reading {} bytes at offset {} is out of bounds for slice of len {}", // buf.len(), // offset, // self.len() // ); // // buf.copy_from_slice(&self[offset as usize..][..buf.len()]); // // Ok(()) // } // // fn write_at_offset(&mut self, offset: u64, bytes: &[u8]) -> anyhow::Result<()> { // anyhow::ensure!( // offset as usize + bytes.len() <= self.len(), // "writing {} bytes at offset {} is out of bounds for slice of len {}", // bytes.len(), // offset, // self.len() // ); // // self[offset as usize..][..bytes.len()].copy_from_slice(bytes); // // Ok(()) // } // } pub struct Ext4Fs { #[allow(dead_code)] file: F, superblock: superblock::Superblock, } impl Ext4Fs { pub fn load(file: F) -> Result, anyhow::Error> { let mut file = file; let superblock_bytes = file.read_at_offset_const::(1024)?; let superblock = Superblock::from_bytes(&superblock_bytes)?; Ok(Ext4Fs { file, superblock }) } pub fn super_block(&self) -> &Superblock { &self.superblock } }