@@ -96,6 +96,32 @@ extension FileManager {
9696 return nil
9797 }
9898 urls = mountPoints ( statBuf, Int ( fsCount) )
99+ #elseif os(WASI)
100+ // Skip the first three file descriptors, which are reserved for stdin, stdout, and stderr.
101+ var fd : __wasi_fd_t = 3
102+ let __WASI_PREOPENTYPE_DIR : UInt8 = 0
103+ while true {
104+ var prestat = __wasi_prestat_t ( )
105+ guard __wasi_fd_prestat_get ( fd, & prestat) == 0 else {
106+ break
107+ }
108+
109+ if prestat. tag == __WASI_PREOPENTYPE_DIR {
110+ var buf = [ UInt8] ( repeating: 0 , count: Int ( prestat. u. dir. pr_name_len) )
111+ guard __wasi_fd_prestat_dir_name ( fd, & buf, prestat. u. dir. pr_name_len) == 0 else {
112+ break
113+ }
114+ let path = buf. withUnsafeBufferPointer { buf in
115+ guard let baseAddress = buf. baseAddress else {
116+ return " "
117+ }
118+ let base = UnsafeRawPointer ( baseAddress) . assumingMemoryBound ( to: Int8 . self)
119+ return string ( withFileSystemRepresentation: base, length: buf. count)
120+ }
121+ urls. append ( URL ( fileURLWithPath: path, isDirectory: true ) )
122+ }
123+ fd += 1
124+ }
99125#else
100126#error("Requires a platform-specific implementation")
101127#endif
@@ -446,6 +472,10 @@ extension FileManager {
446472 }
447473
448474 internal func _attributesOfFileSystemIncludingBlockSize( forPath path: String ) throws -> ( attributes: [ FileAttributeKey : Any ] , blockSize: UInt64 ? ) {
475+ #if os(WASI)
476+ // WASI doesn't have statvfs
477+ throw _NSErrorWithErrno ( ENOTSUP, reading: true , path: path)
478+ #else
449479 var result : [ FileAttributeKey : Any ] = [ : ]
450480 var finalBlockSize : UInt64 ?
451481
@@ -478,6 +508,7 @@ extension FileManager {
478508 finalBlockSize = blockSize
479509 }
480510 return ( attributes: result, blockSize: finalBlockSize)
511+ #endif // os(WASI)
481512 }
482513
483514 internal func _createSymbolicLink( atPath path: String , withDestinationPath destPath: String ) throws {
@@ -507,6 +538,11 @@ extension FileManager {
507538 }
508539
509540 internal func _recursiveDestinationOfSymbolicLink( atPath path: String ) throws -> String {
541+ #if os(WASI)
542+ // TODO: Remove this guard when realpath implementation will be released
543+ // See https://github.com/WebAssembly/wasi-libc/pull/473
544+ throw _NSErrorWithErrno ( ENOTSUP, reading: true , path: path)
545+ #else
510546 // Throw error if path is not a symbolic link:
511547 let path = try _destinationOfSymbolicLink ( atPath: path)
512548
@@ -520,10 +556,16 @@ extension FileManager {
520556 }
521557
522558 return String ( cString: resolvedPath)
559+ #endif
523560 }
524561
525562 /* Returns a String with a canonicalized path for the element at the specified path. */
526563 internal func _canonicalizedPath( toFileAtPath path: String ) throws -> String {
564+ #if os(WASI)
565+ // TODO: Remove this guard when realpath implementation will be released
566+ // See https://github.com/WebAssembly/wasi-libc/pull/473
567+ throw _NSErrorWithErrno ( ENOTSUP, reading: true , path: path)
568+ #else
527569 let bufSize = Int ( PATH_MAX + 1 )
528570 var buf = [ Int8] ( repeating: 0 , count: bufSize)
529571 let done = try _fileSystemRepresentation ( withPath: path) {
@@ -534,6 +576,7 @@ extension FileManager {
534576 }
535577
536578 return self . string ( withFileSystemRepresentation: buf, length: strlen ( buf) )
579+ #endif
537580 }
538581
539582 internal func _readFrom( fd: Int32 , toBuffer buffer: UnsafeMutablePointer < UInt8 > , length bytesToRead: Int , filename: String ) throws -> Int {
@@ -591,12 +634,14 @@ extension FileManager {
591634 }
592635 defer { close ( dstfd) }
593636
637+ #if !os(WASI) // WASI doesn't have ownership concept
594638 // Set the file permissions using fchmod() instead of when open()ing to avoid umask() issues
595639 let permissions = fileInfo. st_mode & ~ S_IFMT
596640 guard fchmod ( dstfd, permissions) == 0 else {
597641 throw _NSErrorWithErrno ( errno, reading: false , path: dstPath,
598642 extraUserInfo: extraErrorInfo ( srcPath: srcPath, dstPath: dstPath, userVariant: variant) )
599643 }
644+ #endif
600645
601646 if fileInfo. st_size == 0 {
602647 // no copying required
@@ -741,6 +786,10 @@ extension FileManager {
741786 if rmdir ( fsRep) == 0 {
742787 return
743788 } else if errno == ENOTEMPTY {
789+ #if os(WASI)
790+ // wasi-libc, which is based on musl, does not provide fts(3)
791+ throw _NSErrorWithErrno ( ENOTSUP, reading: false , path: path)
792+ #else
744793 let ps = UnsafeMutablePointer< UnsafeMutablePointer< Int8>?> . allocate( capacity: 2 )
745794 ps. initialize ( to: UnsafeMutablePointer ( mutating: fsRep) )
746795 ps. advanced ( by: 1 ) . initialize ( to: nil )
@@ -783,6 +832,7 @@ extension FileManager {
783832 } else {
784833 let _ = _NSErrorWithErrno ( ENOTEMPTY, reading: false , path: path)
785834 }
835+ #endif
786836 } else if errno != ENOTDIR {
787837 throw _NSErrorWithErrno ( errno, reading: false , path: path)
788838 } else if unlink ( fsRep) != 0 {
@@ -885,6 +935,7 @@ extension FileManager {
885935 return false
886936 }
887937
938+ #if !os(WASI) // WASI doesn't have ownership concept
888939 // Stat the parent directory, if that fails, return false.
889940 let parentS = try _lstatFile ( atPath: path, withFileSystemRepresentation: parentFsRep)
890941
@@ -895,6 +946,7 @@ extension FileManager {
895946 // If the current user owns the file, return true.
896947 return s. st_uid == getuid ( )
897948 }
949+ #endif
898950
899951 // Return true as the best guess.
900952 return true
@@ -1065,6 +1117,26 @@ extension FileManager {
10651117 return temp. _bridgeToObjectiveC ( ) . appendingPathComponent ( dest)
10661118 }
10671119
1120+ #if os(WASI)
1121+ // For platforms that don't support FTS, we just throw an error for now.
1122+ // TODO: Provide readdir(2) based implementation here or FTS in wasi-libc?
1123+ internal class NSURLDirectoryEnumerator : DirectoryEnumerator {
1124+ var _url : URL
1125+ var _errorHandler : ( ( URL , Error ) -> Bool ) ?
1126+
1127+ init ( url: URL , options: FileManager . DirectoryEnumerationOptions , errorHandler: ( ( URL , Error ) -> Bool ) ? ) {
1128+ _url = url
1129+ _errorHandler = errorHandler
1130+ }
1131+
1132+ override func nextObject( ) -> Any ? {
1133+ if let handler = _errorHandler {
1134+ _ = handler ( _url, _NSErrorWithErrno ( ENOTSUP, reading: true , url: _url) )
1135+ }
1136+ return nil
1137+ }
1138+ }
1139+ #else
10681140 internal class NSURLDirectoryEnumerator : DirectoryEnumerator {
10691141 var _url : URL
10701142 var _options : FileManager . DirectoryEnumerationOptions
@@ -1198,6 +1270,7 @@ extension FileManager {
11981270 return nil
11991271 }
12001272 }
1273+ #endif
12011274
12021275 internal func _updateTimes( atPath path: String , withFileSystemRepresentation fsr: UnsafePointer < Int8 > , creationTime: Date ? = nil , accessTime: Date ? = nil , modificationTime: Date ? = nil ) throws {
12031276 let stat = try _lstatFile ( atPath: path, withFileSystemRepresentation: fsr)
0 commit comments