Merge pull request #2201 from bytecodealliance/pch/wasi_common_move_type_imports
wasi-common: code motion around type imports
This commit is contained in:
@@ -6,7 +6,7 @@ use crate::sys::osdir::OsDir;
|
|||||||
use crate::sys::stdio::NullDevice;
|
use crate::sys::stdio::NullDevice;
|
||||||
use crate::sys::stdio::{Stderr, StderrExt, Stdin, StdinExt, Stdout, StdoutExt};
|
use crate::sys::stdio::{Stderr, StderrExt, Stdin, StdinExt, Stdout, StdoutExt};
|
||||||
use crate::virtfs::{VirtualDir, VirtualDirEntry};
|
use crate::virtfs::{VirtualDir, VirtualDirEntry};
|
||||||
use crate::wasi::types;
|
use crate::wasi::types::Fd;
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
@@ -331,7 +331,7 @@ impl WasiCtxBuilder {
|
|||||||
|
|
||||||
struct EntryTable {
|
struct EntryTable {
|
||||||
fd_pool: FdPool,
|
fd_pool: FdPool,
|
||||||
entries: HashMap<types::Fd, Rc<Entry>>,
|
entries: HashMap<Fd, Rc<Entry>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntryTable {
|
impl EntryTable {
|
||||||
@@ -342,25 +342,25 @@ impl EntryTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains(&self, fd: &types::Fd) -> bool {
|
fn contains(&self, fd: &Fd) -> bool {
|
||||||
self.entries.contains_key(fd)
|
self.entries.contains_key(fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&mut self, entry: Entry) -> Option<types::Fd> {
|
fn insert(&mut self, entry: Entry) -> Option<Fd> {
|
||||||
let fd = self.fd_pool.allocate()?;
|
let fd = self.fd_pool.allocate()?;
|
||||||
self.entries.insert(fd, Rc::new(entry));
|
self.entries.insert(fd, Rc::new(entry));
|
||||||
Some(fd)
|
Some(fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_at(&mut self, fd: &types::Fd, entry: Rc<Entry>) {
|
fn insert_at(&mut self, fd: &Fd, entry: Rc<Entry>) {
|
||||||
self.entries.insert(*fd, entry);
|
self.entries.insert(*fd, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, fd: &types::Fd) -> Option<Rc<Entry>> {
|
fn get(&self, fd: &Fd) -> Option<Rc<Entry>> {
|
||||||
self.entries.get(fd).map(Rc::clone)
|
self.entries.get(fd).map(Rc::clone)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove(&mut self, fd: types::Fd) -> Option<Rc<Entry>> {
|
fn remove(&mut self, fd: Fd) -> Option<Rc<Entry>> {
|
||||||
let entry = self.entries.remove(&fd)?;
|
let entry = self.entries.remove(&fd)?;
|
||||||
self.fd_pool.deallocate(fd);
|
self.fd_pool.deallocate(fd);
|
||||||
Some(entry)
|
Some(entry)
|
||||||
@@ -390,12 +390,12 @@ impl WasiCtx {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check if `WasiCtx` contains the specified raw WASI `fd`.
|
/// Check if `WasiCtx` contains the specified raw WASI `fd`.
|
||||||
pub(crate) fn contains_entry(&self, fd: types::Fd) -> bool {
|
pub(crate) fn contains_entry(&self, fd: Fd) -> bool {
|
||||||
self.entries.borrow().contains(&fd)
|
self.entries.borrow().contains(&fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an immutable `Entry` corresponding to the specified raw WASI `fd`.
|
/// Get an immutable `Entry` corresponding to the specified raw WASI `fd`.
|
||||||
pub(crate) fn get_entry(&self, fd: types::Fd) -> Result<Rc<Entry>, Error> {
|
pub(crate) fn get_entry(&self, fd: Fd) -> Result<Rc<Entry>, Error> {
|
||||||
match self.entries.borrow().get(&fd) {
|
match self.entries.borrow().get(&fd) {
|
||||||
Some(entry) => Ok(entry),
|
Some(entry) => Ok(entry),
|
||||||
None => Err(Error::Badf),
|
None => Err(Error::Badf),
|
||||||
@@ -406,18 +406,18 @@ impl WasiCtx {
|
|||||||
///
|
///
|
||||||
/// The `Entry` will automatically get another free raw WASI `fd` assigned. Note that
|
/// The `Entry` will automatically get another free raw WASI `fd` assigned. Note that
|
||||||
/// the two subsequent free raw WASI `fd`s do not have to be stored contiguously.
|
/// the two subsequent free raw WASI `fd`s do not have to be stored contiguously.
|
||||||
pub(crate) fn insert_entry(&self, entry: Entry) -> Result<types::Fd, Error> {
|
pub(crate) fn insert_entry(&self, entry: Entry) -> Result<Fd, Error> {
|
||||||
self.entries.borrow_mut().insert(entry).ok_or(Error::Mfile)
|
self.entries.borrow_mut().insert(entry).ok_or(Error::Mfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert the specified `Entry` with the specified raw WASI `fd` key into the `WasiCtx`
|
/// Insert the specified `Entry` with the specified raw WASI `fd` key into the `WasiCtx`
|
||||||
/// object.
|
/// object.
|
||||||
pub(crate) fn insert_entry_at(&self, fd: types::Fd, entry: Rc<Entry>) {
|
pub(crate) fn insert_entry_at(&self, fd: Fd, entry: Rc<Entry>) {
|
||||||
self.entries.borrow_mut().insert_at(&fd, entry)
|
self.entries.borrow_mut().insert_at(&fd, entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove `Entry` corresponding to the specified raw WASI `fd` from the `WasiCtx` object.
|
/// Remove `Entry` corresponding to the specified raw WASI `fd` from the `WasiCtx` object.
|
||||||
pub(crate) fn remove_entry(&self, fd: types::Fd) -> Result<Rc<Entry>, Error> {
|
pub(crate) fn remove_entry(&self, fd: Fd) -> Result<Rc<Entry>, Error> {
|
||||||
self.entries.borrow_mut().remove(fd).ok_or(Error::Badf)
|
self.entries.borrow_mut().remove(fd).ok_or(Error::Badf)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
use crate::handle::{Handle, HandleRights};
|
use crate::handle::{Filetype, Handle, HandleRights};
|
||||||
use crate::wasi::types::Filetype;
|
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::ops::Deref;
|
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)]
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use crate::fs::{File, OpenOptions, ReadDir};
|
use crate::fs::{Fd, File, OpenOptions, ReadDir};
|
||||||
use crate::wasi::types;
|
|
||||||
use crate::wasi::wasi_snapshot_preview1::WasiSnapshotPreview1;
|
use crate::wasi::wasi_snapshot_preview1::WasiSnapshotPreview1;
|
||||||
use crate::WasiCtx;
|
use crate::WasiCtx;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@@ -18,12 +17,12 @@ use std::{io, path::Path};
|
|||||||
/// don't interoperate well with the capability-oriented security model.
|
/// don't interoperate well with the capability-oriented security model.
|
||||||
pub struct Dir<'ctx> {
|
pub struct Dir<'ctx> {
|
||||||
ctx: &'ctx WasiCtx,
|
ctx: &'ctx WasiCtx,
|
||||||
fd: types::Fd,
|
fd: Fd,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> Dir<'ctx> {
|
impl<'ctx> Dir<'ctx> {
|
||||||
/// Constructs a new instance of `Self` from the given raw WASI file descriptor.
|
/// Constructs a new instance of `Self` from the given raw WASI file descriptor.
|
||||||
pub unsafe fn from_raw_wasi_fd(ctx: &'ctx WasiCtx, fd: types::Fd) -> Self {
|
pub unsafe fn from_raw_wasi_fd(ctx: &'ctx WasiCtx, fd: Fd) -> Self {
|
||||||
Self { ctx, fd }
|
Self { ctx, fd }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +38,7 @@ impl<'ctx> Dir<'ctx> {
|
|||||||
/// [`std::fs::File::open`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.open
|
/// [`std::fs::File::open`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.open
|
||||||
pub fn open_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<File> {
|
pub fn open_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<File> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let mut fd = types::Fd::from(0);
|
let mut fd = Fd::from(0);
|
||||||
|
|
||||||
// TODO: Refactor the hostcalls functions to split out the encoding/decoding
|
// TODO: Refactor the hostcalls functions to split out the encoding/decoding
|
||||||
// parts from the underlying functionality, so that we can call into the
|
// parts from the underlying functionality, so that we can call into the
|
||||||
@@ -92,7 +91,7 @@ impl<'ctx> Dir<'ctx> {
|
|||||||
/// TODO: Not yet implemented. See the comment in `open_file`.
|
/// TODO: Not yet implemented. See the comment in `open_file`.
|
||||||
pub fn open_dir<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Self> {
|
pub fn open_dir<P: AsRef<Path>>(&mut self, path: P) -> io::Result<Self> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let mut fd = types::Fd::from(0);
|
let mut fd = Fd::from(0);
|
||||||
|
|
||||||
// TODO: See the comment in `open_file`.
|
// TODO: See the comment in `open_file`.
|
||||||
unimplemented!("Dir::open_dir");
|
unimplemented!("Dir::open_dir");
|
||||||
@@ -124,7 +123,7 @@ impl<'ctx> Dir<'ctx> {
|
|||||||
/// [`std::fs::File::create`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.create
|
/// [`std::fs::File::create`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.create
|
||||||
pub fn create_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<File> {
|
pub fn create_file<P: AsRef<Path>>(&mut self, path: P) -> io::Result<File> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
let mut fd = types::Fd::from(0);
|
let mut fd = Fd::from(0);
|
||||||
|
|
||||||
// TODO: See the comments in `open_file`.
|
// TODO: See the comments in `open_file`.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use crate::fs::Metadata;
|
use crate::fs::{Fd, Metadata};
|
||||||
use crate::wasi::types;
|
|
||||||
use crate::wasi::wasi_snapshot_preview1::WasiSnapshotPreview1;
|
use crate::wasi::wasi_snapshot_preview1::WasiSnapshotPreview1;
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use crate::WasiCtx;
|
use crate::WasiCtx;
|
||||||
@@ -19,7 +18,7 @@ use std::io;
|
|||||||
/// [`Dir::create_file`]: struct.Dir.html#method.create_file
|
/// [`Dir::create_file`]: struct.Dir.html#method.create_file
|
||||||
pub struct File<'ctx> {
|
pub struct File<'ctx> {
|
||||||
ctx: &'ctx WasiCtx,
|
ctx: &'ctx WasiCtx,
|
||||||
fd: types::Fd,
|
fd: Fd,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'ctx> File<'ctx> {
|
impl<'ctx> File<'ctx> {
|
||||||
@@ -28,7 +27,7 @@ impl<'ctx> File<'ctx> {
|
|||||||
/// This corresponds to [`std::fs::File::from_raw_fd`].
|
/// This corresponds to [`std::fs::File::from_raw_fd`].
|
||||||
///
|
///
|
||||||
/// [`std::fs::File::from_raw_fd`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.from_raw_fd
|
/// [`std::fs::File::from_raw_fd`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.from_raw_fd
|
||||||
pub unsafe fn from_raw_wasi_fd(ctx: &'ctx WasiCtx, fd: types::Fd) -> Self {
|
pub unsafe fn from_raw_wasi_fd(ctx: &'ctx WasiCtx, fd: Fd) -> Self {
|
||||||
Self { ctx, fd }
|
Self { ctx, fd }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +88,7 @@ impl<'ctx> io::Read for File<'ctx> {
|
|||||||
/// TODO: Not yet implemented. See the comment in `Dir::open_file`.
|
/// TODO: Not yet implemented. See the comment in `Dir::open_file`.
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
// TODO
|
// TODO
|
||||||
// let iov = [types::Iovec {
|
// let iov = [Iovec {
|
||||||
// buf: buf.as_mut_ptr() as *mut u8,
|
// buf: buf.as_mut_ptr() as *mut u8,
|
||||||
// buf_len: buf.len(),
|
// buf_len: buf.len(),
|
||||||
// }];
|
// }];
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ mod open_options;
|
|||||||
mod permissions;
|
mod permissions;
|
||||||
mod readdir;
|
mod readdir;
|
||||||
|
|
||||||
|
pub use crate::wasi::types::Fd;
|
||||||
|
|
||||||
pub use dir::*;
|
pub use dir::*;
|
||||||
pub use dir_builder::*;
|
pub use dir_builder::*;
|
||||||
pub use dir_entry::*;
|
pub use dir_entry::*;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use crate::fs::DirEntry;
|
use crate::fs::{DirEntry, Fd};
|
||||||
use crate::wasi::types;
|
|
||||||
|
|
||||||
/// Iterator over the entries in a directory.
|
/// Iterator over the entries in a directory.
|
||||||
///
|
///
|
||||||
@@ -9,12 +8,12 @@ use crate::wasi::types;
|
|||||||
///
|
///
|
||||||
/// [`std::fs::ReadDir`]: https://doc.rust-lang.org/std/fs/struct.ReadDir.html
|
/// [`std::fs::ReadDir`]: https://doc.rust-lang.org/std/fs/struct.ReadDir.html
|
||||||
pub struct ReadDir {
|
pub struct ReadDir {
|
||||||
fd: types::Fd,
|
fd: Fd,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReadDir {
|
impl ReadDir {
|
||||||
/// Constructs a new instance of `Self` from the given raw WASI file descriptor.
|
/// Constructs a new instance of `Self` from the given raw WASI file descriptor.
|
||||||
pub unsafe fn from_raw_wasi_fd(fd: types::Fd) -> Self {
|
pub unsafe fn from_raw_wasi_fd(fd: Fd) -> Self {
|
||||||
Self { fd }
|
Self { fd }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ pub mod fs;
|
|||||||
mod handle;
|
mod handle;
|
||||||
pub mod old;
|
pub mod old;
|
||||||
mod path;
|
mod path;
|
||||||
mod poll;
|
|
||||||
mod sandboxed_tty_writer;
|
mod sandboxed_tty_writer;
|
||||||
|
pub(crate) mod sched;
|
||||||
pub mod snapshots;
|
pub mod snapshots;
|
||||||
mod string_array;
|
mod string_array;
|
||||||
mod sys;
|
mod sys;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use crate::entry::Entry;
|
use crate::entry::Entry;
|
||||||
use crate::handle::{Handle, HandleRights};
|
use crate::handle::{Fdflags, Filetype, Handle, HandleRights, Lookupflags, Oflags};
|
||||||
use crate::wasi::types;
|
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::path::{Component, Path};
|
use std::path::{Component, Path};
|
||||||
use std::str;
|
use std::str;
|
||||||
@@ -13,7 +12,7 @@ pub(crate) use crate::sys::path::{from_host, open_rights};
|
|||||||
pub(crate) fn get(
|
pub(crate) fn get(
|
||||||
entry: &Entry,
|
entry: &Entry,
|
||||||
required_rights: &HandleRights,
|
required_rights: &HandleRights,
|
||||||
dirflags: types::Lookupflags,
|
dirflags: Lookupflags,
|
||||||
path: &str,
|
path: &str,
|
||||||
needs_final_component: bool,
|
needs_final_component: bool,
|
||||||
) -> Result<(Box<dyn Handle>, String)> {
|
) -> Result<(Box<dyn Handle>, String)> {
|
||||||
@@ -26,7 +25,7 @@ pub(crate) fn get(
|
|||||||
return Err(Error::Ilseq);
|
return Err(Error::Ilseq);
|
||||||
}
|
}
|
||||||
|
|
||||||
if entry.get_file_type() != types::Filetype::Directory {
|
if entry.get_file_type() != Filetype::Directory {
|
||||||
// if `dirfd` doesn't refer to a directory, return `Notdir`.
|
// if `dirfd` doesn't refer to a directory, return `Notdir`.
|
||||||
return Err(Error::Notdir);
|
return Err(Error::Notdir);
|
||||||
}
|
}
|
||||||
@@ -102,8 +101,8 @@ pub(crate) fn get(
|
|||||||
&head,
|
&head,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
types::Oflags::DIRECTORY,
|
Oflags::DIRECTORY,
|
||||||
types::Fdflags::empty(),
|
Fdflags::empty(),
|
||||||
) {
|
) {
|
||||||
Ok(new_dir) => {
|
Ok(new_dir) => {
|
||||||
dir_stack.push(new_dir);
|
dir_stack.push(new_dir);
|
||||||
@@ -141,8 +140,7 @@ pub(crate) fn get(
|
|||||||
}
|
}
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
} else if ends_with_slash
|
} else if ends_with_slash || dirflags.contains(&Lookupflags::SYMLINK_FOLLOW)
|
||||||
|| dirflags.contains(&types::Lookupflags::SYMLINK_FOLLOW)
|
|
||||||
{
|
{
|
||||||
// if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt
|
// if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt
|
||||||
// symlink expansion
|
// symlink expansion
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
use crate::entry::EntryHandle;
|
|
||||||
use crate::wasi::types;
|
|
||||||
|
|
||||||
pub(crate) use crate::sys::poll::*;
|
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
|
||||||
pub(crate) struct ClockEventData {
|
|
||||||
pub(crate) delay: u128, // delay is expressed in nanoseconds
|
|
||||||
pub(crate) userdata: types::Userdata,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub(crate) struct FdEventData {
|
|
||||||
pub(crate) handle: EntryHandle,
|
|
||||||
pub(crate) r#type: types::Eventtype,
|
|
||||||
pub(crate) userdata: types::Userdata,
|
|
||||||
}
|
|
||||||
17
crates/wasi-common/src/sched.rs
Normal file
17
crates/wasi-common/src/sched.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
use crate::entry::EntryHandle;
|
||||||
|
pub use crate::wasi::types::{
|
||||||
|
Clockid, Errno, Event, EventFdReadwrite, Eventrwflags, Eventtype, Subclockflags,
|
||||||
|
SubscriptionClock, Timestamp, Userdata,
|
||||||
|
};
|
||||||
|
#[derive(Debug, Copy, Clone)]
|
||||||
|
pub struct ClockEventData {
|
||||||
|
pub delay: u128, // delay is expressed in nanoseconds
|
||||||
|
pub userdata: Userdata,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct FdEventData {
|
||||||
|
pub handle: EntryHandle,
|
||||||
|
pub r#type: Eventtype,
|
||||||
|
pub userdata: Userdata,
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::wasi::types::{Subclockflags, SubscriptionClock};
|
use crate::sched::{Subclockflags, SubscriptionClock};
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::wasi::types;
|
use crate::handle::{Fstflags, Timestamp};
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use filetime::{set_file_handle_times, FileTime};
|
use filetime::{set_file_handle_times, FileTime};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@@ -8,14 +8,14 @@ pub(crate) use super::sys_impl::fd::*;
|
|||||||
|
|
||||||
pub(crate) fn filestat_set_times(
|
pub(crate) fn filestat_set_times(
|
||||||
file: &File,
|
file: &File,
|
||||||
st_atim: types::Timestamp,
|
st_atim: Timestamp,
|
||||||
st_mtim: types::Timestamp,
|
st_mtim: Timestamp,
|
||||||
fst_flags: types::Fstflags,
|
fst_flags: Fstflags,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let set_atim = fst_flags.contains(&types::Fstflags::ATIM);
|
let set_atim = fst_flags.contains(&Fstflags::ATIM);
|
||||||
let set_atim_now = fst_flags.contains(&types::Fstflags::ATIM_NOW);
|
let set_atim_now = fst_flags.contains(&Fstflags::ATIM_NOW);
|
||||||
let set_mtim = fst_flags.contains(&types::Fstflags::MTIM);
|
let set_mtim = fst_flags.contains(&Fstflags::MTIM);
|
||||||
let set_mtim_now = fst_flags.contains(&types::Fstflags::MTIM_NOW);
|
let set_mtim_now = fst_flags.contains(&Fstflags::MTIM_NOW);
|
||||||
|
|
||||||
if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) {
|
if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) {
|
||||||
return Err(Error::Inval);
|
return Err(Error::Inval);
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ cfg_if! {
|
|||||||
pub(crate) use sys_impl::path;
|
pub(crate) use sys_impl::path;
|
||||||
pub(crate) use sys_impl::poll;
|
pub(crate) use sys_impl::poll;
|
||||||
|
|
||||||
use super::handle::Handle;
|
use super::handle::{Filetype, Handle};
|
||||||
use crate::wasi::types;
|
|
||||||
use osdir::OsDir;
|
use osdir::OsDir;
|
||||||
use osfile::OsFile;
|
use osfile::OsFile;
|
||||||
use osother::OsOther;
|
use osother::OsOther;
|
||||||
@@ -67,7 +66,7 @@ impl TryFrom<File> for Box<dyn Handle> {
|
|||||||
fn try_from(file: File) -> io::Result<Self> {
|
fn try_from(file: File) -> io::Result<Self> {
|
||||||
let file_type = get_file_type(&file)?;
|
let file_type = get_file_type(&file)?;
|
||||||
match file_type {
|
match file_type {
|
||||||
types::Filetype::RegularFile => {
|
Filetype::RegularFile => {
|
||||||
let handle = OsFile::try_from(file)?;
|
let handle = OsFile::try_from(file)?;
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
handle = tracing::field::debug(&handle),
|
handle = tracing::field::debug(&handle),
|
||||||
@@ -75,7 +74,7 @@ impl TryFrom<File> for Box<dyn Handle> {
|
|||||||
);
|
);
|
||||||
Ok(Box::new(handle))
|
Ok(Box::new(handle))
|
||||||
}
|
}
|
||||||
types::Filetype::Directory => {
|
Filetype::Directory => {
|
||||||
let handle = OsDir::try_from(file)?;
|
let handle = OsDir::try_from(file)?;
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
handle = tracing::field::debug(&handle),
|
handle = tracing::field::debug(&handle),
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
use super::sys_impl::oshandle::RawOsHandle;
|
use super::sys_impl::oshandle::RawOsHandle;
|
||||||
use super::{fd, path, AsFile};
|
use super::{fd, path, AsFile};
|
||||||
use crate::handle::{Handle, HandleRights};
|
use crate::handle::{
|
||||||
use crate::wasi::types;
|
Dircookie, Dirent, Fdflags, Filestat, Filetype, Fstflags, Handle, HandleRights, Oflags,
|
||||||
|
};
|
||||||
|
use crate::sched::Timestamp;
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -30,8 +32,8 @@ impl Handle for OsDir {
|
|||||||
let new = Self::new(self.rights.get(), handle)?;
|
let new = Self::new(self.rights.get(), handle)?;
|
||||||
Ok(Box::new(new))
|
Ok(Box::new(new))
|
||||||
}
|
}
|
||||||
fn get_file_type(&self) -> types::Filetype {
|
fn get_file_type(&self) -> Filetype {
|
||||||
types::Filetype::Directory
|
Filetype::Directory
|
||||||
}
|
}
|
||||||
fn get_rights(&self) -> HandleRights {
|
fn get_rights(&self) -> HandleRights {
|
||||||
self.rights.get()
|
self.rights.get()
|
||||||
@@ -40,45 +42,45 @@ impl Handle for OsDir {
|
|||||||
self.rights.set(rights)
|
self.rights.set(rights)
|
||||||
}
|
}
|
||||||
// FdOps
|
// FdOps
|
||||||
fn fdstat_get(&self) -> Result<types::Fdflags> {
|
fn fdstat_get(&self) -> Result<Fdflags> {
|
||||||
fd::fdstat_get(&*self.as_file()?)
|
fd::fdstat_get(&*self.as_file()?)
|
||||||
}
|
}
|
||||||
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
|
fn fdstat_set_flags(&self, fdflags: Fdflags) -> Result<()> {
|
||||||
if let Some(new_file) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
|
if let Some(new_file) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
|
||||||
self.handle.update_from(new_file);
|
self.handle.update_from(new_file);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn filestat_get(&self) -> Result<types::Filestat> {
|
fn filestat_get(&self) -> Result<Filestat> {
|
||||||
fd::filestat_get(&*self.as_file()?)
|
fd::filestat_get(&*self.as_file()?)
|
||||||
}
|
}
|
||||||
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<()> {
|
||||||
fd::filestat_set_times(&*self.as_file()?, atim, mtim, fst_flags)
|
fd::filestat_set_times(&*self.as_file()?, atim, mtim, fst_flags)
|
||||||
}
|
}
|
||||||
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>> {
|
||||||
fd::readdir(self, cookie)
|
fd::readdir(self, cookie)
|
||||||
}
|
}
|
||||||
// PathOps
|
// PathOps
|
||||||
fn create_directory(&self, path: &str) -> Result<()> {
|
fn create_directory(&self, path: &str) -> Result<()> {
|
||||||
path::create_directory(self, path)
|
path::create_directory(self, path)
|
||||||
}
|
}
|
||||||
fn filestat_get_at(&self, path: &str, follow: bool) -> Result<types::Filestat> {
|
fn filestat_get_at(&self, path: &str, follow: bool) -> Result<Filestat> {
|
||||||
path::filestat_get_at(self, path, follow)
|
path::filestat_get_at(self, path, follow)
|
||||||
}
|
}
|
||||||
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<()> {
|
||||||
path::filestat_set_times_at(self, path, atim, mtim, fst_flags, follow)
|
path::filestat_set_times_at(self, path, atim, mtim, fst_flags, follow)
|
||||||
@@ -88,8 +90,8 @@ impl Handle for OsDir {
|
|||||||
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>> {
|
||||||
path::open(self, path, read, write, oflags, fd_flags)
|
path::open(self, path, read, write, oflags, fd_flags)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
use super::sys_impl::oshandle::RawOsHandle;
|
use super::sys_impl::oshandle::RawOsHandle;
|
||||||
use super::{fd, AsFile};
|
use super::{fd, AsFile};
|
||||||
use crate::handle::{Handle, HandleRights};
|
use crate::handle::{
|
||||||
use crate::wasi::types;
|
Advice, Fdflags, Filesize, Filestat, Filetype, Fstflags, Handle, HandleRights,
|
||||||
|
};
|
||||||
|
use crate::sched::Timestamp;
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
@@ -56,8 +58,8 @@ impl Handle for OsFile {
|
|||||||
let rights = self.rights.clone();
|
let rights = self.rights.clone();
|
||||||
Ok(Box::new(Self { rights, handle }))
|
Ok(Box::new(Self { rights, handle }))
|
||||||
}
|
}
|
||||||
fn get_file_type(&self) -> types::Filetype {
|
fn get_file_type(&self) -> Filetype {
|
||||||
types::Filetype::RegularFile
|
Filetype::RegularFile
|
||||||
}
|
}
|
||||||
fn get_rights(&self) -> HandleRights {
|
fn get_rights(&self) -> HandleRights {
|
||||||
self.rights.get()
|
self.rights.get()
|
||||||
@@ -66,15 +68,10 @@ impl Handle for OsFile {
|
|||||||
self.rights.set(rights)
|
self.rights.set(rights)
|
||||||
}
|
}
|
||||||
// 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<()> {
|
|
||||||
fd::advise(self, advice, offset, len)
|
fd::advise(self, advice, offset, len)
|
||||||
}
|
}
|
||||||
fn allocate(&self, offset: types::Filesize, len: types::Filesize) -> Result<()> {
|
fn allocate(&self, offset: Filesize, len: Filesize) -> Result<()> {
|
||||||
let fd = self.as_file()?;
|
let fd = self.as_file()?;
|
||||||
let metadata = fd.metadata()?;
|
let metadata = fd.metadata()?;
|
||||||
let current_size = metadata.len();
|
let current_size = metadata.len();
|
||||||
@@ -92,27 +89,27 @@ impl Handle for OsFile {
|
|||||||
self.as_file()?.sync_data()?;
|
self.as_file()?.sync_data()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn fdstat_get(&self) -> Result<types::Fdflags> {
|
fn fdstat_get(&self) -> Result<Fdflags> {
|
||||||
fd::fdstat_get(&*self.as_file()?)
|
fd::fdstat_get(&*self.as_file()?)
|
||||||
}
|
}
|
||||||
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
|
fn fdstat_set_flags(&self, fdflags: Fdflags) -> Result<()> {
|
||||||
if let Some(new_handle) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
|
if let Some(new_handle) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
|
||||||
self.handle.update_from(new_handle);
|
self.handle.update_from(new_handle);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn filestat_get(&self) -> Result<types::Filestat> {
|
fn filestat_get(&self) -> Result<Filestat> {
|
||||||
fd::filestat_get(&*self.as_file()?)
|
fd::filestat_get(&*self.as_file()?)
|
||||||
}
|
}
|
||||||
fn filestat_set_size(&self, size: types::Filesize) -> Result<()> {
|
fn filestat_set_size(&self, size: Filesize) -> Result<()> {
|
||||||
self.as_file()?.set_len(size)?;
|
self.as_file()?.set_len(size)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
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<()> {
|
||||||
fd::filestat_set_times(&*self.as_file()?, atim, mtim, fst_flags)
|
fd::filestat_set_times(&*self.as_file()?, atim, mtim, fst_flags)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
use super::sys_impl::oshandle::RawOsHandle;
|
use super::sys_impl::oshandle::RawOsHandle;
|
||||||
use super::{fd, AsFile};
|
use super::{fd, AsFile};
|
||||||
use crate::handle::{Handle, HandleRights};
|
use crate::handle::{Fdflags, Filetype, Handle, HandleRights};
|
||||||
use crate::sandboxed_tty_writer::SandboxedTTYWriter;
|
use crate::sandboxed_tty_writer::SandboxedTTYWriter;
|
||||||
use crate::wasi::types::{self, Filetype};
|
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
@@ -79,10 +78,10 @@ impl Handle for OsOther {
|
|||||||
self.rights.set(new_rights)
|
self.rights.set(new_rights)
|
||||||
}
|
}
|
||||||
// FdOps
|
// FdOps
|
||||||
fn fdstat_get(&self) -> Result<types::Fdflags> {
|
fn fdstat_get(&self) -> Result<Fdflags> {
|
||||||
fd::fdstat_get(&*self.as_file()?)
|
fd::fdstat_get(&*self.as_file()?)
|
||||||
}
|
}
|
||||||
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
|
fn fdstat_set_flags(&self, fdflags: Fdflags) -> Result<()> {
|
||||||
if let Some(handle) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
|
if let Some(handle) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
|
||||||
self.handle.update_from(handle);
|
self.handle.update_from(handle);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,8 @@
|
|||||||
// TODO it might worth re-investigating the suitability of this type on Windows.
|
// TODO it might worth re-investigating the suitability of this type on Windows.
|
||||||
|
|
||||||
use super::{fd, AsFile};
|
use super::{fd, AsFile};
|
||||||
use crate::handle::{Handle, HandleRights};
|
use crate::handle::{Fdflags, Filetype, Handle, HandleRights, Rights, RightsExt, Size};
|
||||||
use crate::sandboxed_tty_writer::SandboxedTTYWriter;
|
use crate::sandboxed_tty_writer::SandboxedTTYWriter;
|
||||||
use crate::wasi::types::{self, Filetype};
|
|
||||||
use crate::wasi::RightsExt;
|
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
@@ -55,10 +53,10 @@ impl Handle for Stdin {
|
|||||||
self.rights.set(new_rights)
|
self.rights.set(new_rights)
|
||||||
}
|
}
|
||||||
// FdOps
|
// FdOps
|
||||||
fn fdstat_get(&self) -> Result<types::Fdflags> {
|
fn fdstat_get(&self) -> Result<Fdflags> {
|
||||||
fd::fdstat_get(&*self.as_file()?)
|
fd::fdstat_get(&*self.as_file()?)
|
||||||
}
|
}
|
||||||
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
|
fn fdstat_set_flags(&self, fdflags: Fdflags) -> Result<()> {
|
||||||
if let Some(_) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
|
if let Some(_) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
|
||||||
// OK, this means we should somehow update the underlying os handle,
|
// OK, this means we should somehow update the underlying os handle,
|
||||||
// and we can't do that with `std::io::std{in, out, err}`, so we'll
|
// and we can't do that with `std::io::std{in, out, err}`, so we'll
|
||||||
@@ -101,10 +99,10 @@ impl Handle for Stdout {
|
|||||||
self.rights.set(new_rights)
|
self.rights.set(new_rights)
|
||||||
}
|
}
|
||||||
// FdOps
|
// FdOps
|
||||||
fn fdstat_get(&self) -> Result<types::Fdflags> {
|
fn fdstat_get(&self) -> Result<Fdflags> {
|
||||||
fd::fdstat_get(&*self.as_file()?)
|
fd::fdstat_get(&*self.as_file()?)
|
||||||
}
|
}
|
||||||
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
|
fn fdstat_set_flags(&self, fdflags: Fdflags) -> Result<()> {
|
||||||
if let Some(_) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
|
if let Some(_) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
|
||||||
// OK, this means we should somehow update the underlying os handle,
|
// OK, this means we should somehow update the underlying os handle,
|
||||||
// and we can't do that with `std::io::std{in, out, err}`, so we'll
|
// and we can't do that with `std::io::std{in, out, err}`, so we'll
|
||||||
@@ -155,10 +153,10 @@ impl Handle for Stderr {
|
|||||||
self.rights.set(new_rights)
|
self.rights.set(new_rights)
|
||||||
}
|
}
|
||||||
// FdOps
|
// FdOps
|
||||||
fn fdstat_get(&self) -> Result<types::Fdflags> {
|
fn fdstat_get(&self) -> Result<Fdflags> {
|
||||||
fd::fdstat_get(&*self.as_file()?)
|
fd::fdstat_get(&*self.as_file()?)
|
||||||
}
|
}
|
||||||
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
|
fn fdstat_set_flags(&self, fdflags: Fdflags) -> Result<()> {
|
||||||
if let Some(_) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
|
if let Some(_) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
|
||||||
// OK, this means we should somehow update the underlying os handle,
|
// OK, this means we should somehow update the underlying os handle,
|
||||||
// and we can't do that with `std::io::std{in, out, err}`, so we'll
|
// and we can't do that with `std::io::std{in, out, err}`, so we'll
|
||||||
@@ -180,17 +178,17 @@ impl Handle for Stderr {
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub(crate) struct NullDevice {
|
pub(crate) struct NullDevice {
|
||||||
pub(crate) rights: Cell<HandleRights>,
|
pub(crate) rights: Cell<HandleRights>,
|
||||||
pub(crate) fd_flags: Cell<types::Fdflags>,
|
pub(crate) fd_flags: Cell<Fdflags>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NullDevice {
|
impl NullDevice {
|
||||||
pub(crate) fn new() -> Self {
|
pub(crate) fn new() -> Self {
|
||||||
let rights = HandleRights::new(
|
let rights = HandleRights::new(
|
||||||
types::Rights::character_device_base(),
|
Rights::character_device_base(),
|
||||||
types::Rights::character_device_inheriting(),
|
Rights::character_device_inheriting(),
|
||||||
);
|
);
|
||||||
let rights = Cell::new(rights);
|
let rights = Cell::new(rights);
|
||||||
let fd_flags = types::Fdflags::empty();
|
let fd_flags = Fdflags::empty();
|
||||||
let fd_flags = Cell::new(fd_flags);
|
let fd_flags = Cell::new(fd_flags);
|
||||||
Self { rights, fd_flags }
|
Self { rights, fd_flags }
|
||||||
}
|
}
|
||||||
@@ -203,8 +201,8 @@ impl Handle for NullDevice {
|
|||||||
fn try_clone(&self) -> io::Result<Box<dyn Handle>> {
|
fn try_clone(&self) -> io::Result<Box<dyn Handle>> {
|
||||||
Ok(Box::new(self.clone()))
|
Ok(Box::new(self.clone()))
|
||||||
}
|
}
|
||||||
fn get_file_type(&self) -> types::Filetype {
|
fn get_file_type(&self) -> Filetype {
|
||||||
types::Filetype::CharacterDevice
|
Filetype::CharacterDevice
|
||||||
}
|
}
|
||||||
fn get_rights(&self) -> HandleRights {
|
fn get_rights(&self) -> HandleRights {
|
||||||
self.rights.get()
|
self.rights.get()
|
||||||
@@ -213,10 +211,10 @@ impl Handle for NullDevice {
|
|||||||
self.rights.set(rights)
|
self.rights.set(rights)
|
||||||
}
|
}
|
||||||
// FdOps
|
// FdOps
|
||||||
fn fdstat_get(&self) -> Result<types::Fdflags> {
|
fn fdstat_get(&self) -> Result<Fdflags> {
|
||||||
Ok(self.fd_flags.get())
|
Ok(self.fd_flags.get())
|
||||||
}
|
}
|
||||||
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
|
fn fdstat_set_flags(&self, fdflags: Fdflags) -> Result<()> {
|
||||||
self.fd_flags.set(fdflags);
|
self.fd_flags.set(fdflags);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -226,7 +224,7 @@ impl Handle for NullDevice {
|
|||||||
fn write_vectored(&self, iovs: &[io::IoSlice]) -> Result<usize> {
|
fn write_vectored(&self, iovs: &[io::IoSlice]) -> Result<usize> {
|
||||||
let mut total_len = 0u32;
|
let mut total_len = 0u32;
|
||||||
for iov in iovs {
|
for iov in iovs {
|
||||||
let len: types::Size = iov.len().try_into()?;
|
let len: Size = iov.len().try_into()?;
|
||||||
total_len = total_len.checked_add(len).ok_or(Error::Overflow)?;
|
total_len = total_len.checked_add(len).ok_or(Error::Overflow)?;
|
||||||
}
|
}
|
||||||
Ok(total_len as usize)
|
Ok(total_len as usize)
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
use crate::wasi::types;
|
use crate::sched::{Clockid, Timestamp};
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use yanix::clock::{clock_getres, clock_gettime, ClockId};
|
use yanix::clock::{clock_getres, clock_gettime, ClockId};
|
||||||
|
|
||||||
pub(crate) fn res_get(clock_id: types::Clockid) -> Result<types::Timestamp> {
|
pub(crate) fn res_get(clock_id: Clockid) -> Result<Timestamp> {
|
||||||
let clock_id: ClockId = clock_id.into();
|
let clock_id: ClockId = clock_id.into();
|
||||||
let timespec = clock_getres(clock_id)?;
|
let timespec = clock_getres(clock_id)?;
|
||||||
|
|
||||||
// convert to nanoseconds, returning EOVERFLOW in case of overflow;
|
// convert to nanoseconds, returning EOVERFLOW in case of overflow;
|
||||||
// this is freelancing a bit from the spec but seems like it'll
|
// this is freelancing a bit from the spec but seems like it'll
|
||||||
// be an unusual situation to hit
|
// be an unusual situation to hit
|
||||||
(timespec.tv_sec as types::Timestamp)
|
(timespec.tv_sec as Timestamp)
|
||||||
.checked_mul(1_000_000_000)
|
.checked_mul(1_000_000_000)
|
||||||
.and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as types::Timestamp))
|
.and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as Timestamp))
|
||||||
.map_or(Err(Error::Overflow), |resolution| {
|
.map_or(Err(Error::Overflow), |resolution| {
|
||||||
// a supported clock can never return zero; this case will probably never get hit, but
|
// a supported clock can never return zero; this case will probably never get hit, but
|
||||||
// make sure we follow the spec
|
// make sure we follow the spec
|
||||||
@@ -23,14 +23,14 @@ pub(crate) fn res_get(clock_id: types::Clockid) -> Result<types::Timestamp> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn time_get(clock_id: types::Clockid) -> Result<types::Timestamp> {
|
pub(crate) fn time_get(clock_id: Clockid) -> Result<Timestamp> {
|
||||||
let clock_id: ClockId = clock_id.into();
|
let clock_id: ClockId = clock_id.into();
|
||||||
let timespec = clock_gettime(clock_id)?;
|
let timespec = clock_gettime(clock_id)?;
|
||||||
|
|
||||||
// convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit
|
// convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit
|
||||||
// from the spec but seems like it'll be an unusual situation to hit
|
// from the spec but seems like it'll be an unusual situation to hit
|
||||||
(timespec.tv_sec as types::Timestamp)
|
(timespec.tv_sec as Timestamp)
|
||||||
.checked_mul(1_000_000_000)
|
.checked_mul(1_000_000_000)
|
||||||
.and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as types::Timestamp))
|
.and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as Timestamp))
|
||||||
.map_or(Err(Error::Overflow), Ok)
|
.map_or(Err(Error::Overflow), Ok)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,18 @@
|
|||||||
use super::oshandle::RawOsHandle;
|
use super::oshandle::RawOsHandle;
|
||||||
|
use crate::handle::{Advice, Dircookie, Dirent, Fdflags, Filesize, Filestat, DIRCOOKIE_START};
|
||||||
use crate::sys::osdir::OsDir;
|
use crate::sys::osdir::OsDir;
|
||||||
use crate::sys::osfile::OsFile;
|
use crate::sys::osfile::OsFile;
|
||||||
use crate::wasi::{self, types};
|
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::os::unix::prelude::AsRawFd;
|
use std::os::unix::prelude::AsRawFd;
|
||||||
|
|
||||||
pub(crate) fn fdstat_get(fd: &File) -> Result<types::Fdflags> {
|
pub(crate) fn fdstat_get(fd: &File) -> Result<Fdflags> {
|
||||||
let fdflags = unsafe { yanix::fcntl::get_status_flags(fd.as_raw_fd())? };
|
let fdflags = unsafe { yanix::fcntl::get_status_flags(fd.as_raw_fd())? };
|
||||||
Ok(fdflags.into())
|
Ok(fdflags.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn fdstat_set_flags(fd: &File, fdflags: types::Fdflags) -> Result<Option<RawOsHandle>> {
|
pub(crate) fn fdstat_set_flags(fd: &File, fdflags: Fdflags) -> Result<Option<RawOsHandle>> {
|
||||||
unsafe { yanix::fcntl::set_status_flags(fd.as_raw_fd(), fdflags.into())? };
|
unsafe { yanix::fcntl::set_status_flags(fd.as_raw_fd(), fdflags.into())? };
|
||||||
// We return None here to signal that the operation succeeded on the original
|
// We return None here to signal that the operation succeeded on the original
|
||||||
// file descriptor and mutating the original WASI Descriptor is thus unnecessary.
|
// file descriptor and mutating the original WASI Descriptor is thus unnecessary.
|
||||||
@@ -20,28 +20,23 @@ pub(crate) fn fdstat_set_flags(fd: &File, fdflags: types::Fdflags) -> Result<Opt
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn advise(
|
pub(crate) fn advise(file: &OsFile, advice: Advice, offset: Filesize, len: Filesize) -> Result<()> {
|
||||||
file: &OsFile,
|
|
||||||
advice: types::Advice,
|
|
||||||
offset: types::Filesize,
|
|
||||||
len: types::Filesize,
|
|
||||||
) -> Result<()> {
|
|
||||||
use yanix::fadvise::{posix_fadvise, PosixFadviseAdvice};
|
use yanix::fadvise::{posix_fadvise, PosixFadviseAdvice};
|
||||||
let offset = offset.try_into()?;
|
let offset = offset.try_into()?;
|
||||||
let len = len.try_into()?;
|
let len = len.try_into()?;
|
||||||
let host_advice = match advice {
|
let host_advice = match advice {
|
||||||
types::Advice::Dontneed => PosixFadviseAdvice::DontNeed,
|
Advice::Dontneed => PosixFadviseAdvice::DontNeed,
|
||||||
types::Advice::Sequential => PosixFadviseAdvice::Sequential,
|
Advice::Sequential => PosixFadviseAdvice::Sequential,
|
||||||
types::Advice::Willneed => PosixFadviseAdvice::WillNeed,
|
Advice::Willneed => PosixFadviseAdvice::WillNeed,
|
||||||
types::Advice::Noreuse => PosixFadviseAdvice::NoReuse,
|
Advice::Noreuse => PosixFadviseAdvice::NoReuse,
|
||||||
types::Advice::Random => PosixFadviseAdvice::Random,
|
Advice::Random => PosixFadviseAdvice::Random,
|
||||||
types::Advice::Normal => PosixFadviseAdvice::Normal,
|
Advice::Normal => PosixFadviseAdvice::Normal,
|
||||||
};
|
};
|
||||||
unsafe { posix_fadvise(file.as_raw_fd(), offset, len, host_advice)? };
|
unsafe { posix_fadvise(file.as_raw_fd(), offset, len, host_advice)? };
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn filestat_get(file: &File) -> Result<types::Filestat> {
|
pub(crate) fn filestat_get(file: &File) -> Result<Filestat> {
|
||||||
use yanix::file::fstat;
|
use yanix::file::fstat;
|
||||||
let stat = unsafe { fstat(file.as_raw_fd())? };
|
let stat = unsafe { fstat(file.as_raw_fd())? };
|
||||||
Ok(stat.try_into()?)
|
Ok(stat.try_into()?)
|
||||||
@@ -49,8 +44,8 @@ pub(crate) fn filestat_get(file: &File) -> Result<types::Filestat> {
|
|||||||
|
|
||||||
pub(crate) fn readdir<'a>(
|
pub(crate) fn readdir<'a>(
|
||||||
dirfd: &'a OsDir,
|
dirfd: &'a OsDir,
|
||||||
cookie: types::Dircookie,
|
cookie: Dircookie,
|
||||||
) -> Result<Box<dyn Iterator<Item = Result<(types::Dirent, String)>> + 'a>> {
|
) -> Result<Box<dyn Iterator<Item = Result<(Dirent, String)>> + 'a>> {
|
||||||
use yanix::dir::{DirIter, Entry, EntryExt, SeekLoc};
|
use yanix::dir::{DirIter, Entry, EntryExt, SeekLoc};
|
||||||
|
|
||||||
// Get an instance of `Dir`; this is host-specific due to intricasies
|
// Get an instance of `Dir`; this is host-specific due to intricasies
|
||||||
@@ -59,7 +54,7 @@ pub(crate) fn readdir<'a>(
|
|||||||
|
|
||||||
// Seek if needed. Unless cookie is wasi::__WASI_DIRCOOKIE_START,
|
// Seek if needed. Unless cookie is wasi::__WASI_DIRCOOKIE_START,
|
||||||
// new items may not be returned to the caller.
|
// new items may not be returned to the caller.
|
||||||
if cookie == wasi::DIRCOOKIE_START {
|
if cookie == DIRCOOKIE_START {
|
||||||
tracing::trace!("fd_readdir: doing rewinddir");
|
tracing::trace!("fd_readdir: doing rewinddir");
|
||||||
dir.rewind();
|
dir.rewind();
|
||||||
} else {
|
} else {
|
||||||
@@ -71,7 +66,7 @@ pub(crate) fn readdir<'a>(
|
|||||||
Ok(Box::new(DirIter::new(dir).map(|entry| {
|
Ok(Box::new(DirIter::new(dir).map(|entry| {
|
||||||
let entry: Entry = entry?;
|
let entry: Entry = entry?;
|
||||||
let name = entry.file_name().to_str()?.to_owned();
|
let name = entry.file_name().to_str()?.to_owned();
|
||||||
let dirent = types::Dirent {
|
let dirent = Dirent {
|
||||||
d_next: entry.seek_loc()?.to_raw().try_into()?,
|
d_next: entry.seek_loc()?.to_raw().try_into()?,
|
||||||
d_ino: entry.ino(),
|
d_ino: entry.ino(),
|
||||||
d_namlen: name.len().try_into()?,
|
d_namlen: name.len().try_into()?,
|
||||||
|
|||||||
@@ -26,9 +26,11 @@ cfg_if::cfg_if! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::handle::HandleRights;
|
use crate::handle::{
|
||||||
|
Fdflags, Filesize, Filestat, Filetype, HandleRights, Lookupflags, Oflags, Rights, RightsExt,
|
||||||
|
};
|
||||||
|
use crate::sched::{Clockid, Timestamp};
|
||||||
use crate::sys::AsFile;
|
use crate::sys::AsFile;
|
||||||
use crate::wasi::{types, RightsExt};
|
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@@ -48,34 +50,34 @@ impl<T: AsRawFd> AsFile for T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_file_type(file: &File) -> io::Result<types::Filetype> {
|
pub(super) fn get_file_type(file: &File) -> io::Result<Filetype> {
|
||||||
let ft = file.metadata()?.file_type();
|
let ft = file.metadata()?.file_type();
|
||||||
let file_type = if ft.is_block_device() {
|
let file_type = if ft.is_block_device() {
|
||||||
tracing::debug!(
|
tracing::debug!(
|
||||||
host_fd = tracing::field::display(file.as_raw_fd()),
|
host_fd = tracing::field::display(file.as_raw_fd()),
|
||||||
"Host fd is a block device"
|
"Host fd is a block device"
|
||||||
);
|
);
|
||||||
types::Filetype::BlockDevice
|
Filetype::BlockDevice
|
||||||
} else if ft.is_char_device() {
|
} else if ft.is_char_device() {
|
||||||
tracing::debug!("Host fd {:?} is a char device", file.as_raw_fd());
|
tracing::debug!("Host fd {:?} is a char device", file.as_raw_fd());
|
||||||
types::Filetype::CharacterDevice
|
Filetype::CharacterDevice
|
||||||
} else if ft.is_dir() {
|
} else if ft.is_dir() {
|
||||||
tracing::debug!("Host fd {:?} is a directory", file.as_raw_fd());
|
tracing::debug!("Host fd {:?} is a directory", file.as_raw_fd());
|
||||||
types::Filetype::Directory
|
Filetype::Directory
|
||||||
} else if ft.is_file() {
|
} else if ft.is_file() {
|
||||||
tracing::debug!("Host fd {:?} is a file", file.as_raw_fd());
|
tracing::debug!("Host fd {:?} is a file", file.as_raw_fd());
|
||||||
types::Filetype::RegularFile
|
Filetype::RegularFile
|
||||||
} else if ft.is_socket() {
|
} else if ft.is_socket() {
|
||||||
tracing::debug!("Host fd {:?} is a socket", file.as_raw_fd());
|
tracing::debug!("Host fd {:?} is a socket", file.as_raw_fd());
|
||||||
use yanix::socket::{get_socket_type, SockType};
|
use yanix::socket::{get_socket_type, SockType};
|
||||||
match unsafe { get_socket_type(file.as_raw_fd())? } {
|
match unsafe { get_socket_type(file.as_raw_fd())? } {
|
||||||
SockType::Datagram => types::Filetype::SocketDgram,
|
SockType::Datagram => Filetype::SocketDgram,
|
||||||
SockType::Stream => types::Filetype::SocketStream,
|
SockType::Stream => Filetype::SocketStream,
|
||||||
_ => return Err(io::Error::from_raw_os_error(libc::EINVAL)),
|
_ => return Err(io::Error::from_raw_os_error(libc::EINVAL)),
|
||||||
}
|
}
|
||||||
} else if ft.is_fifo() {
|
} else if ft.is_fifo() {
|
||||||
tracing::debug!("Host fd {:?} is a fifo", file.as_raw_fd());
|
tracing::debug!("Host fd {:?} is a fifo", file.as_raw_fd());
|
||||||
types::Filetype::Unknown
|
Filetype::Unknown
|
||||||
} else {
|
} else {
|
||||||
tracing::debug!("Host fd {:?} is unknown", file.as_raw_fd());
|
tracing::debug!("Host fd {:?} is unknown", file.as_raw_fd());
|
||||||
return Err(io::Error::from_raw_os_error(libc::EINVAL));
|
return Err(io::Error::from_raw_os_error(libc::EINVAL));
|
||||||
@@ -83,48 +85,44 @@ pub(super) fn get_file_type(file: &File) -> io::Result<types::Filetype> {
|
|||||||
Ok(file_type)
|
Ok(file_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_rights(file: &File, file_type: &types::Filetype) -> io::Result<HandleRights> {
|
pub(super) fn get_rights(file: &File, file_type: &Filetype) -> io::Result<HandleRights> {
|
||||||
use yanix::{fcntl, file::OFlags};
|
use yanix::{fcntl, file::OFlags};
|
||||||
let (base, inheriting) = match file_type {
|
let (base, inheriting) = match file_type {
|
||||||
types::Filetype::BlockDevice => (
|
Filetype::BlockDevice => (
|
||||||
types::Rights::block_device_base(),
|
Rights::block_device_base(),
|
||||||
types::Rights::block_device_inheriting(),
|
Rights::block_device_inheriting(),
|
||||||
),
|
),
|
||||||
types::Filetype::CharacterDevice => {
|
Filetype::CharacterDevice => {
|
||||||
use yanix::file::isatty;
|
use yanix::file::isatty;
|
||||||
if unsafe { isatty(file.as_raw_fd())? } {
|
if unsafe { isatty(file.as_raw_fd())? } {
|
||||||
(types::Rights::tty_base(), types::Rights::tty_base())
|
(Rights::tty_base(), Rights::tty_base())
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
types::Rights::character_device_base(),
|
Rights::character_device_base(),
|
||||||
types::Rights::character_device_inheriting(),
|
Rights::character_device_inheriting(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
types::Filetype::SocketDgram | types::Filetype::SocketStream => (
|
Filetype::SocketDgram | Filetype::SocketStream => {
|
||||||
types::Rights::socket_base(),
|
(Rights::socket_base(), Rights::socket_inheriting())
|
||||||
types::Rights::socket_inheriting(),
|
}
|
||||||
|
Filetype::SymbolicLink | Filetype::Unknown => (
|
||||||
|
Rights::regular_file_base(),
|
||||||
|
Rights::regular_file_inheriting(),
|
||||||
),
|
),
|
||||||
types::Filetype::SymbolicLink | types::Filetype::Unknown => (
|
Filetype::Directory => (Rights::directory_base(), Rights::directory_inheriting()),
|
||||||
types::Rights::regular_file_base(),
|
Filetype::RegularFile => (
|
||||||
types::Rights::regular_file_inheriting(),
|
Rights::regular_file_base(),
|
||||||
),
|
Rights::regular_file_inheriting(),
|
||||||
types::Filetype::Directory => (
|
|
||||||
types::Rights::directory_base(),
|
|
||||||
types::Rights::directory_inheriting(),
|
|
||||||
),
|
|
||||||
types::Filetype::RegularFile => (
|
|
||||||
types::Rights::regular_file_base(),
|
|
||||||
types::Rights::regular_file_inheriting(),
|
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
let mut rights = HandleRights::new(base, inheriting);
|
let mut rights = HandleRights::new(base, inheriting);
|
||||||
let flags = unsafe { fcntl::get_status_flags(file.as_raw_fd())? };
|
let flags = unsafe { fcntl::get_status_flags(file.as_raw_fd())? };
|
||||||
let accmode = flags & OFlags::ACCMODE;
|
let accmode = flags & OFlags::ACCMODE;
|
||||||
if accmode == OFlags::RDONLY {
|
if accmode == OFlags::RDONLY {
|
||||||
rights.base &= !types::Rights::FD_WRITE;
|
rights.base &= !Rights::FD_WRITE;
|
||||||
} else if accmode == OFlags::WRONLY {
|
} else if accmode == OFlags::WRONLY {
|
||||||
rights.base &= !types::Rights::FD_READ;
|
rights.base &= !Rights::FD_READ;
|
||||||
}
|
}
|
||||||
Ok(rights)
|
Ok(rights)
|
||||||
}
|
}
|
||||||
@@ -133,9 +131,9 @@ pub fn preopen_dir<P: AsRef<Path>>(path: P) -> io::Result<File> {
|
|||||||
File::open(path)
|
File::open(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<types::Clockid> for ClockId {
|
impl From<Clockid> for ClockId {
|
||||||
fn from(clock_id: types::Clockid) -> Self {
|
fn from(clock_id: Clockid) -> Self {
|
||||||
use types::Clockid::*;
|
use Clockid::*;
|
||||||
match clock_id {
|
match clock_id {
|
||||||
Realtime => Self::Realtime,
|
Realtime => Self::Realtime,
|
||||||
Monotonic => Self::Monotonic,
|
Monotonic => Self::Monotonic,
|
||||||
@@ -145,29 +143,29 @@ impl From<types::Clockid> for ClockId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<types::Fdflags> for OFlags {
|
impl From<Fdflags> for OFlags {
|
||||||
fn from(fdflags: types::Fdflags) -> Self {
|
fn from(fdflags: Fdflags) -> Self {
|
||||||
let mut nix_flags = Self::empty();
|
let mut nix_flags = Self::empty();
|
||||||
if fdflags.contains(&types::Fdflags::APPEND) {
|
if fdflags.contains(&Fdflags::APPEND) {
|
||||||
nix_flags.insert(Self::APPEND);
|
nix_flags.insert(Self::APPEND);
|
||||||
}
|
}
|
||||||
if fdflags.contains(&types::Fdflags::DSYNC) {
|
if fdflags.contains(&Fdflags::DSYNC) {
|
||||||
nix_flags.insert(Self::DSYNC);
|
nix_flags.insert(Self::DSYNC);
|
||||||
}
|
}
|
||||||
if fdflags.contains(&types::Fdflags::NONBLOCK) {
|
if fdflags.contains(&Fdflags::NONBLOCK) {
|
||||||
nix_flags.insert(Self::NONBLOCK);
|
nix_flags.insert(Self::NONBLOCK);
|
||||||
}
|
}
|
||||||
if fdflags.contains(&types::Fdflags::RSYNC) {
|
if fdflags.contains(&Fdflags::RSYNC) {
|
||||||
nix_flags.insert(O_RSYNC);
|
nix_flags.insert(O_RSYNC);
|
||||||
}
|
}
|
||||||
if fdflags.contains(&types::Fdflags::SYNC) {
|
if fdflags.contains(&Fdflags::SYNC) {
|
||||||
nix_flags.insert(Self::SYNC);
|
nix_flags.insert(Self::SYNC);
|
||||||
}
|
}
|
||||||
nix_flags
|
nix_flags
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<OFlags> for types::Fdflags {
|
impl From<OFlags> for Fdflags {
|
||||||
fn from(oflags: OFlags) -> Self {
|
fn from(oflags: OFlags) -> Self {
|
||||||
let mut fdflags = Self::empty();
|
let mut fdflags = Self::empty();
|
||||||
if oflags.contains(OFlags::APPEND) {
|
if oflags.contains(OFlags::APPEND) {
|
||||||
@@ -189,30 +187,30 @@ impl From<OFlags> for types::Fdflags {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<types::Oflags> for OFlags {
|
impl From<Oflags> for OFlags {
|
||||||
fn from(oflags: types::Oflags) -> Self {
|
fn from(oflags: Oflags) -> Self {
|
||||||
let mut nix_flags = Self::empty();
|
let mut nix_flags = Self::empty();
|
||||||
if oflags.contains(&types::Oflags::CREAT) {
|
if oflags.contains(&Oflags::CREAT) {
|
||||||
nix_flags.insert(Self::CREAT);
|
nix_flags.insert(Self::CREAT);
|
||||||
}
|
}
|
||||||
if oflags.contains(&types::Oflags::DIRECTORY) {
|
if oflags.contains(&Oflags::DIRECTORY) {
|
||||||
nix_flags.insert(Self::DIRECTORY);
|
nix_flags.insert(Self::DIRECTORY);
|
||||||
}
|
}
|
||||||
if oflags.contains(&types::Oflags::EXCL) {
|
if oflags.contains(&Oflags::EXCL) {
|
||||||
nix_flags.insert(Self::EXCL);
|
nix_flags.insert(Self::EXCL);
|
||||||
}
|
}
|
||||||
if oflags.contains(&types::Oflags::TRUNC) {
|
if oflags.contains(&Oflags::TRUNC) {
|
||||||
nix_flags.insert(Self::TRUNC);
|
nix_flags.insert(Self::TRUNC);
|
||||||
}
|
}
|
||||||
nix_flags
|
nix_flags
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<libc::stat> for types::Filestat {
|
impl TryFrom<libc::stat> for Filestat {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from(filestat: libc::stat) -> Result<Self> {
|
fn try_from(filestat: libc::stat) -> Result<Self> {
|
||||||
fn filestat_to_timestamp(secs: u64, nsecs: u64) -> Result<types::Timestamp> {
|
fn filestat_to_timestamp(secs: u64, nsecs: u64) -> Result<Timestamp> {
|
||||||
secs.checked_mul(1_000_000_000)
|
secs.checked_mul(1_000_000_000)
|
||||||
.and_then(|sec_nsec| sec_nsec.checked_add(nsecs))
|
.and_then(|sec_nsec| sec_nsec.checked_add(nsecs))
|
||||||
.ok_or(Error::Overflow)
|
.ok_or(Error::Overflow)
|
||||||
@@ -238,7 +236,7 @@ impl TryFrom<libc::stat> for types::Filestat {
|
|||||||
dev,
|
dev,
|
||||||
ino,
|
ino,
|
||||||
nlink: filestat.st_nlink.into(),
|
nlink: filestat.st_nlink.into(),
|
||||||
size: filestat.st_size as types::Filesize,
|
size: filestat.st_size as Filesize,
|
||||||
atim,
|
atim,
|
||||||
ctim,
|
ctim,
|
||||||
mtim,
|
mtim,
|
||||||
@@ -247,7 +245,7 @@ impl TryFrom<libc::stat> for types::Filestat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<yanix::file::FileType> for types::Filetype {
|
impl From<yanix::file::FileType> for Filetype {
|
||||||
fn from(ft: yanix::file::FileType) -> Self {
|
fn from(ft: yanix::file::FileType) -> Self {
|
||||||
use yanix::file::FileType::*;
|
use yanix::file::FileType::*;
|
||||||
match ft {
|
match ft {
|
||||||
@@ -267,10 +265,10 @@ impl From<yanix::file::FileType> for types::Filetype {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<types::Lookupflags> for AtFlags {
|
impl From<Lookupflags> for AtFlags {
|
||||||
fn from(flags: types::Lookupflags) -> Self {
|
fn from(flags: Lookupflags) -> Self {
|
||||||
match flags {
|
match flags {
|
||||||
types::Lookupflags::SYMLINK_FOLLOW => Self::empty(),
|
Lookupflags::SYMLINK_FOLLOW => Self::empty(),
|
||||||
_ => Self::SYMLINK_NOFOLLOW,
|
_ => Self::SYMLINK_NOFOLLOW,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use super::oshandle::RawOsHandle;
|
use super::oshandle::RawOsHandle;
|
||||||
use crate::handle::HandleRights;
|
use crate::handle::{HandleRights, Rights, RightsExt};
|
||||||
use crate::wasi::{types, RightsExt};
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -24,16 +23,13 @@ impl TryFrom<File> for OsDir {
|
|||||||
|
|
||||||
fn get_rights(file: &File) -> io::Result<HandleRights> {
|
fn get_rights(file: &File) -> io::Result<HandleRights> {
|
||||||
use yanix::{fcntl, file::OFlags};
|
use yanix::{fcntl, file::OFlags};
|
||||||
let mut rights = HandleRights::new(
|
let mut rights = HandleRights::new(Rights::directory_base(), Rights::directory_inheriting());
|
||||||
types::Rights::directory_base(),
|
|
||||||
types::Rights::directory_inheriting(),
|
|
||||||
);
|
|
||||||
let flags = unsafe { fcntl::get_status_flags(file.as_raw_fd())? };
|
let flags = unsafe { fcntl::get_status_flags(file.as_raw_fd())? };
|
||||||
let accmode = flags & OFlags::ACCMODE;
|
let accmode = flags & OFlags::ACCMODE;
|
||||||
if accmode == OFlags::RDONLY {
|
if accmode == OFlags::RDONLY {
|
||||||
rights.base &= !types::Rights::FD_WRITE;
|
rights.base &= !Rights::FD_WRITE;
|
||||||
} else if accmode == OFlags::WRONLY {
|
} else if accmode == OFlags::WRONLY {
|
||||||
rights.base &= !types::Rights::FD_READ;
|
rights.base &= !Rights::FD_READ;
|
||||||
}
|
}
|
||||||
Ok(rights)
|
Ok(rights)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use super::oshandle::RawOsHandle;
|
use super::oshandle::RawOsHandle;
|
||||||
use crate::handle::HandleRights;
|
use crate::handle::{HandleRights, Rights, RightsExt};
|
||||||
use crate::sys::osfile::OsFile;
|
use crate::sys::osfile::OsFile;
|
||||||
use crate::wasi::{types, RightsExt};
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -24,15 +23,15 @@ impl TryFrom<File> for OsFile {
|
|||||||
fn get_rights(file: &File) -> io::Result<HandleRights> {
|
fn get_rights(file: &File) -> io::Result<HandleRights> {
|
||||||
use yanix::{fcntl, file::OFlags};
|
use yanix::{fcntl, file::OFlags};
|
||||||
let mut rights = HandleRights::new(
|
let mut rights = HandleRights::new(
|
||||||
types::Rights::regular_file_base(),
|
Rights::regular_file_base(),
|
||||||
types::Rights::regular_file_inheriting(),
|
Rights::regular_file_inheriting(),
|
||||||
);
|
);
|
||||||
let flags = unsafe { fcntl::get_status_flags(file.as_raw_fd())? };
|
let flags = unsafe { fcntl::get_status_flags(file.as_raw_fd())? };
|
||||||
let accmode = flags & OFlags::ACCMODE;
|
let accmode = flags & OFlags::ACCMODE;
|
||||||
if accmode == OFlags::RDONLY {
|
if accmode == OFlags::RDONLY {
|
||||||
rights.base &= !types::Rights::FD_WRITE;
|
rights.base &= !Rights::FD_WRITE;
|
||||||
} else if accmode == OFlags::WRONLY {
|
} else if accmode == OFlags::WRONLY {
|
||||||
rights.base &= !types::Rights::FD_READ;
|
rights.base &= !Rights::FD_READ;
|
||||||
}
|
}
|
||||||
Ok(rights)
|
Ok(rights)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use super::oshandle::RawOsHandle;
|
use super::oshandle::RawOsHandle;
|
||||||
use super::{get_file_type, get_rights};
|
use super::{get_file_type, get_rights};
|
||||||
|
use crate::handle::Filetype;
|
||||||
use crate::sys::osother::OsOther;
|
use crate::sys::osother::OsOther;
|
||||||
use crate::wasi::types;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -12,7 +12,7 @@ impl TryFrom<File> for OsOther {
|
|||||||
|
|
||||||
fn try_from(file: File) -> io::Result<Self> {
|
fn try_from(file: File) -> io::Result<Self> {
|
||||||
let file_type = get_file_type(&file)?;
|
let file_type = get_file_type(&file)?;
|
||||||
if file_type == types::Filetype::RegularFile || file_type == types::Filetype::Directory {
|
if file_type == Filetype::RegularFile || file_type == Filetype::Directory {
|
||||||
return Err(io::Error::from_raw_os_error(libc::EINVAL));
|
return Err(io::Error::from_raw_os_error(libc::EINVAL));
|
||||||
}
|
}
|
||||||
let rights = get_rights(&file, &file_type)?;
|
let rights = get_rights(&file, &file_type)?;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::handle::{Handle, HandleRights};
|
use crate::handle::{Fdflags, Filestat, Fstflags, Handle, HandleRights, Oflags, Rights};
|
||||||
|
use crate::sched::Timestamp;
|
||||||
use crate::sys::osdir::OsDir;
|
use crate::sys::osdir::OsDir;
|
||||||
use crate::sys::AsFile;
|
use crate::sys::AsFile;
|
||||||
use crate::wasi::types;
|
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::ffi::OsStr;
|
use std::ffi::OsStr;
|
||||||
@@ -23,29 +23,29 @@ pub(crate) fn from_host<S: AsRef<OsStr>>(s: S) -> Result<String> {
|
|||||||
|
|
||||||
pub(crate) fn open_rights(
|
pub(crate) fn open_rights(
|
||||||
input_rights: &HandleRights,
|
input_rights: &HandleRights,
|
||||||
oflags: types::Oflags,
|
oflags: Oflags,
|
||||||
fs_flags: types::Fdflags,
|
fs_flags: Fdflags,
|
||||||
) -> HandleRights {
|
) -> HandleRights {
|
||||||
// which rights are needed on the dirfd?
|
// which rights are needed on the dirfd?
|
||||||
let mut needed_base = types::Rights::PATH_OPEN;
|
let mut needed_base = Rights::PATH_OPEN;
|
||||||
let mut needed_inheriting = input_rights.base | input_rights.inheriting;
|
let mut needed_inheriting = input_rights.base | input_rights.inheriting;
|
||||||
|
|
||||||
// convert open flags
|
// convert open flags
|
||||||
let oflags: OFlags = oflags.into();
|
let oflags: OFlags = oflags.into();
|
||||||
if oflags.contains(OFlags::CREAT) {
|
if oflags.contains(OFlags::CREAT) {
|
||||||
needed_base |= types::Rights::PATH_CREATE_FILE;
|
needed_base |= Rights::PATH_CREATE_FILE;
|
||||||
}
|
}
|
||||||
if oflags.contains(OFlags::TRUNC) {
|
if oflags.contains(OFlags::TRUNC) {
|
||||||
needed_base |= types::Rights::PATH_FILESTAT_SET_SIZE;
|
needed_base |= Rights::PATH_FILESTAT_SET_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert file descriptor flags
|
// convert file descriptor flags
|
||||||
let fdflags: OFlags = fs_flags.into();
|
let fdflags: OFlags = fs_flags.into();
|
||||||
if fdflags.contains(OFlags::DSYNC) {
|
if fdflags.contains(OFlags::DSYNC) {
|
||||||
needed_inheriting |= types::Rights::FD_DATASYNC;
|
needed_inheriting |= Rights::FD_DATASYNC;
|
||||||
}
|
}
|
||||||
if fdflags.intersects(super::O_RSYNC | OFlags::SYNC) {
|
if fdflags.intersects(super::O_RSYNC | OFlags::SYNC) {
|
||||||
needed_inheriting |= types::Rights::FD_SYNC;
|
needed_inheriting |= Rights::FD_SYNC;
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleRights::new(needed_base, needed_inheriting)
|
HandleRights::new(needed_base, needed_inheriting)
|
||||||
@@ -98,8 +98,8 @@ pub(crate) fn open(
|
|||||||
path: &str,
|
path: &str,
|
||||||
read: bool,
|
read: bool,
|
||||||
write: bool,
|
write: bool,
|
||||||
oflags: types::Oflags,
|
oflags: Oflags,
|
||||||
fs_flags: types::Fdflags,
|
fs_flags: Fdflags,
|
||||||
) -> Result<Box<dyn Handle>> {
|
) -> Result<Box<dyn Handle>> {
|
||||||
use yanix::file::{fstatat, openat, AtFlags, FileType, Mode, OFlags};
|
use yanix::file::{fstatat, openat, AtFlags, FileType, Mode, OFlags};
|
||||||
|
|
||||||
@@ -216,7 +216,7 @@ pub(crate) fn remove_directory(dirfd: &OsDir, path: &str) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn filestat_get_at(dirfd: &OsDir, path: &str, follow: bool) -> Result<types::Filestat> {
|
pub(crate) fn filestat_get_at(dirfd: &OsDir, path: &str, follow: bool) -> Result<Filestat> {
|
||||||
use yanix::file::{fstatat, AtFlags};
|
use yanix::file::{fstatat, AtFlags};
|
||||||
let flags = if follow {
|
let flags = if follow {
|
||||||
AtFlags::empty()
|
AtFlags::empty()
|
||||||
@@ -231,18 +231,18 @@ pub(crate) fn filestat_get_at(dirfd: &OsDir, path: &str, follow: bool) -> Result
|
|||||||
pub(crate) fn filestat_set_times_at(
|
pub(crate) fn filestat_set_times_at(
|
||||||
dirfd: &OsDir,
|
dirfd: &OsDir,
|
||||||
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<()> {
|
||||||
use std::time::{Duration, UNIX_EPOCH};
|
use std::time::{Duration, UNIX_EPOCH};
|
||||||
use yanix::filetime::*;
|
use yanix::filetime::*;
|
||||||
|
|
||||||
let set_atim = fst_flags.contains(&types::Fstflags::ATIM);
|
let set_atim = fst_flags.contains(&Fstflags::ATIM);
|
||||||
let set_atim_now = fst_flags.contains(&types::Fstflags::ATIM_NOW);
|
let set_atim_now = fst_flags.contains(&Fstflags::ATIM_NOW);
|
||||||
let set_mtim = fst_flags.contains(&types::Fstflags::MTIM);
|
let set_mtim = fst_flags.contains(&Fstflags::MTIM);
|
||||||
let set_mtim_now = fst_flags.contains(&types::Fstflags::MTIM_NOW);
|
let set_mtim_now = fst_flags.contains(&Fstflags::MTIM_NOW);
|
||||||
|
|
||||||
if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) {
|
if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) {
|
||||||
return Err(Error::Inval);
|
return Err(Error::Inval);
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
use crate::entry::EntryHandle;
|
use crate::entry::EntryHandle;
|
||||||
use crate::poll::{ClockEventData, FdEventData};
|
use crate::handle::Filetype;
|
||||||
|
use crate::sched::{
|
||||||
|
ClockEventData, Errno, Event, EventFdReadwrite, Eventrwflags, Eventtype, FdEventData,
|
||||||
|
};
|
||||||
use crate::sys::AsFile;
|
use crate::sys::AsFile;
|
||||||
use crate::wasi::types;
|
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::{convert::TryInto, os::unix::prelude::AsRawFd};
|
use std::{convert::TryInto, os::unix::prelude::AsRawFd};
|
||||||
@@ -11,7 +13,7 @@ use yanix::poll::{poll, PollFd, PollFlags};
|
|||||||
pub(crate) fn oneoff(
|
pub(crate) fn oneoff(
|
||||||
timeout: Option<ClockEventData>,
|
timeout: Option<ClockEventData>,
|
||||||
fd_events: Vec<FdEventData>,
|
fd_events: Vec<FdEventData>,
|
||||||
events: &mut Vec<types::Event>,
|
events: &mut Vec<Event>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if fd_events.is_empty() && timeout.is_none() {
|
if fd_events.is_empty() && timeout.is_none() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@@ -22,8 +24,8 @@ pub(crate) fn oneoff(
|
|||||||
.map(|event| {
|
.map(|event| {
|
||||||
let mut flags = PollFlags::empty();
|
let mut flags = PollFlags::empty();
|
||||||
match event.r#type {
|
match event.r#type {
|
||||||
types::Eventtype::FdRead => flags.insert(PollFlags::POLLIN),
|
Eventtype::FdRead => flags.insert(PollFlags::POLLIN),
|
||||||
types::Eventtype::FdWrite => flags.insert(PollFlags::POLLOUT),
|
Eventtype::FdWrite => flags.insert(PollFlags::POLLOUT),
|
||||||
// An event on a file descriptor can currently only be of type FD_READ or FD_WRITE
|
// An event on a file descriptor can currently only be of type FD_READ or FD_WRITE
|
||||||
// Nothing else has been defined in the specification, and these are also the only two
|
// Nothing else has been defined in the specification, and these are also the only two
|
||||||
// events we filtered before. If we get something else here, the code has a serious bug.
|
// events we filtered before. If we get something else here, the code has a serious bug.
|
||||||
@@ -65,13 +67,13 @@ pub(crate) fn oneoff(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_timeout_event(timeout: ClockEventData, events: &mut Vec<types::Event>) {
|
fn handle_timeout_event(timeout: ClockEventData, events: &mut Vec<Event>) {
|
||||||
events.push(types::Event {
|
events.push(Event {
|
||||||
userdata: timeout.userdata,
|
userdata: timeout.userdata,
|
||||||
error: types::Errno::Success,
|
error: Errno::Success,
|
||||||
type_: types::Eventtype::Clock,
|
type_: Eventtype::Clock,
|
||||||
fd_readwrite: types::EventFdReadwrite {
|
fd_readwrite: EventFdReadwrite {
|
||||||
flags: types::Eventrwflags::empty(),
|
flags: Eventrwflags::empty(),
|
||||||
nbytes: 0,
|
nbytes: 0,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -79,11 +81,11 @@ fn handle_timeout_event(timeout: ClockEventData, events: &mut Vec<types::Event>)
|
|||||||
|
|
||||||
fn handle_fd_event(
|
fn handle_fd_event(
|
||||||
ready_events: impl Iterator<Item = (FdEventData, yanix::poll::PollFd)>,
|
ready_events: impl Iterator<Item = (FdEventData, yanix::poll::PollFd)>,
|
||||||
events: &mut Vec<types::Event>,
|
events: &mut Vec<Event>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
fn query_nbytes(handle: EntryHandle) -> Result<u64> {
|
fn query_nbytes(handle: EntryHandle) -> Result<u64> {
|
||||||
let file = handle.as_file()?;
|
let file = handle.as_file()?;
|
||||||
if handle.get_file_type() == types::Filetype::RegularFile {
|
if handle.get_file_type() == Filetype::RegularFile {
|
||||||
// fionread may overflow for large files, so use another way for regular files.
|
// fionread may overflow for large files, so use another way for regular files.
|
||||||
use yanix::file::tell;
|
use yanix::file::tell;
|
||||||
let meta = file.metadata()?;
|
let meta = file.metadata()?;
|
||||||
@@ -106,50 +108,50 @@ fn handle_fd_event(
|
|||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
let nbytes = if fd_event.r#type == types::Eventtype::FdRead {
|
let nbytes = if fd_event.r#type == Eventtype::FdRead {
|
||||||
query_nbytes(fd_event.handle)?
|
query_nbytes(fd_event.handle)?
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|
||||||
let output_event = if revents.contains(PollFlags::POLLNVAL) {
|
let output_event = if revents.contains(PollFlags::POLLNVAL) {
|
||||||
types::Event {
|
Event {
|
||||||
userdata: fd_event.userdata,
|
userdata: fd_event.userdata,
|
||||||
error: Error::Badf.into(),
|
error: Error::Badf.into(),
|
||||||
type_: fd_event.r#type,
|
type_: fd_event.r#type,
|
||||||
fd_readwrite: types::EventFdReadwrite {
|
fd_readwrite: EventFdReadwrite {
|
||||||
nbytes: 0,
|
nbytes: 0,
|
||||||
flags: types::Eventrwflags::FD_READWRITE_HANGUP,
|
flags: Eventrwflags::FD_READWRITE_HANGUP,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else if revents.contains(PollFlags::POLLERR) {
|
} else if revents.contains(PollFlags::POLLERR) {
|
||||||
types::Event {
|
Event {
|
||||||
userdata: fd_event.userdata,
|
userdata: fd_event.userdata,
|
||||||
error: Error::Io.into(),
|
error: Error::Io.into(),
|
||||||
type_: fd_event.r#type,
|
type_: fd_event.r#type,
|
||||||
fd_readwrite: types::EventFdReadwrite {
|
fd_readwrite: EventFdReadwrite {
|
||||||
nbytes: 0,
|
nbytes: 0,
|
||||||
flags: types::Eventrwflags::FD_READWRITE_HANGUP,
|
flags: Eventrwflags::FD_READWRITE_HANGUP,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else if revents.contains(PollFlags::POLLHUP) {
|
} else if revents.contains(PollFlags::POLLHUP) {
|
||||||
types::Event {
|
Event {
|
||||||
userdata: fd_event.userdata,
|
userdata: fd_event.userdata,
|
||||||
error: types::Errno::Success,
|
error: Errno::Success,
|
||||||
type_: fd_event.r#type,
|
type_: fd_event.r#type,
|
||||||
fd_readwrite: types::EventFdReadwrite {
|
fd_readwrite: EventFdReadwrite {
|
||||||
nbytes: 0,
|
nbytes: 0,
|
||||||
flags: types::Eventrwflags::FD_READWRITE_HANGUP,
|
flags: Eventrwflags::FD_READWRITE_HANGUP,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else if revents.contains(PollFlags::POLLIN) | revents.contains(PollFlags::POLLOUT) {
|
} else if revents.contains(PollFlags::POLLIN) | revents.contains(PollFlags::POLLOUT) {
|
||||||
types::Event {
|
Event {
|
||||||
userdata: fd_event.userdata,
|
userdata: fd_event.userdata,
|
||||||
error: types::Errno::Success,
|
error: Errno::Success,
|
||||||
type_: fd_event.r#type,
|
type_: fd_event.r#type,
|
||||||
fd_readwrite: types::EventFdReadwrite {
|
fd_readwrite: EventFdReadwrite {
|
||||||
nbytes: nbytes.try_into()?,
|
nbytes: nbytes.try_into()?,
|
||||||
flags: types::Eventrwflags::empty(),
|
flags: Eventrwflags::empty(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::wasi::types;
|
use crate::sched::{Clockid, Timestamp};
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use cpu_time::{ProcessTime, ThreadTime};
|
use cpu_time::{ProcessTime, ThreadTime};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
@@ -12,7 +12,7 @@ lazy_static! {
|
|||||||
|
|
||||||
// Timer resolution on Windows is really hard. We may consider exposing the resolution of the respective
|
// Timer resolution on Windows is really hard. We may consider exposing the resolution of the respective
|
||||||
// timers as an associated function in the future.
|
// timers as an associated function in the future.
|
||||||
pub(crate) fn res_get(clock_id: types::Clockid) -> Result<types::Timestamp> {
|
pub(crate) fn res_get(clock_id: Clockid) -> Result<Timestamp> {
|
||||||
let ts = match clock_id {
|
let ts = match clock_id {
|
||||||
// This is the best that we can do with std::time::SystemTime.
|
// This is the best that we can do with std::time::SystemTime.
|
||||||
// Rust uses GetSystemTimeAsFileTime, which is said to have the resolution of
|
// Rust uses GetSystemTimeAsFileTime, which is said to have the resolution of
|
||||||
@@ -47,25 +47,25 @@ pub(crate) fn res_get(clock_id: types::Clockid) -> Result<types::Timestamp> {
|
|||||||
// [4] https://www.codeproject.com/Tips/1011902/High-Resolution-Time-For-Windows
|
// [4] https://www.codeproject.com/Tips/1011902/High-Resolution-Time-For-Windows
|
||||||
// [5] https://stackoverflow.com/questions/7685762/windows-7-timing-functions-how-to-use-getsystemtimeadjustment-correctly
|
// [5] https://stackoverflow.com/questions/7685762/windows-7-timing-functions-how-to-use-getsystemtimeadjustment-correctly
|
||||||
// [6] https://bugs.python.org/issue19007
|
// [6] https://bugs.python.org/issue19007
|
||||||
types::Clockid::Realtime => 55_000_000,
|
Clockid::Realtime => 55_000_000,
|
||||||
// std::time::Instant uses QueryPerformanceCounter & QueryPerformanceFrequency internally
|
// std::time::Instant uses QueryPerformanceCounter & QueryPerformanceFrequency internally
|
||||||
types::Clockid::Monotonic => *PERF_COUNTER_RES,
|
Clockid::Monotonic => *PERF_COUNTER_RES,
|
||||||
// The best we can do is to hardcode the value from the docs.
|
// The best we can do is to hardcode the value from the docs.
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocesstimes
|
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getprocesstimes
|
||||||
types::Clockid::ProcessCputimeId => 100,
|
Clockid::ProcessCputimeId => 100,
|
||||||
// The best we can do is to hardcode the value from the docs.
|
// The best we can do is to hardcode the value from the docs.
|
||||||
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadtimes
|
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-getthreadtimes
|
||||||
types::Clockid::ThreadCputimeId => 100,
|
Clockid::ThreadCputimeId => 100,
|
||||||
};
|
};
|
||||||
Ok(ts)
|
Ok(ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn time_get(clock_id: types::Clockid) -> Result<types::Timestamp> {
|
pub(crate) fn time_get(clock_id: Clockid) -> Result<Timestamp> {
|
||||||
let duration = match clock_id {
|
let duration = match clock_id {
|
||||||
types::Clockid::Realtime => get_monotonic_time(),
|
Clockid::Realtime => get_monotonic_time(),
|
||||||
types::Clockid::Monotonic => get_realtime_time()?,
|
Clockid::Monotonic => get_realtime_time()?,
|
||||||
types::Clockid::ProcessCputimeId => get_proc_cputime()?,
|
Clockid::ProcessCputimeId => get_proc_cputime()?,
|
||||||
types::Clockid::ThreadCputimeId => get_thread_cputime()?,
|
Clockid::ThreadCputimeId => get_thread_cputime()?,
|
||||||
};
|
};
|
||||||
let duration = duration.as_nanos().try_into()?;
|
let duration = duration.as_nanos().try_into()?;
|
||||||
Ok(duration)
|
Ok(duration)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
use super::file_serial_no;
|
use super::file_serial_no;
|
||||||
use super::oshandle::RawOsHandle;
|
use super::oshandle::RawOsHandle;
|
||||||
|
use crate::handle::{Advice, Dircookie, Dirent, Fdflags, Filesize, Filestat};
|
||||||
use crate::path;
|
use crate::path;
|
||||||
use crate::sys::osdir::OsDir;
|
use crate::sys::osdir::OsDir;
|
||||||
use crate::sys::osfile::OsFile;
|
use crate::sys::osfile::OsFile;
|
||||||
use crate::sys::AsFile;
|
use crate::sys::AsFile;
|
||||||
use crate::wasi::types;
|
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::{File, OpenOptions};
|
||||||
@@ -14,8 +14,8 @@ use std::path::Path;
|
|||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
use winx::file::{AccessMode, FileModeInformation, Flags};
|
use winx::file::{AccessMode, FileModeInformation, Flags};
|
||||||
|
|
||||||
pub(crate) fn fdstat_get(file: &File) -> Result<types::Fdflags> {
|
pub(crate) fn fdstat_get(file: &File) -> Result<Fdflags> {
|
||||||
let mut fdflags = types::Fdflags::empty();
|
let mut fdflags = Fdflags::empty();
|
||||||
let handle = file.as_raw_handle();
|
let handle = file.as_raw_handle();
|
||||||
let access_mode = winx::file::query_access_information(handle)?;
|
let access_mode = winx::file::query_access_information(handle)?;
|
||||||
let mode = winx::file::query_mode_information(handle)?;
|
let mode = winx::file::query_mode_information(handle)?;
|
||||||
@@ -24,13 +24,13 @@ pub(crate) fn fdstat_get(file: &File) -> Result<types::Fdflags> {
|
|||||||
if access_mode.contains(AccessMode::FILE_APPEND_DATA)
|
if access_mode.contains(AccessMode::FILE_APPEND_DATA)
|
||||||
&& !access_mode.contains(AccessMode::FILE_WRITE_DATA)
|
&& !access_mode.contains(AccessMode::FILE_WRITE_DATA)
|
||||||
{
|
{
|
||||||
fdflags |= types::Fdflags::APPEND;
|
fdflags |= Fdflags::APPEND;
|
||||||
}
|
}
|
||||||
|
|
||||||
if mode.contains(FileModeInformation::FILE_WRITE_THROUGH) {
|
if mode.contains(FileModeInformation::FILE_WRITE_THROUGH) {
|
||||||
// Only report __WASI_FDFLAGS_SYNC
|
// Only report __WASI_FDFLAGS_SYNC
|
||||||
// This is technically the only one of the O_?SYNC flags Windows supports.
|
// This is technically the only one of the O_?SYNC flags Windows supports.
|
||||||
fdflags |= types::Fdflags::SYNC;
|
fdflags |= Fdflags::SYNC;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Files do not support the `__WASI_FDFLAGS_NONBLOCK` flag
|
// Files do not support the `__WASI_FDFLAGS_NONBLOCK` flag
|
||||||
@@ -42,10 +42,7 @@ pub(crate) fn fdstat_get(file: &File) -> Result<types::Fdflags> {
|
|||||||
// handle came from `CreateFile`, but the Rust's libstd will use `GetStdHandle`
|
// handle came from `CreateFile`, but the Rust's libstd will use `GetStdHandle`
|
||||||
// rather than `CreateFile`. Relevant discussion can be found in:
|
// rather than `CreateFile`. Relevant discussion can be found in:
|
||||||
// https://github.com/rust-lang/rust/issues/40490
|
// https://github.com/rust-lang/rust/issues/40490
|
||||||
pub(crate) fn fdstat_set_flags(
|
pub(crate) fn fdstat_set_flags(file: &File, fdflags: Fdflags) -> Result<Option<RawOsHandle>> {
|
||||||
file: &File,
|
|
||||||
fdflags: types::Fdflags,
|
|
||||||
) -> Result<Option<RawOsHandle>> {
|
|
||||||
let handle = file.as_raw_handle();
|
let handle = file.as_raw_handle();
|
||||||
let access_mode = winx::file::query_access_information(handle)?;
|
let access_mode = winx::file::query_access_information(handle)?;
|
||||||
let new_access_mode = file_access_mode_from_fdflags(
|
let new_access_mode = file_access_mode_from_fdflags(
|
||||||
@@ -65,14 +62,14 @@ pub(crate) fn fdstat_set_flags(
|
|||||||
|
|
||||||
pub(crate) fn advise(
|
pub(crate) fn advise(
|
||||||
_file: &OsFile,
|
_file: &OsFile,
|
||||||
_advice: types::Advice,
|
_advice: Advice,
|
||||||
_offset: types::Filesize,
|
_offset: Filesize,
|
||||||
_len: types::Filesize,
|
_len: Filesize,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_access_mode_from_fdflags(fdflags: types::Fdflags, read: bool, write: bool) -> AccessMode {
|
fn file_access_mode_from_fdflags(fdflags: Fdflags, read: bool, write: bool) -> AccessMode {
|
||||||
let mut access_mode = AccessMode::READ_CONTROL;
|
let mut access_mode = AccessMode::READ_CONTROL;
|
||||||
|
|
||||||
// Note that `GENERIC_READ` and `GENERIC_WRITE` cannot be used to properly support append-only mode
|
// Note that `GENERIC_READ` and `GENERIC_WRITE` cannot be used to properly support append-only mode
|
||||||
@@ -89,7 +86,7 @@ fn file_access_mode_from_fdflags(fdflags: types::Fdflags, read: bool, write: boo
|
|||||||
// For append, grant the handle FILE_APPEND_DATA access but *not* FILE_WRITE_DATA.
|
// For append, grant the handle FILE_APPEND_DATA access but *not* FILE_WRITE_DATA.
|
||||||
// This makes the handle "append only".
|
// This makes the handle "append only".
|
||||||
// Changes to the file pointer will be ignored (like POSIX's O_APPEND behavior).
|
// Changes to the file pointer will be ignored (like POSIX's O_APPEND behavior).
|
||||||
if fdflags.contains(&types::Fdflags::APPEND) {
|
if fdflags.contains(&Fdflags::APPEND) {
|
||||||
access_mode.insert(AccessMode::FILE_APPEND_DATA);
|
access_mode.insert(AccessMode::FILE_APPEND_DATA);
|
||||||
access_mode.remove(AccessMode::FILE_WRITE_DATA);
|
access_mode.remove(AccessMode::FILE_WRITE_DATA);
|
||||||
}
|
}
|
||||||
@@ -127,8 +124,8 @@ fn file_access_mode_from_fdflags(fdflags: types::Fdflags, read: bool, write: boo
|
|||||||
// other entries, in order they were returned by FindNextFileW get subsequent integers as their cookies
|
// other entries, in order they were returned by FindNextFileW get subsequent integers as their cookies
|
||||||
pub(crate) fn readdir(
|
pub(crate) fn readdir(
|
||||||
dirfd: &OsDir,
|
dirfd: &OsDir,
|
||||||
cookie: types::Dircookie,
|
cookie: Dircookie,
|
||||||
) -> Result<Box<dyn Iterator<Item = Result<(types::Dirent, String)>>>> {
|
) -> Result<Box<dyn Iterator<Item = Result<(Dirent, String)>>>> {
|
||||||
use winx::file::get_file_path;
|
use winx::file::get_file_path;
|
||||||
|
|
||||||
let cookie = cookie.try_into()?;
|
let cookie = cookie.try_into()?;
|
||||||
@@ -146,7 +143,7 @@ pub(crate) fn readdir(
|
|||||||
let ftype = dir.file_type()?;
|
let ftype = dir.file_type()?;
|
||||||
let name = path::from_host(dir.file_name())?;
|
let name = path::from_host(dir.file_name())?;
|
||||||
let d_ino = File::open(dir.path()).and_then(|f| file_serial_no(&f))?;
|
let d_ino = File::open(dir.path()).and_then(|f| file_serial_no(&f))?;
|
||||||
let dirent = types::Dirent {
|
let dirent = Dirent {
|
||||||
d_namlen: name.len().try_into()?,
|
d_namlen: name.len().try_into()?,
|
||||||
d_type: ftype.into(),
|
d_type: ftype.into(),
|
||||||
d_ino,
|
d_ino,
|
||||||
@@ -171,8 +168,8 @@ pub(crate) fn readdir(
|
|||||||
fn dirent_from_path<P: AsRef<Path>>(
|
fn dirent_from_path<P: AsRef<Path>>(
|
||||||
path: P,
|
path: P,
|
||||||
name: &str,
|
name: &str,
|
||||||
cookie: types::Dircookie,
|
cookie: Dircookie,
|
||||||
) -> Result<(types::Dirent, String)> {
|
) -> Result<(Dirent, String)> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
trace!("dirent_from_path: opening {}", path.to_string_lossy());
|
trace!("dirent_from_path: opening {}", path.to_string_lossy());
|
||||||
|
|
||||||
@@ -183,7 +180,7 @@ fn dirent_from_path<P: AsRef<Path>>(
|
|||||||
.open(path)?;
|
.open(path)?;
|
||||||
let ty = file.metadata()?.file_type();
|
let ty = file.metadata()?.file_type();
|
||||||
let name = name.to_owned();
|
let name = name.to_owned();
|
||||||
let dirent = types::Dirent {
|
let dirent = Dirent {
|
||||||
d_namlen: name.len().try_into()?,
|
d_namlen: name.len().try_into()?,
|
||||||
d_next: cookie,
|
d_next: cookie,
|
||||||
d_type: ty.into(),
|
d_type: ty.into(),
|
||||||
@@ -192,7 +189,7 @@ fn dirent_from_path<P: AsRef<Path>>(
|
|||||||
Ok((dirent, name))
|
Ok((dirent, name))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn filestat_get(file: &File) -> Result<types::Filestat> {
|
pub(crate) fn filestat_get(file: &File) -> Result<Filestat> {
|
||||||
let filestat = file.try_into()?;
|
let filestat = file.try_into()?;
|
||||||
Ok(filestat)
|
Ok(filestat)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,8 @@ pub(crate) mod path;
|
|||||||
pub(crate) mod poll;
|
pub(crate) mod poll;
|
||||||
pub(crate) mod stdio;
|
pub(crate) mod stdio;
|
||||||
|
|
||||||
use crate::handle::HandleRights;
|
use crate::handle::{Fdflags, Filestat, Filetype, HandleRights, Oflags, Rights, RightsExt};
|
||||||
use crate::sys::AsFile;
|
use crate::sys::AsFile;
|
||||||
use crate::wasi::{types, RightsExt};
|
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::convert::{TryFrom, TryInto};
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@@ -28,54 +27,50 @@ impl<T: AsRawHandle> AsFile for T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_file_type(file: &File) -> io::Result<types::Filetype> {
|
pub(super) fn get_file_type(file: &File) -> io::Result<Filetype> {
|
||||||
let file_type = unsafe { winx::file::get_file_type(file.as_raw_handle())? };
|
let file_type = unsafe { winx::file::get_file_type(file.as_raw_handle())? };
|
||||||
let file_type = if file_type.is_char() {
|
let file_type = if file_type.is_char() {
|
||||||
// character file: LPT device or console
|
// character file: LPT device or console
|
||||||
// TODO: rule out LPT device
|
// TODO: rule out LPT device
|
||||||
types::Filetype::CharacterDevice
|
Filetype::CharacterDevice
|
||||||
} else if file_type.is_disk() {
|
} else if file_type.is_disk() {
|
||||||
// disk file: file, dir or disk device
|
// disk file: file, dir or disk device
|
||||||
let meta = file.metadata()?;
|
let meta = file.metadata()?;
|
||||||
if meta.is_dir() {
|
if meta.is_dir() {
|
||||||
types::Filetype::Directory
|
Filetype::Directory
|
||||||
} else if meta.is_file() {
|
} else if meta.is_file() {
|
||||||
types::Filetype::RegularFile
|
Filetype::RegularFile
|
||||||
} else {
|
} else {
|
||||||
return Err(io::Error::from_raw_os_error(libc::EINVAL));
|
return Err(io::Error::from_raw_os_error(libc::EINVAL));
|
||||||
}
|
}
|
||||||
} else if file_type.is_pipe() {
|
} else if file_type.is_pipe() {
|
||||||
// pipe object: socket, named pipe or anonymous pipe
|
// pipe object: socket, named pipe or anonymous pipe
|
||||||
// TODO: what about pipes, etc?
|
// TODO: what about pipes, etc?
|
||||||
types::Filetype::SocketStream
|
Filetype::SocketStream
|
||||||
} else {
|
} else {
|
||||||
return Err(io::Error::from_raw_os_error(libc::EINVAL));
|
return Err(io::Error::from_raw_os_error(libc::EINVAL));
|
||||||
};
|
};
|
||||||
Ok(file_type)
|
Ok(file_type)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn get_rights(file_type: &types::Filetype) -> io::Result<HandleRights> {
|
pub(super) fn get_rights(file_type: &Filetype) -> io::Result<HandleRights> {
|
||||||
let (base, inheriting) = match file_type {
|
let (base, inheriting) = match file_type {
|
||||||
types::Filetype::BlockDevice => (
|
Filetype::BlockDevice => (
|
||||||
types::Rights::block_device_base(),
|
Rights::block_device_base(),
|
||||||
types::Rights::block_device_inheriting(),
|
Rights::block_device_inheriting(),
|
||||||
),
|
),
|
||||||
types::Filetype::CharacterDevice => (types::Rights::tty_base(), types::Rights::tty_base()),
|
Filetype::CharacterDevice => (Rights::tty_base(), Rights::tty_base()),
|
||||||
types::Filetype::SocketDgram | types::Filetype::SocketStream => (
|
Filetype::SocketDgram | Filetype::SocketStream => {
|
||||||
types::Rights::socket_base(),
|
(Rights::socket_base(), Rights::socket_inheriting())
|
||||||
types::Rights::socket_inheriting(),
|
}
|
||||||
|
Filetype::SymbolicLink | Filetype::Unknown => (
|
||||||
|
Rights::regular_file_base(),
|
||||||
|
Rights::regular_file_inheriting(),
|
||||||
),
|
),
|
||||||
types::Filetype::SymbolicLink | types::Filetype::Unknown => (
|
Filetype::Directory => (Rights::directory_base(), Rights::directory_inheriting()),
|
||||||
types::Rights::regular_file_base(),
|
Filetype::RegularFile => (
|
||||||
types::Rights::regular_file_inheriting(),
|
Rights::regular_file_base(),
|
||||||
),
|
Rights::regular_file_inheriting(),
|
||||||
types::Filetype::Directory => (
|
|
||||||
types::Rights::directory_base(),
|
|
||||||
types::Rights::directory_inheriting(),
|
|
||||||
),
|
|
||||||
types::Filetype::RegularFile => (
|
|
||||||
types::Rights::regular_file_base(),
|
|
||||||
types::Rights::regular_file_inheriting(),
|
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
let rights = HandleRights::new(base, inheriting);
|
let rights = HandleRights::new(base, inheriting);
|
||||||
@@ -132,12 +127,12 @@ fn systemtime_to_timestamp(st: SystemTime) -> Result<u64> {
|
|||||||
.map_err(Into::into) // u128 doesn't fit into u64
|
.map_err(Into::into) // u128 doesn't fit into u64
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&File> for types::Filestat {
|
impl TryFrom<&File> for Filestat {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from(file: &File) -> Result<Self> {
|
fn try_from(file: &File) -> Result<Self> {
|
||||||
let metadata = file.metadata()?;
|
let metadata = file.metadata()?;
|
||||||
Ok(types::Filestat {
|
Ok(Filestat {
|
||||||
dev: device_id(file)?,
|
dev: device_id(file)?,
|
||||||
ino: file_serial_no(file)?,
|
ino: file_serial_no(file)?,
|
||||||
nlink: num_hardlinks(file)?.try_into()?, // u64 doesn't fit into u32
|
nlink: num_hardlinks(file)?.try_into()?, // u64 doesn't fit into u32
|
||||||
@@ -150,15 +145,15 @@ impl TryFrom<&File> for types::Filestat {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<types::Oflags> for CreationDisposition {
|
impl From<Oflags> for CreationDisposition {
|
||||||
fn from(oflags: types::Oflags) -> Self {
|
fn from(oflags: Oflags) -> Self {
|
||||||
if oflags.contains(&types::Oflags::CREAT) {
|
if oflags.contains(&Oflags::CREAT) {
|
||||||
if oflags.contains(&types::Oflags::EXCL) {
|
if oflags.contains(&Oflags::EXCL) {
|
||||||
CreationDisposition::CREATE_NEW
|
CreationDisposition::CREATE_NEW
|
||||||
} else {
|
} else {
|
||||||
CreationDisposition::CREATE_ALWAYS
|
CreationDisposition::CREATE_ALWAYS
|
||||||
}
|
}
|
||||||
} else if oflags.contains(&types::Oflags::TRUNC) {
|
} else if oflags.contains(&Oflags::TRUNC) {
|
||||||
CreationDisposition::TRUNCATE_EXISTING
|
CreationDisposition::TRUNCATE_EXISTING
|
||||||
} else {
|
} else {
|
||||||
CreationDisposition::OPEN_EXISTING
|
CreationDisposition::OPEN_EXISTING
|
||||||
@@ -166,8 +161,8 @@ impl From<types::Oflags> for CreationDisposition {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<types::Fdflags> for Flags {
|
impl From<Fdflags> for Flags {
|
||||||
fn from(fdflags: types::Fdflags) -> Self {
|
fn from(fdflags: Fdflags) -> Self {
|
||||||
// Enable backup semantics so directories can be opened as files
|
// Enable backup semantics so directories can be opened as files
|
||||||
let mut flags = Flags::FILE_FLAG_BACKUP_SEMANTICS;
|
let mut flags = Flags::FILE_FLAG_BACKUP_SEMANTICS;
|
||||||
|
|
||||||
@@ -176,9 +171,9 @@ impl From<types::Fdflags> for Flags {
|
|||||||
// treat I/O operations on files as synchronous. WASI might have an async-io API in the future.
|
// treat I/O operations on files as synchronous. WASI might have an async-io API in the future.
|
||||||
|
|
||||||
// Technically, Windows only supports __WASI_FDFLAGS_SYNC, but treat all the flags as the same.
|
// Technically, Windows only supports __WASI_FDFLAGS_SYNC, but treat all the flags as the same.
|
||||||
if fdflags.contains(&types::Fdflags::DSYNC)
|
if fdflags.contains(&Fdflags::DSYNC)
|
||||||
|| fdflags.contains(&types::Fdflags::RSYNC)
|
|| fdflags.contains(&Fdflags::RSYNC)
|
||||||
|| fdflags.contains(&types::Fdflags::SYNC)
|
|| fdflags.contains(&Fdflags::SYNC)
|
||||||
{
|
{
|
||||||
flags.insert(Flags::FILE_FLAG_WRITE_THROUGH);
|
flags.insert(Flags::FILE_FLAG_WRITE_THROUGH);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use super::oshandle::RawOsHandle;
|
use super::oshandle::RawOsHandle;
|
||||||
use crate::handle::HandleRights;
|
use crate::handle::{HandleRights, Rights, RightsExt};
|
||||||
use crate::wasi::{types, RightsExt};
|
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
@@ -55,16 +54,13 @@ impl TryFrom<File> for OsDir {
|
|||||||
|
|
||||||
fn get_rights(file: &File) -> io::Result<HandleRights> {
|
fn get_rights(file: &File) -> io::Result<HandleRights> {
|
||||||
use winx::file::{query_access_information, AccessMode};
|
use winx::file::{query_access_information, AccessMode};
|
||||||
let mut rights = HandleRights::new(
|
let mut rights = HandleRights::new(Rights::directory_base(), Rights::directory_inheriting());
|
||||||
types::Rights::directory_base(),
|
|
||||||
types::Rights::directory_inheriting(),
|
|
||||||
);
|
|
||||||
let mode = query_access_information(file.as_raw_handle())?;
|
let mode = query_access_information(file.as_raw_handle())?;
|
||||||
if mode.contains(AccessMode::FILE_GENERIC_READ) {
|
if mode.contains(AccessMode::FILE_GENERIC_READ) {
|
||||||
rights.base |= types::Rights::FD_READ;
|
rights.base |= Rights::FD_READ;
|
||||||
}
|
}
|
||||||
if mode.contains(AccessMode::FILE_GENERIC_WRITE) {
|
if mode.contains(AccessMode::FILE_GENERIC_WRITE) {
|
||||||
rights.base |= types::Rights::FD_WRITE;
|
rights.base |= Rights::FD_WRITE;
|
||||||
}
|
}
|
||||||
Ok(rights)
|
Ok(rights)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
use super::oshandle::RawOsHandle;
|
use super::oshandle::RawOsHandle;
|
||||||
use crate::handle::HandleRights;
|
use crate::handle::{HandleRights, Rights, RightsExt};
|
||||||
use crate::sys::osfile::OsFile;
|
use crate::sys::osfile::OsFile;
|
||||||
use crate::wasi::{types, RightsExt};
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -24,15 +23,15 @@ impl TryFrom<File> for OsFile {
|
|||||||
fn get_rights(file: &File) -> io::Result<HandleRights> {
|
fn get_rights(file: &File) -> io::Result<HandleRights> {
|
||||||
use winx::file::{query_access_information, AccessMode};
|
use winx::file::{query_access_information, AccessMode};
|
||||||
let mut rights = HandleRights::new(
|
let mut rights = HandleRights::new(
|
||||||
types::Rights::regular_file_base(),
|
Rights::regular_file_base(),
|
||||||
types::Rights::regular_file_inheriting(),
|
Rights::regular_file_inheriting(),
|
||||||
);
|
);
|
||||||
let mode = query_access_information(file.as_raw_handle())?;
|
let mode = query_access_information(file.as_raw_handle())?;
|
||||||
if mode.contains(AccessMode::FILE_GENERIC_READ) {
|
if mode.contains(AccessMode::FILE_GENERIC_READ) {
|
||||||
rights.base |= types::Rights::FD_READ;
|
rights.base |= Rights::FD_READ;
|
||||||
}
|
}
|
||||||
if mode.contains(AccessMode::FILE_GENERIC_WRITE) {
|
if mode.contains(AccessMode::FILE_GENERIC_WRITE) {
|
||||||
rights.base |= types::Rights::FD_WRITE;
|
rights.base |= Rights::FD_WRITE;
|
||||||
}
|
}
|
||||||
Ok(rights)
|
Ok(rights)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use super::oshandle::RawOsHandle;
|
use super::oshandle::RawOsHandle;
|
||||||
use super::{get_file_type, get_rights};
|
use super::{get_file_type, get_rights};
|
||||||
|
use crate::handle::Filetype;
|
||||||
use crate::sys::osother::OsOther;
|
use crate::sys::osother::OsOther;
|
||||||
use crate::wasi::types;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -12,7 +12,7 @@ impl TryFrom<File> for OsOther {
|
|||||||
|
|
||||||
fn try_from(file: File) -> io::Result<Self> {
|
fn try_from(file: File) -> io::Result<Self> {
|
||||||
let file_type = get_file_type(&file)?;
|
let file_type = get_file_type(&file)?;
|
||||||
if file_type == types::Filetype::RegularFile || file_type == types::Filetype::Directory {
|
if file_type == Filetype::RegularFile || file_type == Filetype::Directory {
|
||||||
return Err(io::Error::from_raw_os_error(libc::EINVAL));
|
return Err(io::Error::from_raw_os_error(libc::EINVAL));
|
||||||
}
|
}
|
||||||
let rights = get_rights(&file_type)?;
|
let rights = get_rights(&file_type)?;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::handle::{Handle, HandleRights};
|
use crate::handle::{Fdflags, Filestat, Fstflags, Handle, HandleRights, Oflags, Rights};
|
||||||
|
use crate::sched::Timestamp;
|
||||||
use crate::sys::osdir::OsDir;
|
use crate::sys::osdir::OsDir;
|
||||||
use crate::sys::{fd, AsFile};
|
use crate::sys::{fd, AsFile};
|
||||||
use crate::wasi::types;
|
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::ffi::{OsStr, OsString};
|
use std::ffi::{OsStr, OsString};
|
||||||
@@ -52,7 +52,7 @@ fn concatenate<P: AsRef<Path>>(file: &OsDir, path: P) -> Result<PathBuf> {
|
|||||||
Ok(out_path)
|
Ok(out_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn file_access_mode_from_fdflags(fdflags: types::Fdflags, read: bool, write: bool) -> AccessMode {
|
fn file_access_mode_from_fdflags(fdflags: Fdflags, read: bool, write: bool) -> AccessMode {
|
||||||
let mut access_mode = AccessMode::READ_CONTROL;
|
let mut access_mode = AccessMode::READ_CONTROL;
|
||||||
|
|
||||||
// We always need `FILE_WRITE_ATTRIBUTES` so that we can set attributes such as filetimes, etc.
|
// We always need `FILE_WRITE_ATTRIBUTES` so that we can set attributes such as filetimes, etc.
|
||||||
@@ -72,7 +72,7 @@ fn file_access_mode_from_fdflags(fdflags: types::Fdflags, read: bool, write: boo
|
|||||||
// For append, grant the handle FILE_APPEND_DATA access but *not* FILE_WRITE_DATA.
|
// For append, grant the handle FILE_APPEND_DATA access but *not* FILE_WRITE_DATA.
|
||||||
// This makes the handle "append only".
|
// This makes the handle "append only".
|
||||||
// Changes to the file pointer will be ignored (like POSIX's O_APPEND behavior).
|
// Changes to the file pointer will be ignored (like POSIX's O_APPEND behavior).
|
||||||
if fdflags.contains(&types::Fdflags::APPEND) {
|
if fdflags.contains(&Fdflags::APPEND) {
|
||||||
access_mode.insert(AccessMode::FILE_APPEND_DATA);
|
access_mode.insert(AccessMode::FILE_APPEND_DATA);
|
||||||
access_mode.remove(AccessMode::FILE_WRITE_DATA);
|
access_mode.remove(AccessMode::FILE_WRITE_DATA);
|
||||||
}
|
}
|
||||||
@@ -92,27 +92,27 @@ pub(crate) fn from_host<S: AsRef<OsStr>>(s: S) -> Result<String> {
|
|||||||
|
|
||||||
pub(crate) fn open_rights(
|
pub(crate) fn open_rights(
|
||||||
input_rights: &HandleRights,
|
input_rights: &HandleRights,
|
||||||
oflags: types::Oflags,
|
oflags: Oflags,
|
||||||
fdflags: types::Fdflags,
|
fdflags: Fdflags,
|
||||||
) -> HandleRights {
|
) -> HandleRights {
|
||||||
// which rights are needed on the dirfd?
|
// which rights are needed on the dirfd?
|
||||||
let mut needed_base = types::Rights::PATH_OPEN;
|
let mut needed_base = Rights::PATH_OPEN;
|
||||||
let mut needed_inheriting = input_rights.base | input_rights.inheriting;
|
let mut needed_inheriting = input_rights.base | input_rights.inheriting;
|
||||||
|
|
||||||
// convert open flags
|
// convert open flags
|
||||||
if oflags.contains(&types::Oflags::CREAT) {
|
if oflags.contains(&Oflags::CREAT) {
|
||||||
needed_base |= types::Rights::PATH_CREATE_FILE;
|
needed_base |= Rights::PATH_CREATE_FILE;
|
||||||
} else if oflags.contains(&types::Oflags::TRUNC) {
|
} else if oflags.contains(&Oflags::TRUNC) {
|
||||||
needed_base |= types::Rights::PATH_FILESTAT_SET_SIZE;
|
needed_base |= Rights::PATH_FILESTAT_SET_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert file descriptor flags
|
// convert file descriptor flags
|
||||||
if fdflags.contains(&types::Fdflags::DSYNC)
|
if fdflags.contains(&Fdflags::DSYNC)
|
||||||
|| fdflags.contains(&types::Fdflags::RSYNC)
|
|| fdflags.contains(&Fdflags::RSYNC)
|
||||||
|| fdflags.contains(&types::Fdflags::SYNC)
|
|| fdflags.contains(&Fdflags::SYNC)
|
||||||
{
|
{
|
||||||
needed_inheriting |= types::Rights::FD_DATASYNC;
|
needed_inheriting |= Rights::FD_DATASYNC;
|
||||||
needed_inheriting |= types::Rights::FD_SYNC;
|
needed_inheriting |= Rights::FD_SYNC;
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleRights::new(needed_base, needed_inheriting)
|
HandleRights::new(needed_base, needed_inheriting)
|
||||||
@@ -206,18 +206,18 @@ pub(crate) fn open(
|
|||||||
path: &str,
|
path: &str,
|
||||||
read: bool,
|
read: bool,
|
||||||
write: bool,
|
write: bool,
|
||||||
oflags: types::Oflags,
|
oflags: Oflags,
|
||||||
fdflags: types::Fdflags,
|
fdflags: Fdflags,
|
||||||
) -> Result<Box<dyn Handle>> {
|
) -> Result<Box<dyn Handle>> {
|
||||||
use winx::file::{AccessMode, CreationDisposition, Flags};
|
use winx::file::{AccessMode, CreationDisposition, Flags};
|
||||||
|
|
||||||
let is_trunc = oflags.contains(&types::Oflags::TRUNC);
|
let is_trunc = oflags.contains(&Oflags::TRUNC);
|
||||||
|
|
||||||
if is_trunc {
|
if is_trunc {
|
||||||
// Windows does not support append mode when opening for truncation
|
// Windows does not support append mode when opening for truncation
|
||||||
// This is because truncation requires `GENERIC_WRITE` access, which will override the removal
|
// This is because truncation requires `GENERIC_WRITE` access, which will override the removal
|
||||||
// of the `FILE_WRITE_DATA` permission.
|
// of the `FILE_WRITE_DATA` permission.
|
||||||
if fdflags.contains(&types::Fdflags::APPEND) {
|
if fdflags.contains(&Fdflags::APPEND) {
|
||||||
return Err(Error::Notsup);
|
return Err(Error::Notsup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,7 +246,7 @@ pub(crate) fn open(
|
|||||||
return Err(Error::Loop);
|
return Err(Error::Loop);
|
||||||
}
|
}
|
||||||
// check if we are trying to open a file as a dir
|
// check if we are trying to open a file as a dir
|
||||||
if file_type.is_file() && oflags.contains(&types::Oflags::DIRECTORY) {
|
if file_type.is_file() && oflags.contains(&Oflags::DIRECTORY) {
|
||||||
return Err(Error::Notdir);
|
return Err(Error::Notdir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -499,7 +499,7 @@ pub(crate) fn remove_directory(dirfd: &OsDir, path: &str) -> Result<()> {
|
|||||||
std::fs::remove_dir(&path).map_err(Into::into)
|
std::fs::remove_dir(&path).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn filestat_get_at(dirfd: &OsDir, path: &str, follow: bool) -> Result<types::Filestat> {
|
pub(crate) fn filestat_get_at(dirfd: &OsDir, path: &str, follow: bool) -> Result<Filestat> {
|
||||||
use winx::file::Flags;
|
use winx::file::Flags;
|
||||||
let path = concatenate(dirfd, path)?;
|
let path = concatenate(dirfd, path)?;
|
||||||
let mut opts = OpenOptions::new();
|
let mut opts = OpenOptions::new();
|
||||||
@@ -517,9 +517,9 @@ pub(crate) fn filestat_get_at(dirfd: &OsDir, path: &str, follow: bool) -> Result
|
|||||||
pub(crate) fn filestat_set_times_at(
|
pub(crate) fn filestat_set_times_at(
|
||||||
dirfd: &OsDir,
|
dirfd: &OsDir,
|
||||||
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<()> {
|
||||||
use winx::file::{AccessMode, Flags};
|
use winx::file::{AccessMode, Flags};
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
use crate::handle::Handle;
|
use crate::handle::{Filetype, Handle};
|
||||||
use crate::poll::{ClockEventData, FdEventData};
|
use crate::sched::{
|
||||||
|
ClockEventData, Errno, Event, EventFdReadwrite, Eventrwflags, Eventtype, FdEventData,
|
||||||
|
};
|
||||||
use crate::sys::osdir::OsDir;
|
use crate::sys::osdir::OsDir;
|
||||||
use crate::sys::osfile::OsFile;
|
use crate::sys::osfile::OsFile;
|
||||||
use crate::sys::osother::OsOther;
|
use crate::sys::osother::OsOther;
|
||||||
use crate::sys::stdio::{Stderr, Stdin, Stdout};
|
use crate::sys::stdio::{Stderr, Stdin, Stdout};
|
||||||
use crate::sys::AsFile;
|
use crate::sys::AsFile;
|
||||||
use crate::wasi::types;
|
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
@@ -24,7 +25,7 @@ enum PollState {
|
|||||||
Ready,
|
Ready,
|
||||||
NotReady, // it's not ready, but we didn't wait
|
NotReady, // it's not ready, but we didn't wait
|
||||||
TimedOut, // it's not ready and a timeout has occurred
|
TimedOut, // it's not ready and a timeout has occurred
|
||||||
Error(types::Errno),
|
Error(Errno),
|
||||||
}
|
}
|
||||||
|
|
||||||
enum WaitMode {
|
enum WaitMode {
|
||||||
@@ -80,7 +81,7 @@ impl StdinPoll {
|
|||||||
// Linux returns `POLLIN` in both cases, and we imitate this behavior.
|
// Linux returns `POLLIN` in both cases, and we imitate this behavior.
|
||||||
let resp = match std::io::stdin().lock().fill_buf() {
|
let resp = match std::io::stdin().lock().fill_buf() {
|
||||||
Ok(_) => PollState::Ready,
|
Ok(_) => PollState::Ready,
|
||||||
Err(e) => PollState::Error(types::Errno::from(Error::from(e))),
|
Err(e) => PollState::Error(Errno::from(Error::from(e))),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Notify the requestor about data in stdin. They may have already timed out,
|
// Notify the requestor about data in stdin. They may have already timed out,
|
||||||
@@ -102,52 +103,45 @@ lazy_static! {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_rw_event(
|
fn make_rw_event(event: &FdEventData, nbytes: std::result::Result<u64, Errno>) -> Event {
|
||||||
event: &FdEventData,
|
|
||||||
nbytes: std::result::Result<u64, types::Errno>,
|
|
||||||
) -> types::Event {
|
|
||||||
let (nbytes, error) = match nbytes {
|
let (nbytes, error) = match nbytes {
|
||||||
Ok(nbytes) => (nbytes, types::Errno::Success),
|
Ok(nbytes) => (nbytes, Errno::Success),
|
||||||
Err(e) => (u64::default(), e),
|
Err(e) => (u64::default(), e),
|
||||||
};
|
};
|
||||||
types::Event {
|
Event {
|
||||||
userdata: event.userdata,
|
userdata: event.userdata,
|
||||||
type_: event.r#type,
|
type_: event.r#type,
|
||||||
error,
|
error,
|
||||||
fd_readwrite: types::EventFdReadwrite {
|
fd_readwrite: EventFdReadwrite {
|
||||||
nbytes,
|
nbytes,
|
||||||
flags: types::Eventrwflags::empty(),
|
flags: Eventrwflags::empty(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_timeout_event(timeout: &ClockEventData) -> types::Event {
|
fn make_timeout_event(timeout: &ClockEventData) -> Event {
|
||||||
types::Event {
|
Event {
|
||||||
userdata: timeout.userdata,
|
userdata: timeout.userdata,
|
||||||
type_: types::Eventtype::Clock,
|
type_: Eventtype::Clock,
|
||||||
error: types::Errno::Success,
|
error: Errno::Success,
|
||||||
fd_readwrite: types::EventFdReadwrite {
|
fd_readwrite: EventFdReadwrite {
|
||||||
nbytes: 0,
|
nbytes: 0,
|
||||||
flags: types::Eventrwflags::empty(),
|
flags: Eventrwflags::empty(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_timeout(
|
fn handle_timeout(timeout_event: ClockEventData, timeout: Duration, events: &mut Vec<Event>) {
|
||||||
timeout_event: ClockEventData,
|
|
||||||
timeout: Duration,
|
|
||||||
events: &mut Vec<types::Event>,
|
|
||||||
) {
|
|
||||||
thread::sleep(timeout);
|
thread::sleep(timeout);
|
||||||
handle_timeout_event(timeout_event, events);
|
handle_timeout_event(timeout_event, events);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_timeout_event(timeout_event: ClockEventData, events: &mut Vec<types::Event>) {
|
fn handle_timeout_event(timeout_event: ClockEventData, events: &mut Vec<Event>) {
|
||||||
let new_event = make_timeout_event(&timeout_event);
|
let new_event = make_timeout_event(&timeout_event);
|
||||||
events.push(new_event);
|
events.push(new_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_rw_event(event: FdEventData, out_events: &mut Vec<types::Event>) {
|
fn handle_rw_event(event: FdEventData, out_events: &mut Vec<Event>) {
|
||||||
let handle = &event.handle;
|
let handle = &event.handle;
|
||||||
let size = if let Some(_) = handle.as_any().downcast_ref::<Stdin>() {
|
let size = if let Some(_) = handle.as_any().downcast_ref::<Stdin>() {
|
||||||
// We return the only universally correct lower bound, see the comment later in the function.
|
// We return the only universally correct lower bound, see the comment later in the function.
|
||||||
@@ -159,12 +153,12 @@ fn handle_rw_event(event: FdEventData, out_events: &mut Vec<types::Event>) {
|
|||||||
// On Unix, ioctl(FIONREAD) will return 0 for stdout/stderr. Emulate the same behavior on Windows.
|
// On Unix, ioctl(FIONREAD) will return 0 for stdout/stderr. Emulate the same behavior on Windows.
|
||||||
Ok(0)
|
Ok(0)
|
||||||
} else {
|
} else {
|
||||||
if event.r#type == types::Eventtype::FdRead {
|
if event.r#type == Eventtype::FdRead {
|
||||||
handle
|
handle
|
||||||
.as_file()
|
.as_file()
|
||||||
.and_then(|f| f.metadata())
|
.and_then(|f| f.metadata())
|
||||||
.map(|m| m.len())
|
.map(|m| m.len())
|
||||||
.map_err(|ioerror| types::Errno::from(Error::from(ioerror)))
|
.map_err(|ioerror| Errno::from(Error::from(ioerror)))
|
||||||
} else {
|
} else {
|
||||||
// The spec is unclear what nbytes should actually be for __WASI_EVENTTYPE_FD_WRITE and
|
// The spec is unclear what nbytes should actually be for __WASI_EVENTTYPE_FD_WRITE and
|
||||||
// the implementation on Unix just returns 0 here, so it's probably fine
|
// the implementation on Unix just returns 0 here, so it's probably fine
|
||||||
@@ -177,7 +171,7 @@ fn handle_rw_event(event: FdEventData, out_events: &mut Vec<types::Event>) {
|
|||||||
out_events.push(new_event);
|
out_events.push(new_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_error_event(event: FdEventData, error: types::Errno, out_events: &mut Vec<types::Event>) {
|
fn handle_error_event(event: FdEventData, error: Errno, out_events: &mut Vec<Event>) {
|
||||||
let new_event = make_rw_event(&event, Err(error));
|
let new_event = make_rw_event(&event, Err(error));
|
||||||
out_events.push(new_event);
|
out_events.push(new_event);
|
||||||
}
|
}
|
||||||
@@ -185,7 +179,7 @@ fn handle_error_event(event: FdEventData, error: types::Errno, out_events: &mut
|
|||||||
pub(crate) fn oneoff(
|
pub(crate) fn oneoff(
|
||||||
timeout: Option<ClockEventData>,
|
timeout: Option<ClockEventData>,
|
||||||
fd_events: Vec<FdEventData>,
|
fd_events: Vec<FdEventData>,
|
||||||
events: &mut Vec<types::Event>,
|
events: &mut Vec<Event>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let timeout = timeout
|
let timeout = timeout
|
||||||
.map(|event| {
|
.map(|event| {
|
||||||
@@ -234,7 +228,7 @@ pub(crate) fn oneoff(
|
|||||||
// considered immediately ready, following the behavior on Linux.
|
// considered immediately ready, following the behavior on Linux.
|
||||||
immediate_events.push(event);
|
immediate_events.push(event);
|
||||||
} else if let Some(other) = handle.as_any().downcast_ref::<OsOther>() {
|
} else if let Some(other) = handle.as_any().downcast_ref::<OsOther>() {
|
||||||
if other.get_file_type() == types::Filetype::SocketStream {
|
if other.get_file_type() == Filetype::SocketStream {
|
||||||
// We map pipe to SocketStream
|
// We map pipe to SocketStream
|
||||||
pipe_events.push(event);
|
pipe_events.push(event);
|
||||||
} else {
|
} else {
|
||||||
@@ -242,7 +236,7 @@ pub(crate) fn oneoff(
|
|||||||
"poll_oneoff: unsupported file type: {}",
|
"poll_oneoff: unsupported file type: {}",
|
||||||
other.get_file_type()
|
other.get_file_type()
|
||||||
);
|
);
|
||||||
handle_error_event(event, types::Errno::Notsup, events);
|
handle_error_event(event, Errno::Notsup, events);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tracing::error!("can poll FdEvent for OS resources only");
|
tracing::error!("can poll FdEvent for OS resources only");
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
use crate::handle::{Handle, HandleRights};
|
use crate::handle::{
|
||||||
use crate::wasi::{self, types, RightsExt};
|
Advice, Dircookie, Dirent, Fdflags, Filesize, Filestat, Filetype, Fstflags, Handle,
|
||||||
|
HandleRights, Oflags, Rights, RightsExt, Size, DIRCOOKIE_START,
|
||||||
|
};
|
||||||
|
use crate::sched::Timestamp;
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
@@ -39,44 +42,44 @@ pub(crate) trait MovableFile {
|
|||||||
pub trait FileContents {
|
pub trait FileContents {
|
||||||
/// The implementation-defined maximum size of the store corresponding to a `FileContents`
|
/// The implementation-defined maximum size of the store corresponding to a `FileContents`
|
||||||
/// implementation.
|
/// implementation.
|
||||||
fn max_size(&self) -> types::Filesize;
|
fn max_size(&self) -> Filesize;
|
||||||
/// The current number of bytes this `FileContents` describes.
|
/// The current number of bytes this `FileContents` describes.
|
||||||
fn size(&self) -> types::Filesize;
|
fn size(&self) -> Filesize;
|
||||||
/// Resize to hold `new_size` number of bytes, or error if this is not possible.
|
/// Resize to hold `new_size` number of bytes, or error if this is not possible.
|
||||||
fn resize(&mut self, new_size: types::Filesize) -> Result<()>;
|
fn resize(&mut self, new_size: Filesize) -> Result<()>;
|
||||||
/// Write a list of `IoSlice` starting at `offset`. `offset` plus the total size of all `iovs`
|
/// Write a list of `IoSlice` starting at `offset`. `offset` plus the total size of all `iovs`
|
||||||
/// is guaranteed to not exceed `max_size`. Implementations must not indicate more bytes have
|
/// is guaranteed to not exceed `max_size`. Implementations must not indicate more bytes have
|
||||||
/// been written than can be held by `iovs`.
|
/// been written than can be held by `iovs`.
|
||||||
fn pwritev(&mut self, iovs: &[io::IoSlice], offset: types::Filesize) -> Result<usize>;
|
fn pwritev(&mut self, iovs: &[io::IoSlice], offset: Filesize) -> Result<usize>;
|
||||||
/// Read from the file from `offset`, filling a list of `IoSlice`. The returend size must not
|
/// Read from the file from `offset`, filling a list of `IoSlice`. The returend size must not
|
||||||
/// be more than the capactiy of `iovs`, and must not exceed the limit reported by
|
/// be more than the capactiy of `iovs`, and must not exceed the limit reported by
|
||||||
/// `self.max_size()`.
|
/// `self.max_size()`.
|
||||||
fn preadv(&self, iovs: &mut [io::IoSliceMut], offset: types::Filesize) -> Result<usize>;
|
fn preadv(&self, iovs: &mut [io::IoSliceMut], offset: Filesize) -> Result<usize>;
|
||||||
/// Write contents from `buf` to this file starting at `offset`. `offset` plus the length of
|
/// Write contents from `buf` to this file starting at `offset`. `offset` plus the length of
|
||||||
/// `buf` is guaranteed to not exceed `max_size`. Implementations must not indicate more bytes
|
/// `buf` is guaranteed to not exceed `max_size`. Implementations must not indicate more bytes
|
||||||
/// have been written than the size of `buf`.
|
/// have been written than the size of `buf`.
|
||||||
fn pwrite(&mut self, buf: &[u8], offset: types::Filesize) -> Result<usize>;
|
fn pwrite(&mut self, buf: &[u8], offset: Filesize) -> Result<usize>;
|
||||||
/// Read from the file at `offset`, filling `buf`. The returned size must not be more than the
|
/// Read from the file at `offset`, filling `buf`. The returned size must not be more than the
|
||||||
/// capacity of `buf`, and `offset` plus the returned size must not exceed `self.max_size()`.
|
/// capacity of `buf`, and `offset` plus the returned size must not exceed `self.max_size()`.
|
||||||
fn pread(&self, buf: &mut [u8], offset: types::Filesize) -> Result<usize>;
|
fn pread(&self, buf: &mut [u8], offset: Filesize) -> Result<usize>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FileContents for VecFileContents {
|
impl FileContents for VecFileContents {
|
||||||
fn max_size(&self) -> types::Filesize {
|
fn max_size(&self) -> Filesize {
|
||||||
std::usize::MAX as types::Filesize
|
std::usize::MAX as Filesize
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size(&self) -> types::Filesize {
|
fn size(&self) -> Filesize {
|
||||||
self.content.len() as types::Filesize
|
self.content.len() as Filesize
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resize(&mut self, new_size: types::Filesize) -> Result<()> {
|
fn resize(&mut self, new_size: Filesize) -> Result<()> {
|
||||||
let new_size: usize = new_size.try_into().map_err(|_| Error::Inval)?;
|
let new_size: usize = new_size.try_into().map_err(|_| Error::Inval)?;
|
||||||
self.content.resize(new_size, 0);
|
self.content.resize(new_size, 0);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn preadv(&self, iovs: &mut [io::IoSliceMut], offset: types::Filesize) -> Result<usize> {
|
fn preadv(&self, iovs: &mut [io::IoSliceMut], offset: Filesize) -> Result<usize> {
|
||||||
let mut read_total = 0usize;
|
let mut read_total = 0usize;
|
||||||
for iov in iovs.iter_mut() {
|
for iov in iovs.iter_mut() {
|
||||||
let skip: u64 = read_total.try_into().map_err(|_| Error::Inval)?;
|
let skip: u64 = read_total.try_into().map_err(|_| Error::Inval)?;
|
||||||
@@ -86,7 +89,7 @@ impl FileContents for VecFileContents {
|
|||||||
Ok(read_total)
|
Ok(read_total)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pwritev(&mut self, iovs: &[io::IoSlice], offset: types::Filesize) -> Result<usize> {
|
fn pwritev(&mut self, iovs: &[io::IoSlice], offset: Filesize) -> Result<usize> {
|
||||||
let mut write_total = 0usize;
|
let mut write_total = 0usize;
|
||||||
for iov in iovs.iter() {
|
for iov in iovs.iter() {
|
||||||
let skip: u64 = write_total.try_into().map_err(|_| Error::Inval)?;
|
let skip: u64 = write_total.try_into().map_err(|_| Error::Inval)?;
|
||||||
@@ -96,7 +99,7 @@ impl FileContents for VecFileContents {
|
|||||||
Ok(write_total)
|
Ok(write_total)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pread(&self, buf: &mut [u8], offset: types::Filesize) -> Result<usize> {
|
fn pread(&self, buf: &mut [u8], offset: Filesize) -> Result<usize> {
|
||||||
trace!(buffer_length = buf.len(), offset = offset, "pread");
|
trace!(buffer_length = buf.len(), offset = offset, "pread");
|
||||||
let offset: usize = offset.try_into().map_err(|_| Error::Inval)?;
|
let offset: usize = offset.try_into().map_err(|_| Error::Inval)?;
|
||||||
|
|
||||||
@@ -109,7 +112,7 @@ impl FileContents for VecFileContents {
|
|||||||
Ok(read_count)
|
Ok(read_count)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pwrite(&mut self, buf: &[u8], offset: types::Filesize) -> Result<usize> {
|
fn pwrite(&mut self, buf: &[u8], offset: Filesize) -> Result<usize> {
|
||||||
let offset: usize = offset.try_into().map_err(|_| Error::Inval)?;
|
let offset: usize = offset.try_into().map_err(|_| Error::Inval)?;
|
||||||
|
|
||||||
let write_end = offset.checked_add(buf.len()).ok_or(Error::Fbig)?;
|
let write_end = offset.checked_add(buf.len()).ok_or(Error::Fbig)?;
|
||||||
@@ -141,9 +144,9 @@ impl VecFileContents {
|
|||||||
/// of data and permissions on a filesystem.
|
/// of data and permissions on a filesystem.
|
||||||
pub struct InMemoryFile {
|
pub struct InMemoryFile {
|
||||||
rights: Cell<HandleRights>,
|
rights: Cell<HandleRights>,
|
||||||
cursor: Cell<types::Filesize>,
|
cursor: Cell<Filesize>,
|
||||||
parent: Rc<RefCell<Option<Box<dyn Handle>>>>,
|
parent: Rc<RefCell<Option<Box<dyn Handle>>>>,
|
||||||
fd_flags: Cell<types::Fdflags>,
|
fd_flags: Cell<Fdflags>,
|
||||||
data: Rc<RefCell<Box<dyn FileContents>>>,
|
data: Rc<RefCell<Box<dyn FileContents>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,14 +157,14 @@ impl InMemoryFile {
|
|||||||
|
|
||||||
pub fn new(contents: Box<dyn FileContents>) -> Self {
|
pub fn new(contents: Box<dyn FileContents>) -> Self {
|
||||||
let rights = HandleRights::new(
|
let rights = HandleRights::new(
|
||||||
types::Rights::regular_file_base(),
|
Rights::regular_file_base(),
|
||||||
types::Rights::regular_file_inheriting(),
|
Rights::regular_file_inheriting(),
|
||||||
);
|
);
|
||||||
let rights = Cell::new(rights);
|
let rights = Cell::new(rights);
|
||||||
Self {
|
Self {
|
||||||
rights,
|
rights,
|
||||||
cursor: Cell::new(0),
|
cursor: Cell::new(0),
|
||||||
fd_flags: Cell::new(types::Fdflags::empty()),
|
fd_flags: Cell::new(Fdflags::empty()),
|
||||||
parent: Rc::new(RefCell::new(None)),
|
parent: Rc::new(RefCell::new(None)),
|
||||||
data: Rc::new(RefCell::new(contents)),
|
data: Rc::new(RefCell::new(contents)),
|
||||||
}
|
}
|
||||||
@@ -187,8 +190,8 @@ impl Handle for InMemoryFile {
|
|||||||
data: Rc::clone(&self.data),
|
data: Rc::clone(&self.data),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
fn get_file_type(&self) -> types::Filetype {
|
fn get_file_type(&self) -> Filetype {
|
||||||
types::Filetype::RegularFile
|
Filetype::RegularFile
|
||||||
}
|
}
|
||||||
fn get_rights(&self) -> HandleRights {
|
fn get_rights(&self) -> HandleRights {
|
||||||
self.rights.get()
|
self.rights.get()
|
||||||
@@ -197,16 +200,11 @@ impl Handle for InMemoryFile {
|
|||||||
self.rights.set(rights)
|
self.rights.set(rights)
|
||||||
}
|
}
|
||||||
// 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<()> {
|
|
||||||
// we'll just ignore advice for now, unless it's totally invalid
|
// we'll just ignore advice for now, unless it's totally invalid
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn allocate(&self, offset: types::Filesize, len: types::Filesize) -> Result<()> {
|
fn allocate(&self, offset: Filesize, len: Filesize) -> Result<()> {
|
||||||
let new_limit = offset.checked_add(len).ok_or(Error::Fbig)?;
|
let new_limit = offset.checked_add(len).ok_or(Error::Fbig)?;
|
||||||
let mut data = self.data.borrow_mut();
|
let mut data = self.data.borrow_mut();
|
||||||
|
|
||||||
@@ -220,15 +218,15 @@ impl Handle for InMemoryFile {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn fdstat_get(&self) -> Result<types::Fdflags> {
|
fn fdstat_get(&self) -> Result<Fdflags> {
|
||||||
Ok(self.fd_flags.get())
|
Ok(self.fd_flags.get())
|
||||||
}
|
}
|
||||||
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
|
fn fdstat_set_flags(&self, fdflags: Fdflags) -> Result<()> {
|
||||||
self.fd_flags.set(fdflags);
|
self.fd_flags.set(fdflags);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn filestat_get(&self) -> Result<types::Filestat> {
|
fn filestat_get(&self) -> Result<Filestat> {
|
||||||
let stat = types::Filestat {
|
let stat = Filestat {
|
||||||
dev: 0,
|
dev: 0,
|
||||||
ino: 0,
|
ino: 0,
|
||||||
nlink: 0,
|
nlink: 0,
|
||||||
@@ -240,17 +238,17 @@ impl Handle for InMemoryFile {
|
|||||||
};
|
};
|
||||||
Ok(stat)
|
Ok(stat)
|
||||||
}
|
}
|
||||||
fn filestat_set_size(&self, st_size: types::Filesize) -> Result<()> {
|
fn filestat_set_size(&self, st_size: Filesize) -> Result<()> {
|
||||||
let mut data = self.data.borrow_mut();
|
let mut data = self.data.borrow_mut();
|
||||||
if st_size > data.max_size() {
|
if st_size > data.max_size() {
|
||||||
return Err(Error::Fbig);
|
return Err(Error::Fbig);
|
||||||
}
|
}
|
||||||
data.resize(st_size)
|
data.resize(st_size)
|
||||||
}
|
}
|
||||||
fn preadv(&self, buf: &mut [io::IoSliceMut], offset: types::Filesize) -> Result<usize> {
|
fn preadv(&self, buf: &mut [io::IoSliceMut], offset: Filesize) -> Result<usize> {
|
||||||
self.data.borrow_mut().preadv(buf, offset)
|
self.data.borrow_mut().preadv(buf, offset)
|
||||||
}
|
}
|
||||||
fn pwritev(&self, buf: &[io::IoSlice], offset: types::Filesize) -> Result<usize> {
|
fn pwritev(&self, buf: &[io::IoSlice], offset: Filesize) -> Result<usize> {
|
||||||
self.data.borrow_mut().pwritev(buf, offset)
|
self.data.borrow_mut().pwritev(buf, offset)
|
||||||
}
|
}
|
||||||
fn read_vectored(&self, iovs: &mut [io::IoSliceMut]) -> Result<usize> {
|
fn read_vectored(&self, iovs: &mut [io::IoSliceMut]) -> Result<usize> {
|
||||||
@@ -262,7 +260,7 @@ impl Handle for InMemoryFile {
|
|||||||
self.cursor.set(update);
|
self.cursor.set(update);
|
||||||
Ok(read)
|
Ok(read)
|
||||||
}
|
}
|
||||||
fn seek(&self, offset: SeekFrom) -> Result<types::Filesize> {
|
fn seek(&self, offset: SeekFrom) -> Result<Filesize> {
|
||||||
let content_len = self.data.borrow().size();
|
let content_len = self.data.borrow().size();
|
||||||
match offset {
|
match offset {
|
||||||
SeekFrom::Current(offset) => {
|
SeekFrom::Current(offset) => {
|
||||||
@@ -297,7 +295,7 @@ impl Handle for InMemoryFile {
|
|||||||
trace!("write_vectored(iovs={:?})", iovs);
|
trace!("write_vectored(iovs={:?})", iovs);
|
||||||
let mut data = self.data.borrow_mut();
|
let mut data = self.data.borrow_mut();
|
||||||
|
|
||||||
let append_mode = self.fd_flags.get().contains(&types::Fdflags::APPEND);
|
let append_mode = self.fd_flags.get().contains(&Fdflags::APPEND);
|
||||||
trace!(" | fd_flags={}", self.fd_flags.get());
|
trace!(" | fd_flags={}", self.fd_flags.get());
|
||||||
|
|
||||||
// If this file is in append mode, we write to the end.
|
// If this file is in append mode, we write to the end.
|
||||||
@@ -310,7 +308,7 @@ impl Handle for InMemoryFile {
|
|||||||
let max_size = iovs
|
let max_size = iovs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|iov| {
|
.map(|iov| {
|
||||||
let cast_iovlen: types::Size = iov
|
let cast_iovlen: Size = iov
|
||||||
.len()
|
.len()
|
||||||
.try_into()
|
.try_into()
|
||||||
.expect("iovec are bounded by wasi max sizes");
|
.expect("iovec are bounded by wasi max sizes");
|
||||||
@@ -319,7 +317,7 @@ impl Handle for InMemoryFile {
|
|||||||
.fold(Some(0u32), |len, iov| len.and_then(|x| x.checked_add(iov)))
|
.fold(Some(0u32), |len, iov| len.and_then(|x| x.checked_add(iov)))
|
||||||
.expect("write_vectored will not be called with invalid iovs");
|
.expect("write_vectored will not be called with invalid iovs");
|
||||||
|
|
||||||
if let Some(end) = write_start.checked_add(max_size as types::Filesize) {
|
if let Some(end) = write_start.checked_add(max_size as Filesize) {
|
||||||
if end > data.max_size() {
|
if end > data.max_size() {
|
||||||
return Err(Error::Fbig);
|
return Err(Error::Fbig);
|
||||||
}
|
}
|
||||||
@@ -348,10 +346,10 @@ impl Handle for InMemoryFile {
|
|||||||
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>> {
|
||||||
if oflags.contains(&types::Oflags::DIRECTORY) {
|
if oflags.contains(&Oflags::DIRECTORY) {
|
||||||
tracing::trace!(
|
tracing::trace!(
|
||||||
"InMemoryFile::openat was passed oflags DIRECTORY, but {:?} is a file.",
|
"InMemoryFile::openat was passed oflags DIRECTORY, but {:?} is a file.",
|
||||||
path
|
path
|
||||||
@@ -411,10 +409,7 @@ pub struct VirtualDir {
|
|||||||
|
|
||||||
impl VirtualDir {
|
impl VirtualDir {
|
||||||
pub fn new(writable: bool) -> Self {
|
pub fn new(writable: bool) -> Self {
|
||||||
let rights = HandleRights::new(
|
let rights = HandleRights::new(Rights::directory_base(), Rights::directory_inheriting());
|
||||||
types::Rights::directory_base(),
|
|
||||||
types::Rights::directory_inheriting(),
|
|
||||||
);
|
|
||||||
let rights = Cell::new(rights);
|
let rights = Cell::new(rights);
|
||||||
Self {
|
Self {
|
||||||
rights,
|
rights,
|
||||||
@@ -480,8 +475,8 @@ impl Handle for VirtualDir {
|
|||||||
entries: Rc::clone(&self.entries),
|
entries: Rc::clone(&self.entries),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
fn get_file_type(&self) -> types::Filetype {
|
fn get_file_type(&self) -> Filetype {
|
||||||
types::Filetype::Directory
|
Filetype::Directory
|
||||||
}
|
}
|
||||||
fn get_rights(&self) -> HandleRights {
|
fn get_rights(&self) -> HandleRights {
|
||||||
self.rights.get()
|
self.rights.get()
|
||||||
@@ -490,8 +485,8 @@ impl Handle for VirtualDir {
|
|||||||
self.rights.set(rights)
|
self.rights.set(rights)
|
||||||
}
|
}
|
||||||
// FdOps
|
// FdOps
|
||||||
fn filestat_get(&self) -> Result<types::Filestat> {
|
fn filestat_get(&self) -> Result<Filestat> {
|
||||||
let stat = types::Filestat {
|
let stat = Filestat {
|
||||||
dev: 0,
|
dev: 0,
|
||||||
ino: 0,
|
ino: 0,
|
||||||
nlink: 0,
|
nlink: 0,
|
||||||
@@ -505,36 +500,36 @@ impl Handle for VirtualDir {
|
|||||||
}
|
}
|
||||||
fn readdir(
|
fn readdir(
|
||||||
&self,
|
&self,
|
||||||
cookie: types::Dircookie,
|
cookie: Dircookie,
|
||||||
) -> Result<Box<dyn Iterator<Item = Result<(types::Dirent, String)>>>> {
|
) -> Result<Box<dyn Iterator<Item = Result<(Dirent, String)>>>> {
|
||||||
struct VirtualDirIter {
|
struct VirtualDirIter {
|
||||||
start: u32,
|
start: u32,
|
||||||
entries: Rc<RefCell<HashMap<PathBuf, Box<dyn Handle>>>>,
|
entries: Rc<RefCell<HashMap<PathBuf, Box<dyn Handle>>>>,
|
||||||
}
|
}
|
||||||
impl Iterator for VirtualDirIter {
|
impl Iterator for VirtualDirIter {
|
||||||
type Item = Result<(types::Dirent, String)>;
|
type Item = Result<(Dirent, String)>;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
tracing::trace!("VirtualDirIter::next continuing from {}", self.start);
|
tracing::trace!("VirtualDirIter::next continuing from {}", self.start);
|
||||||
if self.start == SELF_DIR_COOKIE {
|
if self.start == SELF_DIR_COOKIE {
|
||||||
self.start += 1;
|
self.start += 1;
|
||||||
let name = ".".to_owned();
|
let name = ".".to_owned();
|
||||||
let dirent = types::Dirent {
|
let dirent = Dirent {
|
||||||
d_next: self.start as u64,
|
d_next: self.start as u64,
|
||||||
d_ino: 0,
|
d_ino: 0,
|
||||||
d_namlen: name.len() as _,
|
d_namlen: name.len() as _,
|
||||||
d_type: types::Filetype::Directory,
|
d_type: Filetype::Directory,
|
||||||
};
|
};
|
||||||
return Some(Ok((dirent, name)));
|
return Some(Ok((dirent, name)));
|
||||||
}
|
}
|
||||||
if self.start == PARENT_DIR_COOKIE {
|
if self.start == PARENT_DIR_COOKIE {
|
||||||
self.start += 1;
|
self.start += 1;
|
||||||
let name = "..".to_owned();
|
let name = "..".to_owned();
|
||||||
let dirent = types::Dirent {
|
let dirent = Dirent {
|
||||||
d_next: self.start as u64,
|
d_next: self.start as u64,
|
||||||
d_ino: 0,
|
d_ino: 0,
|
||||||
d_namlen: name.len() as _,
|
d_namlen: name.len() as _,
|
||||||
d_type: types::Filetype::Directory,
|
d_type: Filetype::Directory,
|
||||||
};
|
};
|
||||||
return Some(Ok((dirent, name)));
|
return Some(Ok((dirent, name)));
|
||||||
}
|
}
|
||||||
@@ -559,8 +554,8 @@ impl Handle for VirtualDir {
|
|||||||
.to_str()
|
.to_str()
|
||||||
.expect("wasi paths are valid utf8 strings")
|
.expect("wasi paths are valid utf8 strings")
|
||||||
.to_owned();
|
.to_owned();
|
||||||
let dirent = || -> Result<types::Dirent> {
|
let dirent = || -> Result<Dirent> {
|
||||||
let dirent = types::Dirent {
|
let dirent = Dirent {
|
||||||
d_namlen: name.len().try_into()?,
|
d_namlen: name.len().try_into()?,
|
||||||
d_type: file.get_file_type(),
|
d_type: file.get_file_type(),
|
||||||
d_ino: 0,
|
d_ino: 0,
|
||||||
@@ -601,34 +596,22 @@ impl Handle for VirtualDir {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn filestat_get_at(&self, path: &str, _follow: bool) -> Result<types::Filestat> {
|
fn filestat_get_at(&self, path: &str, _follow: bool) -> Result<Filestat> {
|
||||||
let stat = self
|
let stat = self
|
||||||
.openat(
|
.openat(path, false, false, Oflags::empty(), Fdflags::empty())?
|
||||||
path,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
types::Oflags::empty(),
|
|
||||||
types::Fdflags::empty(),
|
|
||||||
)?
|
|
||||||
.filestat_get()?;
|
.filestat_get()?;
|
||||||
Ok(stat)
|
Ok(stat)
|
||||||
}
|
}
|
||||||
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<()> {
|
||||||
self.openat(
|
self.openat(path, false, false, Oflags::empty(), Fdflags::empty())?
|
||||||
path,
|
.filestat_set_times(atim, mtim, fst_flags)?;
|
||||||
false,
|
|
||||||
false,
|
|
||||||
types::Oflags::empty(),
|
|
||||||
types::Fdflags::empty(),
|
|
||||||
)?
|
|
||||||
.filestat_set_times(atim, mtim, fst_flags)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
fn openat(
|
fn openat(
|
||||||
@@ -636,8 +619,8 @@ impl Handle for VirtualDir {
|
|||||||
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>> {
|
||||||
if path == "." {
|
if path == "." {
|
||||||
return self.try_clone().map_err(Into::into);
|
return self.try_clone().map_err(Into::into);
|
||||||
@@ -659,14 +642,14 @@ impl Handle for VirtualDir {
|
|||||||
let entry_count = entries.len();
|
let entry_count = entries.len();
|
||||||
match entries.entry(Path::new(file_name).to_path_buf()) {
|
match entries.entry(Path::new(file_name).to_path_buf()) {
|
||||||
Entry::Occupied(e) => {
|
Entry::Occupied(e) => {
|
||||||
let creat_excl_mask = types::Oflags::CREAT | types::Oflags::EXCL;
|
let creat_excl_mask = Oflags::CREAT | Oflags::EXCL;
|
||||||
if (oflags & creat_excl_mask) == creat_excl_mask {
|
if (oflags & creat_excl_mask) == creat_excl_mask {
|
||||||
tracing::trace!("VirtualDir::openat was passed oflags CREAT|EXCL, but the file {:?} exists.", file_name);
|
tracing::trace!("VirtualDir::openat was passed oflags CREAT|EXCL, but the file {:?} exists.", file_name);
|
||||||
return Err(Error::Exist);
|
return Err(Error::Exist);
|
||||||
}
|
}
|
||||||
|
|
||||||
if oflags.contains(&types::Oflags::DIRECTORY)
|
if oflags.contains(&Oflags::DIRECTORY)
|
||||||
&& e.get().get_file_type() != types::Filetype::Directory
|
&& e.get().get_file_type() != Filetype::Directory
|
||||||
{
|
{
|
||||||
tracing::trace!(
|
tracing::trace!(
|
||||||
"VirtualDir::openat was passed oflags DIRECTORY, but {:?} is a file.",
|
"VirtualDir::openat was passed oflags DIRECTORY, but {:?} is a file.",
|
||||||
@@ -709,12 +692,12 @@ impl Handle for VirtualDir {
|
|||||||
match entries.entry(Path::new(trimmed_path).to_path_buf()) {
|
match entries.entry(Path::new(trimmed_path).to_path_buf()) {
|
||||||
Entry::Occupied(e) => {
|
Entry::Occupied(e) => {
|
||||||
// first, does this name a directory?
|
// first, does this name a directory?
|
||||||
if e.get().get_file_type() != types::Filetype::Directory {
|
if e.get().get_file_type() != Filetype::Directory {
|
||||||
return Err(Error::Notdir);
|
return Err(Error::Notdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Okay, but is the directory empty?
|
// Okay, but is the directory empty?
|
||||||
let iter = e.get().readdir(wasi::DIRCOOKIE_START)?;
|
let iter = e.get().readdir(DIRCOOKIE_START)?;
|
||||||
if iter.skip(RESERVED_ENTRY_COUNT as usize).next().is_some() {
|
if iter.skip(RESERVED_ENTRY_COUNT as usize).next().is_some() {
|
||||||
return Err(Error::Notempty);
|
return Err(Error::Notempty);
|
||||||
}
|
}
|
||||||
@@ -757,7 +740,7 @@ impl Handle for VirtualDir {
|
|||||||
match entries.entry(Path::new(trimmed_path).to_path_buf()) {
|
match entries.entry(Path::new(trimmed_path).to_path_buf()) {
|
||||||
Entry::Occupied(e) => {
|
Entry::Occupied(e) => {
|
||||||
// Directories must be removed through `remove_directory`, not `unlink_file`.
|
// Directories must be removed through `remove_directory`, not `unlink_file`.
|
||||||
if e.get().get_file_type() == types::Filetype::Directory {
|
if e.get().get_file_type() == Filetype::Directory {
|
||||||
return Err(Error::Isdir);
|
return Err(Error::Isdir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,9 @@
|
|||||||
//!
|
//!
|
||||||
//! Note that `poll_oneoff` is not supported for these types, so they do not match the behavior of
|
//! Note that `poll_oneoff` is not supported for these types, so they do not match the behavior of
|
||||||
//! real pipes exactly.
|
//! real pipes exactly.
|
||||||
use crate::handle::{Handle, HandleRights};
|
use crate::handle::{
|
||||||
use crate::wasi::types;
|
Advice, Fdflags, Filesize, Filestat, Filetype, Handle, HandleRights, Oflags, Rights,
|
||||||
|
};
|
||||||
use crate::{Error, Result};
|
use crate::{Error, Result};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
@@ -54,7 +55,6 @@ impl<R: Read + Any> ReadPipe<R> {
|
|||||||
///
|
///
|
||||||
/// All `Handle` read operations delegate to reading from this underlying reader.
|
/// All `Handle` read operations delegate to reading from this underlying reader.
|
||||||
pub fn from_shared(reader: Arc<RwLock<R>>) -> Self {
|
pub fn from_shared(reader: Arc<RwLock<R>>) -> Self {
|
||||||
use types::Rights;
|
|
||||||
Self {
|
Self {
|
||||||
rights: RwLock::new(HandleRights::from_base(
|
rights: RwLock::new(HandleRights::from_base(
|
||||||
Rights::FD_DATASYNC
|
Rights::FD_DATASYNC
|
||||||
@@ -115,8 +115,8 @@ impl<R: Read + Any> Handle for ReadPipe<R> {
|
|||||||
Ok(Box::new(self.clone()))
|
Ok(Box::new(self.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_file_type(&self) -> types::Filetype {
|
fn get_file_type(&self) -> Filetype {
|
||||||
types::Filetype::Unknown
|
Filetype::Unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rights(&self) -> HandleRights {
|
fn get_rights(&self) -> HandleRights {
|
||||||
@@ -127,26 +127,21 @@ impl<R: Read + Any> Handle for ReadPipe<R> {
|
|||||||
*self.rights.write().unwrap() = rights;
|
*self.rights.write().unwrap() = rights;
|
||||||
}
|
}
|
||||||
|
|
||||||
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::Spipe)
|
Err(Error::Spipe)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate(&self, _offset: types::Filesize, _len: types::Filesize) -> Result<()> {
|
fn allocate(&self, _offset: Filesize, _len: Filesize) -> Result<()> {
|
||||||
Err(Error::Spipe)
|
Err(Error::Spipe)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fdstat_set_flags(&self, _fdflags: types::Fdflags) -> Result<()> {
|
fn fdstat_set_flags(&self, _fdflags: Fdflags) -> Result<()> {
|
||||||
// do nothing for now
|
// do nothing for now
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filestat_get(&self) -> Result<types::Filestat> {
|
fn filestat_get(&self) -> Result<Filestat> {
|
||||||
let stat = types::Filestat {
|
let stat = Filestat {
|
||||||
dev: 0,
|
dev: 0,
|
||||||
ino: 0,
|
ino: 0,
|
||||||
nlink: 0,
|
nlink: 0,
|
||||||
@@ -159,18 +154,18 @@ impl<R: Read + Any> Handle for ReadPipe<R> {
|
|||||||
Ok(stat)
|
Ok(stat)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filestat_set_size(&self, _st_size: types::Filesize) -> Result<()> {
|
fn filestat_set_size(&self, _st_size: Filesize) -> Result<()> {
|
||||||
Err(Error::Spipe)
|
Err(Error::Spipe)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn preadv(&self, buf: &mut [io::IoSliceMut], offset: types::Filesize) -> Result<usize> {
|
fn preadv(&self, buf: &mut [io::IoSliceMut], offset: Filesize) -> Result<usize> {
|
||||||
if offset != 0 {
|
if offset != 0 {
|
||||||
return Err(Error::Spipe);
|
return Err(Error::Spipe);
|
||||||
}
|
}
|
||||||
Ok(self.reader.write().unwrap().read_vectored(buf)?)
|
Ok(self.reader.write().unwrap().read_vectored(buf)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn seek(&self, _offset: io::SeekFrom) -> Result<types::Filesize> {
|
fn seek(&self, _offset: io::SeekFrom) -> Result<Filesize> {
|
||||||
Err(Error::Spipe)
|
Err(Error::Spipe)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,8 +182,8 @@ impl<R: Read + Any> Handle for ReadPipe<R> {
|
|||||||
_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::Notdir)
|
Err(Error::Notdir)
|
||||||
}
|
}
|
||||||
@@ -256,7 +251,6 @@ impl<W: Write + Any> WritePipe<W> {
|
|||||||
///
|
///
|
||||||
/// All `Handle` write operations delegate to writing to this underlying writer.
|
/// All `Handle` write operations delegate to writing to this underlying writer.
|
||||||
pub fn from_shared(writer: Arc<RwLock<W>>) -> Self {
|
pub fn from_shared(writer: Arc<RwLock<W>>) -> Self {
|
||||||
use types::Rights;
|
|
||||||
Self {
|
Self {
|
||||||
rights: RwLock::new(HandleRights::from_base(
|
rights: RwLock::new(HandleRights::from_base(
|
||||||
Rights::FD_DATASYNC
|
Rights::FD_DATASYNC
|
||||||
@@ -300,8 +294,8 @@ impl<W: Write + Any> Handle for WritePipe<W> {
|
|||||||
Ok(Box::new(self.clone()))
|
Ok(Box::new(self.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_file_type(&self) -> types::Filetype {
|
fn get_file_type(&self) -> Filetype {
|
||||||
types::Filetype::Unknown
|
Filetype::Unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rights(&self) -> HandleRights {
|
fn get_rights(&self) -> HandleRights {
|
||||||
@@ -312,26 +306,21 @@ impl<W: Write + Any> Handle for WritePipe<W> {
|
|||||||
*self.rights.write().unwrap() = rights;
|
*self.rights.write().unwrap() = rights;
|
||||||
}
|
}
|
||||||
|
|
||||||
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::Spipe)
|
Err(Error::Spipe)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn allocate(&self, _offset: types::Filesize, _len: types::Filesize) -> Result<()> {
|
fn allocate(&self, _offset: Filesize, _len: Filesize) -> Result<()> {
|
||||||
Err(Error::Spipe)
|
Err(Error::Spipe)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fdstat_set_flags(&self, _fdflags: types::Fdflags) -> Result<()> {
|
fn fdstat_set_flags(&self, _fdflags: Fdflags) -> Result<()> {
|
||||||
// do nothing for now
|
// do nothing for now
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filestat_get(&self) -> Result<types::Filestat> {
|
fn filestat_get(&self) -> Result<Filestat> {
|
||||||
let stat = types::Filestat {
|
let stat = Filestat {
|
||||||
dev: 0,
|
dev: 0,
|
||||||
ino: 0,
|
ino: 0,
|
||||||
nlink: 0,
|
nlink: 0,
|
||||||
@@ -344,18 +333,18 @@ impl<W: Write + Any> Handle for WritePipe<W> {
|
|||||||
Ok(stat)
|
Ok(stat)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filestat_set_size(&self, _st_size: types::Filesize) -> Result<()> {
|
fn filestat_set_size(&self, _st_size: Filesize) -> Result<()> {
|
||||||
Err(Error::Spipe)
|
Err(Error::Spipe)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pwritev(&self, buf: &[io::IoSlice], offset: types::Filesize) -> Result<usize> {
|
fn pwritev(&self, buf: &[io::IoSlice], offset: Filesize) -> Result<usize> {
|
||||||
if offset != 0 {
|
if offset != 0 {
|
||||||
return Err(Error::Spipe);
|
return Err(Error::Spipe);
|
||||||
}
|
}
|
||||||
Ok(self.writer.write().unwrap().write_vectored(buf)?)
|
Ok(self.writer.write().unwrap().write_vectored(buf)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn seek(&self, _offset: io::SeekFrom) -> Result<types::Filesize> {
|
fn seek(&self, _offset: io::SeekFrom) -> Result<Filesize> {
|
||||||
Err(Error::Spipe)
|
Err(Error::Spipe)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,8 +361,8 @@ impl<W: Write + Any> Handle for WritePipe<W> {
|
|||||||
_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::Notdir)
|
Err(Error::Notdir)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user