use crate::FileTime; use std::fs::{self, File}; use std::io; use std::os::unix::prelude::*; use std::path::Path; pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { let fd = open_redox(p, 0).map_err(|err| io::Error::from_raw_os_error(err.errno))?; let res = set_file_times_redox(fd, atime, mtime); let _ = syscall::close(fd); res } pub fn set_file_mtime(p: &Path, mtime: FileTime) -> io::Result<()> { let fd = open_redox(p, 0).map_err(|err| io::Error::from_raw_os_error(err.errno))?; let mut st = syscall::Stat::default(); let res = match syscall::fstat(fd, &mut st) { Err(err) => Err(io::Error::from_raw_os_error(err.errno)), Ok(_) => set_file_times_redox( fd, FileTime { seconds: st.st_atime as i64, nanos: st.st_atime_nsec as u32, }, mtime, ), }; let _ = syscall::close(fd); res } pub fn set_file_atime(p: &Path, atime: FileTime) -> io::Result<()> { let fd = open_redox(p, 0).map_err(|err| io::Error::from_raw_os_error(err.errno))?; let mut st = syscall::Stat::default(); let res = match syscall::fstat(fd, &mut st) { Err(err) => Err(io::Error::from_raw_os_error(err.errno)), Ok(_) => set_file_times_redox( fd, atime, FileTime { seconds: st.st_mtime as i64, nanos: st.st_mtime_nsec as u32, }, ), }; let _ = syscall::close(fd); res } pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { let fd = open_redox(p, syscall::O_NOFOLLOW) .map_err(|err| io::Error::from_raw_os_error(err.errno))?; let res = set_file_times_redox(fd, atime, mtime); let _ = syscall::close(fd); res } pub fn set_file_handle_times( f: &File, atime: Option, mtime: Option, ) -> io::Result<()> { let (atime1, mtime1) = match (atime, mtime) { (Some(a), Some(b)) => (a, b), (None, None) => return Ok(()), (Some(a), None) => { let meta = f.metadata()?; (a, FileTime::from_last_modification_time(&meta)) } (None, Some(b)) => { let meta = f.metadata()?; (FileTime::from_last_access_time(&meta), b) } }; set_file_times_redox(f.as_raw_fd() as usize, atime1, mtime1) } fn open_redox(path: &Path, flags: usize) -> syscall::Result { match path.to_str() { Some(string) => syscall::open(string, flags), None => Err(syscall::Error::new(syscall::EINVAL)), } } fn set_file_times_redox(fd: usize, atime: FileTime, mtime: FileTime) -> io::Result<()> { use syscall::TimeSpec; fn to_timespec(ft: &FileTime) -> TimeSpec { TimeSpec { tv_sec: ft.seconds(), tv_nsec: ft.nanoseconds() as i32, } } let times = [to_timespec(&atime), to_timespec(&mtime)]; match syscall::futimens(fd, ×) { Ok(_) => Ok(()), Err(err) => Err(io::Error::from_raw_os_error(err.errno)), } } pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime { FileTime { seconds: meta.mtime(), nanos: meta.mtime_nsec() as u32, } } pub fn from_last_access_time(meta: &fs::Metadata) -> FileTime { FileTime { seconds: meta.atime(), nanos: meta.atime_nsec() as u32, } } pub fn from_creation_time(_meta: &fs::Metadata) -> Option { None }