From c76327f96ebbe0f8c54a4f7dc3cd09b80097838e Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 25 May 2022 13:21:36 +0100 Subject: [PATCH] [ui] list drives by increasing order of size * Also silence MSVC and MinGW obnoxious warnings about bidirectional Unicode characters. --- .vs/rufus.vcxproj | 16 +++---- configure | 2 +- configure.ac | 2 +- src/dev.c | 104 ++++++++++++++++++++++++++++++++-------------- src/drive.h | 1 + src/rufus.c | 32 ++++++-------- src/rufus.h | 11 +++++ src/rufus.rc | 10 ++--- 8 files changed, 112 insertions(+), 66 deletions(-) diff --git a/.vs/rufus.vcxproj b/.vs/rufus.vcxproj index b10989f7..4e53ec6f 100644 --- a/.vs/rufus.vcxproj +++ b/.vs/rufus.vcxproj @@ -128,7 +128,7 @@ CompileAsC true false - 4091;28251;28252;28253;%(DisableSpecificWarnings) + 4091;5255;28251;28252;28253;%(DisableSpecificWarnings) Disabled /utf-8 $(ExternalCompilerOptions) %(AdditionalOptions) @@ -154,7 +154,7 @@ CompileAsC true false - 4091;28251;28252;28253;%(DisableSpecificWarnings) + 4091;5255;28251;28252;28253;%(DisableSpecificWarnings) /utf-8 $(ExternalCompilerOptions) %(AdditionalOptions) @@ -181,7 +181,7 @@ CompileAsC true false - 4091;28251;28252;28253;%(DisableSpecificWarnings) + 4091;5255;28251;28252;28253;%(DisableSpecificWarnings) /utf-8 $(ExternalCompilerOptions) %(AdditionalOptions) @@ -212,7 +212,7 @@ CompileAsC true false - 4091;28251;28252;28253;%(DisableSpecificWarnings) + 4091;5255;28251;28252;28253;%(DisableSpecificWarnings) Disabled /utf-8 $(ExternalCompilerOptions) %(AdditionalOptions) @@ -238,7 +238,7 @@ CompileAsC true false - 4091;28251;28252;28253;%(DisableSpecificWarnings) + 4091;5255;28251;28252;28253;%(DisableSpecificWarnings) NDEBUG /utf-8 $(ExternalCompilerOptions) %(AdditionalOptions) true @@ -266,7 +266,7 @@ CompileAsC true false - 4091;28251;28252;28253;%(DisableSpecificWarnings) + 4091;5255;28251;28252;28253;%(DisableSpecificWarnings) NDEBUG /utf-8 $(ExternalCompilerOptions) %(AdditionalOptions) true @@ -296,7 +296,7 @@ CompileAsC true false - 4091;28251;28252;28253;%(DisableSpecificWarnings) + 4091;5255;28251;28252;28253;%(DisableSpecificWarnings) NDEBUG /utf-8 $(ExternalCompilerOptions) %(AdditionalOptions) true @@ -329,7 +329,7 @@ CompileAsC true false - 4091;28251;28252;28253;%(DisableSpecificWarnings) + 4091;5255;28251;28252;28253;%(DisableSpecificWarnings) NDEBUG /utf-8 $(ExternalCompilerOptions) %(AdditionalOptions) true diff --git a/configure b/configure index 158b46b6..32a44771 100755 --- a/configure +++ b/configure @@ -4726,7 +4726,7 @@ fi rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext CFLAGS="${saved_CFLAGS}" -AM_CFLAGS="$AM_CFLAGS -DUNICODE -D_UNICODE -UNDEBUG -DCOBJMACROS -D__USE_MINGW_ANSI_STDIO=0 -std=gnu99 -Wshadow -Wall -Wformat-security -Wundef -Wunused -Wstrict-prototypes -Wno-restrict -Werror-implicit-function-declaration $nopointersign_cflags" +AM_CFLAGS="$AM_CFLAGS -DUNICODE -D_UNICODE -UNDEBUG -DCOBJMACROS -D__USE_MINGW_ANSI_STDIO=0 -std=gnu99 -Wshadow -Wall -Wformat-security -Wundef -Wunused -Wstrict-prototypes -Wno-restrict -Werror-implicit-function-declaration -Wbidi-chars=none $nopointersign_cflags" diff --git a/configure.ac b/configure.ac index 7e4b242d..2b5e66a4 100644 --- a/configure.ac +++ b/configure.ac @@ -64,7 +64,7 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])], [nopointersign_cflags="-Wno-pointer-sign"], [nopointersign_cflags=""]) CFLAGS="${saved_CFLAGS}" -AM_CFLAGS="$AM_CFLAGS -DUNICODE -D_UNICODE -UNDEBUG -DCOBJMACROS -D__USE_MINGW_ANSI_STDIO=0 -std=gnu99 -Wshadow -Wall -Wformat-security -Wundef -Wunused -Wstrict-prototypes -Wno-restrict -Werror-implicit-function-declaration $nopointersign_cflags" +AM_CFLAGS="$AM_CFLAGS -DUNICODE -D_UNICODE -UNDEBUG -DCOBJMACROS -D__USE_MINGW_ANSI_STDIO=0 -std=gnu99 -Wshadow -Wall -Wformat-security -Wundef -Wunused -Wstrict-prototypes -Wno-restrict -Werror-implicit-function-declaration -Wbidi-chars=none $nopointersign_cflags" AC_SUBST([VISIBILITY_CFLAGS]) AC_SUBST([AM_CFLAGS]) diff --git a/src/dev.c b/src/dev.c index c416fa21..97c03a8c 100644 --- a/src/dev.c +++ b/src/dev.c @@ -44,8 +44,7 @@ #include "drive.h" #include "dev.h" -extern StrArray DriveId, DriveName, DriveLabel, DriveHub; -extern uint32_t DrivePort[MAX_DRIVES]; +extern RUFUS_DRIVE rufus_drive[MAX_DRIVES]; extern BOOL enable_HDDs, enable_VHDs, use_fake_units, enable_vmdk, usb_debug; extern BOOL list_non_usb_removable_drives, its_a_me_mario; @@ -139,29 +138,30 @@ BOOL CyclePort(int index) DWORD size; USB_CYCLE_PORT_PARAMS cycle_port; + assert(index < MAX_DRIVES); // Wait at least 10 secs between resets if (GetTickCount64() < LastReset + 10000ULL) { uprintf("You must wait at least 10 seconds before trying to reset a device"); return FALSE; } - if (DriveHub.String[index] == NULL) { + if (rufus_drive[index].hub == NULL) { uprintf("The device you are trying to reset does not appear to be a USB device..."); return FALSE; } LastReset = GetTickCount64(); - handle = CreateFileA(DriveHub.String[index], GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + handle = CreateFileA(rufus_drive[index].hub, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); if (handle == INVALID_HANDLE_VALUE) { - uprintf("Could not open %s: %s", DriveHub.String[index], WindowsErrorString()); + uprintf("Could not open %s: %s", rufus_drive[index].hub, WindowsErrorString()); goto out; } size = sizeof(cycle_port); memset(&cycle_port, 0, size); - cycle_port.ConnectionIndex = DrivePort[index]; - uprintf("Cycling port %d (reset) on %s", DrivePort[index], DriveHub.String[index]); + cycle_port.ConnectionIndex = rufus_drive[index].port; + uprintf("Cycling port %d (reset) on %s", rufus_drive[index].port, rufus_drive[index].hub); // As per https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/content/usbioctl/ni-usbioctl-ioctl_usb_hub_cycle_port // IOCTL_USB_HUB_CYCLE_PORT is not supported on Windows 7, Windows Vista, and Windows Server 2008 if (!DeviceIoControl(handle, IOCTL_USB_HUB_CYCLE_PORT, &cycle_port, size, &cycle_port, size, &size, NULL)) { @@ -191,7 +191,8 @@ int CycleDevice(int index) SP_DEVINFO_DATA dev_info_data; SP_PROPCHANGE_PARAMS propchange_params; - if ((index < 0) || (safe_strlen(DriveId.String[index]) < 8)) + assert(index < MAX_DRIVES); + if ((index < 0) || (safe_strlen(rufus_drive[index].id) < 8)) return ERROR_INVALID_PARAMETER; // Need DIGCF_ALLCLASSES else disabled devices won't be listed. @@ -210,7 +211,7 @@ int CycleDevice(int index) continue; } - if (safe_strcmp(DriveId.String[index], device_instance_id) != 0) + if (safe_strcmp(rufus_drive[index].id, device_instance_id) != 0) continue; found = TRUE; @@ -421,6 +422,19 @@ BOOL GetOpticalMedia(IMG_SAVE* img_save) #define FORCED_NAME "VendorCo Disk USB Device" #endif +void ClearDrives(void) +{ + int i; + for (i = 0; i < MAX_DRIVES && rufus_drive[i].size != 0; i++) { + free(rufus_drive[i].id); + free(rufus_drive[i].name); + free(rufus_drive[i].display_name); + free(rufus_drive[i].label); + free(rufus_drive[i].hub); + } + memset(rufus_drive, 0, sizeof(rufus_drive)); +} + /* * Refresh the list of USB devices */ @@ -474,16 +488,13 @@ BOOL GetDevices(DWORD devnum) ULONG list_size[ARRAYSIZE(usbstor_name)] = { 0 }, list_start[ARRAYSIZE(usbstor_name)] = { 0 }, full_list_size, ulFlags; HANDLE hDrive; LONG maxwidth = 0; - int s, score, drive_number, remove_drive; - char drive_letters[27], *device_id, *devid_list = NULL, entry_msg[128]; - char *p, *label, *entry, buffer[MAX_PATH], str[MAX_PATH], device_instance_id[MAX_PATH], *method_str, *hub_path; + int s, u, v, score, drive_number, remove_drive, num_drives = 0; + char drive_letters[27], *device_id, *devid_list = NULL, display_msg[128]; + char *p, *label, *display_name, buffer[MAX_PATH], str[MAX_PATH], device_instance_id[MAX_PATH], *method_str, *hub_path; usb_device_props props; IGNORE_RETVAL(ComboBox_ResetContent(hDeviceList)); - StrArrayClear(&DriveId); - StrArrayClear(&DriveName); - StrArrayClear(&DriveLabel); - StrArrayClear(&DriveHub); + ClearDrives(); StrArrayCreate(&dev_if_path, 128); // Add a dummy for string index zero, as this is what non matching hashes will point to StrArrayAdd(&dev_if_path, "", TRUE); @@ -601,7 +612,7 @@ BOOL GetDevices(DWORD devnum) goto out; } dev_info_data.cbSize = sizeof(dev_info_data); - for (i=0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) { + for (i = 0; num_drives < MAX_DRIVES && SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) { memset(buffer, 0, sizeof(buffer)); memset(&props, 0, sizeof(props)); method_str = ""; @@ -907,7 +918,7 @@ BOOL GetDevices(DWORD devnum) // 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, + display_name = lmprintf(MSG_046, label, drive_number, SizeToHumanReadable(GetDriveSize(drive_index), FALSE, use_fake_units)); } else { // Find the UEFI:TOGO partition(s) (and eliminate them form our listing) @@ -921,14 +932,14 @@ BOOL GetDevices(DWORD devnum) } // We have multiple volumes assigned to the same device (multiple partitions) // If that is the case, use "Multiple Volumes" instead of the label - static_strcpy(entry_msg, (((drive_letters[0] != 0) && (drive_letters[1] != 0))? + static_strcpy(display_msg, (((drive_letters[0] != 0) && (drive_letters[1] != 0))? lmprintf(MSG_047):label)); for (k=0, remove_drive=0; drive_letters[k] && (!remove_drive); k++) { // Append all the drive letters we detected letter_name[2] = drive_letters[k]; if (right_to_left_mode) - static_strcat(entry_msg, RIGHT_TO_LEFT_MARK); - static_strcat(entry_msg, letter_name); + static_strcat(display_msg, RIGHT_TO_LEFT_MARK); + static_strcat(display_msg, letter_name); if (drive_letters[k] == (PathGetDriveNumberU(app_dir) + 'A')) remove_drive = 1; if (drive_letters[k] == (PathGetDriveNumberU(system_dir) + 'A')) @@ -941,20 +952,25 @@ BOOL GetDevices(DWORD devnum) safe_free(devint_detail_data); break; } - safe_sprintf(&entry_msg[strlen(entry_msg)], sizeof(entry_msg) - strlen(entry_msg), + safe_sprintf(&display_msg[strlen(display_msg)], sizeof(display_msg) - strlen(display_msg), "%s [%s]", (right_to_left_mode)?RIGHT_TO_LEFT_MARK:"", SizeToHumanReadable(GetDriveSize(drive_index), FALSE, use_fake_units)); - entry = entry_msg; + display_name = display_msg; } - // Must ensure that the combo box is UNSORTED for indexes to be the same - StrArrayAdd(&DriveId, device_instance_id, TRUE); - StrArrayAdd(&DriveName, buffer, TRUE); - StrArrayAdd(&DriveLabel, label, TRUE); - if ((hub_path != NULL) && (StrArrayAdd(&DriveHub, hub_path, TRUE) >= 0)) - DrivePort[DriveHub.Index - 1] = props.port; - - IGNORE_RETVAL(ComboBox_SetItemData(hDeviceList, ComboBox_AddStringU(hDeviceList, entry), drive_index)); - maxwidth = max(maxwidth, GetEntryWidth(hDeviceList, entry)); + rufus_drive[num_drives].index = drive_index; + rufus_drive[num_drives].id = safe_strdup(device_instance_id); + rufus_drive[num_drives].name = safe_strdup(buffer); + rufus_drive[num_drives].display_name = safe_strdup(display_name); + rufus_drive[num_drives].label = safe_strdup(label); + rufus_drive[num_drives].size = GetDriveSize(drive_index); + assert(rufus_drive[num_drives].size != 0); + if (hub_path != NULL) { + rufus_drive[num_drives].hub = safe_strdup(hub_path); + rufus_drive[num_drives].port = props.port; + } + num_drives++; + if (num_drives >= MAX_DRIVES) + uprintf("Warning: Found more than %d drives - ignoring remaining ones...", MAX_DRIVES); safe_free(devint_detail_data); break; } @@ -962,6 +978,30 @@ BOOL GetDevices(DWORD devnum) } SetupDiDestroyDeviceInfoList(dev_info); + // Reorder the drives by increasing size, using the "selection sort" algorithm + for (u = 0; u < num_drives - 1; u++) { + uint64_t min_drive_size = rufus_drive[u].size; + int min_index = u; + for (v = u + 1; v < num_drives; v++) { + if (rufus_drive[v].size < min_drive_size) { + min_drive_size = rufus_drive[v].size; + min_index = v; + } + } + if (min_index != u) { + RUFUS_DRIVE tmp; + memcpy(&tmp, &rufus_drive[u], sizeof(RUFUS_DRIVE)); + memcpy(&rufus_drive[u], &rufus_drive[min_index], sizeof(RUFUS_DRIVE)); + memcpy(&rufus_drive[min_index], &tmp, sizeof(RUFUS_DRIVE)); + } + } + + // Now populate the drive combo box + // NB: The combo box must have the UNSORTED attribute for indexes to remain the ones we assign + for (u = 0; u < num_drives; u++) { + IGNORE_RETVAL(ComboBox_SetItemData(hDeviceList, ComboBox_AddStringU(hDeviceList, rufus_drive[u].display_name), rufus_drive[u].index)); + maxwidth = max(maxwidth, GetEntryWidth(hDeviceList, rufus_drive[u].display_name)); + } // Adjust the Dropdown width to the maximum text size SendMessage(hDeviceList, CB_SETDROPPEDWIDTH, (WPARAM)maxwidth, 0); diff --git a/src/drive.h b/src/drive.h index 1a6be225..16caa367 100644 --- a/src/drive.h +++ b/src/drive.h @@ -413,6 +413,7 @@ BOOL RefreshDriveLayout(HANDLE hDrive); const char* GetMBRPartitionType(const uint8_t type); const char* GetGPTPartitionType(const GUID* guid); const char* GetExtFsLabel(DWORD DriveIndex, uint64_t PartitionOffset); +void ClearDrives(void); BOOL GetDevices(DWORD devnum); BOOL CyclePort(int index); int CycleDevice(int index); diff --git a/src/rufus.c b/src/rufus.c index a1fa5528..382a7034 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -108,7 +108,7 @@ HWND hMainDialog, hMultiToolbar, hSaveToolbar, hHashToolbar, hAdvancedDeviceTool HFONT hInfoFont; uint8_t image_options = IMOP_WINTOGO; uint16_t rufus_version[3], embedded_sl_version[2]; -uint32_t dur_mins, dur_secs, DrivePort[MAX_DRIVES];; +uint32_t dur_mins, dur_secs; loc_cmd* selected_locale = NULL; WORD selected_langid = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT); DWORD MainThreadId; @@ -134,10 +134,11 @@ char embedded_sl_version_ext[2][32]; char ClusterSizeLabel[MAX_CLUSTER_SIZES][64]; char msgbox[1024], msgbox_title[32], *ini_file = NULL, *image_path = NULL, *short_image_path; char *archive_path = NULL, image_option_txt[128], *fido_url = NULL; -StrArray DriveId, DriveName, DriveLabel, DriveHub, BlockingProcess, ImageList; +StrArray BlockingProcess, ImageList; // Number of steps for each FS for FCC_STRUCTURE_PROGRESS const int nb_steps[FS_MAX] = { 5, 5, 12, 1, 10, 1, 1, 1, 1 }; const char* flash_type[BADLOCKS_PATTERN_TYPES] = { "SLC", "MLC", "TLC" }; +RUFUS_DRIVE rufus_drive[MAX_DRIVES] = { 0 }; // TODO: Remember to update copyright year in stdlg's AboutCallback() WM_INITDIALOG, // localization_data.sh and the .rc when the year changes! @@ -727,11 +728,11 @@ static void SetProposedLabel(int ComboIndex) } // Else if no existing label is available, propose one according to the size (eg: "256MB", "8GB") - if ((_stricmp(no_label, DriveLabel.String[ComboIndex]) == 0) || (_stricmp(no_label, empty) == 0) - || (safe_stricmp(lmprintf(MSG_207), DriveLabel.String[ComboIndex]) == 0)) { + if ((_stricmp(no_label, rufus_drive[ComboIndex].label) == 0) || (_stricmp(no_label, empty) == 0) + || (safe_stricmp(lmprintf(MSG_207), rufus_drive[ComboIndex].label) == 0)) { SetWindowTextU(hLabel, SelectedDrive.proposed_label); } else { - SetWindowTextU(hLabel, DriveLabel.String[ComboIndex]); + SetWindowTextU(hLabel, rufus_drive[ComboIndex].label); } } @@ -944,14 +945,14 @@ static BOOL PopulateProperties(void) SizeToHumanReadable(SelectedDrive.DiskSize, FALSE, TRUE)); // Add a tooltip (with the size of the device in parenthesis) - device_tooltip = (char*) malloc(safe_strlen(DriveName.String[device_index]) + 32); + device_tooltip = (char*) malloc(safe_strlen(rufus_drive[device_index].name) + 32); if (device_tooltip != NULL) { if (right_to_left_mode) - safe_sprintf(device_tooltip, safe_strlen(DriveName.String[device_index]) + 32, "(%s) %s", - SizeToHumanReadable(SelectedDrive.DiskSize, FALSE, FALSE), DriveName.String[device_index]); + safe_sprintf(device_tooltip, safe_strlen(rufus_drive[device_index].name) + 32, "(%s) %s", + SizeToHumanReadable(SelectedDrive.DiskSize, FALSE, FALSE), rufus_drive[device_index].name); else - safe_sprintf(device_tooltip, safe_strlen(DriveName.String[device_index]) + 32, "%s (%s)", - DriveName.String[device_index], SizeToHumanReadable(SelectedDrive.DiskSize, FALSE, FALSE)); + safe_sprintf(device_tooltip, safe_strlen(rufus_drive[device_index].name) + 32, "%s (%s)", + rufus_drive[device_index].name, SizeToHumanReadable(SelectedDrive.DiskSize, FALSE, FALSE)); CreateTooltip(hDeviceList, device_tooltip, -1); free(device_tooltip); } @@ -1951,10 +1952,6 @@ static void InitDialog(HWND hDlg) IGNORE_RETVAL(ComboBox_SetCurSel(hDiskID, 0)); // Create the string arrays - StrArrayCreate(&DriveId, MAX_DRIVES); - StrArrayCreate(&DriveName, MAX_DRIVES); - StrArrayCreate(&DriveLabel, MAX_DRIVES); - StrArrayCreate(&DriveHub, MAX_DRIVES); StrArrayCreate(&BlockingProcess, 16); StrArrayCreate(&ImageList, 16); // Set various checkboxes @@ -2031,7 +2028,7 @@ static void SaveVHD(void) if ((DriveIndex < 0) || (format_thread != NULL)) return; - static_sprintf(filename, "%s.vhd", DriveLabel.String[DriveIndex]); + static_sprintf(filename, "%s.vhd", rufus_drive[DriveIndex].label); img_save.Type = IMG_SAVE_TYPE_VHD; img_save.DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, DriveIndex); img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, 0); @@ -2317,10 +2314,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA if (ulRegister != 0) SHChangeNotifyDeregister(ulRegister); PostQuitMessage(0); - StrArrayDestroy(&DriveId); - StrArrayDestroy(&DriveName); - StrArrayDestroy(&DriveLabel); - StrArrayDestroy(&DriveHub); + ClearDrives(); StrArrayDestroy(&BlockingProcess); StrArrayDestroy(&ImageList); DestroyAllTooltips(); diff --git a/src/rufus.h b/src/rufus.h index 2fbe30f7..e78809ca 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -401,6 +401,17 @@ typedef struct { #define SL_MAJOR(x) ((uint8_t)((x)>>8)) #define SL_MINOR(x) ((uint8_t)(x)) +typedef struct { + char* id; + char* name; + char* display_name; + char* label; + char* hub; + DWORD index; + uint32_t port; + uint64_t size; +} RUFUS_DRIVE; + typedef struct { uint16_t version[3]; uint32_t platform_min[2]; // minimum platform version required diff --git a/src/rufus.rc b/src/rufus.rc index 33e20afa..4b93971e 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 3.19.1890" +CAPTION "Rufus 3.19.1891" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -395,8 +395,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,19,1890,0 - PRODUCTVERSION 3,19,1890,0 + FILEVERSION 3,19,1891,0 + PRODUCTVERSION 3,19,1891,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -414,13 +414,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.19.1890" + VALUE "FileVersion", "3.19.1891" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2022 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-3.19.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.19.1890" + VALUE "ProductVersion", "3.19.1891" END END BLOCK "VarFileInfo"