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