@@ -835,6 +835,7 @@ pub(crate) mod module {
835835 fn _umask ( mask : i32 ) -> i32 ;
836836 fn _dup ( fd : i32 ) -> i32 ;
837837 fn _dup2 ( fd : i32 , fd2 : i32 ) -> i32 ;
838+ fn _open_osfhandle ( osfhandle : intptr_t , flags : i32 ) -> i32 ;
838839 }
839840
840841 /// Close fd and convert error to PyException (PEP 446 cleanup)
@@ -854,6 +855,113 @@ pub(crate) mod module {
854855 }
855856 }
856857
858+ #[ pyfunction]
859+ fn pipe ( vm : & VirtualMachine ) -> PyResult < ( i32 , i32 ) > {
860+ use windows_sys:: Win32 :: System :: Pipes :: CreatePipe ;
861+
862+ let ( read_handle, write_handle) = unsafe {
863+ let mut read = MaybeUninit :: < isize > :: uninit ( ) ;
864+ let mut write = MaybeUninit :: < isize > :: uninit ( ) ;
865+ let res = CreatePipe (
866+ read. as_mut_ptr ( ) as * mut _ ,
867+ write. as_mut_ptr ( ) as * mut _ ,
868+ std:: ptr:: null ( ) ,
869+ 0 ,
870+ ) ;
871+ if res == 0 {
872+ return Err ( errno_err ( vm) ) ;
873+ }
874+ ( read. assume_init ( ) , write. assume_init ( ) )
875+ } ;
876+
877+ // Convert handles to file descriptors
878+ // O_NOINHERIT = 0x80 (MSVC CRT)
879+ const O_NOINHERIT : i32 = 0x80 ;
880+ let read_fd = unsafe { _open_osfhandle ( read_handle, O_NOINHERIT ) } ;
881+ let write_fd = unsafe { _open_osfhandle ( write_handle, libc:: O_WRONLY | O_NOINHERIT ) } ;
882+
883+ if read_fd == -1 || write_fd == -1 {
884+ unsafe {
885+ Foundation :: CloseHandle ( read_handle as _ ) ;
886+ Foundation :: CloseHandle ( write_handle as _ ) ;
887+ }
888+ return Err ( errno_err ( vm) ) ;
889+ }
890+
891+ Ok ( ( read_fd, write_fd) )
892+ }
893+
894+ #[ pyfunction]
895+ fn getppid ( ) -> u32 {
896+ use windows_sys:: Win32 :: System :: Threading :: GetCurrentProcess ;
897+
898+ #[ repr( C ) ]
899+ struct ProcessBasicInformation {
900+ exit_status : isize ,
901+ peb_base_address : * mut std:: ffi:: c_void ,
902+ affinity_mask : usize ,
903+ base_priority : i32 ,
904+ unique_process_id : usize ,
905+ inherited_from_unique_process_id : usize ,
906+ }
907+
908+ type NtQueryInformationProcessFn = unsafe extern "system" fn (
909+ process_handle : isize ,
910+ process_information_class : u32 ,
911+ process_information : * mut std:: ffi:: c_void ,
912+ process_information_length : u32 ,
913+ return_length : * mut u32 ,
914+ ) -> i32 ;
915+
916+ let ntdll = unsafe {
917+ windows_sys:: Win32 :: System :: LibraryLoader :: GetModuleHandleW ( windows_sys:: w!(
918+ "ntdll.dll"
919+ ) )
920+ } ;
921+ if ntdll. is_null ( ) {
922+ return 0 ;
923+ }
924+
925+ let func = unsafe {
926+ windows_sys:: Win32 :: System :: LibraryLoader :: GetProcAddress (
927+ ntdll,
928+ c"NtQueryInformationProcess" . as_ptr ( ) as * const u8 ,
929+ )
930+ } ;
931+ let Some ( func) = func else {
932+ return 0 ;
933+ } ;
934+ let nt_query: NtQueryInformationProcessFn = unsafe { std:: mem:: transmute ( func) } ;
935+
936+ let mut info = ProcessBasicInformation {
937+ exit_status : 0 ,
938+ peb_base_address : std:: ptr:: null_mut ( ) ,
939+ affinity_mask : 0 ,
940+ base_priority : 0 ,
941+ unique_process_id : 0 ,
942+ inherited_from_unique_process_id : 0 ,
943+ } ;
944+
945+ let status = unsafe {
946+ nt_query (
947+ GetCurrentProcess ( ) as isize ,
948+ 0 , // ProcessBasicInformation
949+ & mut info as * mut _ as * mut std:: ffi:: c_void ,
950+ std:: mem:: size_of :: < ProcessBasicInformation > ( ) as u32 ,
951+ std:: ptr:: null_mut ( ) ,
952+ )
953+ } ;
954+
955+ if status >= 0
956+ && info. inherited_from_unique_process_id != 0
957+ && info. inherited_from_unique_process_id < u32:: MAX as usize
958+ {
959+ info. inherited_from_unique_process_id as u32
960+ } else {
961+ 0
962+ }
963+ }
964+
857965 #[ pyfunction]
858966 fn dup ( fd : i32 , vm : & VirtualMachine ) -> PyResult < i32 > {
859967 let fd2 = unsafe { suppress_iph ! ( _dup( fd) ) } ;
0 commit comments