Skip to content

Commit 5f2922f

Browse files
committed
Adopt utimensat for setting file modification dates
1 parent cb06baa commit 5f2922f

File tree

2 files changed

+26
-9
lines changed

2 files changed

+26
-9
lines changed

Sources/FoundationEssentials/FileManager/FileManager+Files.swift

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -965,15 +965,15 @@ extension _FileManagerImpl {
965965

966966
if let date = attributes[.modificationDate] as? Date {
967967
let (isecs, fsecs) = modf(date.timeIntervalSince1970)
968-
if let tv_sec = time_t(exactly: isecs),
969-
let tv_usec = suseconds_t(exactly: round(fsecs * 1000000.0)) {
970-
var timevals = (timeval(), timeval())
971-
timevals.0.tv_sec = tv_sec
972-
timevals.0.tv_usec = tv_usec
973-
timevals.1 = timevals.0
974-
try withUnsafePointer(to: timevals) {
975-
try $0.withMemoryRebound(to: timeval.self, capacity: 2) {
976-
if utimes(fileSystemRepresentation, $0) != 0 {
968+
if let tv_sec = Int(exactly: isecs),
969+
let tv_nsec = Int(exactly: round(fsecs * 1000000000.0)) {
970+
var timespecs = (timespec(), timespec())
971+
timespecs.0.tv_sec = tv_sec
972+
timespecs.0.tv_nsec = tv_nsec
973+
timespecs.1 = timespecs.0
974+
try withUnsafePointer(to: timespecs) {
975+
try $0.withMemoryRebound(to: timespec.self, capacity: 2) {
976+
if utimensat(AT_FDCWD, fileSystemRepresentation, $0, 0) != 0 {
977977
throw CocoaError.errorWithFilePath(path, errno: errno, reading: false)
978978
}
979979
}

Tests/FoundationEssentialsTests/FileManager/FileManagerTests.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,23 @@ final class FileManagerTests : XCTestCase {
793793
}
794794
}
795795

796+
func testNanosecondModificationDate() throws {
797+
try FileManagerPlayground {
798+
"foo"
799+
}.test {
800+
#if os(Windows)
801+
// Windows supports 100-nanosecond precision (10 seconds + 300 nano seconds)
802+
let date = Date(timeIntervalSince1970: 10.0000003)
803+
#else
804+
// non-Windows supports nanosecond precision (10 seconds + 3 nano seconds)
805+
let date = Date(timeIntervalSince1970: 10.000000003)
806+
#endif
807+
try $0.setAttributes([.modificationDate : date], ofItemAtPath: "foo")
808+
let readDate = try $0.attributesOfItem(atPath: "foo")[.modificationDate] as? Date
809+
XCTAssertEqual(readDate, date)
810+
}
811+
}
812+
796813
func testImplicitlyConvertibleFileAttributes() throws {
797814
try FileManagerPlayground {
798815
File("foo", attributes: [.posixPermissions : UInt16(0o644)])

0 commit comments

Comments
 (0)