@@ -21,7 +21,7 @@ use windows_sys::{
21
21
Foundation :: {
22
22
CloseHandle , GetLastError , ERROR_ACCESS_DENIED , ERROR_HANDLE_EOF , ERROR_IO_INCOMPLETE ,
23
23
ERROR_IO_PENDING , ERROR_NOT_FOUND , ERROR_NO_DATA , ERROR_PIPE_CONNECTED ,
24
- ERROR_SHARING_VIOLATION ,
24
+ ERROR_SHARING_VIOLATION , FILETIME ,
25
25
} ,
26
26
Networking :: WinSock :: {
27
27
closesocket, setsockopt, shutdown, socklen_t, WSAIoctl , WSARecv , WSARecvFrom , WSASend ,
@@ -207,20 +207,85 @@ impl OpCode for CloseFile {
207
207
}
208
208
}
209
209
210
+ /// A mixture of [`BY_HANDLE_FILE_INFORMATION`], [`FILE_ATTRIBUTE_TAG_INFO`] and
211
+ /// [`WIN32_FIND_DATAW`]. The field names follows Hungarian case, to make it
212
+ /// look like Windows API.
213
+ #[ derive( Default , Clone ) ]
214
+ #[ allow( non_snake_case, missing_docs) ]
215
+ pub struct FileMetadata {
216
+ pub dwFileAttributes : u32 ,
217
+ pub ftCreationTime : u64 ,
218
+ pub ftLastAccessTime : u64 ,
219
+ pub ftLastWriteTime : u64 ,
220
+ pub nFileSize : u64 ,
221
+ pub dwReparseTag : u32 ,
222
+ pub dwVolumeSerialNumber : Option < u32 > ,
223
+ pub nNumberOfLinks : Option < u32 > ,
224
+ pub nFileIndex : Option < u64 > ,
225
+ }
226
+
227
+ impl FileMetadata {
228
+ fn is_reparse_point ( & self ) -> bool {
229
+ self . dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT != 0
230
+ }
231
+ }
232
+
233
+ const fn create_u64 ( high : u32 , low : u32 ) -> u64 {
234
+ ( ( high as u64 ) << 32 ) | ( low as u64 )
235
+ }
236
+
237
+ const fn filetime_u64 ( t : FILETIME ) -> u64 {
238
+ create_u64 ( t. dwHighDateTime , t. dwLowDateTime )
239
+ }
240
+
241
+ impl From < BY_HANDLE_FILE_INFORMATION > for FileMetadata {
242
+ fn from ( value : BY_HANDLE_FILE_INFORMATION ) -> Self {
243
+ Self {
244
+ dwFileAttributes : value. dwFileAttributes ,
245
+ ftCreationTime : filetime_u64 ( value. ftCreationTime ) ,
246
+ ftLastAccessTime : filetime_u64 ( value. ftLastAccessTime ) ,
247
+ ftLastWriteTime : filetime_u64 ( value. ftLastWriteTime ) ,
248
+ nFileSize : create_u64 ( value. nFileSizeHigh , value. nFileSizeLow ) ,
249
+ dwReparseTag : 0 ,
250
+ dwVolumeSerialNumber : Some ( value. dwVolumeSerialNumber ) ,
251
+ nNumberOfLinks : Some ( value. nNumberOfLinks ) ,
252
+ nFileIndex : Some ( create_u64 ( value. nFileIndexHigh , value. nFileIndexLow ) ) ,
253
+ }
254
+ }
255
+ }
256
+
257
+ impl From < WIN32_FIND_DATAW > for FileMetadata {
258
+ fn from ( value : WIN32_FIND_DATAW ) -> Self {
259
+ let mut this = Self {
260
+ dwFileAttributes : value. dwFileAttributes ,
261
+ ftCreationTime : filetime_u64 ( value. ftCreationTime ) ,
262
+ ftLastAccessTime : filetime_u64 ( value. ftLastAccessTime ) ,
263
+ ftLastWriteTime : filetime_u64 ( value. ftLastWriteTime ) ,
264
+ nFileSize : create_u64 ( value. nFileSizeHigh , value. nFileSizeLow ) ,
265
+ dwReparseTag : 0 ,
266
+ dwVolumeSerialNumber : None ,
267
+ nNumberOfLinks : None ,
268
+ nFileIndex : None ,
269
+ } ;
270
+ if this. is_reparse_point ( ) {
271
+ this. dwReparseTag = value. dwReserved0 ;
272
+ }
273
+ this
274
+ }
275
+ }
276
+
210
277
/// Get metadata of an opened file.
211
278
pub struct FileStat {
212
279
pub ( crate ) fd : RawFd ,
213
- pub ( crate ) stat : BY_HANDLE_FILE_INFORMATION ,
214
- pub ( crate ) reparse_tag : u32 ,
280
+ pub ( crate ) stat : FileMetadata ,
215
281
}
216
282
217
283
impl FileStat {
218
284
/// Create [`FileStat`].
219
285
pub fn new ( fd : RawFd ) -> Self {
220
286
Self {
221
287
fd,
222
- stat : unsafe { std:: mem:: zeroed ( ) } ,
223
- reparse_tag : 0 ,
288
+ stat : Default :: default ( ) ,
224
289
}
225
290
}
226
291
}
@@ -231,11 +296,10 @@ impl OpCode for FileStat {
231
296
}
232
297
233
298
unsafe fn operate ( mut self : Pin < & mut Self > , _optr : * mut OVERLAPPED ) -> Poll < io:: Result < usize > > {
234
- syscall ! (
235
- BOOL ,
236
- GetFileInformationByHandle ( self . fd as _, & mut self . stat)
237
- ) ?;
238
- if self . stat . dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT != 0 {
299
+ let mut stat = unsafe { std:: mem:: zeroed ( ) } ;
300
+ syscall ! ( BOOL , GetFileInformationByHandle ( self . fd as _, & mut stat) ) ?;
301
+ self . stat = stat. into ( ) ;
302
+ if self . stat . is_reparse_point ( ) {
239
303
let mut tag: FILE_ATTRIBUTE_TAG_INFO = std:: mem:: zeroed ( ) ;
240
304
syscall ! (
241
305
BOOL ,
@@ -246,9 +310,8 @@ impl OpCode for FileStat {
246
310
std:: mem:: size_of:: <FILE_ATTRIBUTE_TAG_INFO >( ) as _
247
311
)
248
312
) ?;
249
- if tag. FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT != 0 {
250
- self . reparse_tag = tag. ReparseTag ;
251
- }
313
+ debug_assert_eq ! ( self . stat. dwFileAttributes, tag. FileAttributes ) ;
314
+ self . stat . dwReparseTag = tag. ReparseTag ;
252
315
}
253
316
Poll :: Ready ( Ok ( 0 ) )
254
317
}
@@ -259,20 +322,18 @@ impl OpCode for FileStat {
259
322
}
260
323
261
324
impl IntoInner for FileStat {
262
- type Inner = ( BY_HANDLE_FILE_INFORMATION , u32 ) ;
325
+ type Inner = FileMetadata ;
263
326
264
327
fn into_inner ( self ) -> Self :: Inner {
265
- ( self . stat , self . reparse_tag )
328
+ self . stat
266
329
}
267
330
}
268
331
269
332
/// Get metadata from path.
270
333
pub struct PathStat {
271
334
pub ( crate ) path : U16CString ,
272
335
pub ( crate ) follow_symlink : bool ,
273
- pub ( crate ) stat : BY_HANDLE_FILE_INFORMATION ,
274
- pub ( crate ) reparse_tag : u32 ,
275
- pub ( crate ) handle_info : bool ,
336
+ pub ( crate ) stat : FileMetadata ,
276
337
}
277
338
278
339
impl PathStat {
@@ -281,19 +342,11 @@ impl PathStat {
281
342
Self {
282
343
path,
283
344
follow_symlink,
284
- stat : unsafe { std:: mem:: zeroed ( ) } ,
285
- reparse_tag : 0 ,
286
- handle_info : true ,
345
+ stat : Default :: default ( ) ,
287
346
}
288
347
}
289
- }
290
-
291
- impl OpCode for PathStat {
292
- fn is_overlapped ( & self ) -> bool {
293
- false
294
- }
295
348
296
- unsafe fn operate ( mut self : Pin < & mut Self > , optr : * mut OVERLAPPED ) -> Poll < io:: Result < usize > > {
349
+ unsafe fn open_and_stat ( & self , optr : * mut OVERLAPPED ) -> io:: Result < FileMetadata > {
297
350
let mut flags = FILE_FLAG_BACKUP_SEMANTICS ;
298
351
if !self . follow_symlink {
299
352
flags |= FILE_FLAG_OPEN_REPARSE_POINT ;
@@ -313,12 +366,24 @@ impl OpCode for PathStat {
313
366
let handle = OwnedHandle :: from_raw_handle ( handle as _ ) ;
314
367
let mut op = FileStat :: new ( handle. as_raw_handle ( ) ) ;
315
368
let op_pin = std:: pin:: Pin :: new ( & mut op) ;
316
- let res = match std:: task:: ready!( op_pin. operate( optr) ) {
317
- Ok ( _) => {
318
- let ( stat, reparse_tag) = op. into_inner ( ) ;
369
+ let res = op_pin. operate ( optr) ;
370
+ if let Poll :: Ready ( res) = res {
371
+ res. map ( |_| op. into_inner ( ) )
372
+ } else {
373
+ unreachable ! ( "FileStat could not return Poll::Pending" )
374
+ }
375
+ }
376
+ }
377
+
378
+ impl OpCode for PathStat {
379
+ fn is_overlapped ( & self ) -> bool {
380
+ false
381
+ }
382
+
383
+ unsafe fn operate ( mut self : Pin < & mut Self > , optr : * mut OVERLAPPED ) -> Poll < io:: Result < usize > > {
384
+ let res = match self . open_and_stat ( optr) {
385
+ Ok ( stat) => {
319
386
self . stat = stat;
320
- self . handle_info = true ;
321
- self . reparse_tag = reparse_tag;
322
387
Ok ( 0 )
323
388
}
324
389
Err ( e)
@@ -331,19 +396,9 @@ impl OpCode for PathStat {
331
396
let mut wfd: WIN32_FIND_DATAW = std:: mem:: zeroed ( ) ;
332
397
let handle = syscall ! ( HANDLE , FindFirstFileW ( self . path. as_ptr( ) , & mut wfd) ) ?;
333
398
FindClose ( handle) ;
334
- self . stat = BY_HANDLE_FILE_INFORMATION {
335
- dwFileAttributes : wfd. dwFileAttributes ,
336
- ftCreationTime : wfd. ftCreationTime ,
337
- ftLastAccessTime : wfd. ftLastAccessTime ,
338
- ftLastWriteTime : wfd. ftLastWriteTime ,
339
- nFileSizeHigh : wfd. nFileSizeHigh ,
340
- nFileSizeLow : wfd. nFileSizeLow ,
341
- ..self . stat
342
- } ;
343
- self . handle_info = false ;
344
- let is_reparse = self . stat . dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT != 0 ;
345
- self . reparse_tag = if is_reparse { wfd. dwReserved0 } else { 0 } ;
346
- let surrogate = self . reparse_tag & 0x20000000 != 0 ;
399
+ self . stat = wfd. into ( ) ;
400
+ let is_reparse = self . stat . is_reparse_point ( ) ;
401
+ let surrogate = self . stat . dwReparseTag & 0x20000000 != 0 ;
347
402
if self . follow_symlink && is_reparse && surrogate {
348
403
Err ( e)
349
404
} else {
@@ -360,14 +415,11 @@ impl OpCode for PathStat {
360
415
}
361
416
}
362
417
363
- /// Now all values of [`BY_HANDLE_FILE_INFORMATION`] is valid. If the last
364
- /// [`bool`] element is `false`, only the fields that are contained in
365
- /// [`WIN32_FIND_DATAW`] are valid.
366
418
impl IntoInner for PathStat {
367
- type Inner = ( BY_HANDLE_FILE_INFORMATION , u32 , bool ) ;
419
+ type Inner = FileMetadata ;
368
420
369
421
fn into_inner ( self ) -> Self :: Inner {
370
- ( self . stat , self . reparse_tag , self . handle_info )
422
+ self . stat
371
423
}
372
424
}
373
425
0 commit comments