1
1
Fork 0
mirror of https://github.com/pbatard/rufus.git synced 2024-08-14 23:57:05 +00:00

[usb] enable listing of non USB card readers

* Also fix the VID:PID population of USB card readers
* Also improve enumeration debugging
* Also add an unofficial cheat mode to list non USB *REMOVABLE* drives
* Closes #693
This commit is contained in:
Pete Batard 2016-02-16 17:47:07 +00:00
parent 58755c1bc4
commit f88faf1a4f
6 changed files with 248 additions and 100 deletions

View file

@ -395,10 +395,10 @@ static BOOL _GetDriveLettersAndType(DWORD DriveIndex, char* drive_letters, UINT*
continue; continue;
} }
/* IOCTL_STORAGE_GET_DEVICE_NUMBER's STORAGE_DEVICE_NUMBER.DeviceNumber is // IOCTL_STORAGE_GET_DEVICE_NUMBER's STORAGE_DEVICE_NUMBER.DeviceNumber is
not unique! An HDD, a DVD and probably other drives can have the same // not unique! An HDD, a DVD and probably other drives can have the same
value there => Use GetDriveType() to filter out unwanted devices. // value there => Use GetDriveType() to filter out unwanted devices.
See https://github.com/pbatard/rufus/issues/32 for details. */ // See https://github.com/pbatard/rufus/issues/32#issuecomment-3785956
_drive_type = GetDriveTypeA(drive); _drive_type = GetDriveTypeA(drive);
if ((_drive_type != DRIVE_REMOVABLE) && (_drive_type != DRIVE_FIXED)) if ((_drive_type != DRIVE_REMOVABLE) && (_drive_type != DRIVE_FIXED))

View file

