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 std::any::Any;
use std::fmt;
use std::io::{self, SeekFrom};
#[derive(Debug, Copy, Clone)]
pub struct HandleRights {
pub(crate) base: Rights,
pub(crate) inheriting: Rights,
}
impl HandleRights {
pub fn new(base: Rights, inheriting: Rights) -> Self {
Self { base, inheriting }
}
pub fn from_base(base: Rights) -> Self {
Self {
base,
inheriting: Rights::empty(),
}
}
pub fn empty() -> Self {
Self {
base: Rights::empty(),
inheriting: Rights::empty(),
}
}
pub fn contains(&self, other: &Self) -> bool {
self.base.contains(&other.base) && self.inheriting.contains(&other.inheriting)
}
pub fn base(&self) -> Rights {
self.base
}
pub fn inheriting(&self) -> Rights {
self.inheriting
}
}
impl fmt::Display for HandleRights {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"HandleRights {{ base: {}, inheriting: {} }}",
self.base, self.inheriting
)
}
}
pub trait Handle {
fn as_any(&self) -> &dyn Any;
fn try_clone(&self) -> io::Result<Box<dyn Handle>>;
fn get_file_type(&self) -> Filetype;
fn get_rights(&self) -> HandleRights {
HandleRights::empty()
}
fn set_rights(&self, rights: HandleRights);
fn is_directory(&self) -> bool {
self.get_file_type() == Filetype::Directory
}
fn is_tty(&self) -> bool {
let file_type = self.get_file_type();
let rights = self.get_rights();
let required_rights = HandleRights::from_base(Rights::FD_SEEK | Rights::FD_TELL);
file_type == Filetype::CharacterDevice && rights.contains(&required_rights)
}
fn advise(&self, _advice: Advice, _offset: Filesize, _len: Filesize) -> Result<()> {
Err(Error::Badf)
}
fn allocate(&self, _offset: Filesize, _len: Filesize) -> Result<()> {
Err(Error::Badf)
}
fn datasync(&self) -> Result<()> {
Err(Error::Inval)
}
fn fdstat_get(&self) -> Result<Fdflags> {
Ok(Fdflags::empty())
}
fn fdstat_set_flags(&self, _fdflags: Fdflags) -> Result<()> {
Err(Error::Badf)
}
fn filestat_get(&self) -> Result<Filestat> {
Err(Error::Badf)
}
fn filestat_set_size(&self, _st_size: Filesize) -> Result<()> {
Err(Error::Badf)
}
fn filestat_set_times(
&self,
_atim: Timestamp,
_mtim: Timestamp,
_fst_flags: Fstflags,
) -> Result<()> {
Err(Error::Badf)
}
fn preadv(&self, _buf: &mut [io::IoSliceMut], _offset: u64) -> Result<usize> {
Err(Error::Badf)
}
fn pwritev(&self, _buf: &[io::IoSlice], _offset: u64) -> Result<usize> {
Err(Error::Badf)
}
fn read_vectored(&self, _iovs: &mut [io::IoSliceMut]) -> Result<usize> {
Err(Error::Badf)
}
fn readdir<'a>(
&'a self,
_cookie: Dircookie,
) -> Result<Box<dyn Iterator<Item = Result<(Dirent, String)>> + 'a>> {
Err(Error::Badf)
}
fn seek(&self, _offset: SeekFrom) -> Result<u64> {
Err(Error::Badf)
}
fn sync(&self) -> Result<()> {
Ok(())
}
fn write_vectored(&self, _iovs: &[io::IoSlice]) -> Result<usize> {
Err(Error::Badf)
}
fn create_directory(&self, _path: &str) -> Result<()> {
Err(Error::Acces)
}
fn filestat_get_at(&self, _path: &str, _follow: bool) -> Result<Filestat> {
Err(Error::Acces)
}
fn filestat_set_times_at(
&self,
_path: &str,
_atim: Timestamp,
_mtim: Timestamp,
_fst_flags: Fstflags,
_follow: bool,
) -> Result<()> {
Err(Error::Acces)
}
fn openat(
&self,
_path: &str,
_read: bool,
_write: bool,
_oflags: Oflags,
_fd_flags: Fdflags,
) -> Result<Box<dyn Handle>> {
Err(Error::Acces)
}
fn link(
&self,
_old_path: &str,
_new_handle: Box<dyn Handle>,
_new_path: &str,
_follow: bool,
) -> Result<()> {
Err(Error::Acces)
}
fn readlink(&self, _path: &str, _buf: &mut [u8]) -> Result<usize> {
Err(Error::Acces)
}
fn readlinkat(&self, _path: &str) -> Result<String> {
Err(Error::Acces)
}
fn remove_directory(&self, _path: &str) -> Result<()> {
Err(Error::Acces)
}
fn rename(&self, _old_path: &str, _new_handle: Box<dyn Handle>, _new_path: &str) -> Result<()> {
Err(Error::Acces)
}
fn symlink(&self, _old_path: &str, _new_path: &str) -> Result<()> {
Err(Error::Acces)
}
fn unlink_file(&self, _path: &str) -> Result<()> {
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 {
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()
}
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
}
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()
}
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()
}
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;