Skip to content

Commit 378d1bf

Browse files
Auto merge of #147504 - joshtriplett:file-times-helpers, r=<try>
Factor out helpers for file times
2 parents 61efd19 + 1bf555c commit 378d1bf

File tree

1 file changed

+73
-42
lines changed

1 file changed

+73
-42
lines changed

library/std/src/sys/fs/unix.rs

Lines changed: 73 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1604,24 +1604,6 @@ impl File {
16041604
}
16051605

16061606
pub fn set_times(&self, times: FileTimes) -> io::Result<()> {
1607-
#[cfg(not(any(
1608-
target_os = "redox",
1609-
target_os = "espidf",
1610-
target_os = "horizon",
1611-
target_os = "nuttx",
1612-
)))]
1613-
let to_timespec = |time: Option<SystemTime>| match time {
1614-
Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts),
1615-
Some(time) if time > crate::sys::time::UNIX_EPOCH => Err(io::const_error!(
1616-
io::ErrorKind::InvalidInput,
1617-
"timestamp is too large to set as a file time",
1618-
)),
1619-
Some(_) => Err(io::const_error!(
1620-
io::ErrorKind::InvalidInput,
1621-
"timestamp is too small to set as a file time",
1622-
)),
1623-
None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }),
1624-
};
16251607
cfg_select! {
16261608
any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx") => {
16271609
// Redox doesn't appear to support `UTIME_OMIT`.
@@ -1634,36 +1616,18 @@ impl File {
16341616
))
16351617
}
16361618
target_vendor = "apple" => {
1637-
let mut buf = [mem::MaybeUninit::<libc::timespec>::uninit(); 3];
1638-
let mut num_times = 0;
1639-
let mut attrlist: libc::attrlist = unsafe { mem::zeroed() };
1640-
attrlist.bitmapcount = libc::ATTR_BIT_MAP_COUNT;
1641-
if times.created.is_some() {
1642-
buf[num_times].write(to_timespec(times.created)?);
1643-
num_times += 1;
1644-
attrlist.commonattr |= libc::ATTR_CMN_CRTIME;
1645-
}
1646-
if times.modified.is_some() {
1647-
buf[num_times].write(to_timespec(times.modified)?);
1648-
num_times += 1;
1649-
attrlist.commonattr |= libc::ATTR_CMN_MODTIME;
1650-
}
1651-
if times.accessed.is_some() {
1652-
buf[num_times].write(to_timespec(times.accessed)?);
1653-
num_times += 1;
1654-
attrlist.commonattr |= libc::ATTR_CMN_ACCTIME;
1655-
}
1619+
let ta = TimesAttrlist::from_times(&times)?;
16561620
cvt(unsafe { libc::fsetattrlist(
16571621
self.as_raw_fd(),
1658-
(&raw const attrlist).cast::<libc::c_void>().cast_mut(),
1659-
buf.as_ptr().cast::<libc::c_void>().cast_mut(),
1660-
num_times * size_of::<libc::timespec>(),
1622+
ta.attrlist(),
1623+
ta.times_buf(),
1624+
ta.times_buf_size(),
16611625
0
16621626
) })?;
16631627
Ok(())
16641628
}
16651629
target_os = "android" => {
1666-
let times = [to_timespec(times.accessed)?, to_timespec(times.modified)?];
1630+
let times = [file_time_to_timespec(times.accessed)?, file_time_to_timespec(times.modified)?];
16671631
// futimens requires Android API level 19
16681632
cvt(unsafe {
16691633
weak!(
@@ -1697,14 +1661,81 @@ impl File {
16971661
return Ok(());
16981662
}
16991663
}
1700-
let times = [to_timespec(times.accessed)?, to_timespec(times.modified)?];
1664+
let times = [file_time_to_timespec(times.accessed)?, file_time_to_timespec(times.modified)?];
17011665
cvt(unsafe { libc::futimens(self.as_raw_fd(), times.as_ptr()) })?;
17021666
Ok(())
17031667
}
17041668
}
17051669
}
17061670
}
17071671

1672+
#[cfg(not(any(
1673+
target_os = "redox",
1674+
target_os = "espidf",
1675+
target_os = "horizon",
1676+
target_os = "nuttx",
1677+
)))]
1678+
fn file_time_to_timespec(time: Option<SystemTime>) -> io::Result<libc::timespec> {
1679+
match time {
1680+
Some(time) if let Some(ts) = time.t.to_timespec() => Ok(ts),
1681+
Some(time) if time > crate::sys::time::UNIX_EPOCH => Err(io::const_error!(
1682+
io::ErrorKind::InvalidInput,
1683+
"timestamp is too large to set as a file time",
1684+
)),
1685+
Some(_) => Err(io::const_error!(
1686+
io::ErrorKind::InvalidInput,
1687+
"timestamp is too small to set as a file time",
1688+
)),
1689+
None => Ok(libc::timespec { tv_sec: 0, tv_nsec: libc::UTIME_OMIT as _ }),
1690+
}
1691+
}
1692+
1693+
#[cfg(target_vendor = "apple")]
1694+
struct TimesAttrlist {
1695+
buf: [mem::MaybeUninit<libc::timespec>; 3],
1696+
attrlist: libc::attrlist,
1697+
num_times: usize,
1698+
}
1699+
1700+
#[cfg(target_vendor = "apple")]
1701+
impl TimesAttrlist {
1702+
fn from_times(times: &FileTimes) -> io::Result<Self> {
1703+
let mut this = Self {
1704+
buf: [mem::MaybeUninit::<libc::timespec>::uninit(); 3],
1705+
attrlist: unsafe { mem::zeroed() },
1706+
num_times: 0,
1707+
};
1708+
this.attrlist.bitmapcount = libc::ATTR_BIT_MAP_COUNT;
1709+
if times.created.is_some() {
1710+
this.buf[this.num_times].write(file_time_to_timespec(times.created)?);
1711+
this.num_times += 1;
1712+
attrlist.commonattr |= libc::ATTR_CMN_CRTIME;
1713+
}
1714+
if times.modified.is_some() {
1715+
this.buf[this.num_times].write(file_time_to_timespec(times.modified)?);
1716+
this.num_times += 1;
1717+
attrlist.commonattr |= libc::ATTR_CMN_MODTIME;
1718+
}
1719+
if times.accessed.is_some() {
1720+
this.buf[this.num_times].write(file_time_to_timespec(times.accessed)?);
1721+
this.num_times += 1;
1722+
attrlist.commonattr |= libc::ATTR_CMN_ACCTIME;
1723+
}
1724+
}
1725+
1726+
fn attrlist(&self) -> *mut libc::c_void {
1727+
(&raw const self.attrlist).cast::<libc::c_void>().cast_mut()
1728+
}
1729+
1730+
fn times_buf(&self) -> *mut libc::c_void {
1731+
self.buf.as_ptr().cast::<libc::c_void>().cast_mut()
1732+
}
1733+
1734+
fn times_buf_size(&self) -> usize {
1735+
self.num_times * size_of::<libc::timespec>()
1736+
}
1737+
}
1738+
17081739
impl DirBuilder {
17091740
pub fn new() -> DirBuilder {
17101741
DirBuilder { mode: 0o777 }

0 commit comments

Comments
 (0)