diff --git a/res/loc/rufus.loc b/res/loc/rufus.loc index d60b1ace..96529de4 100644 --- a/res/loc/rufus.loc +++ b/res/loc/rufus.loc @@ -330,6 +330,8 @@ t MSG_126 "Set the partition size units." t MSG_127 "Do not show this message again" t MSG_128 "Important notice about Secure Boot" t MSG_129 "You have just created a media that uses the UEFI:NTFS bootloader. Please remember that, to boot this media, YOU MUST DISABLE SECURE BOOT.\nFor details on why this is necessary, see the 'More Information' button below." +t MSG_130 "Windows image selection" +t MSG_131 "This ISO contains multiple Windows images.\nPlease select the one you wish to use for installation:" t MSG_150 "Type of computer you plan to use this bootable drive with. It is your responsibility to determine whether " "your target is of BIOS or UEFI type before you start creating the drive, as it may fail to boot otherwise." # You shouldn't translate 'Legacy Mode' as this is an option that usually appears in English in the UEFI settings. diff --git a/src/format.c b/src/format.c index 65f63330..3d896b17 100644 --- a/src/format.c +++ b/src/format.c @@ -61,7 +61,7 @@ static float format_percent = 0.0f; static int task_number = 0; extern const int nb_steps[FS_MAX]; extern uint32_t dur_mins, dur_secs; -static int fs_index = 0, wintogo_index = -1; +static int fs_index = 0, wintogo_index = -1, wininst_index = 0; extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive, fast_zeroing, enable_file_indexing, write_as_image; uint8_t *grub2_buf = NULL; long grub2_len; @@ -1298,30 +1298,45 @@ out: return r; } -// Checks which versions of Windows are available in an install.wim image +// Checks which versions of Windows are available in an install image // to set our extraction index. Asks the user to select one if needed. // Returns -2 on user cancel, -1 on other error, >=0 on success. int SetWinToGoIndex(void) { char *mounted_iso, *build, image[128]; char tmp_path[MAX_PATH] = "", xml_file[MAX_PATH] = ""; + char *install_names[MAX_WININST]; StrArray version_name, version_index; int i, build_nr = 0; BOOL bNonStandard = FALSE; // Sanity checks wintogo_index = -1; + wininst_index = 0; if ((nWindowsVersion < WINDOWS_8) || ((WimExtractCheck() & 4) == 0) || (ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem)) != FS_NTFS)) { - return FALSE; + return -1; } + + // If we have multiple windows install images, ask the user the one to use + if (img_report.wininst_index > 1) { + for (i = 0; i < img_report.wininst_index; i++) + install_names[i] = &img_report.wininst_path[i][2]; + wininst_index = SelectionDialog(lmprintf(MSG_130), lmprintf(MSG_131), install_names, img_report.wininst_index); + if (wininst_index < 0) + return -2; + wininst_index--; + if ((wininst_index < 0) || (wininst_index >= MAX_WININST)) + wininst_index = 0; + } + // Mount the install.wim image, that resides on the ISO mounted_iso = MountISO(image_path); if (mounted_iso == NULL) { uprintf("Could not mount ISO for Windows To Go selection"); return FALSE; } - static_sprintf(image, "%s%s", mounted_iso, &img_report.install_wim_path[2]); + static_sprintf(image, "%s%s", mounted_iso, &img_report.wininst_path[wininst_index][2]); // Now take a look at the XML file in install.wim to list our versions if ((GetTempPathU(sizeof(tmp_path), tmp_path) == 0) @@ -1335,7 +1350,7 @@ int SetWinToGoIndex(void) // Must use the Windows WIM API as 7z messes up the XML if (!WimExtractFile_API(image, 0, "[1].xml", xml_file)) { - uprintf("Failed to acquire WIM index"); + uprintf("Could not acquire WIM index"); goto out; } @@ -1428,7 +1443,7 @@ static BOOL SetupWinToGo(const char* drive_name, BOOL use_ms_efi) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT); return FALSE; } - static_sprintf(image, "%s%s", mounted_iso, &img_report.install_wim_path[2]); + static_sprintf(image, "%s%s", mounted_iso, &img_report.wininst_path[wininst_index][2]); uprintf("Mounted ISO as '%s'", mounted_iso); // Now we use the WIM API to apply that image @@ -2112,7 +2127,7 @@ DWORD WINAPI FormatThread(void* param) // EFI mode selected, with no 'boot###.efi' but Windows 7 x64's 'bootmgr.efi' (bit #0) if ((tt == TT_UEFI) && HAS_WIN7_EFI(img_report)) { PrintInfoDebug(0, MSG_232); - img_report.install_wim_path[0] = drive_name[0]; + img_report.wininst_path[0][0] = drive_name[0]; efi_dst[0] = drive_name[0]; efi_dst[sizeof(efi_dst) - sizeof("\\bootx64.efi")] = 0; if (!CreateDirectoryA(efi_dst, 0)) { @@ -2120,7 +2135,7 @@ DWORD WINAPI FormatThread(void* param) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH); } else { efi_dst[sizeof(efi_dst) - sizeof("\\bootx64.efi")] = '\\'; - if (!WimExtractFile(img_report.install_wim_path, 1, "Windows\\Boot\\EFI\\bootmgfw.efi", efi_dst)) { + if (!WimExtractFile(img_report.wininst_path[0], 1, "Windows\\Boot\\EFI\\bootmgfw.efi", efi_dst)) { uprintf("Failed to setup Win7 EFI boot\n"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH); } diff --git a/src/iso.c b/src/iso.c index 9892e657..e4b48ada 100644 --- a/src/iso.c +++ b/src/iso.c @@ -77,8 +77,8 @@ 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_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" }; +static const char* sources_str = "/sources"; +static const char* wininst_name[] = { "install.wim", "install.esd", "install.swm" }; // We only support GRUB/BIOS (x86) that uses a standard config dir (/boot/grub/i386-pc/) // If the disc was mastered properly, GRUB/EFI will take care of itself static const char* grub_dirname = "/boot/grub/i386-pc"; @@ -223,11 +223,16 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t file_length, const img_report.has_efi |= (2<> 24) & 0xff, - (img_report.install_wim_version >> 16) & 0xff, (img_report.install_wim_version >> 8) & 0xff); - // Microsoft somehow managed to make their ESD WIMs incompatible with their own APIs - // (yes, EVEN the Windows 10 APIs), so we must filter them out... - if (img_report.install_wim_version >= MAX_WIM_VERSION) - uprintf(" Note: This WIM version is NOT compatible with Windows To Go"); + if (HAS_WININST(img_report)) { + inst_str[3] = '0' + img_report.wininst_index; + uprintf(" Uses: Install.%s%s (version %d.%d.%d%s)", &img_report.wininst_path[0][strlen(img_report.wininst_path[0]) - 3], + (img_report.wininst_index > 1) ? inst_str : "", (img_report.wininst_version >> 24) & 0xff, + (img_report.wininst_version >> 16) & 0xff, (img_report.wininst_version >> 8) & 0xff, + (img_report.wininst_version >= SPECIAL_WIM_VERSION) ? "+": ""); } PRINT_ISO_PROP(img_report.has_symlinks, " Note: This ISO uses symbolic links, which will not be replicated due to file system limitations."); PRINT_ISO_PROP(img_report.has_symlinks, " Because of this, some features from this image may not work..."); @@ -1196,7 +1196,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param) (!HAS_SYSLINUX(img_report) || (SL_MAJOR(img_report.sl_version) <= 5))) || ((IS_FAT(fs)) && (!HAS_SYSLINUX(img_report)) && (!allow_dual_uefi_bios) && !IS_EFI_BOOTABLE(img_report) && (!HAS_REACTOS(img_report)) && !HAS_KOLIBRIOS(img_report) && (!HAS_GRUB(img_report))) - || ((IS_FAT(fs)) && (HAS_WINDOWS(img_report) || HAS_INSTALL_WIM(img_report)) && (!allow_dual_uefi_bios)) ) { + || ((IS_FAT(fs)) && (HAS_WINDOWS(img_report) || HAS_WININST(img_report)) && (!allow_dual_uefi_bios)) ) { // Incompatible FS and ISO MessageBoxExU(hMainDialog, lmprintf(MSG_096), lmprintf(MSG_092), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid); goto out; diff --git a/src/rufus.h b/src/rufus.h index 2246e6ff..6f4f54ca 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -71,6 +71,7 @@ #define MAX_GUID_STRING_LENGTH 40 #define MAX_GPT_PARTITIONS 128 #define MAX_SECTORS_TO_CLEAR 128 // nb sectors to zap when clearing the MBR/GPT (must be >34) +#define MAX_WININST 4 // Max number of install[.wim|.esd] we can handle on an image #define MBR_UEFI_MARKER 0x49464555 // 'U', 'E', 'F', 'I', as a 32 bit little endian longword #define MORE_INFO_URL 0xFFFF #define STATUS_MSG_TIMEOUT 3500 // How long should cheat mode messages appear for on the status bar @@ -287,7 +288,7 @@ enum checksum_type { #define WINPE_I386 0x0007 #define WINPE_AMD64 0x0023 #define WINPE_MININT 0x01C0 -#define MAX_WIM_VERSION 0x000E0000 +#define SPECIAL_WIM_VERSION 0x000E0000 #define HAS_KOLIBRIOS(r) (r.has_kolibrios) #define HAS_REACTOS(r) (r.reactos_path[0] != 0) #define HAS_GRUB(r) ((r.has_grub2) || (r.has_grub4dos)) @@ -295,33 +296,34 @@ enum checksum_type { #define HAS_BOOTMGR_BIOS(r) (r.has_bootmgr) #define HAS_BOOTMGR_EFI(r) (r.has_bootmgr_efi) #define HAS_BOOTMGR(r) (HAS_BOOTMGR_BIOS(r) || HAS_BOOTMGR_EFI(r)) -#define HAS_INSTALL_WIM(r) (r.install_wim_path[0] != 0) +#define HAS_WININST(r) (r.wininst_index != 0) #define HAS_WINPE(r) (((r.winpe & WINPE_I386) == WINPE_I386)||((r.winpe & WINPE_AMD64) == WINPE_AMD64)||((r.winpe & WINPE_MININT) == WINPE_MININT)) #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_WIN7_EFI(r) ((r.has_efi == 1) && HAS_WININST(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 != 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 HAS_WINTOGO(r) (HAS_BOOTMGR(r) && IS_EFI_BOOTABLE(r) && HAS_WININST(r)) #define HAS_PERSISTENCE(r) (r.has_casper) #define IS_FAT(fs) ((fs == FS_FAT16) || (fs == FS_FAT32)) typedef struct { - char label[192]; /* 3*64 to account for UTF-8 */ - char usb_label[192]; /* converted USB label for workaround */ - 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 */ + char label[192]; // 3*64 to account for UTF-8 + char usb_label[192]; // converted USB label for workaround + 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 wininst_path[MAX_WININST][64]; // path to the Windows install image(s) + char efi_img_path[128]; // path to an efi.img file uint64_t image_size; uint64_t projected_size; int64_t mismatch_size; - uint32_t install_wim_version; + uint32_t wininst_version; BOOLEAN is_iso; BOOLEAN is_bootable_img; uint16_t winpe; uint8_t has_efi; + uint8_t wininst_index; BOOLEAN has_4GB_file; BOOLEAN has_long_filename; BOOLEAN has_symlinks; diff --git a/src/rufus.rc b/src/rufus.rc index 9dc531a6..911c5e71 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.5.1436" +CAPTION "Rufus 3.5.1437" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -394,8 +394,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,5,1436,0 - PRODUCTVERSION 3,5,1436,0 + FILEVERSION 3,5,1437,0 + PRODUCTVERSION 3,5,1437,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -413,13 +413,13 @@ BEGIN VALUE "Comments", "https://akeo.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.5.1436" + VALUE "FileVersion", "3.5.1437" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2018 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus-3.5.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.5.1436" + VALUE "ProductVersion", "3.5.1437" END END BLOCK "VarFileInfo" diff --git a/src/vhd.c b/src/vhd.c index 8664eea5..005b1058 100644 --- a/src/vhd.c +++ b/src/vhd.c @@ -86,8 +86,9 @@ typedef struct vhd_footer { #pragma pack(pop) // WIM API Prototypes -#define WIM_GENERIC_READ GENERIC_READ -#define WIM_OPEN_EXISTING OPEN_EXISTING +#define WIM_GENERIC_READ GENERIC_READ +#define WIM_OPEN_EXISTING OPEN_EXISTING +#define WIM_UNDOCUMENTED_BULLSHIT 0x20000000 PF_TYPE_DECL(WINAPI, HANDLE, WIMCreateFile, (PWSTR, DWORD, DWORD, DWORD, DWORD, PDWORD)); PF_TYPE_DECL(WINAPI, BOOL, WIMSetTemporaryPath, (HANDLE, PWSTR)); PF_TYPE_DECL(WINAPI, HANDLE, WIMLoadImage, (HANDLE, DWORD)); @@ -396,7 +397,12 @@ BOOL WimExtractFile_API(const char* image, int index, const char* src, const cha goto out; } - hWim = pfWIMCreateFile(wimage, WIM_GENERIC_READ, WIM_OPEN_EXISTING, 0, 0, &dw); + // Thanks to dism++ for figuring out that you can use UNDOCUMENTED FLAG 0x20000000 + // to open newer install.wim/install.esd images, without running into obnoxious error: + // [0x0000000B] An attempt was made to load a program with an incorrect format. + // No thanks to Microsoft for NOT DOCUMENTING THEIR UTTER BULLSHIT with the WIM API! + hWim = pfWIMCreateFile(wimage, WIM_GENERIC_READ, WIM_OPEN_EXISTING, + (img_report.wininst_version >= SPECIAL_WIM_VERSION) ? WIM_UNDOCUMENTED_BULLSHIT : 0, 0, NULL); if (hWim == NULL) { uprintf(" Could not access image: %s", WindowsErrorString()); goto out; @@ -643,7 +649,6 @@ DWORD WINAPI WimProgressCallback(DWORD dwMsgId, WPARAM wParam, LPARAM lParam, PV static DWORD WINAPI WimApplyImageThread(LPVOID param) { BOOL r = FALSE; - DWORD dw = 0; HANDLE hWim = NULL; HANDLE hImage = NULL; wchar_t wtemp[MAX_PATH] = {0}; @@ -670,7 +675,8 @@ static DWORD WINAPI WimApplyImageThread(LPVOID param) goto out; } - hWim = pfWIMCreateFile(wimage, WIM_GENERIC_READ, WIM_OPEN_EXISTING, 0, 0, &dw); + hWim = pfWIMCreateFile(wimage, WIM_GENERIC_READ, WIM_OPEN_EXISTING, + (img_report.wininst_version >= SPECIAL_WIM_VERSION) ? WIM_UNDOCUMENTED_BULLSHIT : 0, 0, NULL); if (hWim == NULL) { uprintf(" Could not access image: %s", WindowsErrorString()); goto out;