@@ -74,20 +74,10 @@ impl FromRawHandle for Handle {
74
74
75
75
impl Handle {
76
76
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 ) } ;
88
78
89
79
match res {
90
- Ok ( _ ) => Ok ( read as usize ) ,
80
+ Ok ( read ) => Ok ( read as usize ) ,
91
81
92
82
// The special treatment of BrokenPipe is to deal with Windows
93
83
// pipe semantics, which yields this error when *reading* from
@@ -109,42 +99,23 @@ impl Handle {
109
99
}
110
100
111
101
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
+
126
105
match res {
127
- Ok ( _ ) => Ok ( read as usize ) ,
106
+ Ok ( read ) => Ok ( read as usize ) ,
128
107
Err ( ref e) if e. raw_os_error ( ) == Some ( c:: ERROR_HANDLE_EOF as i32 ) => Ok ( 0 ) ,
129
108
Err ( e) => Err ( e) ,
130
109
}
131
110
}
132
111
133
112
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
+ } ;
145
116
146
117
match res {
147
- Ok ( _ ) => {
118
+ Ok ( read ) => {
148
119
// Safety: `read` bytes were written to the initialized portion of the buffer
149
120
unsafe {
150
121
buf. assume_init ( read as usize ) ;
@@ -221,18 +192,7 @@ impl Handle {
221
192
}
222
193
223
194
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
+ self . synchronous_write ( & buf, None )
236
196
}
237
197
238
198
pub fn write_vectored ( & self , bufs : & [ IoSlice < ' _ > ] ) -> io:: Result < usize > {
@@ -245,21 +205,7 @@ impl Handle {
245
205
}
246
206
247
207
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
+ self . synchronous_write ( & buf, Some ( offset) )
263
209
}
264
210
265
211
pub fn try_clone ( & self ) -> io:: Result < Self > {
@@ -274,6 +220,97 @@ impl Handle {
274
220
) -> io:: Result < Self > {
275
221
Ok ( Self ( self . 0 . duplicate ( access, inherit, options) ?) )
276
222
}
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
+ 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 = unsafe {
285
+ c:: NtWriteFile (
286
+ self . as_handle ( ) ,
287
+ ptr:: null_mut ( ) ,
288
+ None ,
289
+ ptr:: null_mut ( ) ,
290
+ & mut io_status,
291
+ buf. as_ptr ( ) ,
292
+ len,
293
+ offset. map ( |n| n as _ ) . as_ref ( ) ,
294
+ None ,
295
+ )
296
+ } ;
297
+ match status {
298
+ // If the operation has not completed then abort the process.
299
+ // Doing otherwise means that the buffer may be read and the stack
300
+ // written to after this function returns.
301
+ c:: STATUS_PENDING => {
302
+ rtabort ! ( "I/O error: operation failed to complete synchronously" ) ;
303
+ }
304
+
305
+ // Success!
306
+ status if c:: nt_success ( status) => Ok ( io_status. Information ) ,
307
+
308
+ status => {
309
+ let error = unsafe { c:: RtlNtStatusToDosError ( status) } ;
310
+ Err ( io:: Error :: from_raw_os_error ( error as _ ) )
311
+ }
312
+ }
313
+ }
277
314
}
278
315
279
316
impl < ' a > Read for & ' a Handle {
0 commit comments