diff --git a/src/.msvc/rufus.vcxproj b/src/.msvc/rufus.vcxproj
index c451b956..ed4d73b1 100644
--- a/src/.msvc/rufus.vcxproj
+++ b/src/.msvc/rufus.vcxproj
@@ -194,6 +194,7 @@
+
@@ -215,6 +216,7 @@
+
diff --git a/src/.msvc/rufus.vcxproj.filters b/src/.msvc/rufus.vcxproj.filters
index e5ced23c..9ed84c82 100644
--- a/src/.msvc/rufus.vcxproj.filters
+++ b/src/.msvc/rufus.vcxproj.filters
@@ -66,6 +66,9 @@
Source Files
+
+ Source Files
+
@@ -122,6 +125,9 @@
Header Files
+
+ Header Files
+
diff --git a/src/.msvc/rufus_sources b/src/.msvc/rufus_sources
index 38385424..b88e38c3 100644
--- a/src/.msvc/rufus_sources
+++ b/src/.msvc/rufus_sources
@@ -45,5 +45,6 @@ SOURCES=rufus.c \
drive.c \
smart.c \
syslinux.c \
+ usb.c \
vhd.c \
rufus.rc
diff --git a/src/Makefile.am b/src/Makefile.am
index 97426851..914dd9ef 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -9,7 +9,7 @@ pkg_v_rc_0 = @echo " RC $@";
%_rc.o: %.rc ../res/localization/embedded.loc
$(pkg_v_rc)$(WINDRES) $(AM_RCFLAGS) -i $< -o $@
-rufus_SOURCES = drive.c icon.c parser.c localization.c iso.c net.c dos.c dos_locale.c badblocks.c syslinux.c vhd.c format.c smart.c stdio.c stdfn.c stdlg.c rufus.c
+rufus_SOURCES = drive.c icon.c parser.c localization.c iso.c net.c dos.c dos_locale.c badblocks.c syslinux.c usb.c vhd.c format.c smart.c stdio.c stdfn.c stdlg.c rufus.c
rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./libcdio $(AM_CFLAGS)
rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows
rufus_LDADD = rufus_rc.o ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \
diff --git a/src/Makefile.in b/src/Makefile.in
index cabe4936..e7dbe8d9 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -47,10 +47,11 @@ am_rufus_OBJECTS = rufus-drive.$(OBJEXT) rufus-icon.$(OBJEXT) \
rufus-parser.$(OBJEXT) rufus-localization.$(OBJEXT) \
rufus-iso.$(OBJEXT) rufus-net.$(OBJEXT) rufus-dos.$(OBJEXT) \
rufus-dos_locale.$(OBJEXT) rufus-badblocks.$(OBJEXT) \
- rufus-syslinux.$(OBJEXT) rufus-vhd.$(OBJEXT) \
- rufus-format.$(OBJEXT) rufus-smart.$(OBJEXT) \
- rufus-stdio.$(OBJEXT) rufus-stdfn.$(OBJEXT) \
- rufus-stdlg.$(OBJEXT) rufus-rufus.$(OBJEXT)
+ rufus-syslinux.$(OBJEXT) rufus-usb.$(OBJEXT) \
+ rufus-vhd.$(OBJEXT) rufus-format.$(OBJEXT) \
+ rufus-smart.$(OBJEXT) rufus-stdio.$(OBJEXT) \
+ rufus-stdfn.$(OBJEXT) rufus-stdlg.$(OBJEXT) \
+ rufus-rufus.$(OBJEXT)
rufus_OBJECTS = $(am_rufus_OBJECTS)
rufus_DEPENDENCIES = rufus_rc.o ms-sys/libmssys.a \
syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \
@@ -186,7 +187,7 @@ SUBDIRS = ms-sys syslinux/libfat syslinux/libinstaller libcdio/iso9660 libcdio/u
pkg_v_rc = $(pkg_v_rc_$(V))
pkg_v_rc_ = $(pkg_v_rc_$(AM_DEFAULT_VERBOSITY))
pkg_v_rc_0 = @echo " RC $@";
-rufus_SOURCES = drive.c icon.c parser.c localization.c iso.c net.c dos.c dos_locale.c badblocks.c syslinux.c vhd.c format.c smart.c stdio.c stdfn.c stdlg.c rufus.c
+rufus_SOURCES = drive.c icon.c parser.c localization.c iso.c net.c dos.c dos_locale.c badblocks.c syslinux.c usb.c vhd.c format.c smart.c stdio.c stdfn.c stdlg.c rufus.c
rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./libcdio $(AM_CFLAGS)
rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows
rufus_LDADD = rufus_rc.o ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \
@@ -327,6 +328,14 @@ rufus-syslinux.obj: syslinux.c
$(AM_V_CC) @AM_BACKSLASH@
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-syslinux.obj `if test -f 'syslinux.c'; then $(CYGPATH_W) 'syslinux.c'; else $(CYGPATH_W) '$(srcdir)/syslinux.c'; fi`
+rufus-usb.o: usb.c
+ $(AM_V_CC) @AM_BACKSLASH@
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-usb.o `test -f 'usb.c' || echo '$(srcdir)/'`usb.c
+
+rufus-usb.obj: usb.c
+ $(AM_V_CC) @AM_BACKSLASH@
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-usb.obj `if test -f 'usb.c'; then $(CYGPATH_W) 'usb.c'; else $(CYGPATH_W) '$(srcdir)/usb.c'; fi`
+
rufus-vhd.o: vhd.c
$(AM_V_CC) @AM_BACKSLASH@
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-vhd.o `test -f 'vhd.c' || echo '$(srcdir)/'`vhd.c
diff --git a/src/localization.c b/src/localization.c
index 44c08024..2cae1dcd 100644
--- a/src/localization.c
+++ b/src/localization.c
@@ -65,6 +65,9 @@ const loc_parse parse_cmd[9] = {
{ 'a', LC_ATTRIBUTES, "s" }, // a "ra"
};
+/* Hash table for reused translation commands */
+static htab_table htab_loc = HTAB_EMPTY;
+
/* Globals */
int loc_line_nr;
struct list_head locale_list = {NULL, NULL};
@@ -85,179 +88,13 @@ static void mtab_destroy(BOOL reinit)
}
}
-/*
- * Hash table functions - modified From glibc 2.3.2:
- * [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986
- * [Knuth] The Art of Computer Programming, part 3 (6.4)
- */
-typedef struct htab_entry {
- uint32_t used;
- char* str;
- loc_cmd* dlg_cmd;
-} htab_entry;
-htab_entry* htab_table = NULL;
-size_t htab_size, htab_filled;
-
-/*
- * For the used double hash method the table size has to be a prime. To
- * correct the user given table size we need a prime test. This trivial
- * algorithm is adequate because the code is called only during init and
- * the number is likely to be small
- */
-static uint32_t isprime(uint32_t number)
-{
- // no even number will be passed
- uint32_t divider = 3;
-
- while((divider * divider < number) && (number % divider != 0))
- divider += 2;
-
- return (number % divider != 0);
-}
-
-/*
- * Before using the hash table we must allocate memory for it.
- * We allocate one element more as the found prime number says.
- * This is done for more effective indexing as explained in the
- * comment for the hash function.
- */
-static BOOL htab_create(uint32_t nel)
-{
- if (htab_table != NULL) {
- return FALSE;
- }
-
- // Change nel to the first prime number not smaller as nel.
- nel |= 1;
- while(!isprime(nel))
- nel += 2;
-
- htab_size = nel;
- htab_filled = 0;
-
- // allocate memory and zero out.
- htab_table = (htab_entry*)calloc(htab_size + 1, sizeof(htab_entry));
- if (htab_table == NULL) {
- uprintf("localization: could not allocate space for hash table\n");
- return FALSE;
- }
-
- return TRUE;
-}
-
-/* After using the hash table it has to be destroyed. */
-static void htab_destroy(void)
-{
- size_t i;
- if (htab_table == NULL) {
- return;
- }
-
- for (i=0; i New entry
-
- // If the table is full return an error
- if (htab_filled >= htab_size) {
- uprintf("localization: hash table is full (%d entries)", htab_size);
- return 0;
- }
-
- safe_free(htab_table[idx].str);
- htab_table[idx].used = hval;
- htab_table[idx].str = (char*) malloc(safe_strlen(str)+1);
- if (htab_table[idx].str == NULL) {
- uprintf("localization: could not duplicate string for hash table\n");
- return 0;
- }
- memcpy(htab_table[idx].str, str, safe_strlen(str)+1);
- ++htab_filled;
-
- return idx;
-}
-
/*
* Add a localization command to a dialog/section
*/
void add_dialog_command(int index, loc_cmd* lcmd)
{
char str[128];
+ loc_cmd* htab_lcmd;
uint32_t i;
if ((lcmd == NULL) || (lcmd->txt[0] == NULL) || (index < 0) || (index >= ARRAYSIZE(loc_dlg))) {
uprintf("localization: invalid parameter for add_dialog_command\n");
@@ -273,13 +110,14 @@ void add_dialog_command(int index, loc_cmd* lcmd)
str[0] = index + 0x30;
str[1] = lcmd->command + 0x30;
safe_strcpy(&str[2], sizeof(str)-2, lcmd->txt[0]);
- i = htab_hash(str);
+ i = htab_hash(str, &htab_loc);
if (i != 0) {
- if (htab_table[i].dlg_cmd != NULL) {
- list_del(&(htab_table[i].dlg_cmd->list));
- free_loc_cmd(htab_table[i].dlg_cmd);
+ htab_lcmd = (loc_cmd*)(htab_loc.table[i].data);
+ if (htab_lcmd != NULL) {
+ list_del(&(htab_lcmd->list));
+ free_loc_cmd(htab_lcmd);
}
- htab_table[i].dlg_cmd = lcmd;
+ htab_loc.table[i].data = (void*)lcmd;
}
list_add(&lcmd->list, &loc_dlg[index].list);
}
@@ -349,7 +187,7 @@ void _init_localization(BOOL reinit) {
list_init(&loc_dlg[i].list);
if (!reinit)
list_init(&locale_list);
- htab_create(LOC_HTAB_SIZE);
+ htab_create(LOC_HTAB_SIZE, &htab_loc);
}
void _exit_localization(BOOL reinit) {
@@ -360,7 +198,7 @@ void _exit_localization(BOOL reinit) {
}
free_dialog_list();
mtab_destroy(reinit);
- htab_destroy();
+ htab_destroy(&htab_loc);
}
/*
diff --git a/src/rufus.c b/src/rufus.c
index 86ff8b5d..e7d624f2 100644
--- a/src/rufus.c
+++ b/src/rufus.c
@@ -28,8 +28,6 @@
#include
#include
#include
-#include
-#include
#include
#include
#include
@@ -128,12 +126,12 @@ int dialog_showing = 0;
uint16_t rufus_version[4], embedded_sl_version[2];
char embedded_sl_version_str[2][12] = { "?.??", "?.??" };
RUFUS_UPDATE update = { {0,0,0,0}, {0,0}, NULL, NULL};
+StrArray DriveID, DriveLabel;
extern char szStatusMessage[256];
static HANDLE format_thid = NULL;
static HWND hProgress = NULL, hBoot = NULL, hSelectISO = NULL;
static HICON hIconDisc, hIconDown, hIconUp, hIconLang;
-static StrArray DriveID, DriveLabel;
static char szTimer[12] = "00:00:00";
static unsigned int timer;
static int64_t last_iso_blocking_status;
@@ -609,267 +607,6 @@ static BOOL PopulateProperties(int ComboIndex)
return TRUE;
}
-/*
- * Refresh the list of USB devices
- */
-static BOOL GetUSBDevices(DWORD devnum)
-{
- // The first two are standard Microsoft drivers (including the Windows 8 UASP one).
- // The rest are the vendor UASP drivers I know of so far - list may be incomplete!
- const char* storage_name[] = { "USBSTOR", "UASPSTOR", "VUSBSTOR", "ETRONSTOR" };
- const char* scsi_name = "SCSI";
- const char* vhd_name = "Virtual Disk";
- char letter_name[] = " (?:)";
- BOOL found = FALSE, is_SCSI, is_UASP, is_VHD;
- HDEVINFO dev_info = NULL;
- SP_DEVINFO_DATA dev_info_data;
- SP_DEVICE_INTERFACE_DATA devint_data;
- PSP_DEVICE_INTERFACE_DETAIL_DATA_A devint_detail_data;
- DEVINST parent_inst, device_inst;
- DWORD size, i, j, k, datatype, drive_index;
- ULONG list_size[ARRAYSIZE(storage_name)], full_list_size;
- HANDLE hDrive;
- LONG maxwidth = 0;
- RECT rect;
- int s, score, drive_number;
- char drive_letters[27], *devid, *devid_list = NULL, entry_msg[128];
- char *label, *entry, buffer[MAX_PATH], str[sizeof("0000:0000")+1];
- uint16_t vid, pid;
- GUID _GUID_DEVINTERFACE_DISK = // only known to some...
- { 0x53f56307L, 0xb6bf, 0x11d0, {0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} };
-
- IGNORE_RETVAL(ComboBox_ResetContent(hDeviceList));
- StrArrayClear(&DriveID);
- StrArrayClear(&DriveLabel);
- GetClientRect(hDeviceList, &rect);
-
- dev_info = SetupDiGetClassDevsA(&_GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
- if (dev_info == INVALID_HANDLE_VALUE) {
- uprintf("SetupDiGetClassDevs (Interface) failed: %s\n", WindowsErrorString());
- return FALSE;
- }
-
- full_list_size = 0;
- for (s=0; s 1) {
- CM_Get_Device_ID_ListA(storage_name[s], &devid_list[i], list_size[s], CM_GETIDLIST_FILTER_SERVICE);
- // list_size is sometimes larger than required thus we need to find the real end
- for (i += list_size[s]; i > 2; i--) {
- if ((devid_list[i-2] != '\0') && (devid_list[i-1] == '\0') && (devid_list[i] == '\0'))
- break;
- }
- }
- }
-
- dev_info_data.cbSize = sizeof(dev_info_data);
- for (i=0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
- memset(buffer, 0, sizeof(buffer));
- if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ENUMERATOR_NAME,
- &datatype, (LPBYTE)buffer, sizeof(buffer), &size)) {
- uprintf("SetupDiGetDeviceRegistryProperty (Enumerator Name) failed: %s\n", WindowsErrorString());
- continue;
- }
- // UASP drives are listed under SCSI (along with regular SYSTEM drives => "DANGER, WILL ROBINSON!!!")
- is_SCSI = (safe_stricmp(buffer, scsi_name) == 0);
- if ((safe_stricmp(buffer, storage_name[0]) != 0) && (!is_SCSI))
- continue;
- memset(buffer, 0, sizeof(buffer));
- vid = 0; pid = 0;
- is_UASP = FALSE, is_VHD = FALSE;
- if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_FRIENDLYNAME,
- &datatype, (LPBYTE)buffer, sizeof(buffer), &size)) {
- uprintf("SetupDiGetDeviceRegistryProperty (Friendly Name) failed: %s\n", WindowsErrorString());
- // We can afford a failure on this call - just replace the name with "USB Storage Device (Generic)"
- safe_strcpy(buffer, sizeof(buffer), lmprintf(MSG_045));
- } else if (safe_strstr(buffer, vhd_name) != NULL) {
- is_VHD = TRUE;
- } else {
- // Get the VID:PID 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...
- for (devid = devid_list; *devid; devid += strlen(devid) + 1) {
- if ( (CM_Locate_DevNodeA(&parent_inst, devid, 0) == 0)
- && (CM_Get_Child(&device_inst, parent_inst, 0) == 0)
- && (device_inst == dev_info_data.DevInst) ) {
- BOOL post_backslash = FALSE;
- // If we're not dealing with the USBSTOR part of our list, then this is an UASP device
- is_UASP = ((((uintptr_t)devid)+2) >= ((uintptr_t)devid_list)+list_size[0]);
- for (j=0, k=0; (j eliminate it!
- continue;
- }
- safe_strcpy(str, sizeof(str), "????:????"); // Couldn't figure VID:PID
- } else {
- safe_sprintf(str, sizeof(str), "%04X:%04X", vid, pid);
- }
- uprintf("Found %s device '%s' (%s)\n", is_UASP?"UAS":"USB", buffer, str);
- }
- devint_data.cbSize = sizeof(devint_data);
- hDrive = INVALID_HANDLE_VALUE;
- devint_detail_data = NULL;
- for (j=0; ;j++) {
- safe_closehandle(hDrive);
- safe_free(devint_detail_data);
-
- if (!SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data, &_GUID_DEVINTERFACE_DISK, j, &devint_data)) {
- if(GetLastError() != ERROR_NO_MORE_ITEMS) {
- uprintf("SetupDiEnumDeviceInterfaces failed: %s\n", WindowsErrorString());
- } else {
- uprintf("A device was eliminated because it didn't report itself as a disk\n");
- }
- break;
- }
-
- if (!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, NULL, 0, &size, NULL)) {
- if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
- devint_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)calloc(1, size);
- if (devint_detail_data == NULL) {
- uprintf("Unable to allocate data for SP_DEVICE_INTERFACE_DETAIL_DATA\n");
- continue;
- }
- devint_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
- } else {
- uprintf("SetupDiGetDeviceInterfaceDetail (dummy) failed: %s\n", WindowsErrorString());
- continue;
- }
- }
- if (devint_detail_data == NULL) {
- uprintf("SetupDiGetDeviceInterfaceDetail (dummy) - no data was allocated\n");
- continue;
- }
- if(!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, devint_detail_data, size, &size, NULL)) {
- uprintf("SetupDiGetDeviceInterfaceDetail (actual) failed: %s\n", WindowsErrorString());
- continue;
- }
-
- hDrive = CreateFileA(devint_detail_data->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
- if(hDrive == INVALID_HANDLE_VALUE) {
- uprintf("Could not open '%s': %s\n", devint_detail_data->DevicePath, WindowsErrorString());
- continue;
- }
-
- drive_number = GetDriveNumber(hDrive, devint_detail_data->DevicePath);
- if (drive_number < 0)
- continue;
-
- drive_index = drive_number + DRIVE_INDEX_MIN;
- if (!IsMediaPresent(drive_index)) {
- uprintf("Device eliminated because it appears to contain no media\n");
- safe_closehandle(hDrive);
- safe_free(devint_detail_data);
- break;
- }
-
- if (GetDriveLabel(drive_index, drive_letters, &label)) {
- if ((!enable_HDDs) && (!is_VHD) && ((score = IsHDD(drive_index, vid, pid, buffer)) > 0)) {
- uprintf("Device eliminated because it was detected as an USB Hard Drive (score %d > 0)\n", score);
- uprintf("If this device is not an USB Hard Drive, please e-mail the author of this application\n");
- uprintf("NOTE: You can enable the listing of USB Hard Drives in 'Advanced Options' (after clicking the white triangle)");
- safe_closehandle(hDrive);
- safe_free(devint_detail_data);
- break;
- }
-
- // The empty string is returned for drives that don't have any volumes assigned
- if (drive_letters[0] == 0) {
- entry = lmprintf(MSG_046, label, drive_number,
- SizeToHumanReadable(GetDriveSize(drive_index), FALSE, use_fake_units));
- } else {
- // We have multiple volumes assigned to the same device (multiple partitions)
- // If that is the case, use "Multiple Volumes" instead of the label
- safe_strcpy(entry_msg, sizeof(entry_msg), ((drive_letters[0] != 0) && (drive_letters[1] != 0))?
- lmprintf(MSG_047):label);
- for (k=0; drive_letters[k]; k++) {
- // Append all the drive letters we detected
- letter_name[2] = drive_letters[k];
- if (right_to_left_mode)
- safe_strcat(entry_msg, sizeof(entry_msg), RIGHT_TO_LEFT_MARK);
- safe_strcat(entry_msg, sizeof(entry_msg), letter_name);
- if (drive_letters[k] == app_dir[0]) break;
- }
- // Repeat as we need to break the outside loop
- if (drive_letters[k] == app_dir[0]) {
- uprintf("Removing %c: from the list: This is the disk from which " APPLICATION_NAME " is running!\n", app_dir[0]);
- safe_closehandle(hDrive);
- safe_free(devint_detail_data);
- break;
- }
- safe_sprintf(&entry_msg[strlen(entry_msg)], sizeof(entry_msg) - strlen(entry_msg),
- "%s [%s]", (right_to_left_mode)?RIGHT_TO_LEFT_MARK:"", SizeToHumanReadable(GetDriveSize(drive_index), FALSE, use_fake_units));
- entry = entry_msg;
- }
-
- // Must ensure that the combo box is UNSORTED for indexes to be the same
- StrArrayAdd(&DriveID, buffer);
- StrArrayAdd(&DriveLabel, label);
-
- IGNORE_RETVAL(ComboBox_SetItemData(hDeviceList, ComboBox_AddStringU(hDeviceList, entry), drive_index));
- maxwidth = max(maxwidth, GetEntryWidth(hDeviceList, entry));
- safe_closehandle(hDrive);
- safe_free(devint_detail_data);
- break;
- }
- }
- }
- SetupDiDestroyDeviceInfoList(dev_info);
-
- // Adjust the Dropdown width to the maximum text size
- SendMessage(hDeviceList, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
-
- if (devnum >= DRIVE_INDEX_MIN) {
- for (i=0; itable != NULL) {
+ uprintf("warning: htab_create() was called with a non empty table");
+ return FALSE;
+ }
+
+ // Change nel to the first prime number not smaller as nel.
+ nel |= 1;
+ while(!isprime(nel))
+ nel += 2;
+
+ htab->size = nel;
+ htab->filled = 0;
+
+ // allocate memory and zero out.
+ htab->table = (htab_entry*)calloc(htab->size + 1, sizeof(htab_entry));
+ if (htab->table == NULL) {
+ uprintf("could not allocate space for hash table\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* After using the hash table it has to be destroyed. */
+void htab_destroy(htab_table* htab)
+{
+ size_t i;
+
+ if ((htab == NULL) || (htab->table == NULL)) {
+ return;
+ }
+
+ for (i=0; isize+1; i++) {
+ if (htab->table[i].used) {
+ safe_free(htab->table[i].str);
+ }
+ }
+ htab->filled = 0; htab->size = 0;
+ safe_free(htab->table);
+ htab->table = NULL;
+}
+
+/*
+ * This is the search function. It uses double hashing with open addressing.
+ * We use a trick to speed up the lookup. The table is created with one
+ * more element available. This enables us to use the index zero special.
+ * This index will never be used because we store the first hash index in
+ * the field used where zero means not used. Every other value means used.
+ * The used field can be used as a first fast comparison for equality of
+ * the stored and the parameter value. This helps to prevent unnecessary
+ * expensive calls of strcmp.
+ */
+uint32_t htab_hash(char* str, htab_table* htab)
+{
+ uint32_t hval, hval2;
+ uint32_t idx;
+ uint32_t r = 0;
+ int c;
+ char* sz = str;
+
+ if ((htab == NULL) || (htab->table == NULL) || (str == NULL)) {
+ return 0;
+ }
+
+ // Compute main hash value using sdbm's algorithm (empirically
+ // shown to produce half the collisions as djb2's).
+ // See http://www.cse.yorku.ca/~oz/hash.html
+ while ((c = *sz++) != 0)
+ r = c + (r << 6) + (r << 16) - r;
+ if (r == 0)
+ ++r;
+
+ // compute table hash: simply take the modulus
+ hval = r % htab->size;
+ if (hval == 0)
+ ++hval;
+
+ // Try the first index
+ idx = hval;
+
+ if (htab->table[idx].used) {
+ if ( (htab->table[idx].used == hval)
+ && (safe_strcmp(str, htab->table[idx].str) == 0) ) {
+ // existing hash
+ return idx;
+ }
+ // uprintf("hash collision ('%s' vs '%s')\n", str, htab_table[idx].str);
+
+ // Second hash function, as suggested in [Knuth]
+ hval2 = 1 + hval % (htab->size - 2);
+
+ do {
+ // Because size is prime this guarantees to step through all available indexes
+ if (idx <= hval2) {
+ idx = ((uint32_t)htab->size) + idx - hval2;
+ } else {
+ idx -= hval2;
+ }
+
+ // If we visited all entries leave the loop unsuccessfully
+ if (idx == hval) {
+ break;
+ }
+
+ // If entry is found use it.
+ if ( (htab->table[idx].used == hval)
+ && (safe_strcmp(str, htab->table[idx].str) == 0) ) {
+ return idx;
+ }
+ }
+ while (htab->table[idx].used);
+ }
+
+ // Not found => New entry
+
+ // If the table is full return an error
+ if (htab->filled >= htab->size) {
+ uprintf("hash table is full (%d entries)", htab->size);
+ return 0;
+ }
+
+ safe_free(htab->table[idx].str);
+ htab->table[idx].used = hval;
+ htab->table[idx].str = (char*) malloc(safe_strlen(str)+1);
+ if (htab->table[idx].str == NULL) {
+ uprintf("could not duplicate string for hash table\n");
+ return 0;
+ }
+ memcpy(htab->table[idx].str, str, safe_strlen(str)+1);
+ ++htab->filled;
+
+ return idx;
+}
+
BOOL is_x64(void)
{
BOOL ret = FALSE;
@@ -151,7 +319,7 @@ void GetWindowsVersion(void)
/*
* String array manipulation
*/
-void StrArrayCreate(StrArray* arr, size_t initial_size)
+void StrArrayCreate(StrArray* arr, uint32_t initial_size)
{
if (arr == NULL) return;
arr->Max = initial_size; arr->Index = 0;
@@ -160,11 +328,11 @@ void StrArrayCreate(StrArray* arr, size_t initial_size)
uprintf("Could not allocate string array\n");
}
-void StrArrayAdd(StrArray* arr, const char* str)
+int32_t StrArrayAdd(StrArray* arr, const char* str)
{
char** old_table;
if ((arr == NULL) || (arr->String == NULL))
- return;
+ return -1;
if (arr->Index == arr->Max) {
arr->Max *= 2;
old_table = arr->String;
@@ -172,13 +340,15 @@ void StrArrayAdd(StrArray* arr, const char* str)
if (arr->String == NULL) {
free(old_table);
uprintf("Could not reallocate string array\n");
- return;
+ return -1;
}
}
arr->String[arr->Index] = safe_strdup(str);
- if (arr->String[arr->Index++] == NULL) {
+ if (arr->String[arr->Index] == NULL) {
uprintf("Could not store string in array\n");
+ return -1;
}
+ return arr->Index++;
}
void StrArrayClear(StrArray* arr)
diff --git a/src/stdio.c b/src/stdio.c
index f987a6e8..7dcbed9d 100644
--- a/src/stdio.c
+++ b/src/stdio.c
@@ -164,14 +164,13 @@ char* SizeToHumanReadable(uint64_t size, BOOL log, BOOL fake_units)
{
int suffix;
static char str_size[32];
- char dir[4];
+ const char* dir = ((right_to_left_mode)&&(!log))?RIGHT_TO_LEFT_MARK:"";
double hr_size = (double)size;
double t;
uint16_t i_size;
char **_msg_table = log?default_msg_table:msg_table;
const double divider = fake_units?1000.0:1024.0;
- static_sprintf(dir, right_to_left_mode?RIGHT_TO_LEFT_MARK:"");
for (suffix=0; suffix
+ *
+ * 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+/* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */
+#ifdef _CRTDBG_MAP_ALLOC
+#include
+#include
+#endif
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "msapi_utf8.h"
+#include "rufus.h"
+#include "drive.h"
+#include "resource.h"
+#include "localization.h"
+#include "usb.h"
+
+extern StrArray DriveID, DriveLabel;
+extern BOOL enable_HDDs, use_fake_units;
+
+/*
+ * Get the VID, PID and current device speed
+ */
+static void GetUSBProperties(char* parent_path, char* device_id, usb_device_props* props)
+{
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ DWORD size;
+ USB_NODE_CONNECTION_INFORMATION_EX conn_info;
+ USB_NODE_CONNECTION_INFORMATION_EX_V2 conn_info_v2;
+
+ if ((parent_path == NULL) || (device_id == NULL) || (props == NULL) || (props->port == 0)) {
+ return;
+ }
+
+ handle = CreateFileA(parent_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
+ if (handle == INVALID_HANDLE_VALUE) {
+ uprintf("could not open hub %s: %s", parent_path, WindowsErrorString());
+ goto out;
+ }
+ memset(&conn_info, 0, sizeof(conn_info));
+ size = sizeof(conn_info);
+ conn_info.ConnectionIndex = (ULONG)props->port;
+ // coverity[tainted_data_argument]
+ if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, &conn_info, size, &conn_info, size, &size, NULL)) {
+ uprintf("could not get node connection information for device '%s': %s", device_id, WindowsErrorString());
+ goto out;
+ }
+
+ props->vid = conn_info.DeviceDescriptor.idVendor;
+ props->pid = conn_info.DeviceDescriptor.idProduct;
+ props->speed = conn_info.Speed + 1;
+
+ // In their great wisdom, Microsoft decided to BREAK the USB speed report between Windows 7 and Windows 8
+ if (nWindowsVersion >= WINDOWS_8) {
+ memset(&conn_info_v2, 0, sizeof(conn_info_v2));
+ size = sizeof(conn_info_v2);
+ conn_info_v2.ConnectionIndex = (ULONG)props->port;
+ conn_info_v2.Length = size;
+ conn_info_v2.SupportedUsbProtocols.Usb300 = 1;
+ if (!DeviceIoControl(handle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, &conn_info_v2, size, &conn_info_v2, size, &size, NULL)) {
+ uprintf("could not get node connection information (V2) for device '%s': %s", device_id, WindowsErrorString());
+ } else if (conn_info_v2.Flags.DeviceIsOperatingAtSuperSpeedOrHigher) {
+ props->speed = USB_SPEED_SUPER_OR_LATER;
+ }
+ }
+
+out:
+ safe_closehandle(handle);
+}
+
+/*
+ * Refresh the list of USB devices
+ */
+BOOL GetUSBDevices(DWORD devnum)
+{
+ // The first two are standard Microsoft drivers (including the Windows 8 UASP one).
+ // The rest are the vendor UASP drivers I know of so far - list may be incomplete!
+ const char* storage_name[] = { "USBSTOR", "UASPSTOR", "VUSBSTOR", "ETRONSTOR" };
+ const char* scsi_name = "SCSI";
+ const char* vhd_name = "Virtual Disk";
+ const char* usb_speed_name[USB_SPEED_MAX] = { "", " 1.0", " 1.1", " 2.0", " 3.0" };
+ // 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;
+ StrArray dev_if_path;
+ char letter_name[] = " (?:)";
+ BOOL found = FALSE, is_SCSI;
+ HDEVINFO dev_info = NULL;
+ SP_DEVINFO_DATA dev_info_data;
+ SP_DEVICE_INTERFACE_DATA devint_data;
+ PSP_DEVICE_INTERFACE_DETAIL_DATA_A devint_detail_data;
+ DEVINST parent_inst, device_inst;
+ DWORD size, i, j, k, datatype, drive_index, port;
+ ULONG list_size[ARRAYSIZE(storage_name)], full_list_size;
+ HANDLE hDrive;
+ LONG maxwidth = 0;
+ RECT rect;
+ int s, score, drive_number;
+ char drive_letters[27], *devid, *devid_list = NULL, entry_msg[128];
+ char *label, *entry, device_id[MAX_PATH], buffer[MAX_PATH], str[128];
+ usb_device_props props;
+ PF_INIT(CM_Get_DevNode_Registry_PropertyA, Cfgmgr32);
+
+ IGNORE_RETVAL(ComboBox_ResetContent(hDeviceList));
+ StrArrayClear(&DriveID);
+ StrArrayClear(&DriveLabel);
+ StrArrayCreate(&dev_if_path, 128);
+ GetClientRect(hDeviceList, &rect);
+
+ // Build a hash table associating a CM Device ID of an USB device with the SetupDI Device Interface Path
+ // of its parent hub - this is needed to retrieve the device speed
+ dev_info = SetupDiGetClassDevsA(&_GUID_DEVINTERFACE_USB_HUB, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
+ if (dev_info != INVALID_HANDLE_VALUE) {
+ if (htab_create(257, &htab_devid)) {
+ dev_info_data.cbSize = sizeof(dev_info_data);
+ for (i=0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
+
+ devint_detail_data = NULL;
+ devint_data.cbSize = sizeof(devint_data);
+ // Only care about the first interface (MemberIndex 0)
+ if ( (SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data, &_GUID_DEVINTERFACE_USB_HUB, 0, &devint_data))
+ && (!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, NULL, 0, &size, NULL))
+ && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ && ((devint_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)calloc(1, size)) != NULL) ) {
+ devint_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
+ if (SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, devint_detail_data, size, &size, NULL)) {
+
+ // Find the Device ID for all the children of this hub
+ if (CM_Get_Child(&device_inst, dev_info_data.DevInst, 0) == CR_SUCCESS) {
+ device_id[0] = 0;
+ s = StrArrayAdd(&dev_if_path, devint_detail_data->DevicePath);
+ if ((s>= 0) && (CM_Get_Device_IDA(device_inst, device_id, sizeof(device_id), 0) == CR_SUCCESS)) {
+ // Lookup port in case SPDRP_ADDRESS doesn't work (which is the case of UASP)
+ port = 0;
+ size = sizeof(port);
+ if (pfCM_Get_DevNode_Registry_PropertyA != NULL)
+ pfCM_Get_DevNode_Registry_PropertyA(device_inst, CM_DRP_ADDRESS, NULL, (PVOID)&port, &size, 0);
+ if ((k = htab_hash(device_id, &htab_devid)) != 0) {
+ htab_devid.table[k].data = (void*)(uintptr_t)((port<<16)|s);
+ }
+ while (CM_Get_Sibling(&device_inst, device_inst, 0) == CR_SUCCESS) {
+ port = 0; size = sizeof(port);
+ if (pfCM_Get_DevNode_Registry_PropertyA != NULL)
+ pfCM_Get_DevNode_Registry_PropertyA(device_inst, CM_DRP_ADDRESS, NULL, (PVOID)&port, &size, 0);
+ device_id[0] = 0;
+ if (CM_Get_Device_IDA(device_inst, device_id, sizeof(device_id), 0) == CR_SUCCESS) {
+ if ((k = htab_hash(device_id, &htab_devid)) != 0) {
+ // store both string index and fallback port in data
+ htab_devid.table[k].data = (void*)(uintptr_t)((port<<16)|s);
+ }
+ }
+ }
+ }
+ }
+ }
+ free(devint_detail_data);
+ }
+ }
+ }
+ SetupDiDestroyDeviceInfoList(dev_info);
+ }
+
+ dev_info = SetupDiGetClassDevsA(&_GUID_DEVINTERFACE_DISK, NULL, NULL, DIGCF_PRESENT|DIGCF_DEVICEINTERFACE);
+ if (dev_info == INVALID_HANDLE_VALUE) {
+ uprintf("SetupDiGetClassDevs (Interface) failed: %s\n", WindowsErrorString());
+ return FALSE;
+ }
+
+ full_list_size = 0;
+ for (s=0; s 1) {
+ CM_Get_Device_ID_ListA(storage_name[s], &devid_list[i], list_size[s], CM_GETIDLIST_FILTER_SERVICE);
+ // list_size is sometimes larger than required thus we need to find the real end
+ for (i += list_size[s]; i > 2; i--) {
+ if ((devid_list[i-2] != '\0') && (devid_list[i-1] == '\0') && (devid_list[i] == '\0'))
+ break;
+ }
+ }
+ }
+
+ dev_info_data.cbSize = sizeof(dev_info_data);
+ for (i=0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
+ memset(buffer, 0, sizeof(buffer));
+ if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_ENUMERATOR_NAME,
+ &datatype, (LPBYTE)buffer, sizeof(buffer), &size)) {
+ uprintf("SetupDiGetDeviceRegistryProperty (Enumerator Name) failed: %s\n", WindowsErrorString());
+ continue;
+ }
+ // UASP drives are listed under SCSI (along with regular SYSTEM drives => "DANGER, WILL ROBINSON!!!")
+ is_SCSI = (safe_stricmp(buffer, scsi_name) == 0);
+ if ((safe_stricmp(buffer, storage_name[0]) != 0) && (!is_SCSI))
+ continue;
+ memset(buffer, 0, sizeof(buffer));
+ memset(&props, 0, sizeof(props));
+ if (!SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data, SPDRP_FRIENDLYNAME,
+ &datatype, (LPBYTE)buffer, sizeof(buffer), &size)) {
+ uprintf("SetupDiGetDeviceRegistryProperty (Friendly Name) failed: %s\n", WindowsErrorString());
+ // We can afford a failure on this call - just replace the name with "USB Storage Device (Generic)"
+ safe_strcpy(buffer, sizeof(buffer), lmprintf(MSG_045));
+ } else if (safe_strstr(buffer, vhd_name) != NULL) {
+ props.is_VHD = TRUE;
+ } else {
+ // Get the VID:PID 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...
+ for (devid = devid_list; *devid; devid += strlen(devid) + 1) {
+ if ( (CM_Locate_DevNodeA(&parent_inst, devid, 0) == CR_SUCCESS)
+ && (CM_Get_Child(&device_inst, parent_inst, 0) == CR_SUCCESS)
+ && (device_inst == dev_info_data.DevInst) ) {
+ BOOL post_backslash = FALSE;
+
+ // If we're not dealing with the USBSTOR part of our list, then this is an UASP device
+ props.is_UASP = ((((uintptr_t)devid)+2) >= ((uintptr_t)devid_list)+list_size[0]);
+
+ // Now get the port number of the device, and its Device ID, which we need to populate the properties
+ if ( (htab_devid.table != NULL) && (SetupDiGetDeviceRegistryPropertyA(dev_info, &dev_info_data,
+ SPDRP_ADDRESS, &datatype, (BYTE*)&props.port, sizeof(props.port), &size)) &&
+ (CM_Get_Device_IDA(parent_inst, device_id, sizeof(device_id), 0) == CR_SUCCESS) ) {
+ j = htab_hash(device_id, &htab_devid);
+ if (props.port == 0) // UAS devices will return port 0 from SPDRP_ADDRESS
+ props.port = ((uint32_t)htab_devid.table[j].data)>>16;
+ if (j > 0) {
+ GetUSBProperties(dev_if_path.String[((uint32_t)htab_devid.table[j].data)&0xFFFF], device_id, &props);
+ }
+ }
+
+ // If the previous calls didn't succeed in getting the VID:PID, try from the device_id
+ // This will be the case for UASP devices for instance
+ if ((props.vid == 0) && (props.pid == 0)) {
+ for (j=0, k=0; (j eliminate it!
+ continue;
+ }
+ safe_strcpy(str, sizeof(str), "????:????"); // Couldn't figure VID:PID
+ } else {
+ static_sprintf(str, "%04X:%04X", props.vid, props.pid);
+ }
+ if (props.speed >= USB_SPEED_MAX)
+ props.speed = 0;
+ uprintf("Found %s%s device '%s' (%s)\n", props.is_UASP?"UAS":"USB", usb_speed_name[props.speed], buffer, str);
+ }
+ devint_data.cbSize = sizeof(devint_data);
+ hDrive = INVALID_HANDLE_VALUE;
+ devint_detail_data = NULL;
+ for (j=0; ;j++) {
+ safe_closehandle(hDrive);
+ safe_free(devint_detail_data);
+
+ if (!SetupDiEnumDeviceInterfaces(dev_info, &dev_info_data, &_GUID_DEVINTERFACE_DISK, j, &devint_data)) {
+ if(GetLastError() != ERROR_NO_MORE_ITEMS) {
+ uprintf("SetupDiEnumDeviceInterfaces failed: %s\n", WindowsErrorString());
+ } else {
+ uprintf("A device was eliminated because it didn't report itself as a disk\n");
+ }
+ break;
+ }
+
+ if (!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, NULL, 0, &size, NULL)) {
+ if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+ devint_detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA_A)calloc(1, size);
+ if (devint_detail_data == NULL) {
+ uprintf("Unable to allocate data for SP_DEVICE_INTERFACE_DETAIL_DATA\n");
+ continue;
+ }
+ devint_detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA_A);
+ } else {
+ uprintf("SetupDiGetDeviceInterfaceDetail (dummy) failed: %s\n", WindowsErrorString());
+ continue;
+ }
+ }
+ if (devint_detail_data == NULL) {
+ uprintf("SetupDiGetDeviceInterfaceDetail (dummy) - no data was allocated\n");
+ continue;
+ }
+ if(!SetupDiGetDeviceInterfaceDetailA(dev_info, &devint_data, devint_detail_data, size, &size, NULL)) {
+ uprintf("SetupDiGetDeviceInterfaceDetail (actual) failed: %s\n", WindowsErrorString());
+ continue;
+ }
+
+ hDrive = CreateFileA(devint_detail_data->DevicePath, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ if(hDrive == INVALID_HANDLE_VALUE) {
+ uprintf("Could not open '%s': %s\n", devint_detail_data->DevicePath, WindowsErrorString());
+ continue;
+ }
+
+ drive_number = GetDriveNumber(hDrive, devint_detail_data->DevicePath);
+ if (drive_number < 0)
+ continue;
+
+ drive_index = drive_number + DRIVE_INDEX_MIN;
+ if (!IsMediaPresent(drive_index)) {
+ uprintf("Device eliminated because it appears to contain no media\n");
+ safe_closehandle(hDrive);
+ safe_free(devint_detail_data);
+ break;
+ }
+
+ if (GetDriveLabel(drive_index, drive_letters, &label)) {
+ if ((!enable_HDDs) && (!props.is_VHD) &&
+ ((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("If this device is not an USB Hard Drive, please e-mail the author of this application\n");
+ uprintf("NOTE: You can enable the listing of USB Hard Drives in 'Advanced Options' (after clicking the white triangle)");
+ safe_closehandle(hDrive);
+ safe_free(devint_detail_data);
+ break;
+ }
+
+ // The empty string is returned for drives that don't have any volumes assigned
+ if (drive_letters[0] == 0) {
+ entry = lmprintf(MSG_046, label, drive_number,
+ SizeToHumanReadable(GetDriveSize(drive_index), FALSE, use_fake_units));
+ } else {
+ // We have multiple volumes assigned to the same device (multiple partitions)
+ // If that is the case, use "Multiple Volumes" instead of the label
+ safe_strcpy(entry_msg, sizeof(entry_msg), ((drive_letters[0] != 0) && (drive_letters[1] != 0))?
+ lmprintf(MSG_047):label);
+ for (k=0; drive_letters[k]; k++) {
+ // Append all the drive letters we detected
+ letter_name[2] = drive_letters[k];
+ if (right_to_left_mode)
+ safe_strcat(entry_msg, sizeof(entry_msg), RIGHT_TO_LEFT_MARK);
+ safe_strcat(entry_msg, sizeof(entry_msg), letter_name);
+ if (drive_letters[k] == app_dir[0]) break;
+ }
+ // Repeat as we need to break the outside loop
+ if (drive_letters[k] == app_dir[0]) {
+ uprintf("Removing %c: from the list: This is the disk from which " APPLICATION_NAME " is running!\n", app_dir[0]);
+ safe_closehandle(hDrive);
+ safe_free(devint_detail_data);
+ break;
+ }
+ safe_sprintf(&entry_msg[strlen(entry_msg)], sizeof(entry_msg) - strlen(entry_msg),
+ "%s [%s]", (right_to_left_mode)?RIGHT_TO_LEFT_MARK:"", SizeToHumanReadable(GetDriveSize(drive_index), FALSE, use_fake_units));
+ entry = entry_msg;
+ }
+
+ // Must ensure that the combo box is UNSORTED for indexes to be the same
+ StrArrayAdd(&DriveID, buffer);
+ StrArrayAdd(&DriveLabel, label);
+
+ IGNORE_RETVAL(ComboBox_SetItemData(hDeviceList, ComboBox_AddStringU(hDeviceList, entry), drive_index));
+ maxwidth = max(maxwidth, GetEntryWidth(hDeviceList, entry));
+ safe_closehandle(hDrive);
+ safe_free(devint_detail_data);
+ break;
+ }
+ }
+ }
+ SetupDiDestroyDeviceInfoList(dev_info);
+
+ // Adjust the Dropdown width to the maximum text size
+ SendMessage(hDeviceList, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0);
+
+ if (devnum >= DRIVE_INDEX_MIN) {
+ for (i=0; i
+ *
+ * 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+
+#define USB_SPEED_UNKNOWN 0
+#define USB_SPEED_LOW 1
+#define USB_SPEED_FULL 2
+#define USB_SPEED_HIGH 3
+#define USB_SPEED_SUPER_OR_LATER 4
+#define USB_SPEED_MAX 5
+
+/* List of the properties we are interested in */
+typedef struct usb_device_props {
+ uint32_t vid;
+ uint32_t pid;
+ uint32_t speed;
+ uint32_t port;
+ BOOL is_UASP;
+ BOOL is_VHD;
+} usb_device_props;
+
+/*
+ * Windows DDK API definitions. Most of it copied from MinGW's includes
+ */
+typedef DWORD DEVNODE, DEVINST;
+typedef DEVNODE *PDEVNODE, *PDEVINST;
+typedef DWORD RETURN_TYPE;
+typedef RETURN_TYPE CONFIGRET;
+typedef CHAR *DEVINSTID_A;
+
+#define CR_SUCCESS 0x00000000
+#define CR_NO_SUCH_DEVNODE 0x0000000D
+#define CM_GETIDLIST_FILTER_SERVICE 2
+#define CM_DRP_ADDRESS 0x0000001D
+
+#ifndef METHOD_BUFFERED
+#define METHOD_BUFFERED 0
+#endif
+#ifndef FILE_ANY_ACCESS
+#define FILE_ANY_ACCESS 0x00000000
+#endif
+#ifndef FILE_DEVICE_UNKNOWN
+#define FILE_DEVICE_UNKNOWN 0x00000022
+#endif
+#ifndef FILE_DEVICE_USB
+#define FILE_DEVICE_USB FILE_DEVICE_UNKNOWN
+#endif
+
+#ifndef CTL_CODE
+#define CTL_CODE(DeviceType, Function, Method, Access)( \
+ ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method))
+#endif
+
+typedef enum USB_CONNECTION_STATUS {
+ NoDeviceConnected,
+ DeviceConnected,
+ DeviceFailedEnumeration,
+ DeviceGeneralFailure,
+ DeviceCausedOvercurrent,
+ DeviceNotEnoughPower,
+ DeviceNotEnoughBandwidth,
+ DeviceHubNestedTooDeeply,
+ DeviceInLegacyHub
+} USB_CONNECTION_STATUS, *PUSB_CONNECTION_STATUS;
+
+typedef enum USB_HUB_NODE {
+ UsbHub,
+ UsbMIParent
+} USB_HUB_NODE;
+
+/* Cfgmgr32.dll interface */
+DECLSPEC_IMPORT CONFIGRET WINAPI CM_Get_Device_IDA(DEVINST dnDevInst, PCSTR Buffer, ULONG BufferLen, ULONG ulFlags);
+DECLSPEC_IMPORT CONFIGRET WINAPI CM_Get_Device_ID_List_SizeA(PULONG pulLen, PCSTR pszFilter, ULONG ulFlags);
+DECLSPEC_IMPORT CONFIGRET WINAPI CM_Get_Device_ID_ListA(PCSTR pszFilter, PCHAR Buffer, ULONG BufferLen, ULONG ulFlags);
+DECLSPEC_IMPORT CONFIGRET WINAPI CM_Locate_DevNodeA(PDEVINST pdnDevInst, DEVINSTID_A pDeviceID, ULONG ulFlags);
+DECLSPEC_IMPORT CONFIGRET WINAPI CM_Get_Child(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags);
+DECLSPEC_IMPORT CONFIGRET WINAPI CM_Get_Sibling(PDEVINST pdnDevInst, DEVINST dnDevInst, ULONG ulFlags);
+// This last one is unknown from MinGW32 and needs to be fetched from the DLL
+PF_TYPE_DECL(WINAPI, CONFIGRET, CM_Get_DevNode_Registry_PropertyA, (DEVINST, ULONG, PULONG, PVOID, PULONG, ULONG));
+
+#define USB_GET_NODE_CONNECTION_INFORMATION_EX 274
+#define USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 279
+
+#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \
+ CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX_V2 \
+ CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX_V2, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/* Most of the structures below need to be packed */
+#pragma pack(push, 1)
+
+typedef struct _USB_DEVICE_DESCRIPTOR {
+ UCHAR bLength;
+ UCHAR bDescriptorType;
+ USHORT bcdUSB;
+ UCHAR bDeviceClass;
+ UCHAR bDeviceSubClass;
+ UCHAR bDeviceProtocol;
+ UCHAR bMaxPacketSize0;
+ USHORT idVendor;
+ USHORT idProduct;
+ USHORT bcdDevice;
+ UCHAR iManufacturer;
+ UCHAR iProduct;
+ UCHAR iSerialNumber;
+ UCHAR bNumConfigurations;
+} USB_DEVICE_DESCRIPTOR, *PUSB_DEVICE_DESCRIPTOR;
+
+typedef struct USB_NODE_CONNECTION_INFORMATION_EX {
+ ULONG ConnectionIndex;
+ USB_DEVICE_DESCRIPTOR DeviceDescriptor;
+ UCHAR CurrentConfigurationValue;
+ UCHAR Speed;
+ BOOLEAN DeviceIsHub;
+ USHORT DeviceAddress;
+ ULONG NumberOfOpenPipes;
+ USB_CONNECTION_STATUS ConnectionStatus;
+// USB_PIPE_INFO PipeList[0];
+} USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX;
+
+typedef union _USB_PROTOCOLS {
+ ULONG ul;
+ struct {
+ ULONG Usb110:1;
+ ULONG Usb200:1;
+ ULONG Usb300:1;
+ ULONG ReservedMBZ:29;
+ };
+} USB_PROTOCOLS, *PUSB_PROTOCOLS;
+
+typedef union _USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS {
+ ULONG ul;
+ struct {
+ ULONG DeviceIsOperatingAtSuperSpeedOrHigher:1;
+ ULONG DeviceIsSuperSpeedCapableOrHigher:1;
+ ULONG ReservedMBZ:30;
+ };
+} USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS, *PUSB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS;
+
+typedef struct _USB_NODE_CONNECTION_INFORMATION_EX_V2 {
+ ULONG ConnectionIndex;
+ ULONG Length;
+ USB_PROTOCOLS SupportedUsbProtocols;
+ USB_NODE_CONNECTION_INFORMATION_EX_V2_FLAGS Flags;
+} USB_NODE_CONNECTION_INFORMATION_EX_V2, *PUSB_NODE_CONNECTION_INFORMATION_EX_V2;
+
+#pragma pack(pop)
+
+const GUID _GUID_DEVINTERFACE_DISK =
+ { 0x53f56307L, 0xb6bf, 0x11d0, {0x94, 0xf2, 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b} };
+const GUID _GUID_DEVINTERFACE_USB_HUB =
+ { 0xf18a0e88L, 0xc30c, 0x11d0, {0x88, 0x15, 0x00, 0xa0, 0xc9, 0x06, 0xbe, 0xd8} };
+
+#define DEVID_HTAB_SIZE 257