ax-fs-ng 0.7.0

ArceOS filesystem module
mod fs;
mod inode;
mod util;

use alloc::boxed::Box;

pub use fs::*;
pub use inode::*;
use rsext4::{
    BlockDevice,
    bmalloc::AbsoluteBN,
    config::BLOCK_SIZE,
    disknode::Ext4Timestamp,
    error::{Ext4Error, Ext4Result},
};

use crate::block::{BlockRegion, FsBlockDevice, RegionBlockDevice};

pub(crate) struct Ext4Disk(RegionBlockDevice<Box<dyn FsBlockDevice>>);

impl Ext4Disk {
    pub fn new(dev: Box<dyn FsBlockDevice>, region: BlockRegion) -> Self {
        Self(RegionBlockDevice::new(dev, region))
    }
}

impl BlockDevice for Ext4Disk {
    fn write(&mut self, buffer: &[u8], block_id: AbsoluteBN, count: u32) -> Ext4Result<()> {
        let dev_block = self.0.block_size();
        if !BLOCK_SIZE.is_multiple_of(dev_block) {
            return Err(Ext4Error::invalid_input());
        }
        let factor = (BLOCK_SIZE / dev_block) as u64;
        let required_size = BLOCK_SIZE * count as usize;
        if buffer.len() < required_size {
            return Err(Ext4Error::buffer_too_small(buffer.len(), required_size));
        }
        let start_block = block_id.raw() * factor;
        self.0
            .write_block(start_block, &buffer[..required_size])
            .map_err(|_| Ext4Error::io())
    }

    fn read(&mut self, buffer: &mut [u8], block_id: AbsoluteBN, count: u32) -> Ext4Result<()> {
        let dev_block = self.0.block_size();
        if !BLOCK_SIZE.is_multiple_of(dev_block) {
            return Err(Ext4Error::invalid_input());
        }
        let factor = (BLOCK_SIZE / dev_block) as u64;
        let required_size = BLOCK_SIZE * count as usize;
        if buffer.len() < required_size {
            return Err(Ext4Error::buffer_too_small(buffer.len(), required_size));
        }
        let start_block = block_id.raw() * factor;
        self.0
            .read_block(start_block, &mut buffer[..required_size])
            .map_err(|_| Ext4Error::io())
    }

    fn open(&mut self) -> Ext4Result<()> {
        Ok(())
    }

    fn close(&mut self) -> Ext4Result<()> {
        self.flush()
    }

    fn total_blocks(&self) -> u64 {
        let dev_block = self.0.block_size() as u64;
        let total_bytes = self.0.num_blocks().saturating_mul(dev_block);
        total_bytes / BLOCK_SIZE as u64
    }

    fn block_size(&self) -> u32 {
        BLOCK_SIZE as u32
    }

    fn flush(&mut self) -> Ext4Result<()> {
        self.0.flush().map_err(|_| Ext4Error::io())
    }

    fn current_time(&self) -> Ext4Result<Ext4Timestamp> {
        if cfg!(feature = "times") {
            let dur = crate::os::wall_time();
            Ok(Ext4Timestamp::new(dur.as_secs() as i64, dur.subsec_nanos()))
        } else {
            Ok(Ext4Timestamp::new(0, 0))
        }
    }
}