//! Implementation of the Second Extended Filesystem (ext2fs) filesystem use alloc::borrow::ToOwned; use alloc::slice; use alloc::sync::Arc; use alloc::vec::Vec; use core::{mem, ptr}; use anyhow::Result; use conquer_once::spin::OnceCell; use spin::Mutex; use self::block::Superblock; use self::inode::{Inode, TypePermissions, ROOT_INODE_INDEX}; use crate::fs::ext2::entry::Directory; use crate::kernel::device::storage::Device; use crate::println; #[allow(clippy::same_name_method)] mod block; mod entry; #[allow(clippy::same_name_method)] mod inode; /// Device on which the Ext2 filesystem is located static DEVICE: OnceCell<Arc<Mutex<dyn Device + Send>>> = OnceCell::uninit(); /// Superblock of the device static SUPERBLOCK: OnceCell<Superblock> = OnceCell::uninit(); /// Reads the device at the given offset **in bytes** and returns the expected structure /// /// # Safety /// /// Must ensure that the structure `T` is present on the device at the given offset unsafe fn read<T>(offset: usize) -> Result<T> { Ok(ptr::read(read_raw(offset, mem::size_of::<T>())?.as_ptr() as *const T)) } /// Reads the device at the given offset **in bytes** and returns the `n` raw bytes /// /// # Safety /// /// Must ensure that the structure `T` is present on the device at the given offset unsafe fn read_raw(offset: usize, n: usize) -> Result<&'static [u8]> { let mut binding = DEVICE.get().expect("The device has not been initialized yet").lock(); let block_size = binding.block_size(); let mut buffer_size = 0_usize; while buffer_size < n { buffer_size += block_size; } let (raw_buffer, _, _) = Vec::<u8>::with_capacity(buffer_size).into_raw_parts(); let buffer = slice::from_raw_parts_mut(raw_buffer, buffer_size); binding.read(buffer, offset / block_size, buffer_size / block_size)?; Ok(buffer[offset % block_size..offset % block_size + n].as_ref()) } /// Searches for an Ext2 filesystem, and returns the root if found pub fn search(device: &Arc<Mutex<dyn Device + Send>>) -> Result<Arc<Mutex<dyn super::node::Directory + Send>>> { DEVICE.init_once(|| Arc::clone(device)); let superblock = Superblock::new()?; SUPERBLOCK.init_once(|| superblock); let root_inode = Inode::new(ROOT_INODE_INDEX)?; println!("{:x?} {:?}", root_inode, TypePermissions::from_bits(root_inode.type_and_permissions)); let root = Directory::root(&root_inode)?; println!("{:?}", root); todo!() }