| use crate::FileTime; |
| use std::ffi::CString; |
| use std::fs; |
| use std::io; |
| use std::os::unix::prelude::*; |
| use std::path::Path; |
| |
| #[allow(dead_code)] |
| pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { |
| set_times(p, Some(atime), Some(mtime), false) |
| } |
| |
| #[allow(dead_code)] |
| pub fn set_file_mtime(p: &Path, mtime: FileTime) -> io::Result<()> { |
| set_times(p, None, Some(mtime), false) |
| } |
| |
| #[allow(dead_code)] |
| pub fn set_file_atime(p: &Path, atime: FileTime) -> io::Result<()> { |
| set_times(p, Some(atime), None, false) |
| } |
| |
| #[cfg(not(target_env = "uclibc"))] |
| #[allow(dead_code)] |
| pub fn set_file_handle_times( |
| f: &fs::File, |
| atime: Option<FileTime>, |
| mtime: Option<FileTime>, |
| ) -> io::Result<()> { |
| let (atime, mtime) = match get_times(atime, mtime, || f.metadata())? { |
| Some(pair) => pair, |
| None => return Ok(()), |
| }; |
| let times = [to_timeval(&atime), to_timeval(&mtime)]; |
| let rc = unsafe { libc::futimes(f.as_raw_fd(), times.as_ptr()) }; |
| return if rc == 0 { |
| Ok(()) |
| } else { |
| Err(io::Error::last_os_error()) |
| }; |
| } |
| |
| #[cfg(target_env = "uclibc")] |
| #[allow(dead_code)] |
| pub fn set_file_handle_times( |
| f: &fs::File, |
| atime: Option<FileTime>, |
| mtime: Option<FileTime>, |
| ) -> io::Result<()> { |
| let (atime, mtime) = match get_times(atime, mtime, || f.metadata())? { |
| Some(pair) => pair, |
| None => return Ok(()), |
| }; |
| let times = [to_timespec(&atime), to_timespec(&mtime)]; |
| let rc = unsafe { libc::futimens(f.as_raw_fd(), times.as_ptr()) }; |
| return if rc == 0 { |
| Ok(()) |
| } else { |
| Err(io::Error::last_os_error()) |
| }; |
| } |
| |
| fn get_times( |
| atime: Option<FileTime>, |
| mtime: Option<FileTime>, |
| current: impl FnOnce() -> io::Result<fs::Metadata>, |
| ) -> io::Result<Option<(FileTime, FileTime)>> { |
| let pair = match (atime, mtime) { |
| (Some(a), Some(b)) => (a, b), |
| (None, None) => return Ok(None), |
| (Some(a), None) => { |
| let meta = current()?; |
| (a, FileTime::from_last_modification_time(&meta)) |
| } |
| (None, Some(b)) => { |
| let meta = current()?; |
| (FileTime::from_last_access_time(&meta), b) |
| } |
| }; |
| Ok(Some(pair)) |
| } |
| |
| #[allow(dead_code)] |
| pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { |
| set_times(p, Some(atime), Some(mtime), true) |
| } |
| |
| pub fn set_times( |
| p: &Path, |
| atime: Option<FileTime>, |
| mtime: Option<FileTime>, |
| symlink: bool, |
| ) -> io::Result<()> { |
| let (atime, mtime) = match get_times(atime, mtime, || p.metadata())? { |
| Some(pair) => pair, |
| None => return Ok(()), |
| }; |
| let p = CString::new(p.as_os_str().as_bytes())?; |
| let times = [to_timeval(&atime), to_timeval(&mtime)]; |
| let rc = unsafe { |
| if symlink { |
| libc::lutimes(p.as_ptr(), times.as_ptr()) |
| } else { |
| libc::utimes(p.as_ptr(), times.as_ptr()) |
| } |
| }; |
| return if rc == 0 { |
| Ok(()) |
| } else { |
| Err(io::Error::last_os_error()) |
| }; |
| } |
| |
| fn to_timeval(ft: &FileTime) -> libc::timeval { |
| libc::timeval { |
| tv_sec: ft.seconds() as libc::time_t, |
| tv_usec: (ft.nanoseconds() / 1000) as libc::suseconds_t, |
| } |
| } |
| |
| fn to_timespec(ft: &FileTime) -> libc::timespec { |
| libc::timespec { |
| tv_sec: ft.seconds() as libc::time_t, |
| #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] |
| tv_nsec: (ft.nanoseconds()) as i64, |
| #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] |
| tv_nsec: (ft.nanoseconds()) as libc::c_long, |
| } |
| } |