@@ -309,4 +309,66 @@ extension FileDescriptor {
309
309
buffer,
310
310
retryOnInterrupt: retryOnInterrupt)
311
311
}
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
+ }
312
374
}
0 commit comments