1 use crate::sync::file::convert_systimespec;
2 use fs_set_times::SetTimes;
3 use std::any::Any;
4 use std::convert::TryInto;
5 use std::io::{self, IsTerminal, Read, Write};
6 use system_interface::io::ReadReady;
7 
8 use crate::{
9     file::{FdFlags, FileType, WasiFile},
10     Error, ErrorExt,
11 };
12 #[cfg(windows)]
13 use io_extras::os::windows::{AsRawHandleOrSocket, RawHandleOrSocket};
14 #[cfg(unix)]
15 use io_lifetimes::{AsFd, BorrowedFd};
16 #[cfg(windows)]
17 use io_lifetimes::{AsHandle, BorrowedHandle};
18 
19 pub struct Stdin(std::io::Stdin);
20 
21 pub fn stdin() -> Stdin {
22     Stdin(std::io::stdin())
23 }
24 
25 #[wiggle::async_trait]
26 impl WasiFile for Stdin {
27     fn as_any(&self) -> &dyn Any {
28         self
29     }
30 
31     #[cfg(unix)]
32     fn pollable(&self) -> Option<rustix::fd::BorrowedFd> {
33         Some(self.0.as_fd())
34     }
35 
36     #[cfg(windows)]
37     fn pollable(&self) -> Option<io_extras::os::windows::RawHandleOrSocket> {
38         Some(self.0.as_raw_handle_or_socket())
39     }
40 
41     async fn get_filetype(&self) -> Result<FileType, Error> {
42         if self.isatty() {
43             Ok(FileType::CharacterDevice)
44         } else {
45             Ok(FileType::Unknown)
46         }
47     }
48     async fn read_vectored<'a>(&self, bufs: &mut [io::IoSliceMut<'a>]) -> Result<u64, Error> {
49         let n = self.0.lock().read_vectored(bufs)?;
50         Ok(n.try_into().map_err(|_| Error::range())?)
51     }
52     async fn read_vectored_at<'a>(
53         &self,
54         _bufs: &mut [io::IoSliceMut<'a>],
55         _offset: u64,
56     ) -> Result<u64, Error> {
57         Err(Error::seek_pipe())
58     }
59     async fn seek(&self, _pos: std::io::SeekFrom) -> Result<u64, Error> {
60         Err(Error::seek_pipe())
61     }
62     async fn peek(&self, _buf: &mut [u8]) -> Result<u64, Error> {
63         Err(Error::seek_pipe())
64     }
65     async fn set_times(
66         &self,
67         atime: Option<crate::SystemTimeSpec>,
68         mtime: Option<crate::SystemTimeSpec>,
69     ) -> Result<(), Error> {
70         self.0
71             .set_times(convert_systimespec(atime), convert_systimespec(mtime))?;
72         Ok(())
73     }
74     fn num_ready_bytes(&self) -> Result<u64, Error> {
75         Ok(self.0.num_ready_bytes()?)
76     }
77     fn isatty(&self) -> bool {
78         #[cfg(unix)]
79         return self.0.as_fd().is_terminal();
80         #[cfg(windows)]
81         return self.0.as_handle().is_terminal();
82     }
83 }
84 #[cfg(windows)]
85 impl AsHandle for Stdin {
86     fn as_handle(&self) -> BorrowedHandle<'_> {
87         self.0.as_handle()
88     }
89 }
90 #[cfg(windows)]
91 impl AsRawHandleOrSocket for Stdin {
92     #[inline]
93     fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
94         self.0.as_raw_handle_or_socket()
95     }
96 }
97 #[cfg(unix)]
98 impl AsFd for Stdin {
99     fn as_fd(&self) -> BorrowedFd<'_> {
100         self.0.as_fd()
101     }
102 }
103 
104 macro_rules! wasi_file_write_impl {
105     ($ty:ty, $ident:ident) => {
106         #[wiggle::async_trait]
107         impl WasiFile for $ty {
108             fn as_any(&self) -> &dyn Any {
109                 self
110             }
111             #[cfg(unix)]
112             fn pollable(&self) -> Option<rustix::fd::BorrowedFd> {
113                 Some(self.0.as_fd())
114             }
115             #[cfg(windows)]
116             fn pollable(&self) -> Option<io_extras::os::windows::RawHandleOrSocket> {
117                 Some(self.0.as_raw_handle_or_socket())
118             }
119             async fn get_filetype(&self) -> Result<FileType, Error> {
120                 if self.isatty() {
121                     Ok(FileType::CharacterDevice)
122                 } else {
123                     Ok(FileType::Unknown)
124                 }
125             }
126             async fn get_fdflags(&self) -> Result<FdFlags, Error> {
127                 Ok(FdFlags::APPEND)
128             }
129             async fn write_vectored<'a>(&self, bufs: &[io::IoSlice<'a>]) -> Result<u64, Error> {
130                 let mut io = self.0.lock();
131                 let n = io.write_vectored(bufs)?;
132                 // On a successful write additionally flush out the bytes to
133                 // handle stdio buffering done by libstd since WASI interfaces
134                 // here aren't buffered.
135                 io.flush()?;
136                 Ok(n.try_into().map_err(|_| {
137                     Error::range().context("converting write_vectored total length")
138                 })?)
139             }
140             async fn write_vectored_at<'a>(
141                 &self,
142                 _bufs: &[io::IoSlice<'a>],
143                 _offset: u64,
144             ) -> Result<u64, Error> {
145                 Err(Error::seek_pipe())
146             }
147             async fn seek(&self, _pos: std::io::SeekFrom) -> Result<u64, Error> {
148                 Err(Error::seek_pipe())
149             }
150             async fn set_times(
151                 &self,
152                 atime: Option<crate::SystemTimeSpec>,
153                 mtime: Option<crate::SystemTimeSpec>,
154             ) -> Result<(), Error> {
155                 self.0
156                     .set_times(convert_systimespec(atime), convert_systimespec(mtime))?;
157                 Ok(())
158             }
159             fn isatty(&self) -> bool {
160                 self.0.is_terminal()
161             }
162         }
163         #[cfg(windows)]
164         impl AsHandle for $ty {
165             fn as_handle(&self) -> BorrowedHandle<'_> {
166                 self.0.as_handle()
167             }
168         }
169         #[cfg(unix)]
170         impl AsFd for $ty {
171             fn as_fd(&self) -> BorrowedFd<'_> {
172                 self.0.as_fd()
173             }
174         }
175         #[cfg(windows)]
176         impl AsRawHandleOrSocket for $ty {
177             #[inline]
178             fn as_raw_handle_or_socket(&self) -> RawHandleOrSocket {
179                 self.0.as_raw_handle_or_socket()
180             }
181         }
182     };
183 }
184 
185 pub struct Stdout(std::io::Stdout);
186 
187 pub fn stdout() -> Stdout {
188     Stdout(std::io::stdout())
189 }
190 wasi_file_write_impl!(Stdout, Stdout);
191 
192 pub struct Stderr(std::io::Stderr);
193 
194 pub fn stderr() -> Stderr {
195     Stderr(std::io::stderr())
196 }
197 wasi_file_write_impl!(Stderr, Stderr);
198