handle: re-export all of the wasi types used by handles

This commit is contained in:
Pat Hickey
2020-09-14 16:27:33 -07:00
parent 43d2799fa2
commit 6db24fd08f
4 changed files with 180 additions and 182 deletions

View File

@@ -5,7 +5,7 @@ use std::ops::Deref;
use std::path::PathBuf; use std::path::PathBuf;
use std::rc::Rc; use std::rc::Rc;
pub(crate) struct EntryHandle(Rc<dyn Handle>); pub struct EntryHandle(Rc<dyn Handle>);
impl EntryHandle { impl EntryHandle {
#[allow(dead_code)] #[allow(dead_code)]

View File

@@ -1,4 +1,7 @@
use crate::wasi::types::{self, Rights}; pub use crate::wasi::types::{
Advice, Dircookie, Dirent, Fdflags, Fdstat, Filedelta, Filesize, Filestat, Filetype, Fstflags,
Lookupflags, Oflags, Prestat, PrestatDir, Rights, Size, Timestamp, Whence,
};
use crate::{Error, Result}; use crate::{Error, Result};
use std::any::Any; use std::any::Any;
use std::fmt; use std::fmt;
@@ -82,13 +85,13 @@ impl fmt::Display for HandleRights {
pub trait Handle { pub trait Handle {
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn try_clone(&self) -> io::Result<Box<dyn Handle>>; fn try_clone(&self) -> io::Result<Box<dyn Handle>>;
fn get_file_type(&self) -> types::Filetype; fn get_file_type(&self) -> Filetype;
fn get_rights(&self) -> HandleRights { fn get_rights(&self) -> HandleRights {
HandleRights::empty() HandleRights::empty()
} }
fn set_rights(&self, rights: HandleRights); fn set_rights(&self, rights: HandleRights);
fn is_directory(&self) -> bool { fn is_directory(&self) -> bool {
self.get_file_type() == types::Filetype::Directory self.get_file_type() == Filetype::Directory
} }
/// Test whether this descriptor is considered a tty within WASI. /// Test whether this descriptor is considered a tty within WASI.
/// Note that since WASI itself lacks an `isatty` syscall and relies /// Note that since WASI itself lacks an `isatty` syscall and relies
@@ -97,41 +100,36 @@ pub trait Handle {
let file_type = self.get_file_type(); let file_type = self.get_file_type();
let rights = self.get_rights(); let rights = self.get_rights();
let required_rights = HandleRights::from_base(Rights::FD_SEEK | Rights::FD_TELL); let required_rights = HandleRights::from_base(Rights::FD_SEEK | Rights::FD_TELL);
file_type == types::Filetype::CharacterDevice && rights.contains(&required_rights) file_type == Filetype::CharacterDevice && rights.contains(&required_rights)
} }
// TODO perhaps should be a separate trait? // TODO perhaps should be a separate trait?
// FdOps // FdOps
fn advise( fn advise(&self, _advice: Advice, _offset: Filesize, _len: Filesize) -> Result<()> {
&self,
_advice: types::Advice,
_offset: types::Filesize,
_len: types::Filesize,
) -> Result<()> {
Err(Error::Badf) Err(Error::Badf)
} }
fn allocate(&self, _offset: types::Filesize, _len: types::Filesize) -> Result<()> { fn allocate(&self, _offset: Filesize, _len: Filesize) -> Result<()> {
Err(Error::Badf) Err(Error::Badf)
} }
fn datasync(&self) -> Result<()> { fn datasync(&self) -> Result<()> {
Err(Error::Inval) Err(Error::Inval)
} }
fn fdstat_get(&self) -> Result<types::Fdflags> { fn fdstat_get(&self) -> Result<Fdflags> {
Ok(types::Fdflags::empty()) Ok(Fdflags::empty())
} }
fn fdstat_set_flags(&self, _fdflags: types::Fdflags) -> Result<()> { fn fdstat_set_flags(&self, _fdflags: Fdflags) -> Result<()> {
Err(Error::Badf) Err(Error::Badf)
} }
fn filestat_get(&self) -> Result<types::Filestat> { fn filestat_get(&self) -> Result<Filestat> {
Err(Error::Badf) Err(Error::Badf)
} }
fn filestat_set_size(&self, _st_size: types::Filesize) -> Result<()> { fn filestat_set_size(&self, _st_size: Filesize) -> Result<()> {
Err(Error::Badf) Err(Error::Badf)
} }
fn filestat_set_times( fn filestat_set_times(
&self, &self,
_atim: types::Timestamp, _atim: Timestamp,
_mtim: types::Timestamp, _mtim: Timestamp,
_fst_flags: types::Fstflags, _fst_flags: Fstflags,
) -> Result<()> { ) -> Result<()> {
Err(Error::Badf) Err(Error::Badf)
} }
@@ -146,8 +144,8 @@ pub trait Handle {
} }
fn readdir<'a>( fn readdir<'a>(
&'a self, &'a self,
_cookie: types::Dircookie, _cookie: Dircookie,
) -> Result<Box<dyn Iterator<Item = Result<(types::Dirent, String)>> + 'a>> { ) -> Result<Box<dyn Iterator<Item = Result<(Dirent, String)>> + 'a>> {
Err(Error::Badf) Err(Error::Badf)
} }
fn seek(&self, _offset: SeekFrom) -> Result<u64> { fn seek(&self, _offset: SeekFrom) -> Result<u64> {
@@ -164,15 +162,15 @@ pub trait Handle {
fn create_directory(&self, _path: &str) -> Result<()> { fn create_directory(&self, _path: &str) -> Result<()> {
Err(Error::Acces) Err(Error::Acces)
} }
fn filestat_get_at(&self, _path: &str, _follow: bool) -> Result<types::Filestat> { fn filestat_get_at(&self, _path: &str, _follow: bool) -> Result<Filestat> {
Err(Error::Acces) Err(Error::Acces)
} }
fn filestat_set_times_at( fn filestat_set_times_at(
&self, &self,
_path: &str, _path: &str,
_atim: types::Timestamp, _atim: Timestamp,
_mtim: types::Timestamp, _mtim: Timestamp,
_fst_flags: types::Fstflags, _fst_flags: Fstflags,
_follow: bool, _follow: bool,
) -> Result<()> { ) -> Result<()> {
Err(Error::Acces) Err(Error::Acces)
@@ -182,8 +180,8 @@ pub trait Handle {
_path: &str, _path: &str,
_read: bool, _read: bool,
_write: bool, _write: bool,
_oflags: types::Oflags, _oflags: Oflags,
_fd_flags: types::Fdflags, _fd_flags: Fdflags,
) -> Result<Box<dyn Handle>> { ) -> Result<Box<dyn Handle>> {
Err(Error::Acces) Err(Error::Acces)
} }
@@ -215,3 +213,148 @@ pub trait Handle {
Err(Error::Acces) Err(Error::Acces)
} }
} }
impl From<std::fs::FileType> for Filetype {
fn from(ftype: std::fs::FileType) -> Self {
if ftype.is_file() {
Self::RegularFile
} else if ftype.is_dir() {
Self::Directory
} else if ftype.is_symlink() {
Self::SymbolicLink
} else {
Self::Unknown
}
}
}
pub(crate) trait AsBytes {
fn as_bytes(&self) -> Result<Vec<u8>>;
}
impl AsBytes for Dirent {
fn as_bytes(&self) -> Result<Vec<u8>> {
use std::convert::TryInto;
use wiggle::GuestType;
assert_eq!(
Self::guest_size(),
std::mem::size_of::<Self>() as _,
"guest repr of Dirent and host repr should match"
);
let offset = Self::guest_size().try_into()?;
let mut bytes: Vec<u8> = Vec::with_capacity(offset);
bytes.resize(offset, 0);
let ptr = bytes.as_mut_ptr() as *mut Self;
unsafe { ptr.write_unaligned(self.clone()) };
Ok(bytes)
}
}
pub(crate) trait RightsExt: Sized {
fn block_device_base() -> Self;
fn block_device_inheriting() -> Self;
fn character_device_base() -> Self;
fn character_device_inheriting() -> Self;
fn directory_base() -> Self;
fn directory_inheriting() -> Self;
fn regular_file_base() -> Self;
fn regular_file_inheriting() -> Self;
fn socket_base() -> Self;
fn socket_inheriting() -> Self;
fn tty_base() -> Self;
fn tty_inheriting() -> Self;
}
impl RightsExt for Rights {
// Block and character device interaction is outside the scope of
// WASI. Simply allow everything.
fn block_device_base() -> Self {
Self::all()
}
fn block_device_inheriting() -> Self {
Self::all()
}
fn character_device_base() -> Self {
Self::all()
}
fn character_device_inheriting() -> Self {
Self::all()
}
// Only allow directory operations on directories. Directories can only
// yield file descriptors to other directories and files.
fn directory_base() -> Self {
Self::FD_FDSTAT_SET_FLAGS
| Self::FD_SYNC
| Self::FD_ADVISE
| Self::PATH_CREATE_DIRECTORY
| Self::PATH_CREATE_FILE
| Self::PATH_LINK_SOURCE
| Self::PATH_LINK_TARGET
| Self::PATH_OPEN
| Self::FD_READDIR
| Self::PATH_READLINK
| Self::PATH_RENAME_SOURCE
| Self::PATH_RENAME_TARGET
| Self::PATH_FILESTAT_GET
| Self::PATH_FILESTAT_SET_SIZE
| Self::PATH_FILESTAT_SET_TIMES
| Self::FD_FILESTAT_GET
| Self::FD_FILESTAT_SET_TIMES
| Self::PATH_SYMLINK
| Self::PATH_UNLINK_FILE
| Self::PATH_REMOVE_DIRECTORY
| Self::POLL_FD_READWRITE
}
fn directory_inheriting() -> Self {
Self::all() ^ Self::SOCK_SHUTDOWN
}
// Operations that apply to regular files.
fn regular_file_base() -> Self {
Self::FD_DATASYNC
| Self::FD_READ
| Self::FD_SEEK
| Self::FD_FDSTAT_SET_FLAGS
| Self::FD_SYNC
| Self::FD_TELL
| Self::FD_WRITE
| Self::FD_ADVISE
| Self::FD_ALLOCATE
| Self::FD_FILESTAT_GET
| Self::FD_FILESTAT_SET_SIZE
| Self::FD_FILESTAT_SET_TIMES
| Self::POLL_FD_READWRITE
}
fn regular_file_inheriting() -> Self {
Self::empty()
}
// Operations that apply to sockets and socket pairs.
fn socket_base() -> Self {
Self::FD_READ
| Self::FD_FDSTAT_SET_FLAGS
| Self::FD_WRITE
| Self::FD_FILESTAT_GET
| Self::POLL_FD_READWRITE
| Self::SOCK_SHUTDOWN
}
fn socket_inheriting() -> Self {
Self::all()
}
// Operations that apply to TTYs.
fn tty_base() -> Self {
Self::FD_READ
| Self::FD_FDSTAT_SET_FLAGS
| Self::FD_WRITE
| Self::FD_FILESTAT_GET
| Self::POLL_FD_READWRITE
}
fn tty_inheriting() -> Self {
Self::empty()
}
}
pub(crate) const DIRCOOKIE_START: Dircookie = 0;

View File

@@ -1,9 +1,9 @@
use crate::entry::{Entry, EntryHandle}; use crate::entry::{Entry, EntryHandle};
use crate::handle::HandleRights; use crate::handle::{AsBytes, HandleRights};
use crate::sys::clock; use crate::sys::{clock, poll};
use crate::wasi::types;
use crate::wasi::wasi_snapshot_preview1::WasiSnapshotPreview1; use crate::wasi::wasi_snapshot_preview1::WasiSnapshotPreview1;
use crate::wasi::{types, AsBytes}; use crate::{path, sched, Error, Result, WasiCtx};
use crate::{path, poll, Error, Result, WasiCtx};
use std::convert::TryInto; use std::convert::TryInto;
use std::io::{self, SeekFrom}; use std::io::{self, SeekFrom};
use std::ops::Deref; use std::ops::Deref;
@@ -681,7 +681,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
} }
let mut events = Vec::new(); let mut events = Vec::new();
let mut timeout: Option<poll::ClockEventData> = None; let mut timeout: Option<sched::ClockEventData> = None;
let mut fd_events = Vec::new(); let mut fd_events = Vec::new();
// As mandated by the WASI spec: // As mandated by the WASI spec:
@@ -699,7 +699,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
delay_ns = tracing::field::debug(delay), delay_ns = tracing::field::debug(delay),
"poll_oneoff" "poll_oneoff"
); );
let current = poll::ClockEventData { let current = sched::ClockEventData {
delay, delay,
userdata: subscription.userdata, userdata: subscription.userdata,
}; };
@@ -728,7 +728,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
continue; continue;
} }
}; };
fd_events.push(poll::FdEventData { fd_events.push(sched::FdEventData {
handle: entry.as_handle(&required_rights)?, handle: entry.as_handle(&required_rights)?,
r#type: types::Eventtype::FdRead, r#type: types::Eventtype::FdRead,
userdata: subscription.userdata, userdata: subscription.userdata,
@@ -754,7 +754,7 @@ impl<'a> WasiSnapshotPreview1 for WasiCtx {
continue; continue;
} }
}; };
fd_events.push(poll::FdEventData { fd_events.push(sched::FdEventData {
handle: entry.as_handle(&required_rights)?, handle: entry.as_handle(&required_rights)?,
r#type: types::Eventtype::FdWrite, r#type: types::Eventtype::FdWrite,
userdata: subscription.userdata, userdata: subscription.userdata,

View File

@@ -1,4 +1,4 @@
use crate::{Error, Result, WasiCtx}; use crate::{Error, WasiCtx};
use tracing::debug; use tracing::debug;
wiggle::from_witx!({ wiggle::from_witx!({
@@ -88,151 +88,6 @@ impl From<wiggle::GuestError> for Errno {
} }
} }
impl From<std::fs::FileType> for types::Filetype {
fn from(ftype: std::fs::FileType) -> Self {
if ftype.is_file() {
Self::RegularFile
} else if ftype.is_dir() {
Self::Directory
} else if ftype.is_symlink() {
Self::SymbolicLink
} else {
Self::Unknown
}
}
}
pub(crate) trait AsBytes {
fn as_bytes(&self) -> Result<Vec<u8>>;
}
impl AsBytes for types::Dirent {
fn as_bytes(&self) -> Result<Vec<u8>> {
use std::convert::TryInto;
use wiggle::GuestType;
assert_eq!(
Self::guest_size(),
std::mem::size_of::<Self>() as _,
"guest repr of types::Dirent and host repr should match"
);
let offset = Self::guest_size().try_into()?;
let mut bytes: Vec<u8> = Vec::with_capacity(offset);
bytes.resize(offset, 0);
let ptr = bytes.as_mut_ptr() as *mut Self;
unsafe { ptr.write_unaligned(self.clone()) };
Ok(bytes)
}
}
pub(crate) trait RightsExt: Sized {
fn block_device_base() -> Self;
fn block_device_inheriting() -> Self;
fn character_device_base() -> Self;
fn character_device_inheriting() -> Self;
fn directory_base() -> Self;
fn directory_inheriting() -> Self;
fn regular_file_base() -> Self;
fn regular_file_inheriting() -> Self;
fn socket_base() -> Self;
fn socket_inheriting() -> Self;
fn tty_base() -> Self;
fn tty_inheriting() -> Self;
}
impl RightsExt for types::Rights {
// Block and character device interaction is outside the scope of
// WASI. Simply allow everything.
fn block_device_base() -> Self {
Self::all()
}
fn block_device_inheriting() -> Self {
Self::all()
}
fn character_device_base() -> Self {
Self::all()
}
fn character_device_inheriting() -> Self {
Self::all()
}
// Only allow directory operations on directories. Directories can only
// yield file descriptors to other directories and files.
fn directory_base() -> Self {
Self::FD_FDSTAT_SET_FLAGS
| Self::FD_SYNC
| Self::FD_ADVISE
| Self::PATH_CREATE_DIRECTORY
| Self::PATH_CREATE_FILE
| Self::PATH_LINK_SOURCE
| Self::PATH_LINK_TARGET
| Self::PATH_OPEN
| Self::FD_READDIR
| Self::PATH_READLINK
| Self::PATH_RENAME_SOURCE
| Self::PATH_RENAME_TARGET
| Self::PATH_FILESTAT_GET
| Self::PATH_FILESTAT_SET_SIZE
| Self::PATH_FILESTAT_SET_TIMES
| Self::FD_FILESTAT_GET
| Self::FD_FILESTAT_SET_TIMES
| Self::PATH_SYMLINK
| Self::PATH_UNLINK_FILE
| Self::PATH_REMOVE_DIRECTORY
| Self::POLL_FD_READWRITE
}
fn directory_inheriting() -> Self {
Self::all() ^ Self::SOCK_SHUTDOWN
}
// Operations that apply to regular files.
fn regular_file_base() -> Self {
Self::FD_DATASYNC
| Self::FD_READ
| Self::FD_SEEK
| Self::FD_FDSTAT_SET_FLAGS
| Self::FD_SYNC
| Self::FD_TELL
| Self::FD_WRITE
| Self::FD_ADVISE
| Self::FD_ALLOCATE
| Self::FD_FILESTAT_GET
| Self::FD_FILESTAT_SET_SIZE
| Self::FD_FILESTAT_SET_TIMES
| Self::POLL_FD_READWRITE
}
fn regular_file_inheriting() -> Self {
Self::empty()
}
// Operations that apply to sockets and socket pairs.
fn socket_base() -> Self {
Self::FD_READ
| Self::FD_FDSTAT_SET_FLAGS
| Self::FD_WRITE
| Self::FD_FILESTAT_GET
| Self::POLL_FD_READWRITE
| Self::SOCK_SHUTDOWN
}
fn socket_inheriting() -> Self {
Self::all()
}
// Operations that apply to TTYs.
fn tty_base() -> Self {
Self::FD_READ
| Self::FD_FDSTAT_SET_FLAGS
| Self::FD_WRITE
| Self::FD_FILESTAT_GET
| Self::POLL_FD_READWRITE
}
fn tty_inheriting() -> Self {
Self::empty()
}
}
pub(crate) const DIRCOOKIE_START: types::Dircookie = 0;
impl crate::fdpool::Fd for types::Fd { impl crate::fdpool::Fd for types::Fd {
fn as_raw(&self) -> u32 { fn as_raw(&self) -> u32 {
(*self).into() (*self).into()