@@ -433,100 +433,46 @@ 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. _writeBytes ( 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. synchronize ( )
447+ }
448+
449+ let fm = FileManager . default
450+ // The destination file path may not exist so provide a default file permissions of RW user only
451+ let permissions = ( try ? fm. _permissionsOfItem ( atPath: path) ) ?? 0o600
452+
453+ if writeOptionsMask. contains ( . atomic) {
454+ let ( newFD, auxFilePath) = try _NSCreateTemporaryFile ( path)
455+ let fh = FileHandle ( fileDescriptor: newFD, closeOnDealloc: true )
456+ do {
457+ try doWrite ( fh)
458+ try _NSCleanupTemporaryFile ( auxFilePath, path)
459+ try fm. setAttributes ( [ . posixPermissions: NSNumber ( value: permissions) ] , ofItemAtPath: path)
460+ } catch {
461+ let savedErrno = errno
462+ try ? fm. removeItem ( atPath: auxFilePath)
463+ throw _NSErrorWithErrno ( savedErrno, reading: false , path: path)
528464 }
529- } )
465+ } else {
466+ var flags = O_WRONLY | O_CREAT | O_TRUNC
467+ if writeOptionsMask. contains ( . withoutOverwriting) {
468+ flags |= O_EXCL
469+ }
470+
471+ guard let fh = FileHandle ( path: path, flags: flags, createMode: permissions) else {
472+ throw _NSErrorWithErrno ( errno, reading: false , path: path)
473+ }
474+ try doWrite ( fh)
475+ }
530476 }
531477
532478 /// Writes the data object's bytes to the file specified by a given path.
0 commit comments