22//@compile-flags: -Zmiri-disable-isolation
33#![ allow( nonstandard_style) ]
44
5- use std:: io:: { ErrorKind , Read , Write } ;
5+ use std:: io:: { ErrorKind , Read , Seek , SeekFrom , Write } ;
66use std:: os:: windows:: ffi:: OsStrExt ;
7- use std:: os:: windows:: io:: AsRawHandle ;
7+ use std:: os:: windows:: io:: { AsRawHandle , FromRawHandle } ;
88use std:: path:: Path ;
9- use std:: { fs, ptr} ;
9+ use std:: { fs, mem , ptr} ;
1010
1111#[ path = "../../utils/mod.rs" ]
1212mod utils;
1313
1414use windows_sys:: Wdk :: Storage :: FileSystem :: { NtReadFile , NtWriteFile } ;
1515use windows_sys:: Win32 :: Foundation :: {
16- CloseHandle , ERROR_ACCESS_DENIED , ERROR_ALREADY_EXISTS , ERROR_IO_DEVICE , GENERIC_READ ,
17- GENERIC_WRITE , GetLastError , RtlNtStatusToDosError , STATUS_ACCESS_DENIED ,
18- STATUS_IO_DEVICE_ERROR , STATUS_SUCCESS , SetLastError ,
16+ CloseHandle , DUPLICATE_SAME_ACCESS , DuplicateHandle , ERROR_ACCESS_DENIED , ERROR_ALREADY_EXISTS ,
17+ ERROR_IO_DEVICE , FALSE , GENERIC_READ , GENERIC_WRITE , GetLastError , RtlNtStatusToDosError ,
18+ STATUS_ACCESS_DENIED , STATUS_IO_DEVICE_ERROR , STATUS_SUCCESS , SetLastError ,
1919} ;
2020use windows_sys:: Win32 :: Storage :: FileSystem :: {
2121 BY_HANDLE_FILE_INFORMATION , CREATE_ALWAYS , CREATE_NEW , CreateFileW , DeleteFileW ,
@@ -24,6 +24,7 @@ use windows_sys::Win32::Storage::FileSystem::{
2424 FILE_SHARE_WRITE , GetFileInformationByHandle , OPEN_ALWAYS , OPEN_EXISTING , SetFilePointerEx ,
2525} ;
2626use windows_sys:: Win32 :: System :: IO :: IO_STATUS_BLOCK ;
27+ use windows_sys:: Win32 :: System :: Threading :: GetCurrentProcess ;
2728
2829fn main ( ) {
2930 unsafe {
@@ -36,6 +37,7 @@ fn main() {
3637 test_ntstatus_to_dos ( ) ;
3738 test_file_read_write ( ) ;
3839 test_file_seek ( ) ;
40+ test_dup_handle ( ) ;
3941 }
4042}
4143
@@ -273,6 +275,39 @@ unsafe fn test_file_read_write() {
273275 assert_eq ! ( GetLastError ( ) , 1234 ) ;
274276}
275277
278+ unsafe fn test_dup_handle ( ) {
279+ let temp = utils:: tmp ( ) . join ( "test_dup.txt" ) ;
280+
281+ let mut file1 = fs:: File :: options ( ) . read ( true ) . write ( true ) . create ( true ) . open ( & temp) . unwrap ( ) ;
282+
283+ file1. write_all ( b"Hello, World!\n " ) . unwrap ( ) ;
284+ file1. seek ( SeekFrom :: Start ( 0 ) ) . unwrap ( ) ;
285+
286+ let first_handle = file1. as_raw_handle ( ) ;
287+
288+ let cur_proc = GetCurrentProcess ( ) ;
289+ let mut second_handle = mem:: zeroed ( ) ;
290+ let res = DuplicateHandle (
291+ cur_proc,
292+ first_handle,
293+ cur_proc,
294+ & mut second_handle,
295+ 0 ,
296+ FALSE ,
297+ DUPLICATE_SAME_ACCESS ,
298+ ) ;
299+ assert ! ( res != 0 ) ;
300+
301+ let mut buf1 = [ 0 ; 5 ] ;
302+ file1. read ( & mut buf1) . unwrap ( ) ;
303+ assert_eq ! ( & buf1, b"Hello" ) ;
304+
305+ let mut file2 = fs:: File :: from_raw_handle ( second_handle) ;
306+ let mut buf2 = [ 0 ; 5 ] ;
307+ file2. read ( & mut buf2) . unwrap ( ) ;
308+ assert_eq ! ( & buf2, b", Wor" ) ;
309+ }
310+
276311unsafe fn test_file_seek ( ) {
277312 let temp = utils:: tmp ( ) . join ( "test_file_seek.txt" ) ;
278313 let mut file = fs:: File :: options ( ) . create ( true ) . write ( true ) . read ( true ) . open ( & temp) . unwrap ( ) ;
0 commit comments