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
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            // Read lock.
236            let fs = filesystem.inner.read().map_err(|_| FsError::Lock)?;
237
238            // The inode of the file.
239            let inode_of_file = inode;
240
241            // Find the position of the file in the parent, and the
242            // inode of the parent.
243            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            // Write lock.
266            let mut fs = filesystem.inner.write().map_err(|_| FsError::Lock)?;
267
268            // Remove the file from the storage.
269            fs.storage.remove(inode_of_file);
270
271            // Remove the child from the parent directory.
272            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        // In `append` mode, it's not possible to seek in the file. In
870        // [`open(2)`](https://man7.org/linux/man-pages/man2/open.2.html),
871        // the `O_APPEND` option describes this behavior well:
872        //
873        // > Before each write(2), the file offset is positioned at
874        // > the end of the file, as if with lseek(2).  The
875        // > modification of the file offset and the write operation
876        // > are performed as a single atomic step.
877        // >
878        // > O_APPEND may lead to corrupted files on NFS filesystems
879        // > if more than one process appends data to a file at once.
880        // > This is because NFS does not support appending to a file,
881        // > so the client kernel has to simulate it, which can't be
882        // > done without a race condition.
883        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        // Write to empty file
1290        file.write(b"hello, world.", &mut cursor).unwrap();
1291        assert_eq!(cursor, 13);
1292        assert_contents(&file, b"hello, world.");
1293
1294        // Write to end of file
1295        file.write(b"goodbye!", &mut cursor).unwrap();
1296        assert_eq!(cursor, 21);
1297        assert_contents(&file, b"hello, world.goodbye!");
1298
1299        // Write to middle of file
1300        cursor = 5;
1301        file.write(b"BOOM", &mut cursor).unwrap();
1302        assert_eq!(cursor, 9);
1303        assert_contents(&file, b"helloBOOMrld.goodbye!");
1304
1305        // Write to middle of file until last byte
1306        cursor = 17;
1307        file.write(b"BANG", &mut cursor).unwrap();
1308        assert_eq!(cursor, 21);
1309        assert_contents(&file, b"helloBOOMrld.goodBANG");
1310
1311        // Write to middle past end of file
1312        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/// The real file! It is simply a buffer of bytes with a cursor that
1481/// represents a read/write position in the buffer.
1482#[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        // SAFETY: `buf[..max_to_read]` and `data_to_copy` have the same size, due to
1510        // how `max_to_read` is computed.
1511        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        // Calculate the next cursor.
1524        let next_cursor: i64 = match position {
1525            // Calculate from the beginning, so `0 + offset`.
1526            io::SeekFrom::Start(offset) => offset.try_into().map_err(to_err)?,
1527
1528            // Calculate from the end, so `buffer.len() + offset`.
1529            io::SeekFrom::End(offset) => {
1530                TryInto::<i64>::try_into(self.buffer.len()).map_err(to_err)? + offset
1531            }
1532
1533            // Calculate from the current cursor, so `cursor + offset`.
1534            io::SeekFrom::Current(offset) => {
1535                TryInto::<i64>::try_into(*cursor).map_err(to_err)? + offset
1536            }
1537        };
1538
1539        // It's an error to seek before byte 0.
1540        if next_cursor < 0 {
1541            return Err(io::Error::new(
1542                io::ErrorKind::InvalidInput,
1543                "seeking before the byte 0",
1544            ));
1545        }
1546
1547        // In this implementation, it's an error to seek beyond the
1548        // end of the buffer.
1549        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            // Writing past the end of the current buffer, must reallocate
1563            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/// Read only file that uses copy-on-write
1582#[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        // SAFETY: `buf[..max_to_read]` and `data_to_copy` have the same size, due to
1604        // how `max_to_read` is computed.
1605        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}