@@ -188,9 +188,11 @@ open class FileManager : NSObject {
188
188
#elseif os(Linux) || os(Android) || CYGWIN
189
189
let modeT = number. uint32Value
190
190
#endif
191
- if chmod ( path, mode_t ( modeT) ) != 0 {
192
- fatalError ( " errno \( errno) " )
193
- }
191
+ _fileSystemRepresentation ( withPath: path, {
192
+ if chmod ( $0, mode_t ( modeT) ) != 0 {
193
+ fatalError ( " errno \( errno) " )
194
+ }
195
+ } )
194
196
} else {
195
197
fatalError ( " Attribute type not implemented: \( attribute) " )
196
198
}
@@ -202,30 +204,32 @@ open class FileManager : NSObject {
202
204
This method replaces createDirectoryAtPath:attributes:
203
205
*/
204
206
open func createDirectory( atPath path: String , withIntermediateDirectories createIntermediates: Bool , attributes: [ FileAttributeKey : Any ] ? = [ : ] ) throws {
205
- if createIntermediates {
206
- var isDir : ObjCBool = false
207
- if !fileExists( atPath: path, isDirectory: & isDir) {
208
- let parent = path. _nsObject. deletingLastPathComponent
209
- if !parent. isEmpty && !fileExists( atPath: parent, isDirectory: & isDir) {
210
- try createDirectory ( atPath: parent, withIntermediateDirectories: true , attributes: attributes)
207
+ try _fileSystemRepresentation ( withPath: path, { pathFsRep in
208
+ if createIntermediates {
209
+ var isDir : ObjCBool = false
210
+ if !fileExists( atPath: path, isDirectory: & isDir) {
211
+ let parent = path. _nsObject. deletingLastPathComponent
212
+ if !parent. isEmpty && !fileExists( atPath: parent, isDirectory: & isDir) {
213
+ try createDirectory ( atPath: parent, withIntermediateDirectories: true , attributes: attributes)
214
+ }
215
+ if mkdir ( pathFsRep, S_IRWXU | S_IRWXG | S_IRWXO) != 0 {
216
+ throw _NSErrorWithErrno ( errno, reading: false , path: path)
217
+ } else if let attr = attributes {
218
+ try self . setAttributes ( attr, ofItemAtPath: path)
219
+ }
220
+ } else if isDir. boolValue {
221
+ return
222
+ } else {
223
+ throw _NSErrorWithErrno ( EEXIST, reading: false , path: path)
211
224
}
212
- if mkdir ( path, S_IRWXU | S_IRWXG | S_IRWXO) != 0 {
225
+ } else {
226
+ if mkdir ( pathFsRep, S_IRWXU | S_IRWXG | S_IRWXO) != 0 {
213
227
throw _NSErrorWithErrno ( errno, reading: false , path: path)
214
228
} else if let attr = attributes {
215
229
try self . setAttributes ( attr, ofItemAtPath: path)
216
230
}
217
- } else if isDir. boolValue {
218
- return
219
- } else {
220
- throw _NSErrorWithErrno ( EEXIST, reading: false , path: path)
221
- }
222
- } else {
223
- if mkdir ( path, S_IRWXU | S_IRWXG | S_IRWXO) != 0 {
224
- throw _NSErrorWithErrno ( errno, reading: false , path: path)
225
- } else if let attr = attributes {
226
- try self . setAttributes ( attr, ofItemAtPath: path)
227
231
}
228
- }
232
+ } )
229
233
}
230
234
231
235
private func _contentsOfDir( atPath path: String , _ closure: ( String , Int32 ) throws -> ( ) ) throws {
@@ -310,10 +314,7 @@ open class FileManager : NSObject {
310
314
This method replaces fileAttributesAtPath:traverseLink:.
311
315
*/
312
316
open func attributesOfItem( atPath path: String ) throws -> [ FileAttributeKey : Any ] {
313
- var s = stat ( )
314
- guard lstat ( path, & s) == 0 else {
315
- throw _NSErrorWithErrno ( errno, reading: true , path: path)
316
- }
317
+ let s = try _lstatFile ( atPath: path)
317
318
var result = [ FileAttributeKey : Any] ( )
318
319
result [ . size] = NSNumber ( value: UInt64 ( s. st_size) )
319
320
@@ -415,9 +416,11 @@ open class FileManager : NSObject {
415
416
This method replaces createSymbolicLinkAtPath:pathContent:
416
417
*/
417
418
open func createSymbolicLink( atPath path: String , withDestinationPath destPath: String ) throws {
418
- if symlink ( destPath, path) == - 1 {
419
- throw _NSErrorWithErrno ( errno, reading: false , path: path)
420
- }
419
+ try _fileSystemRepresentation ( withPath: path, andPath: destPath, {
420
+ guard symlink ( $1, $0) == 0 else {
421
+ throw _NSErrorWithErrno ( errno, reading: false , path: path)
422
+ }
423
+ } )
421
424
}
422
425
423
426
/* destinationOfSymbolicLinkAtPath:error: returns an NSString containing the path of the item pointed at by the symlink specified by 'path'. If this method returns 'nil', an NSError will be returned by reference in the 'error' parameter.
@@ -427,7 +430,9 @@ open class FileManager : NSObject {
427
430
open func destinationOfSymbolicLink( atPath path: String ) throws -> String {
428
431
let bufSize = Int ( PATH_MAX + 1 )
429
432
var buf = [ Int8] ( repeating: 0 , count: bufSize)
430
- let len = readlink ( path, & buf, bufSize)
433
+ let len = _fileSystemRepresentation ( withPath: path) {
434
+ readlink ( $0, & buf, bufSize)
435
+ }
431
436
if len < 0 {
432
437
throw _NSErrorWithErrno ( errno, reading: true , path: path)
433
438
}
@@ -508,6 +513,22 @@ open class FileManager : NSObject {
508
513
}
509
514
}
510
515
516
+ private func _copySymlink( atPath srcPath: String , toPath dstPath: String ) throws {
517
+ let bufSize = Int ( PATH_MAX) + 1
518
+ var buf = [ Int8] ( repeating: 0 , count: bufSize)
519
+
520
+ try _fileSystemRepresentation ( withPath: srcPath) { srcFsRep in
521
+ let len = readlink ( srcFsRep, & buf, bufSize)
522
+ if len < 0 {
523
+ throw _NSErrorWithErrno ( errno, reading: true , path: srcPath)
524
+ }
525
+ try _fileSystemRepresentation ( withPath: dstPath) { dstFsRep in
526
+ if symlink ( buf, dstFsRep) == - 1 {
527
+ throw _NSErrorWithErrno ( errno, reading: false , path: dstPath)
528
+ }
529
+ }
530
+ }
531
+ }
511
532
512
533
open func copyItem( atPath srcPath: String , toPath dstPath: String ) throws {
513
534
guard
@@ -519,8 +540,7 @@ open class FileManager : NSObject {
519
540
520
541
func copyNonDirectory( srcPath: String , dstPath: String , fileType: FileAttributeType ) throws {
521
542
if fileType == . typeSymbolicLink {
522
- let destination = try destinationOfSymbolicLink ( atPath: srcPath)
523
- try createSymbolicLink ( atPath: dstPath, withDestinationPath: destination)
543
+ try _copySymlink ( atPath: srcPath, toPath: dstPath)
524
544
} else if fileType == . typeRegular {
525
545
try _copyRegularFile ( atPath: srcPath, toPath: dstPath)
526
546
}
@@ -553,24 +573,28 @@ open class FileManager : NSObject {
553
573
guard !self . fileExists ( atPath: dstPath) else {
554
574
throw NSError ( domain: NSCocoaErrorDomain, code: CocoaError . fileWriteFileExists. rawValue, userInfo: [ NSFilePathErrorKey : NSString ( dstPath) ] )
555
575
}
556
- if rename ( srcPath, dstPath) != 0 {
557
- if errno == EXDEV {
558
- // TODO: Copy and delete.
559
- NSUnimplemented ( " Cross-device moves not yet implemented " )
560
- } else {
561
- throw _NSErrorWithErrno ( errno, reading: false , path: srcPath)
576
+ try _fileSystemRepresentation ( withPath: srcPath, andPath: dstPath, {
577
+ if rename ( $0, $1) != 0 {
578
+ if errno == EXDEV {
579
+ // TODO: Copy and delete.
580
+ NSUnimplemented ( " Cross-device moves not yet implemented " )
581
+ } else {
582
+ throw _NSErrorWithErrno ( errno, reading: false , path: srcPath)
583
+ }
562
584
}
563
- }
585
+ } )
564
586
}
565
587
566
588
open func linkItem( atPath srcPath: String , toPath dstPath: String ) throws {
567
589
var isDir : ObjCBool = false
568
590
if self . fileExists ( atPath: srcPath, isDirectory: & isDir) {
569
591
if !isDir. boolValue {
570
592
// TODO: Symlinks should be copied instead of hard-linked.
571
- if link ( srcPath, dstPath) == - 1 {
572
- throw _NSErrorWithErrno ( errno, reading: false , path: srcPath)
573
- }
593
+ try _fileSystemRepresentation ( withPath: srcPath, andPath: dstPath, {
594
+ if link ( $0, $1) == - 1 {
595
+ throw _NSErrorWithErrno ( errno, reading: false , path: srcPath)
596
+ }
597
+ } )
574
598
} else {
575
599
// TODO: Recurse through directories, copying them.
576
600
NSUnimplemented ( " Recursive linking not yet implemented " )
@@ -622,7 +646,7 @@ open class FileManager : NSObject {
622
646
623
647
} else if errno != ENOTDIR {
624
648
throw _NSErrorWithErrno ( errno, reading: false , path: path)
625
- } else if unlink ( path) != 0 {
649
+ } else if _fileSystemRepresentation ( withPath : path, { unlink ( $0 ) != 0 } ) {
626
650
throw _NSErrorWithErrno ( errno, reading: false , path: path)
627
651
}
628
652
}
@@ -676,7 +700,7 @@ open class FileManager : NSObject {
676
700
677
701
@discardableResult
678
702
open func changeCurrentDirectoryPath( _ path: String ) -> Bool {
679
- return chdir ( path) == 0
703
+ return _fileSystemRepresentation ( withPath : path, { chdir ( $0 ) == 0 } )
680
704
}
681
705
682
706
/* 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.
@@ -686,40 +710,47 @@ open class FileManager : NSObject {
686
710
}
687
711
688
712
open func fileExists( atPath path: String , isDirectory: UnsafeMutablePointer < ObjCBool > ? ) -> Bool {
689
- var s = stat ( )
690
- guard lstat ( path, & s) >= 0 else {
691
- return false
692
- }
693
-
694
- if ( s. st_mode & S_IFMT) == S_IFLNK {
695
- // don't chase the link for this magic case -- we might be /Net/foo
696
- // which is a symlink to /private/Net/foo which is not yet mounted...
697
- if isDirectory == nil && ( s. st_mode & S_ISVTX) == S_ISVTX {
698
- return true
699
- }
700
- // chase the link; too bad if it is a slink to /Net/foo
701
- guard stat ( path, & s) >= 0 else {
713
+ return _fileSystemRepresentation ( withPath: path, { fsRep in
714
+ guard var s = try ? _lstatFile ( atPath: path, withFileSystemRepresentation: fsRep) else {
702
715
return false
703
716
}
704
- }
705
717
706
- if let isDirectory = isDirectory {
707
- isDirectory. pointee = ObjCBool ( ( s. st_mode & S_IFMT) == S_IFDIR)
708
- }
718
+ if ( s. st_mode & S_IFMT) == S_IFLNK {
719
+ // don't chase the link for this magic case -- we might be /Net/foo
720
+ // which is a symlink to /private/Net/foo which is not yet mounted...
721
+ if isDirectory == nil && ( s. st_mode & S_ISVTX) == S_ISVTX {
722
+ return true
723
+ }
724
+ // chase the link; too bad if it is a slink to /Net/foo
725
+ guard stat ( fsRep, & s) >= 0 else {
726
+ return false
727
+ }
728
+ }
709
729
710
- return true
730
+ if let isDirectory = isDirectory {
731
+ isDirectory. pointee = ObjCBool ( ( s. st_mode & S_IFMT) == S_IFDIR)
732
+ }
733
+
734
+ return true
735
+ } )
711
736
}
712
737
713
738
open func isReadableFile( atPath path: String ) -> Bool {
714
- return access ( path, R_OK) == 0
739
+ return _fileSystemRepresentation ( withPath: path, {
740
+ access ( $0, R_OK) == 0
741
+ } )
715
742
}
716
743
717
744
open func isWritableFile( atPath path: String ) -> Bool {
718
- return access ( path, W_OK) == 0
745
+ return _fileSystemRepresentation ( withPath: path, {
746
+ access ( $0, W_OK) == 0
747
+ } )
719
748
}
720
749
721
750
open func isExecutableFile( atPath path: String ) -> Bool {
722
- return access ( path, X_OK) == 0
751
+ return _fileSystemRepresentation ( withPath: path, {
752
+ access ( $0, X_OK) == 0
753
+ } )
723
754
}
724
755
725
756
open func isDeletableFile( atPath path: String ) -> Bool {
@@ -812,10 +843,14 @@ open class FileManager : NSObject {
812
843
let _fsRep : UnsafePointer < Int8 >
813
844
if fsRep == nil {
814
845
_fsRep = fileSystemRepresentation ( withPath: path)
815
- defer { _fsRep. deallocate ( ) }
816
846
} else {
817
847
_fsRep = fsRep!
818
848
}
849
+
850
+ defer {
851
+ if fsRep == nil { _fsRep. deallocate ( ) }
852
+ }
853
+
819
854
var statInfo = stat ( )
820
855
guard lstat ( _fsRep, & statInfo) == 0 else {
821
856
throw _NSErrorWithErrno ( errno, reading: true , path: path)
@@ -961,7 +996,24 @@ open class FileManager : NSObject {
961
996
}
962
997
return UnsafePointer ( buf)
963
998
}
964
-
999
+
1000
+ internal func _fileSystemRepresentation< ResultType> ( withPath path: String , _ body: ( UnsafePointer < Int8 > ) throws -> ResultType ) rethrows -> ResultType {
1001
+ let fsRep = fileSystemRepresentation ( withPath: path)
1002
+ defer { fsRep. deallocate ( ) }
1003
+ return try body ( fsRep)
1004
+ }
1005
+
1006
+ internal func _fileSystemRepresentation< ResultType> ( withPath path1: String , andPath path2: String , _ body: ( UnsafePointer < Int8 > , UnsafePointer < Int8 > ) throws -> ResultType ) rethrows -> ResultType {
1007
+
1008
+ let fsRep1 = fileSystemRepresentation ( withPath: path1)
1009
+ let fsRep2 = fileSystemRepresentation ( withPath: path2)
1010
+ defer {
1011
+ fsRep1. deallocate ( )
1012
+ fsRep2. deallocate ( )
1013
+ }
1014
+ return try body ( fsRep1, fsRep2)
1015
+ }
1016
+
965
1017
/* stringWithFileSystemRepresentation:length: returns an NSString created from an array of bytes that are in the filesystem representation.
966
1018
*/
967
1019
open func string( withFileSystemRepresentation str: UnsafePointer < Int8 > , length len: Int ) -> String {
0 commit comments