async_wasi/snapshots/
env.rs

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}