virtual_fs/mem_fs/
mod.rs

1mod file;
2mod file_opener;
3mod filesystem;
4mod offloaded_file;
5mod stdio;
6
7use file::{File, FileHandle, ReadOnlyFile};
8pub use filesystem::FileSystem;
9pub use offloaded_file::OffloadBackingStore;
10#[cfg(not(feature = "js"))]
11use std::time::{SystemTime, UNIX_EPOCH};
12pub use stdio::{Stderr, Stdin, Stdout};
13#[cfg(feature = "js")]
14pub use web_time::{SystemTime, UNIX_EPOCH};
15
16use crate::Metadata;
17use std::{
18    ffi::{OsStr, OsString},
19    path::PathBuf,
20    sync::{Arc, Mutex},
21};
22
23use self::offloaded_file::OffloadedFile;
24
25type Inode = usize;
26const ROOT_INODE: Inode = 0;
27
28#[derive(Debug)]
29struct FileNode {
30    inode: Inode,
31    name: OsString,
32    file: File,
33    metadata: Metadata,
34}
35
36#[derive(Debug)]
37struct ReadOnlyFileNode {
38    inode: Inode,
39    name: OsString,
40    file: ReadOnlyFile,
41    metadata: Metadata,
42}
43
44#[derive(Debug)]
45struct OffloadedFileNode {
46    inode: Inode,
47    name: OsString,
48    file: OffloadedFile,
49    metadata: Metadata,
50}
51
52#[derive(Debug)]
53struct ArcFileNode {
54    inode: Inode,
55    name: OsString,
56    fs: Arc<dyn crate::FileSystem + Send + Sync>,
57    path: PathBuf,
58    metadata: Metadata,
59}
60
61// FIXME: this is broken!!! A `VirtualFile` stores its own offset,
62// so a file stored this way can only be read once!
63#[derive(Debug)]
64struct CustomFileNode {
65    inode: Inode,
66    name: OsString,
67    file: Mutex<Box<dyn crate::VirtualFile + Send + Sync>>,
68    metadata: Metadata,
69}
70
71#[derive(Debug)]
72struct DirectoryNode {
73    inode: Inode,
74    name: OsString,
75    children: Vec<Inode>,
76    metadata: Metadata,
77}
78
79#[derive(Debug)]
80struct ArcDirectoryNode {
81    inode: Inode,
82    name: OsString,
83    fs: Arc<dyn crate::FileSystem + Send + Sync>,
84    path: PathBuf,
85    metadata: Metadata,
86}
87
88#[derive(Debug)]
89enum Node {
90    File(FileNode),
91    OffloadedFile(OffloadedFileNode),
92    ReadOnlyFile(ReadOnlyFileNode),
93    ArcFile(ArcFileNode),
94    CustomFile(CustomFileNode),
95    Directory(DirectoryNode),
96    ArcDirectory(ArcDirectoryNode),
97}
98
99impl Node {
100    fn inode(&self) -> Inode {
101        *match self {
102            Self::File(FileNode { inode, .. }) => inode,
103            Self::OffloadedFile(OffloadedFileNode { inode, .. }) => inode,
104            Self::ReadOnlyFile(ReadOnlyFileNode { inode, .. }) => inode,
105            Self::ArcFile(ArcFileNode { inode, .. }) => inode,
106            Self::CustomFile(CustomFileNode { inode, .. }) => inode,
107            Self::Directory(DirectoryNode { inode, .. }) => inode,
108            Self::ArcDirectory(ArcDirectoryNode { inode, .. }) => inode,
109        }
110    }
111
112    fn name(&self) -> &OsStr {
113        match self {
114            Self::File(FileNode { name, .. }) => name.as_os_str(),
115            Self::OffloadedFile(OffloadedFileNode { name, .. }) => name.as_os_str(),
116            Self::ReadOnlyFile(ReadOnlyFileNode { name, .. }) => name.as_os_str(),
117            Self::ArcFile(ArcFileNode { name, .. }) => name.as_os_str(),
118            Self::CustomFile(CustomFileNode { name, .. }) => name.as_os_str(),
119            Self::Directory(DirectoryNode { name, .. }) => name.as_os_str(),
120            Self::ArcDirectory(ArcDirectoryNode { name, .. }) => name.as_os_str(),
121        }
122    }
123
124    fn metadata(&self) -> &Metadata {
125        match self {
126            Self::File(FileNode { metadata, .. }) => metadata,
127            Self::OffloadedFile(OffloadedFileNode { metadata, .. }) => metadata,
128            Self::ReadOnlyFile(ReadOnlyFileNode { metadata, .. }) => metadata,
129            Self::ArcFile(ArcFileNode { metadata, .. }) => metadata,
130            Self::CustomFile(CustomFileNode { metadata, .. }) => metadata,
131            Self::Directory(DirectoryNode { metadata, .. }) => metadata,
132            Self::ArcDirectory(ArcDirectoryNode { metadata, .. }) => metadata,
133        }
134    }
135
136    fn metadata_mut(&mut self) -> &mut Metadata {
137        match self {
138            Self::File(FileNode { metadata, .. }) => metadata,
139            Self::OffloadedFile(OffloadedFileNode { metadata, .. }) => metadata,
140            Self::ReadOnlyFile(ReadOnlyFileNode { metadata, .. }) => metadata,
141            Self::ArcFile(ArcFileNode { metadata, .. }) => metadata,
142            Self::CustomFile(CustomFileNode { metadata, .. }) => metadata,
143            Self::Directory(DirectoryNode { metadata, .. }) => metadata,
144            Self::ArcDirectory(ArcDirectoryNode { metadata, .. }) => metadata,
145        }
146    }
147
148    fn set_name(&mut self, new_name: OsString) {
149        match self {
150            Self::File(FileNode { name, .. }) => *name = new_name,
151            Self::OffloadedFile(OffloadedFileNode { name, .. }) => *name = new_name,
152            Self::ReadOnlyFile(ReadOnlyFileNode { name, .. }) => *name = new_name,
153            Self::ArcFile(ArcFileNode { name, .. }) => *name = new_name,
154            Self::CustomFile(CustomFileNode { name, .. }) => *name = new_name,
155            Self::Directory(DirectoryNode { name, .. }) => *name = new_name,
156            Self::ArcDirectory(ArcDirectoryNode { name, .. }) => *name = new_name,
157        }
158    }
159}
160
161fn time() -> u64 {
162    // SAFETY: It's very unlikely that the system returns a time that
163    // is before `UNIX_EPOCH` :-).
164    SystemTime::now()
165        .duration_since(UNIX_EPOCH)
166        .unwrap()
167        .as_nanos() as u64
168}