1use std::fmt::Debug;
2
3use self::vfs::{virtual_sys::StdioSys, WasiDir, WasiFile, WasiFileSys, WasiNode};
4
5pub use super::common::{error::Errno, types as wasi_types, vfs};
6
7#[cfg(all(unix, feature = "async_tokio"))]
8pub use super::common::net::async_tokio::AsyncWasiSocket;
9
10#[derive(Debug)]
11pub enum VFD {
12 Inode {
13 dev: usize,
14 ino: usize,
15 },
16 #[cfg(all(unix, feature = "async_tokio"))]
17 AsyncSocket(AsyncWasiSocket),
18}
19
20impl VFD {
21 #[cfg(all(unix, feature = "async_tokio"))]
22 pub fn is_socket(&self) -> bool {
23 matches!(self, VFD::AsyncSocket(_))
24 }
25
26 pub fn is_inode(&self) -> bool {
27 matches!(self, VFD::Inode { .. })
28 }
29}
30
31pub trait AsyncVM: Send + Sync {
32 fn yield_now(&mut self) -> Result<(), Errno>;
33}
34
35pub struct VFS {
36 vfs: slab::Slab<Box<dyn WasiFileSys<Index = usize> + Send + Sync>>,
37 preopens: Vec<(String, usize)>,
38 fds: slab::Slab<VFD>,
39}
40
41impl Debug for VFS {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 f.debug_struct("VFS")
44 .field("preopens", &self.preopens)
45 .field("fds", &self.fds)
46 .finish()
47 }
48}
49
50impl VFS {
51 pub fn new_with_stdio<IN, OUT, ERR>(stdio_sys: StdioSys<IN, OUT, ERR>) -> Self
52 where
53 IN: std::io::Read + Send + Sync + 'static,
54 OUT: std::io::Write + Send + Sync + 'static,
55 ERR: std::io::Write + Send + Sync + 'static,
56 {
57 let mut vfs: slab::Slab<Box<dyn WasiFileSys<Index = usize> + Send + Sync>> =
58 slab::Slab::new();
59 let dev = vfs.insert(Box::new(stdio_sys));
60
61 let mut fds = slab::Slab::with_capacity(3);
62 fds.insert(VFD::Inode { dev, ino: 0 });
63 fds.insert(VFD::Inode { dev, ino: 1 });
64 fds.insert(VFD::Inode { dev, ino: 2 });
65
66 Self {
67 vfs,
68 preopens: vec![],
69 fds,
70 }
71 }
72
73 pub fn new() -> Self {
74 let stdio_sys = StdioSys::new(std::io::stdin(), std::io::stdout(), std::io::stderr());
75 let mut vfs: slab::Slab<Box<dyn WasiFileSys<Index = usize> + Send + Sync>> =
76 slab::Slab::new();
77 let dev = vfs.insert(Box::new(stdio_sys));
78
79 let mut fds = slab::Slab::with_capacity(3);
80 fds.insert(VFD::Inode { dev, ino: 0 });
81 fds.insert(VFD::Inode { dev, ino: 1 });
82 fds.insert(VFD::Inode { dev, ino: 2 });
83
84 Self {
85 vfs,
86 preopens: vec![],
87 fds,
88 }
89 }
90
91 pub fn mount_file_sys(
92 &mut self,
93 path: &str,
94 file_sys: Box<dyn WasiFileSys<Index = usize> + Send + Sync>,
95 ) {
96 let vfs_id = self.vfs.insert(file_sys);
97 self.preopens.push((path.to_string(), vfs_id));
98 self.fds.insert(VFD::Inode {
99 dev: vfs_id,
100 ino: 0,
101 });
102 }
103}
104
105impl VFS {
106 pub fn path_open(
107 &mut self,
108 dirfd: usize,
109 path: &str,
110 oflags: vfs::OFlags,
111 fs_rights_base: vfs::WASIRights,
112 fs_rights_inheriting: vfs::WASIRights,
113 fdflags: vfs::FdFlags,
114 ) -> Result<usize, Errno> {
115 log::trace!("path_open {dirfd} {path}");
116 let (dev, ino) = self.get_inode_index(dirfd)?;
117 let vfs = self.vfs.get_mut(dev).ok_or(Errno::__WASI_ERRNO_BADF)?;
118 let ino = vfs.path_open(
119 ino,
120 path,
121 oflags,
122 fs_rights_base,
123 fs_rights_inheriting,
124 fdflags,
125 )?;
126 log::trace!("path_open {dirfd} {path} fd=({dev},{ino})");
127
128 if ino != 0 {
129 Ok(self.fds.insert(VFD::Inode { dev, ino }))
130 } else {
131 Ok(dirfd)
132 }
133 }
134
135 pub fn path_rename(
136 &mut self,
137 old_dir_fd: usize,
138 old_path: &str,
139 new_dir_fd: usize,
140 new_path: &str,
141 ) -> Result<(), Errno> {
142 log::trace!(
143 "path_rename {:?} {:?}",
144 (old_dir_fd, old_path),
145 (new_dir_fd, new_path)
146 );
147
148 let (dev0, ino0, dev1, ino1) = if old_dir_fd == new_dir_fd {
149 if let VFD::Inode { dev, ino } =
150 self.fds.get(old_dir_fd).ok_or(Errno::__WASI_ERRNO_BADF)?
151 {
152 (*dev, *ino, *dev, *ino)
153 } else {
154 return Err(Errno::__WASI_ERRNO_BADF);
155 }
156 } else if let (
157 VFD::Inode {
158 dev: dev0,
159 ino: ino0,
160 },
161 VFD::Inode {
162 dev: dev1,
163 ino: ino1,
164 },
165 ) = self
166 .fds
167 .get2_mut(old_dir_fd, new_dir_fd)
168 .ok_or(Errno::__WASI_ERRNO_BADF)?
169 {
170 (*dev0, *ino0, *dev1, *ino1)
171 } else {
172 return Err(Errno::__WASI_ERRNO_BADF);
173 };
174
175 if dev0 != dev1 {
176 return Err(Errno::__WASI_ERRNO_XDEV);
177 }
178
179 if ino0 != 0 || ino1 != 0 {
180 return Err(Errno::__WASI_ERRNO_ACCES);
181 }
182
183 let vfs = self.vfs.get_mut(dev0).ok_or(Errno::__WASI_ERRNO_BADF)?;
184 vfs.path_rename(ino0, old_path, ino1, new_path)
185 }
186
187 pub fn fd_preopen_get(&mut self, fd: usize) -> Result<String, Errno> {
188 log::trace!("fd_preopen_get({fd})");
189 if fd < 3 {
190 return Err(Errno::__WASI_ERRNO_BADF);
191 }
192 let fd = fd - 3;
193 Ok(self
194 .preopens
195 .get(fd)
196 .ok_or(Errno::__WASI_ERRNO_BADF)?
197 .0
198 .clone())
199 }
200
201 pub fn fd_renumber(&mut self, _from: usize, _to: usize) -> Result<(), Errno> {
202 Err(Errno::__WASI_ERRNO_NOTSUP)
203 }
204
205 pub fn fd_advise(
206 &mut self,
207 _fd: usize,
208 _offset: wasi_types::__wasi_filesize_t,
209 _len: wasi_types::__wasi_filesize_t,
210 _advice: wasi_types::__wasi_advice_t::Type,
211 ) -> Result<(), Errno> {
212 Ok(())
213 }
214
215 pub fn fd_close(&mut self, fd: usize) -> Result<(), Errno> {
216 match self.fds.get(fd) {
217 Some(VFD::Inode { dev, ino }) => {
218 if *ino == 0 {
219 return Err(Errno::__WASI_ERRNO_NOTSUP);
220 }
221 if let Some(vfs) = self.vfs.get_mut(*dev) {
222 log::trace!("fclose fd=({},{})", *dev, *ino);
223 vfs.fclose(*ino)?;
224 }
225 self.fds.remove(fd);
226 }
227 Some(VFD::AsyncSocket(_)) => {
228 self.fds.remove(fd);
229 }
230 None => {}
231 }
232
233 Ok(())
234 }
235
236 pub fn path_filestat_get(
237 &self,
238 dir_fd: usize,
239 path: &str,
240 follow_symlinks: bool,
241 ) -> Result<(u64, vfs::Filestat), Errno> {
242 let (dev, ino) = self.get_inode_index(dir_fd)?;
243 let vfs = self.vfs.get(dev).ok_or(Errno::__WASI_ERRNO_BADF)?;
244 Ok((
245 dev as u64,
246 vfs.path_filestat_get(ino, path, follow_symlinks)?,
247 ))
248 }
249
250 pub fn path_create_directory(&mut self, dir_fd: usize, path: &str) -> Result<(), Errno> {
251 let (dev, ino) = self.get_inode_index(dir_fd)?;
252 let vfs = self.vfs.get_mut(dev).ok_or(Errno::__WASI_ERRNO_BADF)?;
253 vfs.path_create_directory(ino, path)
254 }
255
256 pub fn path_remove_directory(&mut self, dir_fd: usize, path: &str) -> Result<(), Errno> {
257 let (dev, ino) = self.get_inode_index(dir_fd)?;
258 let vfs = self.vfs.get_mut(dev).ok_or(Errno::__WASI_ERRNO_BADF)?;
259 vfs.path_remove_directory(ino, path)
260 }
261
262 pub fn path_unlink_file(&mut self, dir_fd: usize, path: &str) -> Result<(), Errno> {
263 let (dev, ino) = self.get_inode_index(dir_fd)?;
264 let vfs = self.vfs.get_mut(dev).ok_or(Errno::__WASI_ERRNO_BADF)?;
265 vfs.path_unlink_file(ino, path)
266 }
267
268 fn get_inode_index(&self, fd: usize) -> Result<(usize, usize), Errno> {
269 if let VFD::Inode { dev, ino } = self.fds.get(fd).ok_or(Errno::__WASI_ERRNO_BADF)? {
270 Ok((*dev, *ino))
271 } else {
272 Err(Errno::__WASI_ERRNO_NOTDIR)
273 }
274 }
275
276 pub fn get_mut_inode(&mut self, fd: usize) -> Result<&mut dyn WasiNode, Errno> {
277 log::trace!("get_mut_inode {fd}");
278
279 let (dev, ino) =
280 if let VFD::Inode { dev, ino } = self.fds.get(fd).ok_or(Errno::__WASI_ERRNO_BADF)? {
281 (*dev, *ino)
282 } else {
283 return Err(Errno::__WASI_ERRNO_BADF);
284 };
285 let vfs = self.vfs.get_mut(dev).ok_or(Errno::__WASI_ERRNO_BADF)?;
286 vfs.get_mut_inode(ino)
287 }
288 pub fn get_inode(&self, fd: usize) -> Result<&dyn WasiNode, Errno> {
289 log::trace!("get_inode {fd}");
290
291 let (dev, ino) =
292 if let VFD::Inode { dev, ino } = self.fds.get(fd).ok_or(Errno::__WASI_ERRNO_BADF)? {
293 (*dev, *ino)
294 } else {
295 return Err(Errno::__WASI_ERRNO_BADF);
296 };
297 let vfs = self.vfs.get(dev).ok_or(Errno::__WASI_ERRNO_BADF)?;
298 vfs.get_inode(ino)
299 }
300
301 pub fn get_mut_file(&mut self, fd: usize) -> Result<&mut dyn WasiFile, Errno> {
302 log::trace!("get_mut_file {fd}");
303
304 let (dev, ino) =
305 if let VFD::Inode { dev, ino } = self.fds.get(fd).ok_or(Errno::__WASI_ERRNO_BADF)? {
306 (*dev, *ino)
307 } else {
308 return Err(Errno::__WASI_ERRNO_BADF);
309 };
310 let vfs = self.vfs.get_mut(dev).ok_or(Errno::__WASI_ERRNO_BADF)?;
311 vfs.get_mut_file(ino)
312 }
313 pub fn get_file(&self, fd: usize) -> Result<&dyn WasiFile, Errno> {
314 log::trace!("get_file {fd}");
315
316 let (dev, ino) =
317 if let VFD::Inode { dev, ino } = self.fds.get(fd).ok_or(Errno::__WASI_ERRNO_BADF)? {
318 (*dev, *ino)
319 } else {
320 return Err(Errno::__WASI_ERRNO_BADF);
321 };
322 let vfs = self.vfs.get(dev).ok_or(Errno::__WASI_ERRNO_BADF)?;
323 vfs.get_file(ino)
324 }
325
326 pub fn get_mut_dir(&mut self, fd: usize) -> Result<&mut dyn WasiDir, Errno> {
327 log::trace!("get_mut_dir {fd}");
328
329 let (dev, ino) =
330 if let VFD::Inode { dev, ino } = self.fds.get(fd).ok_or(Errno::__WASI_ERRNO_BADF)? {
331 (*dev, *ino)
332 } else {
333 return Err(Errno::__WASI_ERRNO_BADF);
334 };
335 let vfs = self.vfs.get_mut(dev).ok_or(Errno::__WASI_ERRNO_BADF)?;
336 vfs.get_mut_dir(ino)
337 }
338 pub fn get_dir(&self, fd: usize) -> Result<&dyn WasiDir, Errno> {
339 log::trace!("get_dir {fd}");
340
341 let (dev, ino) =
342 if let VFD::Inode { dev, ino } = self.fds.get(fd).ok_or(Errno::__WASI_ERRNO_BADF)? {
343 (*dev, *ino)
344 } else {
345 return Err(Errno::__WASI_ERRNO_BADF);
346 };
347 let vfs = self.vfs.get(dev).ok_or(Errno::__WASI_ERRNO_BADF)?;
348 vfs.get_dir(ino)
349 }
350
351 #[cfg(all(unix, feature = "async_tokio"))]
352 pub fn get_mut_socket(&mut self, fd: usize) -> Result<&mut AsyncWasiSocket, Errno> {
353 if let VFD::AsyncSocket(s) = self.fds.get_mut(fd).ok_or(Errno::__WASI_ERRNO_BADF)? {
354 Ok(s)
355 } else {
356 Err(Errno::__WASI_ERRNO_NOTSOCK)
357 }
358 }
359 #[cfg(all(unix, feature = "async_tokio"))]
360 pub fn get_socket(&self, fd: usize) -> Result<&AsyncWasiSocket, Errno> {
361 if let VFD::AsyncSocket(s) = self.fds.get(fd).ok_or(Errno::__WASI_ERRNO_BADF)? {
362 Ok(s)
363 } else {
364 Err(Errno::__WASI_ERRNO_NOTSOCK)
365 }
366 }
367 #[cfg(all(unix, feature = "async_tokio"))]
368 pub fn insert_socket(&mut self, s: AsyncWasiSocket) -> Result<usize, Errno> {
369 Ok(self.fds.insert(VFD::AsyncSocket(s)))
370 }
371}