use crate::BackhandError;
use std::path::PathBuf;
#[derive(Debug, PartialEq, Eq, Default, Clone, Copy)]
pub struct BackhandNodeHeader {
pub permissions: u16,
pub uid: u32,
pub gid: u32,
pub mtime: u32,
}
impl From<crate::v4::filesystem::node::NodeHeader> for BackhandNodeHeader {
fn from(header: crate::v4::filesystem::node::NodeHeader) -> Self {
Self {
permissions: header.permissions,
uid: header.uid,
gid: header.gid,
mtime: header.mtime,
}
}
}
#[cfg(feature = "v3")]
impl From<crate::v3::filesystem::node::NodeHeader> for BackhandNodeHeader {
fn from(header: crate::v3::filesystem::node::NodeHeader) -> Self {
Self {
permissions: header.permissions,
uid: header.uid,
gid: header.gid,
mtime: header.mtime,
}
}
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub struct BackhandDataSize {
pub size: u32,
pub uncompressed: bool,
}
impl From<crate::v4::data::DataSize> for BackhandDataSize {
fn from(ds: crate::v4::data::DataSize) -> Self {
Self { size: ds.size(), uncompressed: ds.uncompressed() }
}
}
#[cfg(feature = "v3")]
impl From<crate::v3::data::DataSize> for BackhandDataSize {
fn from(ds: crate::v3::data::DataSize) -> Self {
Self { size: ds.size(), uncompressed: ds.uncompressed() }
}
}
impl BackhandDataSize {
pub fn to_v4_datasize(self) -> crate::v4::data::DataSize {
crate::v4::data::DataSize::new(self.size, self.uncompressed)
}
#[cfg(feature = "v3")]
pub fn to_v3_datasize(self) -> crate::v3::data::DataSize {
crate::v3::data::DataSize::new(self.size, self.uncompressed)
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum BackhandSquashfsFileReader {
Basic {
blocks_start: u64, frag_index: u32,
block_offset: u32,
file_size: u32,
block_sizes: Vec<BackhandDataSize>,
},
Extended {
blocks_start: u64,
frag_index: u32,
block_offset: u32,
file_size: u64,
sparse: u64,
link_count: u32,
xattr_index: u32,
block_sizes: Vec<BackhandDataSize>,
},
}
impl BackhandSquashfsFileReader {
pub fn file_len(&self) -> usize {
match self {
Self::Basic { file_size, .. } => *file_size as usize,
Self::Extended { file_size, .. } => *file_size as usize,
}
}
pub fn frag_index(&self) -> usize {
match self {
Self::Basic { frag_index, .. } => *frag_index as usize,
Self::Extended { frag_index, .. } => *frag_index as usize,
}
}
pub fn block_sizes(&self) -> &[BackhandDataSize] {
match self {
Self::Basic { block_sizes, .. } => block_sizes,
Self::Extended { block_sizes, .. } => block_sizes,
}
}
pub fn blocks_start(&self) -> u64 {
match self {
Self::Basic { blocks_start, .. } => *blocks_start,
Self::Extended { blocks_start, .. } => *blocks_start,
}
}
pub fn block_offset(&self) -> u32 {
match self {
Self::Basic { block_offset, .. } => *block_offset,
Self::Extended { block_offset, .. } => *block_offset,
}
}
}
impl From<&crate::v4::filesystem::node::SquashfsFileReader> for BackhandSquashfsFileReader {
fn from(v4_file: &crate::v4::filesystem::node::SquashfsFileReader) -> Self {
match v4_file {
crate::v4::filesystem::node::SquashfsFileReader::Basic(basic) => Self::Basic {
blocks_start: basic.blocks_start.into(),
frag_index: basic.frag_index,
block_offset: basic.block_offset,
file_size: basic.file_size,
block_sizes: basic.block_sizes.iter().map(|&ds| ds.into()).collect(),
},
crate::v4::filesystem::node::SquashfsFileReader::Extended(extended) => Self::Extended {
blocks_start: extended.blocks_start,
frag_index: extended.frag_index,
block_offset: extended.block_offset,
file_size: extended.file_size,
sparse: extended.sparse,
link_count: extended.link_count,
xattr_index: extended.xattr_index,
block_sizes: extended.block_sizes.iter().map(|&ds| ds.into()).collect(),
},
}
}
}
#[cfg(feature = "v3")]
impl From<&crate::v3::filesystem::node::SquashfsFileReader> for BackhandSquashfsFileReader {
fn from(v3_file: &crate::v3::filesystem::node::SquashfsFileReader) -> Self {
match v3_file {
crate::v3::filesystem::node::SquashfsFileReader::Basic(basic) => Self::Basic {
blocks_start: basic.blocks_start,
frag_index: basic.frag,
block_offset: basic.block_offset,
file_size: basic.file_size,
block_sizes: basic.block_sizes.iter().map(|&ds| ds.into()).collect(),
},
crate::v3::filesystem::node::SquashfsFileReader::Extended(extended) => Self::Extended {
blocks_start: extended.blocks_start,
frag_index: extended.frag_index,
block_offset: extended.block_offset,
file_size: extended.file_size,
sparse: 0, link_count: extended.link_count,
xattr_index: 0, block_sizes: extended.block_sizes.iter().map(|&ds| ds.into()).collect(),
},
}
}
}
impl From<&crate::v4::filesystem::node::Node<crate::v4::filesystem::node::SquashfsFileReader>>
for BackhandNode
{
fn from(
v4_node: &crate::v4::filesystem::node::Node<
crate::v4::filesystem::node::SquashfsFileReader,
>,
) -> Self {
let inner = match &v4_node.inner {
crate::v4::filesystem::node::InnerNode::File(file) => {
BackhandInnerNode::File(file.into())
}
crate::v4::filesystem::node::InnerNode::Symlink(symlink) => {
BackhandInnerNode::Symlink { link: symlink.link.clone() }
}
crate::v4::filesystem::node::InnerNode::Dir(_) => BackhandInnerNode::Dir,
crate::v4::filesystem::node::InnerNode::CharacterDevice(dev) => {
BackhandInnerNode::CharacterDevice { device_number: dev.device_number }
}
crate::v4::filesystem::node::InnerNode::BlockDevice(dev) => {
BackhandInnerNode::BlockDevice { device_number: dev.device_number }
}
crate::v4::filesystem::node::InnerNode::NamedPipe => BackhandInnerNode::NamedPipe,
crate::v4::filesystem::node::InnerNode::Socket => BackhandInnerNode::Socket,
};
Self { fullpath: v4_node.fullpath.clone(), header: v4_node.header.into(), inner }
}
}
#[cfg(feature = "v3")]
impl From<&crate::v3::filesystem::node::Node<crate::v3::filesystem::node::SquashfsFileReader>>
for BackhandNode
{
fn from(
v3_node: &crate::v3::filesystem::node::Node<
crate::v3::filesystem::node::SquashfsFileReader,
>,
) -> Self {
let inner = match &v3_node.inner {
crate::v3::filesystem::node::InnerNode::File(file) => {
BackhandInnerNode::File(file.into())
}
crate::v3::filesystem::node::InnerNode::Symlink(symlink) => {
BackhandInnerNode::Symlink { link: symlink.link.clone() }
}
crate::v3::filesystem::node::InnerNode::Dir(_) => BackhandInnerNode::Dir,
crate::v3::filesystem::node::InnerNode::CharacterDevice(dev) => {
BackhandInnerNode::CharacterDevice { device_number: dev.device_number }
}
crate::v3::filesystem::node::InnerNode::BlockDevice(dev) => {
BackhandInnerNode::BlockDevice { device_number: dev.device_number }
}
crate::v3::filesystem::node::InnerNode::NamedPipe => BackhandInnerNode::NamedPipe,
crate::v3::filesystem::node::InnerNode::Socket => BackhandInnerNode::Socket,
};
Self { fullpath: v3_node.fullpath.clone(), header: v3_node.header.into(), inner }
}
}
#[derive(Debug, Clone)]
pub struct BackhandNode {
pub fullpath: PathBuf,
pub header: BackhandNodeHeader,
pub inner: BackhandInnerNode,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum BackhandInnerNode {
File(BackhandSquashfsFileReader),
Symlink { link: PathBuf },
Dir,
CharacterDevice { device_number: u32 },
BlockDevice { device_number: u32 },
NamedPipe,
Socket,
}
pub trait FilesystemReaderTrait: Send + Sync {
fn files(&self) -> Box<dyn Iterator<Item = BackhandNode> + '_>;
fn file_data(&self, file: &BackhandSquashfsFileReader) -> Result<Vec<u8>, BackhandError>;
}
impl<'b> FilesystemReaderTrait for crate::v4::filesystem::reader::FilesystemReader<'b> {
fn files(&self) -> Box<dyn Iterator<Item = BackhandNode> + '_> {
Box::new(self.files().map(|node| node.into()))
}
fn file_data(&self, file: &BackhandSquashfsFileReader) -> Result<Vec<u8>, BackhandError> {
let v4_file = match file {
BackhandSquashfsFileReader::Basic {
blocks_start,
frag_index,
block_offset,
file_size,
block_sizes,
} => crate::v4::filesystem::node::SquashfsFileReader::Basic(
crate::v4::inode::BasicFile {
blocks_start: (*blocks_start).try_into().map_err(|e| {
BackhandError::NumericConversion(format!(
"ExtendedDirectory file_size: {}",
e
))
})?,
frag_index: *frag_index,
block_offset: *block_offset,
file_size: *file_size,
block_sizes: block_sizes.iter().map(|&ds| ds.to_v4_datasize()).collect(),
},
),
BackhandSquashfsFileReader::Extended {
blocks_start,
frag_index,
block_offset,
file_size,
sparse,
link_count,
xattr_index,
block_sizes,
} => crate::v4::filesystem::node::SquashfsFileReader::Extended(
crate::v4::inode::ExtendedFile {
blocks_start: *blocks_start,
frag_index: *frag_index,
block_offset: *block_offset,
file_size: *file_size,
sparse: *sparse,
link_count: *link_count,
xattr_index: *xattr_index,
block_sizes: block_sizes.iter().map(|&ds| ds.to_v4_datasize()).collect(),
},
),
};
let file_handle = self.file(&v4_file);
let mut reader = file_handle.reader();
let mut data = Vec::new();
if let Err(_e) = std::io::Read::read_to_end(&mut reader, &mut data) {
return Ok(Vec::new());
}
Ok(data)
}
}
#[cfg(feature = "v3")]
impl<'b> FilesystemReaderTrait for crate::v3::filesystem::reader::FilesystemReader<'b> {
fn files(&self) -> Box<dyn Iterator<Item = BackhandNode> + '_> {
Box::new(self.files().map(|node| node.into()))
}
fn file_data(&self, file: &BackhandSquashfsFileReader) -> Result<Vec<u8>, BackhandError> {
let v3_file = match file {
BackhandSquashfsFileReader::Basic {
blocks_start,
frag_index,
block_offset,
file_size,
block_sizes,
} => crate::v3::filesystem::node::SquashfsFileReader::Basic(
crate::v3::inode::BasicFile {
blocks_start: *blocks_start,
frag: *frag_index,
block_offset: *block_offset,
file_size: *file_size,
block_sizes: block_sizes.iter().map(|&ds| ds.to_v3_datasize()).collect(),
},
),
BackhandSquashfsFileReader::Extended {
blocks_start,
frag_index,
block_offset,
file_size,
link_count,
block_sizes,
..
} => crate::v3::filesystem::node::SquashfsFileReader::Extended(
crate::v3::inode::ExtendedFile {
blocks_start: *blocks_start,
frag_index: *frag_index,
block_offset: *block_offset,
file_size: *file_size,
link_count: *link_count,
block_sizes: block_sizes.iter().map(|&ds| ds.to_v3_datasize()).collect(),
},
),
};
let file_handle = self.file(&v3_file);
let mut reader = file_handle.reader();
let mut data = Vec::new();
if let Err(_e) = std::io::Read::read_to_end(&mut reader, &mut data) {
return Ok(Vec::new());
}
Ok(data)
}
}