@@ -234,22 +234,16 @@ struct UnflushedSnapshotInner {
234234
235235impl UnflushedSnapshotInner {
236236 fn sync_all ( self ) -> Result < SnapshotDirPath , SnapshotError > {
237- fn fsync ( path : & Path ) -> io:: Result < ( ) > {
238- File :: open ( path)
239- . and_then ( |fd| fd. sync_all ( ) )
240- . map_err ( |e| io:: Error :: new ( e. kind ( ) , format ! ( "failed to fsync {}: {}" , path. display( ) , e) ) )
241- }
242-
243237 // Sync all objects and their parent directories.
244238 // The paths yielded by the [Snapshot::files] iterator are constructed
245239 // by [DirTree::file_path], which creates a path with a parent.
246240 // `parent()` is thus known to succeed.
247241 for ( _, path) in self . snapshot . files ( & self . object_repo ) {
248- fsync ( & path) ?;
249- fsync ( path. parent ( ) . unwrap ( ) ) ?;
242+ FileOrDirPath :: File ( & path) . sync_all ( ) ?;
243+ FileOrDirPath :: Dir ( path. parent ( ) . unwrap ( ) ) . sync_all ( ) ?;
250244 }
251245 // Sync the root directory of the object repo
252- fsync ( self . object_repo . root ( ) ) ?;
246+ FileOrDirPath :: Dir ( self . object_repo . root ( ) ) . sync_all ( ) ?;
253247 // Write out the snapshot file (syncs internally).
254248 self . snapshot_repo
255249 . write_snapshot_file ( & self . snapshot_dir , self . snapshot ) ?;
@@ -855,7 +849,7 @@ impl SnapshotRepository {
855849 . into_inner ( )
856850 . expect ( "buffered writer just flushed" )
857851 . sync_all ( ) ?;
858- File :: open ( & snapshot_dir. 0 ) ? . sync_all ( ) ?;
852+ FileOrDirPath :: Dir ( & snapshot_dir. 0 ) . sync_all ( ) ?;
859853 }
860854
861855 Ok ( ( ) )
@@ -1363,6 +1357,32 @@ pub struct ReconstructedSnapshot {
13631357 pub compress_type : CompressType ,
13641358}
13651359
1360+ /// A [Path] statically known to point to either a file or a directory.
1361+ enum FileOrDirPath < ' a > {
1362+ File ( & ' a Path ) ,
1363+ Dir ( & ' a Path ) ,
1364+ }
1365+
1366+ impl FileOrDirPath < ' _ > {
1367+ /// `fsync` the file or directory at path `self`.
1368+ ///
1369+ /// On *nix systems, both a file and its enclosing directory should be
1370+ /// `fsync`ed to make the file durable.
1371+ ///
1372+ /// On Windows, only the file needs to be synced, and it's even an error to
1373+ /// sync a directory. Passing in [Self::Dir] is thus a no-op on Windows.
1374+ fn sync_all ( & self ) -> io:: Result < ( ) > {
1375+ #[ cfg( target_os = "windows" ) ]
1376+ if let Self :: Dir ( _) = self {
1377+ return Ok ( ( ) ) ;
1378+ }
1379+ let ( Self :: File ( path) | Self :: Dir ( path) ) = self ;
1380+ File :: open ( path)
1381+ . and_then ( |fd| fd. sync_all ( ) )
1382+ . map_err ( |e| io:: Error :: new ( e. kind ( ) , format ! ( "failed to fsync {}: {}" , path. display( ) , e) ) )
1383+ }
1384+ }
1385+
13661386#[ cfg( test) ]
13671387mod tests {
13681388 use std:: fs:: OpenOptions ;
0 commit comments