Skip to content

Commit 8de8027

Browse files
committed
Fix WASI build (dirent, umask, errno and open flag tests)
1 parent 7f9dba8 commit 8de8027

File tree

6 files changed

+83
-16
lines changed

6 files changed

+83
-16
lines changed

Sources/CSystem/include/CSystemWASI.h

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift System open source project
33
4-
Copyright (c) 2024 Apple Inc. and the Swift System project authors
4+
Copyright (c) 2024 - 2025 Apple Inc. and the Swift System project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66
77
See https://swift.org/LICENSE.txt for license information
@@ -11,8 +11,10 @@
1111

1212
#if __wasi__
1313

14+
#include <dirent.h>
1415
#include <errno.h>
1516
#include <fcntl.h>
17+
#include <limits.h> // For NAME_MAX
1618

1719
// wasi-libc defines the following constants in a way that Clang Importer can't
1820
// understand, so we need to expose them manually.
@@ -28,4 +30,37 @@ static inline int32_t _getConst_O_WRONLY(void) { return O_WRONLY; }
2830
static inline int32_t _getConst_EWOULDBLOCK(void) { return EWOULDBLOCK; }
2931
static inline int32_t _getConst_EOPNOTSUPP(void) { return EOPNOTSUPP; }
3032

33+
static inline uint8_t _getConst_DT_DIR(void) { return DT_DIR; }
34+
35+
// Modified dirent struct that can be imported to Swift
36+
struct _system_dirent {
37+
ino_t d_ino;
38+
unsigned char d_type;
39+
// char d_name[] cannot be imported to Swift
40+
char d_name[NAME_MAX + 1];
41+
};
42+
43+
// Convert WASI dirent with d_name[] to _system_dirent
44+
static inline
45+
struct _system_dirent *
46+
_system_dirent_from_wasi_dirent(const struct dirent *wasi_dirent) {
47+
48+
// Match readdir behavior and use thread-local storage for the converted dirent
49+
static __thread struct _system_dirent _converted_dirent;
50+
51+
if (wasi_dirent == NULL) {
52+
return NULL;
53+
}
54+
55+
memset(&_converted_dirent, 0, sizeof(struct _system_dirent));
56+
57+
_converted_dirent.d_ino = wasi_dirent->d_ino;
58+
_converted_dirent.d_type = wasi_dirent->d_type;
59+
60+
strncpy(_converted_dirent.d_name, wasi_dirent->d_name, NAME_MAX);
61+
_converted_dirent.d_name[NAME_MAX] = '\0';
62+
63+
return &_converted_dirent;
64+
}
65+
3166
#endif

Sources/System/FileOperations.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift System open source project
33

4-
Copyright (c) 2020 - 2024 Apple Inc. and the Swift System project authors
4+
Copyright (c) 2020 - 2025 Apple Inc. and the Swift System project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66

77
See https://swift.org/LICENSE.txt for license information
@@ -509,6 +509,7 @@ extension FileDescriptor {
509509
}
510510
}
511511

512+
#if !os(WASI) // WASI has no umask
512513
extension FilePermissions {
513514
/// The file creation permission mask (aka "umask").
514515
///
@@ -549,3 +550,4 @@ extension FilePermissions {
549550
return system_umask(mode)
550551
}
551552
}
553+
#endif

Sources/System/Internals/Syscalls.swift

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift System open source project
33

4-
Copyright (c) 2020 - 2024 Apple Inc. and the Swift System project authors
4+
Copyright (c) 2020 - 2025 Apple Inc. and the Swift System project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66

