@@ -567,6 +567,97 @@ pub(crate) mod module {
567567 . is_some_and ( |p| _test_file_exists ( & p, false ) )
568568 }
569569
570+ /// Check if a path is on a Windows Dev Drive.
571+ #[ pyfunction]
572+ fn _path_isdevdrive ( path : OsPath , vm : & VirtualMachine ) -> PyResult < bool > {
573+ use windows_sys:: Win32 :: Foundation :: CloseHandle ;
574+ use windows_sys:: Win32 :: Storage :: FileSystem :: {
575+ CreateFileW , FILE_FLAG_BACKUP_SEMANTICS , FILE_READ_ATTRIBUTES , FILE_SHARE_READ ,
576+ FILE_SHARE_WRITE , GetDriveTypeW , GetVolumePathNameW , OPEN_EXISTING ,
577+ } ;
578+ use windows_sys:: Win32 :: System :: IO :: DeviceIoControl ;
579+ use windows_sys:: Win32 :: System :: Ioctl :: FSCTL_QUERY_PERSISTENT_VOLUME_STATE ;
580+ use windows_sys:: Win32 :: System :: WindowsProgramming :: DRIVE_FIXED ;
581+
582+ // PERSISTENT_VOLUME_STATE_DEV_VOLUME flag - not yet in windows-sys
583+ const PERSISTENT_VOLUME_STATE_DEV_VOLUME : u32 = 0x00002000 ;
584+
585+ // FILE_FS_PERSISTENT_VOLUME_INFORMATION structure
586+ #[ repr( C ) ]
587+ struct FileFsPersistentVolumeInformation {
588+ volume_flags : u32 ,
589+ flag_mask : u32 ,
590+ version : u32 ,
591+ reserved : u32 ,
592+ }
593+
594+ let wide_path = path. to_wide_cstring ( vm) ?;
595+ let mut volume = [ 0u16 ; Foundation :: MAX_PATH as usize ] ;
596+
597+ // Get volume path
598+ let ret = unsafe {
599+ GetVolumePathNameW ( wide_path. as_ptr ( ) , volume. as_mut_ptr ( ) , volume. len ( ) as _ )
600+ } ;
601+ if ret == 0 {
602+ return Err ( vm. new_last_os_error ( ) ) ;
603+ }
604+
605+ // Check if it's a fixed drive
606+ if unsafe { GetDriveTypeW ( volume. as_ptr ( ) ) } != DRIVE_FIXED {
607+ return Ok ( false ) ;
608+ }
609+
610+ // Open the volume
611+ let handle = unsafe {
612+ CreateFileW (
613+ volume. as_ptr ( ) ,
614+ FILE_READ_ATTRIBUTES ,
615+ FILE_SHARE_READ | FILE_SHARE_WRITE ,
616+ std:: ptr:: null ( ) ,
617+ OPEN_EXISTING ,
618+ FILE_FLAG_BACKUP_SEMANTICS ,
619+ std:: ptr:: null_mut ( ) ,
620+ )
621+ } ;
622+ if handle == INVALID_HANDLE_VALUE {
623+ return Err ( vm. new_last_os_error ( ) ) ;
624+ }
625+
626+ // Query persistent volume state
627+ let mut volume_state = FileFsPersistentVolumeInformation {
628+ volume_flags : 0 ,
629+ flag_mask : PERSISTENT_VOLUME_STATE_DEV_VOLUME ,
630+ version : 1 ,
631+ reserved : 0 ,
632+ } ;
633+
634+ let ret = unsafe {
635+ DeviceIoControl (
636+ handle,
637+ FSCTL_QUERY_PERSISTENT_VOLUME_STATE ,
638+ & volume_state as * const _ as * const std:: ffi:: c_void ,
639+ std:: mem:: size_of :: < FileFsPersistentVolumeInformation > ( ) as u32 ,
640+ & mut volume_state as * mut _ as * mut std:: ffi:: c_void ,
641+ std:: mem:: size_of :: < FileFsPersistentVolumeInformation > ( ) as u32 ,
642+ std:: ptr:: null_mut ( ) ,
643+ std:: ptr:: null_mut ( ) ,
644+ )
645+ } ;
646+
647+ unsafe { CloseHandle ( handle) } ;
648+
649+ if ret == 0 {
650+ let err = io:: Error :: last_os_error ( ) ;
651+ // ERROR_INVALID_PARAMETER means not supported on this platform
652+ if err. raw_os_error ( ) == Some ( Foundation :: ERROR_INVALID_PARAMETER as i32 ) {
653+ return Ok ( false ) ;
654+ }
655+ return Err ( err. to_pyexception ( vm) ) ;
656+ }
657+
658+ Ok ( ( volume_state. volume_flags & PERSISTENT_VOLUME_STATE_DEV_VOLUME ) != 0 )
659+ }
660+
570661 // cwait is available on MSVC only
571662 #[ cfg( target_env = "msvc" ) ]
572663 unsafe extern "C" {
0 commit comments