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