]> git.lizzy.rs Git - rust.git/blob - library/std/src/sys/windows/handle.rs
Auto merge of #107843 - bjorn3:sync_cg_clif-2023-02-09, r=bjorn3
[rust.git] / library / std / src / sys / windows / handle.rs
1 #![unstable(issue = "none", feature = "windows_handle")]
2
3 #[cfg(test)]
4 mod tests;
5
6 use crate::cmp;
7 use crate::io::{self, BorrowedCursor, ErrorKind, IoSlice, IoSliceMut, Read};
8 use crate::mem;
9 use crate::os::windows::io::{
10     AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle, OwnedHandle, RawHandle,
11 };
12 use crate::ptr;
13 use crate::sys::c;
14 use crate::sys::cvt;
15 use crate::sys_common::{AsInner, FromInner, IntoInner};
16
17 /// An owned container for `HANDLE` object, closing them on Drop.
18 ///
19 /// All methods are inherited through a `Deref` impl to `RawHandle`
20 pub struct Handle(OwnedHandle);
21
22 impl Handle {
23     pub fn new_event(manual: bool, init: bool) -> io::Result<Handle> {
24         unsafe {
25             let event =
26                 c::CreateEventW(ptr::null_mut(), manual as c::BOOL, init as c::BOOL, ptr::null());
27             if event.is_null() {
28                 Err(io::Error::last_os_error())
29             } else {
30                 Ok(Handle::from_raw_handle(event))
31             }
32         }
33     }
34 }
35
36 impl AsInner<OwnedHandle> for Handle {
37     fn as_inner(&self) -> &OwnedHandle {
38         &self.0
39     }
40 }
41
42 impl IntoInner<OwnedHandle> for Handle {
43     fn into_inner(self) -> OwnedHandle {
44         self.0
45     }
46 }
47
48 impl FromInner<OwnedHandle> for Handle {
49     fn from_inner(file_desc: OwnedHandle) -> Self {
50         Self(file_desc)
51     }
52 }
53
54 impl AsHandle for Handle {
55     fn as_handle(&self) -> BorrowedHandle<'_> {
56         self.0.as_handle()
57     }
58 }
59
60 impl AsRawHandle for Handle {
61     fn as_raw_handle(&self) -> RawHandle {
62         self.0.as_raw_handle()
63     }
64 }
65
66 impl IntoRawHandle for Handle {
67     fn into_raw_handle(self) -> RawHandle {
68         self.0.into_raw_handle()
69     }
70 }
71
72 impl FromRawHandle for Handle {
73     unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
74         Self(FromRawHandle::from_raw_handle(raw_handle))
75     }
76 }
77
78 impl Handle {
79     pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
80         let res = unsafe { self.synchronous_read(buf.as_mut_ptr().cast(), buf.len(), None) };
81
82         match res {
83             Ok(read) => Ok(read as usize),
84
85             // The special treatment of BrokenPipe is to deal with Windows
86             // pipe semantics, which yields this error when *reading* from
87             // a pipe after the other end has closed; we interpret that as
88             // EOF on the pipe.
89             Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(0),
90
91             Err(e) => Err(e),
92         }
93     }
94
95     pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
96         crate::io::default_read_vectored(|buf| self.read(buf), bufs)
97     }
98
99     #[inline]
100     pub fn is_read_vectored(&self) -> bool {
101         false
102     }
103
104     pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
105         let res =
106             unsafe { self.synchronous_read(buf.as_mut_ptr().cast(), buf.len(), Some(offset)) };
107
108         match res {
109             Ok(read) => Ok(read as usize),
110             Err(ref e) if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) => Ok(0),
111             Err(e) => Err(e),
112         }
113     }
114
115     pub fn read_buf(&self, mut cursor: BorrowedCursor<'_>) -> io::Result<()> {
116         let res =
117             unsafe { self.synchronous_read(cursor.as_mut().as_mut_ptr(), cursor.capacity(), None) };
118
119         match res {
120             Ok(read) => {
121                 // Safety: `read` bytes were written to the initialized portion of the buffer
122                 unsafe {
123                     cursor.advance(read as usize);
124                 }
125                 Ok(())
126             }
127
128             // The special treatment of BrokenPipe is to deal with Windows
129             // pipe semantics, which yields this error when *reading* from
130             // a pipe after the other end has closed; we interpret that as
131             // EOF on the pipe.
132             Err(ref e) if e.kind() == ErrorKind::BrokenPipe => Ok(()),
133
134             Err(e) => Err(e),
135         }
136     }
137
138     pub unsafe fn read_overlapped(
139         &self,
140         buf: &mut [u8],
141         overlapped: *mut c::OVERLAPPED,
142     ) -> io::Result<Option<usize>> {
143         let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD;
144         let mut amt = 0;
145         let res = cvt(c::ReadFile(
146             self.as_handle(),
147             buf.as_ptr() as c::LPVOID,
148             len,
149             &mut amt,
150             overlapped,
151         ));
152         match res {
153             Ok(_) => Ok(Some(amt as usize)),
154             Err(e) => {
155                 if e.raw_os_error() == Some(c::ERROR_IO_PENDING as i32) {
156                     Ok(None)
157                 } else if e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32) {
158                     Ok(Some(0))
159                 } else {
160                     Err(e)
161                 }
162             }
163         }
164     }
165
166     pub fn overlapped_result(
167         &self,
168         overlapped: *mut c::OVERLAPPED,
169         wait: bool,
170     ) -> io::Result<usize> {
171         unsafe {
172             let mut bytes = 0;
173             let wait = if wait { c::TRUE } else { c::FALSE };
174             let res =
175                 cvt(c::GetOverlappedResult(self.as_raw_handle(), overlapped, &mut bytes, wait));
176             match res {
177                 Ok(_) => Ok(bytes as usize),
178                 Err(e) => {
179                     if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32)
180                         || e.raw_os_error() == Some(c::ERROR_BROKEN_PIPE as i32)
181                     {
182                         Ok(0)
183                     } else {
184                         Err(e)
185                     }
186                 }
187             }
188         }
189     }
190
191     pub fn cancel_io(&self) -> io::Result<()> {
192         unsafe { cvt(c::CancelIo(self.as_raw_handle())).map(drop) }
193     }
194
195     pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
196         self.synchronous_write(&buf, None)
197     }
198
199     pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
200         crate::io::default_write_vectored(|buf| self.write(buf), bufs)
201     }
202
203     #[inline]
204     pub fn is_write_vectored(&self) -> bool {
205         false
206     }
207
208     pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
209         self.synchronous_write(&buf, Some(offset))
210     }
211
212     pub fn try_clone(&self) -> io::Result<Self> {
213         Ok(Self(self.0.try_clone()?))
214     }
215
216     pub fn duplicate(
217         &self,
218         access: c::DWORD,
219         inherit: bool,
220         options: c::DWORD,
221     ) -> io::Result<Self> {
222         Ok(Self(self.0.as_handle().duplicate(access, inherit, options)?))
223     }
224
225     /// Performs a synchronous read.
226     ///
227     /// If the handle is opened for asynchronous I/O then this abort the process.
228     /// See #81357.
229     ///
230     /// If `offset` is `None` then the current file position is used.
231     unsafe fn synchronous_read(
232         &self,
233         buf: *mut mem::MaybeUninit<u8>,
234         len: usize,
235         offset: Option<u64>,
236     ) -> io::Result<usize> {
237         let mut io_status = c::IO_STATUS_BLOCK::default();
238
239         // The length is clamped at u32::MAX.
240         let len = cmp::min(len, c::DWORD::MAX as usize) as c::DWORD;
241         let status = c::NtReadFile(
242             self.as_handle(),
243             ptr::null_mut(),
244             None,
245             ptr::null_mut(),
246             &mut io_status,
247             buf,
248             len,
249             offset.map(|n| n as _).as_ref(),
250             None,
251         );
252
253         let status = if status == c::STATUS_PENDING {
254             c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE);
255             io_status.status()
256         } else {
257             status
258         };
259         match status {
260             // If the operation has not completed then abort the process.
261             // Doing otherwise means that the buffer and stack may be written to
262             // after this function returns.
263             c::STATUS_PENDING => rtabort!("I/O error: operation failed to complete synchronously"),
264
265             // Return `Ok(0)` when there's nothing more to read.
266             c::STATUS_END_OF_FILE => Ok(0),
267
268             // Success!
269             status if c::nt_success(status) => Ok(io_status.Information),
270
271             status => {
272                 let error = c::RtlNtStatusToDosError(status);
273                 Err(io::Error::from_raw_os_error(error as _))
274             }
275         }
276     }
277
278     /// Performs a synchronous write.
279     ///
280     /// If the handle is opened for asynchronous I/O then this abort the process.
281     /// See #81357.
282     ///
283     /// If `offset` is `None` then the current file position is used.
284     fn synchronous_write(&self, buf: &[u8], offset: Option<u64>) -> io::Result<usize> {
285         let mut io_status = c::IO_STATUS_BLOCK::default();
286
287         // The length is clamped at u32::MAX.
288         let len = cmp::min(buf.len(), c::DWORD::MAX as usize) as c::DWORD;
289         let status = unsafe {
290             c::NtWriteFile(
291                 self.as_handle(),
292                 ptr::null_mut(),
293                 None,
294                 ptr::null_mut(),
295                 &mut io_status,
296                 buf.as_ptr(),
297                 len,
298                 offset.map(|n| n as _).as_ref(),
299                 None,
300             )
301         };
302         let status = if status == c::STATUS_PENDING {
303             unsafe { c::WaitForSingleObject(self.as_raw_handle(), c::INFINITE) };
304             io_status.status()
305         } else {
306             status
307         };
308         match status {
309             // If the operation has not completed then abort the process.
310             // Doing otherwise means that the buffer may be read and the stack
311             // written to after this function returns.
312             c::STATUS_PENDING => rtabort!("I/O error: operation failed to complete synchronously"),
313
314             // Success!
315             status if c::nt_success(status) => Ok(io_status.Information),
316
317             status => {
318                 let error = unsafe { c::RtlNtStatusToDosError(status) };
319                 Err(io::Error::from_raw_os_error(error as _))
320             }
321         }
322     }
323 }
324
325 impl<'a> Read for &'a Handle {
326     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
327         (**self).read(buf)
328     }
329
330     fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
331         (**self).read_vectored(bufs)
332     }
333 }