1use std::path::Path;
6
7use crate::error::Error;
8
9#[derive(Debug, PartialEq)]
10pub enum SyncMode {
11 Sync,
13
14 Filesystem,
16
17 File,
19
20 Data,
22}
23
24pub fn sync<P: AsRef<Path>>(file: Option<P>, mode: SyncMode) -> Result<(), Error> {
26 if mode == SyncMode::Sync || file.is_none() {
27 return unsafe { nc::sync().map_err(Into::into) };
28 }
29 let file = file.unwrap();
30 let file = file.as_ref();
31 let mut open_flags = nc::O_RDONLY | nc::O_NONBLOCK;
32 let mut fd = unsafe { nc::open(file, open_flags, 0) };
33 if fd.is_err() {
34 open_flags = nc::O_WRONLY | nc::O_NONBLOCK;
35 fd = unsafe { nc::open(file, open_flags, 0) };
36 }
37 let fd = fd?;
38 let fdflags = unsafe { nc::fcntl(fd, nc::F_GETFL, 0)? };
40 let _ = unsafe { nc::fcntl(fd, nc::F_SETFL, (fdflags & !nc::O_NONBLOCK) as usize)? };
41
42 match mode {
43 SyncMode::Filesystem => unsafe { nc::syncfs(fd)? },
44 SyncMode::File => unsafe { nc::fsync(fd)? },
45 SyncMode::Data => unsafe { nc::fdatasync(fd)? },
46 _ => (),
47 }
48
49 unsafe { nc::close(fd)? };
50 Ok(())
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56
57 #[test]
58 fn test_sync() {
59 assert!(sync::<&str>(None, SyncMode::Sync).is_ok());
60 assert!(sync(Some("/etc/passwd"), SyncMode::Filesystem).is_ok());
61 assert!(sync(Some("/etc/passwd"), SyncMode::File).is_ok());
62 assert!(sync(Some("/etc/passwd"), SyncMode::Data).is_ok());
63 }
64}