| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672 |
- /*
- This source file is part of the Swift System open source project
- Copyright (c) 2020 - 2026 Apple Inc. and the Swift System project authors
- Licensed under Apache License v2.0 with Runtime Library Exception
- See https://swift.org/LICENSE.txt for license information
- */
- @available(System 0.0.1, *)
- extension FileDescriptor {
- /// Opens or creates a file for reading or writing.
- ///
- /// - Parameters:
- /// - path: The location of the file to open.
- /// - mode: The read and write access to use.
- /// - options: The behavior for opening the file.
- /// - permissions: The file permissions to use for created files.
- /// This value must not be `nil` when `options` contains `.create`;
- /// passing `nil` in that case is a programmer error and traps at runtime.
- /// - retryOnInterrupt: Whether to retry the open operation
- /// if it throws ``Errno/interrupted``.
- /// The default is `true`.
- /// Pass `false` to try only once and throw an error upon interruption.
- /// - Returns: A file descriptor for the open file
- ///
- /// The corresponding C function is `open`.
- @_alwaysEmitIntoClient
- public static func open(
- _ path: FilePath,
- _ mode: FileDescriptor.AccessMode,
- options: FileDescriptor.OpenOptions = FileDescriptor.OpenOptions(),
- permissions: FilePermissions? = nil,
- retryOnInterrupt: Bool = true
- ) throws -> FileDescriptor {
- #if !os(Windows)
- return try path.withCString {
- try FileDescriptor.open(
- $0, mode, options: options, permissions: permissions, retryOnInterrupt: retryOnInterrupt)
- }
- #else
- return try path.withPlatformString {
- try FileDescriptor.open(
- $0, mode, options: options, permissions: permissions, retryOnInterrupt: retryOnInterrupt)
- }
- #endif
- }
- #if !os(Windows)
- // On Darwin, `CInterop.PlatformChar` is less available than
- // `FileDescriptor.open`, so we need to use `CChar` instead.
-
- /// Opens or creates a file for reading or writing.
- ///
- /// - Parameters:
- /// - path: The location of the file to open.
- /// - mode: The read and write access to use.
- /// - options: The behavior for opening the file.
- /// - permissions: The file permissions to use for created files.
- /// This value must not be `nil` when `options` contains `.create`;
- /// passing `nil` in that case is a programmer error and traps at runtime.
- /// - retryOnInterrupt: Whether to retry the open operation
- /// if it throws ``Errno/interrupted``.
- /// The default is `true`.
- /// Pass `false` to try only once and throw an error upon interruption.
- /// - Returns: A file descriptor for the open file
- ///
- /// The corresponding C function is `open`.
- @_alwaysEmitIntoClient
- public static func open(
- _ path: UnsafePointer<CChar>,
- _ mode: FileDescriptor.AccessMode,
- options: FileDescriptor.OpenOptions = FileDescriptor.OpenOptions(),
- permissions: FilePermissions? = nil,
- retryOnInterrupt: Bool = true
- ) throws -> FileDescriptor {
- try FileDescriptor._open(
- path, mode, options: options, permissions: permissions, retryOnInterrupt: retryOnInterrupt
- ).get()
- }
- @usableFromInline
- internal static func _open(
- _ path: UnsafePointer<CChar>,
- _ mode: FileDescriptor.AccessMode,
- options: FileDescriptor.OpenOptions,
- permissions: FilePermissions?,
- retryOnInterrupt: Bool
- ) -> Result<FileDescriptor, Errno> {
- let oFlag = mode.rawValue | options.rawValue
- let descOrError: Result<CInt, Errno> = valueOrErrno(retryOnInterrupt: retryOnInterrupt) {
- if let permissions = permissions {
- return system_open(path, oFlag, permissions.rawValue)
- }
- if options.contains(.create) {
- fatalError(
- "FileDescriptor.open: 'permissions' must not be nil when 'options' contains '.create'")
- }
- return system_open(path, oFlag)
- }
- return descOrError.map { FileDescriptor(rawValue: $0) }
- }
- #else
- /// Opens or creates a file for reading or writing.
- ///
- /// - Parameters:
- /// - path: The location of the file to open.
- /// - mode: The read and write access to use.
- /// - options: The behavior for opening the file.
- /// - permissions: The file permissions to use for created files.
- /// This value must not be `nil` when `options` contains `.create`;
- /// passing `nil` in that case is a programmer error and traps at runtime.
- /// - retryOnInterrupt: Whether to retry the open operation
- /// if it throws ``Errno/interrupted``.
- /// The default is `true`.
- /// Pass `false` to try only once and throw an error upon interruption.
- /// - Returns: A file descriptor for the open file
- ///
- /// The corresponding C function is `open`.
- @_alwaysEmitIntoClient
- public static func open(
- _ path: UnsafePointer<CInterop.PlatformChar>,
- _ mode: FileDescriptor.AccessMode,
- options: FileDescriptor.OpenOptions = FileDescriptor.OpenOptions(),
- permissions: FilePermissions? = nil,
- retryOnInterrupt: Bool = true
- ) throws -> FileDescriptor {
- try FileDescriptor._open(
- path, mode, options: options, permissions: permissions, retryOnInterrupt: retryOnInterrupt
- ).get()
- }
- @usableFromInline
- internal static func _open(
- _ path: UnsafePointer<CInterop.PlatformChar>,
- _ mode: FileDescriptor.AccessMode,
- options: FileDescriptor.OpenOptions,
- permissions: FilePermissions?,
- retryOnInterrupt: Bool
- ) -> Result<FileDescriptor, Errno> {
- let oFlag = mode.rawValue | options.rawValue
- let descOrError: Result<CInt, Errno> = valueOrErrno(retryOnInterrupt: retryOnInterrupt) {
- if let permissions = permissions {
- return system_open(path, oFlag, permissions.rawValue)
- }
- return system_open(path, oFlag)
- }
- return descOrError.map { FileDescriptor(rawValue: $0) }
- }
- #endif
- /// Deletes a file descriptor.
- ///
- /// Deletes the file descriptor from the per-process object reference table.
- /// If this is the last reference to the underlying object,
- /// the object will be deactivated.
- ///
- /// The corresponding C function is `close`.
- @_alwaysEmitIntoClient
- public func close() throws { try _close().get() }
- @usableFromInline
- internal func _close() -> Result<(), Errno> {
- nothingOrErrno(retryOnInterrupt: false) { system_close(self.rawValue) }
- }
- /// Repositions the offset for the given file descriptor.
- ///
- /// - Parameters:
- /// - offset: The new offset for the file descriptor.
- /// - whence: The origin of the new offset.
- /// - Returns: The file's offset location,
- /// in bytes from the beginning of the file.
- ///
- /// The corresponding C function is `lseek`.
- @_alwaysEmitIntoClient
- @discardableResult
- public func seek(
- offset: Int64, from whence: FileDescriptor.SeekOrigin
- ) throws -> Int64 {
- try _seek(offset: offset, from: whence).get()
- }
- @usableFromInline
- internal func _seek(
- offset: Int64, from whence: FileDescriptor.SeekOrigin
- ) -> Result<Int64, Errno> {
- valueOrErrno(retryOnInterrupt: false) {
- Int64(system_lseek(self.rawValue, _COffT(offset), whence.rawValue))
- }
- }
- @_alwaysEmitIntoClient
- @available(*, unavailable, renamed: "seek")
- public func lseek(
- offset: Int64, from whence: FileDescriptor.SeekOrigin
- ) throws -> Int64 {
- try seek(offset: offset, from: whence)
- }
- /// Reads bytes at the current file offset into a buffer.
- ///
- /// - Parameters:
- /// - buffer: The region of memory to read into.
- /// - retryOnInterrupt: Whether to retry the read operation
- /// if it throws ``Errno/interrupted``.
- /// The default is `true`.
- /// Pass `false` to try only once and throw an error upon interruption.
- /// - Returns: The number of bytes that were read.
- ///
- /// The <doc://com.apple.documentation/documentation/swift/unsafemutablerawbufferpointer/count-95usp> property of `buffer`
- /// determines the maximum number of bytes that are read into that buffer.
- ///
- /// After reading,
- /// this method increments the file's offset by the number of bytes read.
- /// To change the file's offset,
- /// call the ``seek(offset:from:)`` method.
- ///
- /// The corresponding C function is `read`.
- @_alwaysEmitIntoClient
- public func read(
- into buffer: UnsafeMutableRawBufferPointer,
- retryOnInterrupt: Bool = true
- ) throws -> Int {
- try _read(into: buffer, retryOnInterrupt: retryOnInterrupt).get()
- }
- @usableFromInline
- internal func _read(
- into buffer: UnsafeMutableRawBufferPointer,
- retryOnInterrupt: Bool
- ) -> Result<Int, Errno> {
- valueOrErrno(retryOnInterrupt: retryOnInterrupt) {
- system_read(self.rawValue, buffer.baseAddress, buffer.count)
- }
- }
- /// Reads bytes at the specified offset into a buffer.
- ///
- /// - Parameters:
- /// - offset: The file offset where reading begins.
- /// - buffer: The region of memory to read into.
- /// - retryOnInterrupt: Whether to retry the read operation
- /// if it throws ``Errno/interrupted``.
- /// The default is `true`.
- /// Pass `false` to try only once and throw an error upon interruption.
- /// - Returns: The number of bytes that were read.
- ///
- /// The <doc://com.apple.documentation/documentation/swift/unsafemutablerawbufferpointer/count-95usp> property of `buffer`
- /// determines the maximum number of bytes that are read into that buffer.
- ///
- /// Unlike <doc:FileDescriptor/read(into:retryOnInterrupt:)>,
- /// this method leaves the file's existing offset unchanged.
- ///
- /// The corresponding C function is `pread`.
- @_alwaysEmitIntoClient
- public func read(
- fromAbsoluteOffset offset: Int64,
- into buffer: UnsafeMutableRawBufferPointer,
- retryOnInterrupt: Bool = true
- ) throws -> Int {
- try _read(
- fromAbsoluteOffset: offset,
- into: buffer,
- retryOnInterrupt: retryOnInterrupt
- ).get()
- }
- @usableFromInline
- internal func _read(
- fromAbsoluteOffset offset: Int64,
- into buffer: UnsafeMutableRawBufferPointer,
- retryOnInterrupt: Bool
- ) -> Result<Int, Errno> {
- valueOrErrno(retryOnInterrupt: retryOnInterrupt) {
- system_pread(self.rawValue, buffer.baseAddress, buffer.count, _COffT(offset))
- }
- }
- @_alwaysEmitIntoClient
- @available(*, unavailable, renamed: "read")
- public func pread(
- fromAbsoluteOffset offset: Int64,
- into buffer: UnsafeMutableRawBufferPointer,
- retryOnInterrupt: Bool = true
- ) throws -> Int {
- try read(
- fromAbsoluteOffset: offset,
- into: buffer,
- retryOnInterrupt: retryOnInterrupt)
- }
- /// Writes the contents of a buffer at the current file offset.
- ///
- /// - Parameters:
- /// - buffer: The region of memory that contains the data being written.
- /// - retryOnInterrupt: Whether to retry the write operation
- /// if it throws ``Errno/interrupted``.
- /// The default is `true`.
- /// Pass `false` to try only once and throw an error upon interruption.
- /// - Returns: The number of bytes that were written.
- ///
- /// After writing,
- /// this method increments the file's offset by the number of bytes written.
- /// To change the file's offset,
- /// call the ``seek(offset:from:)`` method.
- ///
- /// The corresponding C function is `write`.
- @_alwaysEmitIntoClient
- public func write(
- _ buffer: UnsafeRawBufferPointer,
- retryOnInterrupt: Bool = true
- ) throws -> Int {
- try _write(buffer, retryOnInterrupt: retryOnInterrupt).get()
- }
- @usableFromInline
- internal func _write(
- _ buffer: UnsafeRawBufferPointer,
- retryOnInterrupt: Bool
- ) -> Result<Int, Errno> {
- valueOrErrno(retryOnInterrupt: retryOnInterrupt) {
- system_write(self.rawValue, buffer.baseAddress, buffer.count)
- }
- }
- /// Writes the contents of a buffer at the specified offset.
- ///
- /// - Parameters:
- /// - offset: The file offset where writing begins.
- /// - buffer: The region of memory that contains the data being written.
- /// - retryOnInterrupt: Whether to retry the write operation
- /// if it throws ``Errno/interrupted``.
- /// The default is `true`.
- /// Pass `false` to try only once and throw an error upon interruption.
- /// - Returns: The number of bytes that were written.
- ///
- /// Unlike ``write(_:retryOnInterrupt:)``,
- /// this method leaves the file's existing offset unchanged.
- ///
- /// The corresponding C function is `pwrite`.
- @_alwaysEmitIntoClient
- public func write(
- toAbsoluteOffset offset: Int64,
- _ buffer: UnsafeRawBufferPointer,
- retryOnInterrupt: Bool = true
- ) throws -> Int {
- try _write(toAbsoluteOffset: offset, buffer, retryOnInterrupt: retryOnInterrupt).get()
- }
- @usableFromInline
- internal func _write(
- toAbsoluteOffset offset: Int64,
- _ buffer: UnsafeRawBufferPointer,
- retryOnInterrupt: Bool
- ) -> Result<Int, Errno> {
- valueOrErrno(retryOnInterrupt: retryOnInterrupt) {
- system_pwrite(self.rawValue, buffer.baseAddress, buffer.count, _COffT(offset))
- }
- }
- @_alwaysEmitIntoClient
- @available(*, unavailable, renamed: "write")
- public func pwrite(
- toAbsoluteOffset offset: Int64,
- into buffer: UnsafeRawBufferPointer,
- retryOnInterrupt: Bool = true
- ) throws -> Int {
- try write(
- toAbsoluteOffset: offset,
- buffer,
- retryOnInterrupt: retryOnInterrupt)
- }
- }
- #if !os(WASI)
- @available(System 0.0.2, *)
- extension FileDescriptor {
- /// Duplicates this file descriptor and returns the newly created copy.
- ///
- /// - Parameters:
- /// - `target`: The desired target file descriptor, or `nil`, in which case
- /// the copy is assigned to the file descriptor with the lowest raw value
- /// that is not currently in use by the process.
- /// - retryOnInterrupt: Whether to retry the duplicate operation
- /// if it throws ``Errno/interrupted``. The default is `true`.
- /// Pass `false` to try only once and throw an error upon interruption.
- /// - Returns: The new file descriptor.
- ///
- /// If the `target` descriptor is already in use, then it is first
- /// deallocated as if a close(2) call had been done first.
- ///
- /// File descriptors are merely references to some underlying system resource.
- /// The system does not distinguish between the original and the new file
- /// descriptor in any way. For example, read, write and seek operations on
- /// one of them also affect the logical file position in the other, and
- /// append mode, non-blocking I/O and asynchronous I/O options are shared
- /// between the references. If a separate pointer into the file is desired,
- /// a different object reference to the file must be obtained by issuing an
- /// additional call to `open`.
- ///
- /// However, each file descriptor maintains its own close-on-exec flag.
- ///
- /// The corresponding C functions are `dup` and `dup2`.
- @_alwaysEmitIntoClient
- @available(System 0.0.2, *)
- public func duplicate(
- as target: FileDescriptor? = nil,
- retryOnInterrupt: Bool = true
- ) throws -> FileDescriptor {
- try _duplicate(as: target, retryOnInterrupt: retryOnInterrupt).get()
- }
- /// Duplicate this file descriptor and return the newly created copy.
- ///
- /// - Parameters:
- /// - target: The desired target file descriptor.
- /// - options: The behavior for creating the target file descriptor.
- /// - retryOnInterrupt: Whether to retry the operation
- /// if it throws ``Errno/interrupted``. The default is `true`.
- /// Pass `false` to try only once and throw an error upon interruption.
- /// - Returns: The new file descriptor.
- ///
- /// If the `target` descriptor is the same as `self`, then EINVAL is thrown.
- /// If the `target` descriptor is already in use, then it is first
- /// deallocated as if a close(2) call had been done first.
- ///
- /// NOTE: This overload called with an empty option set is not necessarily
- /// equivalent to calling the overload with no options, because `dup3` with
- /// no set options is not required to behave identically to `dup2`.
- ///
- /// File descriptors are merely references to some underlying system resource.
- /// The system does not distinguish between the original and the new file
- /// descriptor in any way. For example, read, write and seek operations on
- /// one of them also affect the logical file position in the other, and
- /// append mode, non-blocking I/O and asynchronous I/O options are shared
- /// between the references. If a separate pointer into the file is desired,
- /// a different object reference to the file must be obtained by issuing an
- /// additional call to `open`.
- ///
- /// However, each file descriptor maintains its own close-on-exec and
- /// close-on-fork flags.
- ///
- /// The corresponding C function is `dup3`.
- @available(Windows, unavailable)
- @available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
- @_alwaysEmitIntoClient
- @discardableResult
- public func duplicate(
- as target: FileDescriptor,
- options: DuplicateOptions,
- retryOnInterrupt: Bool = true
- ) throws(Errno) -> FileDescriptor {
- let result = _duplicate(
- as: target, options: options.rawValue, retryOnInterrupt: retryOnInterrupt
- )
- return try result.get()
- }
- @available(System 0.0.2, *)
- @usableFromInline
- internal func _duplicate(
- as target: FileDescriptor?,
- retryOnInterrupt: Bool
- ) -> Result<FileDescriptor, Errno> {
- valueOrErrno(retryOnInterrupt: retryOnInterrupt) {
- if let target {
- system_dup2(self.rawValue, target.rawValue)
- } else {
- system_dup(self.rawValue)
- }
- }.map(FileDescriptor.init(rawValue:))
- }
- @available(Windows, unavailable)
- @available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
- @usableFromInline
- internal func _duplicate(
- as target: FileDescriptor,
- options: Int32,
- retryOnInterrupt: Bool
- ) -> Result<FileDescriptor, Errno> {
- valueOrErrno(retryOnInterrupt: retryOnInterrupt) {
- system_dup3(self.rawValue, target.rawValue, options)
- }.map(FileDescriptor.init(rawValue:))
- }
- @_alwaysEmitIntoClient
- @available(*, unavailable, renamed: "duplicate")
- public func dup() throws -> FileDescriptor {
- fatalError("Not implemented")
- }
- @_alwaysEmitIntoClient
- @available(*, unavailable, renamed: "duplicate")
- public func dup2() throws -> FileDescriptor {
- fatalError("Not implemented")
- }
- @_alwaysEmitIntoClient
- @available(*, unavailable, renamed: "duplicate")
- public func dup3() throws -> FileDescriptor {
- fatalError("Not implemented")
- }
- }
- #endif // !os(WASI)
- #if !os(WASI)
- @available(System 1.1.0, *)
- extension FileDescriptor {
- /// Creates a unidirectional data channel, which can be used for
- /// interprocess communication.
- ///
- /// - Returns: The pair of file descriptors.
- ///
- /// The corresponding C function is `pipe`.
- @_alwaysEmitIntoClient
- @available(System 1.1.0, *)
- public static func pipe(
- ) throws -> (readEnd: FileDescriptor, writeEnd: FileDescriptor) {
- try _pipe().get()
- }
- /// Creates a unidirectional data channel, which can be used for
- /// interprocess communication.
- ///
- /// NOTE: This overload called with an empty option set is not necessarily
- /// equivalent to calling the overload with no options. On Windows, the
- /// no-parameter `pipe()` overload enables the `.closeOnExec` behaviour,
- /// but this overload disables it when called with an empty option set.
- ///
- /// - Parameters:
- /// - options: The behavior for creating the pipe.
- ///
- /// - Returns: The pair of file descriptors.
- ///
- /// The corresponding C function is `pipe2`.
- @_alwaysEmitIntoClient
- @available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
- public static func pipe(
- options: PipeOptions
- ) throws(Errno) -> (readEnd: FileDescriptor, writeEnd: FileDescriptor) {
- try _pipe(options: options.rawValue).get()
- }
- @available(System 1.1.0, *)
- @usableFromInline
- internal static func _pipe(
- ) -> Result<(readEnd: FileDescriptor, writeEnd: FileDescriptor), Errno> {
- var fds: (Int32, Int32) = (-1, -1)
- return withUnsafeMutablePointer(to: &fds) { pointer in
- pointer.withMemoryRebound(to: Int32.self, capacity: 2) { fds in
- valueOrErrno(retryOnInterrupt: false) {
- system_pipe(fds)
- }.map { _ in (.init(rawValue: fds[0]), .init(rawValue: fds[1])) }
- }
- }
- }
- @available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
- @usableFromInline
- internal static func _pipe(
- options: Int32,
- ) -> Result<(readEnd: FileDescriptor, writeEnd: FileDescriptor), Errno> {
- var fds: (Int32, Int32) = (-1, -1)
- return withUnsafeMutablePointer(to: &fds) { pointer in
- pointer.withMemoryRebound(to: Int32.self, capacity: 2) { fds in
- valueOrErrno(retryOnInterrupt: false) {
- system_pipe2(fds, options)
- }.map { _ in (.init(rawValue: fds[0]), .init(rawValue: fds[1])) }
- }
- }
- }
- @_alwaysEmitIntoClient
- @available(*, unavailable, renamed: "pipe")
- public static func pipe2() throws -> FileDescriptor {
- fatalError("Not implemented")
- }
- }
- #endif // !os(WASI)
- @available(System 1.2.0, *)
- extension FileDescriptor {
- /// Truncates or extends the file referenced by this file descriptor.
- ///
- /// - Parameters:
- /// - newSize: The length in bytes to resize the file to.
- /// - retryOnInterrupt: Whether to retry the write operation
- /// if it throws ``Errno/interrupted``. The default is `true`.
- /// Pass `false` to try only once and throw an error upon interruption.
- ///
- /// The file referenced by this file descriptor will by truncated (or extended) to `newSize`.
- ///
- /// If the current size of the file exceeds `newSize`, any extra data is discarded. If the current
- /// size of the file is smaller than `newSize`, the file is extended and filled with zeros to the
- /// provided size.
- ///
- /// This function requires that the file has been opened for writing.
- ///
- /// - Note: This function does not modify the current offset for any open file descriptors
- /// associated with the file.
- ///
- /// The corresponding C function is `ftruncate`.
- @available(System 1.2.0, *)
- @_alwaysEmitIntoClient
- public func resize(
- to newSize: Int64,
- retryOnInterrupt: Bool = true
- ) throws {
- try _resize(
- to: newSize,
- retryOnInterrupt: retryOnInterrupt
- ).get()
- }
- @available(System 1.2.0, *)
- @usableFromInline
- internal func _resize(
- to newSize: Int64,
- retryOnInterrupt: Bool
- ) -> Result<(), Errno> {
- nothingOrErrno(retryOnInterrupt: retryOnInterrupt) {
- system_ftruncate(self.rawValue, _COffT(newSize))
- }
- }
- }
- #if !os(WASI) // WASI has no umask
- extension FilePermissions {
- /// The file creation permission mask (aka "umask").
- ///
- /// Permissions set in this mask will be cleared by functions that create
- /// files or directories. Note that this mask is process-wide, and that
- /// *getting* it is not thread safe.
- internal static var creationMask: FilePermissions {
- get {
- let oldMask = _umask(0o22)
- _ = _umask(oldMask)
- return FilePermissions(rawValue: oldMask)
- }
- set {
- _ = _umask(newValue.rawValue)
- }
- }
- /// Change the file creation permission mask, run some code, then
- /// restore it to its original value.
- ///
- /// - Parameters:
- /// - permissions: The new permission mask.
- ///
- /// This is more efficient than reading `creationMask` and restoring it
- /// afterwards, because of the way reading the creation mask works.
- internal static func withCreationMask<R>(
- _ permissions: FilePermissions,
- body: () throws -> R
- ) rethrows -> R {
- let oldMask = _umask(permissions.rawValue)
- defer {
- _ = _umask(oldMask)
- }
- return try body()
- }
- internal static func _umask(_ mode: CModeT) -> CModeT {
- return system_umask(mode)
- }
- }
- #endif // !os(WASI)
|