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…
	
	Add table
		Add a link
		
	
		Reference in a new issue