Android always has `utimensat` available, so it is not necessary (or possible, for that matter) to emulate it. Mark the fallback path as `unreachable!()`.
61 lines
2.0 KiB
Rust
61 lines
2.0 KiB
Rust
//! This module consists of helper types and functions for dealing
|
|
//! with setting the file times specific to Linux.
|
|
use crate::filetime::FileTime;
|
|
use crate::{cstr, from_success_code};
|
|
use std::fs::File;
|
|
use std::io::Result;
|
|
use std::sync::atomic::{AtomicBool, Ordering::Relaxed};
|
|
|
|
/// Wrapper for `utimensat` syscall, however, with an added twist such that `utimensat` symbol
|
|
/// is firstly resolved (i.e., we check whether it exists on the host), and only used if that is
|
|
/// the case. Otherwise, the syscall resorts to a less accurate `utimesat` emulated syscall.
|
|
/// The original implementation can be found here: [filetime::unix::linux::set_times]
|
|
///
|
|
/// [filetime::unix::linux::set_times]: https://github.com/alexcrichton/filetime/blob/master/src/unix/linux.rs#L64
|
|
pub fn utimensat(
|
|
dirfd: &File,
|
|
path: &str,
|
|
atime: FileTime,
|
|
mtime: FileTime,
|
|
symlink_nofollow: bool,
|
|
) -> Result<()> {
|
|
use crate::filetime::to_timespec;
|
|
use std::os::unix::prelude::*;
|
|
|
|
let flags = if symlink_nofollow {
|
|
libc::AT_SYMLINK_NOFOLLOW
|
|
} else {
|
|
0
|
|
};
|
|
|
|
// Attempt to use the `utimensat` syscall, but if it's not supported by the
|
|
// current kernel then fall back to an older syscall.
|
|
static INVALID: AtomicBool = AtomicBool::new(false);
|
|
if !INVALID.load(Relaxed) {
|
|
let path = cstr(path)?;
|
|
let times = [to_timespec(&atime)?, to_timespec(&mtime)?];
|
|
let res = from_success_code(unsafe {
|
|
libc::syscall(
|
|
libc::SYS_utimensat,
|
|
dirfd.as_raw_fd(),
|
|
path.as_ptr(),
|
|
times.as_ptr(),
|
|
flags,
|
|
)
|
|
});
|
|
let err = match res {
|
|
Ok(()) => return Ok(()),
|
|
Err(e) => e,
|
|
};
|
|
if err.raw_os_error().unwrap() == libc::ENOSYS {
|
|
INVALID.store(true, Relaxed);
|
|
}
|
|
return Err(err);
|
|
}
|
|
|
|
#[cfg(not(target_os = "android"))]
|
|
return super::utimesat::utimesat(dirfd, path, atime, mtime, symlink_nofollow);
|
|
#[cfg(target_os = "android")]
|
|
unreachable!();
|
|
}
|