@@ -42,6 +42,14 @@ fn path_to_windows_str<T: AsRef<OsStr>>(path: &T) -> Vec<u16> {
4242 path. as_ref ( ) . encode_wide ( ) . chain ( Some ( 0 ) ) . collect ( )
4343}
4444
45+ fn remove_file_if_exists ( path : & Path ) -> lightning:: io:: Result < ( ) > {
46+ match fs:: remove_file ( path) {
47+ Ok ( ( ) ) => Ok ( ( ) ) ,
48+ Err ( e) if e. kind ( ) == ErrorKind :: NotFound => Ok ( ( ) ) ,
49+ Err ( e) => Err ( e. into ( ) ) ,
50+ }
51+ }
52+
4553// The number of times we retry listing keys in `FilesystemStore::list` before we give up reaching
4654// a consistent view and error out.
4755const LIST_DIR_CONSISTENCY_RETRIES : usize = 10 ;
@@ -277,64 +285,81 @@ impl FilesystemStoreInner {
277285 let tmp_file_ext = format ! ( "{}.tmp" , self . tmp_file_counter. fetch_add( 1 , Ordering :: AcqRel ) ) ;
278286 tmp_file_path. set_extension ( tmp_file_ext) ;
279287
280- {
281- let mut tmp_file = fs :: File :: create ( & tmp_file_path ) ? ;
282- tmp_file. write_all ( & buf) ?;
288+ let tmp_file_res = match fs :: File :: create ( & tmp_file_path ) {
289+ Ok ( mut tmp_file) => ( || -> lightning :: io :: Result < ( ) > {
290+ tmp_file. write_all ( & buf) ?;
283291
284- // If we need to preserve the original mtime (for updates), set it before fsync.
285- if let Some ( mtime) = mtime {
286- let times = fs:: FileTimes :: new ( ) . set_modified ( mtime) ;
287- tmp_file. set_times ( times) ?;
288- }
292+ // If we need to preserve the original mtime (for updates), set it before fsync.
293+ if let Some ( mtime) = mtime {
294+ let times = fs:: FileTimes :: new ( ) . set_modified ( mtime) ;
295+ tmp_file. set_times ( times) ?;
296+ }
289297
290- tmp_file. sync_all ( ) ?;
298+ tmp_file. sync_all ( ) ?;
299+ Ok ( ( ) )
300+ } ) ( ) ,
301+ Err ( e) => return Err ( e. into ( ) ) ,
302+ } ;
303+ if let Err ( e) = tmp_file_res {
304+ let _ = remove_file_if_exists ( & tmp_file_path) ;
305+ return Err ( e) ;
291306 }
292307
293- self . execute_locked_write ( inner_lock_ref, dest_file_path. clone ( ) , version, || {
294- #[ cfg( not( target_os = "windows" ) ) ]
295- {
296- fs:: rename ( & tmp_file_path, & dest_file_path) ?;
297- let dir_file = fs:: OpenOptions :: new ( ) . read ( true ) . open ( & parent_directory) ?;
298- dir_file. sync_all ( ) ?;
299- Ok ( ( ) )
300- }
308+ let mut tmp_file_needs_cleanup = true ;
309+ let write_res =
310+ self . execute_locked_write ( inner_lock_ref, dest_file_path. clone ( ) , version, || {
311+ #[ cfg( not( target_os = "windows" ) ) ]
312+ {
313+ fs:: rename ( & tmp_file_path, & dest_file_path) ?;
314+ tmp_file_needs_cleanup = false ;
315+ let dir_file = fs:: OpenOptions :: new ( ) . read ( true ) . open ( & parent_directory) ?;
316+ dir_file. sync_all ( ) ?;
317+ Ok ( ( ) )
318+ }
301319
302- #[ cfg( target_os = "windows" ) ]
303- {
304- let res = if dest_file_path. exists ( ) {
305- call ! ( unsafe {
306- windows_sys:: Win32 :: Storage :: FileSystem :: ReplaceFileW (
320+ #[ cfg( target_os = "windows" ) ]
321+ {
322+ let res = if dest_file_path. exists ( ) {
323+ call ! ( unsafe {
324+ windows_sys:: Win32 :: Storage :: FileSystem :: ReplaceFileW (
307325 path_to_windows_str( & dest_file_path) . as_ptr( ) ,
308326 path_to_windows_str( & tmp_file_path) . as_ptr( ) ,
309327 std:: ptr:: null( ) ,
310328 windows_sys:: Win32 :: Storage :: FileSystem :: REPLACEFILE_IGNORE_MERGE_ERRORS ,
311329 std:: ptr:: null_mut( ) as * const core:: ffi:: c_void,
312330 std:: ptr:: null_mut( ) as * const core:: ffi:: c_void,
313331 )
314- } )
315- } else {
316- call ! ( unsafe {
317- windows_sys:: Win32 :: Storage :: FileSystem :: MoveFileExW (
332+ } )
333+ } else {
334+ call ! ( unsafe {
335+ windows_sys:: Win32 :: Storage :: FileSystem :: MoveFileExW (
318336 path_to_windows_str( & tmp_file_path) . as_ptr( ) ,
319337 path_to_windows_str( & dest_file_path) . as_ptr( ) ,
320338 windows_sys:: Win32 :: Storage :: FileSystem :: MOVEFILE_WRITE_THROUGH
321339 | windows_sys:: Win32 :: Storage :: FileSystem :: MOVEFILE_REPLACE_EXISTING ,
322340 )
323- } )
324- } ;
325-
326- match res {
327- Ok ( ( ) ) => {
328- // We fsync the dest file in hopes this will also flush the metadata to disk.
329- let dest_file =
330- fs:: OpenOptions :: new ( ) . read ( true ) . write ( true ) . open ( & dest_file_path) ?;
331- dest_file. sync_all ( ) ?;
332- Ok ( ( ) )
333- } ,
334- Err ( e) => Err ( e. into ( ) ) ,
341+ } )
342+ } ;
343+
344+ match res {
345+ Ok ( ( ) ) => {
346+ tmp_file_needs_cleanup = false ;
347+ // We fsync the dest file in hopes this will also flush the metadata to disk.
348+ let dest_file = fs:: OpenOptions :: new ( )
349+ . read ( true )
350+ . write ( true )
351+ . open ( & dest_file_path) ?;
352+ dest_file. sync_all ( ) ?;
353+ Ok ( ( ) )
354+ } ,
355+ Err ( e) => Err ( e. into ( ) ) ,
356+ }
335357 }
336- }
337- } )
358+ } ) ;
359+ if tmp_file_needs_cleanup {
360+ let _ = remove_file_if_exists ( & tmp_file_path) ;
361+ }
362+ write_res
338363 }
339364
340365 fn remove_version (
0 commit comments