diff --git a/src/backend/libc/fs/syscalls.rs b/src/backend/libc/fs/syscalls.rs index a098e2b80..f03d87c98 100644 --- a/src/backend/libc/fs/syscalls.rs +++ b/src/backend/libc/fs/syscalls.rs @@ -802,8 +802,8 @@ pub(crate) fn utimensat( flags: AtFlags, ) -> io::Result<()> { // Old 32-bit version: libc has `utimensat` but it is not y2038 safe by - // default. But there may be a `__utimensat16` we can use. - #[cfg(fix_y2038)] + // default. But there may be a `__utimensat64` we can use. + #[cfg(all(fix_y2038, not(apple)))] { #[cfg(target_env = "gnu")] if let Some(libc_utimensat) = __utimensat64.get() { @@ -874,6 +874,10 @@ pub(crate) fn utimensat( )); } + // Convert `times`. We only need this in the child, but do it before + // calling `fork` because it might fail. + let (attrbuf_size, times, attrs) = times_to_attrlist(times)?; + // `setattrlistat` was introduced in 10.13 along with `utimensat`, so // if we don't have `utimensat`, we don't have `setattrlistat` either. // Emulate it using `fork`, and `fchdir` and [`setattrlist`]. @@ -896,8 +900,6 @@ pub(crate) fn utimensat( flags_arg |= FSOPT_NOFOLLOW; } - let (attrbuf_size, times, attrs) = times_to_attrlist(times); - if setattrlist( c_str(path), &attrs, @@ -954,7 +956,7 @@ pub(crate) fn utimensat( } } -#[cfg(fix_y2038)] +#[cfg(all(fix_y2038, not(apple)))] fn utimensat_old( dirfd: BorrowedFd<'_>, path: &CStr, @@ -1505,7 +1507,7 @@ fn libc_statvfs_to_statvfs(from: c::statvfs) -> StatVfs { pub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> { // Old 32-bit version: libc has `futimens` but it is not y2038 safe by // default. But there may be a `__futimens64` we can use. - #[cfg(fix_y2038)] + #[cfg(all(fix_y2038, not(apple)))] { #[cfg(target_env = "gnu")] if let Some(libc_futimens) = __futimens64.get() { @@ -1556,7 +1558,7 @@ pub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> } // Otherwise use `fsetattrlist`. - let (attrbuf_size, times, attrs) = times_to_attrlist(times); + let (attrbuf_size, times, attrs) = times_to_attrlist(times)?; ret(fsetattrlist( borrowed_fd(fd), @@ -1568,7 +1570,7 @@ pub(crate) fn futimens(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> } } -#[cfg(fix_y2038)] +#[cfg(all(fix_y2038, not(apple)))] fn futimens_old(fd: BorrowedFd<'_>, times: &Timestamps) -> io::Result<()> { let old_times = [ c::timespec { @@ -2147,7 +2149,7 @@ pub(crate) fn fcntl_global_nocache(fd: BorrowedFd<'_>, value: bool) -> io::Resul /// Convert `times` from a `futimens`/`utimensat` argument into `setattrlist` /// arguments. #[cfg(apple)] -fn times_to_attrlist(times: &Timestamps) -> (c::size_t, [c::timespec; 2], Attrlist) { +fn times_to_attrlist(times: &Timestamps) -> io::Result<(c::size_t, [c::timespec; 2], Attrlist)> { // ABI details. const ATTR_CMN_MODTIME: u32 = 0x0000_0400; const ATTR_CMN_ACCTIME: u32 = 0x0000_1000; @@ -2156,7 +2158,8 @@ fn times_to_attrlist(times: &Timestamps) -> (c::size_t, [c::timespec; 2], Attrli let mut times = times.clone(); // If we have any `UTIME_NOW` elements, replace them with the current time. - if times.last_access.tv_nsec == c::UTIME_NOW || times.last_modification.tv_nsec == c::UTIME_NOW + if times.last_access.tv_nsec == c::UTIME_NOW.into() + || times.last_modification.tv_nsec == c::UTIME_NOW.into() { let now = { let mut tv = c::timeval { @@ -2172,11 +2175,17 @@ fn times_to_attrlist(times: &Timestamps) -> (c::size_t, [c::timespec; 2], Attrli tv_nsec: (tv.tv_usec * 1000) as _, } }; - if times.last_access.tv_nsec == c::UTIME_NOW { - times.last_access = now; + if times.last_access.tv_nsec == c::UTIME_NOW.into() { + times.last_access = crate::timespec::Timespec { + tv_sec: now.tv_sec.into(), + tv_nsec: now.tv_nsec as _, + }; } - if times.last_modification.tv_nsec == c::UTIME_NOW { - times.last_modification = now; + if times.last_modification.tv_nsec == c::UTIME_NOW.into() { + times.last_modification = crate::timespec::Timespec { + tv_sec: now.tv_sec.into(), + tv_nsec: now.tv_nsec as _, + }; } } @@ -2198,19 +2207,33 @@ fn times_to_attrlist(times: &Timestamps) -> (c::size_t, [c::timespec; 2], Attrli tv_nsec: 0, }; 2]; let mut times_index = 0; - if times.last_modification.tv_nsec != c::UTIME_OMIT { + if times.last_modification.tv_nsec != c::UTIME_OMIT.into() { attrs.commonattr |= ATTR_CMN_MODTIME; - return_times[times_index] = times.last_modification; + return_times[times_index] = c::timespec { + tv_sec: times + .last_modification + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: times.last_modification.tv_nsec as _, + }; times_index += 1; times_size += size_of::(); } - if times.last_access.tv_nsec != c::UTIME_OMIT { + if times.last_access.tv_nsec != c::UTIME_OMIT.into() { attrs.commonattr |= ATTR_CMN_ACCTIME; - return_times[times_index] = times.last_access; + return_times[times_index] = c::timespec { + tv_sec: times + .last_access + .tv_sec + .try_into() + .map_err(|_| io::Errno::OVERFLOW)?, + tv_nsec: times.last_access.tv_nsec as _, + }; times_size += size_of::(); } - (times_size, return_times, attrs) + Ok((times_size, return_times, attrs)) } /// Support type for `Attrlist`.