Skip to content

Commit ff46f85

Browse files
committed
fixups
1 parent fe1b938 commit ff46f85

File tree

4 files changed

+178
-28
lines changed

4 files changed

+178
-28
lines changed

Sources/SystemExtras/FileOperations.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,10 @@ extension FileDescriptor {
249249

250250
@_alwaysEmitIntoClient
251251
public var device: UInt64 {
252-
UInt64(rawValue.st_dev)
252+
if (rawValue.st_dev < 0) {
253+
return UInt64(bitPattern: Int64(rawValue.st_dev))
254+
}
255+
return UInt64(rawValue.st_dev)
253256
}
254257

255258
@_alwaysEmitIntoClient

Sources/WASI/MemoryFileSystem/MemoryFSNodes.swift

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,131 @@ internal final class MemoryCharacterDeviceNode: MemFSNode {
8686
init(kind: Kind) {
8787
self.kind = kind
8888
}
89+
}
90+
91+
/// A WASIFile implementation for character devices like /dev/null
92+
internal final class MemoryCharacterDeviceEntry: WASIFile {
93+
let deviceNode: MemoryCharacterDeviceNode
94+
let accessMode: FileAccessMode
95+
96+
init(deviceNode: MemoryCharacterDeviceNode, accessMode: FileAccessMode) {
97+
self.deviceNode = deviceNode
98+
self.accessMode = accessMode
99+
}
100+
101+
// MARK: - WASIEntry
102+
103+
func attributes() throws -> WASIAbi.Filestat {
104+
return WASIAbi.Filestat(
105+
dev: 0, ino: 0, filetype: .CHARACTER_DEVICE,
106+
nlink: 1, size: 0,
107+
atim: 0, mtim: 0, ctim: 0
108+
)
109+
}
110+
111+
func fileType() throws -> WASIAbi.FileType {
112+
return .CHARACTER_DEVICE
113+
}
114+
115+
func status() throws -> WASIAbi.Fdflags {
116+
return []
117+
}
118+
119+
func setTimes(
120+
atim: WASIAbi.Timestamp, mtim: WASIAbi.Timestamp,
121+
fstFlags: WASIAbi.FstFlags
122+
) throws {
123+
// No-op for character devices
124+
}
125+
126+
func advise(
127+
offset: WASIAbi.FileSize, length: WASIAbi.FileSize, advice: WASIAbi.Advice
128+
) throws {
129+
// No-op for character devices
130+
}
131+
132+
func close() throws {
133+
// No-op for character devices
134+
}
135+
136+
// MARK: - WASIFile
137+
138+
func fdStat() throws -> WASIAbi.FdStat {
139+
var fsRightsBase: WASIAbi.Rights = []
140+
if accessMode.contains(.read) {
141+
fsRightsBase.insert(.FD_READ)
142+
}
143+
if accessMode.contains(.write) {
144+
fsRightsBase.insert(.FD_WRITE)
145+
}
146+
147+
return WASIAbi.FdStat(
148+
fsFileType: .CHARACTER_DEVICE,
149+
fsFlags: [],
150+
fsRightsBase: fsRightsBase,
151+
fsRightsInheriting: []
152+
)
153+
}
154+
155+
func setFdStatFlags(_ flags: WASIAbi.Fdflags) throws {
156+
// No-op for character devices
157+
}
158+
159+
func setFilestatSize(_ size: WASIAbi.FileSize) throws {
160+
throw WASIAbi.Errno.EINVAL
161+
}
162+
163+
func sync() throws {
164+
// No-op for character devices
165+
}
166+
167+
func datasync() throws {
168+
// No-op for character devices
169+
}
170+
171+
func tell() throws -> WASIAbi.FileSize {
172+
return 0
173+
}
174+
175+
func seek(offset: WASIAbi.FileDelta, whence: WASIAbi.Whence) throws -> WASIAbi.FileSize {
176+
throw WASIAbi.Errno.ESPIPE
177+
}
178+
179+
func write<Buffer: Sequence>(vectored buffer: Buffer) throws -> WASIAbi.Size where Buffer.Element == WASIAbi.IOVec {
180+
guard accessMode.contains(.write) else {
181+
throw WASIAbi.Errno.EBADF
182+
}
183+
184+
switch deviceNode.kind {
185+
case .null:
186+
// /dev/null discards all writes but reports them as successful
187+
var totalBytes: UInt32 = 0
188+
for iovec in buffer {
189+
iovec.withHostBufferPointer { bufferPtr in
190+
totalBytes += UInt32(bufferPtr.count)
191+
}
192+
}
193+
return totalBytes
194+
}
195+
}
196+
197+
func pwrite<Buffer: Sequence>(vectored buffer: Buffer, offset: WASIAbi.FileSize) throws -> WASIAbi.Size where Buffer.Element == WASIAbi.IOVec {
198+
throw WASIAbi.Errno.ESPIPE
199+
}
200+
201+
func read<Buffer: Sequence>(into buffer: Buffer) throws -> WASIAbi.Size where Buffer.Element == WASIAbi.IOVec {
202+
guard accessMode.contains(.read) else {
203+
throw WASIAbi.Errno.EBADF
204+
}
205+
206+
switch deviceNode.kind {
207+
case .null:
208+
// /dev/null always returns EOF (0 bytes read)
209+
return 0
210+
}
211+
}
212+
213+
func pread<Buffer: Sequence>(into buffer: Buffer, offset: WASIAbi.FileSize) throws -> WASIAbi.Size where Buffer.Element == WASIAbi.IOVec {
214+
throw WASIAbi.Errno.ESPIPE
215+
}
89216
}

Sources/WASI/MemoryFileSystem/MemoryFileSystem.swift

Lines changed: 46 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import SystemPackage
1818
/// ```
1919
public final class MemoryFileSystem: FileSystemProvider, FileSystem {
2020
private static let rootPath = "/"
21-
21+
2222
private var root: MemoryDirectoryNode
2323
private let preopenPaths: [String]
2424

@@ -45,7 +45,7 @@ public final class MemoryFileSystem: FileSystemProvider, FileSystem {
4545
}
4646

4747
// MARK: - FileSystemProvider (Public API)
48-
48+
4949
/// Adds a file to the file system with the given byte content.
5050
///
5151
/// - Parameters:
@@ -114,28 +114,28 @@ public final class MemoryFileSystem: FileSystemProvider, FileSystem {
114114
}
115115

116116
// MARK: - FileSystem (Internal WASI API)
117-
117+
118118
internal func getPreopenPaths() -> [String] {
119119
return preopenPaths
120120
}
121-
121+
122122
internal func openDirectory(at path: String) throws -> any WASIDir {
123123
guard let node = lookup(at: path) else {
124124
throw WASIAbi.Errno.ENOENT
125125
}
126-
126+
127127
guard let dirNode = node as? MemoryDirectoryNode else {
128128
throw WASIAbi.Errno.ENOTDIR
129129
}
130-
130+
131131
return MemoryDirEntry(
132132
preopenPath: preopenPaths.contains(path) ? path : nil,
133133
dirNode: dirNode,
134134
path: path,
135135
fileSystem: self
136136
)
137137
}
138-
138+
139139
internal func openAt(
140140
dirFd: any WASIDir,
141141
path: String,
@@ -148,11 +148,11 @@ public final class MemoryFileSystem: FileSystemProvider, FileSystem {
148148
guard let memoryDir = dirFd as? MemoryDirEntry else {
149149
throw WASIAbi.Errno.EBADF
150150
}
151-
151+
152152
let fullPath = memoryDir.path.hasSuffix("/") ? memoryDir.path + path : memoryDir.path + "/" + path
153-
153+
154154
var node = resolve(from: memoryDir.dirNode, at: memoryDir.path, path: path)
155-
155+
156156
if node != nil {
157157
if oflags.contains(.EXCL) && oflags.contains(.CREAT) {
158158
throw WASIAbi.Errno.EEXIST
@@ -164,50 +164,69 @@ public final class MemoryFileSystem: FileSystemProvider, FileSystem {
164164
throw WASIAbi.Errno.ENOENT
165165
}
166166
}
167-
167+
168168
guard let resolvedNode = node else {
169169
throw WASIAbi.Errno.ENOENT
170170
}
171-
171+
172172
if oflags.contains(.DIRECTORY) {
173173
guard resolvedNode.type == .directory else {
174174
throw WASIAbi.Errno.ENOTDIR
175175
}
176176
}
177-
177+
178+
// Handle directory nodes
178179
if resolvedNode.type == .directory {
179180
guard let dirNode = resolvedNode as? MemoryDirectoryNode else {
180181
throw WASIAbi.Errno.ENOTDIR
181182
}
182-
return .directory(MemoryDirEntry(
183-
preopenPath: nil,
184-
dirNode: dirNode,
185-
path: fullPath,
186-
fileSystem: self
187-
))
188-
} else if resolvedNode.type == .file {
183+
return .directory(
184+
MemoryDirEntry(
185+
preopenPath: nil,
186+
dirNode: dirNode,
187+
path: fullPath,
188+
fileSystem: self
189+
))
190+
}
191+
192+
// Handle regular file nodes
193+
if resolvedNode.type == .file {
189194
guard let fileNode = resolvedNode as? MemoryFileNode else {
190195
throw WASIAbi.Errno.EBADF
191196
}
192-
197+
193198
if oflags.contains(.TRUNC) && fsRightsBase.contains(.FD_WRITE) {
194199
fileNode.content = .bytes([])
195200
}
196-
201+
197202
var accessMode: FileAccessMode = []
198203
if fsRightsBase.contains(.FD_READ) {
199204
accessMode.insert(.read)
200205
}
201206
if fsRightsBase.contains(.FD_WRITE) {
202207
accessMode.insert(.write)
203208
}
204-
209+
205210
return .file(MemoryFileEntry(fileNode: fileNode, accessMode: accessMode, position: 0))
206-
} else {
207-
throw WASIAbi.Errno.ENOTSUP
208211
}
212+
if resolvedNode.type == .characterDevice {
213+
guard let deviceNode = resolvedNode as? MemoryCharacterDeviceNode else {
214+
throw WASIAbi.Errno.EBADF
215+
}
216+
217+
var accessMode: FileAccessMode = []
218+
if fsRightsBase.contains(.FD_READ) {
219+
accessMode.insert(.read)
220+
}
221+
if fsRightsBase.contains(.FD_WRITE) {
222+
accessMode.insert(.write)
223+
}
224+
225+
return .file(MemoryCharacterDeviceEntry(deviceNode: deviceNode, accessMode: accessMode))
226+
}
227+
throw WASIAbi.Errno.ENOTSUP
209228
}
210-
229+
211230
internal func createStdioFile(fd: FileDescriptor, accessMode: FileAccessMode) -> any WASIFile {
212231
return MemoryStdioFile(fd: fd, accessMode: accessMode)
213232
}
@@ -463,4 +482,4 @@ public final class MemoryFileSystem: FileSystemProvider, FileSystem {
463482
let parentPath = Self.rootPath + parentComponents.joined(separator: "/")
464483
return (parentPath, fileName)
465484
}
466-
}
485+
}

Sources/WasmKitWASI/WASIBridgeToHost+WasmKit.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import WASI
22
import WasmKit
33

44
public typealias WASIBridgeToHost = WASI.WASIBridgeToHost
5+
public typealias MemoryFileSystem = WASI.MemoryFileSystem
56

67
extension WASIBridgeToHost {
78

0 commit comments

Comments
 (0)