11import SystemPackage
22
3+ #if canImport(Darwin)
4+ import Darwin
5+ #elseif canImport(Glibc)
6+ import Glibc
7+ #elseif canImport(Musl)
8+ import Musl
9+ #elseif os(Windows)
10+ import ucrt
11+ import WinSDK
12+ #endif
13+
14+ func currentTimestamp( ) -> WASIAbi . Timestamp {
15+ #if os(Windows)
16+ var ft = FILETIME ( )
17+ GetSystemTimeAsFileTime ( & ft)
18+ let intervals = ( Int64 ( ft. dwHighDateTime) << 32 ) | Int64 ( ft. dwLowDateTime)
19+ let unixIntervals = intervals - 116_444_736_000_000_000
20+ return WASIAbi . Timestamp ( unixIntervals * 100 )
21+ #else
22+ var ts = timespec ( )
23+ clock_gettime ( CLOCK_REALTIME, & ts)
24+ return WASIAbi . Timestamp ( ts. tv_sec) * 1_000_000_000 + WASIAbi. Timestamp ( ts. tv_nsec)
25+ #endif
26+ }
27+
328/// Base protocol for all file system nodes in memory.
429protocol MemFSNode : AnyObject {
530 var type : MemFSNodeType { get }
@@ -17,22 +42,62 @@ final class MemoryDirectoryNode: MemFSNode {
1742 let type : MemFSNodeType = . directory
1843 private var children : [ String : MemFSNode ] = [ : ]
1944
20- init ( ) { }
45+ private var _atim : WASIAbi . Timestamp
46+ private var _mtim : WASIAbi . Timestamp
47+ private var _ctim : WASIAbi . Timestamp
48+
49+ init ( ) {
50+ let now = currentTimestamp ( )
51+ self . _atim = now
52+ self . _mtim = now
53+ self . _ctim = now
54+ }
55+
56+ var timestamps : ( atim: WASIAbi . Timestamp , mtim: WASIAbi . Timestamp , ctim: WASIAbi . Timestamp ) {
57+ return ( _atim, _mtim, _ctim)
58+ }
59+
60+ func touchAccessTime( ) {
61+ _atim = currentTimestamp ( )
62+ }
63+
64+ func touchModificationTime( ) {
65+ let now = currentTimestamp ( )
66+ _mtim = now
67+ _ctim = now
68+ }
69+
70+ func setTimes( atim: WASIAbi . Timestamp ? , mtim: WASIAbi . Timestamp ? ) {
71+ let now = currentTimestamp ( )
72+ if let atim = atim {
73+ _atim = atim
74+ }
75+ if let mtim = mtim {
76+ _mtim = mtim
77+ }
78+ _ctim = now
79+ }
2180
2281 func getChild( name: String ) -> MemFSNode ? {
2382 return children [ name]
2483 }
2584
2685 func setChild( name: String , node: MemFSNode ) {
2786 children [ name] = node
87+ touchModificationTime ( )
2888 }
2989
3090 @discardableResult
3191 func removeChild( name: String ) -> Bool {
32- return children. removeValue ( forKey: name) != nil
92+ let removed = children. removeValue ( forKey: name) != nil
93+ if removed {
94+ touchModificationTime ( )
95+ }
96+ return removed
3397 }
3498
3599 func listChildren( ) -> [ String ] {
100+ touchAccessTime ( )
36101 return Array ( children. keys) . sorted ( )
37102 }
38103
@@ -46,8 +111,16 @@ final class MemoryFileNode: MemFSNode {
46111 let type : MemFSNodeType = . file
47112 var content : FileContent
48113
114+ private var _atim : WASIAbi . Timestamp
115+ private var _mtim : WASIAbi . Timestamp
116+ private var _ctim : WASIAbi . Timestamp
117+
49118 init ( content: FileContent ) {
50119 self . content = content
120+ let now = currentTimestamp ( )
121+ self . _atim = now
122+ self . _mtim = now
123+ self . _ctim = now
51124 }
52125
53126 convenience init ( bytes: some Sequence < UInt8 > ) {
@@ -71,6 +144,56 @@ final class MemoryFileNode: MemFSNode {
71144 }
72145 }
73146 }
147+
148+ var timestamps : ( atim: WASIAbi . Timestamp , mtim: WASIAbi . Timestamp , ctim: WASIAbi . Timestamp ) {
149+ switch content {
150+ case . bytes:
151+ return ( _atim, _mtim, _ctim)
152+ case . handle( let fd) :
153+ do {
154+ let attrs = try fd. attributes ( )
155+ let atim =
156+ WASIAbi . Timestamp ( attrs. accessTime. seconds) * 1_000_000_000
157+ + WASIAbi. Timestamp ( attrs. accessTime. nanoseconds)
158+ let mtim =
159+ WASIAbi . Timestamp ( attrs. modificationTime. seconds) * 1_000_000_000
160+ + WASIAbi. Timestamp ( attrs. modificationTime. nanoseconds)
161+ let ctim =
162+ WASIAbi . Timestamp ( attrs. creationTime. seconds) * 1_000_000_000
163+ + WASIAbi. Timestamp ( attrs. creationTime. nanoseconds)
164+ return ( atim, mtim, ctim)
165+ } catch {
166+ return ( 0 , 0 , 0 )
167+ }
168+ }
169+ }
170+
171+ func touchAccessTime( ) {
172+ if case . bytes = content {
173+ _atim = currentTimestamp ( )
174+ }
175+ }
176+
177+ func touchModificationTime( ) {
178+ if case . bytes = content {
179+ let now = currentTimestamp ( )
180+ _mtim = now
181+ _ctim = now
182+ }
183+ }
184+
185+ func setTimes( atim: WASIAbi . Timestamp ? , mtim: WASIAbi . Timestamp ? ) {
186+ if case . bytes = content {
187+ let now = currentTimestamp ( )
188+ if let atim = atim {
189+ _atim = atim
190+ }
191+ if let mtim = mtim {
192+ _mtim = mtim
193+ }
194+ _ctim = now
195+ }
196+ }
74197}
75198
76199/// A character device node in the memory file system.
@@ -183,7 +306,6 @@ final class MemoryCharacterDeviceEntry: WASIFile {
183306
184307 switch deviceNode. kind {
185308 case . null:
186- // /dev/null discards all writes but reports them as successful
187309 var totalBytes : UInt32 = 0
188310 for iovec in buffer {
189311 iovec. withHostBufferPointer { bufferPtr in
@@ -205,7 +327,6 @@ final class MemoryCharacterDeviceEntry: WASIFile {
205327
206328 switch deviceNode. kind {
207329 case . null:
208- // /dev/null always returns EOF (0 bytes read)
209330 return 0
210331 }
211332 }
0 commit comments