mirror of
https://github.com/apple/swift-nio.git
synced 2026-05-20 20:30:36 +00:00
6b33489e64
This re-enables documentation lost during refactoring work, under the target _NIOFileSystem resolves #3474 ### Motivation: During the refactoring of NIOFileSystem and recent Swift updates, the mechanism to "shadow" symbols using `@_exported import` has stopped working for documentation and imports for symbols, which means that _NIOFileSystem is the target that needs to host the documentation for this (for now) ### Modifications: Moves DocC catalog into _NIOFileSystem target, and updates disambiguation hashes on overloaded symbols in order to verify no warnings are presented while generating documentation. Updates .spi.yml to present _NIOFileSystem instead of NIOFileSystem ### Result: Previous documentation should be available again, although at a slightly different URI structure within Swift Package Index. Co-authored-by: Cory Benfield <lukasa@apple.com>
299 lines
11 KiB
Swift
299 lines
11 KiB
Swift
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This source file is part of the SwiftNIO open source project
|
|
//
|
|
// Copyright (c) 2025 Apple Inc. and the SwiftNIO project authors
|
|
// Licensed under Apache License v2.0
|
|
//
|
|
// See LICENSE.txt for license information
|
|
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import SystemPackage
|
|
|
|
/// Options for opening file handles.
|
|
public enum OpenOptions: Sendable {
|
|
/// Options for opening a file for reading.
|
|
public struct Read: Hashable, Sendable {
|
|
/// If the last path component is a symbolic link then this flag determines whether the
|
|
/// link is followed. If `false` and the last path component is a symbolic link then an
|
|
/// error is thrown.
|
|
public var followSymbolicLinks: Bool
|
|
|
|
/// Marks the descriptor of the opened file as 'close-on-exec'.
|
|
public var closeOnExec: Bool
|
|
|
|
/// Creates a new set of options for opening a file for reading.
|
|
///
|
|
/// - Parameters:
|
|
/// - followSymbolicLinks: Whether symbolic links should be followed, defaults to `true`.
|
|
/// - closeOnExec: Whether the descriptor should be marked as closed-on-exec, defaults
|
|
/// to `false`.
|
|
public init(
|
|
followSymbolicLinks: Bool = true,
|
|
closeOnExec: Bool = false
|
|
) {
|
|
self.followSymbolicLinks = followSymbolicLinks
|
|
self.closeOnExec = closeOnExec
|
|
}
|
|
}
|
|
|
|
/// Options for opening a directory.
|
|
public struct Directory: Hashable, Sendable {
|
|
/// If the last path component is a symbolic link then this flag determines whether the
|
|
/// link is followed. If `false` and the last path component is a symbolic link then an
|
|
/// error is thrown.
|
|
public var followSymbolicLinks: Bool
|
|
|
|
/// Marks the descriptor of the opened file as 'close-on-exec'.
|
|
public var closeOnExec: Bool
|
|
|
|
/// Creates a new set of options for opening a directory.
|
|
///
|
|
/// - Parameters:
|
|
/// - followSymbolicLinks: Whether symbolic links should be followed, defaults to `true`.
|
|
/// - closeOnExec: Whether the descriptor should be marked as closed-on-exec, defaults
|
|
/// to `false`.
|
|
public init(
|
|
followSymbolicLinks: Bool = true,
|
|
closeOnExec: Bool = false
|
|
) {
|
|
self.followSymbolicLinks = followSymbolicLinks
|
|
self.closeOnExec = closeOnExec
|
|
}
|
|
}
|
|
|
|
/// Options for opening a file for writing (or reading and writing).
|
|
///
|
|
/// You can use the following methods to create commonly used sets of options:
|
|
/// - ``newFile(replaceExisting:permissions:)`` to create a new file, optionally replacing
|
|
/// one which already exists.
|
|
/// - ``modifyFile(createIfNecessary:permissions:)`` to modify an existing file, optionally
|
|
/// creating it if it doesn't exist.
|
|
public struct Write: Hashable, Sendable {
|
|
/// The behavior for opening an existing file.
|
|
public var existingFile: OpenOptions.ExistingFile
|
|
|
|
/// The creation options for a new file, if one should be created. `nil` means that no
|
|
/// file should be created.
|
|
public var newFile: OpenOptions.NewFile?
|
|
|
|
/// If the last path component is a symbolic link then this flag determines whether the
|
|
/// link is followed. If `false` and the last path component is a symbolic link then an
|
|
/// error is thrown.
|
|
public var followSymbolicLinks: Bool
|
|
|
|
/// Marks the descriptor of the opened file as 'close-on-exec'.
|
|
public var closeOnExec: Bool
|
|
|
|
/// Creates a new set of options for opening a directory.
|
|
///
|
|
/// - Parameters:
|
|
/// - existingFile: Options for handling an existing file.
|
|
/// - newFile: Options for creating a new file.
|
|
/// - followSymbolicLinks: Whether symbolic links should be followed, defaults to `true`.
|
|
/// - closeOnExec: Whether the descriptor should be marked as closed-on-exec, defaults
|
|
/// to `false`.
|
|
public init(
|
|
existingFile: OpenOptions.ExistingFile,
|
|
newFile: OpenOptions.NewFile?,
|
|
followSymbolicLinks: Bool = true,
|
|
closeOnExec: Bool = false
|
|
) {
|
|
self.existingFile = existingFile
|
|
self.newFile = newFile
|
|
self.followSymbolicLinks = followSymbolicLinks
|
|
self.closeOnExec = closeOnExec
|
|
}
|
|
|
|
/// Create a new file for writing to.
|
|
///
|
|
/// - Parameters:
|
|
/// - replaceExisting: Whether any existing file of the same name is replaced. If
|
|
/// this is `true` then any existing file of the same name will be replaced with the
|
|
/// new file. If this is `false` and a file already exists an error is thrown.
|
|
/// - permissions: The permissions to apply to the newly created file. Default permissions
|
|
/// (read-write owner permissions and read permissions for everyone else) are applied
|
|
/// if `nil`.
|
|
/// - Returns: Options for creating a new file for writing.
|
|
public static func newFile(
|
|
replaceExisting: Bool,
|
|
permissions: FilePermissions? = nil
|
|
) -> Self {
|
|
Write(
|
|
existingFile: replaceExisting ? .truncate : .none,
|
|
newFile: NewFile(permissions: permissions)
|
|
)
|
|
}
|
|
|
|
/// Opens a file for modifying.
|
|
///
|
|
/// - Parameters:
|
|
/// - createIfNecessary: Whether a file should be created if one doesn't exist. If
|
|
/// `false` and a file doesn't exist then an error is thrown.
|
|
/// - permissions: The permissions to apply to the newly created file. Default permissions
|
|
/// (read-write owner permissions and read permissions for everyone else) are applied
|
|
/// if `nil`. Ignored if `createIfNonExistent` is `false`.
|
|
/// - Returns: Options for modifying an existing file for writing.
|
|
public static func modifyFile(
|
|
createIfNecessary: Bool,
|
|
permissions: FilePermissions? = nil
|
|
) -> Self {
|
|
Write(
|
|
existingFile: .open,
|
|
newFile: createIfNecessary ? NewFile(permissions: permissions) : nil
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
extension OpenOptions {
|
|
/// Options for opening an existing file.
|
|
public enum ExistingFile: Sendable, Hashable {
|
|
/// Indicates that no file exists. If a file does exist then an error is thrown when
|
|
/// opening the file.
|
|
case none
|
|
|
|
/// Any existing file should be opened without modification.
|
|
case open
|
|
|
|
/// Truncate the existing file.
|
|
///
|
|
/// Setting this is equivalent to opening a file with `O_TRUNC`.
|
|
case truncate
|
|
}
|
|
|
|
/// Options for creating a new file.
|
|
public struct NewFile: Sendable, Hashable {
|
|
/// The permissions to apply to the new file. `nil` implies default permissions
|
|
/// should be applied.
|
|
public var permissions: FilePermissions?
|
|
|
|
/// Whether the file should be created and updated as a single transaction, if
|
|
/// applicable.
|
|
///
|
|
/// When this option is set and applied the newly created file will only materialize
|
|
/// on the file system when the file is closed.
|
|
/// When used in conjunction with
|
|
/// ``FileSystemProtocol/withFileHandle(forWritingAt:options:execute:)`` and
|
|
/// ``FileSystemProtocol/withFileHandle(forReadingAndWritingAt:options:execute:)`` the
|
|
/// file will only materialize when the file is closed and no errors have been thrown.
|
|
///
|
|
/// - Important: This flag is only applied if ``OpenOptions/Write/existingFile`` is
|
|
/// ``OpenOptions/ExistingFile/none``.
|
|
public var transactionalCreation: Bool
|
|
|
|
public init(
|
|
permissions: FilePermissions? = nil,
|
|
transactionalCreation: Bool = true
|
|
) {
|
|
self.permissions = permissions
|
|
self.transactionalCreation = transactionalCreation
|
|
}
|
|
}
|
|
}
|
|
|
|
extension OpenOptions.Write {
|
|
@_spi(Testing)
|
|
public var permissionsForRegularFile: FilePermissions? {
|
|
if let newFile = self.newFile {
|
|
return newFile.permissions ?? .defaultsForRegularFile
|
|
} else {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
var descriptorOptions: FileDescriptor.OpenOptions {
|
|
var options = FileDescriptor.OpenOptions()
|
|
|
|
if !self.followSymbolicLinks {
|
|
options.insert(.noFollow)
|
|
}
|
|
|
|
if self.closeOnExec {
|
|
options.insert(.closeOnExec)
|
|
}
|
|
|
|
if self.newFile != nil {
|
|
options.insert(.create)
|
|
}
|
|
|
|
switch self.existingFile {
|
|
case .none:
|
|
options.insert(.exclusiveCreate)
|
|
case .open:
|
|
()
|
|
case .truncate:
|
|
options.insert(.truncate)
|
|
}
|
|
|
|
return options
|
|
}
|
|
}
|
|
|
|
extension OpenOptions.Read {
|
|
var descriptorOptions: FileDescriptor.OpenOptions {
|
|
var options = FileDescriptor.OpenOptions()
|
|
|
|
if !self.followSymbolicLinks {
|
|
options.insert(.noFollow)
|
|
}
|
|
|
|
if self.closeOnExec {
|
|
options.insert(.closeOnExec)
|
|
}
|
|
|
|
return options
|
|
}
|
|
}
|
|
|
|
extension OpenOptions.Directory {
|
|
var descriptorOptions: FileDescriptor.OpenOptions {
|
|
var options = FileDescriptor.OpenOptions([.directory])
|
|
|
|
if !self.followSymbolicLinks {
|
|
options.insert(.noFollow)
|
|
}
|
|
|
|
if self.closeOnExec {
|
|
options.insert(.closeOnExec)
|
|
}
|
|
|
|
return options
|
|
}
|
|
}
|
|
|
|
extension FileDescriptor.OpenOptions {
|
|
public init(_ options: OpenOptions.Read) {
|
|
self = options.descriptorOptions
|
|
}
|
|
|
|
public init(_ options: OpenOptions.Write) {
|
|
self = options.descriptorOptions
|
|
}
|
|
|
|
public init(_ options: OpenOptions.Directory) {
|
|
self = options.descriptorOptions
|
|
}
|
|
}
|
|
|
|
extension FilePermissions {
|
|
/// Default permissions for regular files; owner read-write, group read, other read.
|
|
internal static let defaultsForRegularFile: FilePermissions = [
|
|
.ownerReadWrite,
|
|
.groupRead,
|
|
.otherRead,
|
|
]
|
|
|
|
/// Default permissions for directories; owner read-write-execute, group read-execute, other
|
|
/// read-execute.
|
|
internal static let defaultsForDirectory: FilePermissions = [
|
|
.ownerReadWriteExecute,
|
|
.groupReadExecute,
|
|
.otherReadExecute,
|
|
]
|
|
}
|