restructure cap-std impls into their own crate
This commit is contained in:
@@ -28,3 +28,9 @@ impl WasiMonotonicClock for MonotonicClock {
|
||||
self.now_with(precision)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WasiClocks {
|
||||
pub system: Box<dyn WasiSystemClock>,
|
||||
pub monotonic: Box<dyn WasiMonotonicClock>,
|
||||
pub creation_time: cap_std::time::Instant,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::clocks::{WasiMonotonicClock, WasiSystemClock};
|
||||
use crate::clocks::WasiClocks;
|
||||
use crate::dir::{DirCaps, DirEntry, WasiDir};
|
||||
use crate::file::{FileCaps, FileEntry, WasiFile};
|
||||
use crate::sched::{SyncSched, WasiSched};
|
||||
use crate::sched::WasiSched;
|
||||
use crate::string_array::{StringArray, StringArrayError};
|
||||
use crate::table::Table;
|
||||
use crate::Error;
|
||||
@@ -11,28 +11,29 @@ use std::path::{Path, PathBuf};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub struct WasiCtx {
|
||||
pub(crate) args: StringArray,
|
||||
pub(crate) env: StringArray,
|
||||
pub(crate) random: RefCell<Box<dyn RngCore>>,
|
||||
pub(crate) clocks: WasiCtxClocks,
|
||||
pub(crate) sched: Box<dyn WasiSched>,
|
||||
table: Rc<RefCell<Table>>,
|
||||
pub args: StringArray,
|
||||
pub env: StringArray,
|
||||
pub random: RefCell<Box<dyn RngCore>>,
|
||||
pub clocks: WasiClocks,
|
||||
pub sched: Box<dyn WasiSched>,
|
||||
pub table: Rc<RefCell<Table>>,
|
||||
}
|
||||
|
||||
impl WasiCtx {
|
||||
pub fn builder() -> WasiCtxBuilder {
|
||||
WasiCtxBuilder(WasiCtx::new())
|
||||
}
|
||||
|
||||
pub fn new() -> Self {
|
||||
WasiCtx {
|
||||
pub fn builder(
|
||||
random: RefCell<Box<dyn RngCore>>,
|
||||
clocks: WasiClocks,
|
||||
sched: Box<dyn WasiSched>,
|
||||
table: Rc<RefCell<Table>>,
|
||||
) -> WasiCtxBuilder {
|
||||
WasiCtxBuilder(WasiCtx {
|
||||
args: StringArray::new(),
|
||||
env: StringArray::new(),
|
||||
random: RefCell::new(Box::new(unsafe { cap_rand::rngs::OsRng::default() })),
|
||||
clocks: WasiCtxClocks::default(),
|
||||
sched: Box::new(SyncSched::default()),
|
||||
table: Rc::new(RefCell::new(Table::new())),
|
||||
}
|
||||
random,
|
||||
clocks,
|
||||
sched,
|
||||
table,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn insert_file(&self, fd: u32, file: Box<dyn WasiFile>, caps: FileCaps) {
|
||||
@@ -98,12 +99,6 @@ impl WasiCtxBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn inherit_stdio(self) -> Self {
|
||||
self.stdin(Box::new(crate::stdio::stdin()))
|
||||
.stdout(Box::new(crate::stdio::stdout()))
|
||||
.stderr(Box::new(crate::stdio::stderr()))
|
||||
}
|
||||
|
||||
pub fn preopened_dir(
|
||||
self,
|
||||
dir: Box<dyn WasiDir>,
|
||||
@@ -119,29 +114,4 @@ impl WasiCtxBuilder {
|
||||
)))?;
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
pub fn random(self, random: Box<dyn RngCore>) -> Self {
|
||||
self.0.random.replace(random);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WasiCtxClocks {
|
||||
pub(crate) system: Box<dyn WasiSystemClock>,
|
||||
pub(crate) monotonic: Box<dyn WasiMonotonicClock>,
|
||||
pub(crate) creation_time: cap_std::time::Instant,
|
||||
}
|
||||
|
||||
impl Default for WasiCtxClocks {
|
||||
fn default() -> WasiCtxClocks {
|
||||
let system = Box::new(unsafe { cap_std::time::SystemClock::new() });
|
||||
let monotonic = unsafe { cap_std::time::MonotonicClock::new() };
|
||||
let creation_time = monotonic.now();
|
||||
let monotonic = Box::new(monotonic);
|
||||
WasiCtxClocks {
|
||||
system,
|
||||
monotonic,
|
||||
creation_time,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,8 @@ use bitflags::bitflags;
|
||||
use cap_fs_ext::SystemTimeSpec;
|
||||
use std::any::Any;
|
||||
use std::cell::Ref;
|
||||
use std::convert::TryInto;
|
||||
use std::ops::Deref;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::PathBuf;
|
||||
|
||||
pub trait WasiDir {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
@@ -187,211 +186,3 @@ impl From<ReaddirCursor> for u64 {
|
||||
c.0
|
||||
}
|
||||
}
|
||||
|
||||
impl WasiDir for cap_std::fs::Dir {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn open_file(
|
||||
&self,
|
||||
symlink_follow: bool,
|
||||
path: &str,
|
||||
oflags: OFlags,
|
||||
caps: FileCaps,
|
||||
fdflags: FdFlags,
|
||||
) -> Result<Box<dyn WasiFile>, Error> {
|
||||
use cap_fs_ext::{FollowSymlinks, OpenOptionsFollowExt};
|
||||
|
||||
let mut opts = cap_std::fs::OpenOptions::new();
|
||||
|
||||
if oflags.contains(OFlags::CREATE | OFlags::EXCLUSIVE) {
|
||||
opts.create_new(true);
|
||||
opts.write(true);
|
||||
} else if oflags.contains(OFlags::CREATE) {
|
||||
opts.create(true);
|
||||
opts.write(true);
|
||||
}
|
||||
if oflags.contains(OFlags::TRUNCATE) {
|
||||
opts.truncate(true);
|
||||
}
|
||||
if caps.contains(FileCaps::WRITE)
|
||||
|| caps.contains(FileCaps::DATASYNC)
|
||||
|| caps.contains(FileCaps::ALLOCATE)
|
||||
|| caps.contains(FileCaps::FILESTAT_SET_SIZE)
|
||||
{
|
||||
opts.write(true);
|
||||
} else {
|
||||
// If not opened write, open read. This way the OS lets us open the file.
|
||||
// If FileCaps::READ is not set, read calls will be rejected at the
|
||||
// get_cap check.
|
||||
opts.read(true);
|
||||
}
|
||||
if caps.contains(FileCaps::READ) {
|
||||
opts.read(true);
|
||||
}
|
||||
if fdflags.contains(FdFlags::APPEND) {
|
||||
opts.append(true);
|
||||
}
|
||||
// XXX what about rest of fdflags - dsync, sync become oflags.
|
||||
// what do we do with nonblock?
|
||||
// what do we do with rsync?
|
||||
|
||||
if symlink_follow {
|
||||
opts.follow(FollowSymlinks::Yes);
|
||||
} else {
|
||||
opts.follow(FollowSymlinks::No);
|
||||
}
|
||||
|
||||
let f = self.open_with(Path::new(path), &opts)?;
|
||||
Ok(Box::new(f))
|
||||
}
|
||||
|
||||
fn open_dir(&self, symlink_follow: bool, path: &str) -> Result<Box<dyn WasiDir>, Error> {
|
||||
let d = if symlink_follow {
|
||||
self.open_dir(Path::new(path))?
|
||||
} else {
|
||||
use cap_fs_ext::DirExt;
|
||||
self.open_dir_nofollow(Path::new(path))?
|
||||
};
|
||||
Ok(Box::new(d))
|
||||
}
|
||||
|
||||
fn create_dir(&self, path: &str) -> Result<(), Error> {
|
||||
self.create_dir(Path::new(path))?;
|
||||
Ok(())
|
||||
}
|
||||
fn readdir(
|
||||
&self,
|
||||
cursor: ReaddirCursor,
|
||||
) -> Result<Box<dyn Iterator<Item = Result<(ReaddirEntity, String), Error>>>, Error> {
|
||||
use cap_fs_ext::MetadataExt;
|
||||
|
||||
// cap_std's read_dir does not include . and .., we should prepend these.
|
||||
// Why does the Ok contain a tuple? We can't construct a cap_std::fs::DirEntry, and we don't
|
||||
// have enough info to make a ReaddirEntity yet.
|
||||
let dir_meta = self.dir_metadata()?;
|
||||
let rd = vec![
|
||||
{
|
||||
let name = ".".to_owned();
|
||||
let namelen = name.as_bytes().len().try_into().expect("1 wont overflow");
|
||||
Ok((FileType::Directory, dir_meta.ino(), namelen, name))
|
||||
},
|
||||
{
|
||||
// XXX if parent dir is mounted it *might* be possible to give its inode, but we
|
||||
// don't know that in this context.
|
||||
let name = "..".to_owned();
|
||||
let namelen = name.as_bytes().len().try_into().expect("2 wont overflow");
|
||||
Ok((FileType::Directory, dir_meta.ino(), namelen, name))
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.chain(
|
||||
// Now process the `DirEntry`s:
|
||||
self.entries()?.map(|entry| {
|
||||
let entry = entry?;
|
||||
let meta = entry.metadata()?;
|
||||
let inode = meta.ino();
|
||||
let filetype = FileType::from(&meta.file_type());
|
||||
let name = entry.file_name().into_string().map_err(|_| Error::Ilseq)?;
|
||||
let namelen = name.as_bytes().len().try_into()?;
|
||||
Ok((filetype, inode, namelen, name))
|
||||
}),
|
||||
)
|
||||
// Enumeration of the iterator makes it possible to define the ReaddirCursor
|
||||
.enumerate()
|
||||
.map(|(ix, r)| match r {
|
||||
Ok((filetype, inode, namelen, name)) => Ok((
|
||||
ReaddirEntity {
|
||||
next: ReaddirCursor::from(ix as u64 + 1),
|
||||
filetype,
|
||||
inode,
|
||||
namelen,
|
||||
},
|
||||
name,
|
||||
)),
|
||||
Err(e) => Err(e),
|
||||
})
|
||||
.skip(u64::from(cursor) as usize);
|
||||
|
||||
Ok(Box::new(rd))
|
||||
}
|
||||
|
||||
fn symlink(&self, src_path: &str, dest_path: &str) -> Result<(), Error> {
|
||||
self.symlink(Path::new(src_path), Path::new(dest_path))?;
|
||||
Ok(())
|
||||
}
|
||||
fn remove_dir(&self, path: &str) -> Result<(), Error> {
|
||||
self.remove_dir(Path::new(path))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unlink_file(&self, path: &str) -> Result<(), Error> {
|
||||
self.remove_file(Path::new(path))?;
|
||||
Ok(())
|
||||
}
|
||||
fn read_link(&self, path: &str) -> Result<PathBuf, Error> {
|
||||
let link = self.read_link(Path::new(path))?;
|
||||
Ok(link)
|
||||
}
|
||||
fn get_filestat(&self) -> Result<Filestat, Error> {
|
||||
let meta = self.dir_metadata()?;
|
||||
use cap_fs_ext::MetadataExt;
|
||||
Ok(Filestat {
|
||||
device_id: meta.dev(),
|
||||
inode: meta.ino(),
|
||||
filetype: FileType::from(&meta.file_type()),
|
||||
nlink: meta.nlink(),
|
||||
size: meta.len(),
|
||||
atim: meta.accessed().map(|t| Some(t.into_std())).unwrap_or(None),
|
||||
mtim: meta.modified().map(|t| Some(t.into_std())).unwrap_or(None),
|
||||
ctim: meta.created().map(|t| Some(t.into_std())).unwrap_or(None),
|
||||
})
|
||||
}
|
||||
fn get_path_filestat(&self, path: &str) -> Result<Filestat, Error> {
|
||||
let meta = self.metadata(Path::new(path))?;
|
||||
use cap_fs_ext::MetadataExt;
|
||||
Ok(Filestat {
|
||||
device_id: meta.dev(),
|
||||
inode: meta.ino(),
|
||||
filetype: FileType::from(&meta.file_type()),
|
||||
nlink: meta.nlink(),
|
||||
size: meta.len(),
|
||||
atim: meta.accessed().map(|t| Some(t.into_std())).unwrap_or(None),
|
||||
mtim: meta.modified().map(|t| Some(t.into_std())).unwrap_or(None),
|
||||
ctim: meta.created().map(|t| Some(t.into_std())).unwrap_or(None),
|
||||
})
|
||||
}
|
||||
fn rename(&self, src_path: &str, dest_dir: &dyn WasiDir, dest_path: &str) -> Result<(), Error> {
|
||||
let dest_dir = dest_dir
|
||||
.as_any()
|
||||
.downcast_ref::<Self>()
|
||||
.ok_or(Error::NotCapable)?;
|
||||
self.rename(Path::new(src_path), dest_dir, Path::new(dest_path))?;
|
||||
Ok(())
|
||||
}
|
||||
fn hard_link(
|
||||
&self,
|
||||
src_path: &str,
|
||||
symlink_follow: bool,
|
||||
target_dir: &dyn WasiDir,
|
||||
target_path: &str,
|
||||
) -> Result<(), Error> {
|
||||
let target_dir = target_dir
|
||||
.as_any()
|
||||
.downcast_ref::<Self>()
|
||||
.ok_or(Error::NotCapable)?;
|
||||
let src_path = Path::new(src_path);
|
||||
let target_path = Path::new(target_path);
|
||||
self.hard_link(src_path, target_dir, target_path)?;
|
||||
Ok(())
|
||||
}
|
||||
fn set_times(
|
||||
&self,
|
||||
path: &str,
|
||||
atime: Option<SystemTimeSpec>,
|
||||
mtime: Option<SystemTimeSpec>,
|
||||
) -> Result<(), Error> {
|
||||
cap_fs_ext::DirExt::set_times(self, Path::new(path), atime, mtime)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,46 +166,3 @@ pub struct FdStat {
|
||||
pub caps: FileCaps,
|
||||
pub flags: FdFlags,
|
||||
}
|
||||
|
||||
impl WasiFile for cap_std::fs::File {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn datasync(&self) -> Result<(), Error> {
|
||||
self.sync_data()?;
|
||||
Ok(())
|
||||
}
|
||||
fn sync(&self) -> Result<(), Error> {
|
||||
self.sync_all()?;
|
||||
Ok(())
|
||||
}
|
||||
fn get_filetype(&self) -> Result<FileType, Error> {
|
||||
let meta = self.metadata()?;
|
||||
Ok(FileType::from(&meta.file_type()))
|
||||
}
|
||||
fn get_fdflags(&self) -> Result<FdFlags, Error> {
|
||||
// XXX get_fdflags is not implemented but lets lie rather than panic:
|
||||
Ok(FdFlags::empty())
|
||||
}
|
||||
fn set_fdflags(&self, _fdflags: FdFlags) -> Result<(), Error> {
|
||||
todo!("set_fdflags is not implemented")
|
||||
}
|
||||
fn get_filestat(&self) -> Result<Filestat, Error> {
|
||||
let meta = self.metadata()?;
|
||||
use cap_fs_ext::MetadataExt;
|
||||
Ok(Filestat {
|
||||
device_id: meta.dev(),
|
||||
inode: meta.ino(),
|
||||
filetype: FileType::from(&meta.file_type()),
|
||||
nlink: meta.nlink(),
|
||||
size: meta.len(),
|
||||
atim: meta.accessed().map(|t| Some(t.into_std())).unwrap_or(None),
|
||||
mtim: meta.modified().map(|t| Some(t.into_std())).unwrap_or(None),
|
||||
ctim: meta.created().map(|t| Some(t.into_std())).unwrap_or(None),
|
||||
})
|
||||
}
|
||||
fn set_filestat_size(&self, size: u64) -> Result<(), Error> {
|
||||
self.set_len(size)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,16 +2,15 @@
|
||||
|
||||
pub mod clocks;
|
||||
mod ctx;
|
||||
mod dir;
|
||||
pub mod dir;
|
||||
mod error;
|
||||
mod file;
|
||||
pub mod file;
|
||||
pub mod pipe;
|
||||
pub mod random;
|
||||
pub mod sched;
|
||||
pub mod snapshots;
|
||||
pub mod stdio;
|
||||
mod string_array;
|
||||
pub mod table;
|
||||
pub mod virt;
|
||||
|
||||
pub use cap_fs_ext::SystemTimeSpec;
|
||||
pub use ctx::{WasiCtx, WasiCtxBuilder};
|
||||
|
||||
@@ -5,9 +5,6 @@ use cap_std::time::{Duration, Instant};
|
||||
use std::cell::Ref;
|
||||
pub mod subscription;
|
||||
|
||||
mod sync;
|
||||
pub use sync::SyncSched;
|
||||
|
||||
use subscription::{MonotonicClockSubscription, RwSubscription, Subscription, SubscriptionResult};
|
||||
|
||||
pub trait WasiSched {
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
#[cfg(unix)]
|
||||
pub use unix::*;
|
||||
|
||||
#[cfg(unix)]
|
||||
mod unix {
|
||||
use crate::file::WasiFile;
|
||||
use crate::sched::subscription::{RwEventFlags, Subscription};
|
||||
use crate::sched::{Poll, WasiSched};
|
||||
use crate::Error;
|
||||
use cap_std::time::Duration;
|
||||
use std::convert::TryInto;
|
||||
use std::ops::Deref;
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use yanix::poll::{PollFd, PollFlags};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct SyncSched {}
|
||||
|
||||
impl WasiSched for SyncSched {
|
||||
fn poll_oneoff<'a>(&self, poll: &'a Poll<'a>) -> Result<(), Error> {
|
||||
if poll.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
let mut pollfds = Vec::new();
|
||||
let timeout = poll.earliest_clock_deadline();
|
||||
for s in poll.rw_subscriptions() {
|
||||
match s {
|
||||
Subscription::Read(f) => {
|
||||
let raw_fd = wasi_file_raw_fd(f.file.deref()).ok_or(Error::Inval)?;
|
||||
pollfds.push(unsafe { PollFd::new(raw_fd, PollFlags::POLLIN) });
|
||||
}
|
||||
|
||||
Subscription::Write(f) => {
|
||||
let raw_fd = wasi_file_raw_fd(f.file.deref()).ok_or(Error::Inval)?;
|
||||
pollfds.push(unsafe { PollFd::new(raw_fd, PollFlags::POLLOUT) });
|
||||
}
|
||||
Subscription::MonotonicClock { .. } => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
let ready = loop {
|
||||
let poll_timeout = if let Some(t) = timeout {
|
||||
let duration = t
|
||||
.deadline
|
||||
.checked_duration_since(t.clock.now(t.precision))
|
||||
.unwrap_or(Duration::from_secs(0));
|
||||
(duration.as_millis() + 1) // XXX try always rounding up?
|
||||
.try_into()
|
||||
.map_err(|_| Error::Overflow)?
|
||||
} else {
|
||||
libc::c_int::max_value()
|
||||
};
|
||||
tracing::debug!(
|
||||
poll_timeout = tracing::field::debug(poll_timeout),
|
||||
poll_fds = tracing::field::debug(&pollfds),
|
||||
"poll"
|
||||
);
|
||||
match yanix::poll::poll(&mut pollfds, poll_timeout) {
|
||||
Ok(ready) => break ready,
|
||||
Err(_) => {
|
||||
let last_err = std::io::Error::last_os_error();
|
||||
if last_err.raw_os_error().unwrap() == libc::EINTR {
|
||||
continue;
|
||||
} else {
|
||||
return Err(last_err.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
if ready > 0 {
|
||||
for (rwsub, pollfd) in poll.rw_subscriptions().zip(pollfds.into_iter()) {
|
||||
if let Some(revents) = pollfd.revents() {
|
||||
let (nbytes, rwsub) = match rwsub {
|
||||
Subscription::Read(sub) => {
|
||||
let ready = sub.file.num_ready_bytes()?;
|
||||
(std::cmp::max(ready, 1), sub)
|
||||
}
|
||||
Subscription::Write(sub) => (0, sub),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if revents.contains(PollFlags::POLLNVAL) {
|
||||
rwsub.error(Error::Badf);
|
||||
} else if revents.contains(PollFlags::POLLERR) {
|
||||
rwsub.error(Error::Io);
|
||||
} else if revents.contains(PollFlags::POLLHUP) {
|
||||
rwsub.complete(nbytes, RwEventFlags::HANGUP);
|
||||
} else {
|
||||
rwsub.complete(nbytes, RwEventFlags::empty());
|
||||
};
|
||||
}
|
||||
}
|
||||
} else {
|
||||
timeout
|
||||
.expect("timed out")
|
||||
.result()
|
||||
.expect("timer deadline is past")
|
||||
.unwrap()
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn sched_yield(&self) -> Result<(), Error> {
|
||||
std::thread::yield_now();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn wasi_file_raw_fd(f: &dyn WasiFile) -> Option<RawFd> {
|
||||
let a = f.as_any();
|
||||
if a.is::<cap_std::fs::File>() {
|
||||
Some(a.downcast_ref::<cap_std::fs::File>().unwrap().as_raw_fd())
|
||||
} else if a.is::<crate::stdio::Stdin>() {
|
||||
Some(a.downcast_ref::<crate::stdio::Stdin>().unwrap().as_raw_fd())
|
||||
} else if a.is::<crate::stdio::Stdout>() {
|
||||
Some(
|
||||
a.downcast_ref::<crate::stdio::Stdout>()
|
||||
.unwrap()
|
||||
.as_raw_fd(),
|
||||
)
|
||||
} else if a.is::<crate::stdio::Stderr>() {
|
||||
Some(
|
||||
a.downcast_ref::<crate::stdio::Stderr>()
|
||||
.unwrap()
|
||||
.as_raw_fd(),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
use crate::file::{FdFlags, FileType, Filestat, WasiFile};
|
||||
use crate::Error;
|
||||
use std::any::Any;
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::io::{AsRawFd, RawFd};
|
||||
use system_interface::io::ReadReady;
|
||||
|
||||
pub struct Stdin(std::io::Stdin);
|
||||
|
||||
pub fn stdin() -> Stdin {
|
||||
Stdin(std::io::stdin())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl AsRawFd for Stdin {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl ReadReady for Stdin {
|
||||
fn num_ready_bytes(&self) -> Result<u64, std::io::Error> {
|
||||
self.0.num_ready_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl WasiFile for Stdin {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn datasync(&self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn sync(&self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn get_filetype(&self) -> Result<FileType, Error> {
|
||||
Ok(FileType::CharacterDevice)
|
||||
}
|
||||
fn get_fdflags(&self) -> Result<FdFlags, Error> {
|
||||
todo!()
|
||||
}
|
||||
fn set_fdflags(&self, _fdflags: FdFlags) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
fn get_filestat(&self) -> Result<Filestat, Error> {
|
||||
todo!()
|
||||
}
|
||||
fn set_filestat_size(&self, _size: u64) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Stdout(std::io::Stdout);
|
||||
|
||||
pub fn stdout() -> Stdout {
|
||||
Stdout(std::io::stdout())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl AsRawFd for Stdout {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl ReadReady for Stdout {
|
||||
fn num_ready_bytes(&self) -> Result<u64, std::io::Error> {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl WasiFile for Stdout {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn datasync(&self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn sync(&self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn get_filetype(&self) -> Result<FileType, Error> {
|
||||
Ok(FileType::CharacterDevice)
|
||||
}
|
||||
fn get_fdflags(&self) -> Result<FdFlags, Error> {
|
||||
todo!()
|
||||
}
|
||||
fn set_fdflags(&self, _fdflags: FdFlags) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
fn get_filestat(&self) -> Result<Filestat, Error> {
|
||||
todo!()
|
||||
}
|
||||
fn set_filestat_size(&self, _size: u64) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Stderr(std::io::Stderr);
|
||||
|
||||
pub fn stderr() -> Stderr {
|
||||
Stderr(std::io::stderr())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl AsRawFd for Stderr {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.0.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl ReadReady for Stderr {
|
||||
fn num_ready_bytes(&self) -> Result<u64, std::io::Error> {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
|
||||
impl WasiFile for Stderr {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
fn datasync(&self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn sync(&self) -> Result<(), Error> {
|
||||
Ok(())
|
||||
}
|
||||
fn get_filetype(&self) -> Result<FileType, Error> {
|
||||
Ok(FileType::CharacterDevice)
|
||||
}
|
||||
fn get_fdflags(&self) -> Result<FdFlags, Error> {
|
||||
todo!()
|
||||
}
|
||||
fn set_fdflags(&self, _fdflags: FdFlags) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
fn get_filestat(&self) -> Result<Filestat, Error> {
|
||||
todo!()
|
||||
}
|
||||
fn set_filestat_size(&self, _size: u64) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
pub mod pipe;
|
||||
Reference in New Issue
Block a user