11use std:: fs;
2+ #[ cfg( target_os = "windows" ) ]
3+ use std:: os:: windows:: ffi:: OsStrExt ;
24use std:: path:: Path ;
35use std:: time:: { SystemTime , UNIX_EPOCH } ;
46
@@ -8,6 +10,8 @@ use serde::{Deserialize, Serialize};
810use crate :: paths:: AppPaths ;
911use crate :: platform:: is_process_running;
1012use crate :: platform:: sync_user_ownership;
13+ #[ cfg( target_os = "windows" ) ]
14+ use windows_sys:: Win32 :: Storage :: FileSystem :: { MOVEFILE_REPLACE_EXISTING , MoveFileExW } ;
1115
1216#[ derive( Debug , Clone , Serialize , Deserialize ) ]
1317pub struct ServiceState {
@@ -229,18 +233,24 @@ fn replace_file(path: &Path, content: &[u8]) -> Result<()> {
229233 fs:: write ( & tmp_path, content)
230234 . with_context ( || format ! ( "failed to write {}" , tmp_path. display( ) ) ) ?;
231235
232- if path. exists ( ) {
233- match fs:: remove_file ( path) {
234- Ok ( ( ) ) => { }
235- Err ( error) if error. kind ( ) == std:: io:: ErrorKind :: NotFound => { }
236- Err ( error) => {
237- let _ = fs:: remove_file ( & tmp_path) ;
238- return Err ( error) . with_context ( || format ! ( "failed to replace {}" , path. display( ) ) ) ;
239- }
240- }
241- }
236+ move_file_replace ( & tmp_path, path) . with_context ( || {
237+ format ! ( "failed to move {} to {}" , tmp_path. display( ) , path. display( ) )
238+ } ) ?;
239+ Ok ( ( ) )
240+ }
242241
243- fs:: rename ( & tmp_path, path)
244- . with_context ( || format ! ( "failed to move {} to {}" , tmp_path. display( ) , path. display( ) ) ) ?;
242+ #[ cfg( target_os = "windows" ) ]
243+ fn move_file_replace ( src : & Path , dst : & Path ) -> Result < ( ) > {
244+ let src_wide: Vec < u16 > = src. as_os_str ( ) . encode_wide ( ) . chain ( Some ( 0 ) ) . collect ( ) ;
245+ let dst_wide: Vec < u16 > = dst. as_os_str ( ) . encode_wide ( ) . chain ( Some ( 0 ) ) . collect ( ) ;
246+ let ok = unsafe { MoveFileExW ( src_wide. as_ptr ( ) , dst_wide. as_ptr ( ) , MOVEFILE_REPLACE_EXISTING ) } ;
247+ if ok == 0 {
248+ return Err ( std:: io:: Error :: last_os_error ( ) ) . context ( "MoveFileExW failed" ) ;
249+ }
245250 Ok ( ( ) )
246251}
252+
253+ #[ cfg( not( target_os = "windows" ) ) ]
254+ fn move_file_replace ( src : & Path , dst : & Path ) -> Result < ( ) > {
255+ fs:: rename ( src, dst) . context ( "rename failed" )
256+ }
0 commit comments