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: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:times.as_ptr()) |
103 | } else { |
104 | libc::utimes(filename:p.as_ptr(), times: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 | |