compression support for zlib

This commit is contained in:
Janis 2023-04-11 01:46:41 +02:00
parent 3aa8ecbd77
commit 8ba04a0b94
5 changed files with 196 additions and 8 deletions

View file

@ -23,6 +23,14 @@ thiserror = { version = "1.0", package = "thiserror-core", default-features = fa
num_enum = {version = "0.5.11", default-features = false}
replace_with = "0.1.7"
miniz_oxide = {version = "0.7.1"}
[dev-dependencies]
env_logger = "*"
test-log = "*"
test-log = "*"
include-blob = "0.1.2"
[build-dependencies]
include-blob = "0.1.2"

View file

@ -360,6 +360,17 @@ impl Parseable for ExtentData {
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, FromPrimitive, IntoPrimitive)]
pub enum CompressionType {
None = 0,
Zlib,
Lzo,
ZStd,
#[num_enum(catch_all)]
Invalid(u8),
}
#[repr(C, packed(1))]
#[derive(Debug, Clone, Copy, FromBytes, AsBytes)]
pub struct ExtentData1 {
@ -372,6 +383,14 @@ pub struct ExtentData1 {
}
impl ExtentData1 {
pub fn decoded_size(&self) -> u64 {
self.decoded_size.get()
}
pub fn compression(&self) -> CompressionType {
self.compression.into()
}
pub fn ty(&self) -> ExtentDataType {
match self.ty {
0 => ExtentDataType::Inline,

View file

@ -21,6 +21,8 @@ pub mod error {
NoDefaultSubvolFsRoot,
#[error("INode could not be found in FsTree")]
INodeNotFound,
#[error("decompression error")]
DecompressionError,
#[error("attempted to access {index}th item out of bounds {range:?}")]
OutOfBounds {
range: core::ops::Range<usize>,

View file

@ -566,6 +566,8 @@ impl<R: super::Read> Fs<R> {
core::ops::Bound::Unbounded => None,
};
log::info!("extents: {}", extents.len());
log::info!("{:?}", extents);
for (offset, extent) in extents.into_iter().filter(|(offset, extent)| {
let extent_start = *offset;
let extent_end = extent_start + extent.len();
@ -602,6 +604,18 @@ impl<R: super::Read> Fs<R> {
}
ExtentData::Other(extent) => {
let address = extent.address() + extent.offset() + start;
log::info!(
"address: {} = {} + {} + {}",
address,
extent.address(),
extent.offset(),
start
);
let address = self
.volume
.inner
.offset_from_logical(address)
.ok_or(Error::BadLogicalAddress)?;
let data = self
.volume
.inner
@ -612,6 +626,63 @@ impl<R: super::Read> Fs<R> {
};
log::info!("reading {} bytes from file", data.len());
log::info!("extent type: {:?}", extent.header().ty());
log::info!("compression: {:?}", extent.header().compression());
log::info!("raw bytes: {:?}", data);
let data = match extent.header().compression() {
crate::structs::CompressionType::None => data,
crate::structs::CompressionType::Zlib => {
let mut state = miniz_oxide::inflate::stream::InflateState::new(
miniz_oxide::DataFormat::Zlib,
);
let mut output_data = vec![0u8; extent.header().decoded_size() as usize];
let mut output = &mut output_data[..];
let mut data = &data[..];
loop {
let result = miniz_oxide::inflate::stream::inflate(
&mut state,
&data,
&mut output,
miniz_oxide::MZFlush::None,
);
log::info!("inflated: {:?}", result);
match result.status.map_err(|_| Error::DecompressionError)? {
miniz_oxide::MZStatus::Ok => {}
miniz_oxide::MZStatus::StreamEnd => break,
_ => {
log::error!("need dict ?!");
return Err(Error::DecompressionError);
}
}
data = &data[result.bytes_consumed..];
output = &mut output[result.bytes_written..];
}
_ = miniz_oxide::inflate::stream::inflate(
&mut state,
&data,
&mut output,
miniz_oxide::MZFlush::Finish,
)
.status
.map_err(|_| Error::DecompressionError)?;
output_data.into()
}
crate::structs::CompressionType::Lzo => {
todo!()
}
crate::structs::CompressionType::ZStd => {
todo!()
}
c => {
log::error!("invalid compression type {:?}", c);
data
}
};
contents.extend_from_slice(&data);
}

View file

@ -5,7 +5,31 @@ use btrfs::v2::volume::*;
use include_blob::include_blob;
fn open_filesystem() -> Result<std::rc::Rc<Volume2<&'static [u8]>>> {
let filesystem_data = include_bytes!("../simple.img").as_slice();
let filesystem_data = include_blob!("simple.img").as_slice();
let volume = Volume::new(filesystem_data)?.into_volume2()?;
Ok(volume)
}
fn open_filesystem_lzo() -> Result<std::rc::Rc<Volume2<&'static [u8]>>> {
let filesystem_data = include_blob!("compressed-lzo.img").as_slice();
let volume = Volume::new(filesystem_data)?.into_volume2()?;
Ok(volume)
}
fn open_filesystem_zlib() -> Result<std::rc::Rc<Volume2<&'static [u8]>>> {
let filesystem_data = include_blob!("compressed-zlib.img").as_slice();
let volume = Volume::new(filesystem_data)?.into_volume2()?;
Ok(volume)
}
fn open_filesystem_zstd() -> Result<std::rc::Rc<Volume2<&'static [u8]>>> {
let filesystem_data = include_blob!("compressed-zstd.img").as_slice();
let volume = Volume::new(filesystem_data)?.into_volume2()?;
@ -14,9 +38,7 @@ fn open_filesystem() -> Result<std::rc::Rc<Volume2<&'static [u8]>>> {
#[test_log::test]
fn asdf() -> Result<()> {
let filesystem_data = include_bytes!("../simple.img").as_slice();
let volume = Volume::new(filesystem_data)?;
//.into_volume2();
let a = open_filesystem()?;
Ok(())
}
@ -121,9 +143,75 @@ fn find_file() -> 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, ..100)
.expect("file contents");
let file_contents = fs.read_inode_raw(&cmake_list, ..).expect("file contents");
assert_eq!(
&file_contents[..52],
b" GNU LESSER GENERAL PUBLIC LICENSE"
);
log::info!("license file:");
log::info!("{}", String::from_utf8_lossy(&file_contents));
Ok(())
}
#[test_log::test]
fn find_file_zlib() -> Result<()> {
let v2 = open_filesystem_zlib()?;
let fs = v2.default_subvolume().expect("default subvol");
let root_dir = fs.get_root_dir();
let children = fs.get_inode_children(&root_dir)?.collect::<Vec<_>>();
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");
//assert_eq!(&file_contents[..11], b"hello world");
log::info!("license file:");
log::info!("{}", String::from_utf8_lossy(&file_contents));
assert_eq!(
&file_contents[..52],
b" GNU LESSER GENERAL PUBLIC LICENSE"
);
Ok(())
}
#[test_log::test]
fn find_file_lzo() -> Result<()> {
let v2 = open_filesystem_lzo()?;
let fs = v2.default_subvolume().expect("default subvol");
let root_dir = fs.get_root_dir();
let children = fs.get_inode_children(&root_dir)?.collect::<Vec<_>>();
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");
assert_eq!(
&file_contents[..52],
b" GNU LESSER GENERAL PUBLIC LICENSE"
);
log::info!("license file:");
log::info!("{}", String::from_utf8_lossy(&file_contents));
Ok(())
}
#[test_log::test]
fn find_file_zstd() -> Result<()> {
let v2 = open_filesystem_zstd()?;
let fs = v2.default_subvolume().expect("default subvol");
let root_dir = fs.get_root_dir();
let children = fs.get_inode_children(&root_dir)?.collect::<Vec<_>>();
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");
assert_eq!(
&file_contents[..52],
b" GNU LESSER GENERAL PUBLIC LICENSE"
);
log::info!("license file:");
log::info!("{}", String::from_utf8_lossy(&file_contents));