| 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 |  | 
|---|