diff --git a/crates/wasi-common/src/sys/stdio.rs b/crates/wasi-common/src/sys/stdio.rs index 6aeed07dabcd..bbd2339ed0ce 100644 --- a/crates/wasi-common/src/sys/stdio.rs +++ b/crates/wasi-common/src/sys/stdio.rs @@ -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, } @@ -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() @@ -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, } @@ -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() @@ -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) } @@ -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, } @@ -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() diff --git a/crates/wasi-common/src/sys/unix/mod.rs b/crates/wasi-common/src/sys/unix/mod.rs index c1fac592b0e4..e71635db0423 100644 --- a/crates/wasi-common/src/sys/unix/mod.rs +++ b/crates/wasi-common/src/sys/unix/mod.rs @@ -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; @@ -78,6 +79,52 @@ pub(super) fn get_file_type(file: &File) -> io::Result { Ok(file_type) } +pub(super) fn get_rights(file: &File, file_type: &types::Filetype) -> io::Result { + 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>(path: P) -> io::Result { File::open(path) } diff --git a/crates/wasi-common/src/sys/unix/osother.rs b/crates/wasi-common/src/sys/unix/osother.rs index 14ee6e365cdd..260c47db8fec 100644 --- a/crates/wasi-common/src/sys/unix/osother.rs +++ b/crates/wasi-common/src/sys/unix/osother.rs @@ -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 for OsOther { type Error = io::Error; @@ -22,45 +22,6 @@ impl TryFrom for OsOther { } } -fn get_rights(file: &File, file_type: &types::Filetype) -> io::Result { - 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> { let file = OpenOptions::new() diff --git a/crates/wasi-common/src/sys/unix/stdio.rs b/crates/wasi-common/src/sys/unix/stdio.rs index caaa4f3686d0..5a38a2992b1c 100644 --- a/crates/wasi-common/src/sys/unix/stdio.rs +++ b/crates/wasi-common/src/sys/unix/stdio.rs @@ -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; @@ -29,9 +29,10 @@ impl StdinExt for Stdin { fn stdin() -> io::Result> { 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 })) } } @@ -39,9 +40,10 @@ impl StdoutExt for Stdout { fn stdout() -> io::Result> { 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 })) } } @@ -49,23 +51,9 @@ impl StderrExt for Stderr { fn stderr() -> io::Result> { 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 { - 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)) -} diff --git a/crates/wasi-common/src/sys/windows/mod.rs b/crates/wasi-common/src/sys/windows/mod.rs index b2a92ccb5260..109385f15adf 100644 --- a/crates/wasi-common/src/sys/windows/mod.rs +++ b/crates/wasi-common/src/sys/windows/mod.rs @@ -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; @@ -27,7 +28,7 @@ impl AsFile for T { } } -pub(crate) fn get_file_type(file: &File) -> io::Result { +pub(super) fn get_file_type(file: &File) -> io::Result { 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 @@ -53,6 +54,34 @@ pub(crate) fn get_file_type(file: &File) -> io::Result { Ok(file_type) } +pub(super) fn get_rights(file_type: &types::Filetype) -> io::Result { + 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>(path: P) -> io::Result { use std::fs::OpenOptions; use std::os::windows::fs::OpenOptionsExt; diff --git a/crates/wasi-common/src/sys/windows/osother.rs b/crates/wasi-common/src/sys/windows/osother.rs index 5f907980fd87..47db73217d90 100644 --- a/crates/wasi-common/src/sys/windows/osother.rs +++ b/crates/wasi-common/src/sys/windows/osother.rs @@ -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; @@ -22,27 +22,6 @@ impl TryFrom for OsOther { } } -fn get_rights(file_type: &types::Filetype) -> io::Result { - 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> { let file = OpenOptions::new().read(true).write(true).open("NUL")?; diff --git a/crates/wasi-common/src/sys/windows/stdio.rs b/crates/wasi-common/src/sys/windows/stdio.rs index f6d33aadedb7..25140db90a9a 100644 --- a/crates/wasi-common/src/sys/windows/stdio.rs +++ b/crates/wasi-common/src/sys/windows/stdio.rs @@ -1,9 +1,11 @@ -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; -use std::os::windows::prelude::{AsRawHandle, RawHandle}; +use std::mem::ManuallyDrop; +use std::os::windows::prelude::{AsRawHandle, FromRawHandle, RawHandle}; impl AsRawHandle for Stdin { fn as_raw_handle(&self) -> RawHandle { @@ -25,29 +27,33 @@ impl AsRawHandle for Stderr { impl StdinExt for Stdin { fn stdin() -> io::Result> { - let rights = get_rights()?; + let file = unsafe { File::from_raw_handle(io::stdin().as_raw_handle()) }; + let file = ManuallyDrop::new(file); + let file_type = get_file_type(&file)?; + let rights = get_rights(&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> { - let rights = get_rights()?; + let file = unsafe { File::from_raw_handle(io::stdin().as_raw_handle()) }; + let file = ManuallyDrop::new(file); + let file_type = get_file_type(&file)?; + let rights = get_rights(&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> { - let rights = get_rights()?; + let file = unsafe { File::from_raw_handle(io::stdin().as_raw_handle()) }; + let file = ManuallyDrop::new(file); + let file_type = get_file_type(&file)?; + let rights = get_rights(&file_type)?; let rights = Cell::new(rights); - Ok(Box::new(Self { rights })) + Ok(Box::new(Self { file_type, rights })) } } - -fn get_rights() -> io::Result { - let rights = HandleRights::new(types::Rights::tty_base(), types::Rights::tty_base()); - Ok(rights) -}