Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions Sources/tart/URL+AccessDate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@ extension URL {
}

func updateAccessDate(_ accessDate: Date = Date()) throws {
let attrs = try resourceValues(forKeys: [.contentAccessDateKey])
let modificationDate = attrs.contentAccessDate!

let times = [accessDate.asTimeval(), modificationDate.asTimeval()]
let ret = utimes(path, times)
let times = [accessDate.asTimespec(), timespec(tv_sec: 0, tv_nsec: Int(UTIME_OMIT))]
let ret = utimensat(AT_FDCWD, path, times, 0)
if ret != 0 {
let details = Errno(rawValue: CInt(errno))

throw RuntimeError.FailedToUpdateAccessDate("utimes(2) failed: \(details)")
throw RuntimeError.FailedToUpdateAccessDate("utimensat(2) failed: \(details)")
}
}
}

extension Date {
func asTimeval() -> timeval {
timeval(tv_sec: Int(timeIntervalSince1970), tv_usec: 0)
func asTimespec() -> timespec {
let seconds = floor(timeIntervalSince1970)
let nanoseconds = (timeIntervalSince1970 - seconds) * 1_000_000_000

return timespec(tv_sec: Int(seconds), tv_nsec: Int(nanoseconds))
}
}
20 changes: 14 additions & 6 deletions Tests/TartTests/URLAccessDateTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,29 @@ import XCTest
@testable import tart

final class URLAccessDateTests: XCTestCase {
func testGetAndSetAccessTime() throws {
func testUpdateAccessDatePreservesModificationDate() throws {
// Create a temporary file
let tmpDir = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
var tmpFile = tmpDir.appendingPathComponent(UUID().uuidString)
FileManager.default.createFile(atPath: tmpFile.path, contents: nil)
defer { try? FileManager.default.removeItem(at: tmpFile) }

// Ensure it's access date is different than our desired access date
let arbitraryDate = Date.init(year: 2008, month: 09, day: 28, hour: 23, minute: 15)
XCTAssertNotEqual(arbitraryDate, try tmpFile.accessDate())
// Ensure its access date is different from our desired access date
let accessDate = Date.init(year: 2008, month: 09, day: 28, hour: 23, minute: 15)
let modificationDate = Date(timeIntervalSince1970: 1_577_836_800.125)
try FileManager.default.setAttributes([.modificationDate: modificationDate], ofItemAtPath: tmpFile.path)
XCTAssertNotEqual(accessDate, try tmpFile.accessDate())

// Set our desired access date for a file
try tmpFile.updateAccessDate(arbitraryDate)
try tmpFile.updateAccessDate(accessDate)

// Ensure the access date has changed to our value
tmpFile.removeCachedResourceValue(forKey: .contentAccessDateKey)
XCTAssertEqual(arbitraryDate, try tmpFile.accessDate())
XCTAssertEqual(accessDate, try tmpFile.accessDate())

// Ensure the modification date has not changed
tmpFile.removeCachedResourceValue(forKey: .contentModificationDateKey)
let attrs = try tmpFile.resourceValues(forKeys: [.contentModificationDateKey])
XCTAssertEqual(modificationDate, try XCTUnwrap(attrs.contentModificationDate))
}
}