diff --git a/kernel/driver/fs/ext2/src/inode/mod.rs b/kernel/driver/fs/ext2/src/inode/mod.rs index 62ffbf8e..e00bd9f1 100644 --- a/kernel/driver/fs/ext2/src/inode/mod.rs +++ b/kernel/driver/fs/ext2/src/inode/mod.rs @@ -229,6 +229,7 @@ impl Inode { self.size_upper = (size >> 32) as u32; self.size_lower = size as u32; } else { + // Unreachable: size is checked in resize() if size > u32::MAX as u64 { todo!("File too large") } @@ -242,8 +243,10 @@ impl Inode { if size == self.size(fs) { return Ok(false); } - - // TODO check max inode size + if size > fs.max_file_size { + // TODO FileTooBig or something + return Err(Error::InvalidArgument); + } let is_symlink = self .mode @@ -256,11 +259,12 @@ impl Inode { } else { size.div_ceil(fs.block_size as u64) }; - // TODO check size_upper as well? - let old_blocks = if is_symlink && self.size_lower < 60 { + + let old_size = self.size(fs); + let old_blocks = if is_symlink && old_size < 60 { 0 } else { - self.size(fs).div_ceil(fs.block_size as u64) + old_size.div_ceil(fs.block_size as u64) }; if new_blocks as usize @@ -268,7 +272,7 @@ impl Inode { + fs.pointers_per_block + fs.pointers_per_block * fs.pointers_per_block { - log::warn!("ext2: only L0/L1 are supported"); + log::warn!("ext2: only L0/L1/L2 are supported"); return Err(Error::InvalidArgument); } diff --git a/kernel/driver/fs/ext2/src/lib.rs b/kernel/driver/fs/ext2/src/lib.rs index ff76cebd..d7b2e239 100644 --- a/kernel/driver/fs/ext2/src/lib.rs +++ b/kernel/driver/fs/ext2/src/lib.rs @@ -9,7 +9,7 @@ use core::mem; use alloc::{boxed::Box, sync::Arc}; use async_trait::async_trait; use bytemuck::Zeroable; -use data::{FsReadonlyFeatures, FsRequiredFeatures}; +use data::{FsReadonlyFeatures, FsRequiredFeatures, DIRECT_BLOCK_COUNT}; use dir::DirectoryNode; use file::RegularNode; use inode::{InodeAccess, InodeCache}; @@ -56,6 +56,8 @@ pub struct Ext2Fs { inodes_per_block: usize, pointers_per_block: usize, + max_file_size: u64, + required_features: FsRequiredFeatures, write_features: FsReadonlyFeatures, @@ -259,17 +261,32 @@ impl Ext2Fs { } }; + let pointers_per_block = block_size / size_of::(); + let max_inode_blocks = (DIRECT_BLOCK_COUNT + + pointers_per_block + + pointers_per_block * pointers_per_block + + pointers_per_block * pointers_per_block * pointers_per_block) + as u64; + let max_file_size = max_inode_blocks.saturating_mul(block_size as u64); + let max_file_size = if write_features.contains(FsReadonlyFeatures::FILE_SIZE_64_BIT) { + max_file_size + } else { + max_file_size.min(u32::MAX as u64) + }; + Ok(Self { block_size, inode_size: superblock.inode_size(), inodes_per_block: block_size / superblock.inode_size(), - pointers_per_block: block_size / size_of::(), + pointers_per_block, total_inodes, total_blocks, block_group_inode_count, block_group_block_count, + max_file_size, + mapper, inode_cache: OneTimeInit::new(), @@ -393,26 +410,6 @@ impl Ext2Fs { self.inode_cache.get().flush().await } - // pub async fn flush_superblock(&self) -> Result<(), Error> { - // let state = self.state.read(); - // if state.dirty { - // log::info!("Flushing superblock"); - // log::info!( - // "inodes {} blocks {}", - // state.superblock.total_unallocated_inodes, - // state.superblock.total_unallocated_blocks - // ); - // self.mapper - // .device() - // .write_exact( - // data::SUPERBLOCK_OFFSET, - // bytemuck::bytes_of(&state.superblock), - // ) - // .await?; - // } - // Ok(()) - // } - async fn read_index(&self, block_index: u32, index: usize) -> Result { self.with_block(block_index, |block| { let indirect: &[u32] = unsafe {