Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 2 additions & 11 deletions Sources/System/FileDescriptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -328,11 +328,7 @@ extension FileDescriptor {

/// Options that specify behavior for a newly-created pipe.
@frozen
@available(macOS, unavailable)
@available(iOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
@available(visionOS, unavailable)
@available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
public struct PipeOptions: OptionSet, Sendable, Hashable, Codable {
/// The raw C options.
@_alwaysEmitIntoClient
Expand Down Expand Up @@ -403,11 +399,7 @@ extension FileDescriptor {
/// Options that specify behavior for a duplicated file descriptor.
@frozen
@available(Windows, unavailable)
@available(macOS, unavailable)
@available(iOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
@available(visionOS, unavailable)
@available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
public struct DuplicateOptions: OptionSet, Sendable, Hashable, Codable {
/// The raw C options.
@_alwaysEmitIntoClient
Expand Down Expand Up @@ -532,7 +524,6 @@ extension FileDescriptor {
@available(*, unavailable, renamed: "nextData")
public static var SEEK_DATA: SeekOrigin { nextData }
#endif

}
}

Expand Down
43 changes: 15 additions & 28 deletions Sources/System/FileOperations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -370,13 +370,13 @@ extension FileDescriptor {
#if !os(WASI)
@available(System 0.0.2, *)
extension FileDescriptor {
/// Duplicates this file descriptor and return the newly created copy.
/// 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 write operation
/// - 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.
Expand Down Expand Up @@ -436,20 +436,19 @@ extension FileDescriptor {
/// close-on-fork flags.
///
/// The corresponding C function is `dup3`.
@discardableResult
@_alwaysEmitIntoClient
@available(Windows, unavailable)
@available(macOS, unavailable)
@available(iOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
@available(visionOS, 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 {
try _duplicate(as: target, options: options.rawValue, retryOnInterrupt: retryOnInterrupt).get()
let result = _duplicate(
as: target, options: options.rawValue, retryOnInterrupt: retryOnInterrupt
)
return try result.get()
}

@available(System 0.0.2, *)
Expand All @@ -468,11 +467,7 @@ extension FileDescriptor {
}

@available(Windows, unavailable)
@available(macOS, unavailable)
@available(iOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
@available(visionOS, unavailable)
@available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
@usableFromInline
internal func _duplicate(
as target: FileDescriptor,
Expand Down Expand Up @@ -502,7 +497,7 @@ extension FileDescriptor {
fatalError("Not implemented")
}
}
#endif
#endif // !os(WASI)

#if !os(WASI)
@available(System 1.1.0, *)
Expand Down Expand Up @@ -535,11 +530,7 @@ extension FileDescriptor {
///
/// The corresponding C function is `pipe2`.
@_alwaysEmitIntoClient
@available(macOS, unavailable)
@available(iOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
@available(visionOS, unavailable)
@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) {
Expand All @@ -560,11 +551,7 @@ extension FileDescriptor {
}
}

@available(macOS, unavailable)
@available(iOS, unavailable)
@available(tvOS, unavailable)
@available(watchOS, unavailable)
@available(visionOS, unavailable)
@available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
@usableFromInline
internal static func _pipe(
options: Int32,
Expand All @@ -585,7 +572,7 @@ extension FileDescriptor {
fatalError("Not implemented")
}
}
#endif
#endif // !os(WASI)

@available(System 1.2.0, *)
extension FileDescriptor {
Expand Down Expand Up @@ -674,4 +661,4 @@ extension FilePermissions {
return system_umask(mode)
}
}
#endif
#endif // !os(WASI)
2 changes: 1 addition & 1 deletion Sources/System/Internals/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -631,7 +631,7 @@ internal var _O_CLOEXEC: CInt {
#if !os(Windows)
@_alwaysEmitIntoClient
internal var _O_CLOFORK: CInt {
#if !os(WASI) && !os(Linux) && !os(Android) && !canImport(Darwin) && !os(FreeBSD)
#if !os(WASI) && !os(Linux) && !os(Android) && !os(FreeBSD)
O_CLOFORK
#elseif os(FreeBSD)
FREEBSD_O_CLOFORK
Expand Down
26 changes: 19 additions & 7 deletions Sources/System/Internals/Syscalls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ import Android
#error("Unsupported Platform")
#endif

#if !SYSTEM_PACKAGE_DARWIN
import CSystem
#endif

// Interacting with the mocking system, tracing, etc., is a potentially significant
// amount of code size, so we hand outline that code for every syscall
Expand Down Expand Up @@ -141,13 +143,18 @@ internal func system_dup2(_ fd: Int32, _ fd2: Int32) -> Int32 {
return dup2(fd, fd2)
}

@available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
internal func system_dup3(_ fd: Int32, _ fd2: Int32, _ oflag: Int32) -> Int32 {
#if ENABLE_MOCKING
#if ENABLE_MOCKING
if mockingEnabled { return _mock(fd, fd2, oflag) }
#endif
#endif
#if SYSTEM_PACKAGE_DARWIN
return dup3(fd, fd2, oflag)
#else
return csystem_posix_dup3(fd, fd2, oflag)
}
#endif
}
#endif // !os(WASI)

#if !os(WASI)
internal func system_pipe(_ fds: UnsafeMutablePointer<Int32>) -> CInt {
Expand All @@ -157,13 +164,18 @@ internal func system_pipe(_ fds: UnsafeMutablePointer<Int32>) -> CInt {
return pipe(fds)
}

@available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
internal func system_pipe2(_ fds: UnsafeMutablePointer<Int32>, _ oflag: Int32) -> CInt {
#if ENABLE_MOCKING
if mockingEnabled { return _mock(fds, oflag) }
#endif
#if SYSTEM_PACKAGE_DARWIN
return pipe2(fds, oflag)
#else
return csystem_posix_pipe2(fds, oflag)
}
#endif
}
#endif // !os(WASI)

internal func system_ftruncate(_ fd: Int32, _ length: off_t) -> Int32 {
#if ENABLE_MOCKING
Expand Down Expand Up @@ -201,7 +213,7 @@ internal func system_confstr(
) -> Int {
return confstr(name, buf, len)
}
#endif
#endif // SYSTEM_PACKAGE_DARWIN

#if !os(Windows)
internal let SYSTEM_AT_REMOVE_DIR = AT_REMOVEDIR
Expand Down Expand Up @@ -269,15 +281,15 @@ internal func system_openat(
#endif
return openat(fd, path, oflag)
}
#endif
#endif // !os(Windows)

#if !os(WASI) // WASI has no umask
internal func system_umask(
_ mode: CInterop.Mode
) -> CInterop.Mode {
return umask(mode)
}
#endif
#endif // !os(WASI)

internal func system_getenv(
_ name: UnsafePointer<CChar>
Expand Down
18 changes: 9 additions & 9 deletions Tests/SystemTests/FileOperationsTest.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
This source file is part of the Swift System open source project

Copyright (c) 2020 - 2025 Apple Inc. and the Swift System project authors
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
Expand Down Expand Up @@ -157,7 +157,8 @@ final class FileOperationsTest: XCTestCase {
// TODO: Test writeAll, writeAll(toAbsoluteOffset), closeAfter
}

#if !os(WASI) // WASI has no pipe
#if !os(WASI) // WASI has no pipe
@available(System 1.1.0, *)
func testAdHocPipe() throws {
// Ad-hoc test testing `Pipe` functionality.
// We cannot test `Pipe` using `MockTestCase` because it calls `pipe` with a pointer to an array local to the `Pipe`, the address of which we do not know prior to invoking `Pipe`.
Expand All @@ -177,7 +178,7 @@ final class FileOperationsTest: XCTestCase {
}
}

#if !SYSTEM_PACKAGE_DARWIN
@available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
func testAdHocPipeWithOptions() throws {
// Ad-hoc test testing `Pipe` functionality.
// We cannot test `Pipe` using `MockTestCase` because it calls `pipe` with a pointer to an array local to the `Pipe`, the address of which we do not know prior to invoking `Pipe`.
Expand All @@ -198,10 +199,9 @@ final class FileOperationsTest: XCTestCase {
}
}
}
#endif // !SYSTEM_PACKAGE_DARWIN
#endif // !os(WASI)
#endif // !os(WASI)

#if !os(Windows)
#if !os(Windows)
func testAdHocDuplicate2() throws {
try withTemporaryFilePath(basename: "test") {
let path = $0.appending("foo2.txt")
Expand Down Expand Up @@ -238,9 +238,8 @@ final class FileOperationsTest: XCTestCase {
}
}
}
#endif // !os(Windows)

#if !SYSTEM_PACKAGE_DARWIN && !os(Windows)
@available(macOS 27.0, iOS 27.0, watchOS 27.0, tvOS 27.0, visionOS 27.0, *)
func testAdHocDuplicate3() throws {

try withTemporaryFilePath(basename: "test") {
Expand Down Expand Up @@ -274,7 +273,7 @@ final class FileOperationsTest: XCTestCase {
}
}
}
#endif // !SYSTEM_PACKAGE_DARWIN && !os(Windows)
#endif // !os(Windows)

func testAdHocOpen() {
// Ad-hoc test touching a file system.
Expand Down Expand Up @@ -334,6 +333,7 @@ final class FileOperationsTest: XCTestCase {
}
#endif // ENABLE_MOCKING

@available(System 1.2.0, *)
func testResizeFile() throws {
try withTemporaryFilePath(basename: "testResizeFile") { path in
let fd = try FileDescriptor.open(path.appending("\(UUID().uuidString).txt"), .readWrite, options: [.create, .truncate], permissions: .ownerReadWrite)
Expand Down
Loading