use super::Cmd; use clap::{Arg, ArgAction, Command}; use std::{error::Error, ffi::CString, io}; #[derive(Debug, Default)] pub struct Sync; impl Cmd for Sync { fn cli(&self) -> clap::Command { Command::new("sync") .about("force completion of pending disk writes (flush cache)") .author("Nathan Fisher") .version(env!("CARGO_PKG_VERSION")) .args([ Arg::new("data") .short('d') .long("data") .help("sync only file data, no unneeded metadata") .conflicts_with("fs") .action(ArgAction::SetTrue), Arg::new("fs") .short('f') .long("file-system") .help("sync the file systems that contain the files") .action(ArgAction::SetTrue), Arg::new("FILE") .help( "If one or more files are specified, sync only them, or \ their containing file systems.", ) .num_args(0..), ]) } fn run(&self, matches: Option<&clap::ArgMatches>) -> Result<(), Box> { let Some(matches) = matches else { return Err(Box::new(io::Error::new(io::ErrorKind::Other, "no input"))); }; if let Some(files) = matches.get_many::("FILE") { for f in files { let file = CString::new(f.as_bytes())?; if matches.get_flag("data") { let rc = unsafe { let fd = libc::open(file.as_ptr(), libc::O_RDWR | libc::O_NOATIME); libc::fdatasync(fd) }; if rc != 0 { return Err(Box::new(io::Error::last_os_error())); } } else if matches.get_flag("fs") { let rc = unsafe { let fd = libc::open(file.as_ptr(), libc::O_RDWR | libc::O_NOATIME); libc::syncfs(fd) }; if rc != 0 { return Err(Box::new(io::Error::last_os_error())); } } else { let rc = unsafe { let fd = libc::open(file.as_ptr(), libc::O_RDWR | libc::O_NOATIME); libc::fsync(fd) }; if rc != 0 { return Err(Box::new(io::Error::last_os_error())); } } } } else { unsafe { libc::sync(); } } Ok(()) } fn path(&self) -> Option { Some(crate::Path::Bin) } }