@@ -433,100 +433,46 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
433
433
return result
434
434
}
435
435
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
- }
467
436
468
437
/// Writes the data object's bytes to the file specified by a given path.
469
438
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
- }
501
439
440
+ func doWrite( _ fh: FileHandle ) throws {
502
441
try self . enumerateByteRangesUsingBlockRethrows { ( buf, range, stop) in
503
442
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)
515
444
}
516
445
}
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)
528
464
}
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
+ }
530
476
}
531
477
532
478
/// Writes the data object's bytes to the file specified by a given path.
0 commit comments