Skip to content

Commit df8d936

Browse files
author
wasim-builds
committed
feat: Add one-shot attribute methods to FileSystemProtocol
Fixes #3648
1 parent 48119db commit df8d936

4 files changed

Lines changed: 155 additions & 2 deletions

File tree

Sources/NIOCore/SocketAddresses.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,21 @@ private typealias in_port_t = WinSDK.u_short
4444
private typealias sa_family_t = WinSDK.ADDRESS_FAMILY
4545
#elseif canImport(Darwin)
4646
import Darwin
47-
#elseif os(Linux) || os(Android) || os(FreeBSD) || os(OpenBSD)
47+
#elseif os(Linux) || os(Android)
4848
#if canImport(Glibc)
4949
@preconcurrency import Glibc
5050
#elseif canImport(Musl)
5151
@preconcurrency import Musl
5252
#elseif canImport(Android)
5353
@preconcurrency import Android
54-
#endif // canImport(Glibc)
54+
#endif
55+
import CNIOLinux
56+
#elseif os(FreeBSD)
57+
@preconcurrency import Glibc
58+
import CNIOFreeBSD
59+
#elseif os(OpenBSD)
60+
@preconcurrency import Glibc
61+
import CNIOOpenBSD
5562
#elseif canImport(WASILibc)
5663
@preconcurrency import WASILibc
5764
#else

Sources/NIOFS/FileSystemProtocol.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,3 +683,48 @@ extension FileSystemProtocol {
683683
}
684684
}
685685
}
686+
687+
// MARK: - File attributes
688+
689+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
690+
extension FileSystemProtocol {
691+
/// Sets the file's last access and last data modification times to the given times.
692+
///
693+
/// - Parameters:
694+
/// - path: The path of the file to modify.
695+
/// - lastAccess: The new value of the file's last access time, as time elapsed since the Epoch.
696+
/// - lastDataModification: The new value of the file's last data modification time, as time elapsed since the Epoch.
697+
public func setTimes(
698+
forFileAt path: NIOFilePath,
699+
lastAccess: FileInfo.Timespec?,
700+
lastDataModification: FileInfo.Timespec?
701+
) async throws {
702+
try await self.withFileHandle(forReadingAt: path) { handle in
703+
try await handle.setTimes(lastAccess: lastAccess, lastDataModification: lastDataModification)
704+
}
705+
}
706+
707+
/// Sets the file's last access time to the given time.
708+
///
709+
/// - Parameters:
710+
/// - path: The path of the file to modify.
711+
/// - time: The time to which the file's last access time should be set.
712+
public func setLastAccessTime(
713+
forFileAt path: NIOFilePath,
714+
to time: FileInfo.Timespec
715+
) async throws {
716+
try await self.setTimes(forFileAt: path, lastAccess: time, lastDataModification: nil)
717+
}
718+
719+
/// Sets the file's last data modification time to the given time.
720+
///
721+
/// - Parameters:
722+
/// - path: The path of the file to modify.
723+
/// - time: The time to which the file's last data modification time should be set.
724+
public func setLastDataModificationTime(
725+
forFileAt path: NIOFilePath,
726+
to time: FileInfo.Timespec
727+
) async throws {
728+
try await self.setTimes(forFileAt: path, lastAccess: nil, lastDataModification: time)
729+
}
730+
}

Sources/_NIOFileSystem/FileSystemProtocol.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,3 +776,48 @@ extension FileSystemProtocol {
776776
}
777777
}
778778
}
779+
780+
// MARK: - File attributes
781+
782+
@available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *)
783+
extension FileSystemProtocol {
784+
/// Sets the file's last access and last data modification times to the given times.
785+
///
786+
/// - Parameters:
787+
/// - path: The path of the file to modify.
788+
/// - lastAccess: The new value of the file's last access time, as time elapsed since the Epoch.
789+
/// - lastDataModification: The new value of the file's last data modification time, as time elapsed since the Epoch.
790+
public func setTimes(
791+
forFileAt path: NIOFilePath,
792+
lastAccess: FileInfo.Timespec?,
793+
lastDataModification: FileInfo.Timespec?
794+
) async throws {
795+
try await self.withFileHandle(forReadingAt: path) { handle in
796+
try await handle.setTimes(lastAccess: lastAccess, lastDataModification: lastDataModification)
797+
}
798+
}
799+
800+
/// Sets the file's last access time to the given time.
801+
///
802+
/// - Parameters:
803+
/// - path: The path of the file to modify.
804+
/// - time: The time to which the file's last access time should be set.
805+
public func setLastAccessTime(
806+
forFileAt path: NIOFilePath,
807+
to time: FileInfo.Timespec
808+
) async throws {
809+
try await self.setTimes(forFileAt: path, lastAccess: time, lastDataModification: nil)
810+
}
811+
812+
/// Sets the file's last data modification time to the given time.
813+
///
814+
/// - Parameters:
815+
/// - path: The path of the file to modify.
816+
/// - time: The time to which the file's last data modification time should be set.
817+
public func setLastDataModificationTime(
818+
forFileAt path: NIOFilePath,
819+
to time: FileInfo.Timespec
820+
) async throws {
821+
try await self.setTimes(forFileAt: path, lastAccess: nil, lastDataModification: time)
822+
}
823+
}

