@@ -74,20 +74,10 @@ impl FromRawHandle for Handle {
7474
7575impl Handle {
7676 pub fn read ( & self , buf : & mut [ u8 ] ) -> io:: Result < usize > {
77- let mut read = 0 ;
78- let len = cmp:: min ( buf. len ( ) , <c:: DWORD >:: MAX as usize ) as c:: DWORD ;
79- let res = cvt ( unsafe {
80- c:: ReadFile (
81- self . as_handle ( ) ,
82- buf. as_mut_ptr ( ) as c:: LPVOID ,
83- len,
84- & mut read,
85- ptr:: null_mut ( ) ,
86- )
87- } ) ;
77+ let res = unsafe { self . synchronous_read ( buf. as_mut_ptr ( ) . cast ( ) , buf. len ( ) , None ) } ;
8878
8979 match res {
90- Ok ( _ ) => Ok ( read as usize ) ,
80+ Ok ( read ) => Ok ( read as usize ) ,
9181
9282 // The special treatment of BrokenPipe is to deal with Windows
9383 // pipe semantics, which yields this error when *reading* from
@@ -109,42 +99,23 @@ impl Handle {
10999 }
110100
111101 pub fn read_at ( & self , buf : & mut [ u8 ] , offset : u64 ) -> io:: Result < usize > {
112- let mut read = 0 ;
113- let len = cmp:: min ( buf. len ( ) , <c:: DWORD >:: MAX as usize ) as c:: DWORD ;
114- let res = unsafe {
115- let mut overlapped: c:: OVERLAPPED = mem:: zeroed ( ) ;
116- overlapped. Offset = offset as u32 ;
117- overlapped. OffsetHigh = ( offset >> 32 ) as u32 ;
118- cvt ( c:: ReadFile (
119- self . as_handle ( ) ,
120- buf. as_mut_ptr ( ) as c:: LPVOID ,
121- len,
122- & mut read,
123- & mut overlapped,
124- ) )
125- } ;
102+ let res =
103+ unsafe { self . synchronous_read ( buf. as_mut_ptr ( ) . cast ( ) , buf. len ( ) , Some ( offset) ) } ;
104+
126105 match res {
127- Ok ( _ ) => Ok ( read as usize ) ,
106+ Ok ( read ) => Ok ( read as usize ) ,
128107 Err ( ref e) if e. raw_os_error ( ) == Some ( c:: ERROR_HANDLE_EOF as i32 ) => Ok ( 0 ) ,
129108 Err ( e) => Err ( e) ,
130109 }
131110 }
132111
133112 pub fn read_buf ( & self , buf : & mut ReadBuf < ' _ > ) -> io:: Result < ( ) > {
134- let mut read = 0 ;
135- let len = cmp:: min ( buf. remaining ( ) , <c:: DWORD >:: MAX as usize ) as c:: DWORD ;
136- let res = cvt ( unsafe {
137- c:: ReadFile (
138- self . as_handle ( ) ,
139- buf. unfilled_mut ( ) . as_mut_ptr ( ) as c:: LPVOID ,
140- len,
141- & mut read,
142- ptr:: null_mut ( ) ,
143- )
144- } ) ;
113+ let res = unsafe {
114+ self . synchronous_read ( buf. unfilled_mut ( ) . as_mut_ptr ( ) , buf. remaining ( ) , None )
115+ } ;
145116
146117 match res {
147- Ok ( _ ) => {
118+ Ok ( read ) => {
148119 // Safety: `read` bytes were written to the initialized portion of the buffer
149120 unsafe {
150121 buf. assume_init ( read as usize ) ;
@@ -221,18 +192,7 @@ impl Handle {
221192 }
222193
223194 pub fn write ( & self , buf : & [ u8 ] ) -> io:: Result < usize > {
224- let mut amt = 0 ;
225- let len = cmp:: min ( buf. len ( ) , <c:: DWORD >:: MAX as usize ) as c:: DWORD ;
226- cvt ( unsafe {
227- c:: WriteFile (
228- self . as_handle ( ) ,
229- buf. as_ptr ( ) as c:: LPVOID ,
230- len,
231- & mut amt,
232- ptr:: null_mut ( ) ,
233- )
234- } ) ?;
235- Ok ( amt as usize )
195+ unsafe { self . synchronous_write ( & buf, None ) }
236196 }
237197
238198 pub fn write_vectored ( & self , bufs : & [ IoSlice < ' _ > ] ) -> io:: Result < usize > {
@@ -245,21 +205,7 @@ impl Handle {
245205 }
246206
247207 pub fn write_at ( & self , buf : & [ u8 ] , offset : u64 ) -> io:: Result < usize > {
248- let mut written = 0 ;
249- let len = cmp:: min ( buf. len ( ) , <c:: DWORD >:: MAX as usize ) as c:: DWORD ;
250- unsafe {
251- let mut overlapped: c:: OVERLAPPED = mem:: zeroed ( ) ;
252- overlapped. Offset = offset as u32 ;
253- overlapped. OffsetHigh = ( offset >> 32 ) as u32 ;
254- cvt ( c:: WriteFile (
255- self . as_handle ( ) ,
256- buf. as_ptr ( ) as c:: LPVOID ,
257- len,
258- & mut written,
259- & mut overlapped,
260- ) ) ?;
261- }
262- Ok ( written as usize )
208+ unsafe { self . synchronous_write ( & buf, Some ( offset) ) }
263209 }
264210
265211 pub fn try_clone ( & self ) -> io:: Result < Self > {
@@ -274,6 +220,96 @@ impl Handle {
274220 ) -> io:: Result < Self > {
275221 Ok ( Self ( self . 0 . duplicate ( access, inherit, options) ?) )
276222 }
223+
224+ /// Performs a synchronous read.
225+ ///
226+ /// If the handle is opened for asynchronous I/O then this abort the process.
227+ /// See #81357.
228+ ///
229+ /// If `offset` is `None` then the current file position is used.
230+ unsafe fn synchronous_read (
231+ & self ,
232+ buf : * mut mem:: MaybeUninit < u8 > ,
233+ len : usize ,
234+ offset : Option < u64 > ,
235+ ) -> io:: Result < usize > {
236+ let mut io_status = c:: IO_STATUS_BLOCK :: default ( ) ;
237+
238+ // The length is clamped at u32::MAX.
239+ let len = cmp:: min ( len, c:: DWORD :: MAX as usize ) as c:: DWORD ;
240+ let status = c:: NtReadFile (
241+ self . as_handle ( ) ,
242+ ptr:: null_mut ( ) ,
243+ None ,
244+ ptr:: null_mut ( ) ,
245+ & mut io_status,
246+ buf,
247+ len,
248+ offset. map ( |n| n as _ ) . as_ref ( ) ,
249+ None ,
250+ ) ;
251+ match status {
252+ // If the operation has not completed then abort the process.
253+ // Doing otherwise means that the buffer and stack may be written to
254+ // after this function returns.
255+ c:: STATUS_PENDING => {
256+ eprintln ! ( "I/O error: operation failed to complete synchronously" ) ;
257+ crate :: process:: abort ( ) ;
258+ }
259+
260+ // Return `Ok(0)` when there's nothing more to read.
261+ c:: STATUS_END_OF_FILE => Ok ( 0 ) ,
262+
263+ // Success!
264+ status if c:: nt_success ( status) => Ok ( io_status. Information ) ,
265+
266+ status => {
267+ let error = c:: RtlNtStatusToDosError ( status) ;
268+ Err ( io:: Error :: from_raw_os_error ( error as _ ) )
269+ }
270+ }
271+ }
272+
273+ /// Performs a synchronous write.
274+ ///
275+ /// If the handle is opened for asynchronous I/O then this abort the process.
276+ /// See #81357.
277+ ///
278+ /// If `offset` is `None` then the current file position is used.
279+ unsafe fn synchronous_write ( & self , buf : & [ u8 ] , offset : Option < u64 > ) -> io:: Result < usize > {
280+ let mut io_status = c:: IO_STATUS_BLOCK :: default ( ) ;
281+
282+ // The length is clamped at u32::MAX.
283+ let len = cmp:: min ( buf. len ( ) , c:: DWORD :: MAX as usize ) as c:: DWORD ;
284+ let status = c:: NtWriteFile (
285+ self . as_handle ( ) ,
286+ ptr:: null_mut ( ) ,
287+ None ,
288+ ptr:: null_mut ( ) ,
289+ & mut io_status,
290+ buf. as_ptr ( ) ,
291+ len,
292+ offset. map ( |n| n as _ ) . as_ref ( ) ,
293+ None ,
294+ ) ;
295+ match status {
296+ // If the operation has not completed then abort the process.
297+ // Doing otherwise means that the buffer maybe read and the stack
298+ // written to after this function returns.
299+ c:: STATUS_PENDING => {
300+ eprintln ! ( "I/O error: operation failed to complete synchronously" ) ;
301+ crate :: process:: abort ( ) ;
302+ }
303+
304+ // Success!
305+ status if c:: nt_success ( status) => Ok ( io_status. Information ) ,
306+
307+ status => {
308+ let error = c:: RtlNtStatusToDosError ( status) ;
309+ Err ( io:: Error :: from_raw_os_error ( error as _ ) )
310+ }
311+ }
312+ }
277313}
278314
279315impl < ' a > Read for & ' a Handle {
0 commit comments