Skip to content

Commit 0945267

Browse files
committed
Allow for stdio to be non-character-device (e.g., piped)
1 parent 1c183f6 commit 0945267

File tree

7 files changed

+128
-111
lines changed

7 files changed

+128
-111
lines changed

crates/wasi-common/src/sys/stdio.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ pub(crate) trait StdinExt: Sized {
3232

3333
#[derive(Debug, Clone)]
3434
pub(crate) struct Stdin {
35+
pub(crate) file_type: Filetype,
3536
pub(crate) rights: Cell<HandleRights>,
3637
}
3738

@@ -43,7 +44,7 @@ impl Handle for Stdin {
4344
Ok(Box::new(self.clone()))
4445
}
4546
fn get_file_type(&self) -> Filetype {
46-
Filetype::CharacterDevice
47+
self.file_type
4748
}
4849
fn get_rights(&self) -> HandleRights {
4950
self.rights.get()
@@ -77,6 +78,7 @@ pub(crate) trait StdoutExt: Sized {
7778

7879
#[derive(Debug, Clone)]
7980
pub(crate) struct Stdout {
81+
pub(crate) file_type: Filetype,
8082
pub(crate) rights: Cell<HandleRights>,
8183
}
8284

@@ -88,7 +90,7 @@ impl Handle for Stdout {
8890
Ok(Box::new(self.clone()))
8991
}
9092
fn get_file_type(&self) -> Filetype {
91-
Filetype::CharacterDevice
93+
self.file_type
9294
}
9395
fn get_rights(&self) -> HandleRights {
9496
self.rights.get()
@@ -113,7 +115,11 @@ impl Handle for Stdout {
113115
// lock for the duration of the scope
114116
let stdout = io::stdout();
115117
let mut stdout = stdout.lock();
116-
let nwritten = SandboxedTTYWriter::new(&mut stdout).write_vectored(&iovs)?;
118+
let nwritten = if self.is_tty() {
119+
SandboxedTTYWriter::new(&mut stdout).write_vectored(&iovs)?
120+
} else {
121+
stdout.write_vectored(iovs)?
122+
};
117123
stdout.flush()?;
118124
Ok(nwritten)
119125
}
@@ -126,6 +132,7 @@ pub(crate) trait StderrExt: Sized {
126132

127133
#[derive(Debug, Clone)]
128134
pub(crate) struct Stderr {
135+
pub(crate) file_type: Filetype,
129136
pub(crate) rights: Cell<HandleRights>,
130137
}
131138

@@ -137,7 +144,7 @@ impl Handle for Stderr {
137144
Ok(Box::new(self.clone()))
138145
}
139146
fn get_file_type(&self) -> Filetype {
140-
Filetype::CharacterDevice
147+
self.file_type
141148
}
142149
fn get_rights(&self) -> HandleRights {
143150
self.rights.get()

crates/wasi-common/src/sys/unix/mod.rs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ cfg_if::cfg_if! {
2626
}
2727
}
2828

29+
use crate::handle::HandleRights;
2930
use crate::sys::AsFile;
30-
use crate::wasi::{types, Errno, Result};
31+
use crate::wasi::{types, Errno, Result, RightsExt};
3132
use std::convert::{TryFrom, TryInto};
3233
use std::fs::File;
3334
use std::io;
@@ -78,6 +79,52 @@ pub(super) fn get_file_type(file: &File) -> io::Result<types::Filetype> {
7879
Ok(file_type)
7980
}
8081

82+
pub(super) fn get_rights(file: &File, file_type: &types::Filetype) -> io::Result<HandleRights> {
83+
use yanix::{fcntl, file::OFlag};
84+
let (base, inheriting) = match file_type {
85+
types::Filetype::BlockDevice => (
86+
types::Rights::block_device_base(),
87+
types::Rights::block_device_inheriting(),
88+
),
89+
types::Filetype::CharacterDevice => {
90+
use yanix::file::isatty;
91+
if unsafe { isatty(file.as_raw_fd())? } {
92+
(types::Rights::tty_base(), types::Rights::tty_base())
93+
} else {
94+
(
95+
types::Rights::character_device_base(),
96+
types::Rights::character_device_inheriting(),
97+
)
98+
}
99+
}
100+
types::Filetype::SocketDgram | types::Filetype::SocketStream => (
101+
types::Rights::socket_base(),
102+
types::Rights::socket_inheriting(),
103+
),
104+
types::Filetype::SymbolicLink | types::Filetype::Unknown => (
105+
types::Rights::regular_file_base(),
106+
types::Rights::regular_file_inheriting(),
107+
),
108+
types::Filetype::Directory => (
109+
types::Rights::directory_base(),
110+
types::Rights::directory_inheriting(),
111+
),
112+
types::Filetype::RegularFile => (
113+
types::Rights::regular_file_base(),
114+
types::Rights::regular_file_inheriting(),
115+
),
116+
};
117+
let mut rights = HandleRights::new(base, inheriting);
118+
let flags = unsafe { fcntl::get_status_flags(file.as_raw_fd())? };
119+
let accmode = flags & OFlag::ACCMODE;
120+
if accmode == OFlag::RDONLY {
121+
rights.base &= !types::Rights::FD_WRITE;
122+
} else if accmode == OFlag::WRONLY {
123+
rights.base &= !types::Rights::FD_READ;
124+
}
125+
Ok(rights)
126+
}
127+
81128
pub fn preopen_dir<P: AsRef<Path>>(path: P) -> io::Result<File> {
82129
File::open(path)
83130
}

crates/wasi-common/src/sys/unix/osother.rs

Lines changed: 4 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use super::get_file_type;
21
use super::oshandle::RawOsHandle;
3-
use crate::handle::{Handle, HandleRights};
2+
use super::{get_file_type, get_rights};
3+
use crate::handle::Handle;
44
use crate::sys::osother::{OsOther, OsOtherExt};
5-
use crate::wasi::{types, RightsExt};
5+
use crate::wasi::types;
66
use std::convert::TryFrom;
77
use std::fs::{File, OpenOptions};
88
use std::io;
9-
use std::os::unix::prelude::{AsRawFd, FromRawFd, IntoRawFd};
9+
use std::os::unix::prelude::{FromRawFd, IntoRawFd};
1010

1111
impl TryFrom<File> for OsOther {
1212
type Error = io::Error;
@@ -22,45 +22,6 @@ impl TryFrom<File> for OsOther {
2222
}
2323
}
2424

25-
fn get_rights(file: &File, file_type: &types::Filetype) -> io::Result<HandleRights> {
26-
use yanix::{fcntl, file::OFlag};
27-
let (base, inheriting) = match file_type {
28-
types::Filetype::BlockDevice => (
29-
types::Rights::block_device_base(),
30-
types::Rights::block_device_inheriting(),
31-
),
32-
types::Filetype::CharacterDevice => {
33-
use yanix::file::isatty;
34-
if unsafe { isatty(file.as_raw_fd())? } {
35-
(types::Rights::tty_base(), types::Rights::tty_base())
36-
} else {
37-
(
38-
types::Rights::character_device_base(),
39-
types::Rights::character_device_inheriting(),
40-
)
41-
}
42-
}
43-
types::Filetype::SocketDgram | types::Filetype::SocketStream => (
44-
types::Rights::socket_base(),
45-
types::Rights::socket_inheriting(),
46-
),
47-
types::Filetype::SymbolicLink | types::Filetype::Unknown => (
48-
types::Rights::regular_file_base(),
49-
types::Rights::regular_file_inheriting(),
50-
),
51-
_ => unreachable!("these should have been handled already!"),
52-
};
53-
let mut rights = HandleRights::new(base, inheriting);
54-
let flags = unsafe { fcntl::get_status_flags(file.as_raw_fd())? };
55-
let accmode = flags & OFlag::ACCMODE;
56-
if accmode == OFlag::RDONLY {
57-
rights.base &= !types::Rights::FD_WRITE;
58-
} else if accmode == OFlag::WRONLY {
59-
rights.base &= !types::Rights::FD_READ;
60-
}
61-
Ok(rights)
62-
}
63-
6425
impl OsOtherExt for OsOther {
6526
fn from_null() -> io::Result<Box<dyn Handle>> {
6627
let file = OpenOptions::new()
Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use crate::handle::{Handle, HandleRights};
1+
use super::{get_file_type, get_rights};
2+
use crate::handle::Handle;
23
use crate::sys::stdio::{Stderr, StderrExt, Stdin, StdinExt, Stdout, StdoutExt};
3-
use crate::wasi::{types, RightsExt};
44
use std::cell::Cell;
55
use std::fs::File;
66
use std::io;
@@ -29,43 +29,31 @@ impl StdinExt for Stdin {
2929
fn stdin() -> io::Result<Box<dyn Handle>> {
3030
let file = unsafe { File::from_raw_fd(io::stdin().as_raw_fd()) };
3131
let file = ManuallyDrop::new(file);
32-
let rights = get_rights(&file)?;
32+
let file_type = get_file_type(&file)?;
33+
let rights = get_rights(&file, &file_type)?;
3334
let rights = Cell::new(rights);
34-
Ok(Box::new(Self { rights }))
35+
Ok(Box::new(Self { file_type, rights }))
3536
}
3637
}
3738

3839
impl StdoutExt for Stdout {
3940
fn stdout() -> io::Result<Box<dyn Handle>> {
4041
let file = unsafe { File::from_raw_fd(io::stdout().as_raw_fd()) };
4142
let file = ManuallyDrop::new(file);
42-
let rights = get_rights(&file)?;
43+
let file_type = get_file_type(&file)?;
44+
let rights = get_rights(&file, &file_type)?;
4345
let rights = Cell::new(rights);
44-
Ok(Box::new(Self { rights }))
46+
Ok(Box::new(Self { file_type, rights }))
4547
}
4648
}
4749

4850
impl StderrExt for Stderr {
4951
fn stderr() -> io::Result<Box<dyn Handle>> {
5052
let file = unsafe { File::from_raw_fd(io::stderr().as_raw_fd()) };
5153
let file = ManuallyDrop::new(file);
52-
let rights = get_rights(&file)?;
54+
let file_type = get_file_type(&file)?;
55+
let rights = get_rights(&file, &file_type)?;
5356
let rights = Cell::new(rights);
54-
Ok(Box::new(Self { rights }))
57+
Ok(Box::new(Self { file_type, rights }))
5558
}
5659
}
57-
58-
fn get_rights(file: &File) -> io::Result<HandleRights> {
59-
use yanix::file::isatty;
60-
let (base, inheriting) = {
61-
if unsafe { isatty(file.as_raw_fd())? } {
62-
(types::Rights::tty_base(), types::Rights::tty_base())
63-
} else {
64-
(
65-
types::Rights::character_device_base(),
66-
types::Rights::character_device_inheriting(),
67-
)
68-
}
69-
};
70-
Ok(HandleRights::new(base, inheriting))
71-
}

crates/wasi-common/src/sys/windows/mod.rs

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ pub(crate) mod path;
88
pub(crate) mod poll;
99
pub(crate) mod stdio;
1010

11+
use crate::handle::HandleRights;
1112
use crate::sys::AsFile;
12-
use crate::wasi::{types, Errno, Result};
13+
use crate::wasi::{types, Errno, Result, RightsExt};
1314
use std::convert::{TryFrom, TryInto};
1415
use std::fs::File;
1516
use std::mem::ManuallyDrop;
@@ -27,7 +28,7 @@ impl<T: AsRawHandle> AsFile for T {
2728
}
2829
}
2930

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

57+
pub(super) fn get_rights(file_type: &types::Filetype) -> io::Result<HandleRights> {
58+
let (base, inheriting) = match file_type {
59+
types::Filetype::BlockDevice => (
60+
types::Rights::block_device_base(),
61+
types::Rights::block_device_inheriting(),
62+
),
63+
types::Filetype::CharacterDevice => (types::Rights::tty_base(), types::Rights::tty_base()),
64+
types::Filetype::SocketDgram | types::Filetype::SocketStream => (
65+
types::Rights::socket_base(),
66+
types::Rights::socket_inheriting(),
67+
),
68+
types::Filetype::SymbolicLink | types::Filetype::Unknown => (
69+
types::Rights::regular_file_base(),
70+
types::Rights::regular_file_inheriting(),
71+
),
72+
types::Filetype::Directory => (
73+
types::Rights::directory_base(),
74+
types::Rights::directory_inheriting(),
75+
),
76+
types::Filetype::RegularFile => (
77+
types::Rights::regular_file_base(),
78+
types::Rights::regular_file_inheriting(),
79+
),
80+
};
81+
let rights = HandleRights::new(base, inheriting);
82+
Ok(rights)
83+
}
84+
5685
pub fn preopen_dir<P: AsRef<Path>>(path: P) -> io::Result<File> {
5786
use std::fs::OpenOptions;
5887
use std::os::windows::fs::OpenOptionsExt;

crates/wasi-common/src/sys/windows/osother.rs

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
use super::get_file_type;
21
use super::oshandle::RawOsHandle;
3-
use crate::handle::{Handle, HandleRights};
2+
use super::{get_file_type, get_rights};
3+
use crate::handle::Handle;
44
use crate::sys::osother::{OsOther, OsOtherExt};
5-
use crate::wasi::{types, RightsExt};
5+
use crate::wasi::types;
66
use std::convert::TryFrom;
77
use std::fs::{File, OpenOptions};
88
use std::io;
@@ -22,27 +22,6 @@ impl TryFrom<File> for OsOther {
2222
}
2323
}
2424

25-
fn get_rights(file_type: &types::Filetype) -> io::Result<HandleRights> {
26-
let (base, inheriting) = match file_type {
27-
types::Filetype::BlockDevice => (
28-
types::Rights::block_device_base(),
29-
types::Rights::block_device_inheriting(),
30-
),
31-
types::Filetype::CharacterDevice => (types::Rights::tty_base(), types::Rights::tty_base()),
32-
types::Filetype::SocketDgram | types::Filetype::SocketStream => (
33-
types::Rights::socket_base(),
34-
types::Rights::socket_inheriting(),
35-
),
36-
types::Filetype::SymbolicLink | types::Filetype::Unknown => (
37-
types::Rights::regular_file_base(),
38-
types::Rights::regular_file_inheriting(),
39-
),
40-
_ => unreachable!("these should have been handled already!"),
41-
};
42-
let rights = HandleRights::new(base, inheriting);
43-
Ok(rights)
44-
}
45-
4625
impl OsOtherExt for OsOther {
4726
fn from_null() -> io::Result<Box<dyn Handle>> {
4827
let file = OpenOptions::new().read(true).write(true).open("NUL")?;

0 commit comments

Comments
 (0)