pb_mapper_core/
durable_file.rs1use std::fs::File;
9use std::path::Path;
10
11pub fn replace_file(from: &Path, to: &Path) -> std::io::Result<()> {
13 #[cfg(windows)]
14 {
15 use std::os::windows::ffi::OsStrExt;
16
17 const MOVEFILE_REPLACE_EXISTING: u32 = 0x1;
18 const MOVEFILE_WRITE_THROUGH: u32 = 0x8;
19 unsafe extern "system" {
20 fn MoveFileExW(
21 lp_existing_file_name: *const u16,
22 lp_new_file_name: *const u16,
23 dw_flags: u32,
24 ) -> i32;
25 }
26 fn wide(path: &Path) -> Vec<u16> {
27 path.as_os_str()
28 .encode_wide()
29 .chain(std::iter::once(0))
30 .collect()
31 }
32 let from_w = wide(from);
33 let to_w = wide(to);
34 let ok = unsafe {
35 MoveFileExW(
36 from_w.as_ptr(),
37 to_w.as_ptr(),
38 MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH,
39 )
40 };
41 if ok == 0 {
42 Err(std::io::Error::last_os_error())
43 } else {
44 Ok(())
45 }
46 }
47 #[cfg(not(windows))]
48 std::fs::rename(from, to)
49}
50
51pub fn sync_parent_directory(path: &Path) -> std::io::Result<()> {
55 let Some(parent) = path.parent() else {
56 return Ok(());
57 };
58 open_directory_for_sync(parent).and_then(|directory| directory.sync_all())
59}
60
61fn open_directory_for_sync(path: &Path) -> std::io::Result<File> {
62 #[cfg(windows)]
63 {
64 use std::fs::OpenOptions;
65 use std::os::windows::fs::OpenOptionsExt;
66 const GENERIC_READ: u32 = 0x8000_0000;
67 const GENERIC_WRITE: u32 = 0x4000_0000;
68 const FILE_FLAG_BACKUP_SEMANTICS: u32 = 0x0200_0000;
69 OpenOptions::new()
70 .access_mode(GENERIC_READ | GENERIC_WRITE)
71 .custom_flags(FILE_FLAG_BACKUP_SEMANTICS)
72 .open(path)
73 }
74 #[cfg(not(windows))]
75 File::open(path)
76}