@ -1883,7 +1883,7 @@ DWORD WINAPI FormatThread(void* param)
} else if (tt == TT_UEFI) { } else if (tt == TT_UEFI) {
// For once, no need to do anything - just check our sanity // For once, no need to do anything - just check our sanity
if ( (bt != BT_ISO) || (!img_report.has_efi) || (fs > FS_NTFS) ) { if ( (bt != BT_ISO) || (!img_report.has_efi) || (fs > FS_NTFS) ) {
uprintf("Spock gone crazy error!\n"); uprintf("Spock gone crazy error in %s:%d", __FILE__, __LINE__);
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INSTALL_FAILURE; FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_INSTALL_FAILURE;
goto out; goto out;
} }

View file

@ -152,7 +152,7 @@ BOOL use_own_c32[NB_OLD_C32] = {FALSE, FALSE}, mbr_selected_by_user = FALSE, tog
BOOL iso_op_in_progress = FALSE, format_op_in_progress = FALSE, right_to_left_mode = FALSE; BOOL iso_op_in_progress = FALSE, format_op_in_progress = FALSE, right_to_left_mode = FALSE;
BOOL enable_HDDs = FALSE, force_update = FALSE, enable_ntfs_compression = FALSE, no_confirmation_on_cancel = FALSE, lock_drive = TRUE; BOOL enable_HDDs = FALSE, force_update = FALSE, enable_ntfs_compression = FALSE, no_confirmation_on_cancel = FALSE, lock_drive = TRUE;
BOOL advanced_mode, allow_dual_uefi_bios, detect_fakes, enable_vmdk, force_large_fat32, usb_debug, use_fake_units, preserve_timestamps; BOOL advanced_mode, allow_dual_uefi_bios, detect_fakes, enable_vmdk, force_large_fat32, usb_debug, use_fake_units, preserve_timestamps;
BOOL zero_drive = FALSE; BOOL zero_drive = FALSE, list_non_usb_removable_drives = FALSE;
int dialog_showing = 0, lang_button_id = 0; int dialog_showing = 0, lang_button_id = 0;
uint16_t rufus_version[3], embedded_sl_version[2]; uint16_t rufus_version[3], embedded_sl_version[2];
char embedded_sl_version_str[2][12] = { "?.??", "?.??" }; char embedded_sl_version_str[2][12] = { "?.??", "?.??" };
@ -1762,7 +1762,7 @@ void InitDialog(HWND hDlg)
if (selected_locale->ctrl_id & LOC_NEEDS_UPDATE) { if (selected_locale->ctrl_id & LOC_NEEDS_UPDATE) {
uprintf("NOTE: The %s translation requires an update, but the current translator hasn't submitted " uprintf("NOTE: The %s translation requires an update, but the current translator hasn't submitted "
"one. Because of this, some messages will only be displayed in English.", selected_locale->txt[1]); "one. Because of this, some messages will only be displayed in English.", selected_locale->txt[1]);
uprintf("If you think you can help update this translation, please e-mail <pete@akeo.ie>."); uprintf("If you think you can help update this translation, please e-mail the author of this application");
} }
SetClusterSizeLabels(); SetClusterSizeLabels();
@ -2826,6 +2826,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
int wait_for_mutex = 0; int wait_for_mutex = 0;
FILE* fd; FILE* fd;
BOOL attached_console = FALSE, external_loc_file = FALSE, lgp_set = FALSE, automount, disable_hogger = FALSE; BOOL attached_console = FALSE, external_loc_file = FALSE, lgp_set = FALSE, automount, disable_hogger = FALSE;
BOOL previous_enable_HDDs = FALSE;
BYTE *loc_data; BYTE *loc_data;
DWORD loc_size, size; DWORD loc_size, size;
char tmp_path[MAX_PATH] = "", loc_file[MAX_PATH] = "", ini_path[MAX_PATH], ini_flags[] = "rb"; char tmp_path[MAX_PATH] = "", loc_file[MAX_PATH] = "", ini_path[MAX_PATH], ini_flags[] = "rb";
@ -3278,6 +3279,26 @@ relaunch:
PostMessage(hDlg, WM_COMMAND, (WPARAM)IDC_START, 0); PostMessage(hDlg, WM_COMMAND, (WPARAM)IDC_START, 0);
} }
// Hazardous cheat modes require Ctrl + Alt
// Ctrl-Alt-F => List non USB removable drives such as eSATA, etc - CAUTION!!!
if ((msg.message == WM_KEYDOWN) && (msg.wParam == 'F') &&
(GetKeyState(VK_CONTROL) & 0x8000) && (GetKeyState(VK_MENU) & 0x8000)) {
list_non_usb_removable_drives = !list_non_usb_removable_drives;
if (list_non_usb_removable_drives) {
previous_enable_HDDs = enable_HDDs;
enable_HDDs = TRUE;
} else {
enable_HDDs = previous_enable_HDDs;
}
CheckDlgButton(hMainDialog, IDC_ENABLE_FIXED_DISKS, enable_HDDs ? BST_CHECKED : BST_UNCHECKED);
PrintStatus2000("Listing of non-USB removable drives", list_non_usb_removable_drives);
uprintf("NOTE: Listing of non-USB removable drives has been %s.", (list_non_usb_removable_drives)?"enabled (CAUTION!)":"disabled");
if (list_non_usb_removable_drives)
uprintf("By using this unofficial cheat mode you forfeit ANY RIGHT to complain if you lose valuable data!");
GetUSBDevices(0);
continue;
}
// Let the system handle dialog messages (e.g. those from the tab key) // Let the system handle dialog messages (e.g. those from the tab key)
if (!IsDialogMessage(hDlg, &msg) && !IsDialogMessage(hLogDlg, &msg)) { if (!IsDialogMessage(hDlg, &msg) && !IsDialogMessage(hLogDlg, &msg)) {
TranslateMessage(&msg); TranslateMessage(&msg);

View file

@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 242, 376 IDD_DIALOG DIALOGEX 12, 12, 242, 376
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES EXSTYLE WS_EX_ACCEPTFILES
CAPTION "Rufus 2.7.857" CAPTION "Rufus 2.7.858"
FONT 8, "Segoe UI Symbol", 400, 0, 0x0 FONT 8, "Segoe UI Symbol", 400, 0, 0x0
BEGIN BEGIN
LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8
@ -320,8 +320,8 @@ END
// //
VS_VERSION_INFO VERSIONINFO VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,7,857,0 FILEVERSION 2,7,858,0
PRODUCTVERSION 2,7,857,0 PRODUCTVERSION 2,7,858,0
FILEFLAGSMASK 0x3fL FILEFLAGSMASK 0x3fL
#ifdef _DEBUG #ifdef _DEBUG
FILEFLAGS 0x1L FILEFLAGS 0x1L
@ -338,13 +338,13 @@ BEGIN
BEGIN BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus" VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "2.7.857" VALUE "FileVersion", "2.7.858"
VALUE "InternalName", "Rufus" VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2016 Pete Batard (GPL v3)" VALUE "LegalCopyright", "© 2011-2016 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe" VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus" VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "2.7.857" VALUE "ProductVersion", "2.7.858"
END END
END END
BLOCK "VarFileInfo" BLOCK "VarFileInfo"

284
src/usb.c
View file

@ -1,7 +1,7 @@
/* /*
* Rufus: The Reliable USB Formatting Utility * Rufus: The Reliable USB Formatting Utility
* USB device listing * USB device listing
* Copyright © 2014 Pete Batard <pete@akeo.ie> * Copyright © 2014-2016 Pete Batard <pete@akeo.ie>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -41,7 +41,7 @@
#include "usb.h" #include "usb.h"
extern StrArray DriveID, DriveLabel; extern StrArray DriveID, DriveLabel;
extern BOOL enable_HDDs, use_fake_units, enable_vmdk, usb_debug; extern BOOL enable_HDDs, use_fake_units, enable_vmdk, usb_debug, list_non_usb_removable_drives;
/* /*
* Get the VID, PID and current device speed * Get the VID, PID and current device speed
@ -133,6 +133,17 @@ static __inline BOOL IsVHD(const char* buffer)
return FALSE; return FALSE;
} }
static __inline BOOL IsRemovable(const char* buffer)
{
switch (*((DWORD*)buffer)) {
case CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL:
case CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL:
return TRUE;
default:
return FALSE;
}
}
/* For debugging user reports of HDDs vs UFDs */ /* For debugging user reports of HDDs vs UFDs */
//#define FORCED_DEVICE //#define FORCED_DEVICE
#ifdef FORCED_DEVICE #ifdef FORCED_DEVICE
@ -146,29 +157,50 @@ static __inline BOOL IsVHD(const char* buffer)
*/ */
BOOL GetUSBDevices(DWORD devnum) BOOL GetUSBDevices(DWORD devnum)
{ {
// The first two are standard Microsoft drivers (including the Windows 8 UASP one). // List of USB storage drivers we know - list may be incomplete!
// The rest are the vendor UASP drivers I know of so far - list may be incomplete! const char* usbstor_name[] = {
const char* storage_name[] = { "USBSTOR", "UASPSTOR", "VUSBSTOR", "ETRONSTOR", "ASUSSTPT" }; // Standard MS USB storage driver
const char* scsi_name = "SCSI"; "USBSTOR",
// USB card readers, with proprietary drivers (Realtek,etc...)
// Mostly "guessed" from http://www.carrona.org/dvrref.php
"RTSUER", "CMIUCR", "EUCR",
// UASP Drivers *MUST* be listed after this, starting with "UASPSTOR"
// (which is Microsoft's native UASP driver for Windows 8 and later)
// as we use "UASPSTOR" as a delimiter
"UASPSTOR", "VUSBSTOR", "ETRONSTOR", "ASUSSTPT"
};
// These are the generic (non USB) storage enumerators we also test
const char* genstor_name[] = {
// Generic storage drivers (Careful now!)
"SCSI", // "STORAGE", // "STORAGE" is used by 'Storage Spaces" and stuff => DANGEROUS!
// Non-USB card reader drivers - *MUST* start with "SD" (delimiter)
// See http://itdoc.hitachi.co.jp/manuals/3021/30213B5200e/DMDS0094.HTM
// Also http://www.carrona.org/dvrref.php. NB: These should be reported
// as enumerators by Rufus when Enum Debug is enabled
"SD", "PCISTOR", "RTSOR", "JMCR", "JMCF", "RIMMPTSK", "RIMSPTSK", "RIXDPTSK",
"TI21SONY", "ESD7SK", "ESM7SK", "O2MD", "O2SD", "VIACR"
};
const char* usb_speed_name[USB_SPEED_MAX] = { "USB", "USB 1.0", "USB 1.1", "USB 2.0", "USB 3.0" }; const char* usb_speed_name[USB_SPEED_MAX] = { "USB", "USB 1.0", "USB 1.1", "USB 2.0", "USB 3.0" };
// Hash table and String Array used to match a Device ID with the parent hub's Device Interface Path // Hash table and String Array used to match a Device ID with the parent hub's Device Interface Path
htab_table htab_devid = HTAB_EMPTY; htab_table htab_devid = HTAB_EMPTY;
StrArray dev_if_path; StrArray dev_if_path;
char letter_name[] = " (?:)"; char letter_name[] = " (?:)";
char drive_name[] = "?:\\";
char uefi_togo_check[] = "?:\\EFI\\Rufus\\ntfs_x64.efi"; char uefi_togo_check[] = "?:\\EFI\\Rufus\\ntfs_x64.efi";
BOOL r = FALSE, found = FALSE, is_SCSI, post_backslash; BOOL r = FALSE, found = FALSE, post_backslash;
HDEVINFO dev_info = NULL; HDEVINFO dev_info = NULL;
SP_DEVINFO_DATA dev_info_data; SP_DEVINFO_DATA dev_info_data;
SP_DEVICE_INTERFACE_DATA devint_data; SP_DEVICE_INTERFACE_DATA devint_data;
PSP_DEVICE_INTERFACE_DETAIL_DATA_A devint_detail_data; PSP_DEVICE_INTERFACE_DETAIL_DATA_A devint_detail_data;
DEVINST parent_inst, grandparent_inst, device_inst; DEVINST parent_inst, grandparent_inst, sibling_inst, device_inst;
DWORD size, i, j, k, l, datatype, drive_index; DWORD size, i, j, k, l, datatype, drive_index;
ULONG list_size[ARRAYSIZE(storage_name)] = { 0 }, list_start[ARRAYSIZE(storage_name)] = { 0 }, full_list_size, ulFlags; DWORD uasp_start = ARRAYSIZE(usbstor_name), card_start = ARRAYSIZE(genstor_name);
ULONG list_size[ARRAYSIZE(usbstor_name)] = { 0 }, list_start[ARRAYSIZE(usbstor_name)] = { 0 }, full_list_size, ulFlags;
HANDLE hDrive; HANDLE hDrive;
LONG maxwidth = 0; LONG maxwidth = 0;
int s, score, drive_number, remove_drive; int s, score, drive_number, remove_drive;
char drive_letters[27], *device_id, *devid_list = NULL, entry_msg[128]; char drive_letters[27], *device_id, *devid_list = NULL, entry_msg[128];
char *label, *entry, buffer[MAX_PATH], str[MAX_PATH], *method_str; char *p, *label, *entry, buffer[MAX_PATH], str[MAX_PATH], *method_str;
usb_device_props props; usb_device_props props;
IGNORE_RETVAL(ComboBox_ResetContent(hDeviceList)); IGNORE_RETVAL(ComboBox_ResetContent(hDeviceList));
@ -235,29 +267,47 @@ BOOL GetUSBDevices(DWORD devnum)
ulFlags = CM_GETIDLIST_FILTER_SERVICE; ulFlags = CM_GETIDLIST_FILTER_SERVICE;
if (nWindowsVersion >= WINDOWS_7) if (nWindowsVersion >= WINDOWS_7)
ulFlags |= CM_GETIDLIST_FILTER_PRESENT; ulFlags |= CM_GETIDLIST_FILTER_PRESENT;
for (s=0; s<ARRAYSIZE(storage_name); s++) { for (s=0; s<ARRAYSIZE(usbstor_name); s++) {
// Get a list of device IDs for all USB storage devices // Get a list of device IDs for all USB storage devices
// This will be used to find if a device is UASP // This will be used to find if a device is UASP
if (CM_Get_Device_ID_List_SizeA(&list_size[s], storage_name[s], ulFlags) != CR_SUCCESS) // Also compute the uasp_start index
if (strcmp(usbstor_name[s], "UASPSTOR") == 0)
uasp_start = s;
if (CM_Get_Device_ID_List_SizeA(&list_size[s], usbstor_name[s], ulFlags) != CR_SUCCESS)
list_size[s] = 0; list_size[s] = 0;
if (list_size[s] != 0) if (list_size[s] != 0)
full_list_size += list_size[s]-1; // remove extra NUL terminator full_list_size += list_size[s]-1; // remove extra NUL terminator
} }
// Compute the card_start index
for (s=0; s<ARRAYSIZE(genstor_name); s++) {
if (strcmp(genstor_name[s], "SD") == 0)
card_start = s;
}
// Overkill, but better safe than sorry. And yeah, we could have used
// arrays of arrays to avoid this, but it's more readable this way.
if ((uasp_start <= 0) || (uasp_start >= ARRAYSIZE(usbstor_name))) {
uprintf("Spock gone crazy error in %s:%d", __FILE__, __LINE__);
goto out;
}
if ((card_start <= 0) || (card_start >= ARRAYSIZE(genstor_name))) {
uprintf("Spock gone crazy error in %s:%d", __FILE__, __LINE__);
goto out;
}
devid_list = NULL; devid_list = NULL;
if (full_list_size != 0) { if (full_list_size != 0) {
full_list_size += 1; // add extra NUL terminator full_list_size += 1; // add extra NUL terminator
devid_list = (char*)malloc(full_list_size); devid_list = (char*)malloc(full_list_size);
if (devid_list == NULL) { if (devid_list == NULL) {
uprintf("Could not allocate Device ID list\n"); uprintf("Could not allocate Device ID list\n");
return FALSE; goto out;
} }
for (s=0, i=0; s<ARRAYSIZE(storage_name); s++) { for (s=0, i=0; s<ARRAYSIZE(usbstor_name); s++) {
list_start[s] = i; list_start[s] = i;
if (list_size[s] > 1) { if (list_size[s] > 1) {
if (CM_Get_Device_ID_ListA(storage_name[s], &devid_list[i], list_size[s], ulFlags) != CR_SUCCESS) if (CM_Get_Device_ID_ListA(usbstor_name[s], &devid_list[i], list_size[s], ulFlags) != CR_SUCCESS)
continue; continue;
if (usb_debug) { if (usb_debug) {
uprintf("Processing IDs belonging to %s:", storage_name[s]); uprintf("Processing IDs belonging to '%s':", usbstor_name[s]);
for (device_id = &devid_list[i]; *device_id != 0; device_id += strlen(device_id) + 1) for (device_id = &devid_list[i]; *device_id != 0; device_id += strlen(device_id) + 1)
uprintf(" %s", device_id); uprintf(" %s", device_id);
} }
@ -270,7 +320,7 @@ BOOL GetUSBDevices(DWORD devnum)
} }
} }
// Now use SetupDi to enumerate all our storage devices // Now use SetupDi to enumerate all our disk storage devices
dev_info = SetupDiGetClassDevsA(&_GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE); dev_info = SetupDiGetClassDevsA(&_GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
if (dev_info == INVALID_HANDLE_VALUE) { if (dev_info == INVALID_HANDLE_VALUE) {
uprintf("SetupDiGetClassDevs (Interface) failed: %s\n", WindowsErrorString()); uprintf("SetupDiGetClassDevs (Interface) failed: %s\n", WindowsErrorString());
@ -279,24 +329,49 @@ BOOL GetUSBDevices(DWORD devnum)
dev_info_data.cbSize = sizeof(dev_info_data); dev_info_data.cbSize = sizeof(dev_info_data);
for (i=0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) { for (i=0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
memset(&props, 0, sizeof(props));
method_str = ""; method_str = "";
if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ENUMERATOR_NAME, if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ENUMERATOR_NAME,
&datatype, (LPBYTE)buffer, sizeof(buffer), &size)) { &datatype, (LPBYTE)buffer, sizeof(buffer), &size)) {
uprintf("SetupDiGetDeviceRegistryProperty (Enumerator Name) failed: %s\n", WindowsErrorString()); uprintf("SetupDiGetDeviceRegistryProperty (Enumerator Name) failed: %s\n", WindowsErrorString());
continue; continue;
} }
// UASP drives are listed under SCSI (along with regular SYSTEM drives => "DANGER, WILL ROBINSON!!!")
is_SCSI = (safe_stricmp(buffer, scsi_name) == 0); for (j = 0; j < ARRAYSIZE(usbstor_name); j++) {
if ((safe_stricmp(buffer, storage_name[0]) != 0) && (!is_SCSI)) if (safe_stricmp(buffer, usbstor_name[0]) == 0) {
props.is_USB = TRUE;
if ((j != 0) && (j < uasp_start))
props.is_CARD = TRUE;
break;
}
}
// UASP drives are listed under SCSI, and we also have non USB card readers to populate
for (j = 0; j < ARRAYSIZE(genstor_name); j++) {
if (safe_stricmp(buffer, genstor_name[j]) == 0) {
props.is_SCSI = TRUE;
if (j >= card_start)
props.is_CARD = TRUE;
break;
}
}
uuprintf("Processing '%s' device:", buffer);
if ((!props.is_USB) && (!props.is_SCSI)) {
uuprintf(" Disabled by policy");
continue; continue;
}
// We can't use the friendly name to find if a drive is a VHD, as friendly name string gets translated // We can't use the friendly name to find if a drive is a VHD, as friendly name string gets translated
// according to your locale, so we poke the Hardware ID // according to your locale, so we poke the Hardware ID
memset(&props, 0, sizeof(props));
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
props.is_VHD = SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_HARDWAREID, props.is_VHD = SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_HARDWAREID,
&datatype, (LPBYTE)buffer, sizeof(buffer), &size) && IsVHD(buffer); &datatype, (LPBYTE)buffer, sizeof(buffer), &size) && IsVHD(buffer);
uuprintf("Processing Device: '%s'", buffer); uuprintf(" Hardware ID: '%s'", buffer);
memset(buffer, 0, sizeof(buffer));
props.is_Removable = SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_REMOVAL_POLICY,
&datatype, (LPBYTE)buffer, sizeof(buffer), &size) && IsRemovable(buffer);
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_FRIENDLYNAME, if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_FRIENDLYNAME,
@ -307,72 +382,92 @@ BOOL GetUSBDevices(DWORD devnum)
} else if ((!props.is_VHD) && (devid_list != NULL)) { } else if ((!props.is_VHD) && (devid_list != NULL)) {
// Get the properties of the device. We could avoid doing this lookup every time by keeping // Get the properties of the device. We could avoid doing this lookup every time by keeping
// a lookup table, but there shouldn't be that many USB storage devices connected... // a lookup table, but there shouldn't be that many USB storage devices connected...
// NB: Each of these Device IDs have an _only_ child, from which we get the Device Instance match. // NB: Each of these Device IDs should have a child, from which we get the Device Instance match.
for (device_id = devid_list; *device_id != 0; device_id += strlen(device_id) + 1) { for (device_id = devid_list; *device_id != 0; device_id += strlen(device_id) + 1) {
if ( (CM_Locate_DevNodeA(&parent_inst, device_id, 0) == CR_SUCCESS) if (CM_Locate_DevNodeA(&parent_inst, device_id, 0) != CR_SUCCESS) {
&& (CM_Get_Child(&device_inst, parent_inst, 0) == CR_SUCCESS) uuprintf("Could not locate device node for '%s'", device_id);
&& (device_inst == dev_info_data.DevInst) ) { continue;
post_backslash = FALSE; }
method_str = ""; if (CM_Get_Child(&device_inst, parent_inst, 0) != CR_SUCCESS) {
uuprintf("Could not get children of '%s'", device_id);
// If we're not dealing with the USBSTOR part of our list, then this is an UASP device continue;
props.is_UASP = ((((uintptr_t)device_id)+2) >= ((uintptr_t)devid_list)+list_start[1]); }
// Now get the properties of the device, and its Device ID, which we need to populate the properties if (device_inst != dev_info_data.DevInst) {
j = htab_hash(device_id, &htab_devid); // Try the siblings
uuprintf(" Matched with ID[%03d]: %s", j, device_id); while (CM_Get_Sibling(&sibling_inst, device_inst, 0) == CR_SUCCESS) {
if (sibling_inst == dev_info_data.DevInst) {
// Try to parse the current device_id string for VID:PID uuprintf("NOTE: Matched instance from sibling for '%s'", device_id);
// We'll use that if we can't get anything better device_inst = sibling_inst;
for (k = 0, l = 0; (k<strlen(device_id)) && (l<2); k++) { break;
// The ID is in the form USB_VENDOR_BUSID\VID_xxxx&PID_xxxx\...
if (device_id[k] == '\\')
post_backslash = TRUE;
if (!post_backslash)
continue;
if (device_id[k] == '_') {
props.pid = (uint16_t)strtoul(&device_id[k + 1], NULL, 16);
if (l++ == 0)
props.vid = props.pid;
} }
} }
if (props.vid != 0) if (device_inst != dev_info_data.DevInst)
method_str = "[ID]"; continue;
// If the hash didn't match a populated string in dev_if_path[] (htab_devid.table[j].data > 0),
// we might have an extra vendor driver in between (e.g. "ASUS USB 3.0 Boost Storage Driver"
// for UASP devices in ASUS "Turbo Mode" or "Apple Mobile Device USB Driver" for iPods)
// so try to see if we can match the grandparent.
if ( ((uintptr_t)htab_devid.table[j].data == 0)
&& (CM_Get_Parent(&grandparent_inst, parent_inst, 0) == CR_SUCCESS)
&& (CM_Get_Device_IDA(grandparent_inst, str, MAX_PATH, 0) == CR_SUCCESS) ) {
device_id = str;
method_str = "[GP]";
j = htab_hash(device_id, &htab_devid);
uuprintf(" Matched with (GP) ID[%03d]: %s", j, device_id);
}
if ((uintptr_t)htab_devid.table[j].data > 0) {
uuprintf(" Matched with Hub[%d]: '%s'", (uintptr_t)htab_devid.table[j].data,
dev_if_path.String[(uintptr_t)htab_devid.table[j].data]);
if (GetUSBProperties(dev_if_path.String[(uintptr_t)htab_devid.table[j].data], device_id, &props))
method_str = "";
#ifdef FORCED_DEVICE
props.vid = FORCED_VID;
props.pid = FORCED_PID;
safe_strcpy(buffer, sizeof(buffer), FORCED_NAME);
#endif
}
break;
} }
post_backslash = FALSE;
method_str = "";
// If we're not dealing with the USBSTOR part of our list, then this is an UASP device
props.is_UASP = ((((uintptr_t)device_id)+2) >= ((uintptr_t)devid_list)+list_start[uasp_start]);
// Now get the properties of the device, and its Device ID, which we need to populate the properties
j = htab_hash(device_id, &htab_devid);
uuprintf(" Matched with ID[%03d]: %s", j, device_id);
// Try to parse the current device_id string for VID:PID
// We'll use that if we can't get anything better
for (k = 0, l = 0; (k<strlen(device_id)) && (l<2); k++) {
// The ID is in the form USB_VENDOR_BUSID\VID_xxxx&PID_xxxx\...
if (device_id[k] == '\\')
post_backslash = TRUE;
if (!post_backslash)
continue;
if (device_id[k] == '_') {
props.pid = (uint16_t)strtoul(&device_id[k + 1], NULL, 16);
if (l++ == 0)
props.vid = props.pid;
}
}
if (props.vid != 0)
method_str = "[ID]";
// If the hash didn't match a populated string in dev_if_path[] (htab_devid.table[j].data > 0),
// we might have an extra vendor driver in between (e.g. "ASUS USB 3.0 Boost Storage Driver"
// for UASP devices in ASUS "Turbo Mode" or "Apple Mobile Device USB Driver" for iPods)
// so try to see if we can match the grandparent.
if ( ((uintptr_t)htab_devid.table[j].data == 0)
&& (CM_Get_Parent(&grandparent_inst, parent_inst, 0) == CR_SUCCESS)
&& (CM_Get_Device_IDA(grandparent_inst, str, MAX_PATH, 0) == CR_SUCCESS) ) {
device_id = str;
method_str = "[GP]";
j = htab_hash(device_id, &htab_devid);
uuprintf(" Matched with (GP) ID[%03d]: %s", j, device_id);
}
if ((uintptr_t)htab_devid.table[j].data > 0) {
uuprintf(" Matched with Hub[%d]: '%s'", (uintptr_t)htab_devid.table[j].data,
dev_if_path.String[(uintptr_t)htab_devid.table[j].data]);
if (GetUSBProperties(dev_if_path.String[(uintptr_t)htab_devid.table[j].data], device_id, &props))
method_str = "";
#ifdef FORCED_DEVICE
props.vid = FORCED_VID;
props.pid = FORCED_PID;
safe_strcpy(buffer, sizeof(buffer), FORCED_NAME);
#endif
}
break;
} }
} }
if (props.is_VHD) { if (props.is_VHD) {
uprintf("Found VHD device '%s'", buffer); uprintf("Found VHD device '%s'", buffer);
} else if ((props.is_CARD) && ((!props.is_USB) || ((props.vid == 0) && (props.pid == 0)))) {
uprintf("Found card reader device '%s'", buffer);
} else if ((!props.is_USB) && (props.is_Removable) && (!props.is_UASP)) {
uprintf("Found non-USB removable device '%s'", buffer);
} else { } else {
if ((props.vid == 0) && (props.pid == 0)) { if ((props.vid == 0) && (props.pid == 0)) {
if (is_SCSI) { if (!props.is_USB) {
// If we have an SCSI drive and couldn't get a VID:PID, we are most likely // If we have a non removable SCSI drive and couldn't get a VID:PID,
// dealing with a system drive => eliminate it! // we are most likely dealing with a system drive => eliminate it!
uuprintf(" Non USB => Eliminated"); uuprintf(" Non-USB or non-removable => Eliminated");
continue; continue;
} }
safe_strcpy(str, sizeof(str), "????:????"); // Couldn't figure VID:PID safe_strcpy(str, sizeof(str), "????:????"); // Couldn't figure VID:PID
@ -444,11 +539,36 @@ BOOL GetUSBDevices(DWORD devnum)
} }
if (GetDriveLabel(drive_index, drive_letters, &label)) { if (GetDriveLabel(drive_index, drive_letters, &label)) {
if ((!enable_HDDs) && (!props.is_VHD) && if ((props.is_SCSI) && (!props.is_UASP) && (!props.is_VHD)) {
if (!props.is_Removable) {
// Non removables should have been eliminated above, but since we
// are potentially dealing with system drives, better safe than sorry
safe_closehandle(hDrive);
safe_free(devint_detail_data);
break;
}
if (!list_non_usb_removable_drives) {
// Go over the mounted partitions and find if GetDriveType() says they are
// removable. If they are not removable, don't allow the drive to be listed
for (p = drive_letters; *p; p++) {
drive_name[0] = *p;
if (GetDriveTypeA(drive_name) != DRIVE_REMOVABLE)
break;
}
if (*p) {
uprintf("Device eliminated because it contains a mounted partition that is set as non-removable");
safe_closehandle(hDrive);
safe_free(devint_detail_data);
break;
}
}
}
if ((!enable_HDDs) && (!props.is_VHD) && (!props.is_CARD) &&
((score = IsHDD(drive_index, (uint16_t)props.vid, (uint16_t)props.pid, buffer)) > 0)) { ((score = IsHDD(drive_index, (uint16_t)props.vid, (uint16_t)props.pid, buffer)) > 0)) {
uprintf("Device eliminated because it was detected as an USB Hard Drive (score %d > 0)\n", score); uprintf("Device eliminated because it was detected as a Hard Drive (score %d > 0)", score);
uprintf("If this device is not an USB Hard Drive, please e-mail the author of this application\n"); if (!list_non_usb_removable_drives)
uprintf("NOTE: You can enable the listing of USB Hard Drives in 'Advanced Options' (after clicking the white triangle)"); uprintf("If this device is not a Hard Drive, please e-mail the author of this application");
uprintf("NOTE: You can enable the listing of Hard Drives in 'Advanced Options' (after clicking the white triangle)");
safe_closehandle(hDrive); safe_closehandle(hDrive);
safe_free(devint_detail_data); safe_free(devint_detail_data);
break; break;

View file

@ -1,7 +1,7 @@
/* /*
* Rufus: The Reliable USB Formatting Utility * Rufus: The Reliable USB Formatting Utility
* USB device listing * USB device listing
* Copyright © 2014 Pete Batard <pete@akeo.ie> * Copyright © 2014-2016 Pete Batard <pete@akeo.ie>
* *
* This program is free software: you can redistribute it and/or modify * This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -32,8 +32,12 @@ typedef struct usb_device_props {
uint32_t pid; uint32_t pid;
uint32_t speed; uint32_t speed;
uint32_t port; uint32_t port;
BOOLEAN is_USB;
BOOLEAN is_SCSI;
BOOLEAN is_CARD;
BOOLEAN is_UASP; BOOLEAN is_UASP;
BOOLEAN is_VHD; BOOLEAN is_VHD;
BOOLEAN is_Removable;
BOOLEAN is_LowerSpeed; BOOLEAN is_LowerSpeed;
} usb_device_props; } usb_device_props;
@ -46,12 +50,15 @@ typedef DWORD RETURN_TYPE;
typedef RETURN_TYPE CONFIGRET; typedef RETURN_TYPE CONFIGRET;
typedef CHAR *DEVINSTID_A; typedef CHAR *DEVINSTID_A;
#define CR_SUCCESS 0x00000000 #define CR_SUCCESS 0x00000000
#define CR_NO_SUCH_DEVNODE 0x0000000D #define CR_NO_SUCH_DEVNODE 0x0000000D
#define CM_GETIDLIST_FILTER_SERVICE 0x00000002 #define CM_GETIDLIST_FILTER_SERVICE 0x00000002
#define CM_REMOVAL_POLICY_EXPECT_NO_REMOVAL 0x00000001
#define CM_REMOVAL_POLICY_EXPECT_ORDERLY_REMOVAL 0x00000002
#define CM_REMOVAL_POLICY_EXPECT_SURPRISE_REMOVAL 0x00000003
// /!\ The following flag is only available on Windows 7 or later! // /!\ The following flag is only available on Windows 7 or later!
#define CM_GETIDLIST_FILTER_PRESENT 0x00000100 #define CM_GETIDLIST_FILTER_PRESENT 0x00000100
#define CM_DRP_ADDRESS 0x0000001D #define CM_DRP_ADDRESS 0x0000001D
#ifndef METHOD_BUFFERED #ifndef METHOD_BUFFERED
#define METHOD_BUFFERED 0 #define METHOD_BUFFERED 0