1+ import SystemPackage
2+
3+ /// A WASIDir implementation backed by an in-memory directory node.
4+ internal struct MemoryDirEntry : WASIDir {
5+ let preopenPath : String ?
6+ let dirNode : MemoryDirectoryNode
7+ let path : String
8+ let fileSystem : MemoryFileSystem
9+
10+ func attributes( ) throws -> WASIAbi . Filestat {
11+ return WASIAbi . Filestat (
12+ dev: 0 , ino: 0 , filetype: . DIRECTORY,
13+ nlink: 1 , size: 0 ,
14+ atim: 0 , mtim: 0 , ctim: 0
15+ )
16+ }
17+
18+ func fileType( ) throws -> WASIAbi . FileType {
19+ return . DIRECTORY
20+ }
21+
22+ func status( ) throws -> WASIAbi . Fdflags {
23+ return [ ]
24+ }
25+
26+ func setTimes(
27+ atim: WASIAbi . Timestamp , mtim: WASIAbi . Timestamp ,
28+ fstFlags: WASIAbi . FstFlags
29+ ) throws {
30+ // No-op for memory filesystem - timestamps not tracked
31+ }
32+
33+ func advise(
34+ offset: WASIAbi . FileSize , length: WASIAbi . FileSize , advice: WASIAbi . Advice
35+ ) throws {
36+ // No-op for memory filesystem
37+ }
38+
39+ func close( ) throws {
40+ // No-op for memory filesystem - no resources to release
41+ }
42+
43+ func openFile(
44+ symlinkFollow: Bool ,
45+ path: String ,
46+ oflags: WASIAbi . Oflags ,
47+ accessMode: FileAccessMode ,
48+ fdflags: WASIAbi . Fdflags
49+ ) throws -> FileDescriptor {
50+ // Memory filesystem doesn't return real file descriptors for this method
51+ // File opening is handled through the WASI bridge's path_open implementation
52+ throw WASIAbi . Errno. ENOTSUP
53+ }
54+
55+ func createDirectory( atPath path: String ) throws {
56+ let fullPath = self . path. hasSuffix ( " / " ) ? self . path + path : self . path + " / " + path
57+ try fileSystem. ensureDirectory ( at: fullPath)
58+ }
59+
60+ func removeDirectory( atPath path: String ) throws {
61+ try fileSystem. removeNode ( in: dirNode, at: path, mustBeDirectory: true )
62+ }
63+
64+ func removeFile( atPath path: String ) throws {
65+ try fileSystem. removeNode ( in: dirNode, at: path, mustBeDirectory: false )
66+ }
67+
68+ func symlink( from sourcePath: String , to destPath: String ) throws {
69+ // Symlinks not supported in memory filesystem
70+ throw WASIAbi . Errno. ENOTSUP
71+ }
72+
73+ func rename( from sourcePath: String , toDir newDir: any WASIDir , to destPath: String ) throws {
74+ guard let newMemoryDir = newDir as? MemoryDirEntry else {
75+ throw WASIAbi . Errno. EXDEV
76+ }
77+
78+ try fileSystem. rename (
79+ from: sourcePath, in: dirNode,
80+ to: destPath, in: newMemoryDir. dirNode
81+ )
82+ }
83+
84+ func readEntries( cookie: WASIAbi . DirCookie ) throws -> AnyIterator < Result < ReaddirElement , any Error > > {
85+ let children = dirNode. listChildren ( )
86+
87+ let iterator = children. enumerated ( )
88+ . dropFirst ( Int ( cookie) )
89+ . map { ( index, name) -> Result < ReaddirElement , any Error > in
90+ return Result ( catching: {
91+ let childPath = self . path. hasSuffix ( " / " ) ? self . path + name : self . path + " / " + name
92+ guard let childNode = fileSystem. lookup ( at: childPath) else {
93+ throw WASIAbi . Errno. ENOENT
94+ }
95+
96+ let fileType : WASIAbi . FileType
97+ switch childNode. type {
98+ case . directory: fileType = . DIRECTORY
99+ case . file: fileType = . REGULAR_FILE
100+ case . characterDevice: fileType = . CHARACTER_DEVICE
101+ }
102+
103+ let dirent = WASIAbi . Dirent (
104+ dNext: WASIAbi . DirCookie ( index + 1 ) ,
105+ dIno: 0 ,
106+ dirNameLen: WASIAbi . DirNameLen ( name. utf8. count) ,
107+ dType: fileType
108+ )
109+
110+ return ( dirent, name)
111+ } )
112+ }
113+ . makeIterator ( )
114+
115+ return AnyIterator ( iterator)
116+ }
117+
118+ func attributes( path: String , symlinkFollow: Bool ) throws -> WASIAbi . Filestat {
119+ let fullPath = self . path. hasSuffix ( " / " ) ? self . path + path : self . path + " / " + path
120+ guard let node = fileSystem. lookup ( at: fullPath) else {
121+ throw WASIAbi . Errno. ENOENT
122+ }
123+
124+ let fileType : WASIAbi . FileType
125+ var size : WASIAbi . FileSize = 0
126+
127+ switch node. type {
128+ case . directory:
129+ fileType = . DIRECTORY
130+ case . file:
131+ fileType = . REGULAR_FILE
132+ if let fileNode = node as? MemoryFileNode {
133+ size = WASIAbi . FileSize ( fileNode. size)
134+ }
135+ case . characterDevice:
136+ fileType = . CHARACTER_DEVICE
137+ }
138+
139+ return WASIAbi . Filestat (
140+ dev: 0 , ino: 0 , filetype: fileType,
141+ nlink: 1 , size: size,
142+ atim: 0 , mtim: 0 , ctim: 0
143+ )
144+ }
145+
146+ func setFilestatTimes(
147+ path: String ,
148+ atim: WASIAbi . Timestamp , mtim: WASIAbi . Timestamp ,
149+ fstFlags: WASIAbi . FstFlags , symlinkFollow: Bool
150+ ) throws {
151+ // No-op for memory filesystem - timestamps not tracked
152+ }
153+ }
0 commit comments