ext2: properly handle max file size

This commit is contained in:
Mark Poliakov 2025-01-02 21:48:00 +02:00
parent d8f035dc69
commit a126118589
2 changed files with 29 additions and 28 deletions

View File

@ -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);
}

View File

@ -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::<u32>();
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::<u32>(),
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<u32, Error> {
self.with_block(block_index, |block| {
let indirect: &[u32] = unsafe {