1use crate::Pfs;
2use crate::image::Image;
3use crate::inode::Inode;
4use std::cmp::min;
5use std::io::{self, Error, Read, Seek, SeekFrom};
6use std::sync::Arc;
7
8#[must_use]
33pub struct File<'a> {
34 pfs: Arc<Pfs<'a>>,
35 inode: usize,
36}
37
38impl<'a> std::fmt::Debug for File<'a> {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 f.debug_struct("File")
41 .field("inode", &self.inode)
42 .field("len", &self.len())
43 .field("mode", &self.mode())
44 .finish_non_exhaustive()
45 }
46}
47
48impl<'a> File<'a> {
49 pub(crate) fn new(pfs: Arc<Pfs<'a>>, inode: usize) -> Self {
50 Self { pfs, inode }
51 }
52
53 #[must_use]
54 pub fn mode(&self) -> u16 {
55 self.inode_ref().mode()
56 }
57
58 #[must_use]
59 pub fn flags(&self) -> u32 {
60 self.inode_ref().flags().value()
61 }
62
63 #[must_use]
64 pub fn len(&self) -> u64 {
65 self.inode_ref().size()
66 }
67
68 #[must_use]
69 pub fn compressed_len(&self) -> u64 {
70 self.inode_ref().compressed_len()
71 }
72
73 #[must_use]
75 pub fn atime(&self) -> u64 {
76 self.inode_ref().atime()
77 }
78
79 #[must_use]
81 pub fn mtime(&self) -> u64 {
82 self.inode_ref().mtime()
83 }
84
85 #[must_use]
87 pub fn ctime(&self) -> u64 {
88 self.inode_ref().ctime()
89 }
90
91 #[must_use]
93 pub fn birthtime(&self) -> u64 {
94 self.inode_ref().birthtime()
95 }
96
97 #[must_use]
99 pub fn mtimensec(&self) -> u32 {
100 self.inode_ref().mtimensec()
101 }
102
103 #[must_use]
105 pub fn atimensec(&self) -> u32 {
106 self.inode_ref().atimensec()
107 }
108
109 #[must_use]
111 pub fn ctimensec(&self) -> u32 {
112 self.inode_ref().ctimensec()
113 }
114
115 #[must_use]
117 pub fn birthnsec(&self) -> u32 {
118 self.inode_ref().birthnsec()
119 }
120
121 #[must_use]
122 pub fn uid(&self) -> u32 {
123 self.inode_ref().uid()
124 }
125
126 #[must_use]
127 pub fn gid(&self) -> u32 {
128 self.inode_ref().gid()
129 }
130
131 #[must_use]
132 pub fn is_compressed(&self) -> bool {
133 self.inode_ref().flags().is_compressed()
134 }
135
136 #[must_use]
137 pub fn is_empty(&self) -> bool {
138 self.len() == 0
139 }
140
141 #[must_use]
151 pub fn as_slice(&self) -> Option<&'a [u8]> {
152 let data = self.pfs.data?;
153
154 if self.is_compressed() {
155 return None;
156 }
157
158 let inode = self.inode_ref();
159
160 if inode.size() == 0 {
161 return Some(&[]);
162 }
163
164 let (start_block, _) = inode.contiguous_blocks()?;
165 let block_size = self.pfs.block_size as u64;
166
167 let start = (start_block as u64) * block_size;
168 let end = start + inode.size();
169
170 data.get(start as usize..end as usize)
171 }
172
173 pub fn read_at(&self, offset: u64, buf: &mut [u8]) -> std::io::Result<usize> {
179 pfs_read_at(&self.pfs, self.inode, offset, buf)
180 }
181
182 #[must_use]
209 pub fn reader(&self) -> FileReader<'a> {
210 FileReader {
211 file: self.clone(),
212 pos: 0,
213 }
214 }
215
216 pub fn into_image(self) -> PfsFileImage<'a> {
220 PfsFileImage {
221 pfs: self.pfs,
222 inode: self.inode,
223 }
224 }
225
226 fn inode_ref(&self) -> &Inode {
227 self.pfs.inode(self.inode)
228 }
229}
230
231impl<'a> Clone for File<'a> {
232 fn clone(&self) -> Self {
233 Self {
234 pfs: self.pfs.clone(),
235 inode: self.inode,
236 }
237 }
238}
239
240pub struct FileReader<'a> {
244 file: File<'a>,
245 pos: u64,
246}
247
248impl<'a> std::fmt::Debug for FileReader<'a> {
249 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
250 f.debug_struct("FileReader")
251 .field("file", &self.file)
252 .field("pos", &self.pos)
253 .finish()
254 }
255}
256
257impl Read for FileReader<'_> {
258 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
259 let n = self.file.read_at(self.pos, buf)?;
260 self.pos += n as u64;
261 Ok(n)
262 }
263}
264
265impl Seek for FileReader<'_> {
266 fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
267 let file_len = self.file.len();
268
269 let new_pos = match pos {
270 SeekFrom::Start(offset) => offset as i64,
271 SeekFrom::End(offset) => file_len as i64 + offset,
272 SeekFrom::Current(offset) => self.pos as i64 + offset,
273 };
274
275 if new_pos < 0 {
276 return Err(io::Error::new(
277 io::ErrorKind::InvalidInput,
278 "seek to a negative position",
279 ));
280 }
281
282 self.pos = new_pos as u64;
283 Ok(self.pos)
284 }
285}
286
287#[derive(Clone)]
296pub struct PfsFileImage<'a> {
297 pfs: Arc<Pfs<'a>>,
298 inode: usize,
299}
300
301impl<'a> std::fmt::Debug for PfsFileImage<'a> {
302 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
303 f.debug_struct("PfsFileImage")
304 .field("inode", &self.inode)
305 .field("len", &self.len())
306 .finish_non_exhaustive()
307 }
308}
309
310impl Image for PfsFileImage<'_> {
311 fn read_at(&self, offset: u64, output_buf: &mut [u8]) -> std::io::Result<usize> {
312 pfs_read_at(&self.pfs, self.inode, offset, output_buf)
313 }
314
315 fn len(&self) -> u64 {
316 self.pfs.inode(self.inode).size()
317 }
318}
319
320fn pfs_read_at(pfs: &Pfs<'_>, inode: usize, offset: u64, buf: &mut [u8]) -> io::Result<usize> {
321 let file_size = pfs.inode(inode).size();
322
323 if buf.is_empty() || offset >= file_size {
324 return Ok(0);
325 }
326
327 let block_map = pfs.block_map(inode);
328 let block_size = pfs.block_size as u64;
329 let image = pfs.image();
330 let mut copied = 0usize;
331 let mut pos = offset;
332
333 loop {
334 let block_index = pos / block_size;
335 let offset_in_block = pos % block_size;
336
337 let block_num = match block_map.get(block_index as usize) {
338 Some(&v) => v,
339 None => {
340 return Err(Error::other(format!(
341 "block #{} is not available",
342 block_index
343 )));
344 }
345 };
346
347 let block_end = (block_index + 1) * block_size;
348 let remaining_in_block = (min(block_end, file_size) - pos) as usize;
349 let to_read = min(remaining_in_block, buf.len() - copied);
350
351 let phys_offset = (block_num as u64) * block_size + offset_in_block;
352
353 image.read_exact_at(phys_offset, &mut buf[copied..copied + to_read])?;
354
355 copied += to_read;
356 pos += to_read as u64;
357
358 if copied == buf.len() || pos >= file_size {
359 break Ok(copied);
360 }
361 }
362}