wasi-common: don't rely on platform dependent "NUL" device
If stdio is not inherited nor associated with a file, WasiCtxBuilder
tries to open "/dev/null" ("NUL" on Windows) and attach stdio to it.
While most platforms today support those device files, it would be
good to avoid unnecessary access to the host device if possible. This
patch instead uses a virtual Handle that emulates the "NUL" device.
This commit is contained in:
@@ -2,7 +2,7 @@ use crate::entry::{Entry, EntryHandle};
|
|||||||
use crate::fdpool::FdPool;
|
use crate::fdpool::FdPool;
|
||||||
use crate::handle::Handle;
|
use crate::handle::Handle;
|
||||||
use crate::sys::osdir::OsDir;
|
use crate::sys::osdir::OsDir;
|
||||||
use crate::sys::osother::{OsOther, OsOtherExt};
|
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;
|
||||||
@@ -136,9 +136,9 @@ pub struct WasiCtxBuilder {
|
|||||||
impl WasiCtxBuilder {
|
impl WasiCtxBuilder {
|
||||||
/// Builder for a new `WasiCtx`.
|
/// Builder for a new `WasiCtx`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let stdin = Some(PendingEntry::Thunk(OsOther::from_null));
|
let stdin = Some(PendingEntry::Handle(Box::new(NullDevice::new())));
|
||||||
let stdout = Some(PendingEntry::Thunk(OsOther::from_null));
|
let stdout = Some(PendingEntry::Handle(Box::new(NullDevice::new())));
|
||||||
let stderr = Some(PendingEntry::Thunk(OsOther::from_null));
|
let stderr = Some(PendingEntry::Handle(Box::new(NullDevice::new())));
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
stdin,
|
stdin,
|
||||||
|
|||||||
@@ -39,6 +39,6 @@ pub use ctx::{WasiCtx, WasiCtxBuilder, WasiCtxBuilderError};
|
|||||||
pub use handle::{Handle, HandleRights};
|
pub use handle::{Handle, HandleRights};
|
||||||
pub use sys::osdir::OsDir;
|
pub use sys::osdir::OsDir;
|
||||||
pub use sys::osfile::OsFile;
|
pub use sys::osfile::OsFile;
|
||||||
pub use sys::osother::{OsOther, OsOtherExt};
|
pub use sys::osother::OsOther;
|
||||||
pub use sys::preopen_dir;
|
pub use sys::preopen_dir;
|
||||||
pub use virtfs::{FileContents, VirtualDirEntry};
|
pub use virtfs::{FileContents, VirtualDirEntry};
|
||||||
|
|||||||
@@ -10,13 +10,6 @@ use std::fs::File;
|
|||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
/// Extra methods for `OsOther` that are only available when configured for
|
|
||||||
/// some operating systems.
|
|
||||||
pub trait OsOtherExt {
|
|
||||||
/// Create `OsOther` as `dyn Handle` from null device.
|
|
||||||
fn from_null() -> io::Result<Box<dyn Handle>>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `OsOther` is something of a catch-all for everything not covered with the specific handle
|
/// `OsOther` is something of a catch-all for everything not covered with the specific handle
|
||||||
/// types (`OsFile`, `OsDir`, `Stdio`). It currently encapsulates handles such as OS pipes,
|
/// types (`OsFile`, `OsDir`, `Stdio`). It currently encapsulates handles such as OS pipes,
|
||||||
/// sockets, streams, etc. As such, when redirecting stdio within `WasiCtxBuilder`, the redirected
|
/// sockets, streams, etc. As such, when redirecting stdio within `WasiCtxBuilder`, the redirected
|
||||||
|
|||||||
@@ -20,9 +20,10 @@ use super::{fd, AsFile};
|
|||||||
use crate::handle::{Handle, HandleRights};
|
use crate::handle::{Handle, HandleRights};
|
||||||
use crate::sandboxed_tty_writer::SandboxedTTYWriter;
|
use crate::sandboxed_tty_writer::SandboxedTTYWriter;
|
||||||
use crate::wasi::types::{self, Filetype};
|
use crate::wasi::types::{self, Filetype};
|
||||||
use crate::wasi::Result;
|
use crate::wasi::{Errno, Result, RightsExt};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
|
use std::convert::TryInto;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
|
|
||||||
pub(crate) trait StdinExt: Sized {
|
pub(crate) trait StdinExt: Sized {
|
||||||
@@ -174,3 +175,59 @@ impl Handle for Stderr {
|
|||||||
Ok(nwritten)
|
Ok(nwritten)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub(crate) struct NullDevice {
|
||||||
|
pub(crate) rights: Cell<HandleRights>,
|
||||||
|
pub(crate) fd_flags: Cell<types::Fdflags>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NullDevice {
|
||||||
|
pub(crate) fn new() -> Self {
|
||||||
|
let rights = HandleRights::new(
|
||||||
|
types::Rights::character_device_base(),
|
||||||
|
types::Rights::character_device_inheriting(),
|
||||||
|
);
|
||||||
|
let rights = Cell::new(rights);
|
||||||
|
let fd_flags = types::Fdflags::empty();
|
||||||
|
let fd_flags = Cell::new(fd_flags);
|
||||||
|
Self { rights, fd_flags }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Handle for NullDevice {
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
fn try_clone(&self) -> io::Result<Box<dyn Handle>> {
|
||||||
|
Ok(Box::new(self.clone()))
|
||||||
|
}
|
||||||
|
fn get_file_type(&self) -> types::Filetype {
|
||||||
|
types::Filetype::CharacterDevice
|
||||||
|
}
|
||||||
|
fn get_rights(&self) -> HandleRights {
|
||||||
|
self.rights.get()
|
||||||
|
}
|
||||||
|
fn set_rights(&self, rights: HandleRights) {
|
||||||
|
self.rights.set(rights)
|
||||||
|
}
|
||||||
|
// FdOps
|
||||||
|
fn fdstat_get(&self) -> Result<types::Fdflags> {
|
||||||
|
Ok(self.fd_flags.get())
|
||||||
|
}
|
||||||
|
fn fdstat_set_flags(&self, fdflags: types::Fdflags) -> Result<()> {
|
||||||
|
self.fd_flags.set(fdflags);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn read_vectored(&self, _iovs: &mut [io::IoSliceMut]) -> Result<usize> {
|
||||||
|
Ok(0)
|
||||||
|
}
|
||||||
|
fn write_vectored(&self, iovs: &[io::IoSlice]) -> Result<usize> {
|
||||||
|
let mut total_len = 0u32;
|
||||||
|
for iov in iovs {
|
||||||
|
let len: types::Size = iov.len().try_into()?;
|
||||||
|
total_len = total_len.checked_add(len).ok_or(Errno::Overflow)?;
|
||||||
|
}
|
||||||
|
Ok(total_len as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
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::Handle;
|
use crate::sys::osother::OsOther;
|
||||||
use crate::sys::osother::{OsOther, OsOtherExt};
|
|
||||||
use crate::wasi::types;
|
use crate::wasi::types;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::os::unix::prelude::{FromRawFd, IntoRawFd};
|
use std::os::unix::prelude::{FromRawFd, IntoRawFd};
|
||||||
|
|
||||||
@@ -21,14 +20,3 @@ impl TryFrom<File> for OsOther {
|
|||||||
Ok(Self::new(file_type, rights, handle))
|
Ok(Self::new(file_type, rights, handle))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OsOtherExt for OsOther {
|
|
||||||
fn from_null() -> io::Result<Box<dyn Handle>> {
|
|
||||||
let file = OpenOptions::new()
|
|
||||||
.read(true)
|
|
||||||
.write(true)
|
|
||||||
.open("/dev/null")?;
|
|
||||||
let file = Self::try_from(file)?;
|
|
||||||
Ok(Box::new(file))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
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::Handle;
|
use crate::sys::osother::OsOther;
|
||||||
use crate::sys::osother::{OsOther, OsOtherExt};
|
|
||||||
use crate::wasi::types;
|
use crate::wasi::types;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fs::{File, OpenOptions};
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::os::windows::prelude::{FromRawHandle, IntoRawHandle};
|
use std::os::windows::prelude::{FromRawHandle, IntoRawHandle};
|
||||||
|
|
||||||
@@ -21,11 +20,3 @@ impl TryFrom<File> for OsOther {
|
|||||||
Ok(Self::new(file_type, rights, handle))
|
Ok(Self::new(file_type, rights, handle))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OsOtherExt for OsOther {
|
|
||||||
fn from_null() -> io::Result<Box<dyn Handle>> {
|
|
||||||
let file = OpenOptions::new().read(true).write(true).open("NUL")?;
|
|
||||||
let file = Self::try_from(file)?;
|
|
||||||
Ok(Box::new(file))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user