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