wasmer_wasix/fs/
fd.rs

1use std::{
2    borrow::Cow,
3    collections::HashMap,
4    path::PathBuf,
5    sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard, atomic::AtomicU64},
6};
7
8#[cfg(feature = "enable-serde")]
9use serde_derive::{Deserialize, Serialize};
10use virtual_fs::{Pipe, PipeRx, PipeTx, VirtualFile};
11use wasmer_wasix_types::wasi::{Fd as WasiFd, Fdflags, Fdflagsext, Filestat, Rights};
12
13use crate::net::socket::InodeSocket;
14use crate::os::epoll::EpollState;
15
16use super::{InodeGuard, InodeWeakGuard, NotificationInner};
17
18/// Shared handle to an open [`VirtualFile`].
19pub(crate) type VirtualFileLock = Arc<RwLock<Box<dyn VirtualFile + Send + Sync + 'static>>>;
20
21#[derive(Debug, Clone)]
22#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
23pub struct Fd {
24    #[cfg_attr(feature = "enable-serde", serde(flatten))]
25    pub inner: FdInner,
26
27    /// Flags that determine how the [`Fd`] can be used.
28    ///
29    /// Used when reopening a [`VirtualFile`] during deserialization.
30    pub open_flags: u16,
31    pub inode: InodeGuard,
32    pub is_stdio: bool,
33}
34
35// This struct contains the bits of Fd that are safe to mutate, so that
36// FdList::get_mut can safely return mutable references.
37#[derive(Debug, Clone)]
38#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
39pub struct FdInner {
40    pub rights: Rights,
41    pub rights_inheriting: Rights,
42    pub flags: Fdflags,         // This is file table related flags, not fd flags
43    pub offset: Arc<AtomicU64>, // This also belongs in the file table
44    pub fd_flags: Fdflagsext,   // This is the actual FD flags that belongs here
45}
46
47impl Fd {
48    /// This [`Fd`] can be used with read system calls.
49    pub const READ: u16 = 1;
50    /// This [`Fd`] can be used with write system calls.
51    pub const WRITE: u16 = 2;
52    /// This [`Fd`] can append in write system calls. Note that the append
53    /// permission implies the write permission.
54    pub const APPEND: u16 = 4;
55    /// This [`Fd`] will delete everything before writing. Note that truncate
56    /// permissions require the write permission.
57    ///
58    /// This permission is currently unused when deserializing.
59    pub const TRUNCATE: u16 = 8;
60    /// This [`Fd`] may create a file before writing to it. Note that create
61    /// permissions require write permissions.
62    ///
63    /// This permission is currently unused when deserializing.
64    pub const CREATE: u16 = 16;
65}
66
67/// A file that Wasi knows about that may or may not be open
68#[derive(Debug)]
69#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
70pub struct InodeVal {
71    pub stat: RwLock<Filestat>,
72    pub is_preopened: bool,
73    pub name: RwLock<Cow<'static, str>>,
74    pub kind: RwLock<Kind>,
75}
76
77impl InodeVal {
78    pub fn read(&self) -> RwLockReadGuard<'_, Kind> {
79        self.kind.read().unwrap()
80    }
81
82    pub fn write(&self) -> RwLockWriteGuard<'_, Kind> {
83        self.kind.write().unwrap()
84    }
85}
86
87/// The core of the filesystem abstraction.  Includes directories,
88/// files, and symlinks.
89#[derive(Debug)]
90#[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))]
91pub enum Kind {
92    File {
93        /// The open file, if it's open
94        #[cfg_attr(feature = "enable-serde", serde(skip))]
95        handle: Option<VirtualFileLock>,
96        /// The path on the host system where the file is located
97        /// This is deprecated and will be removed soon
98        path: PathBuf,
99        /// Marks the file as a special file that only one `fd` can exist for
100        /// This is useful when dealing with host-provided special files that
101        /// should be looked up by path
102        /// TODO: clarify here?
103        fd: Option<u32>,
104    },
105    #[cfg_attr(feature = "enable-serde", serde(skip))]
106    Socket {
107        /// Represents a networking socket
108        socket: InodeSocket,
109    },
110    #[cfg_attr(feature = "enable-serde", serde(skip))]
111    PipeTx {
112        tx: PipeTx,
113    },
114    #[cfg_attr(feature = "enable-serde", serde(skip))]
115    PipeRx {
116        rx: PipeRx,
117    },
118    #[cfg_attr(feature = "enable-serde", serde(skip))]
119    DuplexPipe {
120        pipe: Pipe,
121    },
122    #[cfg_attr(feature = "enable-serde", serde(skip))]
123    Epoll {
124        state: Arc<EpollState>,
125    },
126    Dir {
127        /// Parent directory
128        parent: InodeWeakGuard,
129        /// The path on the host system where the directory is located
130        // TODO: wrap it like VirtualFile
131        path: PathBuf,
132        /// The entries of a directory are lazily filled.
133        entries: HashMap<String, InodeGuard>,
134    },
135    /// The same as Dir but without the irrelevant bits
136    /// The root is immutable after creation; generally the Kind::Root
137    /// branch of whatever code you're writing will be a simpler version of
138    /// your Kind::Dir logic
139    Root {
140        entries: HashMap<String, InodeGuard>,
141    },
142    /// The first two fields are data _about_ the symlink
143    /// the last field is the data _inside_ the symlink
144    ///
145    /// `base_po_dir` should never be the root because:
146    /// - Right now symlinks are not allowed in the immutable root
147    /// - There is always a closer pre-opened dir to the symlink file (by definition of the root being a collection of preopened dirs)
148    Symlink {
149        /// The preopened dir that this symlink file is relative to (via `path_to_symlink`)
150        base_po_dir: WasiFd,
151        /// The path to the symlink from the `base_po_dir`
152        path_to_symlink: PathBuf,
153        /// the value of the symlink as a relative path
154        relative_path: PathBuf,
155    },
156    Buffer {
157        buffer: Vec<u8>,
158    },
159    EventNotifications {
160        inner: Arc<NotificationInner>,
161    },
162}