1use core::fmt;
2use core::num::NonZeroUsize;
3use no_std_io2::io::Read;
4use std::path::{Path, PathBuf};
5use std::sync::{Arc, Mutex};
6
7use super::super::data::Added;
8use super::super::data::DataSize;
9use super::super::id::Id;
10use super::super::inode::{BasicFile, ExtendedFile, InodeHeader};
11use super::normalize_squashfs_path;
12use super::reader::FilesystemReaderFile;
13use crate::error::BackhandError;
14
15#[derive(Debug, PartialEq, Eq, Default, Clone, Copy)]
17pub struct NodeHeader {
18 pub permissions: u16,
19 pub uid: u32,
21 pub gid: u32,
23 pub mtime: u32,
24}
25
26impl NodeHeader {
27 pub fn new(permissions: u16, uid: u32, gid: u32, mtime: u32) -> Self {
28 Self { permissions, uid, gid, mtime }
29 }
30}
31
32impl NodeHeader {
33 pub fn from_inode(inode_header: InodeHeader, id_table: &[Id]) -> Result<Self, BackhandError> {
34 let uid = if (inode_header.uid as usize) < id_table.len() {
35 id_table[inode_header.uid as usize].num
36 } else {
37 0
39 };
40 let gid = if (inode_header.gid as usize) < id_table.len() {
42 id_table[inode_header.gid as usize].num
43 } else {
44 0
46 };
47 Ok(Self { permissions: inode_header.permissions, uid, gid, mtime: inode_header.mtime })
48 }
49}
50
51#[derive(Clone, Debug)]
53pub struct Node<T> {
54 pub fullpath: PathBuf,
55 pub header: NodeHeader,
56 pub inner: InnerNode<T>,
57}
58
59impl<T> PartialEq for Node<T> {
60 fn eq(&self, other: &Self) -> bool {
61 self.fullpath.eq(&other.fullpath)
62 }
63}
64impl<T> Eq for Node<T> {}
65impl<T> PartialOrd for Node<T> {
66 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
67 Some(self.cmp(other))
68 }
69}
70impl<T> Ord for Node<T> {
71 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
72 self.fullpath.cmp(&other.fullpath)
73 }
74}
75
76impl<T> Node<T> {
77 pub fn new_root(header: NodeHeader) -> Self {
78 let fullpath = PathBuf::from("/");
79 let inner = InnerNode::Dir(SquashfsDir::default());
80 Self { fullpath, header, inner }
81 }
82}
83
84#[derive(Debug, Clone, PartialEq, Eq)]
86pub enum InnerNode<T> {
87 File(T),
89 Symlink(SquashfsSymlink),
90 Dir(SquashfsDir),
91 CharacterDevice(SquashfsCharacterDevice),
92 BlockDevice(SquashfsBlockDevice),
93 NamedPipe,
94 Socket,
95}
96
97#[derive(Debug, PartialEq, Eq, Clone)]
99pub enum SquashfsFileReader {
100 Basic(BasicFile),
101 Extended(ExtendedFile),
102}
103
104impl SquashfsFileReader {
105 pub fn file_len(&self) -> usize {
106 match self {
107 SquashfsFileReader::Basic(basic) => basic.file_size as usize,
108 SquashfsFileReader::Extended(extended) => extended.file_size as usize,
109 }
110 }
111
112 pub fn frag_index(&self) -> usize {
113 match self {
114 SquashfsFileReader::Basic(basic) => basic.frag as usize,
115 SquashfsFileReader::Extended(extended) => extended.frag_index as usize,
116 }
117 }
118
119 pub fn block_sizes(&self) -> &[DataSize] {
120 match self {
121 SquashfsFileReader::Basic(basic) => &basic.block_sizes,
122 SquashfsFileReader::Extended(extended) => &extended.block_sizes,
123 }
124 }
125
126 pub fn blocks_start(&self) -> u64 {
127 match self {
128 SquashfsFileReader::Basic(basic) => basic.blocks_start,
129 SquashfsFileReader::Extended(extended) => extended.blocks_start,
130 }
131 }
132
133 pub fn block_offset(&self) -> u32 {
134 match self {
135 SquashfsFileReader::Basic(basic) => basic.block_offset,
136 SquashfsFileReader::Extended(extended) => extended.block_offset,
137 }
138 }
139}
140
141pub enum SquashfsFileWriter<'a, 'b, 'c> {
143 UserDefined(Arc<Mutex<dyn Read + 'c>>),
144 SquashfsFile(FilesystemReaderFile<'a, 'b>),
145 Consumed(usize, Added),
146}
147
148impl fmt::Debug for SquashfsFileWriter<'_, '_, '_> {
149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
150 f.debug_struct("FileWriter").finish()
151 }
152}
153
154#[derive(Debug, PartialEq, Eq, Clone)]
156pub struct SquashfsSymlink {
157 pub link: PathBuf,
158}
159
160#[derive(Debug, PartialEq, Eq, Clone, Copy, Default)]
162pub struct SquashfsDir {}
163
164#[derive(Debug, PartialEq, Eq, Clone, Copy)]
166pub struct SquashfsCharacterDevice {
167 pub device_number: u32,
168}
169
170#[derive(Debug, PartialEq, Eq, Clone, Copy)]
172pub struct SquashfsBlockDevice {
173 pub device_number: u32,
174}
175
176#[derive(Debug, Clone)]
177pub struct Nodes<T> {
178 pub nodes: Vec<Node<T>>,
179}
180
181impl<T> Nodes<T> {
182 pub fn new_root(header: NodeHeader) -> Self {
183 Self { nodes: vec![Node::new_root(header)] }
184 }
185
186 pub fn root(&self) -> &Node<T> {
187 &self.nodes[0]
188 }
189
190 pub fn root_mut(&mut self) -> &mut Node<T> {
191 &mut self.nodes[0]
192 }
193
194 pub fn node_mut<S: AsRef<Path>>(&mut self, path: S) -> Option<&mut Node<T>> {
195 let find_path = normalize_squashfs_path(path.as_ref()).ok()?;
198 self.nodes
199 .binary_search_by(|node| node.fullpath.cmp(&find_path))
200 .ok()
201 .map(|found| &mut self.nodes[found])
202 }
203
204 pub fn insert(&mut self, node: Node<T>) -> Result<(), BackhandError> {
205 let path = &node.fullpath;
206 let parent = node.fullpath.parent().ok_or(BackhandError::InvalidFilePath)?;
207
208 let parent = self.node_mut(parent).ok_or(BackhandError::InvalidFilePath)?;
210 match &parent.inner {
211 InnerNode::Dir(_) => {}
212 _ => return Err(BackhandError::InvalidFilePath),
213 }
214
215 match self.nodes.binary_search_by(|node| node.fullpath.as_path().cmp(path)) {
216 Ok(_index) => Err(BackhandError::DuplicatedFileName),
218 Err(index) => {
220 self.nodes.insert(index, node);
221 Ok(())
222 }
223 }
224 }
225
226 fn inner_children_of(&self, node_index: usize) -> Option<&[Node<T>]> {
227 let parent = &self.nodes[node_index];
228 let children_start = node_index + 1;
229 let unbounded_children = self.nodes.get(children_start..)?;
230 let children_len = unbounded_children
231 .iter()
232 .enumerate()
233 .find(|(_, node)| !node.fullpath.starts_with(&parent.fullpath))
234 .map(|(index, _)| index)
235 .unwrap_or(unbounded_children.len());
236 Some(&unbounded_children[..children_len])
237 }
238
239 pub fn node(&self, node_index: NonZeroUsize) -> Option<&Node<T>> {
240 self.nodes.get(node_index.get() - 1)
241 }
242
243 pub fn children_of(
244 &self,
245 node_index: NonZeroUsize,
246 ) -> impl Iterator<Item = (NonZeroUsize, &Node<T>)> {
247 self.inner_children_of(node_index.get() - 1).unwrap_or(&[]).iter().enumerate().map(
248 move |(index, node)| (NonZeroUsize::new(node_index.get() + index + 1).unwrap(), node),
249 )
250 }
251}