-
Notifications
You must be signed in to change notification settings - Fork 14
/
windows.rs
149 lines (133 loc) · 4.33 KB
/
windows.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
use crate::PipeReader;
use crate::PipeWriter;
use std::fs::File;
use std::io;
use std::os::windows::prelude::*;
use std::ptr;
use windows_sys::Win32::Foundation::{
DuplicateHandle, BOOL, DUPLICATE_SAME_ACCESS, HANDLE, INVALID_HANDLE_VALUE,
};
use windows_sys::Win32::System::Pipes::CreatePipe;
use windows_sys::Win32::System::Threading::GetCurrentProcess;
pub(crate) fn pipe() -> io::Result<(PipeReader, PipeWriter)> {
let mut read_pipe = INVALID_HANDLE_VALUE;
let mut write_pipe = INVALID_HANDLE_VALUE;
let ret = unsafe {
// NOTE: These pipes do not support IOCP. We might want to emulate
// anonymous pipes with CreateNamedPipe, as Rust's stdlib does.
CreatePipe(&mut read_pipe, &mut write_pipe, ptr::null_mut(), 0)
};
if ret == 0 {
Err(io::Error::last_os_error())
} else {
unsafe {
Ok((
PipeReader::from_raw_handle(read_pipe as _),
PipeWriter::from_raw_handle(write_pipe as _),
))
}
}
}
pub(crate) fn dup<F: AsRawHandle>(wrapper: &F) -> io::Result<File> {
// We rely on ("abuse") std::fs::File for a lot of descriptor/handle
// operations. (For example, setting F_DUPFD_CLOEXEC on Unix is a
// compatibility mess.) However, in the particular case of try_clone on
// Windows, the standard library has a bug where duplicated handles end up
// inheritable when they shouldn't be. See
// https://github.com/rust-lang/rust/pull/65316. This leads to races where
// child processes can inherit each other's handles, which tends to cause
// deadlocks when the handle in question is a stdout pipe. To get that
// right, we explicitly make the necessary system calls here, just like
// libstd apart from that one flag.
// TODO: The fix for this issue shipped in Rust 1.40 (December 2019). When
// we bump the MSRV past that point, we can go ahead and delete this
// workaround. Until then, no rush.
let source_handle = wrapper.as_raw_handle() as HANDLE;
let desired_access = 0; // Ignored because of DUPLICATE_SAME_ACCESS.
let inherit_handle = false as BOOL; // <-- Libstd sets this to true!
let options = DUPLICATE_SAME_ACCESS;
let mut duplicated_handle = 0 as HANDLE;
let ret = unsafe {
let current_process = GetCurrentProcess();
DuplicateHandle(
current_process,
source_handle,
current_process,
&mut duplicated_handle,
desired_access,
inherit_handle,
options,
)
};
if ret == 0 {
Err(io::Error::last_os_error())
} else {
unsafe { Ok(File::from_raw_handle(duplicated_handle as RawHandle)) }
}
}
impl IntoRawHandle for PipeReader {
fn into_raw_handle(self) -> RawHandle {
self.0.into_raw_handle()
}
}
impl AsRawHandle for PipeReader {
fn as_raw_handle(&self) -> RawHandle {
self.0.as_raw_handle()
}
}
impl FromRawHandle for PipeReader {
unsafe fn from_raw_handle(handle: RawHandle) -> PipeReader {
PipeReader(File::from_raw_handle(handle))
}
}
impl IntoRawHandle for PipeWriter {
fn into_raw_handle(self) -> RawHandle {
self.0.into_raw_handle()
}
}
impl AsRawHandle for PipeWriter {
fn as_raw_handle(&self) -> RawHandle {
self.0.as_raw_handle()
}
}
impl FromRawHandle for PipeWriter {
unsafe fn from_raw_handle(handle: RawHandle) -> PipeWriter {
PipeWriter(File::from_raw_handle(handle))
}
}
#[cfg(feature = "io_safety")]
impl From<PipeReader> for OwnedHandle {
fn from(reader: PipeReader) -> Self {
reader.0.into()
}
}
#[cfg(feature = "io_safety")]
impl AsHandle for PipeReader {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.0.as_handle()
}
}
#[cfg(feature = "io_safety")]
impl From<OwnedHandle> for PipeReader {
fn from(handle: OwnedHandle) -> Self {
PipeReader(handle.into())
}
}
#[cfg(feature = "io_safety")]
impl From<PipeWriter> for OwnedHandle {
fn from(writer: PipeWriter) -> Self {
writer.0.into()
}
}
#[cfg(feature = "io_safety")]
impl AsHandle for PipeWriter {
fn as_handle(&self) -> BorrowedHandle<'_> {
self.0.as_handle()
}
}
#[cfg(feature = "io_safety")]
impl From<OwnedHandle> for PipeWriter {
fn from(handle: OwnedHandle) -> Self {
PipeWriter(handle.into())
}
}