From 194024bc088a762546226eec310d3a5b3ab6a24c Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Sun, 18 Oct 2026 23:30:56 +0200 Subject: [PATCH] fix(ext4): remove old monolithic ext4.rs superseded by ext4/ directory --- crates/servers/storage-server/src/fs/ext4.rs | 345 ------------------- 1 file changed, 345 deletions(-) delete mode 100644 crates/servers/storage-server/src/fs/ext4.rs diff --git a/crates/servers/storage-server/src/fs/ext4.rs b/crates/servers/storage-server/src/fs/ext4.rs deleted file mode 100644 index 5a8b714..0000000 --- a/crates/servers/storage-server/src/fs/ext4.rs +++ /dev/null @@ -1,345 +0,0 @@ -use port_block_device::{BlockDevice, SectorId}; -use crate::filesystem::{DirEntry, FileHandle, FileName, FileSystem}; - -const SECTOR_SIZE: usize = 512; -const SUPERBLOCK_OFFSET: usize = 1024; -const EXT4_MAGIC: u16 = 0xEF53; -const ROOT_INODE: u32 = 2; -const MAX_OPEN_FILES: usize = 8; -const EXTENT_MAGIC: u16 = 0xF30A; - -struct Superblock { - inodes_count: u32, - blocks_count: u32, - block_size: usize, - blocks_per_group: u32, - inodes_per_group: u32, - inode_size: u16, - first_data_block: u32, -} - -impl Superblock { - fn parse(data: &[u8]) -> Option { - if data.len() < 256 { return None; } - let magic = u16::from_le_bytes([data[0x38], data[0x39]]); - if magic != EXT4_MAGIC { return None; } - - let log_block_size = u32::from_le_bytes([data[0x18], data[0x19], data[0x1A], data[0x1B]]); - Some(Self { - inodes_count: read_u32(data, 0x00), - blocks_count: read_u32(data, 0x04), - block_size: 1024 << log_block_size, - blocks_per_group: read_u32(data, 0x20), - inodes_per_group: read_u32(data, 0x28), - inode_size: u16::from_le_bytes([data[0x58], data[0x59]]), - first_data_block: read_u32(data, 0x14), - }) - } - - fn sectors_per_block(&self) -> usize { - self.block_size / SECTOR_SIZE - } - - fn inode_block_group(&self, inode: u32) -> u32 { - (inode - 1) / self.inodes_per_group - } - - fn inode_index_in_group(&self, inode: u32) -> u32 { - (inode - 1) % self.inodes_per_group - } -} - -struct Inode { - mode: u16, - size: u64, - flags: u32, - block_data: [u8; 60], -} - -impl Inode { - fn is_dir(&self) -> bool { self.mode & 0xF000 == 0x4000 } - fn is_file(&self) -> bool { self.mode & 0xF000 == 0x8000 } - fn uses_extents(&self) -> bool { self.flags & 0x80000 != 0 } -} - -#[derive(Clone, Copy)] -struct Extent { - logical_block: u32, - length: u16, - physical_block: u64, -} - -impl Extent { - fn parse(data: &[u8]) -> Self { - let start_hi = u16::from_le_bytes([data[6], data[7]]) as u64; - let start_lo = read_u32(data, 8) as u64; - Self { - logical_block: read_u32(data, 0), - length: u16::from_le_bytes([data[4], data[5]]), - physical_block: (start_hi << 32) | start_lo, - } - } -} - -#[derive(Clone, Copy)] -struct OpenFile { - inode_num: u32, - size: usize, - offset: usize, - name: FileName, - first_extent: Extent, -} - -pub struct Ext4 { - device: B, - sb: Superblock, - gdt_block: u32, - open_files: [Option; MAX_OPEN_FILES], -} - -impl Ext4 { - pub fn mount(mut device: B) -> Option { - let mut buf = [0u8; 1024]; - // Superblock starts at byte 1024 = sector 2 - if !device.read_sector(SectorId::new(2), &mut buf[..512]) { return None; } - if !device.read_sector(SectorId::new(3), &mut buf[512..]) { return None; } - - let sb = Superblock::parse(&buf)?; - let gdt_block = sb.first_data_block + 1; - - Some(Self { - device, - sb, - gdt_block, - open_files: [const { None }; MAX_OPEN_FILES], - }) - } - - fn read_block(&mut self, block: u64, buf: &mut [u8]) -> bool { - let start_sector = (block as usize) * self.sb.sectors_per_block(); - let spb = self.sb.sectors_per_block(); - for i in 0..spb { - let offset = i * SECTOR_SIZE; - if offset + SECTOR_SIZE > buf.len() { break; } - if !self.device.read_sector( - SectorId::new((start_sector + i) as u32), - &mut buf[offset..offset + SECTOR_SIZE], - ) { - return false; - } - } - true - } - - fn read_inode(&mut self, inode_num: u32) -> Option { - let bg = self.sb.inode_block_group(inode_num); - let index = self.sb.inode_index_in_group(inode_num); - - // Read block group descriptor - let mut gdt_buf = [0u8; 4096]; - self.read_block(self.gdt_block as u64, &mut gdt_buf); - let gd_offset = (bg as usize) * 32; - let inode_table_block = read_u32(&gdt_buf, gd_offset + 8); - - // Calculate inode position - 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]; - self.read_block((inode_table_block + block_offset as u32) as u64, &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: u16::from_le_bytes([d[0x00], d[0x01]]), - size, - flags: read_u32(d, 0x20), - block_data, - }) - } - - fn read_extents(&self, inode: &Inode) -> Option { - if !inode.uses_extents() { return None; } - let hdr = &inode.block_data; - let magic = u16::from_le_bytes([hdr[0], hdr[1]]); - if magic != EXTENT_MAGIC { return None; } - let entries = u16::from_le_bytes([hdr[2], hdr[3]]); - let depth = u16::from_le_bytes([hdr[6], hdr[7]]); - if depth != 0 || entries == 0 { return None; } - Some(Extent::parse(&hdr[12..24])) - } - - fn find_in_dir(&mut self, dir_inode: u32, name: &[u8]) -> Option { - let inode = self.read_inode(dir_inode)?; - if !inode.is_dir() { return None; } - - let extent = self.read_extents(&inode)?; - let mut block_buf = [0u8; 4096]; - - for blk in 0..extent.length as u64 { - self.read_block(extent.physical_block + blk, &mut block_buf); - let mut pos = 0; - while pos + 8 <= self.sb.block_size { - let entry_inode = read_u32(&block_buf, pos); - let rec_len = u16::from_le_bytes([block_buf[pos + 4], block_buf[pos + 5]]) as usize; - let name_len = block_buf[pos + 6] as usize; - - if rec_len == 0 { break; } - if entry_inode != 0 && name_len == name.len() { - if &block_buf[pos + 8..pos + 8 + name_len] == name { - return Some(entry_inode); - } - } - pos += rec_len; - } - } - None - } - - fn resolve_path(&mut self, path: &[u8]) -> Option { - 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 { - for i in 0..MAX_OPEN_FILES { - if self.open_files[i].is_none() { - return Some(FileHandle::new(i as u16)); - } - } - None - } -} - -impl FileSystem for Ext4 { - fn open(&mut self, path: &[u8]) -> Option { - let inode_num = self.resolve_path(path)?; - let inode = self.read_inode(inode_num)?; - if !inode.is_file() { return None; } - - let extent = self.read_extents(&inode)?; - let handle = self.alloc_handle()?; - self.open_files[handle.raw() as usize] = Some(OpenFile { - inode_num, - size: inode.size as usize, - offset: 0, - name: FileName::from_bytes(path), - first_extent: extent, - }); - Some(handle) - } - - fn read(&mut self, handle: FileHandle, buf: &mut [u8]) -> Option { - let file = *self.open_files[handle.raw() as usize].as_ref()?; - if file.offset >= file.size { return Some(0); } - - let remaining = file.size - file.offset; - let to_read = buf.len().min(remaining); - let bs = self.sb.block_size; - - let block_in_extent = file.offset / bs; - let byte_in_block = file.offset % bs; - - let mut block_buf = [0u8; 4096]; - let phys_block = file.first_extent.physical_block + block_in_extent as u64; - self.read_block(phys_block, &mut block_buf); - - let available = bs - byte_in_block; - let chunk = to_read.min(available); - buf[..chunk].copy_from_slice(&block_buf[byte_in_block..byte_in_block + chunk]); - - self.open_files[handle.raw() as usize].as_mut().map(|f| f.offset += chunk); - Some(chunk) - } - - fn write(&mut self, _handle: FileHandle, _buf: &[u8]) -> Option { - // Write requires block allocation + inode update + extent modification - // Deferred: needs block bitmap management - None - } - - fn close(&mut self, handle: FileHandle) { - self.open_files[handle.raw() as usize] = None; - } - - fn list_dir(&mut self, path: &[u8], entries: &mut [DirEntry]) -> Option { - let dir_inode_num = if path.is_empty() || path == b"/" { - ROOT_INODE - } else { - self.resolve_path(path)? - }; - - let inode = self.read_inode(dir_inode_num)?; - if !inode.is_dir() { return None; } - - let extent = self.read_extents(&inode)?; - let mut block_buf = [0u8; 4096]; - let mut count = 0; - - for blk in 0..extent.length as u64 { - self.read_block(extent.physical_block + blk, &mut block_buf); - let mut pos = 0; - while pos + 8 <= self.sb.block_size && count < entries.len() { - let entry_inode = read_u32(&block_buf, pos); - let rec_len = u16::from_le_bytes([block_buf[pos + 4], block_buf[pos + 5]]) as usize; - let name_len = block_buf[pos + 6] as usize; - let file_type = block_buf[pos + 7]; - - if rec_len == 0 { break; } - if entry_inode != 0 && name_len > 0 { - let name = &block_buf[pos + 8..pos + 8 + name_len]; - if name != b"." && name != b".." { - let child_size = if file_type == 1 { - self.read_inode(entry_inode) - .map(|i| i.size as usize) - .unwrap_or(0) - } else { 0 }; - - entries[count] = DirEntry { - name: FileName::from_bytes(name), - size: child_size, - is_dir: file_type == 2, - }; - count += 1; - } - } - pos += rec_len; - } - } - Some(count) - } - - fn create(&mut self, _path: &[u8]) -> Option { - // Create requires inode allocation + directory entry insertion - // Deferred: needs inode bitmap management - None - } - - fn delete(&mut self, _path: &[u8]) -> bool { - // Delete requires inode deallocation + directory entry removal - false - } - - fn file_size(&mut self, handle: FileHandle) -> Option { - self.open_files[handle.raw() as usize].as_ref().map(|f| f.size) - } - - fn mkdir(&mut self, _path: &[u8]) -> bool { false } -} - -fn read_u32(data: &[u8], offset: usize) -> u32 { - u32::from_le_bytes([data[offset], data[offset + 1], data[offset + 2], data[offset + 3]]) -}