From 952620d90566ca9c9be9af19ebdc82f17fbfca74 Mon Sep 17 00:00:00 2001 From: juls0730 <62722391+juls0730@users.noreply.github.com> Date: Tue, 19 Mar 2024 03:58:47 -0500 Subject: [PATCH] fully functional squashfs driver!! + gen code cleanup --- Makefile | 4 +- src/drivers/fs/fat.rs | 150 ++-- src/drivers/fs/initramfs/compressors/gzip.rs | 24 +- src/drivers/fs/initramfs/mod.rs | 804 +++++++++++++++---- src/drivers/fs/vfs.rs | 86 +- src/libs/cell/mod.rs | 4 + src/libs/math.rs | 89 ++ src/libs/mod.rs | 1 + src/main.rs | 70 +- 9 files changed, 944 insertions(+), 288 deletions(-) create mode 100644 src/libs/math.rs diff --git a/Makefile b/Makefile index d32e509..bdf09c9 100644 --- a/Makefile +++ b/Makefile @@ -78,7 +78,7 @@ copy-initramfs-files: echo "Hello World from Initramfs" > ${INITRAMFS_PATH}/example.txt echo "Second file for testing" > ${INITRAMFS_PATH}/example2.txt mkdir -p ${INITRAMFS_PATH}/firstdir/seconddirbutlonger/ - echo "Hell yeah, we getting a working initramfs using a custom squashfs driver!!" > ${INITRAMFS_PATH}/firstdir/seconddirbutlonger/yeah.txt + echo "Nexted file reads!!" > ${INITRAMFS_PATH}/firstdir/seconddirbutlonger/yeah.txt compile-initramfs: copy-initramfs-files # Make squashfs without compression temporaily so I can get it working before I have to write a gzip driver @@ -100,7 +100,7 @@ endif python scripts/font.py mv scripts/font.psf ${INITRAMFS_PATH}/ - # python scripts/initramfs-test.py 1000 ${INITRAMFS_PATH}/ + python scripts/initramfs-test.py 100 ${INITRAMFS_PATH}/ copy-iso-files: # Limine files diff --git a/src/drivers/fs/fat.rs b/src/drivers/fs/fat.rs index 86a8eea..599fb67 100755 --- a/src/drivers/fs/fat.rs +++ b/src/drivers/fs/fat.rs @@ -511,21 +511,18 @@ impl FatFs { } impl FsOps for FatFs { - fn mount(&self, path: &str, data: &mut *mut u8, vfsp: *const super::vfs::Vfs) { + fn mount(&mut self, _path: &str, data: &mut *mut u8, _vfsp: *const super::vfs::Vfs) { // TODO: load the FAT into memory here *data = core::ptr::addr_of!(*self) as *mut u8; - - // *data = unsafe { alloc::alloc::alloc(alloc::alloc::Layout::new::>()) }; - // unsafe { *data.cast::>() = None }; } - fn unmount(&self, vfsp: *const super::vfs::Vfs) { + fn unmount(&mut self, _vfsp: *const super::vfs::Vfs) { // TODO: unload the FAT form memory } - fn root(&self, vfsp: *const super::vfs::Vfs) -> super::vfs::VNode { - let mut root_cluster = match self.fat_type { + fn root(&mut self, vfsp: *const super::vfs::Vfs) -> super::vfs::VNode { + let root_cluster = match self.fat_type { FatType::Fat32(ebpb) => ebpb.root_dir_cluster as usize, _ => self.sector_to_cluster( self.bpb.reserved_sectors as usize @@ -535,7 +532,6 @@ impl FsOps for FatFs { let file = File::Dir(FatDirectory { directory_cluster: root_cluster, - // fat_fs: self, }); return super::vfs::VNode { @@ -552,19 +548,23 @@ impl FsOps for FatFs { }; } - fn fid(&self, path: &str, vfsp: *const super::vfs::Vfs) -> Option { + fn fid(&mut self, _path: &str, _vfsp: *const super::vfs::Vfs) -> Option { todo!("FAT FID"); } - fn statfs(&self, vfsp: *const super::vfs::Vfs) -> super::vfs::StatFs { + fn statfs(&mut self, _vfsp: *const super::vfs::Vfs) -> super::vfs::StatFs { todo!("FAT STATFS"); } - fn sync(&self, vfsp: *const super::vfs::Vfs) { + fn sync(&mut self, _vfsp: *const super::vfs::Vfs) { todo!("FAT SYNC"); } - fn vget(&self, fid: super::vfs::FileId, vfsp: *const super::vfs::Vfs) -> super::vfs::VNode { + fn vget( + &mut self, + _fid: super::vfs::FileId, + _vfsp: *const super::vfs::Vfs, + ) -> super::vfs::VNode { todo!("FAT VGET"); } @@ -607,64 +607,71 @@ enum File { } impl<'a> VNodeOperations for File { - fn access(&self, m: u32, c: super::vfs::UserCred, vp: *const VNode) { + fn access(&mut self, _m: u32, _c: super::vfs::UserCred, _vp: *const VNode) { todo!("VNODE OPERATIONS"); } - fn bmap(&self, block_number: u32, bnp: (), vp: *const VNode) -> super::vfs::VNode { + fn bmap(&mut self, _block_number: u32, _bnp: (), _vp: *const VNode) -> super::vfs::VNode { todo!("VNODE OPERATIONS"); } - fn bread(&self, block_number: u32, vp: *const VNode) -> Arc<[u8]> { + fn bread(&mut self, _block_number: u32, _vp: *const VNode) -> Arc<[u8]> { todo!("VNODE OPERATIONS"); } - fn close(&self, f: u32, c: super::vfs::UserCred, vp: *const VNode) { + fn close(&mut self, _f: u32, _c: super::vfs::UserCred, _vp: *const VNode) { todo!("VNODE OPERATIONS"); } fn create( - &self, - nm: &str, - va: super::vfs::VAttr, - e: u32, - m: u32, - c: super::vfs::UserCred, - vp: *const VNode, + &mut self, + _nm: &str, + _va: super::vfs::VAttr, + _e: u32, + _m: u32, + _c: super::vfs::UserCred, + _vp: *const VNode, ) -> Result { todo!("VNODE OPERATIONS"); } - fn fsync(&self, c: super::vfs::UserCred, vp: *const VNode) { + fn fsync(&mut self, _c: super::vfs::UserCred, _vp: *const VNode) { todo!("VNODE OPERATIONS"); } - fn getattr(&self, c: super::vfs::UserCred, vp: *const VNode) -> super::vfs::VAttr { + fn getattr(&mut self, _c: super::vfs::UserCred, _vp: *const VNode) -> super::vfs::VAttr { todo!("VNODE OPERATIONS"); } - fn inactive(&self, c: super::vfs::UserCred, vp: *const VNode) { + fn inactive(&mut self, _c: super::vfs::UserCred, _vp: *const VNode) { todo!("VNODE OPERATIONS"); } - fn ioctl(&self, com: u32, d: *mut u8, f: u32, c: super::vfs::UserCred, vp: *const VNode) { + fn ioctl( + &mut self, + _com: u32, + _d: *mut u8, + _f: u32, + _c: super::vfs::UserCred, + _vp: *const VNode, + ) { todo!("VNODE OPERATIONS"); } fn link( - &self, - target_dir: *mut super::vfs::VNode, - target_name: &str, - c: super::vfs::UserCred, - vp: *const VNode, + &mut self, + _target_dir: *mut super::vfs::VNode, + _target_name: &str, + _c: super::vfs::UserCred, + _vp: *const VNode, ) { todo!("VNODE OPERATIONS"); } fn lookup( - &self, + &mut self, nm: &str, - c: super::vfs::UserCred, + _c: super::vfs::UserCred, vp: *const VNode, ) -> Result { let fat_fs = unsafe { (*(*vp).parent).data.cast::() }; @@ -708,16 +715,21 @@ impl<'a> VNodeOperations for File { } fn mkdir( - &self, - nm: &str, - va: super::vfs::VAttr, - c: super::vfs::UserCred, - vp: *const VNode, + &mut self, + _nm: &str, + _va: super::vfs::VAttr, + _c: super::vfs::UserCred, + _vp: *const VNode, ) -> Result { todo!("VNODE OPERATIONS"); } - fn open(&self, f: u32, c: super::vfs::UserCred, vp: *const VNode) -> Result, ()> { + fn open( + &mut self, + _f: u32, + _c: super::vfs::UserCred, + vp: *const VNode, + ) -> Result, ()> { match self { File::Archive(archive) => { let fat_fs = unsafe { (*(*vp).parent).data.cast::() }; @@ -780,59 +792,67 @@ impl<'a> VNodeOperations for File { } _ => panic!("Cannot open non archives"), } - - todo!("VNODE OPERATIONS"); } fn rdwr( - &self, - uiop: *const super::vfs::UIO, - direction: super::vfs::IODirection, - f: u32, - c: super::vfs::UserCred, - vp: *const VNode, + &mut self, + _uiop: *const super::vfs::UIO, + _direction: super::vfs::IODirection, + _f: u32, + _c: super::vfs::UserCred, + _vp: *const VNode, ) { todo!("VNODE OPERATIONS"); } - fn readdir(&self, uiop: *const super::vfs::UIO, c: super::vfs::UserCred, vp: *const VNode) { + fn readdir( + &mut self, + _uiop: *const super::vfs::UIO, + _c: super::vfs::UserCred, + _vp: *const VNode, + ) { todo!("VNODE OPERATIONS"); } - fn readlink(&self, uiop: *const super::vfs::UIO, c: super::vfs::UserCred, vp: *const VNode) { + fn readlink( + &mut self, + _uiop: *const super::vfs::UIO, + _c: super::vfs::UserCred, + _vp: *const VNode, + ) { todo!("VNODE OPERATIONS"); } fn rename( - &self, - nm: &str, - target_dir: *mut super::vfs::VNode, - target_name: &str, - c: super::vfs::UserCred, - vp: *const VNode, + &mut self, + _nm: &str, + _target_dir: *mut super::vfs::VNode, + _target_name: &str, + _c: super::vfs::UserCred, + _vp: *const VNode, ) { todo!("VNODE OPERATIONS"); } - fn select(&self, w: super::vfs::IODirection, c: super::vfs::UserCred, vp: *const VNode) { + fn select(&mut self, _w: super::vfs::IODirection, _c: super::vfs::UserCred, _vp: *const VNode) { todo!("VNODE OPERATIONS"); } - fn setattr(&self, va: super::vfs::VAttr, c: super::vfs::UserCred, vp: *const VNode) { + fn setattr(&mut self, _va: super::vfs::VAttr, _c: super::vfs::UserCred, _vp: *const VNode) { todo!("VNODE OPERATIONS"); } - fn strategy(&self, bp: (), vp: *const VNode) { + fn strategy(&mut self, _bp: (), _vp: *const VNode) { todo!("VNODE OPERATIONS"); } fn symlink( - &self, - link_name: &str, - va: super::vfs::VAttr, - target_name: &str, - c: super::vfs::UserCred, - vp: *const VNode, + &mut self, + _link_name: &str, + _va: super::vfs::VAttr, + _target_name: &str, + _c: super::vfs::UserCred, + _vp: *const VNode, ) { todo!("VNODE OPERATIONS"); } diff --git a/src/drivers/fs/initramfs/compressors/gzip.rs b/src/drivers/fs/initramfs/compressors/gzip.rs index 9a25909..7aacace 100644 --- a/src/drivers/fs/initramfs/compressors/gzip.rs +++ b/src/drivers/fs/initramfs/compressors/gzip.rs @@ -36,25 +36,28 @@ pub enum CompressionErrors { // RFC 1950: "ZLIB Compressed Data Format Specification" // RFC 1951: "DEFLATE Compressed Data Format Specification" -pub fn uncompress_data(bytes: &[u8]) -> Result, CompressionErrors> { +pub fn uncompress_data(bytes: &[u8]) -> Result, ()> { assert!(bytes.len() > 2); // Compression Method and flags let cmf = bytes[0]; if (cmf & 0x0F) != 0x08 { - return Err(CompressionErrors::NotDeflate); + return Err(()); + // return Err(CompressionErrors::NotDeflate); } let window_log2 = cmf >> 4 & 0x0F; if window_log2 > 0x07 { - return Err(CompressionErrors::UnsupportedWindowSize); + return Err(()); + // return Err(CompressionErrors::UnsupportedWindowSize); } let flags = bytes[1]; if (cmf as u32 * 256 + flags as u32) % 31 != 0 { - return Err(CompressionErrors::FCheckFailed); + return Err(()); + // return Err(CompressionErrors::FCheckFailed); } let present_dictionary = flags >> 5 & 0x01 != 0; @@ -62,7 +65,8 @@ pub fn uncompress_data(bytes: &[u8]) -> Result, CompressionErrors> { if present_dictionary { // cry - return Err(CompressionErrors::UnsupportedDictionary); + return Err(()); + // return Err(CompressionErrors::UnsupportedDictionary); } let mut inflate_context = InflateContext::new(&bytes[2..bytes.len() - 4]); @@ -70,7 +74,8 @@ pub fn uncompress_data(bytes: &[u8]) -> Result, CompressionErrors> { let data = inflate_context.decompress(); if data.is_err() { - return Err(CompressionErrors::FailedCompression); + return Err(()); + // return Err(CompressionErrors::FailedCompression); } let data = data.unwrap(); @@ -79,7 +84,8 @@ pub fn uncompress_data(bytes: &[u8]) -> Result, CompressionErrors> { let checksum = u32::from_le_bytes(bytes[bytes.len() - 4..].try_into().unwrap()); if adler32(&data) != checksum { - return Err(CompressionErrors::FailedChecksum); + return Err(()); + // return Err(CompressionErrors::FailedChecksum); } return Ok(data); @@ -178,7 +184,7 @@ impl InflateContext { return (base + if num != 0 { self.get_bits(num) } else { 0 } as usize) as u32; } - pub fn decompress(&mut self) -> Result, ()> { + pub fn decompress(&mut self) -> Result, ()> { build_fixed(); loop { @@ -205,7 +211,7 @@ impl InflateContext { } } - return Ok(Arc::from(self.output_buf.clone())); + return Ok(self.output_buf.clone()); } fn decode(&mut self, huff: &mut Huff) -> u32 { diff --git a/src/drivers/fs/initramfs/mod.rs b/src/drivers/fs/initramfs/mod.rs index f87b2df..be346fd 100755 --- a/src/drivers/fs/initramfs/mod.rs +++ b/src/drivers/fs/initramfs/mod.rs @@ -1,20 +1,27 @@ pub mod compressors; -use core::fmt::{self, Debug}; +use core::{ + fmt::{self, Debug}, + mem::MaybeUninit, + ops::{Index, Range, RangeFrom, RangeFull}, +}; -use alloc::{boxed::Box, sync::Arc, vec::Vec}; +use alloc::{borrow::Cow, boxed::Box, string::String, sync::Arc, vec::Vec}; use limine::ModuleRequest; -use crate::libs::cell::LazyCell; +use crate::{ + libs::{ + cell::Cell, + math::{ceil, floor}, + }, + println, +}; -use super::vfs::{FsOps, VNode, VNodeOperations}; +use super::vfs::{FsOps, VNode, VNodeOperations, VNodeType}; pub static MODULE_REQUEST: ModuleRequest = ModuleRequest::new(0); -// TODO: do something better than this shite -pub static INITRAMFS: LazyCell = LazyCell::new(init); - -fn init() -> Squashfs<'static> { +pub fn init() -> Squashfs<'static> { // TODO: Put the module request stuff in another file? if MODULE_REQUEST.get_response().get().is_none() { panic!("Module request in none!"); @@ -55,14 +62,165 @@ fn init() -> Squashfs<'static> { return squashfs; } +#[repr(u8)] +#[derive(Clone, Copy)] +enum Table { + // Metadata table + Inode, + Dir, + Frag, + Export, + ID, + Xattr, +} + +const CHUNK_SIZE: usize = 8192; +const HEADER_SIZE: usize = 2; + +struct Chunk<'a> { + data: Cow<'a, [u8]>, +} + +impl Chunk<'_> { + fn header(&self) -> u16 { + u16::from_le_bytes(self.data[0..HEADER_SIZE].try_into().unwrap()) + } + + fn len(&self) -> usize { + self.header() as usize & 0x7FFF + } + + fn is_compressed(&self) -> bool { + self.header() & 0x8000 == 0 + } + + fn decompress(&mut self, decompressor: &dyn Fn(&[u8]) -> Result, ()>) { + if self.is_compressed() { + let decompressed_data = decompressor(&self.data[HEADER_SIZE..]).unwrap(); + + let header = decompressed_data.len() as u16 | 0x8000; + + let data = [header.to_le_bytes().to_vec(), decompressed_data].concat(); + + self.data = Cow::Owned(data); + } + } +} + +impl Index for Chunk<'_> { + type Output = u8; + + fn index(&self, index: usize) -> &Self::Output { + &self.data[index] + } +} + +impl Index> for Chunk<'_> { + type Output = [u8]; + + fn index(&self, index: Range) -> &Self::Output { + &self.data[index] + } +} + +impl Index> for Chunk<'_> { + type Output = [u8]; + + fn index(&self, index: RangeFrom) -> &Self::Output { + &self.data[index] + } +} + +struct ChunkReader<'a, F> { + chunks: Vec>, + decompressor: F, +} + +impl<'a, F: Fn(&[u8]) -> Result, ()>> ChunkReader<'a, F> { + fn new(data: &'a [u8], decompressor: F) -> Self { + let mut chunks: Vec> = Vec::new(); + + let mut offset = 0; + loop { + if offset == data.len() { + break; + } + + let length = + (u16::from_le_bytes(data[offset..offset + HEADER_SIZE].try_into().unwrap()) + & 0x7FFF) as usize + + HEADER_SIZE; + + chunks.push(Chunk { + data: Cow::Borrowed(&data[offset..offset + length]), + }); + + offset += length; + } + + Self { + chunks, + decompressor, + } + } + + pub fn get_slice(&mut self, mut chunk: u64, mut offset: u16, size: usize) -> Vec { + // handle cases where the chunks arent aligned to CHUNK_SIZE (they're compressed and are doing stupid things) + { + let mut chunk_idx = 0; + let mut total_length = 0; + + while total_length != chunk { + chunk_idx += 1; + total_length += (self.chunks[0].len() as usize + HEADER_SIZE) as u64; + } + + chunk = chunk_idx; + } + + let mut chunks_to_read = 1; + { + let mut available_bytes = { + self.chunks[chunk as usize].decompress(&self.decompressor); + self.chunks[chunk as usize][offset as usize..].len() + }; + + while available_bytes < size { + self.chunks[chunk as usize + chunks_to_read].decompress(&self.decompressor); + available_bytes += self.chunks[chunk as usize + chunks_to_read].len(); + chunks_to_read += 1; + } + } + + let mut data = Vec::new(); + + for i in chunk as usize..chunk as usize + chunks_to_read { + self.chunks[i].decompress(&self.decompressor); + + let block_start = offset as usize + HEADER_SIZE; + let mut block_end = self.chunks[i].len() + HEADER_SIZE; + + if (block_end - block_start) > size { + block_end = block_start + size; + } + + data.extend(self.chunks[i][block_start..block_end].into_iter()); + + offset = 0; + } + + data + } +} + #[repr(C)] -#[derive(Debug)] +// #[derive(Debug)] pub struct Squashfs<'a> { - superblock: SquashfsSuperblock, + pub superblock: SquashfsSuperblock, start: *mut u8, data_table: &'a [u8], - inode_table: &'a [u8], - directory_table: &'a [u8], + inode_table: Cell Result, ()>>>>, + directory_table: Cell Result, ()>>>>, fragment_table: Option<&'a [u8]>, export_table: Option<&'a [u8]>, id_table: &'a [u8], @@ -80,80 +238,76 @@ impl Squashfs<'_> { let superblock = SquashfsSuperblock::new(squashfs_data)?; + let decompressor = match superblock.compressor { + SquashfsCompressionType::Gzip => Box::new(compressors::gzip::uncompress_data), + compressor => panic!("Unsupported SquashFS decompressor {compressor:?}"), + }; + + // The easy part with none of this metadata nonesense let data_table = &squashfs_data [core::mem::size_of::()..superblock.inode_table as usize]; - macro_rules! get_metadata_table { - ($table_type:ident) => {{ - // get table size minus the top bit (indicates compression) plus 2, because - // The table size is minus the size of the size header (two bytes) - let table_size = (u16::from_le_bytes( - squashfs_data - [superblock.$table_type as usize..superblock.$table_type as usize + 2] - .try_into() - .unwrap(), - ) & 0x7FFF) - + 2; + let mut tables: Vec<(Table, u64)> = Vec::new(); - &squashfs_data[superblock.$table_type as usize - ..superblock.$table_type as usize + table_size as usize] - }}; + tables.push((Table::Inode, superblock.inode_table)); + tables.push((Table::Dir, superblock.dir_table)); + + if superblock.frag_table != u64::MAX { + tables.push((Table::Frag, superblock.frag_table)); } - let inode_table = get_metadata_table!(inode_table); + if superblock.export_table != u64::MAX { + tables.push((Table::Export, superblock.export_table)); + } - let directory_table = get_metadata_table!(dir_table); + tables.push((Table::ID, superblock.id_table)); - let fragment_table: Option<&[u8]> = { - if superblock.frag_table == u64::MAX { - None - } else if superblock.export_table != u64::MAX { - Some( - &squashfs_data - [superblock.frag_table as usize..superblock.export_table as usize], - ) - } else if superblock.xattr_table != u64::MAX { - Some( - &squashfs_data[superblock.frag_table as usize..superblock.xattr_table as usize], - ) + if superblock.xattr_table != u64::MAX { + tables.push((Table::Xattr, superblock.xattr_table)); + } + + let mut inode_table: MaybeUninit< + ChunkReader<'static, Box Result, ()>>>, + > = MaybeUninit::uninit(); + let mut directory_table: MaybeUninit< + ChunkReader<'static, Box Result, ()>>>, + > = MaybeUninit::uninit(); + let mut fragment_table = None; + let mut export_table = None; + let mut id_table: &[u8] = &[]; + let mut xattr_table = None; + + for (i, &(table, offset)) in tables.iter().enumerate() { + let whole_table = if i == tables.len() - 1 { + &squashfs_data[offset as usize..] } else { - Some(&squashfs_data[superblock.frag_table as usize..superblock.id_table as usize]) - } - }; + &squashfs_data[offset as usize..tables[i + 1].1 as usize] + }; - let export_table: Option<&[u8]> = { - if superblock.export_table == u64::MAX { - None - } else if superblock.xattr_table != u64::MAX { - Some( - &squashfs_data - [superblock.export_table as usize..superblock.xattr_table as usize], - ) - } else { - Some(&squashfs_data[superblock.export_table as usize..superblock.id_table as usize]) + match table { + Table::Inode => { + inode_table = + MaybeUninit::new(ChunkReader::new(whole_table, decompressor.clone())); + } + Table::Dir => { + directory_table = + MaybeUninit::new(ChunkReader::new(whole_table, decompressor.clone())); + } + Table::Frag => { + fragment_table = Some(whole_table); + } + Table::Export => export_table = Some(whole_table), + Table::ID => id_table = whole_table, + Table::Xattr => xattr_table = Some(whole_table), } - }; - - let id_table: &[u8] = if superblock.xattr_table != u64::MAX { - &squashfs_data[superblock.id_table as usize..superblock.xattr_table as usize] - } else { - &squashfs_data[superblock.id_table as usize..] - }; - - let xattr_table: Option<&[u8]> = { - if superblock.xattr_table == u64::MAX { - None - } else { - Some(&squashfs_data[superblock.xattr_table as usize..]) - } - }; + } return Ok(Squashfs { superblock, start: ptr, data_table, - inode_table, - directory_table, + inode_table: Cell::new(unsafe { inode_table.assume_init() }), + directory_table: Cell::new(unsafe { directory_table.assume_init() }), fragment_table, export_table, id_table, @@ -161,40 +315,211 @@ impl Squashfs<'_> { }); } - fn read_root_dir(&self) -> BasicDirectoryInode { - let root_inode_offset = self.superblock.root_inode_offset as usize; + fn get_inode_block_offset(&self, inode: u64) -> (u64, u16) { + let inode_block = ((inode >> 16) & 0x0000FFFFFFFFFFFF) as u64; + let inode_offset = (inode & 0xFFFF) as u16; - let root_inode: BasicDirectoryInode = self - .read_inode(root_inode_offset as u32) - .try_into() - .expect("Failed to try_into"); - - return root_inode; + (inode_block, inode_offset) } - fn read_inode(&self, inode_num: u32) -> Inode { - let inode_table = &self.get_decompressed_table(self.inode_table, (true, None)); + fn read_root_dir(&mut self) -> Inode { + self.read_inode(self.superblock.root_inode) + } - let inode_offset = inode_num as usize; + fn read_inode(&mut self, inode: u64) -> Inode { + let (inode_block, inode_offset) = self.get_inode_block_offset(inode); - let inode_file_type: InodeFileType = u16::from_le_bytes( - inode_table[inode_offset..(inode_offset + 2)] + // println!("inode block: {inode_block} inode offset: {inode_offset}"); + + let file_type = InodeFileType::from(u16::from_le_bytes( + self.inode_table + .get_mut() + .get_slice(inode_block, inode_offset, 2) .try_into() .unwrap(), - ) - .into(); + )); - match inode_file_type { - InodeFileType::BasicDirectory => { - return Inode::BasicDirectory(BasicDirectoryInode::from_bytes( - &inode_table[inode_offset..], - )); - } - InodeFileType::BasicFile => { - return Inode::BasicFile(BasicFileInode::from_bytes(&inode_table[inode_offset..])); - } - _ => panic!("Unsupported or unknown inode file type {inode_file_type:?}!"), + let inode_size = match file_type { + InodeFileType::BasicDirectory => core::mem::size_of::(), + InodeFileType::ExtendedDirectory => core::mem::size_of::(), + InodeFileType::BasicFile => core::mem::size_of::(), + inode_type => unimplemented!("Inode type {inode_type:?}"), }; + + let inode_bytes: &[u8] = + &self + .inode_table + .get_mut() + .get_slice(inode_block, inode_offset, inode_size); + + // println!("{inode_bytes:X?}"); + + Inode::from(inode_bytes) + } + + fn find_entry_in_directory(&mut self, dir: Inode, name: &str) -> Result { + let dir_inode = match dir { + Inode::BasicDirectory(dir) => { + (dir.block_index as usize) << 16 | dir.block_offset as usize + } + Inode::ExtendedDirectory(dir) => { + (dir.block_index as usize) << 16 | dir.block_offset as usize + } + _ => return Err(()), + }; + + println!("here"); + + let dir_size = match dir { + Inode::BasicDirectory(dir) => dir.file_size as usize, + Inode::ExtendedDirectory(dir) => dir.file_size as usize, + _ => return Err(()), + }; + + if dir_size == 0 { + // directory has no entries + return Err(()); + } + + let (mut directory_block, mut directory_offset) = + self.get_inode_block_offset(dir_inode as u64); + + let directory_table_offset = + ((directory_block as usize / 8194) * 8192) + directory_offset as usize; + + // println!("here"); + + // println!("past here"); + + // println!("dir_size: {dir_size}"); + + let mut directory_table_header = { + let bytes: &[u8] = &self.directory_table.get_mut().get_slice( + directory_block, + directory_offset, + core::mem::size_of::(), + ); + + DirectoryTableHeader::from(bytes) + }; + + let mut offset = core::mem::size_of::(); + let mut i = 0; + + println!("looking for {name}"); + + loop { + println!( + "{directory_block} {directory_offset} {} {}", + directory_offset as usize + offset, + directory_table_header.start + ); + + // TODO: this is dumb, but it works + if self.directory_table.get().chunks[directory_block as usize / 8194].len() + - HEADER_SIZE + < directory_offset as usize + offset as usize + { + directory_block += 8194; + directory_offset = ((offset + directory_offset as usize) + - (self.directory_table.get().chunks[directory_block as usize / 8194].len() + - HEADER_SIZE)) as u16 + - HEADER_SIZE as u16; + offset = 0; + } + + println!( + "{directory_block} {directory_offset} {}", + directory_offset as usize + offset + ); + + // println!( + // "directory table offset: {}", + // directory_table_offset + offset + // ); + + if i == directory_table_header.entry_count && offset != dir_size { + // println!("reading next dir"); + + //read second table + directory_table_header = { + let bytes: &[u8] = &self.directory_table.get_mut().get_slice( + directory_block, + directory_offset + offset as u16, + core::mem::size_of::(), + ); + + DirectoryTableHeader::from(bytes) + }; + + // println!("{directory_table_header:?}"); + + i = 0; + offset += core::mem::size_of::(); + + // todo!("read next table"); + continue; + } + + if offset >= dir_size { + println!("We have reached the end"); + + break; + } + + let name_size = u16::from_le_bytes( + self.directory_table.get_mut() + .get_slice( + directory_block, + directory_offset + (offset as u16 + 6), + 2 + ) + .try_into() + .unwrap(), + ) as usize + // the name is stored off-by-one + + 1; + + // println!( + // "{:X?}", + // &self.directory_table.get_slice( + // directory_block as usize, + // directory_offset as usize + offset + // ..directory_offset as usize + offset + (8 + name_size), + // ) + // ); + + let directory_entry = + DirectoryTableEntry::from_bytes(&self.directory_table.get_mut().get_slice( + directory_block, + directory_offset + offset as u16, + 8 + name_size, + )); + + println!("{}", directory_entry.name); + println!("{directory_entry:?} {offset} {}", 8 + name_size); + + offset += 8 + name_size; + + // println!("{offset}"); + + if directory_entry.name == name { + println!( + "READING: {} {}", + ((directory_table_header.start as usize / (CHUNK_SIZE + HEADER_SIZE)) & 0xFFFF), + directory_entry.offset + ); + + let directory_entry_inode = (directory_table_header.start as usize) << 16 + | (directory_entry.offset as usize); + + return Ok(self.read_inode(directory_entry_inode as u64)); + } + + i += 1; + } + + return Err(()); } // metadata_block takes a tuple, the first element is whether the array is a metadata block, @@ -238,16 +563,19 @@ impl Squashfs<'_> { } impl<'a> FsOps for Squashfs<'a> { - fn mount(&self, path: &str, data: &mut *mut u8, vfsp: *const super::vfs::Vfs) { + fn mount(&mut self, path: &str, data: &mut *mut u8, vfsp: *const super::vfs::Vfs) { + // STUB + + // not recommended:tm: + *data = core::ptr::addr_of!(*self) as *mut u8; + } + + fn unmount(&mut self, vfsp: *const super::vfs::Vfs) { // STUB } - fn unmount(&self, vfsp: *const super::vfs::Vfs) { - // STUB - } - - fn root(&self, vfsp: *const super::vfs::Vfs) -> super::vfs::VNode { - let root_dir = Inode::BasicDirectory(self.read_root_dir()); + fn root(&mut self, vfsp: *const super::vfs::Vfs) -> super::vfs::VNode { + let root_dir = self.read_root_dir(); super::vfs::VNode { flags: 0, @@ -255,7 +583,7 @@ impl<'a> FsOps for Squashfs<'a> { shared_lock_count: 0, exclusive_lock_count: 0, vfs_mounted_here: None, - ops: Box::new(Inode::BasicDirectory(self.read_root_dir())), + ops: Box::new(root_dir), node_data: None, parent: vfsp, typ: super::vfs::VNodeType::Directory, @@ -263,19 +591,19 @@ impl<'a> FsOps for Squashfs<'a> { } } - fn fid(&self, path: &str, vfsp: *const super::vfs::Vfs) -> Option { + fn fid(&mut self, path: &str, vfsp: *const super::vfs::Vfs) -> Option { todo!(); } - fn statfs(&self, vfsp: *const super::vfs::Vfs) -> super::vfs::StatFs { + fn statfs(&mut self, vfsp: *const super::vfs::Vfs) -> super::vfs::StatFs { todo!(); } - fn sync(&self, vfsp: *const super::vfs::Vfs) { + fn sync(&mut self, vfsp: *const super::vfs::Vfs) { todo!(); } - fn vget(&self, fid: super::vfs::FileId, vfsp: *const super::vfs::Vfs) -> super::vfs::VNode { + fn vget(&mut self, fid: super::vfs::FileId, vfsp: *const super::vfs::Vfs) -> super::vfs::VNode { todo!(); } } @@ -314,19 +642,127 @@ impl<'a> FsOps for Squashfs<'a> { enum Inode { BasicFile(BasicFileInode), BasicDirectory(BasicDirectoryInode), + ExtendedDirectory(ExtendedDirectoryInode), +} + +impl From<&[u8]> for Inode { + fn from(value: &[u8]) -> Self { + let file_type = InodeFileType::from(u16::from_le_bytes(value[0..2].try_into().unwrap())); + + match file_type { + InodeFileType::BasicDirectory => { + Inode::BasicDirectory(BasicDirectoryInode::from_bytes(value)) + } + InodeFileType::ExtendedDirectory => { + Inode::ExtendedDirectory(ExtendedDirectoryInode::from_bytes(value)) + } + InodeFileType::BasicFile => Inode::BasicFile(BasicFileInode::from_bytes(value)), + _ => unimplemented!("Inode from bytes"), + } + } } impl VNodeOperations for Inode { - fn open(&self, f: u32, c: super::vfs::UserCred, vp: *const VNode) -> Result, ()> { + fn open(&mut self, f: u32, c: super::vfs::UserCred, vp: *const VNode) -> Result, ()> { + let squashfs = unsafe { (*(*vp).parent).data.cast::() }; + + match self { + Inode::BasicFile(file) => unsafe { + // TODO: is this really how you're supposed to do this? + let mut block_data: Vec = Vec::with_capacity(file.file_size as usize); + + let data_table: Vec; + + let block_offset = if file.frag_idx == u32::MAX { + data_table = (*squashfs).get_decompressed_table( + (*squashfs).data_table, + ( + false, + Some(!(*squashfs).superblock.features().uncompressed_data_blocks), + ), + ); + + file.block_offset as usize + } else { + // Tail end packing + let fragment_table = (*squashfs).get_decompressed_table( + (*squashfs).fragment_table.unwrap(), + ( + false, + Some(false), // Some( + // !self + // .header + // .squashfs + // .superblock + // .features() + // .uncompressed_fragments, + // ), + ), + ); + + let fragment_pointer = ((*squashfs).start as u64 + + u64::from_le_bytes( + fragment_table[file.frag_idx as usize..(file.frag_idx + 8) as usize] + .try_into() + .unwrap(), + )) as *mut u8; + + // build array since fragment_pointer is not guaranteed to be 0x02 aligned + // We add two since fragment_pointer points to the beginning of the fragment block, + // Which is a metadata block, and we get the size, but that excludes the two header bytes, + // And since we are building the array due to unaligned pointer shenanigans we need to + // include the header bytes otherwise we are short by two bytes + let fragment_block_size = + (u16::from_le(core::ptr::read_unaligned(fragment_pointer as *mut u16)) + & 0x7FFF) + + 2; + + let mut fragment_block_raw = Vec::new(); + for i in 0..fragment_block_size as usize { + fragment_block_raw.push(core::ptr::read_unaligned(fragment_pointer.add(i))) + } + + let fragment_block = + (*squashfs).get_decompressed_table(&fragment_block_raw, (true, None)); + + let fragment_start = + u64::from_le_bytes(fragment_block[0..8].try_into().unwrap()); + let fragment_size = + u32::from_le_bytes(fragment_block[8..12].try_into().unwrap()); + let fragment_compressed = fragment_size & 1 << 24 == 0; + let fragment_size = fragment_size & 0xFEFFFFFF; + + let data_table_raw = core::slice::from_raw_parts( + ((*squashfs).start as u64 + fragment_start) as *mut u8, + fragment_size as usize, + ) + .to_vec(); + + data_table = (*squashfs).get_decompressed_table( + &data_table_raw, + (false, Some(fragment_compressed)), + ); + + file.block_offset as usize + }; + + block_data + .extend(&data_table[block_offset..(block_offset + file.file_size as usize)]); + + return Ok(Arc::from(block_data)); + }, + _ => panic!("Tried to open non-file"), + } + todo!() } - fn close(&self, f: u32, c: super::vfs::UserCred, vp: *const VNode) { + fn close(&mut self, f: u32, c: super::vfs::UserCred, vp: *const VNode) { todo!() } fn rdwr( - &self, + &mut self, uiop: *const super::vfs::UIO, direction: super::vfs::IODirection, f: u32, @@ -336,37 +772,65 @@ impl VNodeOperations for Inode { todo!() } - fn ioctl(&self, com: u32, d: *mut u8, f: u32, c: super::vfs::UserCred, vp: *const VNode) { + fn ioctl(&mut self, com: u32, d: *mut u8, f: u32, c: super::vfs::UserCred, vp: *const VNode) { todo!() } - fn select(&self, w: super::vfs::IODirection, c: super::vfs::UserCred, vp: *const VNode) { + fn select(&mut self, w: super::vfs::IODirection, c: super::vfs::UserCred, vp: *const VNode) { todo!() } - fn getattr(&self, c: super::vfs::UserCred, vp: *const VNode) -> super::vfs::VAttr { + fn getattr(&mut self, c: super::vfs::UserCred, vp: *const VNode) -> super::vfs::VAttr { todo!() } - fn setattr(&self, va: super::vfs::VAttr, c: super::vfs::UserCred, vp: *const VNode) { + fn setattr(&mut self, va: super::vfs::VAttr, c: super::vfs::UserCred, vp: *const VNode) { todo!() } - fn access(&self, m: u32, c: super::vfs::UserCred, vp: *const VNode) { + fn access(&mut self, m: u32, c: super::vfs::UserCred, vp: *const VNode) { todo!() } fn lookup( - &self, + &mut self, nm: &str, c: super::vfs::UserCred, vp: *const VNode, ) -> Result { - todo!() + let squashfs = unsafe { (*(*vp).parent).data.cast::() }; + + match self { + Inode::BasicDirectory(_) | Inode::ExtendedDirectory(_) => unsafe { + println!("Looking for {nm}"); + + let inode = (*squashfs).find_entry_in_directory(*self, nm)?; + let vnode_type = match inode { + Inode::BasicDirectory(_) | Inode::ExtendedDirectory(_) => VNodeType::Directory, + Inode::BasicFile(_) => VNodeType::Regular, + }; + + let vnode = VNode { + flags: 0, + ref_count: 0, + shared_lock_count: 0, + exclusive_lock_count: 0, + vfs_mounted_here: None, + ops: Box::new(inode), + node_data: None, + parent: (*vp).parent, + typ: vnode_type, + data: core::ptr::null_mut(), + }; + + return Ok(vnode); + }, + _ => panic!("tried to lookup on non directory"), + } } fn create( - &self, + &mut self, nm: &str, va: super::vfs::VAttr, e: u32, @@ -378,7 +842,7 @@ impl VNodeOperations for Inode { } fn link( - &self, + &mut self, target_dir: *mut super::vfs::VNode, target_name: &str, c: super::vfs::UserCred, @@ -388,7 +852,7 @@ impl VNodeOperations for Inode { } fn rename( - &self, + &mut self, nm: &str, target_dir: *mut super::vfs::VNode, target_name: &str, @@ -399,7 +863,7 @@ impl VNodeOperations for Inode { } fn mkdir( - &self, + &mut self, nm: &str, va: super::vfs::VAttr, c: super::vfs::UserCred, @@ -408,12 +872,12 @@ impl VNodeOperations for Inode { todo!() } - fn readdir(&self, uiop: *const super::vfs::UIO, c: super::vfs::UserCred, vp: *const VNode) { + fn readdir(&mut self, uiop: *const super::vfs::UIO, c: super::vfs::UserCred, vp: *const VNode) { todo!() } fn symlink( - &self, + &mut self, link_name: &str, va: super::vfs::VAttr, target_name: &str, @@ -423,27 +887,32 @@ impl VNodeOperations for Inode { todo!() } - fn readlink(&self, uiop: *const super::vfs::UIO, c: super::vfs::UserCred, vp: *const VNode) { + fn readlink( + &mut self, + uiop: *const super::vfs::UIO, + c: super::vfs::UserCred, + vp: *const VNode, + ) { todo!() } - fn fsync(&self, c: super::vfs::UserCred, vp: *const VNode) { + fn fsync(&mut self, c: super::vfs::UserCred, vp: *const VNode) { todo!() } - fn inactive(&self, c: super::vfs::UserCred, vp: *const VNode) { + fn inactive(&mut self, c: super::vfs::UserCred, vp: *const VNode) { todo!() } - fn bmap(&self, block_number: u32, bnp: (), vp: *const VNode) -> super::vfs::VNode { + fn bmap(&mut self, block_number: u32, bnp: (), vp: *const VNode) -> super::vfs::VNode { todo!() } - fn strategy(&self, bp: (), vp: *const VNode) { + fn strategy(&mut self, bp: (), vp: *const VNode) { todo!() } - fn bread(&self, block_number: u32, vp: *const VNode) -> Arc<[u8]> { + fn bread(&mut self, block_number: u32, vp: *const VNode) -> Arc<[u8]> { todo!() } } @@ -469,6 +938,7 @@ macro_rules! inode_enum_try_into { inode_enum_try_into!(BasicFileInode, BasicFile); inode_enum_try_into!(BasicDirectoryInode, BasicDirectory); +inode_enum_try_into!(ExtendedDirectoryInode, ExtendedDirectory); // TODO: can we remove the dependence on squahsfs?? #[repr(C)] @@ -599,6 +1069,43 @@ impl BasicDirectoryInode { // } } +#[repr(C)] +#[derive(Clone, Copy, Debug)] +struct ExtendedDirectoryInode { + header: InodeHeader, + link_count: u32, // 8 + file_size: u32, // 10 + block_index: u32, // 4 + parent_inode: u32, // 16 + index_count: u16, + block_offset: u16, // 12 + xattr_index: u32, +} + +impl ExtendedDirectoryInode { + fn from_bytes(bytes: &[u8]) -> Self { + let header = InodeHeader::from_bytes(bytes); + let link_count = u32::from_le_bytes(bytes[16..20].try_into().unwrap()); + let file_size = u32::from_le_bytes(bytes[20..24].try_into().unwrap()); + let block_index = u32::from_le_bytes(bytes[24..28].try_into().unwrap()); + let parent_inode = u32::from_le_bytes(bytes[28..32].try_into().unwrap()); + let index_count = u16::from_le_bytes(bytes[32..34].try_into().unwrap()); + let block_offset = u16::from_le_bytes(bytes[34..36].try_into().unwrap()); + let xattr_index = u32::from_le_bytes(bytes[36..40].try_into().unwrap()); + + return Self { + header, + link_count, + file_size, + block_index, + parent_inode, + index_count, + block_offset, + xattr_index, + }; + } +} + #[repr(C)] #[derive(Clone, Copy, Debug)] struct BasicFileInode { @@ -607,7 +1114,7 @@ struct BasicFileInode { frag_idx: u32, // 8 block_offset: u32, // 12 file_size: u32, // 16 - block_sizes: *const u32, + // block_sizes: *const u32, } impl BasicFileInode { @@ -617,7 +1124,7 @@ impl BasicFileInode { let frag_idx = u32::from_le_bytes(bytes[20..24].try_into().unwrap()); let block_offset = u32::from_le_bytes(bytes[24..28].try_into().unwrap()); let file_size = u32::from_le_bytes(bytes[28..32].try_into().unwrap()); - let block_sizes = bytes[32..].as_ptr() as *const u32; + // let block_sizes = bytes[32..].as_ptr() as *const u32; return Self { header, @@ -625,7 +1132,7 @@ impl BasicFileInode { frag_idx, block_offset, file_size, - block_sizes, + // block_sizes, }; } } @@ -733,12 +1240,12 @@ struct DirectoryTableHeader { inode_num: u32, } -impl DirectoryTableHeader { - fn from_bytes(bytes: &[u8]) -> Self { +impl From<&[u8]> for DirectoryTableHeader { + fn from(value: &[u8]) -> Self { // count is off by 1 entry - let entry_count = u32::from_le_bytes(bytes[0..4].try_into().unwrap()) + 1; - let start = u32::from_le_bytes(bytes[4..8].try_into().unwrap()); - let inode_num = u32::from_le_bytes(bytes[8..12].try_into().unwrap()); + let entry_count = u32::from_le_bytes(value[0..4].try_into().unwrap()) + 1; + let start = u32::from_le_bytes(value[4..8].try_into().unwrap()); + let inode_num = u32::from_le_bytes(value[8..12].try_into().unwrap()); return Self { entry_count, @@ -750,22 +1257,23 @@ impl DirectoryTableHeader { #[repr(C)] #[derive(Debug)] -struct DirectoryTableEntry<'a> { +struct DirectoryTableEntry { offset: u16, inode_offset: i16, inode_type: InodeFileType, name_size: u16, - name: &'a str, // the file name length is name_size + 1 bytes + name: String, // the file name length is name_size + 1 bytes } -impl<'a> DirectoryTableEntry<'a> { - fn from_bytes(bytes: &'a [u8]) -> Self { +impl DirectoryTableEntry { + fn from_bytes(bytes: &[u8]) -> Self { let offset = u16::from_le_bytes(bytes[0..2].try_into().unwrap()); let inode_offset = i16::from_le_bytes(bytes[2..4].try_into().unwrap()); let inode_type = u16::from_le_bytes(bytes[4..6].try_into().unwrap()).into(); let name_size = u16::from_le_bytes(bytes[6..8].try_into().unwrap()); - let name = core::str::from_utf8(&bytes[8..((name_size as usize) + 1) + 8]) - .expect("Failed to make DirectoryHeader name"); + let name = String::from_utf8(bytes[8..((name_size as usize) + 1) + 8].to_vec()).unwrap(); + // let name = core::str::from_utf8(&bytes[8..((name_size as usize) + 1) + 8]) + // .expect("Failed to make DirectoryHeader name"); return Self { offset, @@ -876,7 +1384,7 @@ impl From for SquashfsCompressionType { #[repr(C, packed)] #[derive(Clone, Copy, Debug)] -struct SquashfsSuperblock { +pub struct SquashfsSuperblock { magic: u32, // 0x73717368 inode_count: u32, // 0x02 mod_time: u32, // varies @@ -888,9 +1396,7 @@ struct SquashfsSuperblock { id_count: u16, // 0x01 ver_major: u16, // 0x04 ver_minor: u16, // 0x00 - root_inode_offset: u16, // - root_inode_block: u32, // - _reserved: u16, // 0x20 + root_inode: u64, // bytes_used: u64, // 0x0103 id_table: u64, // 0x00FB xattr_table: u64, // 0xFFFFFFFFFFFFFFFF @@ -914,9 +1420,7 @@ impl SquashfsSuperblock { id_count: u16::from_le_bytes(bytes[26..28].try_into().unwrap()), ver_major: u16::from_le_bytes(bytes[28..30].try_into().unwrap()), ver_minor: u16::from_le_bytes(bytes[30..32].try_into().unwrap()), - root_inode_offset: u16::from_le_bytes(bytes[32..34].try_into().unwrap()), - root_inode_block: u32::from_le_bytes(bytes[34..38].try_into().unwrap()), - _reserved: u16::from_le_bytes(bytes[38..40].try_into().unwrap()), + root_inode: u64::from_le_bytes(bytes[32..40].try_into().unwrap()), bytes_used: u64::from_le_bytes(bytes[40..48].try_into().unwrap()), id_table: u64::from_le_bytes(bytes[48..56].try_into().unwrap()), xattr_table: u64::from_le_bytes(bytes[56..64].try_into().unwrap()), diff --git a/src/drivers/fs/vfs.rs b/src/drivers/fs/vfs.rs index e109c0b..9dec810 100755 --- a/src/drivers/fs/vfs.rs +++ b/src/drivers/fs/vfs.rs @@ -110,15 +110,15 @@ impl Vfs { pub trait FsOps { // yes, the vfsp was the best solution I could come up with - fn mount(&self, path: &str, data: &mut *mut u8, vfsp: *const Vfs); - fn unmount(&self, vfsp: *const Vfs); - fn root(&self, vfsp: *const Vfs) -> VNode; - fn statfs(&self, vfsp: *const Vfs) -> StatFs; - fn sync(&self, vfsp: *const Vfs); - fn fid(&self, path: &str, vfsp: *const Vfs) -> Option; + fn mount(&mut self, path: &str, data: &mut *mut u8, vfsp: *const Vfs); + fn unmount(&mut self, vfsp: *const Vfs); + fn root(&mut self, vfsp: *const Vfs) -> VNode; + fn statfs(&mut self, vfsp: *const Vfs) -> StatFs; + fn sync(&mut self, vfsp: *const Vfs); + fn fid(&mut self, path: &str, vfsp: *const Vfs) -> Option; // idk how the fuck you're supposed to accomplish this // good luck I guess. - fn vget(&self, fid: FileId, vfsp: *const Vfs) -> VNode; + fn vget(&mut self, fid: FileId, vfsp: *const Vfs) -> VNode; } pub struct FileId { @@ -208,17 +208,24 @@ pub struct UIO { } pub trait VNodeOperations { - fn open(&self, f: u32, c: UserCred, vp: *const VNode) -> Result, ()>; - fn close(&self, f: u32, c: UserCred, vp: *const VNode); - fn rdwr(&self, uiop: *const UIO, direction: IODirection, f: u32, c: UserCred, vp: *const VNode); - fn ioctl(&self, com: u32, d: *mut u8, f: u32, c: UserCred, vp: *const VNode); - fn select(&self, w: IODirection, c: UserCred, vp: *const VNode); - fn getattr(&self, c: UserCred, vp: *const VNode) -> VAttr; - fn setattr(&self, va: VAttr, c: UserCred, vp: *const VNode); - fn access(&self, m: u32, c: UserCred, vp: *const VNode); - fn lookup(&self, nm: &str, c: UserCred, vp: *const VNode) -> Result; + fn open(&mut self, f: u32, c: UserCred, vp: *const VNode) -> Result, ()>; + fn close(&mut self, f: u32, c: UserCred, vp: *const VNode); + fn rdwr( + &mut self, + uiop: *const UIO, + direction: IODirection, + f: u32, + c: UserCred, + vp: *const VNode, + ); + fn ioctl(&mut self, com: u32, d: *mut u8, f: u32, c: UserCred, vp: *const VNode); + fn select(&mut self, w: IODirection, c: UserCred, vp: *const VNode); + fn getattr(&mut self, c: UserCred, vp: *const VNode) -> VAttr; + fn setattr(&mut self, va: VAttr, c: UserCred, vp: *const VNode); + fn access(&mut self, m: u32, c: UserCred, vp: *const VNode); + fn lookup(&mut self, nm: &str, c: UserCred, vp: *const VNode) -> Result; fn create( - &self, + &mut self, nm: &str, va: VAttr, e: u32, @@ -226,24 +233,31 @@ pub trait VNodeOperations { c: UserCred, vp: *const VNode, ) -> Result; - fn link(&self, target_dir: *mut VNode, target_name: &str, c: UserCred, vp: *const VNode); + fn link(&mut self, target_dir: *mut VNode, target_name: &str, c: UserCred, vp: *const VNode); fn rename( - &self, + &mut self, nm: &str, target_dir: *mut VNode, target_name: &str, c: UserCred, vp: *const VNode, ); - fn mkdir(&self, nm: &str, va: VAttr, c: UserCred, vp: *const VNode) -> Result; - fn readdir(&self, uiop: *const UIO, c: UserCred, vp: *const VNode); - fn symlink(&self, link_name: &str, va: VAttr, target_name: &str, c: UserCred, vp: *const VNode); - fn readlink(&self, uiop: *const UIO, c: UserCred, vp: *const VNode); - fn fsync(&self, c: UserCred, vp: *const VNode); - fn inactive(&self, c: UserCred, vp: *const VNode); - fn bmap(&self, block_number: u32, bnp: (), vp: *const VNode) -> VNode; - fn strategy(&self, bp: (), vp: *const VNode); - fn bread(&self, block_number: u32, vp: *const VNode) -> Arc<[u8]>; + fn mkdir(&mut self, nm: &str, va: VAttr, c: UserCred, vp: *const VNode) -> Result; + fn readdir(&mut self, uiop: *const UIO, c: UserCred, vp: *const VNode); + fn symlink( + &mut self, + link_name: &str, + va: VAttr, + target_name: &str, + c: UserCred, + vp: *const VNode, + ); + fn readlink(&mut self, uiop: *const UIO, c: UserCred, vp: *const VNode); + fn fsync(&mut self, c: UserCred, vp: *const VNode); + fn inactive(&mut self, c: UserCred, vp: *const VNode); + fn bmap(&mut self, block_number: u32, bnp: (), vp: *const VNode) -> VNode; + fn strategy(&mut self, bp: (), vp: *const VNode); + fn bread(&mut self, block_number: u32, vp: *const VNode) -> Arc<[u8]>; } pub struct VAttr { @@ -267,7 +281,9 @@ pub struct VAttr { pub fn add_vfs(mount_point: &str, fs_ops: Box) -> Result<(), ()> { let layout = alloc::alloc::Layout::new::(); - let vfs = unsafe { alloc(layout).cast::() }; + // TODO: investigate why on earth this gives me an allocation error + // let vfs = unsafe { alloc(layout).cast::() }; + let vfs = PHYSICAL_MEMORY_MANAGER.alloc(1).unwrap().cast::(); let vfs = unsafe { &mut *vfs }; @@ -286,7 +302,7 @@ pub fn add_vfs(mount_point: &str, fs_ops: Box) -> Result<(), ()> { (*vfs) .ops - .as_ref() + .as_mut() .unwrap() .mount(mount_point, &mut vfs.data, vfsp); } @@ -302,8 +318,8 @@ pub fn add_vfs(mount_point: &str, fs_ops: Box) -> Result<(), ()> { let target_vfs = unsafe { ROOT_VFS.next.unwrap() }; - let binding = unsafe { &(*target_vfs).ops }; - let mut cur_vnode = binding.as_ref().unwrap().root(target_vfs); + let binding = unsafe { &mut (*target_vfs).ops }; + let mut cur_vnode = binding.as_mut().unwrap().root(target_vfs); let parts = mount_point.split('/').collect::>(); @@ -329,7 +345,7 @@ pub fn add_vfs(mount_point: &str, fs_ops: Box) -> Result<(), ()> { (*vfs) .ops - .as_ref() + .as_mut() .unwrap() .mount(mount_point, &mut vfs.data, vfsp); } @@ -342,8 +358,8 @@ pub fn add_vfs(mount_point: &str, fs_ops: Box) -> Result<(), ()> { pub fn vfs_open(path: &str) -> Result { let parts = path.split('/').collect::>(); let target_vfs = unsafe { ROOT_VFS.next.unwrap() }; - let binding = unsafe { &(*target_vfs).ops }; - let mut cur_vnode = binding.as_ref().unwrap().root(target_vfs); + let binding = unsafe { &mut (*target_vfs).ops }; + let mut cur_vnode = binding.as_mut().unwrap().root(target_vfs); for part in parts { if part.is_empty() { diff --git a/src/libs/cell/mod.rs b/src/libs/cell/mod.rs index 3b531b5..278d931 100644 --- a/src/libs/cell/mod.rs +++ b/src/libs/cell/mod.rs @@ -21,6 +21,10 @@ impl Cell { return unsafe { &*self.value.get() }; } + pub fn get_mut(&self) -> &mut T { + return unsafe { &mut *self.value.get() }; + } + pub fn set(&self, new_value: T) { unsafe { *self.value.get() = new_value }; } diff --git a/src/libs/math.rs b/src/libs/math.rs new file mode 100644 index 0000000..717e494 --- /dev/null +++ b/src/libs/math.rs @@ -0,0 +1,89 @@ +pub fn abs(x: f64) -> f64 { + return f64::from_bits(x.to_bits() & (u64::MAX / 2)); +} + +const TOINT: f64 = 1. / f64::EPSILON; + +pub fn floor(x: f64) -> f64 { + #[cfg(all( + any(target_arch = "x86", target_arch = "x86_64"), + not(target_feature = "sse2") + ))] + { + if abs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated > x { + return truncated - 1.0; + } else { + return truncated; + } + } else { + return x; + } + } + + let ui = x.to_bits(); + let e = ((ui >> 52) & 0x7FF) as i32; + + if (e >= 0x3FF + 52) || (x == 0.) { + return x; + } + + let y = if (ui >> 63) != 0 { + x - TOINT + TOINT - x + } else { + x + TOINT + TOINT - x + }; + + if e < 0x3FF { + return if (ui >> 63) != 0 { -1. } else { 0. }; + } + + if y > 0. { + return x + y - 1.; + } else { + return x + y; + } +} + +pub fn ceil(x: f64) -> f64 { + #[cfg(all( + any(target_arch = "x86", target_arch = "x86_64"), + not(target_feature = "sse2") + ))] + { + if abs(x).to_bits() < 4503599627370496.0_f64.to_bits() { + let truncated = x as i64 as f64; + if truncated < x { + return truncated + 1.0; + } else { + return truncated; + } + } else { + return x; + } + } + + let u: u64 = x.to_bits(); + let e: i64 = (u >> 52 & 0x7ff) as i64; + + if e >= 0x3ff + 52 || x == 0. { + return x; + } + + let y = if (u >> 63) != 0 { + x - TOINT + TOINT - x + } else { + x + TOINT - TOINT - x + }; + + if e < 0x3ff { + return if (u >> 63) != 0 { -0. } else { 1. }; + } + + if y < 0. { + return x + y + 1.; + } else { + return x + y; + } +} diff --git a/src/libs/mod.rs b/src/libs/mod.rs index 8e1965f..8a99071 100644 --- a/src/libs/mod.rs +++ b/src/libs/mod.rs @@ -1,3 +1,4 @@ pub mod cell; +pub mod math; pub mod sync; pub mod uuid; diff --git a/src/main.rs b/src/main.rs index 123f1b1..e7eb8a6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,10 +9,12 @@ use core::ffi::CStr; use alloc::{format, vec::Vec}; -use drivers::serial::{read_serial, write_serial}; use limine::KernelFileRequest; -use crate::drivers::fs::vfs::{vfs_open, UserCred}; +use crate::drivers::fs::{ + initramfs, + vfs::{vfs_open, UserCred}, +}; extern crate alloc; @@ -30,24 +32,38 @@ pub extern "C" fn _start() -> ! { drivers::serial::init_serial(); + // let squashfs = initramfs::init(); + + // crate::println!("{:?}", squashfs.superblock); + + let _ = drivers::fs::vfs::add_vfs("/", alloc::boxed::Box::new(initramfs::init())); + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] drivers::pci::enumerate_pci_bus(); - drivers::storage::ide::init(); + let mut file = vfs_open("/firstdir/seconddirbutlonger/yeah.txt").unwrap(); - let nested_file = vfs_open("/boot/limine/limine.cfg").unwrap(); + // drivers::storage::ide::init(); + // let nested_file = vfs_open("/boot/limine/limine.cfg").unwrap(); + + // crate::println!( + // "{:X?}", + // nested_file + // .ops + // .open(0, UserCred { uid: 0, gid: 0 }, nested_file.as_ptr()) + // ); + + // let file = vfs_open("/example.txt").unwrap(); crate::println!( "{:X?}", - nested_file - .ops - .open(0, UserCred { uid: 0, gid: 0 }, nested_file.as_ptr()) - ); - - let file = vfs_open("/example.txt").unwrap(); - crate::println!( - "{:X?}", - file.ops.open(0, UserCred { uid: 0, gid: 0 }, file.as_ptr()) + core::str::from_utf8( + &file + .ops + .open(0, UserCred { uid: 0, gid: 0 }, file.as_ptr()) + .unwrap() + ) + .unwrap() ); let fb = drivers::video::get_framebuffer().unwrap(); @@ -72,23 +88,23 @@ pub extern "C" fn _start() -> ! { fb.blit_screen(buffer, None); - loop { - let ch = read_serial(); + // loop { + // let ch = read_serial(); - if ch == b'\x00' { - continue; - } + // if ch == b'\x00' { + // continue; + // } - if ch == b'\x08' { - write_serial(b'\x08'); - write_serial(b' '); - write_serial(b'\x08'); - } + // if ch == b'\x08' { + // write_serial(b'\x08'); + // write_serial(b' '); + // write_serial(b'\x08'); + // } - if ch > 0x20 && ch < 0x7F { - write_serial(ch); - } - } + // if ch > 0x20 && ch < 0x7F { + // write_serial(ch); + // } + // } hcf(); }