@@ -29,9 +29,11 @@ pub async fn write_atomic_restricted(
2929 file_mode : u32 ,
3030 dir_mode : u32 ,
3131) -> io:: Result < ( ) > {
32- let path = path. as_ref ( ) . to_owned ( ) ;
32+ let dest = path. as_ref ( ) . to_owned ( ) ;
3333 let contents = contents. as_ref ( ) . to_vec ( ) ;
34- tokio:: task:: spawn_blocking ( move || {
34+ let path = dest. clone ( ) ;
35+
36+ let tmp_path = tokio:: task:: spawn_blocking ( move || {
3537 let parent = path. parent ( ) . ok_or_else ( || {
3638 io:: Error :: new (
3739 io:: ErrorKind :: InvalidInput ,
@@ -56,21 +58,23 @@ pub async fn write_atomic_restricted(
5658
5759 write_file_with_mode ( & tmp_path, & contents, file_mode) ?;
5860
59- let persist_result = atomic_rename_over_impl ( & tmp_path, & path) ;
60- if persist_result. is_err ( ) {
61- let _ = std:: fs:: remove_file ( & tmp_path) ;
62- }
63- persist_result
61+ io:: Result :: Ok ( tmp_path)
6462 } )
6563 . await
66- . map_err ( io:: Error :: other) ?
64+ . map_err ( io:: Error :: other) ??;
65+
66+ let rename_result = atomic_rename_over ( & tmp_path, & dest) . await ;
67+ if rename_result. is_err ( ) {
68+ let _ = tokio:: fs:: remove_file ( & tmp_path) . await ;
69+ }
70+ rename_result
6771}
6872
6973/// Atomically replace `to` with `from`.
7074///
71- /// On Unix this is a single `rename(2)` call — atomic by POSIX
72- /// guarantee. On Windows this uses `ReplaceFileW` (preserves ACLs
73- /// and alternate data streams) when the target exists, falling back
75+ /// On Unix this delegates to [`tokio::fs::rename`] ( `rename(2)` — atomic
76+ /// by POSIX guarantee) . On Windows this uses `ReplaceFileW` (preserves
77+ /// ACLs and alternate data streams) when the target exists, falling back
7478/// to `MoveFileExW` with `MOVEFILE_REPLACE_EXISTING` for first-write.
7579///
7680/// # Errors
@@ -81,11 +85,18 @@ pub async fn atomic_rename_over(
8185 from : impl AsRef < Path > ,
8286 to : impl AsRef < Path > ,
8387) -> io:: Result < ( ) > {
84- let from = from. as_ref ( ) . to_owned ( ) ;
85- let to = to. as_ref ( ) . to_owned ( ) ;
86- tokio:: task:: spawn_blocking ( move || atomic_rename_over_impl ( & from, & to) )
87- . await
88- . map_err ( io:: Error :: other) ?
88+ #[ cfg( unix) ]
89+ {
90+ tokio:: fs:: rename ( from. as_ref ( ) , to. as_ref ( ) ) . await
91+ }
92+ #[ cfg( windows) ]
93+ {
94+ let from = from. as_ref ( ) . to_owned ( ) ;
95+ let to = to. as_ref ( ) . to_owned ( ) ;
96+ tokio:: task:: spawn_blocking ( move || atomic_rename_over_impl ( & from, & to) )
97+ . await
98+ . map_err ( io:: Error :: other) ?
99+ }
89100}
90101
91102/// Remove a file if it exists; silently return `Ok(())` if it does not.
@@ -148,11 +159,6 @@ fn write_file_with_mode(path: &Path, contents: &[u8], _mode: u32) -> io::Result<
148159 std:: fs:: write ( path, contents)
149160}
150161
151- #[ cfg( unix) ]
152- fn atomic_rename_over_impl ( from : & Path , to : & Path ) -> io:: Result < ( ) > {
153- std:: fs:: rename ( from, to)
154- }
155-
156162#[ cfg( windows) ]
157163fn atomic_rename_over_impl ( from : & Path , to : & Path ) -> io:: Result < ( ) > {
158164 use windows:: core:: HSTRING ;
0 commit comments