squashfs_async/
fragments.rs

1//! Fragments and fragments table.
2use serde::Deserialize;
3use tokio::io::{AsyncReadExt, AsyncSeekExt};
4
5use super::data;
6use super::deser;
7use super::error::FragmentsError;
8use super::metadata;
9use super::superblock::SuperBlock;
10
11/// Location in the [`FragmentsTable`]
12#[derive(Debug, Default, Copy, Clone, Deserialize)]
13pub struct FragmentLocation {
14    pub index: u32,
15    pub offset: u32,
16}
17impl FragmentLocation {
18    pub fn valid(&self) -> bool {
19        self.index != 0xFFFFFFFF
20    }
21}
22
23/// Fragments table entry
24#[derive(Debug, Deserialize)]
25pub struct Entry {
26    pub start: u64,
27    pub size: data::BlockSize,
28    _unused: u32,
29}
30/// Fragments table (a simple list of [`Entry`])
31#[derive(Default, Debug)]
32pub struct FragmentsTable {
33    pub entries: Vec<Entry>,
34}
35impl std::fmt::Display for FragmentsTable {
36    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
37        write!(f, "Fragment table with {} entries", self.entries.len())
38    }
39}
40
41impl FragmentsTable {
42    /// Get an entry from its location
43    pub fn entry(&self, location: FragmentLocation) -> Result<&Entry, FragmentsError> {
44        if !location.valid() {
45            return Err(FragmentsError::InvalidLocation);
46        }
47
48        self.entries
49            .get(location.index as usize)
50            .ok_or(FragmentsError::InvalidLocation)
51    }
52    /// Read fragments table
53    pub async fn from_reader(
54        superblock: &SuperBlock,
55        mut r: impl crate::AsyncSeekBufRead,
56    ) -> Result<Self, FragmentsError> {
57        r.seek(std::io::SeekFrom::Start(superblock.fragment_table_start))
58            .await
59            .map_err(FragmentsError::ReadFailure)?;
60        let n = (superblock.fragment_entry_count as f64 / 512.0).ceil() as usize;
61        let mut locations = Vec::<u64>::with_capacity(n);
62        for _ in 0..n {
63            locations.push(
64                r.read_u64_le()
65                    .await
66                    .map_err(|_| FragmentsError::InvalidLocation)?,
67            )
68        }
69        let mut entries = Vec::<Entry>::with_capacity(superblock.fragment_entry_count as usize);
70        for l in locations {
71            r.seek(std::io::SeekFrom::Start(l))
72                .await
73                .map_err(FragmentsError::ReadFailure)?;
74            let block =
75                metadata::MetadataBlock::from_reader(&mut r, superblock.compression).await?;
76            entries.extend(
77                block
78                    .data
79                    .chunks(16)
80                    .map(deser::bincode_deser)
81                    .collect::<Result<Vec<Entry>, _>>()
82                    .map_err(|_| FragmentsError::InvalidEntry)?,
83            );
84        }
85        Ok(Self { entries })
86    }
87}