Tests/NIOFSIntegrationTests/FileSystemTests.swift

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,62 @@ final class FileSystemTests: XCTestCase {
7070

7171
var fs: FileSystem { .shared }
7272

73+
func testSetLastAccessAndDataModificationTimes() async throws {
74+
let path = try await self.fs.temporaryFilePath()
75+
try await self.fs.withFileHandle(forWritingAt: path, options: .newFile(replaceExisting: false)) { _ in }
76+
77+
let originalInfo = try await self.fs.info(forFileAt: path)
78+
let originalLastAccessTime = originalInfo?.lastAccessTime
79+
let originalLastDataModificationTime = originalInfo?.lastDataModificationTime
80+
81+
let newAccessTime = FileInfo.Timespec(seconds: 10, nanoseconds: 5)
82+
let newDataModTime = FileInfo.Timespec(seconds: 20, nanoseconds: 25)
83+
84+
try await self.fs.setTimes(forFileAt: path, lastAccess: newAccessTime, lastDataModification: newDataModTime)
85+
86+
let newInfo = try await self.fs.info(forFileAt: path)
87+
XCTAssertEqual(newInfo?.lastAccessTime, newAccessTime)
88+
XCTAssertEqual(newInfo?.lastDataModificationTime, newDataModTime)
89+
XCTAssertNotEqual(newInfo?.lastAccessTime, originalLastAccessTime)
90+
XCTAssertNotEqual(newInfo?.lastDataModificationTime, originalLastDataModificationTime)
91+
92+
try await self.fs.removeItem(at: path)
93+
}
94+
95+
func testSetLastAccessTime() async throws {
96+
let path = try await self.fs.temporaryFilePath()
97+
try await self.fs.withFileHandle(forWritingAt: path, options: .newFile(replaceExisting: false)) { _ in }
98+
99+
let originalInfo = try await self.fs.info(forFileAt: path)
100+
let originalLastDataModificationTime = originalInfo?.lastDataModificationTime
101+
102+
let newAccessTime = FileInfo.Timespec(seconds: 10, nanoseconds: 5)
103+
try await self.fs.setLastAccessTime(forFileAt: path, to: newAccessTime)
104+
105+
let newInfo = try await self.fs.info(forFileAt: path)
106+
XCTAssertEqual(newInfo?.lastAccessTime, newAccessTime)
107+
XCTAssertEqual(newInfo?.lastDataModificationTime, originalLastDataModificationTime)
108+
109+
try await self.fs.removeItem(at: path)
110+
}
111+
112+
func testSetLastDataModificationTime() async throws {
113+
let path = try await self.fs.temporaryFilePath()
114+
try await self.fs.withFileHandle(forWritingAt: path, options: .newFile(replaceExisting: false)) { _ in }
115+
116+
let originalInfo = try await self.fs.info(forFileAt: path)
117+
let originalLastAccessTime = originalInfo?.lastAccessTime
118+
119+
let newDataModTime = FileInfo.Timespec(seconds: 20, nanoseconds: 25)
120+
try await self.fs.setLastDataModificationTime(forFileAt: path, to: newDataModTime)
121+
122+
let newInfo = try await self.fs.info(forFileAt: path)
123+
XCTAssertEqual(newInfo?.lastDataModificationTime, newDataModTime)
124+
XCTAssertEqual(newInfo?.lastAccessTime, originalLastAccessTime)
125+
126+
try await self.fs.removeItem(at: path)
127+
}
128+
73129
func testOpenFileForReading() async throws {
74130
try await self.fs.withFileHandle(forReadingAt: .testDataReadme) { file in
75131
let info = try await file.info()

0 commit comments

Comments
 (0)