use std::sync::{Mutex, RwLock};
use super::super::data::DataSize;
use super::super::fragment::Fragment;
use super::super::id::Id;
use super::super::squashfs::Squashfs;
use super::node::Nodes;
use super::node::{Node, SquashfsFileReader};
use crate::error::BackhandError;
use crate::kinds::Kind;
use crate::traits::block_reader::{self, BlockReaderVersion, Cache};
use crate::traits::types::Compressor;
use crate::v4::reader::BufReadSeek;
const NO_FRAGMENT: usize = 0xffffffff;
#[cfg(not(feature = "parallel"))]
use crate::traits::block_reader_no_parallel as block_reader_impl;
#[cfg(feature = "parallel")]
use crate::traits::block_reader_parallel as block_reader_impl;
pub type SquashfsRawData<'a, 'b> = block_reader_impl::SquashfsRawData<'a, 'b, V3Blocks>;
pub type SquashfsReadFile<'a, 'b> = block_reader_impl::SquashfsReadFile<'a, 'b, V3Blocks>;
pub struct FilesystemReader<'b> {
pub kind: Kind,
pub block_size: u32,
pub block_log: u16,
pub compressor: Option<Compressor>,
pub mod_time: u32,
pub id_table: Vec<Id>,
pub fragments: Option<Vec<Fragment>>,
pub root: Nodes<SquashfsFileReader>,
pub(crate) reader: Mutex<Box<dyn BufReadSeek + 'b>>,
pub(crate) cache: RwLock<Cache>,
}
impl<'b> FilesystemReader<'b> {
pub fn from_reader<R>(reader: R) -> Result<Self, BackhandError>
where
R: BufReadSeek + 'b,
{
let squashfs = Squashfs::from_reader_with_offset(reader, 0)?;
squashfs.into_filesystem_reader()
}
pub fn from_reader_with_offset<R>(reader: R, offset: u64) -> Result<Self, BackhandError>
where
R: BufReadSeek + 'b,
{
let squashfs = Squashfs::from_reader_with_offset(reader, offset)?;
squashfs.into_filesystem_reader()
}
pub fn from_reader_with_offset_and_kind<R>(
reader: R,
offset: u64,
kind: Kind,
) -> Result<Self, BackhandError>
where
R: BufReadSeek + 'b,
{
let squashfs = Squashfs::from_reader_with_offset_and_kind(reader, offset, kind)?;
squashfs.into_filesystem_reader()
}
pub fn file<'a>(&'a self, file: &'a SquashfsFileReader) -> FilesystemReaderFile<'a, 'b> {
FilesystemReaderFile::new(self, file)
}
pub fn files(&self) -> impl Iterator<Item = &Node<SquashfsFileReader>> {
self.root.nodes.iter()
}
}
pub struct V3Blocks;
impl<'b> BlockReaderVersion<'b> for V3Blocks {
type DataSize = DataSize;
type Fragment = Fragment;
type File = SquashfsFileReader;
type System = FilesystemReader<'b>;
fn data_size(data_size: &Self::DataSize) -> u32 {
data_size.size()
}
fn data_uncompressed(data_size: &Self::DataSize) -> bool {
data_size.uncompressed()
}
fn fragment_start(fragment: &Self::Fragment) -> u64 {
fragment.start
}
fn fragment_size(fragment: &Self::Fragment) -> Self::DataSize {
fragment.size
}
fn file_len(file: &Self::File) -> usize {
file.file_len()
}
fn block_sizes(file: &Self::File) -> &[Self::DataSize] {
file.block_sizes()
}
fn blocks_start(file: &Self::File) -> u64 {
file.blocks_start()
}
fn block_offset(file: &Self::File) -> u32 {
file.block_offset()
}
fn kind(system: &Self::System) -> &Kind {
&system.kind
}
fn block_size(system: &Self::System) -> u32 {
system.block_size
}
fn compressor(system: &Self::System) -> Option<Compressor> {
system.compressor
}
fn reader(system: &Self::System) -> &Mutex<Box<dyn BufReadSeek + 'b>> {
&system.reader
}
fn cache(system: &Self::System) -> &RwLock<Cache> {
&system.cache
}
fn fragment_of<'a>(
system: &'a Self::System,
file: &'a Self::File,
) -> Result<Option<&'a Self::Fragment>, BackhandError> {
if file.frag_index() == NO_FRAGMENT {
return Ok(None);
}
match system.fragments.as_ref() {
None => Ok(None),
Some(fragments) => fragments
.get(file.frag_index())
.map(Some)
.ok_or(BackhandError::CorruptedOrInvalidSquashfs),
}
}
}
pub type FilesystemReaderFile<'a, 'b> = block_reader::FilesystemReaderFile<'a, 'b, V3Blocks>;
impl<'a, 'b> FilesystemReaderFile<'a, 'b> {
pub fn reader(&self) -> SquashfsReadFile<'a, 'b> {
self.raw_data_reader().into_reader()
}
pub fn reader_checked(&self) -> Result<SquashfsReadFile<'a, 'b>, BackhandError> {
Ok(self.raw_data_reader_checked()?.into_reader())
}
pub(crate) fn raw_data_reader(&self) -> SquashfsRawData<'a, 'b> {
SquashfsRawData::new(self.system, self.file)
.unwrap_or_else(|_| SquashfsRawData::new_without_fragment(self.system, self.file))
}
pub(crate) fn raw_data_reader_checked(&self) -> Result<SquashfsRawData<'a, 'b>, BackhandError> {
SquashfsRawData::new(self.system, self.file)
}
}