From 5d371088cb00d34e1193ad64dc34b6dc0ece2304 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 9 Aug 2017 16:27:11 +0100 Subject: [PATCH] [iso] add EFI boot support from 'efi.img' FAT images * Required to support Debian Live 9.1 in ISO mode * Note that this only works if the efi.img boot files do not require additional content besides the one extracted from the ISO. --- src/format.c | 2 +- src/iso.c | 276 +++++++++++++++++++++++++++++++++++++++-------- src/msapi_utf8.h | 21 ++-- src/rufus.c | 9 +- src/rufus.h | 5 +- src/rufus.rc | 10 +- 6 files changed, 263 insertions(+), 60 deletions(-) diff --git a/src/format.c b/src/format.c index 475bc05f..731f1408 100644 --- a/src/format.c +++ b/src/format.c @@ -2042,7 +2042,7 @@ DWORD WINAPI FormatThread(void* param) efi_dst[0] = drive_name[0]; efi_dst[sizeof(efi_dst) - sizeof("\\bootx64.efi")] = 0; if (!CreateDirectoryA(efi_dst, 0)) { - uprintf("Could not create directory '%s': %s\n", WindowsErrorString()); + uprintf("Could not create directory '%s': %s\n", efi_dst, WindowsErrorString()); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH); } else { efi_dst[sizeof(efi_dst) - sizeof("\\bootx64.efi")] = '\\'; diff --git a/src/iso.c b/src/iso.c index 2b468c8c..bf4bb340 100644 --- a/src/iso.c +++ b/src/iso.c @@ -39,6 +39,7 @@ #include #include "rufus.h" +#include "libfat.h" #include "missing.h" #include "resource.h" #include "msapi_utf8.h" @@ -73,6 +74,7 @@ static const char* grldr_name = "grldr"; static const char* ldlinux_name = "ldlinux.sys"; static const char* ldlinux_c32 = "ldlinux.c32"; static const char* efi_dirname = "/efi/boot"; +static const char* efi_img_name = "efi.img"; // Used by Debian Live ISOHybrids static const char* efi_bootname[] = { "bootia32.efi", "bootia64.efi", "bootx64.efi", "bootarm.efi", "bootaa64.efi", "bootebc.efi" }; static const char* install_wim_path = "/sources"; static const char* install_wim_name[] = { "install.wim", "install.swm" }; @@ -202,6 +204,10 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t i_file_length, cons if ((img_report.reactos_path[0] == 0) && (safe_stricmp(psz_basename, reactos_name) == 0)) safe_strcpy(img_report.reactos_path, sizeof(img_report.reactos_path), psz_fullpath); + // Check for the first 'efi.img' we can find (that hopefully contains EFI boot files) + if (!HAS_EFI_IMG(img_report) && (safe_stricmp(psz_basename, efi_img_name) == 0)) + safe_strcpy(img_report.efi_img_path, sizeof(img_report.efi_img_path), psz_fullpath); + // Check for the EFI boot entries if (safe_stricmp(psz_dirname, efi_dirname) == 0) { for (i=0; i create a new one - if (fd == NULL) { - uprintf("Unable to create %s - booting from USB will not work", path); - r = 1; - } else { - fprintf(fd, "DEFAULT loadconfig\n\nLABEL loadconfig\n CONFIG %s\n", img_report.cfg_path); - for (i=safe_strlen(img_report.cfg_path); (i>0)&&(img_report.cfg_path[i]!='/'); i--); - if (i>0) { - img_report.cfg_path[i] = 0; - fprintf(fd, " APPEND %s/\n", img_report.cfg_path); - img_report.cfg_path[i] = '/'; - } - uprintf("Created: %s", path); + } else { + // For Debian live ISOs, that only provide EFI boot files in a FAT efi.img + if (img_report.has_efi == 0x80) + ExtractEfiImgFiles(dest_dir); + if (HAS_SYSLINUX(img_report)) { + safe_sprintf(path, sizeof(path), "%s\\syslinux.cfg", dest_dir); + // Create a /syslinux.cfg (if none exists) that points to the existing isolinux cfg + fd = fopen(path, "r"); + if (fd != NULL && img_report.needs_syslinux_overwrite) { + fclose(fd); + fd = NULL; + safe_sprintf(path2, sizeof(path2), "%s\\syslinux.org", dest_dir); + uprintf("Renaming: %s ➔ %s", path, path2); + IGNORE_RETVAL(rename(path, path2)); } + if (fd == NULL) { + fd = fopen(path, "w"); // No "/syslinux.cfg" => create a new one + if (fd == NULL) { + uprintf("Unable to create %s - booting from USB will not work", path); + r = 1; + } else { + fprintf(fd, "DEFAULT loadconfig\n\nLABEL loadconfig\n CONFIG %s\n", img_report.cfg_path); + for (i = safe_strlen(img_report.cfg_path); (i > 0) && (img_report.cfg_path[i] != '/'); i--); + if (i > 0) { + img_report.cfg_path[i] = 0; + fprintf(fd, " APPEND %s/\n", img_report.cfg_path); + img_report.cfg_path[i] = '/'; + } + uprintf("Created: %s", path); + } + } + if (fd != NULL) + fclose(fd); } - if (fd != NULL) - fclose(fd); } if (p_iso != NULL) iso9660_close(p_iso); @@ -945,7 +959,7 @@ int64_t ExtractISOFile(const char* iso, const char* iso_file, const char* dest_f file_handle = CreateFileU(dest_file, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, attributes, NULL); if (file_handle == INVALID_HANDLE_VALUE) { - uprintf(" Unable to create file %s: %s\n", dest_file, WindowsErrorString()); + uprintf(" Could not create file %s: %s", dest_file, WindowsErrorString()); goto out; } @@ -956,12 +970,12 @@ int64_t ExtractISOFile(const char* iso, const char* iso_file, const char* dest_f p_udf_root = udf_get_root(p_udf, true, 0); if (p_udf_root == NULL) { - uprintf("Could not locate UDF root directory\n"); + uprintf("Could not locate UDF root directory"); goto out; } p_udf_file = udf_fopen(p_udf_root, iso_file); if (!p_udf_file) { - uprintf("Could not locate file %s in ISO image\n", iso_file); + uprintf("Could not locate file %s in ISO image", iso_file); goto out; } file_length = udf_get_file_length(p_udf_file); @@ -969,12 +983,12 @@ int64_t ExtractISOFile(const char* iso, const char* iso_file, const char* dest_f memset(buf, 0, UDF_BLOCKSIZE); read_size = udf_read_block(p_udf_file, buf, 1); if (read_size < 0) { - uprintf("Error reading UDF file %s\n", iso_file); + uprintf("Error reading UDF file %s", iso_file); goto out; } buf_size = (DWORD)MIN(file_length, read_size); if (!WriteFileWithRetry(file_handle, buf, buf_size, &wr_size, WRITE_RETRIES)) { - uprintf(" Error writing file %s: %s\n", dest_file, WindowsErrorString()); + uprintf(" Error writing file %s: %s", dest_file, WindowsErrorString()); goto out; } file_length -= read_size; @@ -985,13 +999,13 @@ int64_t ExtractISOFile(const char* iso, const char* iso_file, const char* dest_f try_iso: p_iso = iso9660_open(iso); if (p_iso == NULL) { - uprintf("Unable to open image '%s'.\n", iso); + uprintf("Unable to open image '%s'", iso); goto out; } p_statbuf = iso9660_ifs_stat_translate(p_iso, iso_file); if (p_statbuf == NULL) { - uprintf("Could not get ISO-9660 file information for file %s\n", iso_file); + uprintf("Could not get ISO-9660 file information for file %s", iso_file); goto out; } @@ -1000,12 +1014,12 @@ try_iso: memset(buf, 0, ISO_BLOCKSIZE); lsn = p_statbuf->lsn + (lsn_t)i; if (iso9660_iso_seek_read(p_iso, buf, lsn, 1) != ISO_BLOCKSIZE) { - uprintf(" Error reading ISO9660 file %s at LSN %lu\n", iso_file, (long unsigned int)lsn); + uprintf(" Error reading ISO9660 file %s at LSN %lu", iso_file, (long unsigned int)lsn); goto out; } buf_size = (DWORD)MIN(file_length, ISO_BLOCKSIZE); if (!WriteFileWithRetry(file_handle, buf, buf_size, &wr_size, WRITE_RETRIES)) { - uprintf(" Error writing file %s: %s\n", dest_file, WindowsErrorString()); + uprintf(" Error writing file %s: %s", dest_file, WindowsErrorString()); goto out; } file_length -= ISO_BLOCKSIZE; @@ -1052,16 +1066,16 @@ uint32_t GetInstallWimVersion(const char* iso) p_udf_root = udf_get_root(p_udf, true, 0); if (p_udf_root == NULL) { - uprintf("Could not locate UDF root directory\n"); + uprintf("Could not locate UDF root directory"); goto out; } p_udf_file = udf_fopen(p_udf_root, wim_path); if (!p_udf_file) { - uprintf("Could not locate file %s in ISO image\n", wim_path); + uprintf("Could not locate file %s in ISO image", wim_path); goto out; } if (udf_read_block(p_udf_file, buf, 1) != UDF_BLOCKSIZE) { - uprintf("Error reading UDF file %s\n", wim_path); + uprintf("Error reading UDF file %s", wim_path); goto out; } r = wim_header[3]; @@ -1070,16 +1084,16 @@ uint32_t GetInstallWimVersion(const char* iso) try_iso: p_iso = iso9660_open(iso); if (p_iso == NULL) { - uprintf("Unable to open image '%s'.\n", iso); + uprintf("Could not open image '%s'", iso); goto out; } p_statbuf = iso9660_ifs_stat_translate(p_iso, wim_path); if (p_statbuf == NULL) { - uprintf("Could not get ISO-9660 file information for file %s\n", wim_path); + uprintf("Could not get ISO-9660 file information for file %s", wim_path); goto out; } if (iso9660_iso_seek_read(p_iso, buf, p_statbuf->lsn, 1) != ISO_BLOCKSIZE) { - uprintf("Error reading ISO9660 file %s at LSN %lu\n", wim_path, (long unsigned int)p_statbuf->lsn); + uprintf("Error reading ISO-9660 file %s at LSN %lu", wim_path, (long unsigned int)p_statbuf->lsn); goto out; } r = wim_header[3]; @@ -1100,6 +1114,184 @@ out: return bswap_uint32(r); } +#define ISO_NB_BLOCKS 16 +typedef struct { + iso9660_t* p_iso; + lsn_t lsn; + libfat_sector_t sec_start; + // Use a multi block buffer, to improve sector reads + uint8_t buf[ISO_BLOCKSIZE * ISO_NB_BLOCKS]; +} iso9660_readfat_private; + +/* + * Read sectors from a FAT img file residing on an ISO-9660 filesystem. + * NB: This assumes that the img file sectors are contiguous on the ISO. + */ +int iso9660_readfat(intptr_t pp, void *buf, size_t secsize, libfat_sector_t sec) +{ + iso9660_readfat_private* p_private = (iso9660_readfat_private*)pp; + + if (sizeof(p_private->buf) % secsize != 0) { + uprintf("iso9660_readfat: Sector size %d is not a divisor of %d", secsize, sizeof(p_private->buf)); + return 0; + } + + if ((sec < p_private->sec_start) || (sec >= p_private->sec_start + sizeof(p_private->buf) / secsize)) { + // Sector being queried is not in our multi block buffer -> Update it + p_private->sec_start = (((sec * secsize) / ISO_BLOCKSIZE) * ISO_BLOCKSIZE) / secsize; + if (iso9660_iso_seek_read(p_private->p_iso, p_private->buf, + p_private->lsn + (lsn_t)((p_private->sec_start * secsize) / ISO_BLOCKSIZE), ISO_NB_BLOCKS) + != ISO_NB_BLOCKS * ISO_BLOCKSIZE) { + uprintf("Error reading ISO-9660 file %s at LSN %lu\n", img_report.efi_img_path, + (long unsigned int)(p_private->lsn + (p_private->sec_start * secsize) / ISO_BLOCKSIZE)); + return 0; + } + } + memcpy(buf, &p_private->buf[(sec - p_private->sec_start)*secsize], secsize); + return (int)secsize; +} + +/* + * Extract EFI bootloaders files from an ISO-9660 FAT img file into directory . + * If is NULL, returns TRUE if an EFI bootloader exists in the img. + * If is not NULL, returns TRUE if any if the bootloaders was properly written. + */ +BOOL ExtractEfiImgFiles(const char* dir) +{ + BOOL ret = FALSE; + HANDLE handle; + DWORD size, file_size, written; + iso9660_t* p_iso = NULL; + iso9660_stat_t* p_statbuf = NULL; + iso9660_readfat_private* p_private = NULL; + libfat_sector_t s; + int32_t dc, c; + struct libfat_filesystem *fs; + struct libfat_direntry direntry; + char name[12] = { 0 }; + char path[64]; + int i, j, k; + void* buf; + + if ((image_path == NULL) || !HAS_EFI_IMG(img_report)) + return FALSE; + + p_iso = iso9660_open(image_path); + if (p_iso == NULL) { + uprintf("Could not open image '%s' as an ISO-9660 file system", image_path); + goto out; + } + p_statbuf = iso9660_ifs_stat_translate(p_iso, img_report.efi_img_path); + if (p_statbuf == NULL) { + uprintf("Could not get ISO-9660 file information for file %s\n", img_report.efi_img_path); + goto out; + } + p_private = malloc(sizeof(iso9660_readfat_private)); + if (p_private == NULL) + goto out; + p_private->p_iso = p_iso; + p_private->lsn = p_statbuf->lsn; + p_private->sec_start = 0; + // Populate our intial buffer + if (iso9660_iso_seek_read(p_private->p_iso, p_private->buf, p_private->lsn, ISO_NB_BLOCKS) != ISO_NB_BLOCKS * ISO_BLOCKSIZE) { + uprintf("Error reading ISO-9660 file %s at LSN %lu\n", img_report.efi_img_path, (long unsigned int)p_private->lsn); + goto out; + } + fs = libfat_open(iso9660_readfat, (intptr_t)p_private); + if (fs == NULL) { + uprintf("FAT access error"); + goto out; + } + + // Navigate to /EFI/BOOT + if (libfat_searchdir(fs, 0, "EFI ", &direntry) < 0) + goto out; + dc = direntry.entry[26] + (direntry.entry[27] << 8); + if (libfat_searchdir(fs, dc, "BOOT ", &direntry) < 0) + goto out; + dc = direntry.entry[26] + (direntry.entry[27] << 8); + + for (i = 0; i < ARRAYSIZE(efi_bootname); i++) { + // Sanity check in case the EFI forum comes up with a 'bootmips64.efi' or something... + if (strlen(efi_bootname[i]) > 12) { + uprintf("Internal error: FAT 8.3"); + continue; + } + for (j = 0, k = 0; efi_bootname[i][j] != 0; j++) { + if (efi_bootname[i][j] == '.') { + while (k < 8) + name[k++] = ' '; + } else + name[k++] = toupper(efi_bootname[i][j]); + } + c = libfat_searchdir(fs, dc, name, &direntry); + if (c > 0) { + if (dir == NULL) { + if (!ret) + uprintf(" Detected EFI bootloader(s) (from '%s'):", img_report.efi_img_path); + uprintf(" ● '%s'", efi_bootname[i]); + ret = TRUE; + } else { + file_size = direntry.entry[28] + (direntry.entry[29] << 8) + (direntry.entry[30] << 16) + + (direntry.entry[31] << 24); + // Sanity check + if (file_size > 64 * MB) { + uprintf("Warning: File size is larger than 64 MB => not extracted"); + continue; + } + static_sprintf(path, "%s\\efi", dir); + if (!CreateDirectoryA(path, 0) && (GetLastError() != ERROR_ALREADY_EXISTS)) { + uprintf("Could not create directory '%s': %s\n", path, WindowsErrorString()); + continue; + } + safe_strcat(path, sizeof(path), "\\boot"); + if (!CreateDirectoryA(path, 0) && (GetLastError() != ERROR_ALREADY_EXISTS)) { + uprintf("Could not create directory '%s': %s\n", path, WindowsErrorString()); + continue; + } + safe_strcat(path, sizeof(path), "\\"); + safe_strcat(path, sizeof(path), efi_bootname[i]); + uprintf("Extracting: %s (from '%s', %s)", path, img_report.efi_img_path, + SizeToHumanReadable(file_size, FALSE, FALSE)); + handle = CreateFileA(path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, + NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); + if (handle == INVALID_HANDLE_VALUE) { + uprintf("Unable to create '%s': %s", path, WindowsErrorString()); + continue; + } + + written = 0; + s = libfat_clustertosector(fs, c); + while ((s != 0) && (s < 0xFFFFFFFFULL) && (written < file_size)) { + buf = libfat_get_sector(fs, s); + size = MIN(LIBFAT_SECTOR_SIZE, file_size - written); + if (!WriteFileWithRetry(handle, buf, size, &size, WRITE_RETRIES) || + (size != MIN(LIBFAT_SECTOR_SIZE, file_size - written))) { + uprintf("Error writing '%s': %s", path, WindowsErrorString()); + CloseHandle(handle); + continue; + } + written += size; + s = libfat_nextsector(fs, s); + } + CloseHandle(handle); + ret = TRUE; + } + } + } + +out: + if (fs != NULL) + libfat_close(fs); + if (p_statbuf != NULL) + safe_free(p_statbuf->rr.psz_symlink); + safe_free(p_statbuf); + safe_free(p_private); + if (p_iso != NULL) + iso9660_close(p_iso); + return ret; +} + // VirtDisk API Prototypes - Only available for Windows 8 or later PF_TYPE_DECL(WINAPI, DWORD, OpenVirtualDisk, (PVIRTUAL_STORAGE_TYPE, PCWSTR, VIRTUAL_DISK_ACCESS_MASK, OPEN_VIRTUAL_DISK_FLAG, POPEN_VIRTUAL_DISK_PARAMETERS, PHANDLE)); diff --git a/src/msapi_utf8.h b/src/msapi_utf8.h index a0b2c0e5..d220fc2e 100644 --- a/src/msapi_utf8.h +++ b/src/msapi_utf8.h @@ -293,6 +293,18 @@ static __inline int LoadStringU(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, i return ret; } +static __inline HMODULE LoadLibraryU(LPCSTR lpFileName) +{ + HMODULE ret; + DWORD err = ERROR_INVALID_DATA; + wconvert(lpFileName); + ret = LoadLibraryW(wlpFileName); + err = GetLastError(); + wfree(lpFileName); + SetLastError(err); + return ret; +} + static __inline int DrawTextU(HDC hDC, LPCSTR lpText, int nCount, LPRECT lpRect, UINT uFormat) { int ret; @@ -1027,15 +1039,6 @@ static __inline BOOL GetVolumeInformationU(LPCSTR lpRootPathName, LPSTR lpVolume return ret; } -static __inline HMODULE LoadLibraryU(LPCSTR lpFileName) -{ - HMODULE h; - wconvert(lpFileName); - h = LoadLibraryW(wlpFileName); - wfree(lpFileName); - return h; -} - #ifdef __cplusplus } #endif diff --git a/src/rufus.c b/src/rufus.c index 2a8def1c..844751c1 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -992,7 +992,10 @@ static void DisplayISOProps(void) PRINT_ISO_PROP(HAS_REACTOS(img_report), " Uses: ReactOS"); PRINT_ISO_PROP(img_report.has_grub4dos, " Uses: Grub4DOS"); PRINT_ISO_PROP(img_report.has_grub2, " Uses: GRUB2"); - PRINT_ISO_PROP(img_report.has_efi, " Uses: EFI %s", HAS_WIN7_EFI(img_report) ? "(win7_x64)" : ""); + if (img_report.has_efi == 0x80) + uprintf(" Uses: EFI (through '%s')", img_report.efi_img_path); + else + PRINT_ISO_PROP(img_report.has_efi, " Uses: EFI %s", HAS_WIN7_EFI(img_report) ? "(win7_x64)" : ""); PRINT_ISO_PROP(HAS_BOOTMGR(img_report), " Uses: Bootmgr"); PRINT_ISO_PROP(HAS_WINPE(img_report), " Uses: WinPE %s", (img_report.uses_minint) ? "(with /minint)" : ""); if (HAS_INSTALL_WIM(img_report)) { @@ -2259,7 +2262,9 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA case WM_COMMAND: #ifdef RUFUS_TEST if (LOWORD(wParam) == IDC_TEST) { - uprintf("Proceed = %s", CheckDriveAccess(2000)?"True":"False"); + ExtractEfiImgFiles("C:\\rufus"); +// ExtractEFI("C:\\rufus\\efi.img", "C:\\rufus\\efi"); +// uprintf("Proceed = %s", CheckDriveAccess(2000)?"True":"False"); // char* choices[] = { "Choice 1", "Choice 2", "Choice 3" }; // SelectionDyn("Test Choice", "Unused", choices, ARRAYSIZE(choices)); break; diff --git a/src/rufus.h b/src/rufus.h index 70094dac..d2cfa677 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -261,8 +261,9 @@ enum checksum_type { #define HAS_WINPE(r) (((r.winpe & WINPE_MININT) == WINPE_MININT)||((r.winpe & WINPE_I386) == WINPE_I386)) #define HAS_WINDOWS(r) (HAS_BOOTMGR(r) || (r.uses_minint) || HAS_WINPE(r)) #define HAS_WIN7_EFI(r) ((r.has_efi == 1) && HAS_INSTALL_WIM(r)) +#define HAS_EFI_IMG(r) (r.efi_img_path[0] != 0) #define IS_DD_BOOTABLE(r) (r.is_bootable_img) -#define IS_EFI_BOOTABLE(r) (r.has_efi) +#define IS_EFI_BOOTABLE(r) (r.has_efi != 0) #define IS_BIOS_BOOTABLE(r) (HAS_BOOTMGR(r) || HAS_SYSLINUX(r) || HAS_WINPE(r) || HAS_GRUB(r) || HAS_REACTOS(r) || HAS_KOLIBRIOS(r)) #define HAS_WINTOGO(r) (HAS_BOOTMGR(r) && IS_EFI_BOOTABLE(r) && HAS_INSTALL_WIM(r) && (r.install_wim_version < MAX_WIM_VERSION)) #define IS_FAT(fs) ((fs == FS_FAT16) || (fs == FS_FAT32)) @@ -273,6 +274,7 @@ typedef struct { char cfg_path[128]; /* path to the ISO's isolinux.cfg */ char reactos_path[128]; /* path to the ISO's freeldr.sys or setupldr.sys */ char install_wim_path[64]; /* path to install.wim or install.swm */ + char efi_img_path[128]; /* path to an efi.img file */ uint64_t image_size; uint64_t projected_size; int64_t mismatch_size; @@ -440,6 +442,7 @@ extern SIZE GetTextSize(HWND hCtrl); extern BOOL ExtractDOS(const char* path); extern BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan); extern int64_t ExtractISOFile(const char* iso, const char* iso_file, const char* dest_file, DWORD attributes); +extern BOOL ExtractEfiImgFiles(const char* dir); extern char* MountISO(const char* path); extern void UnMountISO(void); extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs); diff --git a/src/rufus.rc b/src/rufus.rc index ef7e0799..8389569c 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 242, 376 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 2.16.1173" +CAPTION "Rufus 2.16.1174" FONT 8, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8 @@ -366,8 +366,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 2,16,1173,0 - PRODUCTVERSION 2,16,1173,0 + FILEVERSION 2,16,1174,0 + PRODUCTVERSION 2,16,1174,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -384,13 +384,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "2.16.1173" + VALUE "FileVersion", "2.16.1174" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", " 2011-2017 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "2.16.1173" + VALUE "ProductVersion", "2.16.1174" END END BLOCK "VarFileInfo"