//! Implementation of the Second Extended Filesystem (ext2fs) filesystem use alloc::slice; use alloc::sync::Arc; use alloc::vec::Vec; use core::{mem, ptr}; use anyhow::{Ok, Result}; use conquer_once::spin::OnceCell; use log::info; use spin::Mutex; use self::block::Superblock; use self::inode::{Inode, ROOT_INODE_INDEX}; use crate::fs::ext2::entry::Directory; use crate::kernel::device::storage::Device; #[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().cast::<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 #[allow(clippy::indexing_slicing)] unsafe fn read_raw(offset: usize, n: usize) -> Result<&'static [u8]> { let 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)?; let root = Directory::root(&root_inode)?; info!("Found the root of the filesystem : {:?}", root); Ok(Arc::new(Mutex::new(root))) }