@@ -434,7 +434,81 @@ open class FileManager : NSObject {
434434
435435 return self . string ( withFileSystemRepresentation: buf, length: Int ( len) )
436436 }
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+
438512 open func copyItem( atPath srcPath: String , toPath dstPath: String ) throws {
439513 guard
440514 let attrs = try ? attributesOfItem ( atPath: srcPath) ,
@@ -448,18 +522,20 @@ open class FileManager : NSObject {
448522 let destination = try destinationOfSymbolicLink ( atPath: srcPath)
449523 try createSymbolicLink ( atPath: dstPath, withDestinationPath: destination)
450524 } 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)
454526 }
455527 }
456528
457529 if fileType == . typeDirectory {
458530 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
463539 if let attrs = try ? attributesOfItem ( atPath: src) , let fileType = attrs [ . type] as? FileAttributeType {
464540 if fileType == . typeDirectory {
465541 try createDirectory ( atPath: dst, withIntermediateDirectories: false , attributes: nil )
0 commit comments