@@ -403,17 +403,61 @@ 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: 0 , 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 ( Windows, unavailable)
437
+ @available ( macOS, unavailable)
438
+ @available ( iOS, unavailable)
439
+ @available ( tvOS, unavailable)
440
+ @available ( watchOS, unavailable)
441
+ @available ( visionOS, unavailable)
442
+ public func duplicate(
443
+ as target: FileDescriptor ,
444
+ options: DuplicateOptions ,
445
+ retryOnInterrupt: Bool = true
446
+ ) throws -> FileDescriptor {
447
+ try _duplicate ( as: target, options: options. rawValue, retryOnInterrupt: retryOnInterrupt) . get ( )
407
448
}
408
449
409
- @available ( System 0 . 0 . 2 , * )
410
450
@usableFromInline
411
451
internal func _duplicate(
412
452
as target: FileDescriptor ? ,
453
+ options: Int32 ,
413
454
retryOnInterrupt: Bool
414
455
) throws -> Result < FileDescriptor , Errno > {
415
456
valueOrErrno ( retryOnInterrupt: retryOnInterrupt) {
416
457
if let target = target {
458
+ if options != 0 {
459
+ return system_dup3 ( self . rawValue, target. rawValue, options)
460
+ }
417
461
return system_dup2 ( self . rawValue, target. rawValue)
418
462
}
419
463
return system_dup ( self . rawValue)
@@ -431,6 +475,12 @@ extension FileDescriptor {
431
475
public func dup2( ) throws -> FileDescriptor {
432
476
fatalError ( " Not implemented " )
433
477
}
478
+
479
+ @_alwaysEmitIntoClient
480
+ @available ( * , unavailable, renamed: " duplicate " )
481
+ public func dup3( ) throws -> FileDescriptor {
482
+ fatalError ( " Not implemented " )
483
+ }
434
484
}
435
485
#endif
436
486
@@ -445,21 +495,48 @@ extension FileDescriptor {
445
495
@_alwaysEmitIntoClient
446
496
@available ( System 1 . 1 . 0 , * )
447
497
public static func pipe( ) throws -> ( readEnd: FileDescriptor , writeEnd: FileDescriptor ) {
448
- try _pipe ( ) . get ( )
498
+ try _pipe ( options: 0 ) . get ( )
499
+ }
500
+
501
+ /// Creates a unidirectional data channel, which can be used for interprocess communication.
502
+ ///
503
+ /// - Parameters:
504
+ /// - options: The behavior for creating the pipe.
505
+ ///
506
+ /// - Returns: The pair of file descriptors.
507
+ ///
508
+ /// The corresponding C function is `pipe2`.
509
+ @_alwaysEmitIntoClient
510
+ @available ( Windows, unavailable)
511
+ @available ( macOS, unavailable)
512
+ @available ( iOS, unavailable)
513
+ @available ( tvOS, unavailable)
514
+ @available ( watchOS, unavailable)
515
+ @available ( visionOS, unavailable)
516
+ public static func pipe( options: PipeOptions ) throws -> ( readEnd: FileDescriptor , writeEnd: FileDescriptor ) {
517
+ try _pipe ( options: options. rawValue) . get ( )
449
518
}
450
519
451
- @available ( System 1 . 1 . 0 , * )
452
520
@usableFromInline
453
- internal static func _pipe( ) -> Result < ( readEnd: FileDescriptor , writeEnd: FileDescriptor ) , Errno > {
521
+ internal static func _pipe( options : Int32 ) -> Result < ( readEnd: FileDescriptor , writeEnd: FileDescriptor ) , Errno > {
454
522
var fds : ( Int32 , Int32 ) = ( - 1 , - 1 )
455
523
return withUnsafeMutablePointer ( to: & fds) { pointer in
456
524
pointer. withMemoryRebound ( to: Int32 . self, capacity: 2 ) { fds in
457
525
valueOrErrno ( retryOnInterrupt: false ) {
458
- system_pipe ( fds)
526
+ if options != 0 {
527
+ return system_pipe2 ( fds, options)
528
+ }
529
+ return system_pipe ( fds)
459
530
} . map { _ in ( . init( rawValue: fds [ 0 ] ) , . init( rawValue: fds [ 1 ] ) ) }
460
531
}
461
532
}
462
533
}
534
+
535
+ @_alwaysEmitIntoClient
536
+ @available ( * , unavailable, renamed: " pipe " )
537
+ public func pipe2( ) throws -> FileDescriptor {
538
+ fatalError ( " Not implemented " )
539
+ }
463
540
}
464
541
#endif
465
542
0 commit comments