77
See https://swift.org/LICENSE.txt for license information
@@ -14,6 +14,7 @@ import Glibc
1414
#elseif canImport(Musl)
1515
import Musl
1616
#elseif canImport(WASILibc)
17+
import CSystem
1718
import WASILibc
1819
#elseif os(Windows)
1920
import ucrt
@@ -189,9 +190,14 @@ internal func system_confstr(
189190

190191
#if !os(Windows)
191192
internal let SYSTEM_AT_REMOVE_DIR = AT_REMOVEDIR
193+
#if os(WASI)
194+
internal let SYSTEM_DT_DIR = _getConst_DT_DIR()
195+
internal typealias system_dirent = _system_dirent
196+
#else
192197
internal let SYSTEM_DT_DIR = DT_DIR
193198
internal typealias system_dirent = dirent
194-
#if os(Linux) || os(Android) || os(FreeBSD) || os(OpenBSD)
199+
#endif
200+
#if os(Linux) || os(Android) || os(FreeBSD) || os(OpenBSD) || os(WASI)
195201
internal typealias system_DIRPtr = OpaquePointer
196202
#else
197203
internal typealias system_DIRPtr = UnsafeMutablePointer<DIR>
@@ -216,8 +222,12 @@ internal func system_fdopendir(
216222

217223
internal func system_readdir(
218224
_ dir: system_DIRPtr
219-
) -> UnsafeMutablePointer<dirent>? {
225+
) -> UnsafeMutablePointer<system_dirent>? {
226+
#if os(WASI)
227+
return _system_dirent_from_wasi_dirent(readdir(dir))
228+
#else
220229
return readdir(dir)
230+
#endif
221231
}
222232

223233
internal func system_rewinddir(
@@ -246,11 +256,13 @@ internal func system_openat(
246256
}
247257
#endif
248258

259+
#if !os(WASI) // WASI has no umask
249260
internal func system_umask(
250261
_ mode: CInterop.Mode
251262
) -> CInterop.Mode {
252263
return umask(mode)
253264
}
265+
#endif
254266

255267
internal func system_getenv(
256268
_ name: UnsafePointer<CChar>

Tests/SystemTests/ErrnoTest.swift

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift System open source project
33

4-
Copyright (c) 2020 Apple Inc. and the Swift System project authors
4+
Copyright (c) 2020 - 2025 Apple Inc. and the Swift System project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66

77
See https://swift.org/LICENSE.txt for license information
@@ -36,7 +36,7 @@ final class ErrnoTest: XCTestCase {
3636
XCTAssert(ENOMEM == Errno.noMemory.rawValue)
3737
XCTAssert(EACCES == Errno.permissionDenied.rawValue)
3838
XCTAssert(EFAULT == Errno.badAddress.rawValue)
39-
#if !os(Windows)
39+
#if !os(Windows) && !os(WASI)
4040
XCTAssert(ENOTBLK == Errno.notBlockDevice.rawValue)
4141
#endif
4242
XCTAssert(EBUSY == Errno.resourceBusy.rawValue)
@@ -74,9 +74,11 @@ final class ErrnoTest: XCTestCase {
7474
XCTAssert(WSAEOPNOTSUPP == Errno.notSupported.rawValue)
7575
XCTAssert(WSAEPFNOSUPPORT == Errno.protocolFamilyNotSupported.rawValue)
7676
#else
77-
XCTAssert(ESOCKTNOSUPPORT == Errno.socketTypeNotSupported.rawValue)
7877
XCTAssert(ENOTSUP == Errno.notSupported.rawValue)
78+
#if !os(WASI)
79+
XCTAssert(ESOCKTNOSUPPORT == Errno.socketTypeNotSupported.rawValue)
7980
XCTAssert(EPFNOSUPPORT == Errno.protocolFamilyNotSupported.rawValue)
81+
#endif
8082
#endif
8183
XCTAssert(EAFNOSUPPORT == Errno.addressFamilyNotSupported.rawValue)
8284
XCTAssert(EADDRINUSE == Errno.addressInUse.rawValue)
@@ -91,7 +93,7 @@ final class ErrnoTest: XCTestCase {
9193
XCTAssert(ENOTCONN == Errno.socketNotConnected.rawValue)
9294
#if os(Windows)
9395
XCTAssert(WSAESHUTDOWN == Errno.socketShutdown.rawValue)
94-
#else
96+
#elseif !os(WASI)
9597
XCTAssert(ESHUTDOWN == Errno.socketShutdown.rawValue)
9698
#endif
9799
XCTAssert(ETIMEDOUT == Errno.timedOut.rawValue)
@@ -100,7 +102,7 @@ final class ErrnoTest: XCTestCase {
100102
XCTAssert(ENAMETOOLONG == Errno.fileNameTooLong.rawValue)
101103
#if os(Windows)
102104
XCTAssert(WSAEHOSTDOWN == Errno.hostIsDown.rawValue)
103-
#else
105+
#elseif !os(WASI)
104106
XCTAssert(EHOSTDOWN == Errno.hostIsDown.rawValue)
105107
#endif
106108
XCTAssert(EHOSTUNREACH == Errno.noRouteToHost.rawValue)
@@ -115,7 +117,9 @@ final class ErrnoTest: XCTestCase {
115117
XCTAssert(WSAEDQUOT == Errno.diskQuotaExceeded.rawValue)
116118
XCTAssert(WSAESTALE == Errno.staleNFSFileHandle.rawValue)
117119
#else
120+
#if !os(WASI)
118121
XCTAssert(EUSERS == Errno.tooManyUsers.rawValue)
122+
#endif
119123
XCTAssert(EDQUOT == Errno.diskQuotaExceeded.rawValue)
120124
XCTAssert(ESTALE == Errno.staleNFSFileHandle.rawValue)
121125
#endif
@@ -171,7 +175,7 @@ final class ErrnoTest: XCTestCase {
171175
XCTAssert(EPROTO == Errno.protocolError.rawValue)
172176
#endif
173177

174-
#if !os(Windows) && !os(FreeBSD)
178+
#if !os(Windows) && !os(FreeBSD) && !os(WASI)
175179
XCTAssert(ENODATA == Errno.noData.rawValue)
176180
XCTAssert(ENOSR == Errno.noStreamResources.rawValue)
177181
XCTAssert(ENOSTR == Errno.notStream.rawValue)
@@ -181,11 +185,13 @@ final class ErrnoTest: XCTestCase {
181185
XCTAssert(EOPNOTSUPP == Errno.notSupportedOnSocket.rawValue)
182186

183187
// From headers but not man page
188+
#if !os(WASI) // Would need to use _getConst func from CSystem
184189
XCTAssert(EWOULDBLOCK == Errno.wouldBlock.rawValue)
190+
#endif
185191
#if os(Windows)
186192
XCTAssert(WSAETOOMANYREFS == Errno.tooManyReferences.rawValue)
187193
XCTAssert(WSAEREMOTE == Errno.tooManyRemoteLevels.rawValue)
188-
#else
194+
#elseif !os(WASI)
189195
XCTAssert(ETOOMANYREFS == Errno.tooManyReferences.rawValue)
190196
XCTAssert(EREMOTE == Errno.tooManyRemoteLevels.rawValue)
191197
#endif

Tests/SystemTests/FileOperationsTest.swift

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift System open source project
33

4-
Copyright (c) 2020 Apple Inc. and the Swift System project authors
4+
Copyright (c) 2020 - 2025 Apple Inc. and the Swift System project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66

77
See https://swift.org/LICENSE.txt for license information
@@ -16,10 +16,13 @@ import XCTest
1616
#endif
1717
#if canImport(Android)
1818
import Android
19+
#elseif os(WASI)
20+
import CSystem
1921
#endif
2022

2123
@available(/*System 0.0.1: macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0*/iOS 8, *)
2224
final class FileOperationsTest: XCTestCase {
25+
#if !os(WASI) // Would need to use _getConst funcs from CSystem
2326
func testSyscalls() {
2427
let fd = FileDescriptor(rawValue: 1)
2528

@@ -88,6 +91,7 @@ final class FileOperationsTest: XCTestCase {
8891

8992
for test in syscallTestCases { test.runAllTests() }
9093
}
94+
#endif // !os(WASI)
9195

9296
func testWriteFromEmptyBuffer() throws {
9397
#if os(Windows)
@@ -153,6 +157,7 @@ final class FileOperationsTest: XCTestCase {
153157
// TODO: Test writeAll, writeAll(toAbsoluteOffset), closeAfter
154158
}
155159

160+
#if !os(WASI) // WASI has no pipe
156161
func testAdHocPipe() throws {
157162
// Ad-hoc test testing `Pipe` functionality.
158163
// We cannot test `Pipe` using `MockTestCase` because it calls `pipe` with a pointer to an array local to the `Pipe`, the address of which we do not know prior to invoking `Pipe`.
@@ -171,6 +176,7 @@ final class FileOperationsTest: XCTestCase {
171176
}
172177
}
173178
}
179+
#endif
174180

175181
func testAdHocOpen() {
176182
// Ad-hoc test touching a file system.
@@ -211,8 +217,13 @@ final class FileOperationsTest: XCTestCase {
211217

212218
func testGithubIssues() {
213219
// https://github.com/apple/swift-system/issues/26
220+
#if os(WASI)
221+
let openOptions = _getConst_O_WRONLY() | _getConst_O_CREAT()
222+
#else
223+
let openOptions = O_WRONLY | O_CREAT
224+
#endif
214225
let issue26 = MockTestCase(
215-
name: "open", .interruptable, "a path", O_WRONLY | O_CREAT, 0o020
226+
name: "open", .interruptable, "a path", openOptions, 0o020
216227
) {
217228
retryOnInterrupt in
218229
_ = try FileDescriptor.open(
@@ -221,7 +232,6 @@ final class FileOperationsTest: XCTestCase {
221232
retryOnInterrupt: retryOnInterrupt)
222233
}
223234
issue26.runAllTests()
224-
225235
}
226236

227237
func testResizeFile() throws {

Tests/SystemTests/FileTypesTest.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
This source file is part of the Swift System open source project
33

4-
Copyright (c) 2020 - 2021 Apple Inc. and the Swift System project authors
4+
Copyright (c) 2020 - 2025 Apple Inc. and the Swift System project authors
55
Licensed under Apache License v2.0 with Runtime Library Exception
66

77
See https://swift.org/LICENSE.txt for license information
@@ -32,13 +32,15 @@ final class FileDescriptorTest: XCTestCase {
3232
XCTAssertEqual(O_WRONLY, FileDescriptor.AccessMode.writeOnly.rawValue)
3333
XCTAssertEqual(O_RDWR, FileDescriptor.AccessMode.readWrite.rawValue)
3434

35+
#if !os(WASI) // Would need to use _getConst funcs from CSystem
3536
#if !os(Windows)
3637
XCTAssertEqual(O_NONBLOCK, FileDescriptor.OpenOptions.nonBlocking.rawValue)
3738
#endif
3839
XCTAssertEqual(O_APPEND, FileDescriptor.OpenOptions.append.rawValue)
3940
XCTAssertEqual(O_CREAT, FileDescriptor.OpenOptions.create.rawValue)
4041
XCTAssertEqual(O_TRUNC, FileDescriptor.OpenOptions.truncate.rawValue)
4142
XCTAssertEqual(O_EXCL, FileDescriptor.OpenOptions.exclusiveCreate.rawValue)
43+
#endif // !os(WASI
4244
#if !os(Windows)
4345
XCTAssertEqual(O_NOFOLLOW, FileDescriptor.OpenOptions.noFollow.rawValue)
4446
XCTAssertEqual(O_CLOEXEC, FileDescriptor.OpenOptions.closeOnExec.rawValue)

0 commit comments

Comments
 (0)