WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 0dbb632

Browse files
committed
Use st_birthtimespec instead of st_ctim.tv_sec on Darwin
st_ctim records the last time the inode changed. Closest thing on linux, but st_birthtimespec is what we actually want here.
1 parent 3f8118c commit 0dbb632

File tree

2 files changed

+19
-1
lines changed

2 files changed

+19
-1
lines changed

Sources/FoundationEssentials/FileManager/FileManager+Files.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ extension stat {
155155

156156
var creationDate: Date {
157157
#if canImport(Darwin)
158-
Date(seconds: TimeInterval(st_ctimespec.tv_sec), nanoSeconds: TimeInterval(st_ctimespec.tv_nsec))
158+
Date(seconds: TimeInterval(st_birthtimespec.tv_sec), nanoSeconds: TimeInterval(st_birthtimespec.tv_nsec))
159159
#else
160160
Date(seconds: TimeInterval(st_ctim.tv_sec), nanoSeconds: TimeInterval(st_ctim.tv_nsec))
161161
#endif

Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,24 @@ private struct FileManagerTests {
10931093
}
10941094
#endif
10951095

1096+
@Test(.enabled(if: isDarwin, "Birth time is only exposed on Darwin"))
1097+
func creationDateUsesBirthTime() async throws {
1098+
try await FilePlayground {
1099+
File("file")
1100+
}.test { fileManager in
1101+
let attrs1 = try fileManager.attributesOfItem(atPath: "file")
1102+
let creation1 = try #require(attrs1[.creationDate] as? Date)
1103+
1104+
// Mutate metadata to advance ctime without touching birth time
1105+
try fileManager.setAttributes([.posixPermissions: 0o600], ofItemAtPath: "file")
1106+
1107+
let attrs2 = try fileManager.attributesOfItem(atPath: "file")
1108+
let creation2 = try #require(attrs2[.creationDate] as? Date)
1109+
1110+
#expect(creation1 == creation2, "Creation date should remain stable when metadata changes (uses birth time, not ctime)")
1111+
}
1112+
}
1113+
10961114
#if canImport(Darwin)
10971115
@Test func SearchPathsWithoutExpandingTilde() async throws {
10981116
for path in _DarwinSearchPaths(for: .libraryDirectory, in: .userDomainMask, expandTilde: false) {

0 commit comments

Comments
 (0)