1use crate::FileTime;
2use std::ffi::CString;
3use std::fs;
4use std::io;
5use std::os::unix::prelude::*;
6use std::path::Path;
7
8#[allow(dead_code)]
9pub 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)]
14pub 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)]
19pub 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)]
25pub 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)]
45pub 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
63fn 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)]
84pub 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
88pub 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
114fn 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")]
122fn 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