@@ -434,7 +434,81 @@ open class FileManager : NSObject {
434
434
435
435
return self . string ( withFileSystemRepresentation: buf, length: Int ( len) )
436
436
}
437
-
437
+
438
+ private func _readFrom( fd: Int32 , toBuffer buffer: UnsafeMutablePointer < UInt8 > , length bytesToRead: Int , filename: String ) throws -> Int {
439
+ var bytesRead = 0
440
+
441
+ repeat {
442
+ bytesRead = read ( fd, buffer, bytesToRead)
443
+ } while bytesRead < 0 && errno == EINTR
444
+ guard bytesRead >= 0 else {
445
+ throw _NSErrorWithErrno ( errno, reading: true , path: filename)
446
+ }
447
+ return bytesRead
448
+ }
449
+
450
+ private func _writeTo( fd: Int32 , fromBuffer buffer : UnsafeMutablePointer < UInt8 > , length bytesToWrite: Int , filename: String ) throws {
451
+ var bytesWritten = 0
452
+ while bytesWritten < bytesToWrite {
453
+ var written = 0
454
+ let bytesLeftToWrite = bytesToWrite - bytesWritten
455
+ repeat {
456
+ written = write ( fd, buffer. advanced ( by: bytesWritten) , bytesLeftToWrite)
457
+ } while written < 0 && errno == EINTR
458
+ guard written >= 0 else {
459
+ throw _NSErrorWithErrno ( errno, reading: false , path: filename)
460
+ }
461
+ bytesWritten += written
462
+ }
463
+ }
464
+
465
+ private func _copyRegularFile( atPath srcPath: String , toPath dstPath: String ) throws {
466
+ let srcRep = fileSystemRepresentation ( withPath: srcPath)
467
+ let dstRep = fileSystemRepresentation ( withPath: dstPath)
468
+ defer {
469
+ srcRep. deallocate ( )
470
+ dstRep. deallocate ( )
471
+ }
472
+
473
+ var fileInfo = stat ( )
474
+ guard stat ( srcRep, & fileInfo) >= 0 else {
475
+ throw _NSErrorWithErrno ( errno, reading: true , path: srcPath)
476
+ }
477
+
478
+ let srcfd = open ( srcRep, O_RDONLY)
479
+ guard srcfd >= 0 else {
480
+ throw _NSErrorWithErrno ( errno, reading: true , path: srcPath)
481
+ }
482
+ defer { close ( srcfd) }
483
+
484
+ let dstfd = open ( dstRep, O_WRONLY | O_CREAT | O_TRUNC, 0o666 )
485
+ guard dstfd >= 0 else {
486
+ throw _NSErrorWithErrno ( errno, reading: false , path: dstPath)
487
+ }
488
+ defer { close ( dstfd) }
489
+
490
+ if fileInfo. st_size == 0 {
491
+ // no copying required
492
+ return
493
+ }
494
+
495
+ let buffer = UnsafeMutablePointer< UInt8> . allocate( capacity: Int ( fileInfo. st_blksize) )
496
+ defer { buffer. deallocate ( ) }
497
+
498
+ var bytesRemaining = Int64 ( fileInfo. st_size)
499
+ while bytesRemaining > 0 {
500
+ let bytesToRead = min ( bytesRemaining, Int64 ( fileInfo. st_blksize) )
501
+ let bytesRead = try _readFrom ( fd: srcfd, toBuffer: buffer, length: Int ( bytesToRead) , filename: srcPath)
502
+ if bytesRead == 0 {
503
+ // Early EOF
504
+ return
505
+ }
506
+ try _writeTo ( fd: dstfd, fromBuffer: buffer, length: bytesRead, filename: dstPath)
507
+ bytesRemaining -= Int64 ( bytesRead)
508
+ }
509
+ }
510
+
511
+
438
512
open func copyItem( atPath srcPath: String , toPath dstPath: String ) throws {
439
513
guard
440
514
let attrs = try ? attributesOfItem ( atPath: srcPath) ,
@@ -448,18 +522,20 @@ open class FileManager : NSObject {
448
522
let destination = try destinationOfSymbolicLink ( atPath: srcPath)
449
523
try createSymbolicLink ( atPath: dstPath, withDestinationPath: destination)
450
524
} else if fileType == . typeRegular {
451
- if createFile ( atPath: dstPath, contents: contents ( atPath: srcPath) , attributes: nil ) == false {
452
- throw NSError ( domain: NSCocoaErrorDomain, code: CocoaError . fileWriteUnknown. rawValue, userInfo: [ NSFilePathErrorKey : NSString ( string: dstPath) ] )
453
- }
525
+ try _copyRegularFile ( atPath: srcPath, toPath: dstPath)
454
526
}
455
527
}
456
528
457
529
if fileType == . typeDirectory {
458
530
try createDirectory ( atPath: dstPath, withIntermediateDirectories: false , attributes: nil )
459
- let subpaths = try subpathsOfDirectory ( atPath: srcPath)
460
- for subpath in subpaths {
461
- let src = srcPath + " / " + subpath
462
- let dst = dstPath + " / " + subpath
531
+
532
+ guard let enumerator = enumerator ( atPath: srcPath) else {
533
+ throw _NSErrorWithErrno ( ENOENT, reading: true , path: srcPath)
534
+ }
535
+
536
+ while let item = enumerator. nextObject ( ) as? String {
537
+ let src = srcPath + " / " + item
538
+ let dst = dstPath + " / " + item
463
539
if let attrs = try ? attributesOfItem ( atPath: src) , let fileType = attrs [ . type] as? FileAttributeType {
464
540
if fileType == . typeDirectory {
465
541
try createDirectory ( atPath: dst, withIntermediateDirectories: false , attributes: nil )
0 commit comments