#![feature(int_roundings)] mod structs; use crate::structs::{Superblock,BlockGroupDescriptor,Inode,DirectoryEntry}; use zerocopy::{ByteSlice}; use uuid::Uuid; #[repr(C)] #[derive(Debug)] pub struct Ext2 { pub superblock: &'static Superblock, pub block_groups: &'static [BlockGroupDescriptor], pub blocks: Vec<&'static [u8]>, pub block_size: usize, pub uuid: Uuid, } const EXT2_MAGIC: u16 = 0xef53; const EXT2_SUPERBLOCK_OFFSET: usize = 2048; impl Ext2 { pub fn new(bytes: B) -> Ext2 { // https://wiki.osdev.org/Ext2#Superblock // parse into Ext2 struct without copying much let x = bytes.split_at(EXT2_SUPERBLOCK_OFFSET); // let y = x.0.split_at(1024).1; // let (prefix, superblock, suffix) = unsafe { bytes.align_to::() }; // println!("{:?}", x.len()); let superblock = unsafe { &*(x.0.split_at(1024).1.as_ptr() as *const Superblock) }; assert_eq!(superblock.magic, EXT2_MAGIC); // println!("{:?} {:?}", prefix, suffix); let block_group_count = superblock .blocks_count .div_ceil(superblock.blocks_per_group) as usize - 3; // assert!(block_igroup_count <= MAX_BLOCK_GROUPS); // let y = x.1, // let (prefix, block_groups, suffix) = unsafe { bytes.align_to::() }; // println!("{:?} {:?}", prefix, suffix); let block_size: usize = 1024 << superblock.log_block_size; let y = x.1.split_at(block_size); let block_groups = unsafe { std::slice::from_raw_parts( y.0.as_ptr() as *const BlockGroupDescriptor, block_group_count, ) }; // i determined the root table to be at inode 5, but i need a better way of finding that // let root_inode_group: usize = (5 - 1) / superblock.inodes_per_group as usize; // let root_inode_index: usize = (5 - 1) % superblock.inodes_per_group as usize; // let root_inode_block = (root_inode_index * superblock.inode_size as usize) as usize / block_size; // println!("{:?}", root_inode_group); // println!("{:?}", root_inode_index); // println!("{:?}", root_inode_block); let blocks = unsafe { std::slice::from_raw_parts( y.1.as_ptr() as *const u8, superblock.blocks_count as usize * block_size, ) } .chunks(block_size) .collect::>(); // let blocks = unsafe { std::slice::from_raw_parts( // y.1.as_ptr() as *const [u8;1024], // superblock.blocks_count as usize) }; // let inodes_per_block = block_size / superblock.inode_size as usize; // let inode_table_block_count: usize = superblock.inodes_per_group as usize / inodes_per_block; // let inode_table = unsafe { std::slice::from_raw_parts( // blocks[(block_groups[root_inode_group].inode_table_block-1) as usize].as_ptr() as *const Inode, // inode_table_block_count) }; // boot block + group descriptors block + inode table blocks // let data_blocks = unsafe { std::slice::from_raw_parts( // blocks[1 + 1 + inode_table_block_count].as_ptr() as *const Inode, // inode_table_block_count) }; // let root_inode = &inode_table[root_inode_index]; // let test_inode = &inode_table[6]; // println!("{:?}", unsafe { std::ffi::CStr::from_ptr(blocks[test_inode.direct_pointer[0] as usize-3].as_ptr() as *const i8) }); // for inode in &inode_table[0..10] { // println!("{:?}", inode); // } // for data_block in root_inode.direct_pointer { // if data_block == 0 { break } // println!("{:?}", blocks[data_block as usize-3]); // } // for ptr in root_inode.direct_pointer { // println!("{:?}", blocks[ptr as usize - 1]); // } // let block_goups = <[BlockGroupDescriptor]>::read_from_prefix(x.1).unwrap(); // println!("{:?}", y.1.split_at(block_size * (block_groups[root_inode_group].inode_table_block-1) as usize).1.split_at(block_size).0); let uuid = Uuid::from_bytes(superblock.fs_id); Ext2 { superblock, block_groups, blocks, block_size, uuid, } } // pub fn read_dir_inode(&self, inode: usize) -> std::io::Result> { // for ptr in root.direct_pointer { // println!("{:?}",ext2.blocks[ptr as usize - 4] ); // } // let directory = ext2.blocks[root.direct_pointer[0] as usize - 3].as_ptr() as *const DirectoryEntry; // Ok(vec!["/"]) // } // pub fn read_dir_inode(&self, inode: usize) { // let dir = self.get_inode(inode); // } pub fn get_inode(&self, inode: usize) -> &Inode { let group: usize = (inode - 1) / self.superblock.inodes_per_group as usize; let index: usize = (inode - 1) % self.superblock.inodes_per_group as usize; let inode_table = unsafe { std::slice::from_raw_parts( self.blocks[(self.block_groups[group].inode_table_block - 1) as usize].as_ptr() as *const Inode, index + 1, ) }; // dbg!(inode_table); &inode_table[index] } pub fn read_dir<'a>(&'a self, inode: &'a Inode) -> Directory<'_> { Directory { inode, disk: self, offset: 0 } } } #[derive(Debug)] pub struct Directory<'a> { inode: &'a Inode, disk: &'a Ext2, offset: usize, } impl<'a> Iterator for Directory<'a> { type Item = &'a DirectoryEntry; fn next(&mut self) -> Option { if self.offset > 0 && self.offset % self.disk.block_size == 0 { return None; } if self.inode.direct_pointer[self.offset / self.disk.block_size] == 0 { return None; } let dir = unsafe { &*(self.disk.blocks [self.inode.direct_pointer[self.offset / self.disk.block_size] as usize - 4] .as_ptr() .add(self.offset % self.disk.block_size) as *const DirectoryEntry) }; self.offset += dir.entry_size as usize; Some(dir) } } fn main() { let disk = include_bytes!("../ext2.img"); let ext2 = Ext2::new(&disk[..]); println!("{:?}", ext2.uuid); // root inode always starts at 2 let root = ext2.get_inode(5); dbg!(root); let dir: Vec<_> = ext2.read_dir(root).collect(); // dbg!(dir); dbg!(dir.clone()); let file = ext2.get_inode(7); dbg!(file); println!("{:?}", unsafe { std::ffi::CStr::from_ptr( ext2.blocks[file.direct_pointer[0] as usize - 3].as_ptr() as *const i8 ) }); // dbg!(dir.next()); // dbg!(dir.next()); // let file = ext2.get_inode(dir.next().unwrap().inode as usize - 8); // dbg!(file); // for ptr in root.direct_pointer { // println!("{:?}",ext2.blocks[ptr as usize - 4] ); // } // std::vec::Vec::from_raw_parts(ext2.blocks[root.direct_pointer[0] as usize - 4].as_ptr() as *const DirectoryEntry, 5, 5) // let directory = ext2.blocks[root.direct_pointer[0] as usize - 4].as_ptr() as *const DirectoryEntry; // dbg!( unsafe { &*directory } ); // println!("{:?}",ext2.blocks[root.direct_pointer[0] as usize - 3] ); // println!("{:?}", unsafe { std::ffi::CStr::from_ptr(ext2.blocks[root.direct_pointer[0] as usize - 3].as_ptr()+ as *const i8) }); }