summaryrefslogtreecommitdiffstats
path: root/third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs')
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs169
1 files changed, 169 insertions, 0 deletions
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs b/third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs
new file mode 100644
index 0000000000..7c65a64705
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs
@@ -0,0 +1,169 @@
+use crate::host;
+use std::fs::File;
+use std::os::unix::prelude::{FileTypeExt, FromRawFd, IntoRawFd, RawFd};
+use std::path::PathBuf;
+
+#[derive(Debug)]
+pub struct FdEntry {
+ pub fd_object: FdObject,
+ pub rights_base: host::__wasi_rights_t,
+ pub rights_inheriting: host::__wasi_rights_t,
+ pub preopen_path: Option<PathBuf>,
+}
+
+impl FdEntry {
+ pub fn from_file(file: File) -> FdEntry {
+ unsafe { FdEntry::from_raw_fd(file.into_raw_fd()) }
+ }
+ pub unsafe fn from_raw_fd_for_io_desc(rawfd: RawFd, writable : bool) -> FdEntry {
+ let (ty, mut rights_base, rights_inheriting) =
+ (
+ host::__WASI_FILETYPE_CHARACTER_DEVICE,
+ host::RIGHTS_TTY_BASE,
+ host::RIGHTS_TTY_BASE,
+ );
+
+ if !writable {
+ rights_base &= !host::__WASI_RIGHT_FD_WRITE as host::__wasi_rights_t;
+ } else {
+ rights_base &= !host::__WASI_RIGHT_FD_READ as host::__wasi_rights_t;
+ }
+
+ FdEntry {
+ fd_object: FdObject {
+ ty: ty as u8,
+ rawfd,
+ needs_close: true,
+ },
+ rights_base,
+ rights_inheriting,
+ preopen_path: None,
+ }
+ }
+
+}
+
+impl FromRawFd for FdEntry {
+ // TODO: make this a different function with error handling, rather than using the trait method
+ unsafe fn from_raw_fd(rawfd: RawFd) -> FdEntry {
+ let (ty, mut rights_base, rights_inheriting) =
+ determine_type_rights(rawfd).expect("can determine file rights");
+
+ use nix::fcntl::{fcntl, OFlag, F_GETFL};
+ let flags_bits = fcntl(rawfd, F_GETFL).expect("fcntl succeeds");
+ let flags = OFlag::from_bits_truncate(flags_bits);
+ let accmode = flags & OFlag::O_ACCMODE;
+ if accmode == OFlag::O_RDONLY {
+ rights_base &= !host::__WASI_RIGHT_FD_WRITE as host::__wasi_rights_t;
+ } else if accmode == OFlag::O_WRONLY {
+ rights_base &= !host::__WASI_RIGHT_FD_READ as host::__wasi_rights_t;
+ }
+
+ FdEntry {
+ fd_object: FdObject {
+ ty: ty as u8,
+ rawfd,
+ needs_close: true,
+ },
+ rights_base,
+ rights_inheriting,
+ preopen_path: None,
+ }
+ }
+}
+
+// TODO: can probably make this safe by using fcntl directly rather than going through `File`
+pub unsafe fn determine_type_rights(
+ rawfd: RawFd,
+) -> Result<
+ (
+ host::__wasi_filetype_t,
+ host::__wasi_rights_t,
+ host::__wasi_rights_t,
+ ),
+ host::__wasi_errno_t,
+> {
+ let (ty, rights_base, rights_inheriting) = {
+ let file = File::from_raw_fd(rawfd);
+ let ft = file.metadata().unwrap().file_type();
+ // we just make a `File` here for convenience; we don't want it to close when it drops
+ std::mem::forget(file);
+ if ft.is_block_device() {
+ (
+ host::__WASI_FILETYPE_BLOCK_DEVICE,
+ host::RIGHTS_BLOCK_DEVICE_BASE,
+ host::RIGHTS_BLOCK_DEVICE_INHERITING,
+ )
+ } else if ft.is_char_device() {
+ if nix::unistd::isatty(rawfd).unwrap() {
+ (
+ host::__WASI_FILETYPE_CHARACTER_DEVICE,
+ host::RIGHTS_TTY_BASE,
+ host::RIGHTS_TTY_BASE,
+ )
+ } else {
+ (
+ host::__WASI_FILETYPE_CHARACTER_DEVICE,
+ host::RIGHTS_CHARACTER_DEVICE_BASE,
+ host::RIGHTS_CHARACTER_DEVICE_INHERITING,
+ )
+ }
+ } else if ft.is_dir() {
+ (
+ host::__WASI_FILETYPE_DIRECTORY,
+ host::RIGHTS_DIRECTORY_BASE,
+ host::RIGHTS_DIRECTORY_INHERITING,
+ )
+ } else if ft.is_file() {
+ (
+ host::__WASI_FILETYPE_REGULAR_FILE,
+ host::RIGHTS_REGULAR_FILE_BASE,
+ host::RIGHTS_REGULAR_FILE_INHERITING,
+ )
+ // } else if ft.is_socket() {
+ // use nix::sys::socket;
+ // match socket::getsockopt(rawfd, socket::sockopt::SockType).unwrap() {
+ // socket::SockType::Datagram => (
+ // host::__WASI_FILETYPE_SOCKET_DGRAM,
+ // host::RIGHTS_SOCKET_BASE,
+ // host::RIGHTS_SOCKET_INHERITING,
+ // ),
+ // socket::SockType::Stream => (
+ // host::__WASI_FILETYPE_SOCKET_STREAM,
+ // host::RIGHTS_SOCKET_BASE,
+ // host::RIGHTS_SOCKET_INHERITING,
+ // ),
+ // _ => return Err(host::__WASI_EINVAL as host::__wasi_errno_t),
+ // }
+ } else if ft.is_fifo() {
+ (
+ host::__WASI_FILETYPE_SOCKET_STREAM,
+ host::RIGHTS_SOCKET_BASE,
+ host::RIGHTS_SOCKET_INHERITING,
+ )
+ } else {
+ return Err(host::__WASI_EINVAL as host::__wasi_errno_t);
+ }
+ };
+ Ok((
+ ty as host::__wasi_filetype_t,
+ rights_base,
+ rights_inheriting,
+ ))
+}
+
+#[derive(Debug)]
+pub struct FdObject {
+ pub ty: host::__wasi_filetype_t,
+ pub rawfd: RawFd,
+ pub needs_close: bool,
+ // TODO: directories
+}
+
+impl Drop for FdObject {
+ fn drop(&mut self) {
+ if self.needs_close {
+ nix::unistd::close(self.rawfd).unwrap_or_else(|e| eprintln!("FdObject::drop(): {}", e));
+ }
+ }
+}