@@ -433,100 +433,47 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
433433 return result
434434 }
435435
436- internal func makeTemporaryFile( inDirectory dirPath: String ) throws -> ( Int32 , String ) {
437- let template = dirPath. _nsObject. appendingPathComponent ( " tmp.XXXXXX " )
438- let maxLength = Int ( PATH_MAX) + 1
439- var buf = [ Int8] ( repeating: 0 , count: maxLength)
440- let _ = template. _nsObject. getFileSystemRepresentation ( & buf, maxLength: maxLength)
441- let fd = mkstemp ( & buf)
442- if fd == - 1 {
443- throw _NSErrorWithErrno ( errno, reading: false , path: dirPath)
444- }
445- let pathResult = FileManager . default. string ( withFileSystemRepresentation: buf, length: Int ( strlen ( buf) ) )
446- return ( fd, pathResult)
447- }
448-
449- internal class func write( toFileDescriptor fd: Int32 , path: String ? = nil , buf: UnsafeRawPointer , length: Int ) throws {
450- var bytesRemaining = length
451- while bytesRemaining > 0 {
452- var bytesWritten : Int
453- repeat {
454- #if os(macOS) || os(iOS)
455- bytesWritten = Darwin . write ( fd, buf. advanced ( by: length - bytesRemaining) , bytesRemaining)
456- #elseif os(Linux) || os(Android) || CYGWIN
457- bytesWritten = Glibc . write ( fd, buf. advanced ( by: length - bytesRemaining) , bytesRemaining)
458- #endif
459- } while ( bytesWritten < 0 && errno == EINTR)
460- if bytesWritten <= 0 {
461- throw _NSErrorWithErrno ( errno, reading: false , path: path)
462- } else {
463- bytesRemaining -= bytesWritten
464- }
465- }
466- }
467436
468437 /// Writes the data object's bytes to the file specified by a given path.
469438 open func write( toFile path: String , options writeOptionsMask: WritingOptions = [ ] ) throws {
470- let fm = FileManager . default
471- try fm. _fileSystemRepresentation ( withPath: path, { pathFsRep in
472- var fd : Int32
473- var mode : mode_t ? = nil
474- let useAuxiliaryFile = writeOptionsMask. contains ( . atomic)
475- var auxFilePath : String ? = nil
476- if useAuxiliaryFile {
477- // Preserve permissions.
478- var info = stat ( )
479- if lstat ( pathFsRep, & info) == 0 {
480- let mode = mode_t ( info. st_mode)
481- } else if errno != ENOENT && errno != ENAMETOOLONG {
482- throw _NSErrorWithErrno ( errno, reading: false , path: path)
483- }
484- let ( newFD, path) = try self . makeTemporaryFile ( inDirectory: path. _nsObject. deletingLastPathComponent)
485- fd = newFD
486- auxFilePath = path
487- fchmod ( fd, 0o666 )
488- } else {
489- var flags = O_WRONLY | O_CREAT | O_TRUNC
490- if writeOptionsMask. contains ( . withoutOverwriting) {
491- flags |= O_EXCL
492- }
493- fd = _CFOpenFileWithMode ( path, flags, 0o666 )
494- }
495- if fd == - 1 {
496- throw _NSErrorWithErrno ( errno, reading: false , path: path)
497- }
498- defer {
499- close ( fd)
500- }
501439
440+ func doWrite( _ fh: FileHandle ) throws {
502441 try self . enumerateByteRangesUsingBlockRethrows { ( buf, range, stop) in
503442 if range. length > 0 {
504- do {
505- try NSData . write ( toFileDescriptor: fd, path: path, buf: buf, length: range. length)
506- if fsync ( fd) < 0 {
507- throw _NSErrorWithErrno ( errno, reading: false , path: path)
508- }
509- } catch {
510- if let auxFilePath = auxFilePath {
511- try ? FileManager . default. removeItem ( atPath: auxFilePath)
512- }
513- throw error
514- }
443+ try fh. _write ( buf: buf, length: range. length)
515444 }
516445 }
517- if let auxFilePath = auxFilePath {
518- try fm. _fileSystemRepresentation ( withPath: auxFilePath, { auxFilePathFsRep in
519- if rename ( auxFilePathFsRep, pathFsRep) != 0 {
520- let savedErrno = errno
521- try ? FileManager . default. removeItem ( atPath: auxFilePath)
522- throw _NSErrorWithErrno ( savedErrno, reading: false , path: path)
523- }
524- if let mode = mode {
525- chmod ( pathFsRep, mode)
526- }
527- } )
446+ try fh. _synchronizeFile ( )
447+ }
448+
449+ let fm = FileManager . default
450+ // The destination file path may not exist so provide a default file mode of RW user only
451+ let permissions = ( try ? fm. attributesOfItem ( atPath: path) [ . posixPermissions] ) as? NSNumber
452+ let mode = permissions? . intValue ?? 0o600
453+
454+ if writeOptionsMask. contains ( . atomic) {
455+ let ( newFD, auxFilePath) = try _NSCreateTemporaryFile ( path)
456+ let fh = FileHandle ( fileDescriptor: newFD, closeOnDealloc: true )
457+ do {
458+ try doWrite ( fh)
459+ try _NSCleanupTemporaryFile ( auxFilePath, path)
460+ try fm. setAttributes ( [ . posixPermissions: NSNumber ( value: mode) ] , ofItemAtPath: path)
461+ } catch {
462+ let savedErrno = errno
463+ try ? fm. removeItem ( atPath: auxFilePath)
464+ throw _NSErrorWithErrno ( savedErrno, reading: false , path: path)
528465 }
529- } )
466+ } else {
467+ var flags = O_WRONLY | O_CREAT | O_TRUNC
468+ if writeOptionsMask. contains ( . withoutOverwriting) {
469+ flags |= O_EXCL
470+ }
471+
472+ guard let fh = FileHandle ( path: path, flags: flags, createMode: mode) else {
473+ throw _NSErrorWithErrno ( errno, reading: false , path: path)
474+ }
475+ try doWrite ( fh)
476+ }
530477 }
531478
532479 /// Writes the data object's bytes to the file specified by a given path.
0 commit comments