1use std::fs::File;
4use std::io;
5use std::path::Path;
6
7#[cfg(target_os = "macos")]
13pub fn durable_sync(file: &File) -> io::Result<()> {
14 use std::os::unix::io::AsRawFd;
15 let ret = unsafe { libc::fcntl(file.as_raw_fd(), libc::F_FULLFSYNC) };
16 if ret == -1 {
17 Err(io::Error::last_os_error())
18 } else {
19 Ok(())
20 }
21}
22
23#[cfg(not(target_os = "macos"))]
24pub fn durable_sync(file: &File) -> io::Result<()> {
25 file.sync_data()
26}
27
28#[cfg(unix)]
32pub fn sync_dir(path: &Path) -> io::Result<()> {
33 let dir = File::open(path)?;
34 durable_sync(&dir)
35}
36
37#[cfg(not(unix))]
38pub fn sync_dir(_path: &Path) -> io::Result<()> {
39 Ok(())
41}
42
43#[cfg(windows)]
47pub fn rename_with_retry(from: &Path, to: &Path) -> io::Result<()> {
48 use std::thread;
49 use std::time::Duration;
50
51 let delays = [50, 100, 200];
52 let mut last_err = None;
53
54 for (attempt, delay_ms) in std::iter::once(&0u64).chain(delays.iter()).enumerate() {
55 if attempt > 0 {
56 thread::sleep(Duration::from_millis(*delay_ms));
57 }
58 match std::fs::rename(from, to) {
59 Ok(()) => return Ok(()),
60 Err(e) => {
61 if e.raw_os_error() == Some(32) {
63 last_err = Some(e);
64 continue;
65 }
66 return Err(e);
67 }
68 }
69 }
70
71 Err(last_err
72 .unwrap_or_else(|| io::Error::new(io::ErrorKind::Other, "rename failed after retries")))
73}
74
75#[cfg(not(windows))]
76pub fn rename_with_retry(from: &Path, to: &Path) -> io::Result<()> {
77 std::fs::rename(from, to)
78}
79
80pub fn resolve_symlinks(path: &Path) -> io::Result<std::path::PathBuf> {
83 std::fs::canonicalize(path)
84}