virtual_fs/mem_fs/
file.rs

1//! This module contains the `FileHandle` and `File`
2//! implementations. They aren't exposed to the public API. Only
3//! `FileHandle` can be used through the `VirtualFile` trait object.
4
5use 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
22/// A file handle. The file system doesn't return the [`File`] type
23/// directly, but rather this `FileHandle` type, which contains the
24/// inode, the flags, and (a light copy of) the filesystem. For each
25/// operations, it is checked that the permissions allow the
26/// operations to be executed, and then it is checked that the file
27/// still exists in the file system. After that, the operation is
28/// delegated to the file itself.
29pub(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        // Update current cursor position if file got truncated
236        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            // Read lock.
246            let fs = filesystem.inner.read().map_err(|_| FsError::Lock)?;
247
248            // The inode of the file.
249            let inode_of_file = inode;
250
251            // Find the position of the file in the parent, and the
252            // inode of the parent.
253            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            // Write lock.
276            let mut fs = filesystem.inner.write().map_err(|_| FsError::Lock)?;
277
278            // Remove the file from the storage.
279            fs.storage.remove(inode_of_file);
280
281            // Remove the child from the parent directory.
282            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        // Write to empty file
1285        file.write(b"hello, world.", &mut cursor).unwrap();
1286        assert_eq!(cursor, 13);
1287        assert_contents(&file, b"hello, world.");
1288
1289        // Write to end of file
1290        file.write(b"goodbye!", &mut cursor).unwrap();
1291        assert_eq!(cursor, 21);
1292        assert_contents(&file, b"hello, world.goodbye!");
1293
1294        // Write to middle of file
1295        cursor = 5;
1296        file.write(b"BOOM", &mut cursor).unwrap();
1297        assert_eq!(cursor, 9);
1298        assert_contents(&file, b"helloBOOMrld.goodbye!");
1299
1300        // Write to middle of file until last byte
1301        cursor = 17;
1302        file.write(b"BANG", &mut cursor).unwrap();
1303        assert_eq!(cursor, 21);
1304        assert_contents(&file, b"helloBOOMrld.goodBANG");
1305
1306        // Write to middle past end of file
1307        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/// The real file! It is simply a buffer of bytes with a cursor that
1476/// represents a read/write position in the buffer.
1477#[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        // POSIX regular files return EOF, not an error, when reading at or beyond EOF.
1503        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        // SAFETY: `buf[..max_to_read]` and `data_to_copy` have the same size, due to
1511        // how `max_to_read` is computed.
1512        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        // Calculate the next cursor.
1525        let next_cursor: i64 = match position {
1526            // Calculate from the beginning, so `0 + offset`.
1527            io::SeekFrom::Start(offset) => offset.try_into().map_err(to_err)?,
1528
1529            // Calculate from the end, so `buffer.len() + offset`.
1530            io::SeekFrom::End(offset) => {
1531                TryInto::<i64>::try_into(self.buffer.len()).map_err(to_err)? + offset
1532            }
1533
1534            // Calculate from the current cursor, so `cursor + offset`.
1535            io::SeekFrom::Current(offset) => {
1536                TryInto::<i64>::try_into(*cursor).map_err(to_err)? + offset
1537            }
1538        };
1539
1540        // It's an error to seek before byte 0.
1541        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            // Materialize the sparse gap with zeroes in this contiguous in-memory buffer.
1565            self.buffer.resize(position, 0)?;
1566        }
1567
1568        if end > self.buffer.len() {
1569            // Writing past the end of the current buffer, must reallocate
1570            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/// Read only file that uses copy-on-write
1589#[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        // SAFETY: `buf[..max_to_read]` and `data_to_copy` have the same size, due to
1611        // how `max_to_read` is computed.
1612        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}