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