1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
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, } }