Skip to content
Snippets Groups Projects
mod.rs 2.34 KiB
Newer Older
//! 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 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)]
#[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)))