vapfs_ufs/src/lib.rs

206 lines
9 KiB
Rust
Raw Normal View History

#![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<Superblock> {
let mut buf: [u8; core::mem::size_of::<Superblock>()] = [0; core::mem::size_of::<Superblock>()];
bd.seek(1024);
let read_count = bd.read_blocks(&mut buf);
if read_count < core::mem::size_of::<Superblock>() {
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::<Superblock>()] = [0; core::mem::size_of::<Superblock>()];
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::<Superblock>()
}
/// Reads the inode at the given index and returns it.
pub fn read_inode(index: Index, sb: &Superblock, bd: &mut dyn BlockDevice) -> Option<Inode> {
let mut buf: [u8; core::mem::size_of::<Inode>()] = [0; core::mem::size_of::<Inode>()];
bd.seek((sb.first_inode_block * sb.block_size as u64) + (index * core::mem::size_of::<Inode>() as u64));
let read_count = bd.read_blocks(&mut buf);
if read_count < core::mem::size_of::<Inode>() {
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::<Inode>()] = [0; core::mem::size_of::<Inode>()];
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::<Inode>() as u64));
let write_count = bd.write_blocks(&buf);
write_count == core::mem::size_of::<Inode>()
}
/// 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<u8> {
let mut buf: Vec<u8> = 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<bool> {
// 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<u8> = 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<bool> {
// 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<u8> = 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<Index> {
// 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<u8> = 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<Index> {
// 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<u8> = 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<u8> = 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<u8> = 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
}