compression support for zlib
This commit is contained in:
parent
3aa8ecbd77
commit
8ba04a0b94
|
@ -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 = "*"
|
||||
|
||||
include-blob = "0.1.2"
|
||||
|
||||
[build-dependencies]
|
||||
include-blob = "0.1.2"
|
|
@ -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,
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
Loading…
Reference in a new issue