@@ -14,7 +14,7 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyRef<PyModule> {
1414pub ( crate ) mod module {
1515 use crate :: {
1616 PyResult , TryFromObject , VirtualMachine ,
17- builtins:: { PyDictRef , PyListRef , PyStrRef , PyTupleRef } ,
17+ builtins:: { PyBaseExceptionRef , PyDictRef , PyListRef , PyStrRef , PyTupleRef } ,
1818 common:: { crt_fd, os:: last_os_error, suppress_iph} ,
1919 convert:: ToPyException ,
2020 function:: { Either , OptionalArg } ,
@@ -391,6 +391,13 @@ pub(crate) mod module {
391391 }
392392 }
393393
394+ #[ pyfunction]
395+ fn get_inheritable ( fd : i32 , vm : & VirtualMachine ) -> PyResult < bool > {
396+ let borrowed = unsafe { crt_fd:: Borrowed :: borrow_raw ( fd) } ;
397+ let handle = crt_fd:: as_handle ( borrowed) . map_err ( |e| e. to_pyexception ( vm) ) ?;
398+ get_handle_inheritable ( handle. as_raw_handle ( ) as _ , vm)
399+ }
400+
394401 #[ pyfunction]
395402 fn getlogin ( vm : & VirtualMachine ) -> PyResult < String > {
396403 let mut buffer = [ 0u16 ; 257 ] ;
@@ -477,6 +484,15 @@ pub(crate) mod module {
477484
478485 unsafe extern "C" {
479486 fn _umask ( mask : i32 ) -> i32 ;
487+ fn _dup ( fd : i32 ) -> i32 ;
488+ fn _dup2 ( fd : i32 , fd2 : i32 ) -> i32 ;
489+ }
490+
491+ /// Close fd and convert error to PyException (PEP 446 cleanup)
492+ #[ cold]
493+ fn close_fd_and_raise ( fd : i32 , err : std:: io:: Error , vm : & VirtualMachine ) -> PyBaseExceptionRef {
494+ let _ = unsafe { crt_fd:: Owned :: from_raw ( fd) } ;
495+ err. to_pyexception ( vm)
480496 }
481497
482498 #[ pyfunction]
@@ -489,6 +505,45 @@ pub(crate) mod module {
489505 }
490506 }
491507
508+ #[ pyfunction]
509+ fn dup ( fd : i32 , vm : & VirtualMachine ) -> PyResult < i32 > {
510+ let fd2 = unsafe { suppress_iph ! ( _dup( fd) ) } ;
511+ if fd2 < 0 {
512+ return Err ( errno_err ( vm) ) ;
513+ }
514+ let borrowed = unsafe { crt_fd:: Borrowed :: borrow_raw ( fd2) } ;
515+ let handle = crt_fd:: as_handle ( borrowed) . map_err ( |e| close_fd_and_raise ( fd2, e, vm) ) ?;
516+ raw_set_handle_inheritable ( handle. as_raw_handle ( ) as _ , false )
517+ . map_err ( |e| close_fd_and_raise ( fd2, e, vm) ) ?;
518+ Ok ( fd2)
519+ }
520+
521+ #[ derive( FromArgs ) ]
522+ struct Dup2Args {
523+ #[ pyarg( positional) ]
524+ fd : i32 ,
525+ #[ pyarg( positional) ]
526+ fd2 : i32 ,
527+ #[ pyarg( any, default = true ) ]
528+ inheritable : bool ,
529+ }
530+
531+ #[ pyfunction]
532+ fn dup2 ( args : Dup2Args , vm : & VirtualMachine ) -> PyResult < i32 > {
533+ let result = unsafe { suppress_iph ! ( _dup2( args. fd, args. fd2) ) } ;
534+ if result < 0 {
535+ return Err ( errno_err ( vm) ) ;
536+ }
537+ if !args. inheritable {
538+ let borrowed = unsafe { crt_fd:: Borrowed :: borrow_raw ( args. fd2 ) } ;
539+ let handle =
540+ crt_fd:: as_handle ( borrowed) . map_err ( |e| close_fd_and_raise ( args. fd2 , e, vm) ) ?;
541+ raw_set_handle_inheritable ( handle. as_raw_handle ( ) as _ , false )
542+ . map_err ( |e| close_fd_and_raise ( args. fd2 , e, vm) ) ?;
543+ }
544+ Ok ( args. fd2 )
545+ }
546+
492547 pub ( crate ) fn support_funcs ( ) -> Vec < SupportFunc > {
493548 Vec :: new ( )
494549 }
0 commit comments