#![no_std] extern crate alloc; use alloc::vec::Vec; use vapfs::{BlockDevice, Index}; use crate::structs::{Inode, Superblock}; pub mod btree; pub mod structs; pub mod bitmap; pub mod crc32; /// Reads the superblock (located at byte offset 1024 of the block device) and returns it. /// Returns None if the block device is too small to contain a superblock. pub fn get_superblock(bd: &mut dyn BlockDevice) -> Option { let mut buf: [u8; core::mem::size_of::()] = [0; core::mem::size_of::()]; bd.seek(1024); let read_count = bd.read_blocks(&mut buf); if read_count < core::mem::size_of::() { return None; } let mut superblock = unsafe { core::ptr::read(buf.as_ptr() as *const Superblock) }; superblock.convert_big_endian_to_native(); Some(superblock) } /// Performs a direct write of a superblock to the block device. /// # Safety /// unsafe because it does not journal the write, and does not update any other metadata. pub unsafe fn write_superblock(mut sb: Superblock, bd: &mut dyn BlockDevice) -> bool { sb.convert_native_to_big_endian(); let mut buf: [u8; core::mem::size_of::()] = [0; core::mem::size_of::()]; core::ptr::write(buf.as_mut_ptr() as *mut Superblock, sb); bd.seek(1024); let write_count = bd.write_blocks(&buf); write_count == core::mem::size_of::() } /// Reads the inode at the given index and returns it. pub fn read_inode(index: Index, sb: &Superblock, bd: &mut dyn BlockDevice) -> Option { let mut buf: [u8; core::mem::size_of::()] = [0; core::mem::size_of::()]; bd.seek((sb.first_inode_block * sb.block_size as u64) + (index * core::mem::size_of::() as u64)); let read_count = bd.read_blocks(&mut buf); if read_count < core::mem::size_of::() { return None; } let mut inode = unsafe { core::ptr::read(buf.as_ptr() as *const Inode) }; inode.convert_big_endian_to_native(); Some(inode) } /// Performs a direct write of an inode to the block device. /// # Safety /// unsafe because it does not journal the write, and does not update any other metadata. pub unsafe fn write_inode(index: Index, sb: &Superblock, bd: &mut dyn BlockDevice, mut inode: Inode) -> bool { inode.convert_native_to_big_endian(); let mut buf: [u8; core::mem::size_of::()] = [0; core::mem::size_of::()]; core::ptr::write(buf.as_mut_ptr() as *mut Inode, inode); bd.seek((sb.first_inode_block * sb.block_size as u64) + (index * core::mem::size_of::() as u64)); let write_count = bd.write_blocks(&buf); write_count == core::mem::size_of::() } /// Reads a single datablock into memory, may return less than the block size if the end of the block device is reached. pub fn read_datablock(index: Index, sb: &Superblock, bd: &mut dyn BlockDevice) -> Vec { let mut buf: Vec = Vec::new(); buf.resize(sb.block_size as usize, 0); bd.seek((sb.first_data_block * sb.block_size as u64) + (index * sb.block_size as u64)); bd.read_blocks(&mut buf); buf } /// Performs a direct write of a datablock to the block device. /// # Safety /// unsafe because it does not journal the write, and does not update any other metadata. pub unsafe fn write_datablock(index: Index, sb: &Superblock, bd: &mut dyn BlockDevice, buf: &[u8]) -> bool { bd.seek((sb.first_data_block * sb.block_size as u64) + (index * sb.block_size as u64)); let write_count = bd.write_blocks(buf); write_count == sb.block_size as usize } /// Checks if a datablock is allocated. /// Will return None if the index is out of bounds or if the block device cannot fill the buffer. pub fn is_datablock_allocated(index: Index, sb: &Superblock, bd: &mut dyn BlockDevice) -> Option { // datablock bitmap is at 1024 + 156 byte offset, length is data_block_count / 8 rounded up let bitmap_offset = 1024 + 156; let bitmap_length = (sb.data_block_count + 7) / 8; if index >= bitmap_length { return None; } let mut bitmap_buf: Vec = Vec::new(); bitmap_buf.resize(bitmap_length as usize, 0); bd.seek(bitmap_offset); let read_count = bd.read_blocks(&mut bitmap_buf); if read_count < bitmap_length as usize { return None; } Some(bitmap::get_bit(&bitmap_buf, index as usize) == bitmap::SET) } /// Checks if an inode is allocated. /// Will return None if the index is out of bounds or if the block device cannot fill the buffer. pub fn is_inode_allocated(index: Index, sb: &Superblock, bd: &mut dyn BlockDevice) -> Option { // inode bitmap is at 1024 + 156 + datablock_bitmap_length byte offset, // length is inode_count / 8 rounded up let bitmap_offset = 1024 + 156 + ((sb.data_block_count + 7) / 8); let bitmap_length = (sb.inode_count + 7) / 8; if index >= bitmap_length { return None; } let mut bitmap_buf: Vec = Vec::new(); bitmap_buf.resize(bitmap_length as usize, 0); bd.seek(bitmap_offset); let read_count = bd.read_blocks(&mut bitmap_buf); if read_count < bitmap_length as usize { return None; } Some(bitmap::get_bit(&bitmap_buf, index as usize) == bitmap::SET) } /// Finds the first unallocated datablock and returns its index. /// Will return None if no unallocated datablock is found, or if the block device cannot fill the buffer. pub fn find_first_unallocated_datablock(sb: &Superblock, bd: &mut dyn BlockDevice) -> Option { // datablock bitmap is at 1024 + 156 byte offset, length is data_block_count / 8 rounded up let bitmap_offset = 1024 + 156; let bitmap_length = (sb.data_block_count + 7) / 8; let mut bitmap_buf: Vec = Vec::new(); bitmap_buf.resize(bitmap_length as usize, 0); bd.seek(bitmap_offset); let read_count = bd.read_blocks(&mut bitmap_buf); if read_count < bitmap_length as usize { return None; } bitmap::find_first_bit_equal_to(&bitmap_buf, bitmap::UNSET).map(|index| index as Index) } /// Finds the first unallocated inode and returns its index. /// Will return None if no unallocated inode is found, or if the block device cannot fill the buffer. pub fn find_first_unallocated_inode(sb: &Superblock, bd: &mut dyn BlockDevice) -> Option { // inode bitmap is at 1024 + 156 + datablock_bitmap_length byte offset, // length is inode_count / 8 rounded up let bitmap_offset = 1024 + 156 + ((sb.data_block_count + 7) / 8); let bitmap_length = (sb.inode_count + 7) / 8; let mut bitmap_buf: Vec = Vec::new(); bitmap_buf.resize(bitmap_length as usize, 0); bd.seek(bitmap_offset); let read_count = bd.read_blocks(&mut bitmap_buf); if read_count < bitmap_length as usize { return None; } bitmap::find_first_bit_equal_to(&bitmap_buf, bitmap::UNSET).map(|index| index as Index) } /// Sets the allocation status of a datablock. /// # Safety /// unsafe because it does not journal the write, and does not update any other metadata. pub unsafe fn set_datablock_allocation_status(index: Index, sb: &Superblock, bd: &mut dyn BlockDevice, allocated: bool) -> bool { // todo! we should maybe optimise this to only write the byte that contains the bit, instead of the whole bitmap // todo! see how much time this saves? // datablock bitmap is at 1024 + 156 byte offset, length is data_block_count / 8 rounded up let bitmap_offset = 1024 + 156; let bitmap_length = (sb.data_block_count + 7) / 8; if index >= bitmap_length { return false; } let mut bitmap_buf: Vec = Vec::new(); bitmap_buf.resize(bitmap_length as usize, 0); bd.seek(bitmap_offset); let read_count = bd.read_blocks(&mut bitmap_buf); if read_count < bitmap_length as usize { return false; } bitmap::set_bit(&mut bitmap_buf, index as usize, allocated); bd.seek(bitmap_offset); let write_count = bd.write_blocks(&bitmap_buf); write_count == bitmap_length as usize } /// Sets the allocation status of an inode. /// # Safety /// unsafe because it does not journal the write, and does not update any other metadata. pub unsafe fn set_inode_allocation_status(index: Index, sb: &Superblock, bd: &mut dyn BlockDevice, allocated: bool) -> bool { // todo! we should maybe optimise this to only write the byte that contains the bit, instead of the whole bitmap // todo! see how much time this saves? // inode bitmap is at 1024 + 156 + datablock_bitmap_length byte offset, // length is inode_count / 8 rounded up let bitmap_offset = 1024 + 156 + ((sb.data_block_count + 7) / 8); let bitmap_length = (sb.inode_count + 7) / 8; if index >= bitmap_length { return false; } let mut bitmap_buf: Vec = Vec::new(); bitmap_buf.resize(bitmap_length as usize, 0); bd.seek(bitmap_offset); let read_count = bd.read_blocks(&mut bitmap_buf); if read_count < bitmap_length as usize { return false; } bitmap::set_bit(&mut bitmap_buf, index as usize, allocated); bd.seek(bitmap_offset); let write_count = bd.write_blocks(&bitmap_buf); write_count == bitmap_length as usize }