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}