2025-07-18 13:59:34 +02:00
|
|
|
use std::io::SeekFrom;
|
2025-07-15 16:45:08 +02:00
|
|
|
|
2025-07-18 13:59:34 +02:00
|
|
|
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<const N: usize>(&mut self, offset: u64) -> anyhow::Result<[u8; N]> {
|
|
|
|
|
let mut buf = [0; N];
|
|
|
|
|
|
|
|
|
|
self.read_at_offset(offset, &mut buf)?;
|
|
|
|
|
|
|
|
|
|
Ok(buf)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<F: std::io::Read + std::io::Write + std::io::Seek> 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<F: FileLike> {
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
file: F,
|
|
|
|
|
|
|
|
|
|
superblock: superblock::Superblock,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl<F: FileLike> Ext4Fs<F> {
|
|
|
|
|
pub fn load(file: F) -> Result<Ext4Fs<F>, anyhow::Error> {
|
|
|
|
|
let mut file = file;
|
|
|
|
|
|
|
|
|
|
let superblock_bytes = file.read_at_offset_const::<SUPERBLOCK_SIZE>(1024)?;
|
|
|
|
|
|
|
|
|
|
let superblock = Superblock::from_bytes(&superblock_bytes)?;
|
|
|
|
|
|
|
|
|
|
Ok(Ext4Fs { file, superblock })
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn super_block(&self) -> &Superblock {
|
|
|
|
|
&self.superblock
|
|
|
|
|
}
|
|
|
|
|
}
|