refactor(userspace): split syscall/fat16/ext4 by concern; trim comments

This commit is contained in:
2026-10-27 13:21:53 +01:00
parent 99273db6d3
commit b4390b7b6d
25 changed files with 1283 additions and 1229 deletions

View File

@@ -3,50 +3,21 @@ pub mod superblock;
pub mod bgd;
pub mod bitmap;
pub mod dir;
mod extent;
mod inode;
mod path;
use port_block_device::BlockDevice;
use crate::filesystem::{DirEntry, FileHandle, FileName, FileSystem};
use io::{read_block, read_u32, read_u16};
use io::read_block;
use superblock::Superblock;
use bgd::BlockGroupDescriptor;
const ROOT_INODE: u32 = 2;
const MAX_OPEN_FILES: usize = 8;
const EXTENT_MAGIC: u16 = 0xF30A;
pub struct Inode {
pub mode: u16,
pub size: u64,
pub flags: u32,
pub links_count: u16,
pub blocks_count: u32,
pub block_data: [u8; 60],
}
impl Inode {
pub fn is_dir(&self) -> bool { self.mode & 0xF000 == 0x4000 }
pub fn is_file(&self) -> bool { self.mode & 0xF000 == 0x8000 }
pub fn uses_extents(&self) -> bool { self.flags & 0x80000 != 0 }
}
#[derive(Clone, Copy)]
pub struct Extent {
pub logical_block: u32,
pub length: u16,
pub physical_block: u64,
}
impl Extent {
pub fn parse(data: &[u8]) -> Self {
let start_hi = read_u16(data, 6) as u64;
let start_lo = read_u32(data, 8) as u64;
Self {
logical_block: read_u32(data, 0),
length: read_u16(data, 4),
physical_block: (start_hi << 32) | start_lo,
}
}
}
pub use inode::{Extent, Inode};
#[derive(Clone, Copy)]
struct OpenFile {
@@ -80,265 +51,6 @@ impl<B: BlockDevice> Ext4<B> {
open_files: [const { None }; MAX_OPEN_FILES],
})
}
fn read_inode(&mut self, inode_num: u32) -> Option<Inode> {
let bgd = BlockGroupDescriptor::read(
&mut self.device, self.gdt_block,
self.sb.inode_block_group(inode_num),
self.sb.sectors_per_block(),
)?;
let index = self.sb.inode_index_in_group(inode_num);
let inode_offset = (index as usize) * (self.sb.inode_size as usize);
let block_offset = inode_offset / self.sb.block_size;
let offset_in_block = inode_offset % self.sb.block_size;
let mut block_buf = [0u8; 4096];
read_block(
&mut self.device,
(bgd.inode_table + block_offset as u32) as u64,
self.sb.sectors_per_block(),
&mut block_buf,
);
let d = &block_buf[offset_in_block..];
if d.len() < 128 { return None; }
let size_lo = read_u32(d, 0x04) as u64;
let size_hi = read_u32(d, 0x6C) as u64;
let size = size_lo | (size_hi << 32);
let mut block_data = [0u8; 60];
block_data.copy_from_slice(&d[0x28..0x64]);
Some(Inode {
mode: read_u16(d, 0x00),
size,
flags: read_u32(d, 0x20),
links_count: read_u16(d, 0x1A),
blocks_count: read_u32(d, 0x1C),
block_data,
})
}
fn write_inode(&mut self, inode_num: u32, inode: &Inode) -> bool {
let bgd = match BlockGroupDescriptor::read(
&mut self.device, self.gdt_block,
self.sb.inode_block_group(inode_num),
self.sb.sectors_per_block(),
) {
Some(b) => b,
None => return false,
};
let index = self.sb.inode_index_in_group(inode_num);
let inode_offset = (index as usize) * (self.sb.inode_size as usize);
let block_offset = inode_offset / self.sb.block_size;
let offset_in_block = inode_offset % self.sb.block_size;
let mut block_buf = [0u8; 4096];
let block_num = (bgd.inode_table + block_offset as u32) as u64;
read_block(&mut self.device, block_num, self.sb.sectors_per_block(), &mut block_buf);
let d = &mut block_buf[offset_in_block..];
io::write_u16(d, 0x00, inode.mode);
io::write_u32(d, 0x04, inode.size as u32);
io::write_u16(d, 0x1A, inode.links_count);
io::write_u32(d, 0x1C, inode.blocks_count);
io::write_u32(d, 0x20, inode.flags);
d[0x28..0x64].copy_from_slice(&inode.block_data);
io::write_u32(d, 0x6C, (inode.size >> 32) as u32);
io::write_block(&mut self.device, block_num, self.sb.sectors_per_block(), &block_buf)
}
pub fn init_empty_inode(mode: u16) -> Inode {
let mut block_data = [0u8; 60];
io::write_u16(&mut block_data, 0, EXTENT_MAGIC);
io::write_u16(&mut block_data, 2, 0); // entries = 0
io::write_u16(&mut block_data, 4, 4); // max = 4
io::write_u16(&mut block_data, 6, 0); // depth = 0
Inode {
mode,
size: 0,
flags: 0x80000,
links_count: 1,
blocks_count: 0,
block_data,
}
}
pub fn read_inode_pub(&mut self, inode_num: u32) -> Option<Inode> {
self.read_inode(inode_num)
}
pub fn write_inode_pub(&mut self, inode_num: u32, inode: &Inode) -> bool {
self.write_inode(inode_num, inode)
}
pub fn alloc_block(&mut self) -> Option<u32> {
let spb = self.sb.sectors_per_block();
bitmap::alloc_block(&mut self.device, &mut self.sb, self.gdt_block, spb)
}
pub fn free_block(&mut self, block: u32) {
let spb = self.sb.sectors_per_block();
bitmap::free_block(&mut self.device, &mut self.sb, self.gdt_block, block, spb);
}
pub fn alloc_inode(&mut self) -> Option<u32> {
let spb = self.sb.sectors_per_block();
bitmap::alloc_inode(&mut self.device, &mut self.sb, self.gdt_block, spb)
}
pub fn free_inode(&mut self, inode: u32) {
let spb = self.sb.sectors_per_block();
bitmap::free_inode(&mut self.device, &mut self.sb, self.gdt_block, inode, spb);
}
pub fn find_in_dir_pub(&mut self, dir_inode_num: u32, name: &[u8]) -> Option<u32> {
let inode = self.read_inode(dir_inode_num)?;
dir::find_entry(&mut self.device, &self.sb, self.gdt_block, &inode, name)
}
pub fn add_dir_entry(&mut self, dir_inode_num: u32, name: &[u8], child_inode: u32, file_type: u8) -> bool {
let inode = match self.read_inode(dir_inode_num) {
Some(i) => i,
None => return false,
};
dir::add_entry(&mut self.device, &self.sb, self.gdt_block, &inode, name, child_inode, file_type)
}
pub fn remove_dir_entry(&mut self, dir_inode_num: u32, name: &[u8]) -> Option<u32> {
let inode = self.read_inode(dir_inode_num)?;
dir::remove_entry(&mut self.device, &self.sb, self.gdt_block, &inode, name)
}
fn read_extents(&self, inode: &Inode) -> Option<Extent> {
if !inode.uses_extents() { return None; }
let hdr = &inode.block_data;
let magic = read_u16(hdr, 0);
if magic != EXTENT_MAGIC { return None; }
let entries = read_u16(hdr, 2);
let depth = read_u16(hdr, 6);
if depth != 0 || entries == 0 { return None; }
Some(Extent::parse(&hdr[12..24]))
}
fn map_logical_block(&mut self, inode: &Inode, logical_block: u32) -> Option<u64> {
if !inode.uses_extents() { return None; }
let hdr = &inode.block_data;
let magic = read_u16(hdr, 0);
if magic != EXTENT_MAGIC { return None; }
let entries = read_u16(hdr, 2);
let depth = read_u16(hdr, 6);
if depth != 0 {
return None;
}
for i in 0..entries as usize {
let off = 12 + i * 12;
if off + 12 > hdr.len() { break; }
let ext = Extent::parse(&hdr[off..off + 12]);
if logical_block >= ext.logical_block
&& logical_block < ext.logical_block + ext.length as u32
{
return Some(ext.physical_block + (logical_block - ext.logical_block) as u64);
}
}
None
}
fn find_in_dir(&mut self, dir_inode: u32, name: &[u8]) -> Option<u32> {
let inode = self.read_inode(dir_inode)?;
dir::find_entry(&mut self.device, &self.sb, self.gdt_block, &inode, name)
}
fn resolve_path(&mut self, path: &[u8]) -> Option<u32> {
let mut current = ROOT_INODE;
for component in path.split(|&b| b == b'/') {
if component.is_empty() { continue; }
current = self.find_in_dir(current, component)?;
}
Some(current)
}
fn alloc_handle(&self) -> Option<FileHandle> {
for i in 0..MAX_OPEN_FILES {
if self.open_files[i].is_none() {
return Some(FileHandle::new(i as u16));
}
}
None
}
fn resolve_parent<'a>(&mut self, path: &'a [u8]) -> Option<(u32, &'a [u8])> {
let path = if path.starts_with(b"/") { &path[1..] } else { path };
if let Some(last_slash) = path.iter().rposition(|&b| b == b'/') {
let parent_path = &path[..last_slash];
let filename = &path[last_slash + 1..];
let parent_inode = self.resolve_path(parent_path)?;
Some((parent_inode, filename))
} else {
Some((ROOT_INODE, path))
}
}
fn append_extent(block_data: &mut [u8], logical_block: u32, physical_block: u64, length: u16) -> bool {
let magic = read_u16(block_data, 0);
if magic != EXTENT_MAGIC { return false; }
let entries = read_u16(block_data, 2);
let max = read_u16(block_data, 4);
if entries > 0 {
let last_off = 12 + (entries as usize - 1) * 12;
let last = Extent::parse(&block_data[last_off..last_off + 12]);
if last.physical_block + last.length as u64 == physical_block
&& last.logical_block + last.length as u32 == logical_block
{
let new_len = last.length + length;
io::write_u16(block_data, last_off + 4, new_len);
return true;
}
}
if entries >= max { return false; }
let off = 12 + entries as usize * 12;
if off + 12 > block_data.len() { return false; }
io::write_u32(block_data, off, logical_block);
io::write_u16(block_data, off + 4, length);
io::write_u16(block_data, off + 6, (physical_block >> 32) as u16);
io::write_u32(block_data, off + 8, physical_block as u32);
io::write_u16(block_data, 2, entries + 1);
true
}
fn count_extent_blocks(block_data: &[u8; 60]) -> u32 {
let magic = read_u16(block_data, 0);
if magic != EXTENT_MAGIC { return 0; }
let entries = read_u16(block_data, 2);
let mut total = 0u32;
for i in 0..entries as usize {
let off = 12 + i * 12;
if off + 12 > block_data.len() { break; }
total += read_u16(block_data, off + 4) as u32;
}
total
}
fn free_all_blocks(&mut self, inode: &Inode) {
if !inode.uses_extents() { return; }
let hdr = &inode.block_data;
let magic = read_u16(hdr, 0);
if magic != EXTENT_MAGIC { return; }
let entries = read_u16(hdr, 2);
for i in 0..entries as usize {
let off = 12 + i * 12;
if off + 12 > hdr.len() { break; }
let ext = Extent::parse(&hdr[off..off + 12]);
for b in 0..ext.length as u32 {
self.free_block(ext.physical_block as u32 + b);
}
}
}
}
impl<B: BlockDevice> FileSystem for Ext4<B> {