@@ -403,17 +403,59 @@ extension FileDescriptor {
403
403
as target: FileDescriptor ? = nil ,
404
404
retryOnInterrupt: Bool = true
405
405
) throws -> FileDescriptor {
406
- try _duplicate ( as: target, retryOnInterrupt: retryOnInterrupt) . get ( )
406
+ try _duplicate ( as: target, options: [ ] , retryOnInterrupt: retryOnInterrupt) . get ( )
407
+ }
408
+
409
+ /// Duplicates this file descriptor and return the newly created copy.
410
+ ///
411
+ /// - Parameters:
412
+ /// - `target`: The desired target file descriptor.
413
+ /// - `options`: The behavior for creating the target file descriptor.
414
+ /// - retryOnInterrupt: Whether to retry the write operation
415
+ /// if it throws ``Errno/interrupted``. The default is `true`.
416
+ /// Pass `false` to try only once and throw an error upon interruption.
417
+ /// - Returns: The new file descriptor.
418
+ ///
419
+ /// If the `target` descriptor is already in use, then it is first
420
+ /// deallocated as if a close(2) call had been done first.
421
+ ///
422
+ /// File descriptors are merely references to some underlying system resource.
423
+ /// The system does not distinguish between the original and the new file
424
+ /// descriptor in any way. For example, read, write and seek operations on
425
+ /// one of them also affect the logical file position in the other, and
426
+ /// append mode, non-blocking I/O and asynchronous I/O options are shared
427
+ /// between the references. If a separate pointer into the file is desired,
428
+ /// a different object reference to the file must be obtained by issuing an
429
+ /// additional call to `open`.
430
+ ///
431
+ /// However, each file descriptor maintains its own close-on-exec flag.
432
+ ///
433
+ ///
434
+ /// The corresponding C function is `dup3`.
435
+ @_alwaysEmitIntoClient
436
+ @available ( System 0 . 0 . 2 , * )
437
+ public func duplicate(
438
+ as target: FileDescriptor ,
439
+ options: DuplicateOptions ,
440
+ retryOnInterrupt: Bool = true
441
+ ) throws -> FileDescriptor {
442
+ try _duplicate ( as: target, options: options, retryOnInterrupt: retryOnInterrupt) . get ( )
407
443
}
408
444
409
445
@available ( System 0 . 0 . 2 , * )
410
446
@usableFromInline
411
447
internal func _duplicate(
412
448
as target: FileDescriptor ? ,
449
+ options: DuplicateOptions ,
413
450
retryOnInterrupt: Bool
414
451
) throws -> Result < FileDescriptor , Errno > {
415
452
valueOrErrno ( retryOnInterrupt: retryOnInterrupt) {
416
453
if let target = target {
454
+ #if !os(Windows) && !canImport(Darwin)
455
+ if !options. isEmpty {
456
+ return system_dup3 ( self . rawValue, target. rawValue, options. rawValue)
457
+ }
458
+ #endif
417
459
return system_dup2 ( self . rawValue, target. rawValue)
418
460
}
419
461
return system_dup ( self . rawValue)
@@ -431,6 +473,12 @@ extension FileDescriptor {
431
473
public func dup2( ) throws -> FileDescriptor {
432
474
fatalError ( " Not implemented " )
433
475
}
476
+
477
+ @_alwaysEmitIntoClient
478
+ @available ( * , unavailable, renamed: " duplicate " )
479
+ public func dup3( ) throws -> FileDescriptor {
480
+ fatalError ( " Not implemented " )
481
+ }
434
482
}
435
483
#endif
436
484
@@ -445,21 +493,46 @@ extension FileDescriptor {
445
493
@_alwaysEmitIntoClient
446
494
@available ( System 1 . 1 . 0 , * )
447
495
public static func pipe( ) throws -> ( readEnd: FileDescriptor , writeEnd: FileDescriptor ) {
448
- try _pipe ( ) . get ( )
496
+ try _pipe ( options: [ ] ) . get ( )
497
+ }
498
+
499
+ /// Creates a unidirectional data channel, which can be used for interprocess communication.
500
+ ///
501
+ /// - Parameters:
502
+ /// - options: The behavior for creating the pipe.
503
+ ///
504
+ /// - Returns: The pair of file descriptors.
505
+ ///
506
+ /// The corresponding C function is `pipe2`.
507
+ @_alwaysEmitIntoClient
508
+ @available ( /*System 1.1.0: macOS 12.3, iOS 15.4, watchOS 8.5, tvOS 15.4*/iOS 8 , * )
509
+ public static func pipe( options: PipeOptions ) throws -> ( readEnd: FileDescriptor , writeEnd: FileDescriptor ) {
510
+ try _pipe ( options: options) . get ( )
449
511
}
450
512
451
513
@available ( System 1 . 1 . 0 , * )
452
514
@usableFromInline
453
- internal static func _pipe( ) -> Result < ( readEnd: FileDescriptor , writeEnd: FileDescriptor ) , Errno > {
515
+ internal static func _pipe( options : PipeOptions ) -> Result < ( readEnd: FileDescriptor , writeEnd: FileDescriptor ) , Errno > {
454
516
var fds : ( Int32 , Int32 ) = ( - 1 , - 1 )
455
517
return withUnsafeMutablePointer ( to: & fds) { pointer in
456
518
pointer. withMemoryRebound ( to: Int32 . self, capacity: 2 ) { fds in
457
519
valueOrErrno ( retryOnInterrupt: false ) {
458
- system_pipe ( fds)
520
+ #if !os(Windows) && !canImport(Darwin)
521
+ if !options. isEmpty {
522
+ return system_pipe2 ( fds, options. rawValue)
523
+ }
524
+ #endif
525
+ return system_pipe ( fds)
459
526
} . map { _ in ( . init( rawValue: fds [ 0 ] ) , . init( rawValue: fds [ 1 ] ) ) }
460
527
}
461
528
}
462
529
}
530
+
531
+ @_alwaysEmitIntoClient
532
+ @available ( * , unavailable, renamed: " pipe " )
533
+ public func pipe2( ) throws -> FileDescriptor {
534
+ fatalError ( " Not implemented " )
535
+ }
463
536
}
464
537
#endif
465
538
0 commit comments