2023-07-25 07:03:06 -07:00
|
|
|
#![no_std]
|
|
|
|
|
|
|
|
extern crate alloc;
|
|
|
|
|
2023-07-27 09:28:06 -07:00
|
|
|
use alloc::vec::Vec;
|
|
|
|
use vapfs::{BlockDevice, Index};
|
|
|
|
use crate::structs::{Inode, Superblock};
|
2023-07-25 07:03:06 -07:00
|
|
|
|
|
|
|
pub mod btree;
|
|
|
|
pub mod structs;
|
|
|
|
pub mod bitmap;
|
2023-07-27 09:28:06 -07:00
|
|
|
pub mod crc32;
|
2023-07-25 07:03:06 -07:00
|
|
|
|
2023-07-27 09:28:06 -07:00
|
|
|
/// 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.
|
2023-07-25 07:03:06 -07:00
|
|
|
pub fn get_superblock(bd: &mut dyn BlockDevice) -> Option<Superblock> {
|
2023-07-27 09:28:06 -07:00
|
|
|
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
|
2023-07-25 07:03:06 -07:00
|
|
|
}
|