mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
Auto merge of #25494 - alexcrichton:stdio-from-raw, r=aturon
This commit implements a number of standard traits for the standard library's process I/O handles. The `FromRaw{Fd,Handle}` traits are now implemented for the `Stdio` type and the `AsRaw{Fd,Handle}` traits are now implemented for the `Child{Stdout,Stdin,Stderr}` types. The stability markers for these implementations mention that they are stable for 1.1 as I will nominate this commit for cherry-picking to beta.
This commit is contained in:
commit
996fb8d001
@ -22,11 +22,8 @@ use io::{self, Error, ErrorKind};
|
||||
use path;
|
||||
use sync::mpsc::{channel, Receiver};
|
||||
use sys::pipe::{self, AnonPipe};
|
||||
use sys::process::Command as CommandImp;
|
||||
use sys::process::Process as ProcessImp;
|
||||
use sys::process::ExitStatus as ExitStatusImp;
|
||||
use sys::process::Stdio as StdioImp2;
|
||||
use sys_common::{AsInner, AsInnerMut};
|
||||
use sys::process as imp;
|
||||
use sys_common::{AsInner, AsInnerMut, FromInner};
|
||||
use thread;
|
||||
|
||||
/// Representation of a running or exited child process.
|
||||
@ -52,10 +49,10 @@ use thread;
|
||||
/// ```
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub struct Child {
|
||||
handle: ProcessImp,
|
||||
handle: imp::Process,
|
||||
|
||||
/// None until wait() or wait_with_output() is called.
|
||||
status: Option<ExitStatusImp>,
|
||||
status: Option<imp::ExitStatus>,
|
||||
|
||||
/// The handle for writing to the child's stdin, if it has been captured
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
@ -70,6 +67,10 @@ pub struct Child {
|
||||
pub stderr: Option<ChildStderr>,
|
||||
}
|
||||
|
||||
impl AsInner<imp::Process> for Child {
|
||||
fn as_inner(&self) -> &imp::Process { &self.handle }
|
||||
}
|
||||
|
||||
/// A handle to a child procesess's stdin
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub struct ChildStdin {
|
||||
@ -87,6 +88,10 @@ impl Write for ChildStdin {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<AnonPipe> for ChildStdin {
|
||||
fn as_inner(&self) -> &AnonPipe { &self.inner }
|
||||
}
|
||||
|
||||
/// A handle to a child procesess's stdout
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub struct ChildStdout {
|
||||
@ -100,6 +105,10 @@ impl Read for ChildStdout {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<AnonPipe> for ChildStdout {
|
||||
fn as_inner(&self) -> &AnonPipe { &self.inner }
|
||||
}
|
||||
|
||||
/// A handle to a child procesess's stderr
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub struct ChildStderr {
|
||||
@ -113,6 +122,10 @@ impl Read for ChildStderr {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<AnonPipe> for ChildStderr {
|
||||
fn as_inner(&self) -> &AnonPipe { &self.inner }
|
||||
}
|
||||
|
||||
/// The `Command` type acts as a process builder, providing fine-grained control
|
||||
/// over how a new process should be spawned. A default configuration can be
|
||||
/// generated using `Command::new(program)`, where `program` gives a path to the
|
||||
@ -131,12 +144,12 @@ impl Read for ChildStderr {
|
||||
/// ```
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub struct Command {
|
||||
inner: CommandImp,
|
||||
inner: imp::Command,
|
||||
|
||||
// Details explained in the builder methods
|
||||
stdin: Option<StdioImp>,
|
||||
stdout: Option<StdioImp>,
|
||||
stderr: Option<StdioImp>,
|
||||
stdin: Option<Stdio>,
|
||||
stdout: Option<Stdio>,
|
||||
stderr: Option<Stdio>,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
@ -153,7 +166,7 @@ impl Command {
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
|
||||
Command {
|
||||
inner: CommandImp::new(program.as_ref()),
|
||||
inner: imp::Command::new(program.as_ref()),
|
||||
stdin: None,
|
||||
stdout: None,
|
||||
stderr: None,
|
||||
@ -210,25 +223,26 @@ impl Command {
|
||||
/// Configuration for the child process's stdin handle (file descriptor 0).
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub fn stdin(&mut self, cfg: Stdio) -> &mut Command {
|
||||
self.stdin = Some(cfg.0);
|
||||
self.stdin = Some(cfg);
|
||||
self
|
||||
}
|
||||
|
||||
/// Configuration for the child process's stdout handle (file descriptor 1).
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub fn stdout(&mut self, cfg: Stdio) -> &mut Command {
|
||||
self.stdout = Some(cfg.0);
|
||||
self.stdout = Some(cfg);
|
||||
self
|
||||
}
|
||||
|
||||
/// Configuration for the child process's stderr handle (file descriptor 2).
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub fn stderr(&mut self, cfg: Stdio) -> &mut Command {
|
||||
self.stderr = Some(cfg.0);
|
||||
self.stderr = Some(cfg);
|
||||
self
|
||||
}
|
||||
|
||||
fn spawn_inner(&self, default_io: StdioImp) -> io::Result<Child> {
|
||||
let default_io = Stdio(default_io);
|
||||
let (their_stdin, our_stdin) = try!(
|
||||
setup_io(self.stdin.as_ref().unwrap_or(&default_io), true)
|
||||
);
|
||||
@ -239,7 +253,8 @@ impl Command {
|
||||
setup_io(self.stderr.as_ref().unwrap_or(&default_io), false)
|
||||
);
|
||||
|
||||
match ProcessImp::spawn(&self.inner, their_stdin, their_stdout, their_stderr) {
|
||||
match imp::Process::spawn(&self.inner, their_stdin, their_stdout,
|
||||
their_stderr) {
|
||||
Err(e) => Err(e),
|
||||
Ok(handle) => Ok(Child {
|
||||
handle: handle,
|
||||
@ -256,7 +271,7 @@ impl Command {
|
||||
/// By default, stdin, stdout and stderr are inherited by the parent.
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub fn spawn(&mut self) -> io::Result<Child> {
|
||||
self.spawn_inner(StdioImp::Inherit)
|
||||
self.spawn_inner(StdioImp::Raw(imp::Stdio::Inherit))
|
||||
}
|
||||
|
||||
/// Executes the command as a child process, waiting for it to finish and
|
||||
@ -279,7 +294,7 @@ impl Command {
|
||||
/// ```
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub fn output(&mut self) -> io::Result<Output> {
|
||||
self.spawn_inner(StdioImp::Piped).and_then(|p| p.wait_with_output())
|
||||
self.spawn_inner(StdioImp::MakePipe).and_then(|p| p.wait_with_output())
|
||||
}
|
||||
|
||||
/// Executes a command as a child process, waiting for it to finish and
|
||||
@ -318,29 +333,27 @@ impl fmt::Debug for Command {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<CommandImp> for Command {
|
||||
fn as_inner(&self) -> &CommandImp { &self.inner }
|
||||
impl AsInner<imp::Command> for Command {
|
||||
fn as_inner(&self) -> &imp::Command { &self.inner }
|
||||
}
|
||||
|
||||
impl AsInnerMut<CommandImp> for Command {
|
||||
fn as_inner_mut(&mut self) -> &mut CommandImp { &mut self.inner }
|
||||
impl AsInnerMut<imp::Command> for Command {
|
||||
fn as_inner_mut(&mut self) -> &mut imp::Command { &mut self.inner }
|
||||
}
|
||||
|
||||
fn setup_io(io: &StdioImp, readable: bool)
|
||||
-> io::Result<(StdioImp2, Option<AnonPipe>)>
|
||||
fn setup_io(io: &Stdio, readable: bool)
|
||||
-> io::Result<(imp::Stdio, Option<AnonPipe>)>
|
||||
{
|
||||
use self::StdioImp::*;
|
||||
Ok(match *io {
|
||||
Null => (StdioImp2::None, None),
|
||||
Inherit => (StdioImp2::Inherit, None),
|
||||
Piped => {
|
||||
Ok(match io.0 {
|
||||
StdioImp::MakePipe => {
|
||||
let (reader, writer) = try!(pipe::anon_pipe());
|
||||
if readable {
|
||||
(StdioImp2::Piped(reader), Some(writer))
|
||||
(imp::Stdio::Piped(reader), Some(writer))
|
||||
} else {
|
||||
(StdioImp2::Piped(writer), Some(reader))
|
||||
(imp::Stdio::Piped(writer), Some(reader))
|
||||
}
|
||||
}
|
||||
StdioImp::Raw(ref raw) => (raw.clone_if_copy(), None),
|
||||
})
|
||||
}
|
||||
|
||||
@ -364,32 +377,36 @@ pub struct Output {
|
||||
pub struct Stdio(StdioImp);
|
||||
|
||||
// The internal enum for stdio setup; see below for descriptions.
|
||||
#[derive(Clone)]
|
||||
enum StdioImp {
|
||||
Piped,
|
||||
Inherit,
|
||||
Null,
|
||||
MakePipe,
|
||||
Raw(imp::Stdio),
|
||||
}
|
||||
|
||||
impl Stdio {
|
||||
/// A new pipe should be arranged to connect the parent and child processes.
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub fn piped() -> Stdio { Stdio(StdioImp::Piped) }
|
||||
pub fn piped() -> Stdio { Stdio(StdioImp::MakePipe) }
|
||||
|
||||
/// The child inherits from the corresponding parent descriptor.
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub fn inherit() -> Stdio { Stdio(StdioImp::Inherit) }
|
||||
pub fn inherit() -> Stdio { Stdio(StdioImp::Raw(imp::Stdio::Inherit)) }
|
||||
|
||||
/// This stream will be ignored. This is the equivalent of attaching the
|
||||
/// stream to `/dev/null`
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub fn null() -> Stdio { Stdio(StdioImp::Null) }
|
||||
pub fn null() -> Stdio { Stdio(StdioImp::Raw(imp::Stdio::None)) }
|
||||
}
|
||||
|
||||
impl FromInner<imp::Stdio> for Stdio {
|
||||
fn from_inner(inner: imp::Stdio) -> Stdio {
|
||||
Stdio(StdioImp::Raw(inner))
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes the result of a process after it has terminated.
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
pub struct ExitStatus(ExitStatusImp);
|
||||
pub struct ExitStatus(imp::ExitStatus);
|
||||
|
||||
impl ExitStatus {
|
||||
/// Was termination successful? Signal termination not considered a success,
|
||||
@ -410,8 +427,8 @@ impl ExitStatus {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsInner<ExitStatusImp> for ExitStatus {
|
||||
fn as_inner(&self) -> &ExitStatusImp { &self.0 }
|
||||
impl AsInner<imp::ExitStatus> for ExitStatus {
|
||||
fn as_inner(&self) -> &imp::ExitStatus { &self.0 }
|
||||
}
|
||||
|
||||
#[stable(feature = "process", since = "1.0.0")]
|
||||
|
@ -13,10 +13,11 @@
|
||||
#![stable(feature = "rust1", since = "1.0.0")]
|
||||
|
||||
use os::unix::raw::{uid_t, gid_t};
|
||||
use os::unix::io::{FromRawFd, RawFd, AsRawFd};
|
||||
use prelude::v1::*;
|
||||
use process;
|
||||
use sys;
|
||||
use sys_common::{AsInnerMut, AsInner};
|
||||
use sys_common::{AsInnerMut, AsInner, FromInner};
|
||||
|
||||
/// Unix-specific extensions to the `std::process::Command` builder
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -63,3 +64,49 @@ impl ExitStatusExt for process::ExitStatus {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||
impl FromRawFd for process::Stdio {
|
||||
/// Creates a new instance of `Stdio` from the raw underlying file
|
||||
/// descriptor.
|
||||
///
|
||||
/// When this `Stdio` is used as an I/O handle for a child process the given
|
||||
/// file descriptor will be `dup`d into the destination file descriptor in
|
||||
/// the child process.
|
||||
///
|
||||
/// Note that this function **does not** take ownership of the file
|
||||
/// descriptor provided and it will **not** be closed when `Stdio` goes out
|
||||
/// of scope. As a result this method is unsafe because due to the lack of
|
||||
/// knowledge about the lifetime of the provided file descriptor, this could
|
||||
/// cause another I/O primitive's ownership property of its file descriptor
|
||||
/// to be violated.
|
||||
///
|
||||
/// Also note that this file descriptor may be used multiple times to spawn
|
||||
/// processes. For example the `Command::spawn` function could be called
|
||||
/// more than once to spawn more than one process sharing this file
|
||||
/// descriptor.
|
||||
unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
|
||||
process::Stdio::from_inner(sys::process::Stdio::Fd(fd))
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||
impl AsRawFd for process::ChildStdin {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().fd().raw()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||
impl AsRawFd for process::ChildStdout {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().fd().raw()
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||
impl AsRawFd for process::ChildStderr {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.as_inner().fd().raw()
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,6 @@ impl AnonPipe {
|
||||
self.0.write(buf)
|
||||
}
|
||||
|
||||
pub fn into_fd(self) -> FileDesc {
|
||||
self.0
|
||||
}
|
||||
pub fn fd(&self) -> &FileDesc { &self.0 }
|
||||
pub fn into_fd(self) -> FileDesc { self.0 }
|
||||
}
|
||||
|
@ -123,6 +123,7 @@ pub enum Stdio {
|
||||
Inherit,
|
||||
Piped(AnonPipe),
|
||||
None,
|
||||
Fd(c_int),
|
||||
}
|
||||
|
||||
const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
|
||||
@ -253,6 +254,7 @@ impl Process {
|
||||
let setup = |src: Stdio, dst: c_int| {
|
||||
let fd = match src {
|
||||
Stdio::Inherit => return true,
|
||||
Stdio::Fd(fd) => return cvt_r(|| libc::dup2(fd, dst)).is_ok(),
|
||||
Stdio::Piped(pipe) => pipe.into_fd(),
|
||||
|
||||
// If a stdio file descriptor is set to be ignored, we open up
|
||||
@ -416,3 +418,14 @@ fn translate_status(status: c_int) -> ExitStatus {
|
||||
ExitStatus::Signal(imp::WTERMSIG(status))
|
||||
}
|
||||
}
|
||||
|
||||
impl Stdio {
|
||||
pub fn clone_if_copy(&self) -> Stdio {
|
||||
match *self {
|
||||
Stdio::Inherit => Stdio::Inherit,
|
||||
Stdio::None => Stdio::None,
|
||||
Stdio::Fd(fd) => Stdio::Fd(fd),
|
||||
Stdio::Piped(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ pub mod ffi;
|
||||
pub mod fs;
|
||||
pub mod io;
|
||||
pub mod raw;
|
||||
pub mod process;
|
||||
|
||||
/// A prelude for conveniently writing platform-specific code.
|
||||
///
|
||||
|
69
src/libstd/sys/windows/ext/process.rs
Normal file
69
src/libstd/sys/windows/ext/process.rs
Normal file
@ -0,0 +1,69 @@
|
||||
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Extensions to `std::process` for Windows.
|
||||
|
||||
#![stable(feature = "from_raw_os", since = "1.1.0")]
|
||||
|
||||
use os::windows::io::{FromRawHandle, RawHandle, AsRawHandle};
|
||||
use process;
|
||||
use sys;
|
||||
use sys_common::{AsInner, FromInner};
|
||||
|
||||
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||
impl FromRawHandle for process::Stdio {
|
||||
/// Creates a new instance of `Stdio` from the raw underlying handle.
|
||||
///
|
||||
/// When this `Stdio` is used as an I/O handle for a child process the given
|
||||
/// handle will be duplicated via `DuplicateHandle` to ensure that the
|
||||
/// handle has the correct permissions to cross the process boundary.
|
||||
///
|
||||
/// Note that this function **does not** take ownership of the handle
|
||||
/// provided and it will **not** be closed when `Stdio` goes out of scope.
|
||||
/// As a result this method is unsafe because due to the lack of knowledge
|
||||
/// about the lifetime of the provided handle, this could cause another I/O
|
||||
/// primitive's ownership property of its handle to be violated.
|
||||
///
|
||||
/// Also note that this handle may be used multiple times to spawn
|
||||
/// processes. For example the `Command::spawn` function could be called
|
||||
/// more than once to spawn more than one process sharing this handle.
|
||||
unsafe fn from_raw_handle(handle: RawHandle) -> process::Stdio {
|
||||
let handle = sys::handle::RawHandle::new(handle as *mut _);
|
||||
process::Stdio::from_inner(sys::process::Stdio::Handle(handle))
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||
impl AsRawHandle for process::Child {
|
||||
fn as_raw_handle(&self) -> RawHandle {
|
||||
self.as_inner().handle().raw() as *mut _
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||
impl AsRawHandle for process::ChildStdin {
|
||||
fn as_raw_handle(&self) -> RawHandle {
|
||||
self.as_inner().handle().raw() as *mut _
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||
impl AsRawHandle for process::ChildStdout {
|
||||
fn as_raw_handle(&self) -> RawHandle {
|
||||
self.as_inner().handle().raw() as *mut _
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||
impl AsRawHandle for process::ChildStderr {
|
||||
fn as_raw_handle(&self) -> RawHandle {
|
||||
self.as_inner().handle().raw() as *mut _
|
||||
}
|
||||
}
|
@ -15,26 +15,55 @@ use io;
|
||||
use libc::funcs::extra::kernel32::{GetCurrentProcess, DuplicateHandle};
|
||||
use libc::{self, HANDLE};
|
||||
use mem;
|
||||
use ops::Deref;
|
||||
use ptr;
|
||||
use sys::cvt;
|
||||
|
||||
pub struct Handle(HANDLE);
|
||||
/// An owned container for `HANDLE` object, closing them on Drop.
|
||||
///
|
||||
/// All methods are inherited through a `Deref` impl to `RawHandle`
|
||||
pub struct Handle(RawHandle);
|
||||
|
||||
unsafe impl Send for Handle {}
|
||||
unsafe impl Sync for Handle {}
|
||||
/// A wrapper type for `HANDLE` objects to give them proper Send/Sync inference
|
||||
/// as well as Rust-y methods.
|
||||
///
|
||||
/// This does **not** drop the handle when it goes out of scope, use `Handle`
|
||||
/// instead for that.
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct RawHandle(HANDLE);
|
||||
|
||||
unsafe impl Send for RawHandle {}
|
||||
unsafe impl Sync for RawHandle {}
|
||||
|
||||
impl Handle {
|
||||
pub fn new(handle: HANDLE) -> Handle {
|
||||
Handle(handle)
|
||||
Handle(RawHandle::new(handle))
|
||||
}
|
||||
|
||||
pub fn raw(&self) -> HANDLE { self.0 }
|
||||
|
||||
pub fn into_raw(self) -> HANDLE {
|
||||
let ret = self.0;
|
||||
let ret = self.raw();
|
||||
mem::forget(self);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Handle {
|
||||
type Target = RawHandle;
|
||||
fn deref(&self) -> &RawHandle { &self.0 }
|
||||
}
|
||||
|
||||
impl Drop for Handle {
|
||||
fn drop(&mut self) {
|
||||
unsafe { let _ = libc::CloseHandle(self.raw()); }
|
||||
}
|
||||
}
|
||||
|
||||
impl RawHandle {
|
||||
pub fn new(handle: HANDLE) -> RawHandle {
|
||||
RawHandle(handle)
|
||||
}
|
||||
|
||||
pub fn raw(&self) -> HANDLE { self.0 }
|
||||
|
||||
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
let mut read = 0;
|
||||
@ -79,9 +108,3 @@ impl Handle {
|
||||
Ok(Handle::new(ret))
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Handle {
|
||||
fn drop(&mut self) {
|
||||
unsafe { let _ = libc::CloseHandle(self.0); }
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ use ptr;
|
||||
use sync::StaticMutex;
|
||||
use sys::c;
|
||||
use sys::fs::{OpenOptions, File};
|
||||
use sys::handle::Handle;
|
||||
use sys::handle::{Handle, RawHandle};
|
||||
use sys::pipe::AnonPipe;
|
||||
use sys::stdio;
|
||||
use sys::{self, cvt};
|
||||
@ -109,6 +109,7 @@ pub enum Stdio {
|
||||
Inherit,
|
||||
Piped(AnonPipe),
|
||||
None,
|
||||
Handle(RawHandle),
|
||||
}
|
||||
|
||||
impl Process {
|
||||
@ -217,6 +218,8 @@ impl Process {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle(&self) -> &Handle { &self.handle }
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
@ -353,6 +356,15 @@ fn make_dirp(d: Option<&OsString>) -> (*const u16, Vec<u16>) {
|
||||
}
|
||||
|
||||
impl Stdio {
|
||||
pub fn clone_if_copy(&self) -> Stdio {
|
||||
match *self {
|
||||
Stdio::Inherit => Stdio::Inherit,
|
||||
Stdio::None => Stdio::None,
|
||||
Stdio::Handle(handle) => Stdio::Handle(handle),
|
||||
Stdio::Piped(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_handle(&self, stdio_id: libc::DWORD) -> io::Result<Handle> {
|
||||
use libc::DUPLICATE_SAME_ACCESS;
|
||||
|
||||
@ -362,6 +374,9 @@ impl Stdio {
|
||||
io.handle().duplicate(0, true, DUPLICATE_SAME_ACCESS)
|
||||
})
|
||||
}
|
||||
Stdio::Handle(ref handle) => {
|
||||
handle.duplicate(0, true, DUPLICATE_SAME_ACCESS)
|
||||
}
|
||||
Stdio::Piped(ref pipe) => {
|
||||
pipe.handle().duplicate(0, true, DUPLICATE_SAME_ACCESS)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user