squashfs_async/inodes/
file.rs1use 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
11pub 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 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}