@@ -973,19 +973,19 @@ pub fn detect_ntfs_drives() -> Vec<char> {
973973
974974/// Checks if a drive is an NTFS volume.
975975///
976- /// This attempts to get NTFS volume data from the drive. If successful,
977- /// the drive is NTFS formatted .
978- #[ allow( unsafe_code) ] // Required: Windows FFI (GetDriveTypeW, CreateFileW, DeviceIoControl )
976+ /// Uses `GetVolumeInformationW` to check the filesystem name, which doesn't
977+ /// require elevated privileges .
978+ #[ allow( unsafe_code) ] // Required: Windows FFI (GetDriveTypeW, GetVolumeInformationW )
979979fn is_ntfs_volume ( drive_letter : char ) -> bool {
980- use windows:: Win32 :: Storage :: FileSystem :: GetDriveTypeW ;
980+ use windows:: Win32 :: Storage :: FileSystem :: { GetDriveTypeW , GetVolumeInformationW } ;
981981
982982 // First check if it's a fixed or removable drive (skip network, CD-ROM, etc.)
983- let path : Vec < u16 > = format ! ( "{}:\\ " , drive_letter. to_ascii_uppercase( ) )
983+ let root_path : Vec < u16 > = format ! ( "{}:\\ " , drive_letter. to_ascii_uppercase( ) )
984984 . encode_utf16 ( )
985985 . chain ( std:: iter:: once ( 0 ) )
986986 . collect ( ) ;
987987
988- let drive_type = unsafe { GetDriveTypeW ( PCWSTR ( path . as_ptr ( ) ) ) } ;
988+ let drive_type = unsafe { GetDriveTypeW ( PCWSTR ( root_path . as_ptr ( ) ) ) } ;
989989
990990 // DRIVE_FIXED = 3, DRIVE_REMOVABLE = 2
991991 // Skip DRIVE_UNKNOWN (0), DRIVE_NO_ROOT_DIR (1), DRIVE_REMOTE (4), DRIVE_CDROM
@@ -994,50 +994,29 @@ fn is_ntfs_volume(drive_letter: char) -> bool {
994994 return false ;
995995 }
996996
997- // Try to open the volume and get NTFS data
998- let volume_path: Vec < u16 > = format ! ( "\\ \\ .\\ {}:" , drive_letter. to_ascii_uppercase( ) )
999- . encode_utf16 ( )
1000- . chain ( std:: iter:: once ( 0 ) )
1001- . collect ( ) ;
997+ // Get filesystem name using GetVolumeInformationW (no admin required)
998+ let mut fs_name_buffer: [ u16 ; 32 ] = [ 0 ; 32 ] ;
1002999
1003- let handle = unsafe {
1004- CreateFileW (
1005- PCWSTR ( volume_path. as_ptr ( ) ) ,
1006- FILE_READ_ATTRIBUTES . 0 ,
1007- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE ,
1008- None ,
1009- OPEN_EXISTING ,
1010- FILE_FLAG_BACKUP_SEMANTICS ,
1011- None ,
1000+ let result = unsafe {
1001+ GetVolumeInformationW (
1002+ PCWSTR ( root_path. as_ptr ( ) ) ,
1003+ None , // Volume name buffer (not needed)
1004+ None , // Volume serial number (not needed)
1005+ None , // Max component length (not needed)
1006+ None , // File system flags (not needed)
1007+ Some ( & mut fs_name_buffer) , // File system name buffer
10121008 )
10131009 } ;
10141010
1015- let Ok ( handle ) = handle else {
1011+ if result . is_err ( ) {
10161012 return false ;
1017- } ;
1018-
1019- // Try to get NTFS volume data
1020- use windows:: Win32 :: System :: IO :: DeviceIoControl ;
1021-
1022- let mut buffer = NTFS_VOLUME_DATA_BUFFER :: default ( ) ;
1023- let mut bytes_returned: u32 = 0 ;
1024-
1025- let result = unsafe {
1026- DeviceIoControl (
1027- handle,
1028- FSCTL_GET_NTFS_VOLUME_DATA ,
1029- None ,
1030- 0 ,
1031- Some ( core:: ptr:: from_mut ( & mut buffer) . cast ( ) ) ,
1032- size_of :: < NTFS_VOLUME_DATA_BUFFER > ( ) as u32 ,
1033- Some ( & mut bytes_returned) ,
1034- None ,
1035- )
1036- } ;
1013+ }
10371014
1038- let _ = unsafe { CloseHandle ( handle) } ;
1015+ // Convert filesystem name to string and check if it's NTFS
1016+ let fs_name = String :: from_utf16_lossy ( & fs_name_buffer) ;
1017+ let fs_name = fs_name. trim_end_matches ( '\0' ) ;
10391018
1040- result . is_ok ( )
1019+ fs_name == "NTFS"
10411020}
10421021
10431022#[ cfg( test) ]
0 commit comments