@@ -1588,7 +1588,98 @@ fn sparsify_snapshot(path: &Path) -> Result<()> {
15881588 Ok ( ( ) )
15891589}
15901590
1591- #[ cfg( not( target_os = "linux" ) ) ]
1591+ /// Windows equivalent: mark the file sparse with FSCTL_SET_SPARSE, then
1592+ /// punch zero ranges with FSCTL_SET_ZERO_DATA.
1593+ #[ cfg( target_os = "windows" ) ]
1594+ fn sparsify_snapshot ( path : & Path ) -> Result < ( ) > {
1595+ use std:: os:: windows:: io:: AsRawHandle ;
1596+ use windows_sys:: Win32 :: Storage :: FileSystem :: { FSCTL_SET_SPARSE , FSCTL_SET_ZERO_DATA } ;
1597+ use windows_sys:: Win32 :: System :: IO :: DeviceIoControl ;
1598+
1599+ let file = std:: fs:: OpenOptions :: new ( )
1600+ . read ( true )
1601+ . write ( true )
1602+ . open ( path) ?;
1603+ let len = file. metadata ( ) ?. len ( ) ;
1604+ let handle = file. as_raw_handle ( ) as isize ;
1605+
1606+ // Mark file as sparse.
1607+ let ok = unsafe {
1608+ DeviceIoControl (
1609+ handle,
1610+ FSCTL_SET_SPARSE ,
1611+ std:: ptr:: null ( ) ,
1612+ 0 ,
1613+ std:: ptr:: null_mut ( ) ,
1614+ 0 ,
1615+ std:: ptr:: null_mut ( ) ,
1616+ std:: ptr:: null_mut ( ) ,
1617+ )
1618+ } ;
1619+ if ok == 0 {
1620+ return Ok ( ( ) ) ;
1621+ }
1622+
1623+ let mmap = unsafe { memmap2:: Mmap :: map ( & file) ? } ;
1624+
1625+ const PAGE : usize = 4096 ;
1626+ const HEADER : usize = PAGE ;
1627+ let zero_page = [ 0u8 ; PAGE ] ;
1628+
1629+ // Coalesce contiguous zero pages into ranges for fewer syscalls.
1630+ let mut punched = 0u64 ;
1631+ let mut offset = HEADER ;
1632+ while offset + PAGE <= len as usize {
1633+ if mmap[ offset..offset + PAGE ] != zero_page {
1634+ offset += PAGE ;
1635+ continue ;
1636+ }
1637+ let range_start = offset;
1638+ while offset + PAGE <= len as usize && mmap[ offset..offset + PAGE ] == zero_page {
1639+ offset += PAGE ;
1640+ }
1641+ let range_end = offset;
1642+
1643+ #[ repr( C ) ]
1644+ struct FileZeroDataInformation {
1645+ file_offset : i64 ,
1646+ beyond_final_zero : i64 ,
1647+ }
1648+
1649+ let info = FileZeroDataInformation {
1650+ file_offset : range_start as i64 ,
1651+ beyond_final_zero : range_end as i64 ,
1652+ } ;
1653+ let ok = unsafe {
1654+ DeviceIoControl (
1655+ handle,
1656+ FSCTL_SET_ZERO_DATA ,
1657+ & info as * const _ as * const _ ,
1658+ std:: mem:: size_of :: < FileZeroDataInformation > ( ) as u32 ,
1659+ std:: ptr:: null_mut ( ) ,
1660+ 0 ,
1661+ std:: ptr:: null_mut ( ) ,
1662+ std:: ptr:: null_mut ( ) ,
1663+ )
1664+ } ;
1665+ if ok != 0 {
1666+ punched += ( range_end - range_start) as u64 / PAGE as u64 ;
1667+ }
1668+ }
1669+ drop ( mmap) ;
1670+
1671+ if punched > 0 {
1672+ eprintln ! (
1673+ " sparsified: punched {} zero pages ({} MiB saved on disk)" ,
1674+ punched,
1675+ punched * 4 / 1024
1676+ ) ;
1677+ }
1678+
1679+ Ok ( ( ) )
1680+ }
1681+
1682+ #[ cfg( not( any( target_os = "linux" , target_os = "windows" ) ) ) ]
15921683fn sparsify_snapshot ( _path : & Path ) -> Result < ( ) > {
15931684 Ok ( ( ) )
15941685}
0 commit comments