mirror of
https://github.com/pbatard/rufus.git
synced 2025-05-19 09:25:12 -04:00
[core] add HDD vs UFD detection
* Initial scoring to try to differentiate UFDs from HDDs (#219) * Also improve GetDriveLetter() and add a global for fixed vs removable * Also fix a bug with reporting of VID:PID with multiple devices * Also fix a warning in localization
This commit is contained in:
parent
803a4bff1c
commit
aa0bf0ee2b
7 changed files with 165 additions and 38 deletions
38
src/drive.c
38
src/drive.c
|
@ -36,7 +36,7 @@
|
|||
* Globals
|
||||
*/
|
||||
RUFUS_DRIVE_INFO SelectedDrive;
|
||||
extern BOOL enable_fixed_disks;
|
||||
extern UINT drive_type;
|
||||
|
||||
// TODO: add a DetectSectorSize()?
|
||||
// http://msdn.microsoft.com/en-us/library/ff800831.aspx
|
||||
|
@ -136,11 +136,11 @@ char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent
|
|||
char path[MAX_PATH];
|
||||
VOLUME_DISK_EXTENTS DiskExtents;
|
||||
DWORD size;
|
||||
UINT drive_type;
|
||||
int i, j;
|
||||
static const char* ignore_device[] = { "\\Device\\CdRom", "\\Device\\Floppy" };
|
||||
static const char* volume_start = "\\\\?\\";
|
||||
|
||||
drive_type = DRIVE_UNKNOWN;
|
||||
CheckDriveIndex(DriveIndex);
|
||||
|
||||
for (i=0; hDrive == INVALID_HANDLE_VALUE; i++) {
|
||||
|
@ -167,9 +167,7 @@ char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent
|
|||
}
|
||||
|
||||
drive_type = GetDriveTypeA(volume_name);
|
||||
// NB: the HP utility allows drive_type == DRIVE_FIXED, which we don't allow by default
|
||||
// Using Alt-F in Rufus does enable listing, but this mode is unsupported.
|
||||
if ((drive_type != DRIVE_REMOVABLE) && ((!enable_fixed_disks) || (drive_type != DRIVE_FIXED)))
|
||||
if ((drive_type != DRIVE_REMOVABLE) && (drive_type != DRIVE_FIXED))
|
||||
continue;
|
||||
|
||||
volume_name[len-1] = 0;
|
||||
|
@ -257,16 +255,17 @@ HANDLE GetLogicalHandle(DWORD DriveIndex, BOOL bWriteAccess, BOOL bLockDrive)
|
|||
/*
|
||||
* Returns the first drive letter for a volume located on the drive identified by DriveIndex
|
||||
*/
|
||||
char GetDriveLetter(DWORD DriveIndex)
|
||||
BOOL GetDriveLetter(DWORD DriveIndex, char* drive_letter)
|
||||
{
|
||||
DWORD size;
|
||||
BOOL r;
|
||||
BOOL r = FALSE;
|
||||
STORAGE_DEVICE_NUMBER_REDEF device_number = {0};
|
||||
UINT drive_type;
|
||||
HANDLE hDrive = INVALID_HANDLE_VALUE;
|
||||
char *drive, drives[26*4]; /* "D:\", "E:\", etc. */
|
||||
char logical_drive[] = "\\\\.\\#:";
|
||||
char drive_letter = ' ';
|
||||
|
||||
drive_type = DRIVE_UNKNOWN;
|
||||
*drive_letter = ' ';
|
||||
CheckDriveIndex(DriveIndex);
|
||||
|
||||
size = GetLogicalDriveStringsA(sizeof(drives), drives);
|
||||
|
@ -279,6 +278,7 @@ char GetDriveLetter(DWORD DriveIndex)
|
|||
goto out;
|
||||
}
|
||||
|
||||
r = TRUE;
|
||||
for (drive = drives ;*drive; drive += safe_strlen(drive)+1) {
|
||||
if (!isalpha(*drive))
|
||||
continue;
|
||||
|
@ -292,9 +292,8 @@ char GetDriveLetter(DWORD DriveIndex)
|
|||
value there => Use GetDriveType() to filter out unwanted devices.
|
||||
See https://github.com/pbatard/rufus/issues/32 for details. */
|
||||
drive_type = GetDriveTypeA(drive);
|
||||
// NB: the HP utility allows drive_type == DRIVE_FIXED, which we don't allow by default
|
||||
// Using Alt-F in Rufus does enable listing, but this mode is unsupported.
|
||||
if ((drive_type != DRIVE_REMOVABLE) && ((!enable_fixed_disks) || (drive_type != DRIVE_FIXED)))
|
||||
|
||||
if ((drive_type != DRIVE_REMOVABLE) && (drive_type != DRIVE_FIXED))
|
||||
continue;
|
||||
|
||||
safe_sprintf(logical_drive, sizeof(logical_drive), "\\\\.\\%c:", drive[0]);
|
||||
|
@ -305,19 +304,19 @@ char GetDriveLetter(DWORD DriveIndex)
|
|||
}
|
||||
|
||||
r = DeviceIoControl(hDrive, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL,
|
||||
0, &device_number, sizeof(device_number), &size, NULL);
|
||||
0, &device_number, sizeof(device_number), &size, NULL) && (size > 0);
|
||||
safe_closehandle(hDrive);
|
||||
if ((!r) || (size <= 0)) {
|
||||
if (!r) {
|
||||
uprintf("Could not get device number for device %s: %s\n",
|
||||
logical_drive, WindowsErrorString());
|
||||
} else if (device_number.DeviceNumber == DriveIndex) {
|
||||
drive_letter = *drive;
|
||||
*drive_letter = *drive;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return drive_letter;
|
||||
return r;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -368,10 +367,11 @@ BOOL GetDriveLabel(DWORD DriveIndex, char* letter, char** label)
|
|||
|
||||
*label = STR_NO_LABEL;
|
||||
|
||||
*letter = GetDriveLetter(DriveIndex);
|
||||
if (!GetDriveLetter(DriveIndex, letter))
|
||||
return FALSE;
|
||||
if (*letter == ' ') {
|
||||
// Drive without volume assigned - Tie to the display of fixed disks
|
||||
return enable_fixed_disks;
|
||||
// Drive without volume assigned - always enabled
|
||||
return TRUE;
|
||||
}
|
||||
AutorunPath[0] = *letter;
|
||||
wDrivePath[0] = *letter;
|
||||
|
|
|
@ -1195,7 +1195,11 @@ DWORD WINAPI FormatThread(LPVOID param)
|
|||
}
|
||||
|
||||
// At this stage with have both a handle and a lock to the physical drive...
|
||||
drive_name[0] = GetDriveLetter(DriveIndex);
|
||||
if (!GetDriveLetter(DriveIndex, &drive_name[0])) {
|
||||
uprintf("Failed to get a drive letter\n");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_ASSIGN_LETTER);
|
||||
goto out;
|
||||
}
|
||||
if (drive_name[0] == ' ') {
|
||||
uprintf("No drive letter was assigned...\n");
|
||||
drive_name[0] = GetUnusedDriveLetter();
|
||||
|
|
|
@ -199,7 +199,7 @@ static uint32_t htab_hash(char* str)
|
|||
do {
|
||||
// Because size is prime this guarantees to step through all available indexes
|
||||
if (idx <= hval2) {
|
||||
idx = htab_size + idx - hval2;
|
||||
idx = ((uint32_t)htab_size) + idx - hval2;
|
||||
} else {
|
||||
idx -= hval2;
|
||||
}
|
||||
|
|
29
src/rufus.c
29
src/rufus.c
|
@ -117,7 +117,8 @@ HWND hDeviceList, hPartitionScheme, hFileSystem, hClusterSize, hLabel, hBootType
|
|||
HWND hISOProgressDlg = NULL, hLogDlg = NULL, hISOProgressBar, hISOFileName, hDiskID;
|
||||
BOOL use_own_c32[NB_OLD_C32] = {FALSE, FALSE}, detect_fakes = TRUE, mbr_selected_by_user = FALSE;
|
||||
BOOL iso_op_in_progress = FALSE, format_op_in_progress = FALSE;
|
||||
BOOL enable_fixed_disks = FALSE, advanced_mode = TRUE, force_update = FALSE;
|
||||
BOOL enable_HDDs = FALSE, advanced_mode = TRUE, force_update = FALSE;
|
||||
UINT drive_type = DRIVE_UNKNOWN;
|
||||
int dialog_showing = 0;
|
||||
uint16_t rufus_version[4];
|
||||
RUFUS_UPDATE update = { {0,0,0,0}, {0,0}, NULL, NULL};
|
||||
|
@ -602,6 +603,7 @@ static BOOL GetUSBDevices(DWORD devnum)
|
|||
HANDLE hDrive;
|
||||
LONG maxwidth = 0;
|
||||
RECT rect;
|
||||
int score;
|
||||
char drive_letter, *devid, *devid_list = NULL;
|
||||
char *label, *entry, buffer[MAX_PATH], str[sizeof("0000:0000")+1];
|
||||
const char* usbstor_name = "USBSTOR";
|
||||
|
@ -653,7 +655,7 @@ static BOOL GetUSBDevices(DWORD devnum)
|
|||
} 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_list) + 1) {
|
||||
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) ) {
|
||||
|
@ -684,7 +686,7 @@ static BOOL GetUSBDevices(DWORD devnum)
|
|||
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 non fixed USB disk\n");
|
||||
uprintf("A device was eliminated because it didn't report itself as a disk\n");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -730,12 +732,19 @@ static BOOL GetUSBDevices(DWORD devnum)
|
|||
continue;
|
||||
}
|
||||
|
||||
// Identify(hDrive);
|
||||
|
||||
if (GetDriveLabel(device_number.DeviceNumber + DRIVE_INDEX_MIN, &drive_letter, &label)) {
|
||||
// Must ensure that the combo box is UNSORTED for indexes to be the same
|
||||
StrArrayAdd(&DriveID, buffer);
|
||||
StrArrayAdd(&DriveLabel, label);
|
||||
|
||||
if ((!enable_HDDs) && ((score = IsHDD(drive_type, vid, pid, buffer)) > IS_HDD_THRESHOLD)) {
|
||||
uprintf("USB HDD device removed (score %d > %d) "
|
||||
"[Note: You can enable USB HDDs in the Advanced Options]\n", score, IS_HDD_THRESHOLD);
|
||||
safe_closehandle(hDrive);
|
||||
safe_free(devint_detail_data);
|
||||
break;
|
||||
}
|
||||
|
||||
// Drive letter ' ' is returned for drives that don't have a volume assigned yet
|
||||
if (drive_letter == ' ') {
|
||||
entry = lmprintf(MSG_046, label, device_number.DeviceNumber);
|
||||
|
@ -1809,8 +1818,8 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
|
|||
break;
|
||||
case IDC_ENABLE_FIXED_DISKS:
|
||||
if ((HIWORD(wParam)) == BN_CLICKED) {
|
||||
enable_fixed_disks = !enable_fixed_disks;
|
||||
PrintStatus2000(lmprintf(MSG_253), enable_fixed_disks);
|
||||
enable_HDDs = !enable_HDDs;
|
||||
PrintStatus2000(lmprintf(MSG_253), enable_HDDs);
|
||||
GetUSBDevices(0);
|
||||
}
|
||||
break;
|
||||
|
@ -2030,7 +2039,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
|
|||
while ((opt = getopt_long(argc, argv, "?fhi:w:l:", long_options, &option_index)) != EOF)
|
||||
switch (opt) {
|
||||
case 'f':
|
||||
enable_fixed_disks = TRUE;
|
||||
enable_HDDs = TRUE;
|
||||
break;
|
||||
case 'i':
|
||||
if (_access(optarg, 0) != -1) {
|
||||
|
@ -2166,8 +2175,8 @@ relaunch:
|
|||
// This is a safety feature, to avoid someone unintentionally formatting a backup
|
||||
// drive instead of an USB key. If this is enabled, Rufus will allow fixed disk formatting.
|
||||
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'F')) {
|
||||
enable_fixed_disks = !enable_fixed_disks;
|
||||
PrintStatus2000(lmprintf(MSG_253), enable_fixed_disks);
|
||||
enable_HDDs = !enable_HDDs;
|
||||
PrintStatus2000(lmprintf(MSG_253), enable_HDDs);
|
||||
GetUSBDevices(0);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#define UDF_FORMAT_SPEED 3.1f // Speed estimate at which we expect UDF drives to be formatted (GB/s)
|
||||
#define UDF_FORMAT_WARN 20 // Duration (in seconds) above which we warn about long UDF formatting times
|
||||
#define MAX_FAT32_SIZE 2.0f // Threshold above which we disable FAT32 formatting (in TB)
|
||||
#define IS_HDD_THRESHOLD 5
|
||||
#define WHITE RGB(255,255,255)
|
||||
#define SEPARATOR_GREY RGB(223,223,223)
|
||||
#define RUFUS_URL "http://rufus.akeo.ie"
|
||||
|
@ -319,7 +320,7 @@ extern HANDLE GetPhysicalHandle(DWORD DriveIndex, BOOL bWriteAccess, BOOL bLockD
|
|||
extern BOOL WaitForLogical(DWORD DriveIndex);
|
||||
extern char* GetLogicalName(DWORD DriveIndex, BOOL bKeepTrailingBackslash, BOOL bSilent);
|
||||
extern HANDLE GetLogicalHandle(DWORD DriveIndex, BOOL bWriteAccess, BOOL bLockDrive);
|
||||
extern char GetDriveLetter(DWORD DriveIndex);
|
||||
extern BOOL GetDriveLetter(DWORD DriveIndex, char* drive_letter);
|
||||
extern char GetUnusedDriveLetter(void);
|
||||
extern BOOL CreatePartition(HANDLE hDrive, int partition_style, int file_system, BOOL mbr_uefi_marker);
|
||||
extern BOOL DeletePartitions(HANDLE hDrive);
|
||||
|
@ -350,7 +351,7 @@ extern char* replace_in_token_data(const char* filename, const char* token, cons
|
|||
extern void parse_update(char* buf, size_t len);
|
||||
extern BOOL WimExtractCheck(void);
|
||||
extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst);
|
||||
extern BOOL Identify(HANDLE hPhysical);
|
||||
extern int IsHDD(UINT drive_type, uint16_t vid, uint16_t pid, const char* strid);
|
||||
|
||||
static __inline BOOL UnlockDrive(HANDLE hDrive)
|
||||
{
|
||||
|
|
10
src/rufus.rc
10
src/rufus.rc
|
@ -33,7 +33,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
|
||||
EXSTYLE WS_EX_APPWINDOW
|
||||
CAPTION "Rufus v1.4.0.315"
|
||||
CAPTION "Rufus v1.4.0.316"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
|
||||
|
@ -289,8 +289,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,4,0,315
|
||||
PRODUCTVERSION 1,4,0,315
|
||||
FILEVERSION 1,4,0,316
|
||||
PRODUCTVERSION 1,4,0,316
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -307,13 +307,13 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
|
||||
VALUE "FileDescription", "Rufus"
|
||||
VALUE "FileVersion", "1.4.0.315"
|
||||
VALUE "FileVersion", "1.4.0.316"
|
||||
VALUE "InternalName", "Rufus"
|
||||
VALUE "LegalCopyright", "© 2011-2013 Pete Batard (GPL v3)"
|
||||
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
|
||||
VALUE "OriginalFilename", "rufus.exe"
|
||||
VALUE "ProductName", "Rufus"
|
||||
VALUE "ProductVersion", "1.4.0.315"
|
||||
VALUE "ProductVersion", "1.4.0.316"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
113
src/smart.c
113
src/smart.c
|
@ -397,4 +397,117 @@ BOOL SmartGetVersion(HANDLE hdevice)
|
|||
* - if IDENTIFY reports SMART capabilities
|
||||
* - if it has extra non hidden partitions that aren't Windows
|
||||
* - if the VID:PID (or VID) is of known USB to IDE/SATA bridge or known UFD maker
|
||||
* - removable flag (how do you actually find that one?)
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
const char* name;
|
||||
const int score;
|
||||
} str_score;
|
||||
|
||||
typedef struct {
|
||||
const uint16_t vid;
|
||||
const int score;
|
||||
} vid_score;
|
||||
|
||||
// If a disk ID starts with these, we consider it likely to be an HDD
|
||||
// The info from http://knowledge.seagate.com/articles/en_US/FAQ/204763en is a start, but not
|
||||
// entirely accurate for our usage as some models will be prefixed with the manufacturer name
|
||||
// '#' below means any number in [0-9]
|
||||
static str_score manufacturer_str[] = {
|
||||
{ "HP ", 10 },
|
||||
{ "ST#", 10 },
|
||||
{ "MX#", 10 },
|
||||
{ "WDC", 10 },
|
||||
{ "IBM", 10 },
|
||||
{ "STM#", 10 },
|
||||
{ "HTS#", 10 },
|
||||
{ "MAXTOR", 10 },
|
||||
{ "HITACHI", 10 },
|
||||
{ "SEAGATE", 10 },
|
||||
{ "SAMSUNG", 10 },
|
||||
{ "FUJITSU", 10 },
|
||||
{ "TOSHIBA", 10 },
|
||||
{ "QUANTUM", 10 },
|
||||
};
|
||||
|
||||
// http://www.linux-usb.org/usb.ids
|
||||
static vid_score manufacturer_vid[] = {
|
||||
{ 0x04b4, 10 }, // Cypress
|
||||
{ 0x067b, 10 }, // Prolific
|
||||
{ 0x0bc2, 10 }, // Seagate
|
||||
{ 0x152d, 10 }, // JMicron
|
||||
};
|
||||
|
||||
/*
|
||||
* This attempts to detect whether a drive is an USB HDD or an USB Flash Drive (UFD).
|
||||
* If someone already has an USB HDD plugged in (say as a backup drive) and plugs an
|
||||
* UFD we *try* to do what we can to avoid them formatting that drive by mistake.
|
||||
* But because there is no foolproof (let alone easy), way to differentiate UFDs from
|
||||
* HDDs, thanks to every manufacturer, Microsoft, and their mothers making it
|
||||
* exceedingly troublesome to find out what type of hardware we are actually accessing
|
||||
* please pay heed to the following warning:
|
||||
*
|
||||
* WARNING: NO PROMISE IS MADE ABOUT THIS ALGORITHM BEING ABLE TO CORRECTLY
|
||||
* DIFFERENTIATE AN USB HDD FROM A FLASH DRIVE. ALSO, REMEMBER THAT THE LICENSE OF THIS
|
||||
* APPLICATION MAKES ABSOLUETLY NO PROMISE ABOUT DATA PRESERVATION (PROVIDED "AS IS").
|
||||
* THUS, IF DATA LOSS IS INCURRED DUE TO THE ALGORITHM BELOW, OR ANY OTHER PART OF THIS
|
||||
* APPLICATION, THE RESPONSIBILITY IS ENTIRELY ON YOU!
|
||||
*
|
||||
* But let me just elaborate further on why differentiating UFDs from HDDs is not as
|
||||
* 'simple' as it seems:
|
||||
* - many USB flash drives manufacturer will present UFDs as non-removable, which used
|
||||
* to be reserved for HDDs => we can't use that as differentiator.
|
||||
* - some UFDs (SanDisk Extreme) have added S.M.A.R.T. support, which also used to be
|
||||
* reserved for HDDs => can't use that either
|
||||
* - even if S.M.A.R.T. was enough, not all USB->IDE or USB->SATA bridges support ATA
|
||||
* passthrough, which is required S.M.A.R.T. data, and each manufacturer of an
|
||||
* USB<->(S)ATA bridge seem to have their own method of implementing passthrough.
|
||||
* - SSDs have also changed the deal completely, as you can get something that looks
|
||||
* like Flash but that is really an HDD.
|
||||
* - Some manufacturers (eg. ALI) provide both USB Flash controllers and USB IDE/SATA
|
||||
* controllers, so we can't exactly use the VID to say for sure what we're looking at.
|
||||
* - Finally, Microsoft is abdsolutely no help either (which is kind of understandable
|
||||
* from the above) => there is no magic API we can query that will tell us what we're
|
||||
* really looking at.
|
||||
*
|
||||
* What you have below, then, is our *current best guess* at differentiating an UFD from
|
||||
* an HDD. Short of a crystal ball however, this remains just a guess, which may be way
|
||||
* off mark. Still, Rufus does produce PROMINENT warnings before you format a drive, and
|
||||
* also provides extensive info about the drive (from the toolips and the log) => PAY
|
||||
* ATTENTION TO THESE OR PAY THE PRICE!
|
||||
*/
|
||||
int IsHDD(UINT drive_type, uint16_t vid, uint16_t pid, const char* strid)
|
||||
{
|
||||
int score = 0;
|
||||
size_t i, mlen, ilen;
|
||||
BOOL wc;
|
||||
|
||||
if (drive_type == DRIVE_FIXED)
|
||||
score += 3;
|
||||
|
||||
ilen = safe_strlen(strid);
|
||||
for (i=0; i<ARRAYSIZE(manufacturer_str); i++) {
|
||||
mlen = strlen(manufacturer_str[i].name);
|
||||
if (mlen > ilen)
|
||||
break;
|
||||
wc = (manufacturer_str[i].name[mlen-1] == '#');
|
||||
if ( (_strnicmp(strid, manufacturer_str[i].name, mlen-((wc)?1:0)) == 0)
|
||||
&& ((!wc) || ((strid[mlen] >= '0') && (strid[mlen] <= '9'))) ) {
|
||||
score += manufacturer_str[i].score;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<ARRAYSIZE(manufacturer_vid); i++) {
|
||||
if (vid == manufacturer_vid[i].vid) {
|
||||
score += manufacturer_vid[i].score;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: try to perform inquiry if uncertain
|
||||
// TODO: lower the score for well known UFD manufacturers (ADATA, SanDisk, etc.)
|
||||
return score;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue