@@ -1418,7 +1418,10 @@ struct StableFileIdentity {
14181418}
14191419
14201420#[ cfg( unix) ]
1421- fn stable_file_identity ( metadata : & std:: fs:: Metadata ) -> Result < StableFileIdentity , ( ) > {
1421+ fn stable_file_identity (
1422+ _path : & Path ,
1423+ metadata : & std:: fs:: Metadata ,
1424+ ) -> Result < StableFileIdentity , ( ) > {
14221425 use std:: os:: unix:: fs:: MetadataExt ;
14231426 Ok ( StableFileIdentity {
14241427 device : metadata. dev ( ) ,
@@ -1431,20 +1434,82 @@ fn stable_file_identity(metadata: &std::fs::Metadata) -> Result<StableFileIdenti
14311434}
14321435
14331436#[ cfg( windows) ]
1434- fn stable_file_identity ( metadata : & std:: fs:: Metadata ) -> Result < StableFileIdentity , ( ) > {
1435- use std:: os:: windows:: fs:: MetadataExt ;
1437+ fn stable_file_identity (
1438+ path : & Path ,
1439+ _metadata : & std:: fs:: Metadata ,
1440+ ) -> Result < StableFileIdentity , ( ) > {
1441+ use std:: ffi:: c_void;
1442+ use std:: mem:: MaybeUninit ;
1443+ use std:: os:: windows:: fs:: OpenOptionsExt ;
1444+ use std:: os:: windows:: io:: AsRawHandle ;
1445+
1446+ #[ repr( C ) ]
1447+ struct FileTime {
1448+ low : u32 ,
1449+ high : u32 ,
1450+ }
1451+
1452+ #[ repr( C ) ]
1453+ struct ByHandleFileInformation {
1454+ _file_attributes : u32 ,
1455+ _creation_time : FileTime ,
1456+ _last_access_time : FileTime ,
1457+ last_write_time : FileTime ,
1458+ volume_serial_number : u32 ,
1459+ file_size_high : u32 ,
1460+ file_size_low : u32 ,
1461+ number_of_links : u32 ,
1462+ file_index_high : u32 ,
1463+ file_index_low : u32 ,
1464+ }
1465+
1466+ #[ link( name = "Kernel32" ) ]
1467+ unsafe extern "system" {
1468+ fn GetFileInformationByHandle (
1469+ file : * mut c_void ,
1470+ information : * mut ByHandleFileInformation ,
1471+ ) -> i32 ;
1472+ }
1473+
1474+ const FILE_FLAG_BACKUP_SEMANTICS : u32 = 0x0200_0000 ;
1475+ let file = std:: fs:: OpenOptions :: new ( )
1476+ . read ( true )
1477+ . custom_flags ( FILE_FLAG_BACKUP_SEMANTICS )
1478+ . open ( path)
1479+ . map_err ( |_| ( ) ) ?;
1480+ let mut information = MaybeUninit :: < ByHandleFileInformation > :: uninit ( ) ;
1481+ // SAFETY: `file` keeps a valid owned handle alive for the call and the
1482+ // Win32 function initializes the complete output structure on success.
1483+ let succeeded = unsafe {
1484+ GetFileInformationByHandle (
1485+ file. as_raw_handle ( ) . cast :: < c_void > ( ) ,
1486+ information. as_mut_ptr ( ) ,
1487+ )
1488+ } ;
1489+ if succeeded == 0 {
1490+ return Err ( ( ) ) ;
1491+ }
1492+ // SAFETY: the successful Win32 call above initialized every field.
1493+ let information = unsafe { information. assume_init ( ) } ;
1494+ let last_write = ( ( information. last_write_time . high as u64 ) << 32 )
1495+ | information. last_write_time . low as u64 ;
14361496 Ok ( StableFileIdentity {
1437- device : metadata. volume_serial_number ( ) . ok_or ( ( ) ) ? as u64 ,
1438- inode : metadata. file_index ( ) . ok_or ( ( ) ) ?,
1439- links : metadata. number_of_links ( ) . ok_or ( ( ) ) ? as u64 ,
1440- length : metadata. file_size ( ) ,
1441- changed_seconds : ( metadata. last_write_time ( ) / 10_000_000 ) as i64 ,
1442- changed_nanos : ( ( metadata. last_write_time ( ) % 10_000_000 ) * 100 ) as i64 ,
1497+ device : information. volume_serial_number as u64 ,
1498+ inode : ( ( information. file_index_high as u64 ) << 32 )
1499+ | information. file_index_low as u64 ,
1500+ links : information. number_of_links as u64 ,
1501+ length : ( ( information. file_size_high as u64 ) << 32 )
1502+ | information. file_size_low as u64 ,
1503+ changed_seconds : ( last_write / 10_000_000 ) as i64 ,
1504+ changed_nanos : ( ( last_write % 10_000_000 ) * 100 ) as i64 ,
14431505 } )
14441506}
14451507
14461508#[ cfg ( not ( any ( unix, windows) ) ) ]
1447- fn stable_file_identity ( _metadata : & std:: fs:: Metadata ) -> Result < StableFileIdentity , ( ) > {
1509+ fn stable_file_identity (
1510+ _path : & Path ,
1511+ _metadata : & std:: fs:: Metadata ,
1512+ ) -> Result < StableFileIdentity , ( ) > {
14481513 Err ( ( ) )
14491514}
14501515
@@ -1475,7 +1540,7 @@ fn read_stable_regular(
14751540 ) ,
14761541 ) ) ;
14771542 }
1478- let before_identity = stable_file_identity ( & before) . map_err ( |_| {
1543+ let before_identity = stable_file_identity ( path , & before) . map_err ( |_| {
14791544 ParentCorpusError :: at (
14801545 ParentCorpusErrorCode :: UnsupportedFilesystem ,
14811546 path,
@@ -1550,7 +1615,7 @@ fn read_stable_regular(
15501615 ) ,
15511616 )
15521617 } ) ?;
1553- let after_identity = stable_file_identity ( & after) . map_err ( |_| {
1618+ let after_identity = stable_file_identity ( path , & after) . map_err ( |_| {
15541619 ParentCorpusError :: at (
15551620 ParentCorpusErrorCode :: UnsupportedFilesystem ,
15561621 path,
@@ -1616,7 +1681,7 @@ fn directory_device(path: &Path) -> Result<u64, ParentCorpusError> {
16161681 ) ,
16171682 ) ) ;
16181683 }
1619- stable_file_identity ( & metadata)
1684+ stable_file_identity ( path , & metadata)
16201685 . map ( |identity| identity. device )
16211686 . map_err ( |_| {
16221687 ParentCorpusError :: at (
@@ -1652,7 +1717,7 @@ fn snapshot_directory_v2(
16521717 ) ,
16531718 )
16541719 } ) ?;
1655- let directory_identity = stable_file_identity ( & directory_before) . map_err ( |_| {
1720+ let directory_identity = stable_file_identity ( directory , & directory_before) . map_err ( |_| {
16561721 ParentCorpusError :: at (
16571722 ParentCorpusErrorCode :: UnsupportedFilesystem ,
16581723 directory,
@@ -1792,7 +1857,7 @@ fn snapshot_directory_v2(
17921857 ) ,
17931858 )
17941859 } ) ?;
1795- let after_identity = stable_file_identity ( & directory_after) . map_err ( |_| {
1860+ let after_identity = stable_file_identity ( directory , & directory_after) . map_err ( |_| {
17961861 ParentCorpusError :: at (
17971862 ParentCorpusErrorCode :: UnsupportedFilesystem ,
17981863 directory,
0 commit comments