@@ -155,22 +155,7 @@ impl DirEntry {
155155    } 
156156
157157    pub  fn  metadata ( & self )  -> io:: Result < FileAttr >  { 
158-         Ok ( FileAttr  { 
159-             attributes :  self . data . dwFileAttributes , 
160-             creation_time :  self . data . ftCreationTime , 
161-             last_access_time :  self . data . ftLastAccessTime , 
162-             last_write_time :  self . data . ftLastWriteTime , 
163-             file_size :  ( ( self . data . nFileSizeHigh  as  u64 )  << 32 )  | ( self . data . nFileSizeLow  as  u64 ) , 
164-             reparse_tag :  if  self . data . dwFileAttributes  &  c:: FILE_ATTRIBUTE_REPARSE_POINT  != 0  { 
165-                 // reserved unless this is a reparse point 
166-                 self . data . dwReserved0 
167-             }  else  { 
168-                 0 
169-             } , 
170-             volume_serial_number :  None , 
171-             number_of_links :  None , 
172-             file_index :  None , 
173-         } ) 
158+         Ok ( self . data . into ( ) ) 
174159    } 
175160} 
176161
@@ -879,6 +864,26 @@ impl FileAttr {
879864        self . file_index 
880865    } 
881866} 
867+ impl  From < c:: WIN32_FIND_DATAW >  for  FileAttr  { 
868+     fn  from ( wfd :  c:: WIN32_FIND_DATAW )  -> Self  { 
869+         FileAttr  { 
870+             attributes :  wfd. dwFileAttributes , 
871+             creation_time :  wfd. ftCreationTime , 
872+             last_access_time :  wfd. ftLastAccessTime , 
873+             last_write_time :  wfd. ftLastWriteTime , 
874+             file_size :  ( ( wfd. nFileSizeHigh  as  u64 )  << 32 )  | ( wfd. nFileSizeLow  as  u64 ) , 
875+             reparse_tag :  if  wfd. dwFileAttributes  &  c:: FILE_ATTRIBUTE_REPARSE_POINT  != 0  { 
876+                 // reserved unless this is a reparse point 
877+                 wfd. dwReserved0 
878+             }  else  { 
879+                 0 
880+             } , 
881+             volume_serial_number :  None , 
882+             number_of_links :  None , 
883+             file_index :  None , 
884+         } 
885+     } 
886+ } 
882887
883888fn  to_u64 ( ft :  & c:: FILETIME )  -> u64  { 
884889    ( ft. dwLowDateTime  as  u64 )  | ( ( ft. dwHighDateTime  as  u64 )  << 32 ) 
@@ -1145,22 +1150,73 @@ pub fn link(_original: &Path, _link: &Path) -> io::Result<()> {
11451150} 
11461151
11471152pub  fn  stat ( path :  & Path )  -> io:: Result < FileAttr >  { 
1148-     let  mut  opts = OpenOptions :: new ( ) ; 
1149-     // No read or write permissions are necessary 
1150-     opts. access_mode ( 0 ) ; 
1151-     // This flag is so we can open directories too 
1152-     opts. custom_flags ( c:: FILE_FLAG_BACKUP_SEMANTICS ) ; 
1153-     let  file = File :: open ( path,  & opts) ?; 
1154-     file. file_attr ( ) 
1153+     metadata ( path,  ReparsePoint :: Follow ) 
11551154} 
11561155
11571156pub  fn  lstat ( path :  & Path )  -> io:: Result < FileAttr >  { 
1157+     metadata ( path,  ReparsePoint :: Open ) 
1158+ } 
1159+ 
1160+ #[ repr( u32 ) ]  
1161+ #[ derive( Clone ,  Copy ,  PartialEq ,  Eq ) ]  
1162+ enum  ReparsePoint  { 
1163+     Follow  = 0 , 
1164+     Open  = c:: FILE_FLAG_OPEN_REPARSE_POINT , 
1165+ } 
1166+ impl  ReparsePoint  { 
1167+     fn  as_flag ( self )  -> u32  { 
1168+         self  as  u32 
1169+     } 
1170+ } 
1171+ 
1172+ fn  metadata ( path :  & Path ,  reparse :  ReparsePoint )  -> io:: Result < FileAttr >  { 
11581173    let  mut  opts = OpenOptions :: new ( ) ; 
11591174    // No read or write permissions are necessary 
11601175    opts. access_mode ( 0 ) ; 
1161-     opts. custom_flags ( c:: FILE_FLAG_BACKUP_SEMANTICS  | c:: FILE_FLAG_OPEN_REPARSE_POINT ) ; 
1162-     let  file = File :: open ( path,  & opts) ?; 
1163-     file. file_attr ( ) 
1176+     opts. custom_flags ( c:: FILE_FLAG_BACKUP_SEMANTICS  | reparse. as_flag ( ) ) ; 
1177+ 
1178+     // Attempt to open the file normally. 
1179+     // If that fails with `ERROR_SHARING_VIOLATION` then retry using `FindFirstFileW`. 
1180+     // If the fallback fails for any reason we return the original error. 
1181+     match  File :: open ( path,  & opts)  { 
1182+         Ok ( file)  => file. file_attr ( ) , 
1183+         Err ( e)  if  e. raw_os_error ( )  == Some ( c:: ERROR_SHARING_VIOLATION  as  _ )  => { 
1184+             // `ERROR_SHARING_VIOLATION` will almost never be returned. 
1185+             // Usually if a file is locked you can still read some metadata. 
1186+             // However, there are special system files, such as 
1187+             // `C:\hiberfil.sys`, that are locked in a way that denies even that. 
1188+             unsafe  { 
1189+                 let  path = maybe_verbatim ( path) ?; 
1190+ 
1191+                 // `FindFirstFileW` accepts wildcard file names. 
1192+                 // Fortunately wildcards are not valid file names and 
1193+                 // `ERROR_SHARING_VIOLATION` means the file exists (but is locked) 
1194+                 // therefore it's safe to assume the file name given does not 
1195+                 // include wildcards. 
1196+                 let  mut  wfd = mem:: zeroed ( ) ; 
1197+                 let  handle = c:: FindFirstFileW ( path. as_ptr ( ) ,  & mut  wfd) ; 
1198+ 
1199+                 if  handle == c:: INVALID_HANDLE_VALUE  { 
1200+                     // This can fail if the user does not have read access to the 
1201+                     // directory. 
1202+                     Err ( e) 
1203+                 }  else  { 
1204+                     // We no longer need the find handle. 
1205+                     c:: FindClose ( handle) ; 
1206+ 
1207+                     // `FindFirstFileW` reads the cached file information from the 
1208+                     // directory. The downside is that this metadata may be outdated. 
1209+                     let  attrs = FileAttr :: from ( wfd) ; 
1210+                     if  reparse == ReparsePoint :: Follow  && attrs. file_type ( ) . is_symlink ( )  { 
1211+                         Err ( e) 
1212+                     }  else  { 
1213+                         Ok ( attrs) 
1214+                     } 
1215+                 } 
1216+             } 
1217+         } 
1218+         Err ( e)  => Err ( e) , 
1219+     } 
11641220} 
11651221
11661222pub  fn  set_perm ( p :  & Path ,  perm :  FilePermissions )  -> io:: Result < ( ) >  { 
0 commit comments