diff --git a/src/unix/linux.rs b/src/unix/linux.rs index c803e02..255fcfb 100644 --- a/src/unix/linux.rs +++ b/src/unix/linux.rs @@ -34,6 +34,11 @@ pub fn set_file_handle_times( static INVALID: AtomicBool = AtomicBool::new(false); if !INVALID.load(SeqCst) { let times = [super::to_timespec(&atime), super::to_timespec(&mtime)]; + + // We normally use a syscall because the `utimensat` function is documented + // as not accepting a file descriptor in the first argument (even though, on + // Linux, the syscall itself can accept a file descriptor there). + #[cfg(not(target_env = "musl"))] let rc = unsafe { libc::syscall( libc::SYS_utimensat, @@ -43,6 +48,24 @@ pub fn set_file_handle_times( 0, ) }; + // However, on musl, we call the musl libc function instead. This is because + // on newer musl versions starting with musl 1.2, `timespec` is always a 64-bit + // value even on 32-bit targets. As a result, musl internally converts their + // `timespec` values to the correct ABI before invoking the syscall. Since we + // use `timespec` from the libc crate, it matches musl's definition and not + // the Linux kernel's version (for some platforms) so we must use musl's + // `utimensat` function to properly convert the value. musl's `utimensat` + // function allows file descriptors in the path argument so this is fine. + #[cfg(target_env = "musl")] + let rc = unsafe { + libc::utimensat( + f.as_raw_fd(), + ptr::null::(), + times.as_ptr(), + 0, + ) + }; + if rc == 0 { return Ok(()); } @@ -78,15 +101,7 @@ fn set_times( if !INVALID.load(SeqCst) { let p = CString::new(p.as_os_str().as_bytes())?; let times = [super::to_timespec(&atime), super::to_timespec(&mtime)]; - let rc = unsafe { - libc::syscall( - libc::SYS_utimensat, - libc::AT_FDCWD, - p.as_ptr(), - times.as_ptr(), - flags, - ) - }; + let rc = unsafe { libc::utimensat(libc::AT_FDCWD, p.as_ptr(), times.as_ptr(), flags) }; if rc == 0 { return Ok(()); } diff --git a/src/unix/mod.rs b/src/unix/mod.rs index 8b77888..df62de4 100644 --- a/src/unix/mod.rs +++ b/src/unix/mod.rs @@ -58,17 +58,16 @@ fn to_timespec(ft: &Option) -> timespec { } } + let mut ts: timespec = unsafe { std::mem::zeroed() }; if let &Some(ft) = ft { - timespec { - tv_sec: ft.seconds() as time_t, - tv_nsec: ft.nanoseconds() as _, - } + ts.tv_sec = ft.seconds() as time_t; + ts.tv_nsec = ft.nanoseconds() as _; } else { - timespec { - tv_sec: 0, - tv_nsec: UTIME_OMIT as _, - } + ts.tv_sec = 0; + ts.tv_nsec = UTIME_OMIT as _; } + + ts } pub fn from_last_modification_time(meta: &fs::Metadata) -> FileTime {