forked from AbleOS/ableos
117 lines
3.7 KiB
Rust
117 lines
3.7 KiB
Rust
//!
|
|
|
|
use {
|
|
alloc::vec::Vec,
|
|
core::{fmt::Debug, mem},
|
|
error::Error,
|
|
sector::{Address, SectorSize},
|
|
volume::Volume,
|
|
};
|
|
|
|
/// The Block Group Descriptor Table contains a descriptor for each block group
|
|
/// within the file system. The number of block groups within the file system,
|
|
/// and correspondingly, the number of entries in the Block Group Descriptor
|
|
/// Table, is described above. Each descriptor contains information regarding
|
|
/// where important data structures for that group are located.
|
|
///
|
|
/// The (`BlockGroupDescriptor`) table is located in the block immediately
|
|
/// following the Superblock. So if the block size (determined from a field in
|
|
/// the superblock) is 1024 bytes per block, the Block Group Descriptor Table
|
|
/// will begin at block 2. For any other block size, it will begin at block 1.
|
|
/// Remember that blocks are numbered starting at 0, and that block numbers
|
|
/// don't usually correspond to physical block addresses.
|
|
#[repr(C, packed)]
|
|
#[derive(Clone, Debug, Copy)]
|
|
pub struct BlockGroupDescriptor {
|
|
/// Block address of block usage bitmap
|
|
pub block_usage_addr: u32,
|
|
/// Block address of inode usage bitmap
|
|
pub inode_usage_addr: u32,
|
|
/// Starting block address of inode table
|
|
pub inode_table_block: u32,
|
|
/// Number of unallocated blocks in group
|
|
pub free_blocks_count: u16,
|
|
/// Number of unallocated inodes in group
|
|
pub free_inodes_count: u16,
|
|
/// Number of directories in group
|
|
pub dirs_count: u16,
|
|
#[doc(hidden)]
|
|
_reserved: [u8; 14],
|
|
}
|
|
|
|
impl BlockGroupDescriptor {
|
|
/// Find a descriptor in a descriptor table
|
|
pub unsafe fn find_descriptor<S: SectorSize, V: Volume<u8, S>>(
|
|
haystack: &V,
|
|
offset: Address<S>,
|
|
) -> Result<(BlockGroupDescriptor, Address<S>), Error> {
|
|
let end =
|
|
offset + Address::from(mem::size_of::<BlockGroupDescriptor>());
|
|
if haystack.size() < end {
|
|
return Err(Error::AddressOutOfBounds {
|
|
sector: end.sector(),
|
|
offset: end.offset(),
|
|
size: end.sector_size(),
|
|
});
|
|
}
|
|
|
|
let descr = haystack
|
|
.slice_unchecked(offset..end)
|
|
.dynamic_cast::<BlockGroupDescriptor>();
|
|
|
|
Ok(descr)
|
|
}
|
|
/// find a descriptor table
|
|
pub unsafe fn find_descriptor_table<S: SectorSize, V: Volume<u8, S>>(
|
|
haystack: &V,
|
|
offset: Address<S>,
|
|
count: usize,
|
|
) -> Result<(Vec<BlockGroupDescriptor>, Address<S>), Error> {
|
|
let end = offset
|
|
+ Address::from(count * mem::size_of::<BlockGroupDescriptor>());
|
|
if haystack.size() < end {
|
|
return Err(Error::AddressOutOfBounds {
|
|
sector: end.sector(),
|
|
offset: end.offset(),
|
|
size: end.sector_size(),
|
|
});
|
|
}
|
|
|
|
let mut vec = Vec::with_capacity(count);
|
|
for i in 0..count {
|
|
let offset = offset
|
|
+ Address::from(i * mem::size_of::<BlockGroupDescriptor>());
|
|
vec.push({
|
|
BlockGroupDescriptor::find_descriptor(haystack, offset)?.0
|
|
});
|
|
}
|
|
|
|
Ok((vec, offset))
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use sector::{Address, Size512};
|
|
|
|
#[test]
|
|
fn find() {
|
|
let volume = vec![0_u8; 4096];
|
|
let table = unsafe {
|
|
BlockGroupDescriptor::find_descriptor_table(
|
|
&volume,
|
|
Address::<Size512>::new(4, 0),
|
|
8,
|
|
)
|
|
};
|
|
assert!(
|
|
table.is_ok(),
|
|
"Err({:?})",
|
|
table.err().unwrap_or_else(|| unreachable!()),
|
|
);
|
|
let table = table.unwrap_or_else(|_| unreachable!());
|
|
assert_eq!(table.0.len(), 8);
|
|
}
|
|
}
|