Skip to content

Commit 87a9135

Browse files
committed
Auto merge of rust-lang#117459 - matthiaskrgr:rollup-t3osb3c, r=matthiaskrgr
Rollup of 5 pull requests Successful merges: - rust-lang#113241 (rustdoc: Document lack of object safety on affected traits) - rust-lang#117388 (Turn const_caller_location from a query to a hook) - rust-lang#117417 (Add a stable MIR visitor) - rust-lang#117439 (prepopulate opaque ty storage before using it) - rust-lang#117451 (Add support for pre-unix-epoch file dates on Apple platforms (rust-lang#108277)) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 4b4a5ae + 2e4a38f commit 87a9135

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

std/src/fs/tests.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,6 +1708,48 @@ fn test_file_times() {
17081708
}
17091709
}
17101710

1711+
#[test]
1712+
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "tvos", target_os = "watchos"))]
1713+
fn test_file_times_pre_epoch_with_nanos() {
1714+
#[cfg(target_os = "ios")]
1715+
use crate::os::ios::fs::FileTimesExt;
1716+
#[cfg(target_os = "macos")]
1717+
use crate::os::macos::fs::FileTimesExt;
1718+
#[cfg(target_os = "tvos")]
1719+
use crate::os::tvos::fs::FileTimesExt;
1720+
#[cfg(target_os = "watchos")]
1721+
use crate::os::watchos::fs::FileTimesExt;
1722+
1723+
let tmp = tmpdir();
1724+
let file = File::create(tmp.join("foo")).unwrap();
1725+
1726+
for (accessed, modified, created) in [
1727+
// The first round is to set filetimes to something we know works, but this time
1728+
// it's validated with nanoseconds as well which probe the numeric boundary.
1729+
(
1730+
SystemTime::UNIX_EPOCH + Duration::new(12345, 1),
1731+
SystemTime::UNIX_EPOCH + Duration::new(54321, 100_000_000),
1732+
SystemTime::UNIX_EPOCH + Duration::new(32123, 999_999_999),
1733+
),
1734+
// The second rounds uses pre-epoch dates along with nanoseconds that probe
1735+
// the numeric boundary.
1736+
(
1737+
SystemTime::UNIX_EPOCH - Duration::new(1, 1),
1738+
SystemTime::UNIX_EPOCH - Duration::new(60, 100_000_000),
1739+
SystemTime::UNIX_EPOCH - Duration::new(3600, 999_999_999),
1740+
),
1741+
] {
1742+
let mut times = FileTimes::new();
1743+
times = times.set_accessed(accessed).set_modified(modified).set_created(created);
1744+
file.set_times(times).unwrap();
1745+
1746+
let metadata = file.metadata().unwrap();
1747+
assert_eq!(metadata.accessed().unwrap(), accessed);
1748+
assert_eq!(metadata.modified().unwrap(), modified);
1749+
assert_eq!(metadata.created().unwrap(), created);
1750+
}
1751+
}
1752+
17111753
#[test]
17121754
#[cfg(windows)]
17131755
fn windows_unix_socket_exists() {

std/src/sys/unix/time.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,30 @@ impl Timespec {
7676
}
7777

7878
const fn new(tv_sec: i64, tv_nsec: i64) -> Timespec {
79+
// On Apple OS, dates before epoch are represented differently than on other
80+
// Unix platforms: e.g. 1/10th of a second before epoch is represented as `seconds=-1`
81+
// and `nanoseconds=100_000_000` on other platforms, but is `seconds=0` and
82+
// `nanoseconds=-900_000_000` on Apple OS.
83+
//
84+
// To compensate, we first detect this special case by checking if both
85+
// seconds and nanoseconds are in range, and then correct the value for seconds
86+
// and nanoseconds to match the common unix representation.
87+
//
88+
// Please note that Apple OS nonetheless accepts the standard unix format when
89+
// setting file times, which makes this compensation round-trippable and generally
90+
// transparent.
91+
#[cfg(any(
92+
target_os = "macos",
93+
target_os = "ios",
94+
target_os = "tvos",
95+
target_os = "watchos"
96+
))]
97+
let (tv_sec, tv_nsec) =
98+
if (tv_sec <= 0 && tv_sec > i64::MIN) && (tv_nsec < 0 && tv_nsec > -1_000_000_000) {
99+
(tv_sec - 1, tv_nsec + 1_000_000_000)
100+
} else {
101+
(tv_sec, tv_nsec)
102+
};
79103
assert!(tv_nsec >= 0 && tv_nsec < NSEC_PER_SEC as i64);
80104
// SAFETY: The assert above checks tv_nsec is within the valid range
81105
Timespec { tv_sec, tv_nsec: unsafe { Nanoseconds(tv_nsec as u32) } }

0 commit comments

Comments
 (0)