| 1 | use crate::FileTime; |
| 2 | use std::ffi::CString; |
| 3 | use std::fs; |
| 4 | use std::io; |
| 5 | use std::os::unix::prelude::*; |
| 6 | use std::path::Path; |
| 7 | |
| 8 | #[allow (dead_code)] |
| 9 | pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { |
| 10 | set_times(p, atime:Some(atime), mtime:Some(mtime), symlink:false) |
| 11 | } |
| 12 | |
| 13 | #[allow (dead_code)] |
| 14 | pub fn set_file_mtime(p: &Path, mtime: FileTime) -> io::Result<()> { |
| 15 | set_times(p, atime:None, mtime:Some(mtime), symlink:false) |
| 16 | } |
| 17 | |
| 18 | #[allow (dead_code)] |
| 19 | pub fn set_file_atime(p: &Path, atime: FileTime) -> io::Result<()> { |
| 20 | set_times(p, atime:Some(atime), mtime:None, symlink:false) |
| 21 | } |
| 22 | |
| 23 | #[cfg (not(target_env = "uclibc" ))] |
| 24 | #[allow (dead_code)] |
| 25 | pub fn set_file_handle_times( |
| 26 | f: &fs::File, |
| 27 | atime: Option<FileTime>, |
| 28 | mtime: Option<FileTime>, |
| 29 | ) -> io::Result<()> { |
| 30 | let (atime: FileTime, mtime: FileTime) = match get_times(atime, mtime, || f.metadata())? { |
| 31 | Some(pair: (FileTime, FileTime)) => pair, |
| 32 | None => return Ok(()), |
| 33 | }; |
| 34 | let times: [timeval; 2] = [to_timeval(&atime), to_timeval(&mtime)]; |
| 35 | let rc: i32 = unsafe { libc::futimes(f.as_raw_fd(), times.as_ptr()) }; |
| 36 | return if rc == 0 { |
| 37 | Ok(()) |
| 38 | } else { |
| 39 | Err(io::Error::last_os_error()) |
| 40 | }; |
| 41 | } |
| 42 | |
| 43 | #[cfg (target_env = "uclibc" )] |
| 44 | #[allow (dead_code)] |
| 45 | pub fn set_file_handle_times( |
| 46 | f: &fs::File, |
| 47 | atime: Option<FileTime>, |
| 48 | mtime: Option<FileTime>, |
| 49 | ) -> io::Result<()> { |
| 50 | let (atime, mtime) = match get_times(atime, mtime, || f.metadata())? { |
| 51 | Some(pair) => pair, |
| 52 | None => return Ok(()), |
| 53 | }; |
| 54 | let times = [to_timespec(&atime), to_timespec(&mtime)]; |
| 55 | let rc = unsafe { libc::futimens(f.as_raw_fd(), times.as_ptr()) }; |
| 56 | return if rc == 0 { |
| 57 | Ok(()) |
| 58 | } else { |
| 59 | Err(io::Error::last_os_error()) |
| 60 | }; |
| 61 | } |
| 62 | |
| 63 | fn get_times( |
| 64 | atime: Option<FileTime>, |
| 65 | mtime: Option<FileTime>, |
| 66 | current: impl FnOnce() -> io::Result<fs::Metadata>, |
| 67 | ) -> io::Result<Option<(FileTime, FileTime)>> { |
| 68 | let pair: (FileTime, FileTime) = match (atime, mtime) { |
| 69 | (Some(a: FileTime), Some(b: FileTime)) => (a, b), |
| 70 | (None, None) => return Ok(None), |
| 71 | (Some(a: FileTime), None) => { |
| 72 | let meta: Metadata = current()?; |
| 73 | (a, FileTime::from_last_modification_time(&meta)) |
| 74 | } |
| 75 | (None, Some(b: FileTime)) => { |
| 76 | let meta: Metadata = current()?; |
| 77 | (FileTime::from_last_access_time(&meta), b) |
| 78 | } |
| 79 | }; |
| 80 | Ok(Some(pair)) |
| 81 | } |
| 82 | |
| 83 | #[allow (dead_code)] |
| 84 | pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> { |
| 85 | set_times(p, atime:Some(atime), mtime:Some(mtime), symlink:true) |
| 86 | } |
| 87 | |
| 88 | pub fn set_times( |
| 89 | p: &Path, |
| 90 | atime: Option<FileTime>, |
| 91 | mtime: Option<FileTime>, |
| 92 | symlink: bool, |
| 93 | ) -> io::Result<()> { |
| 94 | let (atime: FileTime, mtime: FileTime) = match get_times(atime, mtime, || p.metadata())? { |
| 95 | Some(pair: (FileTime, FileTime)) => pair, |
| 96 | None => return Ok(()), |
| 97 | }; |
| 98 | let p: CString = CString::new(p.as_os_str().as_bytes())?; |
| 99 | let times: [timeval; 2] = [to_timeval(&atime), to_timeval(&mtime)]; |
| 100 | let rc: i32 = unsafe { |
| 101 | if symlink { |
| 102 | libc::lutimes(file:p.as_ptr(), times.as_ptr()) |
| 103 | } else { |
| 104 | libc::utimes(filename:p.as_ptr(), times.as_ptr()) |
| 105 | } |
| 106 | }; |
| 107 | return if rc == 0 { |
| 108 | Ok(()) |
| 109 | } else { |
| 110 | Err(io::Error::last_os_error()) |
| 111 | }; |
| 112 | } |
| 113 | |
| 114 | fn to_timeval(ft: &FileTime) -> libc::timeval { |
| 115 | libc::timeval { |
| 116 | tv_sec: ft.seconds() as libc::time_t, |
| 117 | tv_usec: (ft.nanoseconds() / 1000) as libc::suseconds_t, |
| 118 | } |
| 119 | } |
| 120 | |
| 121 | #[cfg (target_env = "uclibc" )] |
| 122 | fn to_timespec(ft: &FileTime) -> libc::timespec { |
| 123 | libc::timespec { |
| 124 | tv_sec: ft.seconds() as libc::time_t, |
| 125 | #[cfg (all(target_arch = "x86_64" , target_pointer_width = "32" ))] |
| 126 | tv_nsec: (ft.nanoseconds()) as i64, |
| 127 | #[cfg (not(all(target_arch = "x86_64" , target_pointer_width = "32" )))] |
| 128 | tv_nsec: (ft.nanoseconds()) as libc::c_long, |
| 129 | } |
| 130 | } |
| 131 | |