Skip to content

Commit cabbc54

Browse files
committed
Allow Foundation to create file with permissions respects process umask
**Problem** `Data.write(to:)` is a only method in the Foundation that can create a regular file. However, it ignores `uamask` and always set 0600 permission unlike macOS Foundation, which respects process `umask`. **Solution** 1. With `.atomic` write option It uses `mkstemp(3)` in `_NSCreateTemporaryFile`, which is always creating a file with 0600 permission, if the system follows the latest POSIX specification or the permission is undefined. On macOS Foundation, therefore `_NSCreateTemporaryFile` uses `mktemp(3)` and `open(2)` instead to respect `umask`. 2. Without `.atomic` write option It uses `0o600` even if it uses `open(2)` that respects `umask`. Simply gives `0o666` instead. This is a bug caused by previous commit in swiftlang#1876. JIRA: https://bugs.swift.org/browse/SR-13307
1 parent 38b6914 commit cabbc54

File tree

2 files changed

+17
-6
lines changed

2 files changed

+17
-6
lines changed

Sources/Foundation/NSData.swift

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -434,10 +434,10 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
434434
}
435435

436436
let fm = FileManager.default
437-
// The destination file path may not exist so provide a default file permissions of RW user only
438-
let permissions = (try? fm._permissionsOfItem(atPath: path)) ?? 0o600
437+
let permissions = try? fm._permissionsOfItem(atPath: path)
439438

440439
if writeOptionsMask.contains(.atomic) {
440+
// Okay... how to use umask to create tempfile?
441441
let (newFD, auxFilePath) = try _NSCreateTemporaryFile(path)
442442
let fh = FileHandle(fileDescriptor: newFD, closeOnDealloc: true)
443443
do {
@@ -446,7 +446,9 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
446446
// requires that there be no open handles to the file
447447
fh.closeFile()
448448
try _NSCleanupTemporaryFile(auxFilePath, path)
449-
try fm.setAttributes([.posixPermissions: NSNumber(value: permissions)], ofItemAtPath: path)
449+
if let permissions = permissions {
450+
try fm.setAttributes([.posixPermissions: NSNumber(value: permissions)], ofItemAtPath: path)
451+
}
450452
} catch {
451453
let savedErrno = errno
452454
try? fm.removeItem(atPath: auxFilePath)
@@ -457,11 +459,15 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
457459
if writeOptionsMask.contains(.withoutOverwriting) {
458460
flags |= O_EXCL
459461
}
462+
let createMode = Int(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
460463

461-
guard let fh = FileHandle(path: path, flags: flags, createMode: permissions) else {
464+
guard let fh = FileHandle(path: path, flags: flags, createMode: createMode) else {
462465
throw _NSErrorWithErrno(errno, reading: false, path: path)
463466
}
464467
try doWrite(fh)
468+
if let permissions = permissions {
469+
try fm.setAttributes([.posixPermissions: NSNumber(value: permissions)], ofItemAtPath: path)
470+
}
465471
}
466472
}
467473

Sources/Foundation/NSPathUtilities.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -760,10 +760,15 @@ internal func _NSCreateTemporaryFile(_ filePath: String) throws -> (Int32, Strin
760760
let maxLength = Int(PATH_MAX) + 1
761761
var buf = [Int8](repeating: 0, count: maxLength)
762762
let _ = template._nsObject.getFileSystemRepresentation(&buf, maxLength: maxLength)
763-
let fd = mkstemp(&buf)
764-
if fd == -1 {
763+
764+
guard let name = mktemp(&buf) else {
765+
throw _NSErrorWithErrno(errno, reading: false, path: filePath)
766+
}
767+
let fd = open(name, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)
768+
if fd != 1 {
765769
throw _NSErrorWithErrno(errno, reading: false, path: filePath)
766770
}
771+
767772
let pathResult = FileManager.default.string(withFileSystemRepresentation: buf, length: Int(strlen(buf)))
768773
#endif
769774
return (fd, pathResult)

0 commit comments

Comments
 (0)