mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[core] report detected USB device speed
* Yes, it takes about all of the changes below, to basically add 3 extra characters in the log... That's Microsoft Windows for you, baby! * Closes #314
This commit is contained in:
parent
4026083da8
commit
c85670f7b7
13 changed files with 847 additions and 471 deletions
|
@ -194,6 +194,7 @@
|
|||
<ClCompile Include="..\stdio.c" />
|
||||
<ClCompile Include="..\stdlg.c" />
|
||||
<ClCompile Include="..\syslinux.c" />
|
||||
<ClCompile Include="..\usb.c" />
|
||||
<ClCompile Include="..\vhd.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -215,6 +216,7 @@
|
|||
<ClInclude Include="..\license.h" />
|
||||
<ClInclude Include="..\smart.h" />
|
||||
<ClInclude Include="..\sys_types.h" />
|
||||
<ClInclude Include="..\usb.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Manifest Include="..\common_controls_and_elevation.manifest" />
|
||||
|
|
|
@ -66,6 +66,9 @@
|
|||
<ClCompile Include="..\smart.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\usb.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\rufus.h">
|
||||
|
@ -122,6 +125,9 @@
|
|||
<ClInclude Include="..\drive.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\usb.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\..\res\rufus.ico">
|
||||
|
|
|
@ -45,5 +45,6 @@ SOURCES=rufus.c \
|
|||
drive.c \
|
||||
smart.c \
|
||||
syslinux.c \
|
||||
usb.c \
|
||||
vhd.c \
|
||||
rufus.rc
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<htab_size+1; i++) {
|
||||
if (htab_table[i].used) {
|
||||
safe_free(htab_table[i].str);
|
||||
}
|
||||
}
|
||||
safe_free(htab_table);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
static uint32_t htab_hash(char* str)
|
||||
{
|
||||
uint32_t hval, hval2;
|
||||
uint32_t idx;
|
||||
uint32_t r = 0;
|
||||
int c;
|
||||
char* sz = str;
|
||||
|
||||
if (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("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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
265
src/rufus.c
265
src/rufus.c
|
@ -28,8 +28,6 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <commctrl.h>
|
||||
#include <setupapi.h>
|
||||
#include <winioctl.h>
|
||||
#include <shlobj.h>
|
||||
#include <process.h>
|
||||
|
@ -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<ARRAYSIZE(storage_name); s++) {
|
||||
// Get a list of hardware IDs for all USB storage devices
|
||||
// This will be used to retrieve the VID:PID of our devices
|
||||
CM_Get_Device_ID_List_SizeA(&list_size[s], storage_name[s], CM_GETIDLIST_FILTER_SERVICE);
|
||||
if (list_size[s] != 0)
|
||||
full_list_size += list_size[s]-1; // remove extra NUL terminator
|
||||
}
|
||||
full_list_size += 1; // add extra NUL terminator
|
||||
if (full_list_size < 2)
|
||||
return FALSE;
|
||||
devid_list = (char*)malloc(full_list_size);
|
||||
if (devid_list == NULL) {
|
||||
uprintf("Could not allocate Dev ID list\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Build a single list from all the storage enumerators we know of
|
||||
for (s=0, i=0; s<ARRAYSIZE(storage_name); s++) {
|
||||
if (list_size[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<strlen(devid))&&(k<2); j++) {
|
||||
// The ID is in the form USB_VENDOR_BUSID\VID_xxxx&PID_xxxx\...
|
||||
if (devid[j] == '\\')
|
||||
post_backslash = TRUE;
|
||||
if (!post_backslash)
|
||||
continue;
|
||||
if (devid[j] == '_') {
|
||||
pid = (uint16_t)strtoul(&devid[j+1], NULL, 16);
|
||||
// We could have used a vid_pid[] table, but keeping vid/pid separate is clearer
|
||||
if (k++==0) vid = pid;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_VHD) {
|
||||
uprintf("Found VHD device '%s'\n", buffer);
|
||||
} else {
|
||||
if ((vid == 0) && (pid == 0)) {
|
||||
if (is_SCSI) {
|
||||
// If we have an SCSI drive and couldn't get a VID:PID, we are most likely
|
||||
// dealing with a system drive => 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; i<ComboBox_GetCount(hDeviceList); i++) {
|
||||
if ((DWORD)ComboBox_GetItemData(hDeviceList, i) == devnum) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
i = 0;
|
||||
IGNORE_RETVAL(ComboBox_SetCurSel(hDeviceList, i));
|
||||
SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_DEVICE, 0);
|
||||
SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_FILESYSTEM,
|
||||
ComboBox_GetCurSel(hFileSystem));
|
||||
safe_free(devid_list);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set up progress bar real estate allocation
|
||||
*/
|
||||
|
|
36
src/rufus.h
36
src/rufus.h
|
@ -346,6 +346,7 @@ extern BOOL SetAutorun(const char* path);
|
|||
extern char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_desc, DWORD options);
|
||||
extern BOOL FileIO(BOOL save, char* path, char** buffer, DWORD* size);
|
||||
extern unsigned char* GetResource(HMODULE module, char* name, char* type, const char* desc, DWORD* len, BOOL duplicate);
|
||||
extern BOOL GetUSBDevices(DWORD devnum);
|
||||
extern BOOL SetLGP(BOOL bRestore, BOOL* bExistingKey, const char* szPath, const char* szPolicy, DWORD dwValue);
|
||||
extern LONG GetEntryWidth(HWND hDropDown, const char* entry);
|
||||
extern DWORD DownloadFile(const char* url, const char* file, HWND hProgressDialog);
|
||||
|
@ -378,14 +379,30 @@ static __inline void *_reallocf(void *ptr, size_t size)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Hash tables */
|
||||
typedef struct htab_entry {
|
||||
uint32_t used;
|
||||
char* str;
|
||||
void* data;
|
||||
} htab_entry;
|
||||
typedef struct htab_table {
|
||||
htab_entry *table;
|
||||
uint32_t size;
|
||||
uint32_t filled;
|
||||
} htab_table;
|
||||
#define HTAB_EMPTY {NULL, 0, 0}
|
||||
extern BOOL htab_create(uint32_t nel, htab_table* htab);
|
||||
extern void htab_destroy(htab_table* htab);
|
||||
extern uint32_t htab_hash(char* str, htab_table* htab);
|
||||
|
||||
/* Basic String Array */
|
||||
typedef struct {
|
||||
char** String;
|
||||
size_t Index; // Current array size
|
||||
size_t Max; // Maximum array size
|
||||
char** String;
|
||||
uint32_t Index; // Current array size
|
||||
uint32_t Max; // Maximum array size
|
||||
} StrArray;
|
||||
extern void StrArrayCreate(StrArray* arr, size_t initial_size);
|
||||
extern void StrArrayAdd(StrArray* arr, const char* str);
|
||||
extern void StrArrayCreate(StrArray* arr, uint32_t initial_size);
|
||||
extern int32_t StrArrayAdd(StrArray* arr, const char* str);
|
||||
extern void StrArrayClear(StrArray* arr);
|
||||
extern void StrArrayDestroy(StrArray* arr);
|
||||
#define IsStrArrayEmpty(arr) (arr.Index == 0)
|
||||
|
@ -469,12 +486,3 @@ static __inline HMODULE GetLibraryHandle(char* szLibraryName) {
|
|||
#define _RT_ICON MAKEINTRESOURCEA(3)
|
||||
#define _RT_RCDATA MAKEINTRESOURCEA(10)
|
||||
#define _RT_GROUP_ICON MAKEINTRESOURCEA((ULONG_PTR)(MAKEINTRESOURCEA(3) + 11))
|
||||
|
||||
/* The CM calls used in GetUSBDevices() - from MinGW's cfgmgr32.h header */
|
||||
typedef DWORD CONFIGRET, DEVINST, *PDEVINST;
|
||||
typedef CHAR *DEVINSTID_A;
|
||||
#define CM_GETIDLIST_FILTER_SERVICE 2
|
||||
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);
|
||||
|
|
12
src/rufus.rc
12
src/rufus.rc
|
@ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
|||
|
||||
IDD_DIALOG DIALOGEX 12, 12, 206, 329
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Rufus 1.4.8.467"
|
||||
CAPTION "Rufus 1.4.8.468"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
|
||||
|
@ -165,7 +165,7 @@ END
|
|||
RTL_IDD_DIALOG DIALOGEX 12, 12, 206, 329
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL
|
||||
CAPTION "Rufus 1.4.8.467"
|
||||
CAPTION "Rufus 1.4.8.468"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
|
||||
|
@ -427,8 +427,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,4,8,467
|
||||
PRODUCTVERSION 1,4,8,467
|
||||
FILEVERSION 1,4,8,468
|
||||
PRODUCTVERSION 1,4,8,468
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -445,13 +445,13 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
|
||||
VALUE "FileDescription", "Rufus"
|
||||
VALUE "FileVersion", "1.4.8.467"
|
||||
VALUE "FileVersion", "1.4.8.468"
|
||||
VALUE "InternalName", "Rufus"
|
||||
VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)"
|
||||
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
|
||||
VALUE "OriginalFilename", "rufus.exe"
|
||||
VALUE "ProductName", "Rufus"
|
||||
VALUE "ProductVersion", "1.4.8.467"
|
||||
VALUE "ProductVersion", "1.4.8.468"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
180
src/stdfn.c
180
src/stdfn.c
|
@ -32,6 +32,174 @@
|
|||
int nWindowsVersion = WINDOWS_UNDEFINED;
|
||||
char WindowsVersionStr[128] = "Windows ";
|
||||
|
||||
/*
|
||||
* 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)
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
BOOL htab_create(uint32_t nel, htab_table* htab)
|
||||
{
|
||||
if (htab == NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
if (htab->table != 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; i<htab->size+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)
|
||||
|
|
|
@ -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<MAX_SIZE_SUFFIXES-1; suffix++) {
|
||||
if (hr_size < divider)
|
||||
break;
|
||||
|
|
435
src/usb.c
Normal file
435
src/usb.c
Normal file
|
@ -0,0 +1,435 @@
|
|||
/*
|
||||
* Rufus: The Reliable USB Formatting Utility
|
||||
* USB device listing
|
||||
* Copyright © 2014 Pete Batard <pete@akeo.ie>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Memory leaks detection - define _CRTDBG_MAP_ALLOC as preprocessor macro */
|
||||
#ifdef _CRTDBG_MAP_ALLOC
|
||||
#include <stdlib.h>
|
||||
#include <crtdbg.h>
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <stdio.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
#include <commctrl.h>
|
||||
#include <setupapi.h>
|
||||
|
||||
#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<ARRAYSIZE(storage_name); s++) {
|
||||
// Get a list of hardware IDs for all USB storage devices
|
||||
// This will be used to retrieve the VID:PID of our devices
|
||||
CM_Get_Device_ID_List_SizeA(&list_size[s], storage_name[s], CM_GETIDLIST_FILTER_SERVICE);
|
||||
if (list_size[s] != 0)
|
||||
full_list_size += list_size[s]-1; // remove extra NUL terminator
|
||||
}
|
||||
full_list_size += 1; // add extra NUL terminator
|
||||
if (full_list_size < 2)
|
||||
return FALSE;
|
||||
devid_list = (char*)malloc(full_list_size);
|
||||
if (devid_list == NULL) {
|
||||
uprintf("Could not allocate Dev ID list\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Build a single list from all the storage enumerators we know of
|
||||
for (s=0, i=0; s<ARRAYSIZE(storage_name); s++) {
|
||||
if (list_size[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<strlen(devid))&&(k<2); j++) {
|
||||
// The ID is in the form USB_VENDOR_BUSID\VID_xxxx&PID_xxxx\...
|
||||
if (devid[j] == '\\')
|
||||
post_backslash = TRUE;
|
||||
if (!post_backslash)
|
||||
continue;
|
||||
if (devid[j] == '_') {
|
||||
props.pid = (uint16_t)strtoul(&devid[j+1], NULL, 16);
|
||||
if (k++==0)
|
||||
props.vid = props.pid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (props.is_VHD) {
|
||||
uprintf("Found VHD device '%s'\n", buffer);
|
||||
} else {
|
||||
if ((props.vid == 0) && (props.pid == 0)) {
|
||||
if (is_SCSI) {
|
||||
// If we have an SCSI drive and couldn't get a VID:PID, we are most likely
|
||||
// dealing with a system drive => 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<ComboBox_GetCount(hDeviceList); i++) {
|
||||
if ((DWORD)ComboBox_GetItemData(hDeviceList, i) == devnum) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
i = 0;
|
||||
IGNORE_RETVAL(ComboBox_SetCurSel(hDeviceList, i));
|
||||
SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_DEVICE, 0);
|
||||
SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_FILESYSTEM,
|
||||
ComboBox_GetCurSel(hFileSystem));
|
||||
safe_free(devid_list);
|
||||
StrArrayDestroy(&dev_if_path);
|
||||
htab_destroy(&htab_devid);
|
||||
return TRUE;
|
||||
}
|
171
src/usb.h
Normal file
171
src/usb.h
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Rufus: The Reliable USB Formatting Utility
|
||||
* USB device listing
|
||||
* Copyright © 2014 Pete Batard <pete@akeo.ie>
|
||||
*
|
||||
* 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#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
|
Loading…
Reference in a new issue