diff --git a/src/ext2.rs b/src/ext2.rs index 15f1caa..84e48e2 100644 --- a/src/ext2.rs +++ b/src/ext2.rs @@ -24,6 +24,7 @@ pub struct Ext2 { descriptor_table: BlockGroupDescriptorTable, inode_cache: RwLock>, dentry_cache: RwLock>, + ind_block_cache: RwLock>>, } impl Ext2 { @@ -35,6 +36,7 @@ impl Ext2 { reader, inode_cache: RwLock::new(HashMap::new()), dentry_cache: RwLock::new(HashMap::new()), + ind_block_cache: RwLock::new(HashMap::new()), }) } diff --git a/src/ext2/block_reader.rs b/src/ext2/block_reader.rs index 18c29da..c6948cb 100644 --- a/src/ext2/block_reader.rs +++ b/src/ext2/block_reader.rs @@ -36,13 +36,12 @@ impl BlockReader { } pub fn read_blocks(&self, block: u32, count: usize) -> io::Result>> { - let mut vec = vec![0; self.block_size * count]; - for block_no in block..(block + count as u32) { - let data = self.read_block(block)?.into_inner(); - vec[((block_no - block) as usize * self.block_size) - ..(((block_no - block) as usize + 1) * self.block_size)] - .copy_from_slice(&data); - } + let mut disk = &self.disk; + let start = self.block_to_byte_offset(block); + let size = self.block_size * count; + let mut vec = vec![0; size]; + disk.seek(SeekFrom::Start(start))?; + disk.read_exact(&mut vec)?; Ok(Cursor::new(vec)) } diff --git a/src/ext2/file.rs b/src/ext2/file.rs index c1cc15e..608f1e5 100644 --- a/src/ext2/file.rs +++ b/src/ext2/file.rs @@ -47,10 +47,8 @@ impl File { } pub fn read_at(&self, buf: &mut [u8], pos: u64, fs: &Ext2) -> io::Result { - //println!("File::read_at(File {{pos: {}, inode: {}, ...}}, &mut [?; {}], {})", self.pos, self.inode.number, buf.len(), pos); let bytes_to_end = u64::from(self.inode.size_lower32).saturating_sub(pos); if bytes_to_end == 0 { - //println!("File::read_at done, reporting 0 bytes read"); return Ok(0); } let start_block = (pos / self.block_size as u64) as u32; @@ -60,25 +58,39 @@ impl File { .reader .read_block_offset( self.inode - .log_to_phys_block(&fs.reader, start_block) + .log_to_phys_block(&fs, start_block) .ok_or_else(|| io::Error::new(io::ErrorKind::UnexpectedEof, "EOF reached"))?, offset as u32, )? .read(buf)?; let mut remaining_bytes = length.saturating_sub((self.block_size - offset) as u64); - for block in (start_block + 1)..=u32::MAX { - if remaining_bytes == 0 { - break; - }; - let _ = - fs.reader - .read_block(self.inode.log_to_phys_block(&fs.reader, block).ok_or_else( - || io::Error::new(io::ErrorKind::UnexpectedEof, "EOF reached"), - )?)? - .read(&mut buf[((length - remaining_bytes) as usize)..])?; - remaining_bytes = remaining_bytes.saturating_sub(self.block_size as u64); + let mut block = start_block + 1; + while remaining_bytes != 0 { + let mut chunk_start_block = self + .inode + .log_to_phys_block(&fs, block) + .ok_or_else(|| io::Error::new(io::ErrorKind::UnexpectedEof, "EOF reached"))?; + let mut chunk_num_blocks = 1; + block += 1; + loop { + if (chunk_num_blocks as usize * self.block_size) as u64 >= remaining_bytes { + break; + } + let Some(phys_block) = self.inode.log_to_phys_block(&fs, block) else { + break; + }; + if phys_block != chunk_start_block + chunk_num_blocks { + break; + } + chunk_num_blocks += 1; + block += 1; + } + let _ = fs + .reader + .read_blocks(chunk_start_block, chunk_num_blocks as usize)? + .read(&mut buf[((length - remaining_bytes) as usize)..])?; + remaining_bytes = remaining_bytes.saturating_sub((self.block_size * chunk_num_blocks as usize) as u64); } - //println!("File::read_at done, reporting {} bytes read", length - remaining_bytes); Ok((length - remaining_bytes) as usize) } } diff --git a/src/ext2/structs.rs b/src/ext2/structs.rs index 3961dd8..9305e8a 100644 --- a/src/ext2/structs.rs +++ b/src/ext2/structs.rs @@ -156,19 +156,24 @@ impl Inode { Ok(ino) } - pub fn pointer_block_blocks(&self, block: u32, reader: &BlockReader) -> io::Result> { - Ok(reader - .read_block(block)? + pub fn pointer_block_blocks(&self, block_no: u32, fs: &Ext2) -> io::Result> { + if let Some(block) = fs.ind_block_cache.read().get(&block_no) { + return Ok(block.clone()); + } + let block = fs.reader + .read_block(block_no)? .into_inner() .iter() .copied() .tuples::<(_, _, _, _)>() .map(|raw| u32::from_le_bytes([raw.0, raw.1, raw.2, raw.3])) - .collect_vec()) + .collect_vec(); + fs.ind_block_cache.write().insert(block_no, block.clone()); + Ok(block) } - pub fn log_to_phys_block(&self, reader: &BlockReader, block: u32) -> Option { - let num_sing_indir = reader.block_size / 4; + pub fn log_to_phys_block(&self, fs: &Ext2, block: u32) -> Option { + let num_sing_indir = fs.reader.block_size / 4; let num_doub_indir = num_sing_indir * num_sing_indir; let num_trip_indir = num_sing_indir * num_doub_indir; if block < 12 { @@ -179,7 +184,7 @@ impl Inode { } } else if block < (12 + num_sing_indir) as u32 { let blocks = self - .pointer_block_blocks(self.singly_indirect_block_pointer, reader) + .pointer_block_blocks(self.singly_indirect_block_pointer, fs) .ok()?; let block = blocks[(block - 12) as usize]; if block == 0 { @@ -192,10 +197,10 @@ impl Inode { let doub_indir_offset = (block as usize - base_block) / num_sing_indir; let sing_indir_offset = (block as usize - base_block) % num_sing_indir; let sing_indir_blocks = self - .pointer_block_blocks(self.doubly_indirect_block_pointer, reader) + .pointer_block_blocks(self.doubly_indirect_block_pointer, fs) .ok()?; let blocks = self - .pointer_block_blocks(sing_indir_blocks[doub_indir_offset], reader) + .pointer_block_blocks(sing_indir_blocks[doub_indir_offset], fs) .ok()?; let block = blocks[sing_indir_offset]; if block == 0 { @@ -211,13 +216,13 @@ impl Inode { let sing_indir_offset = ((block as usize - base_block) % num_doub_indir) % num_sing_indir; let doub_indir_blocks = self - .pointer_block_blocks(self.triply_indirect_block_pointer, reader) + .pointer_block_blocks(self.triply_indirect_block_pointer, fs) .ok()?; let sing_indir_blocks = self - .pointer_block_blocks(doub_indir_blocks[trip_indir_offset], reader) + .pointer_block_blocks(doub_indir_blocks[trip_indir_offset], fs) .ok()?; let blocks = self - .pointer_block_blocks(sing_indir_blocks[doub_indir_offset], reader) + .pointer_block_blocks(sing_indir_blocks[doub_indir_offset], fs) .ok()?; let block = blocks[sing_indir_offset]; if block == 0 {