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