use super::{fd, AsFile};
use crate::handle::{Fdflags, Filetype, Handle, HandleRights, Rights, RightsExt, Size};
use crate::sandboxed_tty_writer::SandboxedTTYWriter;
use crate::{Error, Result};
use std::any::Any;
use std::cell::Cell;
use std::convert::TryInto;
use std::io::{self, Read, Write};
pub(crate) trait StdinExt: Sized {
fn stdin() -> io::Result<Box<dyn Handle>>;
}
#[derive(Debug, Clone)]
pub(crate) struct Stdin {
pub(crate) file_type: Filetype,
pub(crate) rights: Cell<HandleRights>,
}
impl Handle for Stdin {
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) -> Filetype {
self.file_type
}
fn get_rights(&self) -> HandleRights {
self.rights.get()
}
fn set_rights(&self, new_rights: HandleRights) {
self.rights.set(new_rights)
}
fn fdstat_get(&self) -> Result<Fdflags> {
fd::fdstat_get(&*self.as_file()?)
}
fn fdstat_set_flags(&self, fdflags: Fdflags) -> Result<()> {
if let Some(_) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
panic!("Tried updating Fdflags on Stdio handle by re-opening as file!");
}
Ok(())
}
fn read_vectored(&self, iovs: &mut [io::IoSliceMut]) -> Result<usize> {
let nread = io::stdin().read_vectored(iovs)?;
Ok(nread)
}
}
pub(crate) trait StdoutExt: Sized {
fn stdout() -> io::Result<Box<dyn Handle>>;
}
#[derive(Debug, Clone)]
pub(crate) struct Stdout {
pub(crate) file_type: Filetype,
pub(crate) rights: Cell<HandleRights>,
}
impl Handle for Stdout {
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) -> Filetype {
self.file_type
}
fn get_rights(&self) -> HandleRights {
self.rights.get()
}
fn set_rights(&self, new_rights: HandleRights) {
self.rights.set(new_rights)
}
fn fdstat_get(&self) -> Result<Fdflags> {
fd::fdstat_get(&*self.as_file()?)
}
fn fdstat_set_flags(&self, fdflags: Fdflags) -> Result<()> {
if let Some(_) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
panic!("Tried updating Fdflags on Stdio handle by re-opening as file!");
}
Ok(())
}
fn write_vectored(&self, iovs: &[io::IoSlice]) -> Result<usize> {
let stdout = io::stdout();
let mut stdout = stdout.lock();
let nwritten = if self.is_tty() {
SandboxedTTYWriter::new(&mut stdout).write_vectored(&iovs)?
} else {
stdout.write_vectored(iovs)?
};
stdout.flush()?;
Ok(nwritten)
}
}
pub(crate) trait StderrExt: Sized {
fn stderr() -> io::Result<Box<dyn Handle>>;
}
#[derive(Debug, Clone)]
pub(crate) struct Stderr {
pub(crate) file_type: Filetype,
pub(crate) rights: Cell<HandleRights>,
}
impl Handle for Stderr {
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) -> Filetype {
self.file_type
}
fn get_rights(&self) -> HandleRights {
self.rights.get()
}
fn set_rights(&self, new_rights: HandleRights) {
self.rights.set(new_rights)
}
fn fdstat_get(&self) -> Result<Fdflags> {
fd::fdstat_get(&*self.as_file()?)
}
fn fdstat_set_flags(&self, fdflags: Fdflags) -> Result<()> {
if let Some(_) = fd::fdstat_set_flags(&*self.as_file()?, fdflags)? {
panic!("Tried updating Fdflags on Stdio handle by re-opening as file!");
}
Ok(())
}
fn write_vectored(&self, iovs: &[io::IoSlice]) -> Result<usize> {
let nwritten = SandboxedTTYWriter::new(&mut io::stderr()).write_vectored(&iovs)?;
Ok(nwritten)
}
}
#[derive(Debug, Clone)]
pub(crate) struct NullDevice {
pub(crate) rights: Cell<HandleRights>,
pub(crate) fd_flags: Cell<Fdflags>,
}
impl NullDevice {
pub(crate) fn new() -> Self {
let rights = HandleRights::new(
Rights::character_device_base(),
Rights::character_device_inheriting(),
);
let rights = Cell::new(rights);
let fd_flags = 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) -> Filetype {
Filetype::CharacterDevice
}
fn get_rights(&self) -> HandleRights {
self.rights.get()
}
fn set_rights(&self, rights: HandleRights) {
self.rights.set(rights)
}
fn fdstat_get(&self) -> Result<Fdflags> {
Ok(self.fd_flags.get())
}
fn fdstat_set_flags(&self, fdflags: 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: Size = iov.len().try_into()?;
total_len = total_len.checked_add(len).ok_or(Error::Overflow)?;
}
Ok(total_len as usize)
}
}