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