Skip to content

Commit

Permalink
Fix compilation on i686-apple-darwin. (#1000)
Browse files Browse the repository at this point in the history
On i686-apple-darwin, `time_t` is 32-bit, so it needs `fix_y2038` and
conversions for `Timespec` values.

Fixes #991.
  • Loading branch information
sunfishcode authored Jan 23, 2024
1 parent 6ec74e0 commit d268591
Showing 1 changed file with 42 additions and 19 deletions.
61 changes: 42 additions & 19 deletions src/backend/libc/fs/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down Expand Up @@ -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`].
Expand All @@ -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,
Expand Down Expand Up @@ -954,7 +956,7 @@ pub(crate) fn utimensat(
}
}

#[cfg(fix_y2038)]
#[cfg(all(fix_y2038, not(apple)))]
fn utimensat_old(
dirfd: BorrowedFd<'_>,
path: &CStr,
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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),
Expand All @@ -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 {
Expand Down Expand Up @@ -2125,7 +2127,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;
Expand All @@ -2134,7 +2136,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 {
Expand All @@ -2150,11 +2153,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 _,
};
}
}

Expand All @@ -2176,19 +2185,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::<c::timespec>();
}
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::<c::timespec>();
}

(times_size, return_times, attrs)
Ok((times_size, return_times, attrs))
}

/// Support type for `Attrlist`.
Expand Down

0 comments on commit d268591

Please sign in to comment.