use std::io;
use std::path::Path;
use super::ops::blocking;
pub async fn sync_dir(path: impl AsRef<Path>) -> io::Result<()> {
let path = path.as_ref().to_path_buf();
blocking(move || sync_dir_now(&path)).await
}
#[cfg(unix)]
fn sync_dir_now(path: &Path) -> io::Result<()> {
let dir = std::fs::File::open(path)?;
let synced = dir.sync_all();
#[cfg(any(target_os = "macos", target_os = "ios"))]
if synced.as_ref().is_err_and(refused) {
use std::os::fd::AsRawFd;
let fd = dir.as_raw_fd();
let barrier = again(|| unsafe { libc::fcntl(fd, libc::F_BARRIERFSYNC) });
if !barrier.as_ref().is_err_and(refused) {
return barrier;
}
return again(|| unsafe { libc::fsync(fd) });
}
synced
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
fn refused(err: &io::Error) -> bool {
matches!(err.raw_os_error(), Some(libc::ENOTSUP | libc::EINVAL))
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
fn again(mut call: impl FnMut() -> libc::c_int) -> io::Result<()> {
loop {
if call() != -1 {
return Ok(());
}
let err = io::Error::last_os_error();
if err.raw_os_error() != Some(libc::EINTR) {
return Err(err);
}
}
}
#[cfg(windows)]
fn sync_dir_now(path: &Path) -> io::Result<()> {
use std::os::windows::fs::OpenOptionsExt;
std::fs::OpenOptions::new()
.read(true)
.write(true)
.custom_flags(crate::syscore::windows::FILE_FLAG_BACKUP_SEMANTICS)
.open(path)?
.sync_all()
}