@@ -309,4 +309,66 @@ extension FileDescriptor {
309309 buffer,
310310 retryOnInterrupt: retryOnInterrupt)
311311 }
312+
313+ /// Duplicate this file descriptor and return the newly created copy.
314+ ///
315+ /// - Parameters:
316+ /// - `target`: The desired target file descriptor, or `nil`, in which case
317+ /// the copy is assigned to the file descriptor with the lowest raw value
318+ /// that is not currently in use by the process.
319+ /// - retryOnInterrupt: Whether to retry the write operation
320+ /// if it throws ``Errno/interrupted``. The default is `true`.
321+ /// Pass `false` to try only once and throw an error upon interruption.
322+ /// - Returns: The new file descriptor.
323+ ///
324+ /// If the `target` descriptor is already in use, then it is first
325+ /// deallocated as if a close(2) call had been done first.
326+ ///
327+ /// File descriptors are merely references to some underlying system resource.
328+ /// The system does not distinguish between the original and the new file
329+ /// descriptor in any way. For example, read, write and seek operations on
330+ /// one of them also affect the logical file position in the other, and
331+ /// append mode, non-blocking I/O and asynchronous I/O options are shared
332+ /// between the references. If a separate pointer into the file is desired,
333+ /// a different object reference to the file must be obtained by issuing an
334+ /// additional call to `open`.
335+ ///
336+ /// However, each file descriptor maintains its own close-on-exec flag.
337+ ///
338+ ///
339+ /// The corresponding C functions are `dup` and `dup2`.
340+ @_alwaysEmitIntoClient
341+ // @available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
342+ public func duplicate(
343+ as target: FileDescriptor ? = nil ,
344+ retryOnInterrupt: Bool = true
345+ ) throws -> FileDescriptor {
346+ try _duplicate ( as: target, retryOnInterrupt: retryOnInterrupt) . get ( )
347+ }
348+
349+ // @available(macOS 9999, iOS 9999, watchOS 9999, tvOS 9999, *)
350+ @usableFromInline
351+ internal func _duplicate(
352+ as target: FileDescriptor ? ,
353+ retryOnInterrupt: Bool
354+ ) throws -> Result < FileDescriptor , Errno > {
355+ valueOrErrno ( retryOnInterrupt: retryOnInterrupt) {
356+ if let target = target {
357+ return system_dup2 ( self . rawValue, target. rawValue)
358+ }
359+ return system_dup ( self . rawValue)
360+ } . map ( FileDescriptor . init ( rawValue: ) )
361+ }
362+
363+ @_alwaysEmitIntoClient
364+ @available ( * , unavailable, renamed: " duplicate " )
365+ public func dup( ) throws -> FileDescriptor {
366+ fatalError ( " Not implemented " )
367+ }
368+
369+ @_alwaysEmitIntoClient
370+ @available ( * , unavailable, renamed: " duplicate " )
371+ public func dup2( ) throws -> FileDescriptor {
372+ fatalError ( " Not implemented " )
373+ }
312374}
0 commit comments