@@ -137,7 +137,9 @@ open class FileManager : NSObject {
137
137
let modeT = number. uint32Value
138
138
#endif
139
139
#if CAN_IMPORT_MINGWCRT
140
- if chmod ( path, Int32 ( mode_t ( modeT) ) ) != 0 {
140
+ if path. withCString ( encodedAs: UTF16 . self, { ( pointer) -> Bool in
141
+ return _wchmod ( pointer, Int32 ( mode_t ( modeT) ) ) != 0
142
+ } ) {
141
143
fatalError ( " errno \( errno) " )
142
144
}
143
145
#else
@@ -164,7 +166,9 @@ open class FileManager : NSObject {
164
166
try createDirectory ( atPath: parent, withIntermediateDirectories: true , attributes: attributes)
165
167
}
166
168
#if CAN_IMPORT_MINGWCRT
167
- let mkdir_failed = _mkdir ( path) != 0
169
+ let mkdir_failed = path. withCString ( encodedAs: UTF16 . self, { pointer in
170
+ return _wmkdir ( pointer) != 0
171
+ } )
168
172
#else
169
173
let mkdir_failed = mkdir ( pathh, S_IRWXU | S_IRWXG | S_IRWXO) != 0
170
174
#endif
@@ -180,7 +184,9 @@ open class FileManager : NSObject {
180
184
}
181
185
} else {
182
186
#if CAN_IMPORT_MINGWCRT
183
- let mkdir_failed = _mkdir ( path) != 0
187
+ let mkdir_failed = path. withCString ( encodedAs: UTF16 . self, { pointer in
188
+ return _wmkdir ( pointer) != 0
189
+ } )
184
190
#else
185
191
let mkdir_failed = mkdir ( pathh, S_IRWXU | S_IRWXG | S_IRWXO) != 0
186
192
#endif
@@ -207,14 +213,39 @@ open class FileManager : NSObject {
207
213
*/
208
214
open func contentsOfDirectory( atPath path: String ) throws -> [ String ] {
209
215
var contents : [ String ] = [ String] ( )
210
-
216
+ #if CAN_IMPORT_MINGWCRT
217
+ let dir = path. withCString ( encodedAs: UTF16 . self, { pointer in
218
+ return _wopendir ( pointer)
219
+ } )
220
+ #else
211
221
let dir = opendir ( path)
212
-
222
+ #endif
223
+
213
224
if dir == nil {
214
225
throw NSError ( domain: NSCocoaErrorDomain, code: CocoaError . fileReadNoSuchFile. rawValue, userInfo: [ NSFilePathErrorKey: path] )
215
226
}
216
-
227
+
228
+ #if CAN_IMPORT_MINGWCRT
217
229
defer {
230
+
231
+ _wclosedir ( dir!)
232
+ }
233
+
234
+ while let entry = _wreaddir ( dir!) {
235
+ let entryNameLen = withUnsafePointer ( to: & entry. pointee. d_namlen) {
236
+ UnsafeRawPointer ( $0) . assumingMemoryBound ( to: UInt16 . self) . pointee
237
+ }
238
+ let entryName = withUnsafePointer ( to: & entry. pointee. d_name) {
239
+ String ( utf16CodeUnits: UnsafeRawPointer ( $0) . assumingMemoryBound ( to: UInt16 . self) , count: Int ( entryNameLen) )
240
+ }
241
+
242
+ if entryName != " . " && entryName != " .. " {
243
+ contents. append ( entryName)
244
+ }
245
+ }
246
+ #else
247
+ defer {
248
+
218
249
closedir ( dir!)
219
250
}
220
251
@@ -227,7 +258,7 @@ open class FileManager : NSObject {
227
258
contents. append ( entryName)
228
259
}
229
260
}
230
-
261
+ #endif
231
262
return contents
232
263
}
233
264
@@ -245,31 +276,74 @@ open class FileManager : NSObject {
245
276
- Returns: An array of NSString objects, each of which contains the path of an item in the directory specified by path. If path is a symbolic link, this method traverses the link. This method returns nil if it cannot retrieve the device of the linked-to file.
246
277
*/
247
278
open func subpathsOfDirectory( atPath path: String ) throws -> [ String ] {
279
+ var contents : [ String ] = [ String] ( )
248
280
#if CAN_IMPORT_MINGWCRT
249
- NSUnimplemented ( )
281
+
282
+ let dir = path. withCString ( encodedAs: UTF16 . self, { pointer in
283
+ return _wopendir ( pointer)
284
+ } )
250
285
#else
251
- var contents : [ String ] = [ String] ( )
252
286
253
287
let dir = opendir ( path)
288
+ #endif
254
289
255
290
if dir == nil {
256
291
throw NSError ( domain: NSCocoaErrorDomain, code: CocoaError . fileReadNoSuchFile. rawValue, userInfo: [ NSFilePathErrorKey: path] )
257
292
}
258
293
294
+
295
+ #if CAN_IMPORT_MINGWCRT
259
296
defer {
297
+
298
+ _wclosedir ( dir!)
299
+ }
300
+
301
+ var entry = _wreaddir ( dir!)
302
+ #else
303
+ defer {
304
+
260
305
closedir ( dir!)
261
306
}
262
-
307
+
263
308
var entry = readdir ( dir!)
309
+ #endif
264
310
265
311
while entry != nil {
312
+ #if CAN_IMPORT_MINGWCRT
313
+ let entryNameLen = withUnsafePointer ( to: & entry!. pointee. d_namlen) {
314
+ UnsafeRawPointer ( $0) . assumingMemoryBound ( to: UInt16 . self) . pointee
315
+ }
316
+ let entryName = withUnsafePointer ( to: & entry!. pointee. d_name) {
317
+ String ( utf16CodeUnits: UnsafeRawPointer ( $0) . assumingMemoryBound ( to: UInt16 . self) , count: Int ( entryNameLen) )
318
+ }
319
+ #else
266
320
let entryName = withUnsafePointer ( to: & entry!. pointee. d_name) {
267
321
String ( cString: UnsafeRawPointer ( $0) . assumingMemoryBound ( to: CChar . self) )
268
322
}
323
+ #endif
269
324
// TODO: `entryName` should be limited in length to `entry.memory.d_namlen`.
270
325
if entryName != " . " && entryName != " .. " {
271
326
contents. append ( entryName)
272
-
327
+
328
+ #if CAN_IMPORT_MINGWCRT
329
+ do {
330
+
331
+ let subPath : String = path + " / " + entryName
332
+ let isDir : Bool = subPath. withCString ( encodedAs: UTF16 . self, { ( pointer) -> Bool in
333
+ var s = _stat64 ( )
334
+ guard _wstat64 ( pointer, & s) >= 0 else {
335
+ return false
336
+ }
337
+
338
+ return ( Int32 ( s. st_mode) & S_IFMT) == S_IFDIR
339
+ } )
340
+
341
+ if isDir {
342
+ let entries = try subpathsOfDirectory ( atPath: subPath)
343
+ contents. append ( contentsOf: entries. map ( { file in " \( entryName) / \( file) " } ) )
344
+ }
345
+ }
346
+ #else
273
347
let entryType = withUnsafePointer ( to: & entry!. pointee. d_type) { ( ptr) -> Int32 in
274
348
return Int32 ( ptr. pointee)
275
349
}
@@ -285,13 +359,16 @@ open class FileManager : NSObject {
285
359
let entries = try subpathsOfDirectory ( atPath: subPath)
286
360
contents. append ( contentsOf: entries. map ( { file in " \( entryName) / \( file) " } ) )
287
361
}
362
+ #endif
288
363
}
289
-
364
+ #if CAN_IMPORT_MINGWCRT
365
+ entry = _wreaddir ( dir!)
366
+ #else
290
367
entry = readdir ( dir!)
368
+ #endif
291
369
}
292
370
293
371
return contents
294
- #endif
295
372
}
296
373
297
374
/* attributesOfItemAtPath:error: returns an NSDictionary of key/value pairs containing the attributes of the item (file, directory, symlink, etc.) at the path in question. If this method returns 'nil', an NSError will be returned by reference in the 'error' parameter. This method does not traverse a terminal symlink.
@@ -300,29 +377,46 @@ open class FileManager : NSObject {
300
377
*/
301
378
open func attributesOfItem( atPath path: String ) throws -> [ FileAttributeKey : Any ] {
302
379
#if CAN_IMPORT_MINGWCRT
303
- NSUnimplemented ( )
380
+ var s = _stat64 ( )
381
+
382
+ guard path. withCString ( encodedAs: UTF16 . self, { ( pointer) -> Bool in
383
+ return _wstat64 ( pointer, & s) == 0
384
+ } ) else {
385
+ throw _NSErrorWithErrno ( errno, reading: true , path: path)
386
+ }
304
387
#else
305
388
var s = stat ( )
306
389
guard lstat ( path, & s) == 0 else {
307
390
throw _NSErrorWithErrno ( errno, reading: true , path: path)
308
391
}
392
+ #endif
309
393
var result = [ FileAttributeKey : Any] ( )
310
394
result [ . size] = NSNumber ( value: UInt64 ( s. st_size) )
311
395
312
396
#if os(OSX) || os(iOS)
313
397
let ti = ( TimeInterval ( s. st_mtimespec. tv_sec) - kCFAbsoluteTimeIntervalSince1970) + ( 1.0e-9 * TimeInterval( s. st_mtimespec. tv_nsec) )
314
398
#elseif os(Android)
315
399
let ti = ( TimeInterval ( s. st_mtime) - kCFAbsoluteTimeIntervalSince1970) + ( 1.0e-9 * TimeInterval( s. st_mtime_nsec) )
400
+ #elseif CAN_IMPORT_MINGWCRT
401
+ let ti = ( TimeInterval ( s. st_mtime) - kCFAbsoluteTimeIntervalSince1970)
316
402
#else
317
- let ti = ( TimeInterval ( s. st_mtim . tv_sec) - kCFAbsoluteTimeIntervalSince1970) + ( 1.0e-9 * TimeInterval( s. st_mtim. tv_nsec) )
403
+ let ti = ( TimeInterval ( s. st_mtime . tv_sec) - kCFAbsoluteTimeIntervalSince1970) + ( 1.0e-9 * TimeInterval( s. st_mtim. tv_nsec) )
318
404
#endif
319
405
result [ . modificationDate] = Date ( timeIntervalSinceReferenceDate: ti)
320
406
321
407
result [ . posixPermissions] = NSNumber ( value: UInt64 ( s. st_mode & 0o7777 ) )
322
408
result [ . referenceCount] = NSNumber ( value: UInt64 ( s. st_nlink) )
323
409
result [ . systemNumber] = NSNumber ( value: UInt64 ( s. st_dev) )
324
410
result [ . systemFileNumber] = NSNumber ( value: UInt64 ( s. st_ino) )
325
-
411
+ #if CAN_IMPORT_MINGWCRT
412
+ var type : FileAttributeType
413
+ switch Int32 ( s. st_mode) & S_IFMT {
414
+ case S_IFCHR: type = . typeCharacterSpecial
415
+ case S_IFDIR: type = . typeDirectory
416
+ case S_IFREG: type = . typeRegular
417
+ default : type = . typeUnknown
418
+ }
419
+ #else
326
420
let pwd = getpwuid ( s. st_uid)
327
421
if pwd != nil && pwd!. pointee. pw_name != nil {
328
422
let name = String ( cString: pwd!. pointee. pw_name)
@@ -345,6 +439,7 @@ open class FileManager : NSObject {
345
439
case S_IFSOCK: type = . typeSocket
346
440
default : type = . typeUnknown
347
441
}
442
+ #endif
348
443
result [ . type] = type
349
444
350
445
if type == . typeBlockSpecial || type == . typeCharacterSpecial {
@@ -363,7 +458,7 @@ open class FileManager : NSObject {
363
458
result [ . groupOwnerAccountID] = NSNumber ( value: UInt64 ( s. st_gid) )
364
459
365
460
return result
366
- #endif
461
+
367
462
}
368
463
369
464
/* attributesOfFileSystemForPath:error: returns an NSDictionary of key/value pairs containing the attributes of the filesystem containing the provided path. If this method returns 'nil', an NSError will be returned by reference in the 'error' parameter. This method does not traverse a terminal symlink.
@@ -431,6 +526,16 @@ open class FileManager : NSObject {
431
526
guard !self . fileExists ( atPath: dstPath) else {
432
527
throw NSError ( domain: NSCocoaErrorDomain, code: CocoaError . fileWriteFileExists. rawValue, userInfo: [ NSFilePathErrorKey : NSString ( dstPath) ] )
433
528
}
529
+ #if CAN_IMPORT_MINGWCRT
530
+
531
+ if !srcPath. withCString ( encodedAs: UTF16 . self, { ( srcPointer) -> Bool in
532
+ return dstPath. withCString ( encodedAs: UTF16 . self, { ( dstPointer) -> Bool in
533
+ return _wrename ( srcPointer, dstPointer) != 0
534
+ } )
535
+ } ) {
536
+ throw _NSErrorWithErrno ( errno, reading: false , path: srcPath)
537
+ }
538
+ #else
434
539
if rename ( srcPath, dstPath) != 0 {
435
540
if errno == EXDEV {
436
541
// TODO: Copy and delete.
@@ -439,6 +544,7 @@ open class FileManager : NSObject {
439
544
throw _NSErrorWithErrno ( errno, reading: false , path: srcPath)
440
545
}
441
546
}
547
+ #endif
442
548
}
443
549
444
550
open func linkItem( atPath srcPath: String , toPath dstPath: String ) throws {
@@ -462,7 +568,30 @@ open class FileManager : NSObject {
462
568
463
569
open func removeItem( atPath path: String ) throws {
464
570
#if CAN_IMPORT_MINGWCRT
465
- NSUnimplemented ( )
571
+ var s = _stat64 ( )
572
+
573
+ guard try path. withCString ( encodedAs: UTF16 . self, { ( pointer) -> Bool in
574
+ guard _wstat64 ( pointer, & s) >= 0 else {
575
+ return false
576
+ }
577
+
578
+ if ( Int32 ( s. st_mode) & S_IFMT) == S_IFDIR {
579
+ let subpaths = try subpathsOfDirectory ( atPath: path)
580
+ for subpath in subpaths {
581
+ try removeItem ( atPath: path + " / " + subpath)
582
+ }
583
+
584
+ return _wrmdir ( pointer) == 0
585
+
586
+ } else {
587
+
588
+ return _wunlink ( pointer) == 0
589
+ }
590
+
591
+ } ) else {
592
+
593
+ throw _NSErrorWithErrno ( errno, reading: true , path: path)
594
+ }
466
595
#else
467
596
if rmdir ( path) == 0 {
468
597
return
@@ -554,19 +683,33 @@ open class FileManager : NSObject {
554
683
open var currentDirectoryPath : String {
555
684
#if CAN_IMPORT_MINGWCRT
556
685
let length = Int32 ( _MAX_PATH) + 1
557
- var buf = [ Int8] ( repeating: 0 , count: Int ( length) )
686
+ var buf = [ UInt16] ( repeating: 0 , count: Int ( length) )
687
+
688
+ _wgetcwd ( & buf, length)
689
+
690
+ let result = String ( utf16CodeUnits: buf, count: wcslen ( buf) )
558
691
#else
559
692
let length = Int ( PATH_MAX) + 1
560
693
var buf = [ Int8] ( repeating: 0 , count: length)
561
- #endif
694
+
562
695
getcwd ( & buf, length)
696
+
563
697
let result = self . string ( withFileSystemRepresentation: buf, length: Int ( strlen ( buf) ) )
698
+ #endif
699
+
700
+
564
701
return result
565
702
}
566
703
567
704
@discardableResult
568
705
open func changeCurrentDirectoryPath( _ path: String ) -> Bool {
706
+ #if CAN_IMPORT_MINGWCRT
707
+ return path. withCString ( encodedAs: UTF16 . self, { ( pointer) -> Bool in
708
+ return _wchdir ( pointer) == 0
709
+ } )
710
+ #else
569
711
return chdir ( path) == 0
712
+ #endif
570
713
}
571
714
572
715
/* The following methods are of limited utility. Attempting to predicate behavior based on the current state of the filesystem or a particular file on the filesystem is encouraging odd behavior in the face of filesystem race conditions. It's far better to attempt an operation (like loading a file or creating a directory) and handle the error gracefully than it is to try to figure out ahead of time whether the operation will succeed.
@@ -577,7 +720,21 @@ open class FileManager : NSObject {
577
720
578
721
open func fileExists( atPath path: String , isDirectory: UnsafeMutablePointer < ObjCBool > ? ) -> Bool {
579
722
#if CAN_IMPORT_MINGWCRT
580
- NSUnimplemented ( )
723
+ var s = _stat64 ( )
724
+ if path. withCString ( encodedAs: UTF16 . self, { ( pointer) -> Bool in
725
+ return _wstat64 ( pointer, & s) >= 0
726
+ } ) {
727
+
728
+ if let isDirectory = isDirectory {
729
+ isDirectory. pointee = ( Int32 ( s. st_mode) & S_IFMT) == S_IFDIR
730
+ }
731
+
732
+ } else {
733
+
734
+ return false
735
+ }
736
+
737
+ return true
581
738
#else
582
739
var s = stat ( )
583
740
if lstat ( path, & s) >= 0 {
0 commit comments