Skip to content

Commit

Permalink
Allow for stdio to be non-character-device (e.g., piped)
Browse files Browse the repository at this point in the history
  • Loading branch information
kubkon committed May 6, 2020
1 parent 40a9e08 commit 991ce43
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 111 deletions.
15 changes: 11 additions & 4 deletions crates/wasi-common/src/sys/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub(crate) trait StdinExt: Sized {

#[derive(Debug, Clone)]
pub(crate) struct Stdin {
pub(crate) file_type: Filetype,
pub(crate) rights: Cell<HandleRights>,
}

Expand All @@ -43,7 +44,7 @@ impl Handle for Stdin {
Ok(Box::new(self.clone()))
}
fn get_file_type(&self) -> Filetype {
Filetype::CharacterDevice
self.file_type
}
fn get_rights(&self) -> HandleRights {
self.rights.get()
Expand Down Expand Up @@ -77,6 +78,7 @@ pub(crate) trait StdoutExt: Sized {

#[derive(Debug, Clone)]
pub(crate) struct Stdout {
pub(crate) file_type: Filetype,
pub(crate) rights: Cell<HandleRights>,
}

Expand All @@ -88,7 +90,7 @@ impl Handle for Stdout {
Ok(Box::new(self.clone()))
}
fn get_file_type(&self) -> Filetype {
Filetype::CharacterDevice
self.file_type
}
fn get_rights(&self) -> HandleRights {
self.rights.get()
Expand All @@ -113,7 +115,11 @@ impl Handle for Stdout {
// lock for the duration of the scope
let stdout = io::stdout();
let mut stdout = stdout.lock();
let nwritten = SandboxedTTYWriter::new(&mut stdout).write_vectored(&iovs)?;
let nwritten = if self.is_tty() {
SandboxedTTYWriter::new(&mut stdout).write_vectored(&iovs)?
} else {
stdout.write_vectored(iovs)?
};
stdout.flush()?;
Ok(nwritten)
}
Expand All @@ -126,6 +132,7 @@ pub(crate) trait StderrExt: Sized {

#[derive(Debug, Clone)]
pub(crate) struct Stderr {
pub(crate) file_type: Filetype,
pub(crate) rights: Cell<HandleRights>,
}

Expand All @@ -137,7 +144,7 @@ impl Handle for Stderr {
Ok(Box::new(self.clone()))
}
fn get_file_type(&self) -> Filetype {
Filetype::CharacterDevice
self.file_type
}
fn get_rights(&self) -> HandleRights {
self.rights.get()
Expand Down
49 changes: 48 additions & 1 deletion crates/wasi-common/src/sys/unix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ cfg_if::cfg_if! {
}
}

use crate::handle::HandleRights;
use crate::sys::AsFile;
use crate::wasi::{types, Errno, Result};
use crate::wasi::{types, Errno, Result, RightsExt};
use std::convert::{TryFrom, TryInto};
use std::fs::File;
use std::io;
Expand Down Expand Up @@ -78,6 +79,52 @@ pub(super) fn get_file_type(file: &File) -> io::Result<types::Filetype> {
Ok(file_type)
}

pub(super) fn get_rights(file: &File, file_type: &types::Filetype) -> io::Result<HandleRights> {
use yanix::{fcntl, file::OFlag};
let (base, inheriting) = match file_type {
types::Filetype::BlockDevice => (
types::Rights::block_device_base(),
types::Rights::block_device_inheriting(),
),
types::Filetype::CharacterDevice => {
use yanix::file::isatty;
if unsafe { isatty(file.as_raw_fd())? } {
(types::Rights::tty_base(), types::Rights::tty_base())
} else {
(
types::Rights::character_device_base(),
types::Rights::character_device_inheriting(),
)
}
}
types::Filetype::SocketDgram | types::Filetype::SocketStream => (
types::Rights::socket_base(),
types::Rights::socket_inheriting(),
),
types::Filetype::SymbolicLink | types::Filetype::Unknown => (
types::Rights::regular_file_base(),
types::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 flags = unsafe { fcntl::get_status_flags(file.as_raw_fd())? };
let accmode = flags & OFlag::ACCMODE;
if accmode == OFlag::RDONLY {
rights.base &= !types::Rights::FD_WRITE;
} else if accmode == OFlag::WRONLY {
rights.base &= !types::Rights::FD_READ;
}
Ok(rights)
}

pub fn preopen_dir<P: AsRef<Path>>(path: P) -> io::Result<File> {
File::open(path)
}
Expand Down
47 changes: 4 additions & 43 deletions crates/wasi-common/src/sys/unix/osother.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use super::get_file_type;
use super::oshandle::RawOsHandle;
use crate::handle::{Handle, HandleRights};
use super::{get_file_type, get_rights};
use crate::handle::Handle;
use crate::sys::osother::{OsOther, OsOtherExt};
use crate::wasi::{types, RightsExt};
use crate::wasi::types;
use std::convert::TryFrom;
use std::fs::{File, OpenOptions};
use std::io;
use std::os::unix::prelude::{AsRawFd, FromRawFd, IntoRawFd};
use std::os::unix::prelude::{FromRawFd, IntoRawFd};

impl TryFrom<File> for OsOther {
type Error = io::Error;
Expand All @@ -22,45 +22,6 @@ impl TryFrom<File> for OsOther {
}
}

fn get_rights(file: &File, file_type: &types::Filetype) -> io::Result<HandleRights> {
use yanix::{fcntl, file::OFlag};
let (base, inheriting) = match file_type {
types::Filetype::BlockDevice => (
types::Rights::block_device_base(),
types::Rights::block_device_inheriting(),
),
types::Filetype::CharacterDevice => {
use yanix::file::isatty;
if unsafe { isatty(file.as_raw_fd())? } {
(types::Rights::tty_base(), types::Rights::tty_base())
} else {
(
types::Rights::character_device_base(),
types::Rights::character_device_inheriting(),
)
}
}
types::Filetype::SocketDgram | types::Filetype::SocketStream => (
types::Rights::socket_base(),
types::Rights::socket_inheriting(),
),
types::Filetype::SymbolicLink | types::Filetype::Unknown => (
types::Rights::regular_file_base(),
types::Rights::regular_file_inheriting(),
),
_ => unreachable!("these should have been handled already!"),
};
let mut rights = HandleRights::new(base, inheriting);
let flags = unsafe { fcntl::get_status_flags(file.as_raw_fd())? };
let accmode = flags & OFlag::ACCMODE;
if accmode == OFlag::RDONLY {
rights.base &= !types::Rights::FD_WRITE;
} else if accmode == OFlag::WRONLY {
rights.base &= !types::Rights::FD_READ;
}
Ok(rights)
}

impl OsOtherExt for OsOther {
fn from_null() -> io::Result<Box<dyn Handle>> {
let file = OpenOptions::new()
Expand Down
34 changes: 11 additions & 23 deletions crates/wasi-common/src/sys/unix/stdio.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::handle::{Handle, HandleRights};
use super::{get_file_type, get_rights};
use crate::handle::Handle;
use crate::sys::stdio::{Stderr, StderrExt, Stdin, StdinExt, Stdout, StdoutExt};
use crate::wasi::{types, RightsExt};
use std::cell::Cell;
use std::fs::File;
use std::io;
Expand Down Expand Up @@ -29,43 +29,31 @@ impl StdinExt for Stdin {
fn stdin() -> io::Result<Box<dyn Handle>> {
let file = unsafe { File::from_raw_fd(io::stdin().as_raw_fd()) };
let file = ManuallyDrop::new(file);
let rights = get_rights(&file)?;
let file_type = get_file_type(&file)?;
let rights = get_rights(&file, &file_type)?;
let rights = Cell::new(rights);
Ok(Box::new(Self { rights }))
Ok(Box::new(Self { file_type, rights }))
}
}

impl StdoutExt for Stdout {
fn stdout() -> io::Result<Box<dyn Handle>> {
let file = unsafe { File::from_raw_fd(io::stdout().as_raw_fd()) };
let file = ManuallyDrop::new(file);
let rights = get_rights(&file)?;
let file_type = get_file_type(&file)?;
let rights = get_rights(&file, &file_type)?;
let rights = Cell::new(rights);
Ok(Box::new(Self { rights }))
Ok(Box::new(Self { file_type, rights }))
}
}

impl StderrExt for Stderr {
fn stderr() -> io::Result<Box<dyn Handle>> {
let file = unsafe { File::from_raw_fd(io::stderr().as_raw_fd()) };
let file = ManuallyDrop::new(file);
let rights = get_rights(&file)?;
let file_type = get_file_type(&file)?;
let rights = get_rights(&file, &file_type)?;
let rights = Cell::new(rights);
Ok(Box::new(Self { rights }))
Ok(Box::new(Self { file_type, rights }))
}
}

fn get_rights(file: &File) -> io::Result<HandleRights> {
use yanix::file::isatty;
let (base, inheriting) = {
if unsafe { isatty(file.as_raw_fd())? } {
(types::Rights::tty_base(), types::Rights::tty_base())
} else {
(
types::Rights::character_device_base(),
types::Rights::character_device_inheriting(),
)
}
};
Ok(HandleRights::new(base, inheriting))
}
33 changes: 31 additions & 2 deletions crates/wasi-common/src/sys/windows/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ pub(crate) mod path;
pub(crate) mod poll;
pub(crate) mod stdio;

use crate::handle::HandleRights;
use crate::sys::AsFile;
use crate::wasi::{types, Errno, Result};
use crate::wasi::{types, Errno, Result, RightsExt};
use std::convert::{TryFrom, TryInto};
use std::fs::File;
use std::mem::ManuallyDrop;
Expand All @@ -27,7 +28,7 @@ impl<T: AsRawHandle> AsFile for T {
}
}

pub(crate) fn get_file_type(file: &File) -> io::Result<types::Filetype> {
pub(super) fn get_file_type(file: &File) -> io::Result<types::Filetype> {
let file_type = unsafe { winx::file::get_file_type(file.as_raw_handle())? };
let file_type = if file_type.is_char() {
// character file: LPT device or console
Expand All @@ -53,6 +54,34 @@ pub(crate) fn get_file_type(file: &File) -> io::Result<types::Filetype> {
Ok(file_type)
}

pub(super) fn get_rights(file_type: &types::Filetype) -> io::Result<HandleRights> {
let (base, inheriting) = match file_type {
types::Filetype::BlockDevice => (
types::Rights::block_device_base(),
types::Rights::block_device_inheriting(),
),
types::Filetype::CharacterDevice => (types::Rights::tty_base(), types::Rights::tty_base()),
types::Filetype::SocketDgram | types::Filetype::SocketStream => (
types::Rights::socket_base(),
types::Rights::socket_inheriting(),
),
types::Filetype::SymbolicLink | types::Filetype::Unknown => (
types::Rights::regular_file_base(),
types::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);
Ok(rights)
}

pub fn preopen_dir<P: AsRef<Path>>(path: P) -> io::Result<File> {
use std::fs::OpenOptions;
use std::os::windows::fs::OpenOptionsExt;
Expand Down
27 changes: 3 additions & 24 deletions crates/wasi-common/src/sys/windows/osother.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use super::get_file_type;
use super::oshandle::RawOsHandle;
use crate::handle::{Handle, HandleRights};
use super::{get_file_type, get_rights};
use crate::handle::Handle;
use crate::sys::osother::{OsOther, OsOtherExt};
use crate::wasi::{types, RightsExt};
use crate::wasi::types;
use std::convert::TryFrom;
use std::fs::{File, OpenOptions};
use std::io;
Expand All @@ -22,27 +22,6 @@ impl TryFrom<File> for OsOther {
}
}

fn get_rights(file_type: &types::Filetype) -> io::Result<HandleRights> {
let (base, inheriting) = match file_type {
types::Filetype::BlockDevice => (
types::Rights::block_device_base(),
types::Rights::block_device_inheriting(),
),
types::Filetype::CharacterDevice => (types::Rights::tty_base(), types::Rights::tty_base()),
types::Filetype::SocketDgram | types::Filetype::SocketStream => (
types::Rights::socket_base(),
types::Rights::socket_inheriting(),
),
types::Filetype::SymbolicLink | types::Filetype::Unknown => (
types::Rights::regular_file_base(),
types::Rights::regular_file_inheriting(),
),
_ => unreachable!("these should have been handled already!"),
};
let rights = HandleRights::new(base, inheriting);
Ok(rights)
}

impl OsOtherExt for OsOther {
fn from_null() -> io::Result<Box<dyn Handle>> {
let file = OpenOptions::new().read(true).write(true).open("NUL")?;
Expand Down
Loading

0 comments on commit 991ce43

Please sign in to comment.