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
use std::io;
use std::mem;
use std::path::Path;
use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
use FileTime;
use super::libc::{self, c_int, c_char, timespec};
pub fn set_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> {
set_times(p, atime, mtime, false)
}
pub fn set_symlink_file_times(p: &Path, atime: FileTime, mtime: FileTime) -> io::Result<()> {
set_times(p, atime, mtime, true)
}
fn set_times(p: &Path, atime: FileTime, mtime: FileTime, symlink: bool) -> io::Result<()> {
let flags = if symlink { libc::AT_SYMLINK_NOFOLLOW } else { 0 };
let utimes = if symlink { libc::lutimes } else { libc::utimes };
static INVALID: AtomicBool = ATOMIC_BOOL_INIT;
if !INVALID.load(Ordering::SeqCst) {
if let Some(f) = utimensat() {
match super::utimensat(p, atime, mtime, f, flags) {
Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {
INVALID.store(true, Ordering::SeqCst);
}
valid => return valid,
}
}
}
super::utimes(p, atime, mtime, utimes)
}
fn utimensat() -> Option<unsafe extern fn(c_int, *const c_char, *const timespec, c_int) -> c_int> {
static ADDR: AtomicUsize = ATOMIC_USIZE_INIT;
unsafe {
match ADDR.load(Ordering::SeqCst) {
0 => {}
1 => return None,
n => return Some(mem::transmute(n)),
}
let name = b"utimensat\0";
let sym = libc::dlsym(libc::RTLD_DEFAULT, name.as_ptr() as *const _);
let (val, ret) = if sym.is_null() {
(1, None)
} else {
(sym as usize, Some(mem::transmute(sym)))
};
ADDR.store(val, Ordering::SeqCst);
return ret
}
}