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)]
89struct SymlinkNode {
90    inode: Inode,
91    name: OsString,
92    target: PathBuf,
93    metadata: Metadata,
94}
95
96#[derive(Debug)]
97enum Node {
98    File(FileNode),
99    OffloadedFile(OffloadedFileNode),
100    ReadOnlyFile(ReadOnlyFileNode),
101    ArcFile(ArcFileNode),
102    CustomFile(CustomFileNode),
103    Symlink(SymlinkNode),
104    Directory(DirectoryNode),
105    ArcDirectory(ArcDirectoryNode),
106}
107
108impl Node {
109    fn inode(&self) -> Inode {
110        *match self {
111            Self::File(FileNode { inode, .. }) => inode,
112            Self::OffloadedFile(OffloadedFileNode { inode, .. }) => inode,
113            Self::ReadOnlyFile(ReadOnlyFileNode { inode, .. }) => inode,
114            Self::ArcFile(ArcFileNode { inode, .. }) => inode,
115            Self::CustomFile(CustomFileNode { inode, .. }) => inode,
116            Self::Symlink(SymlinkNode { inode, .. }) => inode,
117            Self::Directory(DirectoryNode { inode, .. }) => inode,
118            Self::ArcDirectory(ArcDirectoryNode { inode, .. }) => inode,
119        }
120    }
121
122    fn name(&self) -> &OsStr {
123        match self {
124            Self::File(FileNode { name, .. }) => name.as_os_str(),
125            Self::OffloadedFile(OffloadedFileNode { name, .. }) => name.as_os_str(),
126            Self::ReadOnlyFile(ReadOnlyFileNode { name, .. }) => name.as_os_str(),
127            Self::ArcFile(ArcFileNode { name, .. }) => name.as_os_str(),
128            Self::CustomFile(CustomFileNode { name, .. }) => name.as_os_str(),
129            Self::Symlink(SymlinkNode { name, .. }) => name.as_os_str(),
130            Self::Directory(DirectoryNode { name, .. }) => name.as_os_str(),
131            Self::ArcDirectory(ArcDirectoryNode { name, .. }) => name.as_os_str(),
132        }
133    }
134
135    fn metadata(&self) -> &Metadata {
136        match self {
137            Self::File(FileNode { metadata, .. }) => metadata,
138            Self::OffloadedFile(OffloadedFileNode { metadata, .. }) => metadata,
139            Self::ReadOnlyFile(ReadOnlyFileNode { metadata, .. }) => metadata,
140            Self::ArcFile(ArcFileNode { metadata, .. }) => metadata,
141            Self::CustomFile(CustomFileNode { metadata, .. }) => metadata,
142            Self::Symlink(SymlinkNode { metadata, .. }) => metadata,
143            Self::Directory(DirectoryNode { metadata, .. }) => metadata,
144            Self::ArcDirectory(ArcDirectoryNode { metadata, .. }) => metadata,
145        }
146    }
147
148    fn metadata_mut(&mut self) -> &mut Metadata {
149        match self {
150            Self::File(FileNode { metadata, .. }) => metadata,
151            Self::OffloadedFile(OffloadedFileNode { metadata, .. }) => metadata,
152            Self::ReadOnlyFile(ReadOnlyFileNode { metadata, .. }) => metadata,
153            Self::ArcFile(ArcFileNode { metadata, .. }) => metadata,
154            Self::CustomFile(CustomFileNode { metadata, .. }) => metadata,
155            Self::Symlink(SymlinkNode { metadata, .. }) => metadata,
156            Self::Directory(DirectoryNode { metadata, .. }) => metadata,
157            Self::ArcDirectory(ArcDirectoryNode { metadata, .. }) => metadata,
158        }
159    }
160
161    fn set_name(&mut self, new_name: OsString) {
162        match self {
163            Self::File(FileNode { name, .. }) => *name = new_name,
164            Self::OffloadedFile(OffloadedFileNode { name, .. }) => *name = new_name,
165            Self::ReadOnlyFile(ReadOnlyFileNode { name, .. }) => *name = new_name,
166            Self::ArcFile(ArcFileNode { name, .. }) => *name = new_name,
167            Self::CustomFile(CustomFileNode { name, .. }) => *name = new_name,
168            Self::Symlink(SymlinkNode { name, .. }) => *name = new_name,
169            Self::Directory(DirectoryNode { name, .. }) => *name = new_name,
170            Self::ArcDirectory(ArcDirectoryNode { name, .. }) => *name = new_name,
171        }
172    }
173}
174
175fn time() -> u64 {
176    // SAFETY: It's very unlikely that the system returns a time that
177    // is before `UNIX_EPOCH` :-).
178    SystemTime::now()
179        .duration_since(UNIX_EPOCH)
180        .unwrap()
181        .as_nanos() as u64
182}