squashfs_async/inodes/
file.rs

1use async_trait::async_trait;
2use serde::Deserialize;
3use tokio::io::{AsyncRead, AsyncReadExt};
4
5use super::super::data::{self, BlockSize};
6use super::super::deser;
7use super::super::error::InodeTableError;
8use super::super::fragments::FragmentLocation;
9use super::super::superblock::SuperBlock;
10
11/// Trait to encompass `BasicFile` and `ExtendedFile`.
12pub trait FileInode: Send + Sync + std::fmt::Debug {
13    fn file_size(&self) -> u64;
14    fn blocks_start(&self) -> u64;
15    fn add_block_size(&mut self, size: BlockSize);
16    fn block_sizes(&self) -> &Vec<BlockSize>;
17    fn fragment(&self) -> FragmentLocation;
18    fn fragment_size(&self, superblock: &SuperBlock) -> u64 {
19        let fragment = self.fragment();
20        if !fragment.valid() {
21            0
22        } else {
23            self.file_size() % superblock.block_size as u64
24        }
25    }
26    fn data_locations(&self) -> Box<dyn Iterator<Item = data::DataLocation> + '_> {
27        let mut block_start = self.blocks_start();
28        Box::new(self.block_sizes().iter().copied().map(move |block_size| {
29            let l = data::DataLocation {
30                block_start,
31                block_size,
32            };
33            block_start += block_size.compressed_size();
34            l
35        }))
36    }
37}
38#[async_trait]
39pub trait FileInodeDeser: FileInode + serde::de::DeserializeOwned + Sized {
40    fn encoded_size() -> usize;
41    fn n_blocks(&self, superblock: &SuperBlock) -> u32 {
42        let n = self.file_size() as f64 / superblock.block_size as f64;
43        if self.fragment().valid() {
44            n.floor() as u32
45        } else {
46            n.ceil() as u32
47        }
48    }
49
50    async fn from_reader(
51        mut r: impl AsyncRead + std::marker::Unpin + Send + Sync,
52        superblock: &SuperBlock,
53    ) -> Result<Self, InodeTableError> {
54        let mut file: Self = deser::bincode_deser_from(&mut r, Self::encoded_size())
55            .await
56            .map_err(|_| InodeTableError::InvalidEntry)?;
57        for _ in 0..file.n_blocks(superblock) {
58            file.add_block_size(BlockSize(
59                r.read_u32_le()
60                    .await
61                    .map_err(|_| InodeTableError::InvalidEntry)?,
62            ));
63        }
64        Ok(file)
65    }
66}
67
68#[derive(Debug, Default, Deserialize)]
69pub(crate) struct BasicFile {
70    blocks_start: u32,
71    // serde flatten does not work here
72    fragment_index: u32,
73    fragment_offset: u32,
74    file_size: u32,
75    #[serde(skip)]
76    block_sizes: Vec<BlockSize>,
77}
78impl FileInodeDeser for BasicFile {
79    fn encoded_size() -> usize {
80        16
81    }
82}
83
84#[async_trait]
85impl FileInode for BasicFile {
86    fn blocks_start(&self) -> u64 {
87        self.blocks_start as u64
88    }
89    fn add_block_size(&mut self, size: BlockSize) {
90        self.block_sizes.push(size)
91    }
92    fn block_sizes(&self) -> &Vec<BlockSize> {
93        &self.block_sizes
94    }
95    fn file_size(&self) -> u64 {
96        self.file_size as u64
97    }
98    fn fragment(&self) -> FragmentLocation {
99        FragmentLocation {
100            index: self.fragment_index,
101            offset: self.fragment_offset,
102        }
103    }
104}
105
106#[derive(Debug, Default, Deserialize)]
107pub(crate) struct ExtendedFile {
108    blocks_start: u64,
109    file_size: u64,
110    _sparse: u64,
111    _hard_link_count: u32,
112    fragment_index: u32,
113    fragment_offset: u32,
114    _xattr_idx: u32,
115    #[serde(skip)]
116    block_sizes: Vec<BlockSize>,
117}
118impl FileInodeDeser for ExtendedFile {
119    fn encoded_size() -> usize {
120        40
121    }
122}
123#[async_trait]
124impl FileInode for ExtendedFile {
125    fn blocks_start(&self) -> u64 {
126        self.blocks_start
127    }
128    fn add_block_size(&mut self, size: BlockSize) {
129        self.block_sizes.push(size)
130    }
131    fn block_sizes(&self) -> &Vec<BlockSize> {
132        &self.block_sizes
133    }
134    fn file_size(&self) -> u64 {
135        self.file_size
136    }
137    fn fragment(&self) -> FragmentLocation {
138        FragmentLocation {
139            index: self.fragment_index,
140            offset: self.fragment_offset,
141        }
142    }
143}