From 6dd58e3b653d568f6ab69172adb26703e09134d9 Mon Sep 17 00:00:00 2001 From: Janis Date: Tue, 11 Apr 2023 02:55:44 +0200 Subject: [PATCH] ACTUAL proper handling of ranges, comments/documentatoin --- btrfs/src/v2/volume.rs | 67 +++++++++++++++++++++++----------- btrfs/tests/read_superblock.rs | 8 +++- 2 files changed, 51 insertions(+), 24 deletions(-) diff --git a/btrfs/src/v2/volume.rs b/btrfs/src/v2/volume.rs index 6196fc7..6c1724c 100644 --- a/btrfs/src/v2/volume.rs +++ b/btrfs/src/v2/volume.rs @@ -8,8 +8,8 @@ use scroll::Pread; use crate::crc32c::calculate_crc32c; use crate::path::Path; use crate::structs::{ - Chunk, DirItemEntry, DirItemType, ExtentData, INodeItem, INodeRefEntry, Item, Key, KeyPtr, - KnownObjectId, ObjectType, RootItem, Stripe, Superblock, TreeItem, + Chunk, CompressionType, DirItemEntry, DirItemType, ExtentData, INodeItem, INodeRefEntry, Item, + Key, KeyPtr, KnownObjectId, ObjectType, RootItem, Stripe, Superblock, TreeItem, }; use crate::{Error, Result}; @@ -569,27 +569,50 @@ impl Fs { log::info!("extents: {}", extents.len()); log::info!("{:?}", extents); for (offset, extent) in extents.into_iter().filter(|(offset, extent)| { + // bounds of the current extent let extent_start = *offset; let extent_end = extent_start + extent.len(); + let extent_len = extent.len(); - // length of the entire range to be read + // entire range we want to read from the file let range_len = end.map(|end| end - start); - // bounds and length of the intersection of the current extent and - // the entire range to be read - let start2 = start.min(extent_start); - let end = end.map(|end| end.max(extent_end)).unwrap_or(extent.len()); - let len = end - start2; + // start of the UNION (from lowest bound to highest bound) of the + // current extent and the entire range + let start = start.min(extent_start); + // end of the UNION of the current extent and the entire range + let end = end.map(|end| end.max(extent_end)); + // width of the union o fthe current extent and the entire range + let len = end.map(|end| (end - start)); - // check if current extent intersects the range we want to read - if let Some(range_len) = range_len { - range_len + range_len < len + if let (Some(len), Some(range_len)) = (len, range_len) { + // proceed if the widths of the 2 ranges (the range we want to + // read, and the current extent) are greater than the width of + // the union range: + // + // In the first example, the 2 ranges overlap, and the width of + // the union is smaller than the sum of the widths of the ranges: + // + // |------range-1------| + // |---range-2----| + // |-----width-of-union-----| + // |-------sum----|-of---widths-------| + // |------------width-of-union------------| + // |------range-1------| + // |---range-2----| + // + // In this second example, the ranges do not overlap, and the + // width of the unions is equal or greater than the sum of the + // widths. + len < extent_len + range_len } else { - start2 < extent_end + start < extent_end } }) { + // let start = start.saturating_sub(offset); - let end = end.map(|end| end - offset).unwrap_or(extent.len()); + + let end = end.map(|end| end - offset).unwrap_or(start + extent.len()); let len = end - start; log::info!("reading {}..{:?} from extent.", start, end); @@ -607,9 +630,10 @@ impl Fs { let range = address ..(address + match extent.extent_data1().compression() { - crate::structs::CompressionType::Zlib - | crate::structs::CompressionType::Lzo - | crate::structs::CompressionType::ZStd => extent.size(), // compressed size + // compressed size + CompressionType::Zlib + | CompressionType::Lzo + | CompressionType::ZStd => extent.size(), _ => len, }); @@ -622,8 +646,8 @@ impl Fs { log::info!("compression: {:?}", extent.header().compression()); let data = match extent.header().compression() { - crate::structs::CompressionType::None => data, - crate::structs::CompressionType::Zlib => { + CompressionType::None => data, + CompressionType::Zlib => { let mut state = miniz_oxide::inflate::stream::InflateState::new( miniz_oxide::DataFormat::Zlib, ); @@ -638,8 +662,6 @@ impl Fs { miniz_oxide::MZFlush::None, ); - log::info!("inflated: {:?}", result); - match result.status.map_err(|_| Error::DecompressionError)? { miniz_oxide::MZStatus::Ok => {} miniz_oxide::MZStatus::StreamEnd => break, @@ -663,10 +685,10 @@ impl Fs { output_data.into() } - crate::structs::CompressionType::Lzo => { + CompressionType::Lzo => { todo!() } - crate::structs::CompressionType::ZStd => { + CompressionType::ZStd => { todo!() } c => { @@ -675,6 +697,7 @@ impl Fs { } }; + // truncate inflated data if needed contents.extend_from_slice(&data[..len as usize]); } diff --git a/btrfs/tests/read_superblock.rs b/btrfs/tests/read_superblock.rs index ced839b..15f78f7 100644 --- a/btrfs/tests/read_superblock.rs +++ b/btrfs/tests/read_superblock.rs @@ -164,7 +164,9 @@ fn find_file_zlib() -> Result<()> { log::info!("chidlren: {:?}", children); let cmake_list = fs.get_inode_by_path(b"/quibble/LICENCE")?; - let file_contents = fs.read_inode_raw(&cmake_list, ..).expect("file contents"); + let file_contents = fs + .read_inode_raw(&cmake_list, ..100) + .expect("file contents"); //assert_eq!(&file_contents[..11], b"hello world"); log::info!("license file:"); log::info!("{}", String::from_utf8_lossy(&file_contents)); @@ -207,7 +209,9 @@ fn find_file_zstd() -> Result<()> { log::info!("chidlren: {:?}", children); let cmake_list = fs.get_inode_by_path(b"/quibble/LICENCE")?; - let file_contents = fs.read_inode_raw(&cmake_list, ..).expect("file contents"); + let file_contents = fs + .read_inode_raw(&cmake_list, ..100) + .expect("file contents"); assert_eq!( &file_contents[..52], b" GNU LESSER GENERAL PUBLIC LICENSE"