mod block_device; mod disk; mod filesystem; mod memory; mod tests; mod utils; use clap::Parser; use fuser::MountOption; use log::debug; use std::sync::Arc; use std::time::Duration; use crate::disk::block::InodeBlock; use crate::disk::inode::InodeMode; use crate::memory::cached_block::BlockCache; use block_device::{memory_disk::MemoryDisk, BlockDevice, BLOCK_SIZE}; use disk::bitmap::Bitmap; use disk::block::DataBlock; use disk::inode::INODE_SIZE; use users::{get_current_gid, get_current_uid}; #[derive(Parser, Debug)] #[command(author, version, about)] struct Args { mount_point: Option, #[arg(long)] auto_unmount: bool, #[arg(long)] allow_root: bool, } const TTL: Duration = Duration::new(0, 0); const INODE_PER_BLOCK: usize = BLOCK_SIZE / INODE_SIZE; /// The design of MyFS is rather simple: /// +-------------------+ /// | Super Block | /// +-------------------+ /// | Inode Bitmap | /// +-------------------+ /// | ... | /// +-------------------+ /// | Data Block Bitmap | /// +-------------------+ /// | ... | /// +-------------------+ /// | Inode Block | /// +-------------------+ /// | ... | /// +-------------------+ /// | Data Block | /// +-------------------+ /// With each block 4KiB, each Inode entry 128B #[repr(C)] struct AyaFS { device: Arc, data_bitmap: Bitmap, inode_bitmap: Bitmap, inode_start_block: usize, data_start_block: usize, cached_inodes: BlockCache, cached_blocks: BlockCache, } impl AyaFS { fn new(device: Arc, total_block_number: usize) -> Self { let max_inode_number: usize = 16384; // TODO: remove hard-coded magic number let inode_block_number = max_inode_number / INODE_PER_BLOCK; // == 128 let inode_bitmap_block_number = (inode_block_number + BLOCK_SIZE - 1) / BLOCK_SIZE; let blocks_remaining = total_block_number - inode_block_number - inode_bitmap_block_number - 1; // let number of data blocks be x, the remaining block number be C, // the corresponding data bitmap length should be ceil(x / BLK_SIZE), // thus we have BLK_SIZE * (C-1) / (BLK_SIZE+1) <= x <= BLK_SIZE * C / (BLK_SIZE+1) // the difference of the two bounds is less than 1, // meaning only 1 integer could be in between. // Thus we have x = floor(BLK_SIZE * C / (BLK_SIZE + 1)) let data_block_number = BLOCK_SIZE * blocks_remaining / (BLOCK_SIZE + 1); let data_bitmap_block_number = blocks_remaining - data_block_number; debug!("data_bitmap_block_number: {}", data_bitmap_block_number); debug!("inode_bitmap_block_number: {}", inode_bitmap_block_number); debug!("inode_block_number: {}", inode_block_number); debug!("data_block_number: {}", data_block_number); debug!( "sum: {}", 1 + data_bitmap_block_number + inode_bitmap_block_number + inode_block_number + data_block_number ); let mut data_bitmap = Bitmap::new(1, data_bitmap_block_number, device.clone()); let _ = data_bitmap.allocate().unwrap(); // data block 0 is not usable let mut inode_bitmap = Bitmap::new( data_bitmap_block_number + 1, inode_bitmap_block_number, device.clone(), ); let _ = inode_bitmap.allocate().unwrap(); // inode block 0 is not usable let mut fs = Self { device: device.clone(), data_bitmap, inode_bitmap, inode_start_block: data_bitmap_block_number + inode_bitmap_block_number + 1, data_start_block: data_bitmap_block_number + inode_bitmap_block_number + inode_block_number + 1, cached_inodes: BlockCache::new(device.clone(), 1024), cached_blocks: BlockCache::new(device.clone(), 8192), }; fs.create_directory(0o755, get_current_uid(), get_current_gid(), 0); fs } } fn main() { env_logger::init(); let args = Args::parse(); let mount_point = args.mount_point.unwrap(); let options = vec![ // MountOption::RO, MountOption::FSName("hello".to_string()), MountOption::AutoUnmount, MountOption::AllowRoot, ]; let mem_disk = Arc::new(MemoryDisk::new(16384)); let filesystem = AyaFS::new(mem_disk, 16384); fuser::mount2(filesystem, mount_point, &options).unwrap(); }