1use futures::future::BoxFuture;
6use shared_buffer::OwnedBuffer;
7use tokio::io::AsyncRead;
8use tokio::io::{AsyncSeek, AsyncWrite};
9
10use self::offloaded_file::OffloadWrite;
11
12use super::*;
13use crate::limiter::TrackedVec;
14use crate::{CopyOnWriteFile, FsError, Result, VirtualFile};
15use std::cmp;
16use std::convert::TryInto;
17use std::fmt;
18use std::io;
19use std::pin::Pin;
20use std::task::{Context, Poll};
21
22pub(super) struct FileHandle {
30 inode: Inode,
31 filesystem: FileSystem,
32 readable: bool,
33 writable: bool,
34 append_mode: bool,
35 cursor: u64,
36 arc_file: Option<Result<Box<dyn VirtualFile + Send + Sync + 'static>>>,
37}
38
39impl Clone for FileHandle {
40 fn clone(&self) -> Self {
41 Self {
42 inode: self.inode,
43 filesystem: self.filesystem.clone(),
44 readable: self.readable,
45 writable: self.writable,
46 append_mode: self.append_mode,
47 cursor: self.cursor,
48 arc_file: None,
49 }
50 }
51}
52
53impl FileHandle {
54 pub(super) fn new(
55 inode: Inode,
56 filesystem: FileSystem,
57 readable: bool,
58 writable: bool,
59 append_mode: bool,
60 cursor: u64,
61 ) -> Self {
62 Self {
63 inode,
64 filesystem,
65 readable,
66 writable,
67 append_mode,
68 cursor,
69 arc_file: None,
70 }
71 }
72
73 fn lazy_load_arc_file_mut(&mut self) -> Result<&mut dyn VirtualFile> {
74 if self.arc_file.is_none() {
75 let fs = match self.filesystem.inner.read() {
76 Ok(fs) => fs,
77 _ => return Err(FsError::EntryNotFound),
78 };
79
80 let inode = fs.storage.get(self.inode);
81 match inode {
82 Some(Node::ArcFile(node)) => {
83 self.arc_file.replace(
84 node.fs
85 .new_open_options()
86 .read(self.readable)
87 .write(self.writable)
88 .append(self.append_mode)
89 .open(node.path.as_path()),
90 );
91 }
92 _ => return Err(FsError::EntryNotFound),
93 }
94 }
95 Ok(self
96 .arc_file
97 .as_mut()
98 .unwrap()
99 .as_mut()
100 .map_err(|err| *err)?
101 .as_mut())
102 }
103
104 fn write_cursor(&self, file_size: u64) -> u64 {
105 if self.append_mode {
106 file_size
107 } else {
108 self.cursor
109 }
110 }
111}
112
113impl VirtualFile for FileHandle {
114 fn last_accessed(&self) -> u64 {
115 let fs = match self.filesystem.inner.read() {
116 Ok(fs) => fs,
117 _ => return 0,
118 };
119
120 let inode = fs.storage.get(self.inode);
121 match inode {
122 Some(node) => node.metadata().accessed,
123 _ => 0,
124 }
125 }
126
127 fn last_modified(&self) -> u64 {
128 let fs = match self.filesystem.inner.read() {
129 Ok(fs) => fs,
130 _ => return 0,
131 };
132
133 let inode = fs.storage.get(self.inode);
134 match inode {
135 Some(node) => node.metadata().modified,
136 _ => 0,
137 }
138 }
139
140 fn created_time(&self) -> u64 {
141 let fs = match self.filesystem.inner.read() {
142 Ok(fs) => fs,
143 _ => return 0,
144 };
145
146 let inode = fs.storage.get(self.inode);
147 let node = match inode {
148 Some(node) => node,
149 _ => return 0,
150 };
151
152 node.metadata().created
153 }
154
155 fn set_times(&mut self, atime: Option<u64>, mtime: Option<u64>) -> crate::Result<()> {
156 let mut fs = match self.filesystem.inner.write() {
157 Ok(fs) => fs,
158 _ => return Err(crate::FsError::Lock),
159 };
160
161 let inode = fs.storage.get_mut(self.inode);
162 if let Some(node) = inode {
163 if let Some(atime) = atime {
164 node.metadata_mut().accessed = atime;
165 }
166 if let Some(mtime) = mtime {
167 node.metadata_mut().modified = mtime;
168 }
169
170 return Ok(());
171 }
172
173 Err(crate::FsError::UnknownError)
174 }
175
176 fn size(&self) -> u64 {
177 let fs = match self.filesystem.inner.read() {
178 Ok(fs) => fs,
179 _ => return 0,
180 };
181
182 let inode = fs.storage.get(self.inode);
183 match inode {
184 Some(Node::File(node)) => node.file.len().try_into().unwrap_or(0),
185 Some(Node::OffloadedFile(node)) => node.file.len(),
186 Some(Node::ReadOnlyFile(node)) => node.file.len().try_into().unwrap_or(0),
187 Some(Node::CustomFile(node)) => {
188 let file = node.file.lock().unwrap();
189 file.size()
190 }
191 Some(Node::ArcFile(node)) => match self.arc_file.as_ref() {
192 Some(file) => file.as_ref().map(|file| file.size()).unwrap_or(0),
193 None => node
194 .fs
195 .new_open_options()
196 .read(self.readable)
197 .write(self.writable)
198 .append(self.append_mode)
199 .open(node.path.as_path())
200 .map(|file| file.size())
201 .unwrap_or(0),
202 },
203 _ => 0,
204 }
205 }
206
207 fn set_len(&mut self, new_size: u64) -> Result<()> {
208 let mut fs = self.filesystem.inner.write().map_err(|_| FsError::Lock)?;
209
210 let inode = fs.storage.get_mut(self.inode);
211 match inode {
212 Some(Node::File(FileNode { file, metadata, .. })) => {
213 file.buffer
214 .resize(new_size.try_into().map_err(|_| FsError::UnknownError)?, 0)?;
215 metadata.len = new_size;
216 }
217 Some(Node::OffloadedFile(OffloadedFileNode { file, metadata, .. })) => {
218 file.resize(new_size, 0);
219 metadata.len = new_size;
220 }
221 Some(Node::CustomFile(node)) => {
222 let mut file = node.file.lock().unwrap();
223 file.set_len(new_size)?;
224 node.metadata.len = new_size;
225 }
226 Some(Node::ReadOnlyFile { .. }) => return Err(FsError::PermissionDenied),
227 Some(Node::ArcFile { .. }) => {
228 drop(fs);
229 let file = self.lazy_load_arc_file_mut()?;
230 file.set_len(new_size)?;
231 }
232 _ => return Err(FsError::NotAFile),
233 }
234
235 self.cursor = self.cursor.min(new_size);
237 Ok(())
238 }
239
240 fn unlink(&mut self) -> Result<()> {
241 let filesystem = self.filesystem.clone();
242 let inode = self.inode;
243
244 let (inode_of_parent, position, inode_of_file) = {
245 let fs = filesystem.inner.read().map_err(|_| FsError::Lock)?;
247
248 let inode_of_file = inode;
250
251 let (position, inode_of_parent) = fs
254 .storage
255 .iter()
256 .find_map(|(inode_of_parent, node)| match node {
257 Node::Directory(DirectoryNode { children, .. }) => {
258 children.iter().enumerate().find_map(|(nth, inode)| {
259 if inode == &inode_of_file {
260 Some((nth, inode_of_parent))
261 } else {
262 None
263 }
264 })
265 }
266
267 _ => None,
268 })
269 .ok_or(FsError::BaseNotDirectory)?;
270
271 (inode_of_parent, position, inode_of_file)
272 };
273
274 {
275 let mut fs = filesystem.inner.write().map_err(|_| FsError::Lock)?;
277
278 fs.storage.remove(inode_of_file);
280
281 fs.remove_child_from_node(inode_of_parent, position)?;
283 }
284
285 Ok(())
286 }
287
288 fn get_special_fd(&self) -> Option<u32> {
289 let fs = match self.filesystem.inner.read() {
290 Ok(a) => a,
291 Err(_) => {
292 return None;
293 }
294 };
295
296 let inode = fs.storage.get(self.inode);
297 match inode {
298 Some(Node::CustomFile(node)) => {
299 let file = node.file.lock().unwrap();
300 file.get_special_fd()
301 }
302 Some(Node::ArcFile(node)) => match self.arc_file.as_ref() {
303 Some(file) => file
304 .as_ref()
305 .map(|file| file.get_special_fd())
306 .unwrap_or(None),
307 None => node
308 .fs
309 .new_open_options()
310 .read(self.readable)
311 .write(self.writable)
312 .append(self.append_mode)
313 .open(node.path.as_path())
314 .map(|file| file.get_special_fd())
315 .unwrap_or(None),
316 },
317 _ => None,
318 }
319 }
320
321 fn copy_reference(
322 &mut self,
323 src: Box<dyn VirtualFile + Send + Sync + 'static>,
324 ) -> BoxFuture<'_, std::io::Result<()>> {
325 let inner = self.filesystem.inner.clone();
326 Box::pin(async move {
327 let mut fs = inner.write().unwrap();
328 let inode = fs.storage.get_mut(self.inode);
329 match inode {
330 Some(inode) => {
331 let metadata = Metadata {
332 ft: crate::FileType {
333 file: true,
334 ..Default::default()
335 },
336 accessed: src.last_accessed(),
337 created: src.created_time(),
338 modified: src.last_modified(),
339 len: src.size(),
340 };
341
342 *inode = Node::CustomFile(CustomFileNode {
343 inode: inode.inode(),
344 name: inode.name().to_string_lossy().to_string().into(),
345 file: Mutex::new(Box::new(CopyOnWriteFile::new(src))),
346 metadata,
347 });
348 Ok(())
349 }
350 None => Err(std::io::ErrorKind::InvalidInput.into()),
351 }
352 })
353 }
354
355 fn copy_from_owned_buffer(&mut self, src: &OwnedBuffer) -> BoxFuture<'_, std::io::Result<()>> {
356 let inner = self.filesystem.inner.clone();
357 let src = src.clone();
358 Box::pin(async move {
359 let mut fs = inner.write().unwrap();
360 let inode = fs.storage.get_mut(self.inode);
361 match inode {
362 Some(inode) => {
363 let metadata = Metadata {
364 ft: crate::FileType {
365 file: true,
366 ..Default::default()
367 },
368 accessed: 1,
369 created: 1,
370 modified: 1,
371 len: src.len() as u64,
372 };
373
374 *inode = Node::ReadOnlyFile(ReadOnlyFileNode {
375 inode: inode.inode(),
376 name: inode.name().to_string_lossy().to_string().into(),
377 file: ReadOnlyFile { buffer: src },
378 metadata,
379 });
380 Ok(())
381 }
382 None => Err(std::io::ErrorKind::InvalidInput.into()),
383 }
384 })
385 }
386
387 fn poll_read_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
388 if !self.readable {
389 return Poll::Ready(Err(io::Error::new(
390 io::ErrorKind::PermissionDenied,
391 format!(
392 "the file (inode `{}) doesn't have the `read` permission",
393 self.inode
394 ),
395 )));
396 }
397
398 let mut fs = self
399 .filesystem
400 .inner
401 .write()
402 .map_err(|_| io::Error::other("failed to acquire a write lock"))?;
403
404 let inode = fs.storage.get_mut(self.inode);
405 match inode {
406 Some(Node::File(node)) => {
407 let remaining = node.file.buffer.len() - (self.cursor as usize);
408 Poll::Ready(Ok(remaining))
409 }
410 Some(Node::OffloadedFile(node)) => {
411 let remaining = node.file.len() as usize - (self.cursor as usize);
412 Poll::Ready(Ok(remaining))
413 }
414 Some(Node::ReadOnlyFile(node)) => {
415 let remaining = node.file.buffer.len() - (self.cursor as usize);
416 Poll::Ready(Ok(remaining))
417 }
418 Some(Node::CustomFile(node)) => {
419 let mut file = node.file.lock().unwrap();
420 let file = Pin::new(file.as_mut());
421 file.poll_read_ready(cx)
422 }
423 Some(Node::ArcFile(_)) => {
424 drop(fs);
425 match self.lazy_load_arc_file_mut() {
426 Ok(file) => {
427 let file = Pin::new(file);
428 file.poll_read_ready(cx)
429 }
430 Err(_) => Poll::Ready(Err(io::Error::new(
431 io::ErrorKind::NotFound,
432 format!("inode `{}` doesn't match a file", self.inode),
433 ))),
434 }
435 }
436 _ => Poll::Ready(Err(io::Error::new(
437 io::ErrorKind::NotFound,
438 format!("inode `{}` doesn't match a file", self.inode),
439 ))),
440 }
441 }
442
443 fn poll_write_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<usize>> {
444 if !self.readable {
445 return Poll::Ready(Err(io::Error::new(
446 io::ErrorKind::PermissionDenied,
447 format!(
448 "the file (inode `{}) doesn't have the `read` permission",
449 self.inode
450 ),
451 )));
452 }
453
454 let mut fs = self
455 .filesystem
456 .inner
457 .write()
458 .map_err(|_| io::Error::other("failed to acquire a write lock"))?;
459
460 let inode = fs.storage.get_mut(self.inode);
461 match inode {
462 Some(Node::File(_)) => Poll::Ready(Ok(8192)),
463 Some(Node::OffloadedFile(_)) => Poll::Ready(Ok(8192)),
464 Some(Node::ReadOnlyFile(_)) => Poll::Ready(Ok(0)),
465 Some(Node::CustomFile(node)) => {
466 let mut file = node.file.lock().unwrap();
467 let file = Pin::new(file.as_mut());
468 file.poll_read_ready(cx)
469 }
470 Some(Node::ArcFile(_)) => {
471 drop(fs);
472 match self.lazy_load_arc_file_mut() {
473 Ok(file) => {
474 let file = Pin::new(file);
475 file.poll_read_ready(cx)
476 }
477 Err(_) => Poll::Ready(Err(io::Error::new(
478 io::ErrorKind::NotFound,
479 format!("inode `{}` doesn't match a file", self.inode),
480 ))),
481 }
482 }
483 _ => Poll::Ready(Err(io::Error::new(
484 io::ErrorKind::NotFound,
485 format!("inode `{}` doesn't match a file", self.inode),
486 ))),
487 }
488 }
489
490 fn write_from_mmap(&mut self, offset: u64, size: u64) -> std::io::Result<()> {
491 if !self.writable {
492 return Err(io::Error::new(
493 io::ErrorKind::PermissionDenied,
494 format!(
495 "the file (inode `{}) doesn't have the `write` permission",
496 self.inode
497 ),
498 ));
499 }
500
501 let mut cursor = self.cursor;
502 {
503 let mut fs = self
504 .filesystem
505 .inner
506 .write()
507 .map_err(|_| io::Error::other("failed to acquire a write lock"))?;
508
509 let inode = fs.storage.get_mut(self.inode);
510 match inode {
511 Some(Node::OffloadedFile(node)) => {
512 node.file
513 .write(OffloadWrite::MmapOffset { offset, size }, &mut cursor)?;
514 node.metadata.len = node.file.len();
515 }
516 _ => {
517 return Err(io::ErrorKind::Unsupported.into());
518 }
519 }
520 }
521 self.cursor = cursor;
522 Ok(())
523 }
524
525 fn as_owned_buffer(&self) -> Option<OwnedBuffer> {
526 let fs = self.filesystem.inner.read().ok()?;
527
528 let inode = fs.storage.get(self.inode)?;
529 match inode {
530 Node::ReadOnlyFile(f) => Some(f.file.buffer.clone()),
531 Node::CustomFile(f) => f.file.lock().ok()?.as_owned_buffer(),
532 _ => None,
533 }
534 }
535}
536
537#[cfg(test)]
538mod test_virtual_file {
539 use crate::{FileSystem as FS, mem_fs::*};
540 use std::thread::sleep;
541 use std::time::Duration;
542
543 macro_rules! path {
544 ($path:expr) => {
545 std::path::Path::new($path)
546 };
547 }
548
549 #[tokio::test]
550 async fn test_last_accessed() {
551 let fs = FileSystem::default();
552
553 let file = fs
554 .new_open_options()
555 .write(true)
556 .create_new(true)
557 .open(path!("/foo.txt"))
558 .expect("failed to create a new file");
559 let last_accessed_time = file.last_accessed();
560
561 assert!(last_accessed_time > 0, "last accessed time is not zero");
562
563 sleep(Duration::from_secs(3));
564
565 let file = fs
566 .new_open_options()
567 .read(true)
568 .open(path!("/foo.txt"))
569 .expect("failed to open a file");
570 let next_last_accessed_time = file.last_accessed();
571
572 assert!(
573 next_last_accessed_time > last_accessed_time,
574 "the last accessed time is updated"
575 );
576 }
577
578 #[tokio::test]
579 async fn test_last_modified() {
580 let fs = FileSystem::default();
581
582 let file = fs
583 .new_open_options()
584 .write(true)
585 .create_new(true)
586 .open(path!("/foo.txt"))
587 .expect("failed to create a new file");
588
589 assert!(file.last_modified() > 0, "last modified time is not zero");
590 }
591
592 #[tokio::test]
593 async fn test_created_time() {
594 let fs = FileSystem::default();
595
596 let file = fs
597 .new_open_options()
598 .write(true)
599 .create_new(true)
600 .open(path!("/foo.txt"))
601 .expect("failed to create a new file");
602 let created_time = file.created_time();
603
604 assert!(created_time > 0, "created time is not zero");
605
606 let file = fs
607 .new_open_options()
608 .read(true)
609 .open(path!("/foo.txt"))
610 .expect("failed to create a new file");
611 let next_created_time = file.created_time();
612
613 assert_eq!(
614 next_created_time, created_time,
615 "created time stays constant"
616 );
617 }
618
619 #[tokio::test]
620 async fn test_size() {
621 let fs = FileSystem::default();
622
623 let file = fs
624 .new_open_options()
625 .write(true)
626 .create_new(true)
627 .open(path!("/foo.txt"))
628 .expect("failed to create a new file");
629
630 assert_eq!(file.size(), 0, "new file is empty");
631 }
632
633 #[tokio::test]
634 async fn test_set_len() {
635 let fs = FileSystem::default();
636
637 let mut file = fs
638 .new_open_options()
639 .write(true)
640 .create_new(true)
641 .open(path!("/foo.txt"))
642 .expect("failed to create a new file");
643
644 assert!(matches!(file.set_len(7), Ok(())), "setting a new length");
645 assert_eq!(file.size(), 7, "file has a new length");
646 }
647
648 #[tokio::test]
649 async fn test_unlink() {
650 let fs = FileSystem::default();
651
652 let mut file = fs
653 .new_open_options()
654 .write(true)
655 .create_new(true)
656 .open(path!("/foo.txt"))
657 .expect("failed to create a new file");
658
659 {
660 let fs_inner = fs.inner.read().unwrap();
661
662 assert_eq!(fs_inner.storage.len(), 2, "storage has the new file");
663 assert!(
664 matches!(
665 fs_inner.storage.get(ROOT_INODE),
666 Some(Node::Directory(DirectoryNode {
667 inode: ROOT_INODE,
668 name,
669 children,
670 ..
671 })) if name == "/" && children == &[1]
672 ),
673 "`/` contains `foo.txt`",
674 );
675 assert!(
676 matches!(
677 fs_inner.storage.get(1),
678 Some(Node::File(FileNode {
679 inode: 1,
680 name,
681 ..
682 })) if name == "foo.txt"
683 ),
684 "`foo.txt` exists and is a file",
685 );
686 }
687
688 assert_eq!(file.unlink(), Ok(()), "unlinking the file");
689
690 {
691 let fs_inner = fs.inner.read().unwrap();
692
693 assert_eq!(
694 fs_inner.storage.len(),
695 1,
696 "storage no longer has the new file"
697 );
698 assert!(
699 matches!(
700 fs_inner.storage.get(ROOT_INODE),
701 Some(Node::Directory(DirectoryNode {
702 inode: ROOT_INODE,
703 name,
704 children,
705 ..
706 })) if name == "/" && children.is_empty()
707 ),
708 "`/` is empty",
709 );
710 }
711 }
712}
713
714impl AsyncRead for FileHandle {
715 fn poll_read(
716 mut self: Pin<&mut Self>,
717 cx: &mut Context<'_>,
718 buf: &mut tokio::io::ReadBuf<'_>,
719 ) -> Poll<io::Result<()>> {
720 if !self.readable {
721 return Poll::Ready(Err(io::Error::new(
722 io::ErrorKind::PermissionDenied,
723 format!(
724 "the file (inode `{}) doesn't have the `read` permission",
725 self.inode
726 ),
727 )));
728 }
729
730 let mut cursor = self.cursor;
731 let ret = {
732 let mut fs = self
733 .filesystem
734 .inner
735 .write()
736 .map_err(|_| io::Error::other("failed to acquire a write lock"))?;
737
738 let inode = fs.storage.get_mut(self.inode);
739 match inode {
740 Some(Node::File(node)) => {
741 let read = unsafe {
742 node.file.read(
743 std::mem::transmute::<&mut [std::mem::MaybeUninit<u8>], &mut [u8]>(
744 buf.unfilled_mut(),
745 ),
746 &mut cursor,
747 )
748 };
749 if let Ok(read) = &read {
750 unsafe { buf.assume_init(*read) };
751 buf.advance(*read);
752 }
753 Poll::Ready(read.map(|_| ()))
754 }
755 Some(Node::OffloadedFile(node)) => {
756 let read = unsafe {
757 node.file.read(
758 std::mem::transmute::<&mut [std::mem::MaybeUninit<u8>], &mut [u8]>(
759 buf.unfilled_mut(),
760 ),
761 &mut cursor,
762 )
763 };
764 if let Ok(read) = &read {
765 unsafe { buf.assume_init(*read) };
766 buf.advance(*read);
767 }
768 Poll::Ready(read.map(|_| ()))
769 }
770 Some(Node::ReadOnlyFile(node)) => {
771 let read = unsafe {
772 node.file.read(
773 std::mem::transmute::<&mut [std::mem::MaybeUninit<u8>], &mut [u8]>(
774 buf.unfilled_mut(),
775 ),
776 &mut cursor,
777 )
778 };
779 if let Ok(read) = &read {
780 unsafe { buf.assume_init(*read) };
781 buf.advance(*read);
782 }
783 Poll::Ready(read.map(|_| ()))
784 }
785 Some(Node::CustomFile(node)) => {
786 let mut file = node.file.lock().unwrap();
787 let file = Pin::new(file.as_mut());
788 file.poll_read(cx, buf)
789 }
790 Some(Node::ArcFile(_)) => {
791 drop(fs);
792 match self.lazy_load_arc_file_mut() {
793 Ok(file) => {
794 let file = Pin::new(file);
795 file.poll_read(cx, buf)
796 }
797 Err(_) => {
798 return Poll::Ready(Err(io::Error::new(
799 io::ErrorKind::NotFound,
800 format!("inode `{}` doesn't match a file", self.inode),
801 )));
802 }
803 }
804 }
805 _ => {
806 return Poll::Ready(Err(io::Error::new(
807 io::ErrorKind::NotFound,
808 format!("inode `{}` doesn't match a file", self.inode),
809 )));
810 }
811 }
812 };
813 self.cursor = cursor;
814 ret
815 }
816}
817
818impl AsyncSeek for FileHandle {
819 fn start_seek(mut self: Pin<&mut Self>, position: io::SeekFrom) -> io::Result<()> {
820 let mut cursor = self.cursor;
821 let ret = {
822 let mut fs = self
823 .filesystem
824 .inner
825 .write()
826 .map_err(|_| io::Error::other("failed to acquire a write lock"))?;
827
828 let inode = fs.storage.get_mut(self.inode);
829 match inode {
830 Some(Node::File(node)) => {
831 node.file.seek(position, &mut cursor)?;
832 Ok(())
833 }
834 Some(Node::OffloadedFile(node)) => {
835 node.file.seek(position, &mut cursor)?;
836 Ok(())
837 }
838 Some(Node::ReadOnlyFile(node)) => {
839 node.file.seek(position, &mut cursor)?;
840 Ok(())
841 }
842 Some(Node::CustomFile(node)) => {
843 let mut file = node.file.lock().unwrap();
844 let file = Pin::new(file.as_mut());
845 file.start_seek(position)
846 }
847 Some(Node::ArcFile(_)) => {
848 drop(fs);
849 match self.lazy_load_arc_file_mut() {
850 Ok(file) => {
851 let file = Pin::new(file);
852 file.start_seek(position)
853 }
854 Err(_) => {
855 return Err(io::Error::new(
856 io::ErrorKind::NotFound,
857 format!("inode `{}` doesn't match a file", self.inode),
858 ));
859 }
860 }
861 }
862 _ => {
863 return Err(io::Error::new(
864 io::ErrorKind::NotFound,
865 format!("inode `{}` doesn't match a file", self.inode),
866 ));
867 }
868 }
869 };
870 self.cursor = cursor;
871 ret
872 }
873
874 fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
875 let mut fs = self
876 .filesystem
877 .inner
878 .write()
879 .map_err(|_| io::Error::other("failed to acquire a write lock"))?;
880
881 let inode = fs.storage.get_mut(self.inode);
882 match inode {
883 Some(Node::File { .. }) => Poll::Ready(Ok(self.cursor)),
884 Some(Node::OffloadedFile { .. }) => Poll::Ready(Ok(self.cursor)),
885 Some(Node::ReadOnlyFile { .. }) => Poll::Ready(Ok(self.cursor)),
886 Some(Node::CustomFile(node)) => {
887 let mut file = node.file.lock().unwrap();
888 let file = Pin::new(file.as_mut());
889 file.poll_complete(cx)
890 }
891 Some(Node::ArcFile { .. }) => {
892 drop(fs);
893 match self.lazy_load_arc_file_mut() {
894 Ok(file) => {
895 let file = Pin::new(file);
896 file.poll_complete(cx)
897 }
898 Err(_) => Poll::Ready(Err(io::Error::new(
899 io::ErrorKind::NotFound,
900 format!("inode `{}` doesn't match a file", self.inode),
901 ))),
902 }
903 }
904 _ => Poll::Ready(Err(io::Error::new(
905 io::ErrorKind::NotFound,
906 format!("inode `{}` doesn't match a file", self.inode),
907 ))),
908 }
909 }
910}
911
912impl AsyncWrite for FileHandle {
913 fn poll_write(
914 mut self: Pin<&mut Self>,
915 cx: &mut Context<'_>,
916 buf: &[u8],
917 ) -> Poll<io::Result<usize>> {
918 if !self.writable {
919 return Poll::Ready(Err(io::Error::new(
920 io::ErrorKind::PermissionDenied,
921 format!(
922 "the file (inode `{}) doesn't have the `write` permission",
923 self.inode
924 ),
925 )));
926 }
927
928 let mut cursor;
929 let bytes_written = {
930 let mut fs = self
931 .filesystem
932 .inner
933 .write()
934 .map_err(|_| io::Error::other("failed to acquire a write lock"))?;
935
936 let inode = fs.storage.get_mut(self.inode);
937 match inode {
938 Some(Node::File(node)) => {
939 cursor = self.write_cursor(node.file.len() as u64);
940 let bytes_written = node.file.write(buf, &mut cursor)?;
941 node.metadata.len = node.file.len().try_into().unwrap();
942 bytes_written
943 }
944 Some(Node::OffloadedFile(node)) => {
945 cursor = self.write_cursor(node.file.len());
946 let bytes_written = node.file.write(OffloadWrite::Buffer(buf), &mut cursor)?;
947 node.metadata.len = node.file.len();
948 bytes_written
949 }
950 Some(Node::ReadOnlyFile(node)) => {
951 cursor = self.write_cursor(node.file.len() as u64);
952 let bytes_written = node.file.write(buf, &mut cursor)?;
953 node.metadata.len = node.file.len().try_into().unwrap();
954 bytes_written
955 }
956 Some(Node::CustomFile(node)) => {
957 let mut guard = node.file.lock().unwrap();
958 cursor = self.write_cursor(guard.size());
959
960 let file = Pin::new(guard.as_mut());
961 if let Err(err) = file.start_seek(io::SeekFrom::Start(cursor)) {
962 return Poll::Ready(Err(err));
963 }
964
965 let file = Pin::new(guard.as_mut());
966 let _ = file.poll_complete(cx);
967
968 let file = Pin::new(guard.as_mut());
969 let bytes_written = match file.poll_write(cx, buf) {
970 Poll::Ready(Ok(a)) => a,
971 Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
972 Poll::Pending => return Poll::Pending,
973 };
974 cursor += bytes_written as u64;
975 node.metadata.len = guard.size();
976 bytes_written
977 }
978 Some(Node::ArcFile(_)) => {
979 drop(fs);
980 match self.lazy_load_arc_file_mut() {
981 Ok(file) => {
982 let file = Pin::new(file);
983 return file.poll_write(cx, buf);
984 }
985 Err(_) => {
986 return Poll::Ready(Err(io::Error::new(
987 io::ErrorKind::NotFound,
988 format!("inode `{}` doesn't match a file", self.inode),
989 )));
990 }
991 }
992 }
993 _ => {
994 return Poll::Ready(Err(io::Error::new(
995 io::ErrorKind::NotFound,
996 format!("inode `{}` doesn't match a file", self.inode),
997 )));
998 }
999 }
1000 };
1001 self.cursor = cursor;
1002 Poll::Ready(Ok(bytes_written))
1003 }
1004
1005 fn poll_write_vectored(
1006 mut self: Pin<&mut Self>,
1007 cx: &mut Context<'_>,
1008 bufs: &[io::IoSlice<'_>],
1009 ) -> Poll<io::Result<usize>> {
1010 let mut cursor = self.cursor;
1011 let ret = {
1012 let mut fs = self
1013 .filesystem
1014 .inner
1015 .write()
1016 .map_err(|_| io::Error::other("failed to acquire a write lock"))?;
1017
1018 let inode = fs.storage.get_mut(self.inode);
1019 match inode {
1020 Some(Node::File(node)) => {
1021 cursor = self.write_cursor(node.file.len() as u64);
1022 let buf = bufs
1023 .iter()
1024 .find(|b| !b.is_empty())
1025 .map_or(&[][..], |b| &**b);
1026 let bytes_written = node.file.write(buf, &mut cursor)?;
1027 node.metadata.len = node.file.buffer.len() as u64;
1028 Poll::Ready(Ok(bytes_written))
1029 }
1030 Some(Node::OffloadedFile(node)) => {
1031 cursor = self.write_cursor(node.file.len());
1032 let buf = bufs
1033 .iter()
1034 .find(|b| !b.is_empty())
1035 .map_or(&[][..], |b| &**b);
1036 let bytes_written = node.file.write(OffloadWrite::Buffer(buf), &mut cursor)?;
1037 node.metadata.len = node.file.len();
1038 Poll::Ready(Ok(bytes_written))
1039 }
1040 Some(Node::ReadOnlyFile(node)) => {
1041 cursor = self.write_cursor(node.file.len() as u64);
1042 let buf = bufs
1043 .iter()
1044 .find(|b| !b.is_empty())
1045 .map_or(&[][..], |b| &**b);
1046 let bytes_written = node.file.write(buf, &mut cursor)?;
1047 node.metadata.len = node.file.buffer.len() as u64;
1048 Poll::Ready(Ok(bytes_written))
1049 }
1050 Some(Node::CustomFile(node)) => {
1051 let mut file = node.file.lock().unwrap();
1052 let file = Pin::new(file.as_mut());
1053 file.poll_write_vectored(cx, bufs)
1054 }
1055 Some(Node::ArcFile(_)) => {
1056 drop(fs);
1057 match self.lazy_load_arc_file_mut() {
1058 Ok(file) => {
1059 let file = Pin::new(file);
1060 file.poll_write_vectored(cx, bufs)
1061 }
1062 Err(_) => Poll::Ready(Err(io::Error::new(
1063 io::ErrorKind::NotFound,
1064 format!("inode `{}` doesn't match a file", self.inode),
1065 ))),
1066 }
1067 }
1068 _ => Poll::Ready(Err(io::Error::new(
1069 io::ErrorKind::NotFound,
1070 format!("inode `{}` doesn't match a file", self.inode),
1071 ))),
1072 }
1073 };
1074 self.cursor = cursor;
1075 ret
1076 }
1077
1078 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1079 let mut fs = self
1080 .filesystem
1081 .inner
1082 .write()
1083 .map_err(|_| io::Error::other("failed to acquire a write lock"))?;
1084
1085 let inode = fs.storage.get_mut(self.inode);
1086 match inode {
1087 Some(Node::File(node)) => Poll::Ready(node.file.flush()),
1088 Some(Node::OffloadedFile(node)) => Poll::Ready(node.file.flush()),
1089 Some(Node::ReadOnlyFile(node)) => Poll::Ready(node.file.flush()),
1090 Some(Node::CustomFile(node)) => {
1091 let mut file = node.file.lock().unwrap();
1092 let file = Pin::new(file.as_mut());
1093 file.poll_flush(cx)
1094 }
1095 Some(Node::ArcFile { .. }) => {
1096 drop(fs);
1097 match self.lazy_load_arc_file_mut() {
1098 Ok(file) => {
1099 let file = Pin::new(file);
1100 file.poll_flush(cx)
1101 }
1102 Err(_) => Poll::Ready(Err(io::Error::new(
1103 io::ErrorKind::NotFound,
1104 format!("inode `{}` doesn't match a file", self.inode),
1105 ))),
1106 }
1107 }
1108 _ => Poll::Ready(Err(io::Error::new(
1109 io::ErrorKind::NotFound,
1110 format!("inode `{}` doesn't match a file", self.inode),
1111 ))),
1112 }
1113 }
1114
1115 fn poll_shutdown(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
1116 let mut fs = self
1117 .filesystem
1118 .inner
1119 .write()
1120 .map_err(|_| io::Error::other("failed to acquire a write lock"))?;
1121
1122 let inode = fs.storage.get_mut(self.inode);
1123 match inode {
1124 Some(Node::File { .. }) => Poll::Ready(Ok(())),
1125 Some(Node::OffloadedFile { .. }) => Poll::Ready(Ok(())),
1126 Some(Node::ReadOnlyFile { .. }) => Poll::Ready(Ok(())),
1127 Some(Node::CustomFile(node)) => {
1128 let mut file = node.file.lock().unwrap();
1129 let file = Pin::new(file.as_mut());
1130 file.poll_shutdown(cx)
1131 }
1132 Some(Node::ArcFile { .. }) => {
1133 drop(fs);
1134 match self.lazy_load_arc_file_mut() {
1135 Ok(file) => {
1136 let file = Pin::new(file);
1137 file.poll_shutdown(cx)
1138 }
1139 Err(_) => Poll::Ready(Err(io::Error::new(
1140 io::ErrorKind::NotFound,
1141 format!("inode `{}` doesn't match a file", self.inode),
1142 ))),
1143 }
1144 }
1145 _ => Poll::Ready(Err(io::Error::new(
1146 io::ErrorKind::NotFound,
1147 format!("inode `{}` doesn't match a file", self.inode),
1148 ))),
1149 }
1150 }
1151
1152 fn is_write_vectored(&self) -> bool {
1153 let mut fs = match self.filesystem.inner.write() {
1154 Ok(a) => a,
1155 Err(_) => return false,
1156 };
1157
1158 let inode = fs.storage.get_mut(self.inode);
1159 match inode {
1160 Some(Node::File { .. }) => false,
1161 Some(Node::OffloadedFile { .. }) => false,
1162 Some(Node::ReadOnlyFile { .. }) => false,
1163 Some(Node::CustomFile(node)) => {
1164 let file = node.file.lock().unwrap();
1165 file.is_write_vectored()
1166 }
1167 Some(Node::ArcFile { .. }) => {
1168 drop(fs);
1169 match self.arc_file.as_ref() {
1170 Some(Ok(file)) => file.is_write_vectored(),
1171 _ => false,
1172 }
1173 }
1174 _ => false,
1175 }
1176 }
1177}
1178
1179#[cfg(test)]
1180mod test_read_write_seek {
1181 use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
1182
1183 use crate::{FileSystem as FS, mem_fs::*};
1184 use std::io;
1185
1186 macro_rules! path {
1187 ($path:expr) => {
1188 std::path::Path::new($path)
1189 };
1190 }
1191
1192 #[tokio::test]
1193 async fn test_writing_at_various_positions() {
1194 let fs = FileSystem::default();
1195
1196 let mut file = fs
1197 .new_open_options()
1198 .read(true)
1199 .write(true)
1200 .create_new(true)
1201 .open(path!("/foo.txt"))
1202 .expect("failed to create a new file");
1203
1204 assert!(
1205 matches!(file.write(b"foo").await, Ok(3)),
1206 "writing `foo` at the end of the file",
1207 );
1208 assert_eq!(file.size(), 3, "checking the size of the file");
1209
1210 assert!(
1211 matches!(file.write(b"bar").await, Ok(3)),
1212 "writing `bar` at the end of the file",
1213 );
1214 assert_eq!(file.size(), 6, "checking the size of the file");
1215
1216 assert!(
1217 matches!(file.seek(io::SeekFrom::Start(0)).await, Ok(0)),
1218 "seeking to 0",
1219 );
1220
1221 assert!(
1222 matches!(file.write(b"baz").await, Ok(3)),
1223 "writing `baz` at the beginning of the file",
1224 );
1225 assert_eq!(file.size(), 6, "checking the size of the file");
1226
1227 assert!(
1228 matches!(file.write(b"qux").await, Ok(3)),
1229 "writing `qux` in the middle of the file",
1230 );
1231 assert_eq!(file.size(), 6, "checking the size of the file");
1232
1233 assert!(
1234 matches!(file.seek(io::SeekFrom::Start(0)).await, Ok(0)),
1235 "seeking to 0",
1236 );
1237
1238 let mut string = String::new();
1239 assert!(
1240 matches!(file.read_to_string(&mut string).await, Ok(6)),
1241 "reading `bazqux`",
1242 );
1243 assert_eq!(string, "bazqux");
1244
1245 assert!(
1246 matches!(file.seek(io::SeekFrom::Current(-3)).await, Ok(3)),
1247 "seeking to 3",
1248 );
1249
1250 let mut string = String::new();
1251 assert!(
1252 matches!(file.read_to_string(&mut string).await, Ok(3)),
1253 "reading `qux`",
1254 );
1255 assert_eq!(string, "qux");
1256
1257 assert!(
1258 matches!(file.seek(io::SeekFrom::End(0)).await, Ok(6)),
1259 "seeking to 6",
1260 );
1261
1262 let mut string = String::new();
1263 assert!(
1264 matches!(file.read_to_string(&mut string).await, Ok(0)),
1265 "reading ``",
1266 );
1267 assert_eq!(string, "");
1268 }
1269
1270 #[test]
1271 pub fn writing_to_middle() {
1272 fn assert_contents(file: &File, expected: &[u8]) {
1273 let mut buf = vec![0; expected.len() + 1];
1274 let mut cursor = 0;
1275 let read = file.read(buf.as_mut(), &mut cursor).unwrap();
1276 assert_eq!(read, expected.len(), "Must have the same amount of data");
1277 assert_eq!(buf[0..expected.len()], *expected);
1278 }
1279
1280 let mut file = File::new(None);
1281
1282 let mut cursor = 0;
1283
1284 file.write(b"hello, world.", &mut cursor).unwrap();
1286 assert_eq!(cursor, 13);
1287 assert_contents(&file, b"hello, world.");
1288
1289 file.write(b"goodbye!", &mut cursor).unwrap();
1291 assert_eq!(cursor, 21);
1292 assert_contents(&file, b"hello, world.goodbye!");
1293
1294 cursor = 5;
1296 file.write(b"BOOM", &mut cursor).unwrap();
1297 assert_eq!(cursor, 9);
1298 assert_contents(&file, b"helloBOOMrld.goodbye!");
1299
1300 cursor = 17;
1302 file.write(b"BANG", &mut cursor).unwrap();
1303 assert_eq!(cursor, 21);
1304 assert_contents(&file, b"helloBOOMrld.goodBANG");
1305
1306 cursor = 17;
1308 file.write(b"OUCH!", &mut cursor).unwrap();
1309 assert_eq!(cursor, 22);
1310 assert_contents(&file, b"helloBOOMrld.goodOUCH!");
1311 }
1312
1313 #[tokio::test]
1314 async fn test_reading() {
1315 let fs = FileSystem::default();
1316
1317 let mut file = fs
1318 .new_open_options()
1319 .read(true)
1320 .write(true)
1321 .create_new(true)
1322 .open(path!("/foo.txt"))
1323 .expect("failed to create a new file");
1324
1325 assert!(
1326 matches!(fs.metadata(path!("/foo.txt")), Ok(Metadata { len: 0, .. })),
1327 "checking the `metadata.len` is 0",
1328 );
1329 assert!(
1330 matches!(file.write(b"foobarbazqux").await, Ok(12)),
1331 "writing `foobarbazqux`",
1332 );
1333
1334 assert!(
1335 matches!(file.seek(io::SeekFrom::Start(0)).await, Ok(0)),
1336 "seeking to 0",
1337 );
1338
1339 let mut buffer = [0; 6];
1340 assert!(
1341 matches!(file.read(&mut buffer[..]).await, Ok(6)),
1342 "reading 6 bytes",
1343 );
1344 assert_eq!(buffer, b"foobar"[..], "checking the 6 bytes");
1345
1346 assert!(
1347 matches!(file.seek(io::SeekFrom::Start(0)).await, Ok(0)),
1348 "seeking to 0",
1349 );
1350
1351 let mut buffer = [0; 16];
1352 assert!(
1353 matches!(file.read(&mut buffer[..]).await, Ok(12)),
1354 "reading more bytes than available",
1355 );
1356 assert_eq!(buffer[..12], b"foobarbazqux"[..], "checking the 12 bytes");
1357 assert!(
1358 matches!(fs.metadata(path!("/foo.txt")), Ok(Metadata { len: 12, .. })),
1359 "checking the `metadata.len` is 0",
1360 );
1361 }
1362
1363 #[tokio::test]
1364 async fn test_reading_to_the_end() {
1365 let fs = FileSystem::default();
1366
1367 let mut file = fs
1368 .new_open_options()
1369 .read(true)
1370 .write(true)
1371 .create_new(true)
1372 .open(path!("/foo.txt"))
1373 .expect("failed to create a new file");
1374
1375 assert!(
1376 matches!(file.write(b"foobarbazqux").await, Ok(12)),
1377 "writing `foobarbazqux`",
1378 );
1379
1380 assert!(
1381 matches!(file.seek(io::SeekFrom::Start(0)).await, Ok(0)),
1382 "seeking to 0",
1383 );
1384
1385 let mut buffer = Vec::new();
1386 assert!(
1387 matches!(file.read_to_end(&mut buffer).await, Ok(12)),
1388 "reading all bytes",
1389 );
1390 assert_eq!(buffer, b"foobarbazqux"[..], "checking all the bytes");
1391 }
1392
1393 #[tokio::test]
1394 async fn test_reading_to_string() {
1395 let fs = FileSystem::default();
1396
1397 let mut file = fs
1398 .new_open_options()
1399 .read(true)
1400 .write(true)
1401 .create_new(true)
1402 .open(path!("/foo.txt"))
1403 .expect("failed to create a new file");
1404
1405 assert!(
1406 matches!(file.write(b"foobarbazqux").await, Ok(12)),
1407 "writing `foobarbazqux`",
1408 );
1409
1410 assert!(
1411 matches!(file.seek(io::SeekFrom::Start(6)).await, Ok(6)),
1412 "seeking to 0",
1413 );
1414
1415 let mut string = String::new();
1416 assert!(
1417 matches!(file.read_to_string(&mut string).await, Ok(6)),
1418 "reading a string",
1419 );
1420 assert_eq!(string, "bazqux", "checking the string");
1421 }
1422
1423 #[tokio::test]
1424 async fn test_reading_exact_buffer() {
1425 let fs = FileSystem::default();
1426
1427 let mut file = fs
1428 .new_open_options()
1429 .read(true)
1430 .write(true)
1431 .create_new(true)
1432 .open(path!("/foo.txt"))
1433 .expect("failed to create a new file");
1434
1435 assert!(
1436 matches!(file.write(b"foobarbazqux").await, Ok(12)),
1437 "writing `foobarbazqux`",
1438 );
1439
1440 assert!(
1441 matches!(file.seek(io::SeekFrom::Start(6)).await, Ok(6)),
1442 "seeking to 0",
1443 );
1444
1445 let mut buffer = [0; 16];
1446 assert!(
1447 file.read_exact(&mut buffer).await.is_err(),
1448 "failing to read an exact buffer",
1449 );
1450
1451 assert!(
1452 matches!(file.seek(io::SeekFrom::End(-5)).await, Ok(7)),
1453 "seeking to 7",
1454 );
1455
1456 let mut buffer = [0; 3];
1457 assert!(
1458 file.read_exact(&mut buffer).await.is_ok(),
1459 "failing to read an exact buffer",
1460 );
1461 }
1462}
1463
1464impl fmt::Debug for FileHandle {
1465 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
1466 formatter
1467 .debug_struct("FileHandle")
1468 .field("inode", &self.inode)
1469 .field("readable", &self.readable)
1470 .field("writable", &self.writable)
1471 .finish()
1472 }
1473}
1474
1475#[derive(Debug)]
1478pub(super) struct File {
1479 buffer: TrackedVec,
1480}
1481
1482impl File {
1483 pub(super) fn new(limiter: Option<crate::limiter::DynFsMemoryLimiter>) -> Self {
1484 Self {
1485 buffer: TrackedVec::new(limiter),
1486 }
1487 }
1488
1489 pub(super) fn truncate(&mut self) {
1490 self.buffer.clear();
1491 }
1492
1493 pub(super) fn len(&self) -> usize {
1494 self.buffer.len()
1495 }
1496}
1497
1498impl File {
1499 pub fn read(&self, buf: &mut [u8], cursor: &mut u64) -> io::Result<usize> {
1500 let cur_pos = *cursor as usize;
1501
1502 if cur_pos >= self.buffer.len() {
1504 return Ok(0);
1505 }
1506
1507 let max_to_read = cmp::min(self.buffer.len() - cur_pos, buf.len());
1508 let data_to_copy = &self.buffer[cur_pos..][..max_to_read];
1509
1510 buf[..max_to_read].copy_from_slice(data_to_copy);
1513
1514 *cursor += max_to_read as u64;
1515
1516 Ok(max_to_read)
1517 }
1518}
1519
1520impl File {
1521 pub fn seek(&self, position: io::SeekFrom, cursor: &mut u64) -> io::Result<u64> {
1522 let to_err = |_| io::ErrorKind::InvalidInput;
1523
1524 let next_cursor: i64 = match position {
1526 io::SeekFrom::Start(offset) => offset.try_into().map_err(to_err)?,
1528
1529 io::SeekFrom::End(offset) => {
1531 TryInto::<i64>::try_into(self.buffer.len()).map_err(to_err)? + offset
1532 }
1533
1534 io::SeekFrom::Current(offset) => {
1536 TryInto::<i64>::try_into(*cursor).map_err(to_err)? + offset
1537 }
1538 };
1539
1540 if next_cursor < 0 {
1542 return Err(io::Error::new(
1543 io::ErrorKind::InvalidInput,
1544 "seeking before the byte 0",
1545 ));
1546 }
1547
1548 let next_cursor = next_cursor.try_into().map_err(to_err)?;
1549 *cursor = next_cursor;
1550
1551 let cursor = *cursor;
1552 Ok(cursor)
1553 }
1554}
1555
1556impl File {
1557 pub fn write(&mut self, buf: &[u8], cursor: &mut u64) -> io::Result<usize> {
1558 let position = *cursor as usize;
1559 let end = position
1560 .checked_add(buf.len())
1561 .ok_or(io::ErrorKind::InvalidInput)?;
1562
1563 if position > self.buffer.len() {
1564 self.buffer.resize(position, 0)?;
1566 }
1567
1568 if end > self.buffer.len() {
1569 let len_after_end = end - self.buffer.len();
1571 let let_to_end = buf.len() - len_after_end;
1572 self.buffer[position..end - len_after_end].copy_from_slice(&buf[0..let_to_end]);
1573 self.buffer.extend_from_slice(&buf[let_to_end..buf.len()])?;
1574 } else {
1575 self.buffer[position..end].copy_from_slice(buf);
1576 }
1577
1578 *cursor += buf.len() as u64;
1579
1580 Ok(buf.len())
1581 }
1582
1583 fn flush(&mut self) -> io::Result<()> {
1584 Ok(())
1585 }
1586}
1587
1588#[derive(Debug)]
1590pub(super) struct ReadOnlyFile {
1591 buffer: OwnedBuffer,
1592}
1593
1594impl ReadOnlyFile {
1595 pub(super) fn new(buffer: OwnedBuffer) -> Self {
1596 Self { buffer }
1597 }
1598
1599 pub(super) fn len(&self) -> usize {
1600 self.buffer.len()
1601 }
1602}
1603
1604impl ReadOnlyFile {
1605 pub fn read(&self, buf: &mut [u8], cursor: &mut u64) -> io::Result<usize> {
1606 let cur_pos = *cursor as usize;
1607 let max_to_read = cmp::min(self.buffer.len() - cur_pos, buf.len());
1608 let data_to_copy = &self.buffer[cur_pos..][..max_to_read];
1609
1610 buf[..max_to_read].copy_from_slice(data_to_copy);
1613
1614 *cursor += max_to_read as u64;
1615
1616 Ok(max_to_read)
1617 }
1618}
1619
1620impl ReadOnlyFile {
1621 pub fn seek(&self, _position: io::SeekFrom, _cursor: &mut u64) -> io::Result<u64> {
1622 Err(io::Error::new(
1623 io::ErrorKind::PermissionDenied,
1624 "file is read-only",
1625 ))
1626 }
1627}
1628
1629impl ReadOnlyFile {
1630 pub fn write(&mut self, _buf: &[u8], _cursor: &mut u64) -> io::Result<usize> {
1631 Err(io::Error::new(
1632 io::ErrorKind::PermissionDenied,
1633 "file is read-only",
1634 ))
1635 }
1636
1637 pub fn flush(&mut self) -> io::Result<()> {
1638 Ok(())
1639 }
1640}