Skip to main content

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 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}