diff --git a/res/togo/san_policy.xml b/res/togo/san_policy.xml deleted file mode 100644 index b85de4dc..00000000 --- a/res/togo/san_policy.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - 4 - - - 4 - - - \ No newline at end of file diff --git a/res/togo/unattend.xml b/res/togo/unattend.xml deleted file mode 100644 index 0f2847d2..00000000 --- a/res/togo/unattend.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - true - - - true - - - \ No newline at end of file diff --git a/src/format.c b/src/format.c index 1b3e7127..33a0ed6d 100644 --- a/src/format.c +++ b/src/format.c @@ -1220,8 +1220,8 @@ out: // 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 *mounted_iso, *build, mounted_image_path[128]; + char xml_file[MAX_PATH] = ""; char *install_names[MAX_WININST]; StrArray version_name, version_index; int i, build_nr = 0; @@ -1230,7 +1230,7 @@ int SetWinToGoIndex(void) // Sanity checks wintogo_index = -1; wininst_index = 0; - if ((nWindowsVersion < WINDOWS_8) || ((WimExtractCheck() & 4) == 0) || + if ((nWindowsVersion < WINDOWS_8) || ((WimExtractCheck(FALSE) & 4) == 0) || (ComboBox_GetCurItemData(hFileSystem) != FS_NTFS)) { return -1; } @@ -1247,18 +1247,18 @@ int SetWinToGoIndex(void) 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; + // If we're not using a straigth install.wim, we need to mount the ISO to access it + if (!img_report.is_windows_img) { + mounted_iso = MountISO(image_path); + if (mounted_iso == NULL) { + uprintf("Could not mount ISO for Windows To Go selection"); + return FALSE; + } + static_sprintf(mounted_image_path, "%s%s", mounted_iso, &img_report.wininst_path[wininst_index][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) - || (GetTempFileNameU(tmp_path, APPLICATION_NAME, 0, xml_file) == 0) - || (xml_file[0] == 0)) { + if ((GetTempFileNameU(temp_dir, APPLICATION_NAME, 0, xml_file) == 0) || (xml_file[0] == 0)) { // Last ditch effort to get a tmp file - just extract it to the current directory static_strcpy(xml_file, ".\\RufVXml.tmp"); } @@ -1266,7 +1266,8 @@ int SetWinToGoIndex(void) DeleteFileU(xml_file); // Must use the Windows WIM API as 7z messes up the XML - if (!WimExtractFile_API(image, 0, "[1].xml", xml_file)) { + if (!WimExtractFile_API(img_report.is_windows_img ? image_path : mounted_image_path, + 0, "[1].xml", xml_file, FALSE)) { uprintf("Could not acquire WIM index"); goto out; } @@ -1328,25 +1329,19 @@ int SetWinToGoIndex(void) out: DeleteFileU(xml_file); - UnMountISO(); + if (!img_report.is_windows_img) + UnMountISO(); return wintogo_index; } // http://technet.microsoft.com/en-ie/library/jj721578.aspx -// As opposed to the technet guide above, we no longer set internal drives offline, -// due to people wondering why they can't see them by default. -//#define SET_INTERNAL_DRIVES_OFFLINE +// As opposed to the technet guide above, we don't set internal drives offline, +// due to people wondering why they can't see them by default and we also use +// bcdedit rather than 'unattend.xml' to disable the recovery environment. static BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp) { -#ifdef SET_INTERNAL_DRIVES_OFFLINE - static char san_policy_path[] = "?:\\san_policy.xml"; -#endif - static char unattend_path[] = "?:\\Windows\\System32\\sysprep\\unattend.xml"; - char *mounted_iso, *ms_efi = NULL, image[128], cmd[MAX_PATH]; - unsigned char *buffer; - DWORD bufsize; + char *mounted_iso, *ms_efi = NULL, mounted_image_path[128], cmd[MAX_PATH]; ULONG cluster_size; - FILE* fd; uprintf("Windows To Go mode selected"); // Additional sanity checks @@ -1355,25 +1350,28 @@ static BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp) return FALSE; } - // First, we need to access 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 installation"); - FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT); - return FALSE; + if (!img_report.is_windows_img) { + mounted_iso = MountISO(image_path); + if (mounted_iso == NULL) { + uprintf("Could not mount ISO for Windows To Go installation"); + FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_ISO_EXTRACT); + return FALSE; + } + static_sprintf(mounted_image_path, "%s%s", mounted_iso, &img_report.wininst_path[wininst_index][2]); + uprintf("Mounted ISO as '%s'", mounted_iso); } - 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 - if (!WimApplyImage(image, wintogo_index, drive_name)) { + if (!WimApplyImage(img_report.is_windows_img ? image_path : mounted_image_path, wintogo_index, drive_name)) { uprintf("Failed to apply Windows To Go image"); if (!IS_ERROR(FormatStatus)) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT); - UnMountISO(); + if (!img_report.is_windows_img) + UnMountISO(); return FALSE; } - UnMountISO(); + if (!img_report.is_windows_img) + UnMountISO(); if (use_esp) { uprintf("Setting up EFI System Partition"); @@ -1406,59 +1404,35 @@ static BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp) } // We invoke the 'bcdboot' command from the host, as the one from the drive produces problems (#558) + // and of course, we couldn't invoke an ARM64 'bcdboot' binary on an x86 host anyway... // Also, since Rufus should (usually) be running as a 32 bit app, on 64 bit systems, we need to use // 'C:\Windows\Sysnative' and not 'C:\Windows\System32' to invoke bcdboot, as 'C:\Windows\System32' // will get converted to 'C:\Windows\SysWOW64' behind the scenes, and there is no bcdboot.exe there. + uprintf("Enabling boot using command:"); static_sprintf(cmd, "%s\\bcdboot.exe %s\\Windows /v /f %s /s %s", sysnative_dir, drive_name, HAS_BOOTMGR_BIOS(img_report) ? (HAS_BOOTMGR_EFI(img_report) ? "ALL" : "BIOS") : "UEFI", (use_esp)?ms_efi:drive_name); - uprintf("Enabling boot using command '%s'", cmd); + uprintf(cmd); if (RunCommand(cmd, sysnative_dir, usb_debug) != 0) { // Try to continue... but report a failure uprintf("Failed to enable boot"); FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_ISO_EXTRACT); } + UpdateProgressWithInfo(OP_FILE_COPY, MSG_267, wim_proc_files + 2 * wim_extra_files, wim_nb_files); + + uprintf("Disable the use of the Windows Recovery Environment using command:"); + static_sprintf(cmd, "%s\\bcdedit.exe /store %s\\EFI\\Microsoft\\Boot\\BCD /set {default} recoveryenabled no", + sysnative_dir, (use_esp) ? ms_efi : drive_name); + uprintf(cmd); + RunCommand(cmd, sysnative_dir, usb_debug); + + UpdateProgressWithInfo(OP_FILE_COPY, MSG_267, wim_nb_files, wim_nb_files); + if (use_esp) { Sleep(200); AltUnmountVolume(ms_efi, FALSE); } - UpdateProgressWithInfo(OP_FILE_COPY, MSG_267, wim_proc_files + 2 * wim_extra_files, wim_nb_files); - - // The following are non fatal if they fail - -#ifdef SET_INTERNAL_DRIVES_OFFLINE - uprintf("Applying 'san_policy.xml', to set the target's internal drives offline..."); - buffer = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_TOGO_SAN_POLICY_XML), - _RT_RCDATA, "san_policy.xml", &bufsize, FALSE); - san_policy_path[0] = drive_name[0]; - fd = fopenU(san_policy_path, "wb"); - if ((fd == NULL) || (fwrite(buffer, 1, bufsize, fd) != bufsize)) { - uprintf("Could not write '%s'\n", san_policy_path); - if (fd) - fclose(fd); - } else { - fclose(fd); - // Can't use the one from the USB (at least for Windows 10 preview), as you'll get - // "Error: 0x800401f0 An error occurred while initializing COM security". - // On the other hand, using Windows 8.1 dism against Windows 10 doesn't work either - // (you get a message about needing to upgrade to latest AIK)... - static_sprintf(cmd, "dism /Image:%s\\ /Apply-Unattend:%s", drive_name, san_policy_path); - if (RunCommand(cmd, NULL, TRUE) != 0) - uprintf("Command '%s' failed to run", cmd); - } -#endif - - uprintf("Copying 'unattend.xml', to disable the use of the Windows Recovery Environment..."); - buffer = GetResource(hMainInstance, MAKEINTRESOURCEA(IDR_TOGO_UNATTEND_XML), - _RT_RCDATA, "unattend.xml", &bufsize, FALSE); - unattend_path[0] = drive_name[0]; - fd = fopenU(unattend_path, "wb"); - if ((fd == NULL) || (fwrite(buffer, 1, bufsize, fd) != bufsize)) - uprintf("Could not write '%s'", unattend_path); - if (fd != NULL) - fclose(fd); - UpdateProgressWithInfo(OP_FILE_COPY, MSG_267, wim_nb_files, wim_nb_files); return TRUE; } @@ -2145,17 +2119,18 @@ DWORD WINAPI FormatThread(void* param) IsFileInDB(FILES_DIR "\\grub4dos-" GRUB4DOS_VERSION "\\grldr")?"✓":"✗"); if (!CopyFileU(FILES_DIR "\\grub4dos-" GRUB4DOS_VERSION "\\grldr", grub4dos_dst, FALSE)) uprintf("Failed to copy file: %s", WindowsErrorString()); - } else if ((boot_type == BT_IMAGE) && (image_path != NULL) && (img_report.is_iso)) { + } else if ((boot_type == BT_IMAGE) && (image_path != NULL) && (img_report.is_iso || img_report.is_windows_img)) { UpdateProgress(OP_FILE_COPY, 0.0f); drive_name[2] = 0; // Ensure our drive is something like 'D:' if (windows_to_go) { PrintInfoDebug(0, MSG_268); if (!SetupWinToGo(DriveIndex, drive_name, (extra_partitions & XP_ESP))) { if (!IS_ERROR(FormatStatus)) - FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT); + FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_ISO_EXTRACT); goto out; } } else { + assert(!img_report.is_windows_img); if (!ExtractISO(image_path, drive_name, FALSE)) { if (!IS_ERROR(FormatStatus)) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT); @@ -2180,7 +2155,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.wininst_path[0], 1, "Windows\\Boot\\EFI\\bootmgfw.efi", efi_dst)) { + if (!WimExtractFile(img_report.wininst_path[0], 1, "Windows\\Boot\\EFI\\bootmgfw.efi", efi_dst, FALSE)) { uprintf("Failed to setup Win7 EFI boot"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH); } diff --git a/src/iso.c b/src/iso.c index 1e809014..f1221431 100644 --- a/src/iso.c +++ b/src/iso.c @@ -89,7 +89,8 @@ static const char* ldlinux_c32 = "ldlinux.c32"; static const char* md5sum_name[] = { "MD5SUMS", "md5sum.txt" }; static const char* casper_dirname = "/casper"; 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* efi_bootname[MAX_ARCHS] = + { "bootia32.efi", "bootia64.efi", "bootx64.efi", "bootarm.efi", "bootaa64.efi", "bootebc.efi" }; 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/) @@ -249,7 +250,7 @@ static BOOL check_iso_props(const char* psz_dirname, int64_t file_length, const // Check for the EFI boot entries if (safe_stricmp(psz_dirname, efi_dirname) == 0) { - for (i=0; i= 0) ? selected_pt : PARTITION_STYLE_MBR; else if (boot_type == BT_UEFI_NTFS) preferred_pt = (selected_pt >= 0) ? selected_pt : PARTITION_STYLE_GPT; - else if ((boot_type == BT_IMAGE) && (image_path != NULL) && (img_report.is_iso)) { + else if ((boot_type == BT_IMAGE) && (image_path != NULL) && (img_report.is_iso || img_report.is_windows_img)) { if (HAS_WINDOWS(img_report) && img_report.has_efi) preferred_pt = allow_dual_uefi_bios? PARTITION_STYLE_MBR : ((selected_pt >= 0) ? selected_pt : PARTITION_STYLE_GPT); @@ -849,7 +851,8 @@ static void EnableControls(BOOL enable, BOOL remove_checkboxes) EnableBootOptions(enable, remove_checkboxes); // Finally, only enable the half-size dropdowns if we aren't dealing with a pure DD image - enable = ((boot_type == BT_IMAGE) && (image_path != NULL) && (!img_report.is_iso)) ? FALSE : enable; + enable = ((boot_type == BT_IMAGE) && (image_path != NULL) && + (!(img_report.is_iso || img_report.is_windows_img))) ? FALSE : enable; EnableWindow(hPartitionScheme, enable); EnableWindow(hTargetSystem, enable); EnableWindow(GetDlgItem(hMainDialog, IDS_CSM_HELP_TXT), enable); @@ -1086,25 +1089,101 @@ static void DisplayISOProps(void) " Because of this, the size required for the target media may be much larger than size of the ISO..."); } -// Insert the image name into the Boot selection dropdown -static void UpdateImage(void) +// Insert the image name into the Boot selection dropdown and (re)populate the Image option dropdown +static void UpdateImage(BOOL update_image_option_only) { assert(image_index != 0); - if (ComboBox_GetItemData(hBootType, image_index) == BT_IMAGE) - ComboBox_DeleteString(hBootType, image_index); - ComboBox_InsertStringU(hBootType, image_index, - (image_path == NULL) ? lmprintf(MSG_281, lmprintf(MSG_280)) : short_image_path); - ComboBox_SetItemData(hBootType, image_index, BT_IMAGE); - IGNORE_RETVAL(ComboBox_SetCurSel(hBootType, image_index)); - boot_type = (int)ComboBox_GetCurItemData(hBootType); - SetBootTypeDropdownWidth(); + if (!update_image_option_only) { + if (ComboBox_GetItemData(hBootType, image_index) == BT_IMAGE) + ComboBox_DeleteString(hBootType, image_index); + ComboBox_InsertStringU(hBootType, image_index, + (image_path == NULL) ? lmprintf(MSG_281, lmprintf(MSG_280)) : short_image_path); + ComboBox_SetItemData(hBootType, image_index, BT_IMAGE); + IGNORE_RETVAL(ComboBox_SetCurSel(hBootType, image_index)); + boot_type = (int)ComboBox_GetCurItemData(hBootType); + SetBootTypeDropdownWidth(); + } + + ComboBox_ResetContent(hImageOption); + if (!img_report.is_windows_img) + IGNORE_RETVAL(ComboBox_SetItemData(hImageOption, ComboBox_AddStringU(hImageOption, lmprintf(MSG_117)), FALSE)); + IGNORE_RETVAL(ComboBox_SetItemData(hImageOption, ComboBox_AddStringU(hImageOption, lmprintf(MSG_118)), TRUE)); + IGNORE_RETVAL(ComboBox_SetCurSel(hImageOption, (img_report.is_windows_img || !windows_to_go_selected) ? 0 : 1)); +} + +static uint8_t FindArch(const char* filename) +{ + uint8_t ret = 0; + HANDLE hFile = NULL, hFileMapping = NULL; + PIMAGE_DOS_HEADER pImageDOSHeader = NULL; + // NB: The field we are after is at the same location for 32 and 64-bit + // PE headers, so we don't need to care about using PIMAGE_NT_HEADERS[32|64] + PIMAGE_NT_HEADERS pImageNTHeader = NULL; + + hFile = CreateFileU(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (hFile == NULL) { + uprintf("FindArch: Could not open file '%s': %s", filename, WindowsErrorString()); + return 0; + } + + hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL); + if (hFileMapping == NULL) { + uprintf("FindArch: Could not create file mapping: %s", WindowsErrorString()); + goto out; + } + + pImageDOSHeader = (PIMAGE_DOS_HEADER)MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0); + if (pImageDOSHeader == NULL) { + uprintf("FindArch: Could not get mapped view address: %s", WindowsErrorString()); + goto out; + } + if (pImageDOSHeader->e_magic != IMAGE_DOS_SIGNATURE) { + uprintf("FindArch: DOS header not found"); + goto out; + } + pImageNTHeader = (PIMAGE_NT_HEADERS)((uintptr_t)pImageDOSHeader + pImageDOSHeader->e_lfanew); + if (pImageNTHeader->Signature != IMAGE_NT_SIGNATURE) { + uprintf("FindArch: NT header not found"); + goto out; + } + + switch (pImageNTHeader->FileHeader.Machine) { + case IMAGE_FILE_MACHINE_I386: + ret = 1; + break; + case IMAGE_FILE_MACHINE_IA64: + ret = 2; + break; + case IMAGE_FILE_MACHINE_AMD64: + ret = 3; + break; + case IMAGE_FILE_MACHINE_ARM: + ret = 4; + break; + case IMAGE_FILE_MACHINE_ARM64: + ret = 5; + break; + case IMAGE_FILE_MACHINE_EBC: + ret = 6; + break; + } + +out: + if (pImageDOSHeader != NULL) + UnmapViewOfFile(pImageDOSHeader); + safe_closehandle(hFileMapping); + safe_closehandle(hFile); + assert(ret <= MAX_ARCHS); + return ret; } // The scanning process can be blocking for message processing => use a thread -DWORD WINAPI ISOScanThread(LPVOID param) +DWORD WINAPI ImageScanThread(LPVOID param) { int i; + uint8_t arch; + char tmp_path[MAX_PATH]; if (image_path == NULL) goto out; @@ -1114,13 +1193,15 @@ DWORD WINAPI ISOScanThread(LPVOID param) memset(&img_report, 0, sizeof(img_report)); img_report.is_iso = (BOOLEAN)ExtractISO(image_path, "", TRUE); img_report.is_bootable_img = (BOOLEAN)IsBootableImage(image_path); + ComboBox_ResetContent(hImageOption); if ((FormatStatus == (ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_CANCELLED)) || - (img_report.image_size == 0) || (!img_report.is_iso && !img_report.is_bootable_img)) { + (img_report.image_size == 0) || + (!img_report.is_iso && !img_report.is_bootable_img && !img_report.is_windows_img)) { // Failed to scan image SendMessage(hMainDialog, UM_PROGRESS_EXIT, 0, 0); safe_free(image_path); - UpdateImage(); + UpdateImage(FALSE); SetMBRProps(); PopulateProperties(); PrintInfoDebug(0, MSG_203); @@ -1129,7 +1210,25 @@ DWORD WINAPI ISOScanThread(LPVOID param) goto out; } - if (img_report.is_bootable_img) { + if (img_report.is_windows_img) { + selection_default = BT_IMAGE; + if (GetTempFileNameU(temp_dir, APPLICATION_NAME, 0, tmp_path) != 0) { + // Only look at index 1 for now. If people complain, we may look for more. + if (WimExtractFile(image_path, 1, "Windows\\Boot\\EFI\\bootmgr.efi", tmp_path, TRUE)) { + arch = FindArch(tmp_path); + if (arch != 0) { + uprintf(" Image contains an %s EFI boot manager", arch_name[arch - 1]); + img_report.has_efi = 1 | (1 << arch); + img_report.has_bootmgr_efi = TRUE; + img_report.wininst_index = 1; + } else { + uprintf(" Image does not contain an EFI boot manager"); + } + } + DeleteFileU(tmp_path); + } + uprintf(" Image is %sa UEFI bootable Windows installation image", img_report.has_efi ? "" : "NOT "); + } else if (img_report.is_bootable_img) { uprintf(" Image is a %sbootable %s image", (img_report.compression_type != BLED_COMPRESSION_NONE) ? "compressed " : "", img_report.is_vhd ? "VHD" : "disk"); selection_default = BT_IMAGE; @@ -1160,13 +1259,13 @@ DWORD WINAPI ISOScanThread(LPVOID param) i++; short_image_path = &image_path[i]; PrintStatus(0, MSG_205, short_image_path); - UpdateImage(); uprintf("Using image: %s (%s)", short_image_path, SizeToHumanReadable(img_report.image_size, FALSE, FALSE)); } + UpdateImage(dont_display_image_name); ToggleImageOptions(); EnableControls(TRUE, FALSE); // Set Target and FS accordingly - if (img_report.is_iso) { + if (img_report.is_iso || img_report.is_windows_img) { IGNORE_RETVAL(ComboBox_SetCurSel(hBootType, image_index)); SetPartitionSchemeAndTargetSystem(FALSE); SetFileSystemAndClusterSize(NULL); @@ -1266,7 +1365,7 @@ static DWORD WINAPI BootCheckThread(LPVOID param) MessageBoxExU(hMainDialog, lmprintf(MSG_091), lmprintf(MSG_090), MB_OK|MB_ICONERROR|MB_IS_RTL, selected_langid); goto out; } - if (HAS_WIN7_EFI(img_report) && (!WimExtractCheck())) { + if (HAS_WIN7_EFI(img_report) && (!WimExtractCheck(FALSE))) { // Your platform cannot extract files from WIM archives => download 7-zip? if (MessageBoxExU(hMainDialog, lmprintf(MSG_102), lmprintf(MSG_101), MB_YESNO|MB_ICONERROR|MB_IS_RTL, selected_langid) == IDYES) ShellExecuteA(hMainDialog, "open", SEVENZIP_URL, NULL, NULL, SW_SHOWNORMAL); @@ -1680,10 +1779,6 @@ static void InitDialog(HWND hDlg) // Fill up the boot options dropdown SetBootOptions(); - // Fill up the Image Options Windows To Go dropdown - IGNORE_RETVAL(ComboBox_SetItemData(hImageOption, ComboBox_AddStringU(hImageOption, lmprintf(MSG_117)), FALSE)); - IGNORE_RETVAL(ComboBox_SetItemData(hImageOption, ComboBox_AddStringU(hImageOption, lmprintf(MSG_118)), TRUE)); - // Fill up the MBR masqueraded disk IDs ("8 disks should be enough for anybody") IGNORE_RETVAL(ComboBox_SetItemData(hDiskID, ComboBox_AddStringU(hDiskID, lmprintf(MSG_030, LEFT_TO_RIGHT_EMBEDDING "0x80" POP_DIRECTIONAL_FORMATTING)), 0x80)); for (i=1; i<=7; i++) { @@ -1744,7 +1839,7 @@ static void InitDialog(HWND hDlg) ToggleImageOptions(); // Process commandline parameters - if (iso_provided) { + if (img_provided) { // Simulate a button click for image selection PostMessage(hDlg, WM_COMMAND, IDC_SELECT, 0); } @@ -2134,7 +2229,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA if (HIWORD(wParam) != CBN_SELCHANGE) break; SetFileSystemAndClusterSize(NULL); - windows_to_go_selection = ComboBox_GetCurSel(hImageOption); + windows_to_go_selected = (BOOL)ComboBox_GetCurItemData(hImageOption); break; case IDC_PERSISTENCE_SIZE: if (HIWORD(wParam) == EN_CHANGE) { @@ -2260,13 +2355,13 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA EnableControls(FALSE, FALSE); DownloadISO(); } else { - if (iso_provided) { + if (img_provided) { uprintf("\r\nImage provided: '%s'", image_path); - iso_provided = FALSE; // One off thing... + img_provided = FALSE; // One off thing... } else { char* old_image_path = image_path; // If declared globaly, lmprintf(MSG_036) would be called on each message... - EXT_DECL(img_ext, NULL, __VA_GROUP__("*.iso;*.img;*.vhd;*.usb;*.bz2;*.bzip2;*.gz;*.lzma;*.xz;*.Z;*.zip"), + EXT_DECL(img_ext, NULL, __VA_GROUP__("*.iso;*.img;*.vhd;*.usb;*.bz2;*.bzip2;*.gz;*.lzma;*.xz;*.Z;*.zip;*.wim;*.esd"), __VA_GROUP__(lmprintf(MSG_036))); image_path = FileDialog(FALSE, NULL, &img_ext, 0); if (image_path == NULL) { @@ -2284,7 +2379,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA } } FormatStatus = 0; - if (CreateThread(NULL, 0, ISOScanThread, NULL, 0, NULL) == NULL) { + if (CreateThread(NULL, 0, ImageScanThread, NULL, 0, NULL) == NULL) { uprintf("Unable to start ISO scanning thread"); FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD); } @@ -2402,7 +2497,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA break; case UM_SELECT_ISO: select_index = 0; - iso_provided = TRUE; + img_provided = TRUE; SetWindowTextU(GetDlgItem(hDlg, IDC_SELECT), uppercase_select[0]); SendMessage(hDlg, WM_COMMAND, IDC_SELECT, 0); break; @@ -2606,7 +2701,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA safe_free(wbuffer); if (image_path != NULL) { - iso_provided = TRUE; + img_provided = TRUE; // Simulate image selection click SendMessage(hDlg, WM_COMMAND, IDC_SELECT, 0); } @@ -3065,7 +3160,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine if (_access(optarg, 0) != -1) { safe_free(image_path); image_path = safe_strdup(optarg); - iso_provided = TRUE; + img_provided = TRUE; } else { printf("Could not find ISO image '%s'\n", optarg); @@ -3490,7 +3585,7 @@ relaunch: enable_iso = !enable_iso; PrintStatusTimeout(lmprintf(MSG_262), enable_iso); if (image_path != NULL) { - iso_provided = TRUE; + img_provided = TRUE; dont_display_image_name = TRUE; SendMessage(hDlg, WM_COMMAND, IDC_SELECT, 0); } diff --git a/src/rufus.h b/src/rufus.h index 7085532e..05cb38ff 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -62,6 +62,7 @@ #define DRIVE_INDEX_MAX 0x000000C0 #define MIN_DRIVE_SIZE 8 // Minimum size a drive must have, to be formattable (in MB) #define MIN_EXTRA_PART_SIZE (1024*1024) // Minimum size of the extra partition, in bytes +#define MAX_ARCHS 6 // Number of arhitectures we recognize #define MAX_DRIVES (DRIVE_INDEX_MAX - DRIVE_INDEX_MIN) #define MAX_TOOLTIPS 128 #define MAX_SIZE_SUFFIXES 6 // bytes, KB, MB, GB, TB, PB @@ -338,6 +339,7 @@ typedef struct { BOOLEAN is_iso; BOOLEAN is_bootable_img; BOOLEAN is_vhd; + BOOLEAN is_windows_img; BOOLEAN disable_iso; uint16_t winpe; uint8_t has_efi; @@ -555,10 +557,10 @@ extern char* replace_in_token_data(const char* filename, const char* token, cons extern char* replace_char(const char* src, const char c, const char* rep); extern void parse_update(char* buf, size_t len); extern void* get_data_from_asn1(const uint8_t* buf, size_t buf_len, const char* oid_str, uint8_t asn1_type, size_t* data_len); -extern uint8_t WimExtractCheck(void); -extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst); -extern BOOL WimExtractFile_API(const char* image, int index, const char* src, const char* dst); -extern BOOL WimExtractFile_7z(const char* image, int index, const char* src, const char* dst); +extern uint8_t WimExtractCheck(BOOL bSilent); +extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst, BOOL bSilent); +extern BOOL WimExtractFile_API(const char* image, int index, const char* src, const char* dst, BOOL bSilent); +extern BOOL WimExtractFile_7z(const char* image, int index, const char* src, const char* dst, BOOL bSilent); extern BOOL WimApplyImage(const char* image, int index, const char* dst); extern BOOL IsBootableImage(const char* path); extern BOOL AppendVHDFooter(const char* vhd_path); diff --git a/src/rufus.rc b/src/rufus.rc index bf707662..e1bcd14d 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.12.1690" +CAPTION "Rufus 3.12.1691" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -308,8 +308,6 @@ BEGIN "IDR_FD_EGA18_CPX RCDATA ""../res/freedos/EGA18.CPX""\r\n" "IDR_XT_HOGGER RCDATA ""../res/hogger/hogger.exe""\r\n" "IDR_UEFI_NTFS RCDATA ""../res/uefi/uefi-ntfs.img""\r\n" - "IDR_TOGO_SAN_POLICY_XML RCDATA ""../res/togo/san_policy.xml""\r\n" - "IDR_TOGO_UNATTEND_XML RCDATA ""../res/togo/unattend.xml""\r\n" "IDI_LANG_16 RCDATA ""../res/icons/lang-16.png""\r\n" "IDI_INFO_16 RCDATA ""../res/icons/info-16.png""\r\n" "IDI_SETTINGS_16 RCDATA ""../res/icons/settings-16.png""\r\n" @@ -397,8 +395,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,12,1690,0 - PRODUCTVERSION 3,12,1690,0 + FILEVERSION 3,12,1691,0 + PRODUCTVERSION 3,12,1691,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -416,13 +414,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.12.1690" + VALUE "FileVersion", "3.12.1691" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2020 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-3.12.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.12.1690" + VALUE "ProductVersion", "3.12.1691" END END BLOCK "VarFileInfo" @@ -494,8 +492,6 @@ IDR_FD_EGA17_CPX RCDATA "../res/freedos/EGA17.CPX" IDR_FD_EGA18_CPX RCDATA "../res/freedos/EGA18.CPX" IDR_XT_HOGGER RCDATA "../res/hogger/hogger.exe" IDR_UEFI_NTFS RCDATA "../res/uefi/uefi-ntfs.img" -IDR_TOGO_SAN_POLICY_XML RCDATA "../res/togo/san_policy.xml" -IDR_TOGO_UNATTEND_XML RCDATA "../res/togo/unattend.xml" IDI_LANG_16 RCDATA "../res/icons/lang-16.png" IDI_INFO_16 RCDATA "../res/icons/info-16.png" IDI_SETTINGS_16 RCDATA "../res/icons/settings-16.png" diff --git a/src/ui.c b/src/ui.c index 9dd4079c..b79a16af 100644 --- a/src/ui.c +++ b/src/ui.c @@ -772,7 +772,8 @@ void ToggleImageOptions(void) uint8_t entry_image_options = image_options; int i, shift = rh; - has_wintogo = ((boot_type == BT_IMAGE) && (image_path != NULL) && (img_report.is_iso) && (nWindowsVersion >= WINDOWS_8) && (HAS_WINTOGO(img_report))); + has_wintogo = ((boot_type == BT_IMAGE) && (image_path != NULL) && (img_report.is_iso || img_report.is_windows_img) && + (nWindowsVersion >= WINDOWS_8) && (HAS_WINTOGO(img_report))); has_persistence = ((boot_type == BT_IMAGE) && (image_path != NULL) && (img_report.is_iso) && (HAS_PERSISTENCE(img_report))); assert(popcnt8(image_options) <= 1); @@ -784,13 +785,20 @@ void ToggleImageOptions(void) if ( ((has_wintogo) && !(image_options & IMOP_WINTOGO)) || ((!has_wintogo) && (image_options & IMOP_WINTOGO)) ) { image_options ^= IMOP_WINTOGO; - // Set the Windows To Go selection in the dropdown - IGNORE_RETVAL(ComboBox_SetCurSel(hImageOption, windows_to_go_selection)); + if (image_options & IMOP_WINTOGO) { + // Set the Windows To Go selection in the dropdown + IGNORE_RETVAL(ComboBox_SetCurSel(hImageOption, (img_report.is_windows_img || !windows_to_go_selected) ? 0 : 1)); + } } if (((has_persistence) && !(image_options & IMOP_PERSISTENCE)) || ((!has_persistence) && (image_options & IMOP_PERSISTENCE))) { image_options ^= IMOP_PERSISTENCE; + if (image_options & IMOP_PERSISTENCE) { + SetWindowTextU(GetDlgItem(hMainDialog, IDS_IMAGE_OPTION_TXT), lmprintf(MSG_123)); + TogglePersistenceControls(persistence_size != 0); + SetPersistenceSize(); + } } if ( ((entry_image_options != 0) && (has_wintogo || has_persistence)) || @@ -815,15 +823,6 @@ void ToggleImageOptions(void) ShowWindow(GetDlgItem(hMainDialog, image_option_toggle_ids[i][0]), (image_options & image_option_toggle_ids[i][1]) ? SW_SHOW : SW_HIDE); } - // Set the dropdown default selection - if (image_options & IMOP_WINTOGO) { - SetWindowTextU(GetDlgItem(hMainDialog, IDS_IMAGE_OPTION_TXT), image_option_txt); - IGNORE_RETVAL(ComboBox_SetCurSel(hImageOption, windows_to_go_selection)); - } else if (image_options & IMOP_PERSISTENCE) { - SetWindowTextU(GetDlgItem(hMainDialog, IDS_IMAGE_OPTION_TXT), lmprintf(MSG_123)); - TogglePersistenceControls(persistence_size != 0); - SetPersistenceSize(); - } // If you don't force a redraw here, all kind of bad UI artifacts happen... InvalidateRect(hMainDialog, NULL, TRUE); } @@ -1180,14 +1179,14 @@ void InitProgress(BOOL bOnlyFormat) nb_slots[OP_FILE_COPY] = 5 + 1; break; case BT_IMAGE: - nb_slots[OP_FILE_COPY] = img_report.is_iso ? -1 : 0; + nb_slots[OP_FILE_COPY] = (img_report.is_iso || img_report.is_windows_img) ? -1 : 0; break; default: nb_slots[OP_FILE_COPY] = 2 + 1; break; } } - if (selection_default == BT_IMAGE && !img_report.is_iso) { + if (selection_default == BT_IMAGE && !(img_report.is_iso || img_report.is_windows_img)) { nb_slots[OP_FORMAT] = -1; } else { nb_slots[OP_ZERO_MBR] = 1; diff --git a/src/ui.h b/src/ui.h index 7caa31f2..309b4712 100644 --- a/src/ui.h +++ b/src/ui.h @@ -74,13 +74,12 @@ enum update_progress_type { extern HWND hMultiToolbar, hSaveToolbar, hHashToolbar, hAdvancedDeviceToolbar, hAdvancedFormatToolbar; extern HFONT hInfoFont; extern UINT_PTR UM_LANGUAGE_MENU_MAX; -extern BOOL advanced_mode_device, advanced_mode_format, force_large_fat32, app_changed_size; +extern BOOL advanced_mode_device, advanced_mode_format, force_large_fat32, app_changed_size, windows_to_go_selected; extern loc_cmd* selected_locale; extern uint64_t persistence_size; extern const char *sfd_name, *flash_type[BADLOCKS_PATTERN_TYPES]; extern char *short_image_path, image_option_txt[128]; -extern int advanced_device_section_height, advanced_format_section_height; -extern int windows_to_go_selection, persistence_unit_selection; +extern int advanced_device_section_height, advanced_format_section_height, persistence_unit_selection; extern int selection_default, cbw, ddw, ddbh, bh, update_progress_type; extern void SetAccessibleName(HWND hCtrl, const char* name); diff --git a/src/vhd.c b/src/vhd.c index 47e56eb3..3cfe6a06 100644 --- a/src/vhd.c +++ b/src/vhd.c @@ -49,6 +49,12 @@ #define VHD_FOOTER_TYPE_DYNAMIC_HARD_DISK 0x00000003 #define VHD_FOOTER_TYPE_DIFFER_HARD_DISK 0x00000004 +#define WIM_MAGIC 0x0000004D4957534DULL // "MSWIM\0\0\0" +#define WIM_HAS_API_EXTRACT 1 +#define WIM_HAS_7Z_EXTRACT 2 +#define WIM_HAS_API_APPLY 4 +#define WIM_HAS_EXTRACT(r) (r & (WIM_HAS_API_EXTRACT|WIM_HAS_7Z_EXTRACT)) + #define SECONDS_SINCE_JAN_1ST_2000 946684800 /* @@ -92,6 +98,8 @@ typedef struct vhd_footer { 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)); +PF_TYPE_DECL(WINAPI, BOOL, WIMMountImage, (PCWSTR, PCWSTR, DWORD, PCWSTR)); +PF_TYPE_DECL(WINAPI, BOOL, WIMUnmountImage, (PCWSTR, PCWSTR, DWORD, BOOL)); PF_TYPE_DECL(WINAPI, BOOL, WIMApplyImage, (HANDLE, PCWSTR, DWORD)); PF_TYPE_DECL(WINAPI, BOOL, WIMExtractImagePath, (HANDLE, PWSTR, PWSTR, DWORD)); PF_TYPE_DECL(WINAPI, BOOL, WIMGetImageInformation, (HANDLE, PVOID, PDWORD)); @@ -105,6 +113,7 @@ HANDLE apply_wim_thread = NULL; extern int default_thread_priority; static uint8_t wim_flags = 0; +static wchar_t wmount_path[MAX_PATH] = { 0 }; static char sevenzip_path[MAX_PATH]; static const char conectix_str[] = VHD_FOOTER_COOKIE; static BOOL count_files; @@ -268,7 +277,6 @@ BOOL IsCompressedBootableImage(const char* path) return FALSE; } - BOOL IsBootableImage(const char* path) { HANDLE handle = INVALID_HANDLE_VALUE; @@ -277,7 +285,8 @@ BOOL IsBootableImage(const char* path) DWORD size; size_t i; uint32_t checksum, old_checksum; - LARGE_INTEGER ptr; + uint64_t wim_magic = 0; + LARGE_INTEGER ptr = { 0 }; BOOL is_bootable_img = FALSE; uprintf("Disk image analysis:"); @@ -297,6 +306,11 @@ BOOL IsBootableImage(const char* path) goto out; } img_report.image_size = (uint64_t)liImageSize.QuadPart; + size = sizeof(wim_magic); + SetFilePointerEx(handle, ptr, NULL, FILE_BEGIN); + img_report.is_windows_img = ReadFile(handle, &wim_magic, size, &size, NULL) && (wim_magic == WIM_MAGIC); + if (img_report.is_windows_img) + goto out; size = sizeof(vhd_footer); if ((img_report.compression_type == BLED_COMPRESSION_NONE) && (img_report.image_size >= (512 + size))) { @@ -335,14 +349,9 @@ out: return is_bootable_img; } -#define WIM_HAS_API_EXTRACT 1 -#define WIM_HAS_7Z_EXTRACT 2 -#define WIM_HAS_API_APPLY 4 -#define WIM_HAS_EXTRACT(r) (r & (WIM_HAS_API_EXTRACT|WIM_HAS_7Z_EXTRACT)) - // Find out if we have any way to extract/apply WIM files on this platform // Returns a bitfield of the methods we can use (1 = Extract using wimgapi, 2 = Extract using 7-Zip, 4 = Apply using wimgapi) -uint8_t WimExtractCheck(void) +uint8_t WimExtractCheck(BOOL bSilent) { PF_INIT(WIMCreateFile, Wimgapi); PF_INIT(WIMSetTemporaryPath, Wimgapi); @@ -361,19 +370,69 @@ uint8_t WimExtractCheck(void) if ((wim_flags & WIM_HAS_API_EXTRACT) && pfWIMApplyImage && pfWIMRegisterMessageCallback && pfWIMUnregisterMessageCallback) wim_flags |= WIM_HAS_API_APPLY; - uprintf("WIM extraction method(s) supported: %s%s%s", (wim_flags & WIM_HAS_7Z_EXTRACT)?"7-Zip": + suprintf("WIM extraction method(s) supported: %s%s%s", (wim_flags & WIM_HAS_7Z_EXTRACT)?"7-Zip": ((wim_flags & WIM_HAS_API_EXTRACT)?"":"NONE"), (WIM_HAS_EXTRACT(wim_flags) == (WIM_HAS_API_EXTRACT|WIM_HAS_7Z_EXTRACT))?", ": "", (wim_flags & WIM_HAS_API_EXTRACT)?"wimgapi.dll":""); - uprintf("WIM apply method supported: %s", (wim_flags & WIM_HAS_API_APPLY)?"wimgapi.dll":"NONE"); + suprintf("WIM apply method supported: %s", (wim_flags & WIM_HAS_API_APPLY)?"wimgapi.dll":"NONE"); return wim_flags; } +// Looks like Microsoft's idea of "mount" for WIM images is to just *extract* all +// files to a mounpoint and pretend it is "mounted", even if you do specify that +// you're not planning to change the content. So, yeah, this is both super slow +// and super wasteful of space... These calls are a complete waste of time. +BOOL WimMountImage(char* pszWimFileName, DWORD dwImageIndex) +{ + BOOL r = FALSE; + wconvert(temp_dir); + wconvert(pszWimFileName); + PF_INIT_OR_OUT(WIMMountImage, Wimgapi); + + if (wmount_path[0] != 0) { + uprintf("WimMountImage: An image is already mounted"); + goto out; + } + if (GetTempFileNameW(wtemp_dir, L"Rufus", 0, wmount_path) == 0) { + uprintf("WimMountImage: Can not create mount directory"); + goto out; + } + DeleteFileW(wmount_path); + if (!CreateDirectoryW(wmount_path, 0)) { + uprintf("WimMountImage: Can not create mount directory"); + goto out; + } + + r = pfWIMMountImage(wmount_path, wpszWimFileName, dwImageIndex, NULL); + if (!r) + uprintf("Could not mount %S on %S: %s", wpszWimFileName, wmount_path, WindowsErrorString()); + +out: + wfree(temp_dir); + wfree(pszWimFileName); + return r; +} + +BOOL WimUnmountImage(void) +{ + BOOL r = FALSE; + PF_INIT_OR_OUT(WIMUnmountImage, Wimgapi); + if (wmount_path[0] == 0) { + uprintf("WimUnmountImage: No image is mounted"); + goto out; + } + r = pfWIMUnmountImage(wmount_path, NULL, 0, FALSE); + if (!r) + uprintf("Could not unmount %S: %s", wmount_path, WindowsErrorString()); + wmount_path[0] = 0; +out: + return r; +} // Extract a file from a WIM image using wimgapi.dll (Windows 7 or later) // NB: if you want progress from a WIM callback, you must run the WIM API call in its own thread // (which we don't do here) as it won't work otherwise. Thanks go to Erwan for figuring this out! -BOOL WimExtractFile_API(const char* image, int index, const char* src, const char* dst) +BOOL WimExtractFile_API(const char* image, int index, const char* src, const char* dst, BOOL bSilent) { static char* index_name = "[1].xml"; BOOL r = FALSE; @@ -393,7 +452,7 @@ BOOL WimExtractFile_API(const char* image, int index, const char* src, const cha PF_INIT_OR_OUT(WIMExtractImagePath, Wimgapi); PF_INIT_OR_OUT(WIMCloseHandle, Wimgapi); - uprintf("Opening: %s:[%d] (API)", image, index); + suprintf("Opening: %s:[%d] (API)", image, index); if (GetTempPathW(ARRAYSIZE(wtemp), wtemp) == 0) { uprintf(" Could not fetch temp path: %s", WindowsErrorString()); goto out; @@ -415,7 +474,7 @@ BOOL WimExtractFile_API(const char* image, int index, const char* src, const cha goto out; } - uprintf("Extracting: %s (From %s)", dst, src); + suprintf("Extracting: %s (From %s)", dst, src); if (safe_strcmp(src, index_name) == 0) { if (!pfWIMGetImageInformation(hWim, &wim_info, &dw)) { uprintf(" Could not access WIM info: %s", WindowsErrorString()); @@ -424,7 +483,7 @@ BOOL WimExtractFile_API(const char* image, int index, const char* src, const cha hFile = CreateFileW(wdst, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if ((hFile == INVALID_HANDLE_VALUE) || (!WriteFile(hFile, wim_info, dw, &dw, NULL))) { - uprintf(" Could not extract file: %s", WindowsErrorString()); + suprintf(" Could not extract file: %s", WindowsErrorString()); goto out; } } else { @@ -434,7 +493,7 @@ BOOL WimExtractFile_API(const char* image, int index, const char* src, const cha goto out; } if (!pfWIMExtractImagePath(hImage, wsrc, wdst, 0)) { - uprintf(" Could not extract file: %s", WindowsErrorString()); + suprintf(" Could not extract file: %s", WindowsErrorString()); goto out; } } @@ -442,7 +501,7 @@ BOOL WimExtractFile_API(const char* image, int index, const char* src, const cha out: if ((hImage != NULL) || (hWim != NULL)) { - uprintf("Closing: %s", image); + suprintf("Closing: %s", image); if (hImage != NULL) pfWIMCloseHandle(hImage); if (hWim != NULL) pfWIMCloseHandle(hWim); } @@ -454,7 +513,7 @@ out: } // Extract a file from a WIM image using 7-Zip -BOOL WimExtractFile_7z(const char* image, int index, const char* src, const char* dst) +BOOL WimExtractFile_7z(const char* image, int index, const char* src, const char* dst, BOOL bSilent) { int n; size_t i; @@ -462,7 +521,7 @@ BOOL WimExtractFile_7z(const char* image, int index, const char* src, const char char tmpdst[MAX_PATH]; char index_prefix[] = "#\\"; - uprintf("Opening: %s:[%d] (7-Zip)", image, index); + suprintf("Opening: %s:[%d] (7-Zip)", image, index); if ((image == NULL) || (src == NULL) || (dst == NULL)) return FALSE; @@ -471,7 +530,7 @@ BOOL WimExtractFile_7z(const char* image, int index, const char* src, const char // that this breaks! index_prefix[0] = '0' + index; - uprintf("Extracting: %s (From %s)", dst, src); + suprintf("Extracting: %s (From %s)", dst, src); // 7z has a quirk where the image index MUST be specified if a // WIM has multiple indexes, but it MUST be removed if there is @@ -500,13 +559,13 @@ BOOL WimExtractFile_7z(const char* image, int index, const char* src, const char } if (n >= 2) { - uprintf(" 7z.exe did not extract %s", tmpdst); + suprintf(" 7z.exe did not extract %s", tmpdst); return FALSE; } // coverity[toctou] - if (rename(tmpdst, dst) != 0) { - uprintf(" Could not rename %s to %s: errno %d", tmpdst, dst, errno); + if (!MoveFileExU(tmpdst, dst, MOVEFILE_REPLACE_EXISTING)) { + uprintf(" Could not rename %s to %s: %s", tmpdst, dst, WindowsErrorString()); return FALSE; } @@ -514,17 +573,17 @@ BOOL WimExtractFile_7z(const char* image, int index, const char* src, const char } // Extract a file from a WIM image -BOOL WimExtractFile(const char* image, int index, const char* src, const char* dst) +BOOL WimExtractFile(const char* image, int index, const char* src, const char* dst, BOOL bSilent) { - if ((wim_flags == 0) && (!WIM_HAS_EXTRACT(WimExtractCheck()))) + if ((wim_flags == 0) && (!WIM_HAS_EXTRACT(WimExtractCheck(TRUE)))) return FALSE; if ((image == NULL) || (src == NULL) || (dst == NULL)) return FALSE; // Prefer 7-Zip as, unsurprisingly, it's faster than the Microsoft way, // but allow fallback if 7-Zip doesn't succeed - return ( ((wim_flags & WIM_HAS_7Z_EXTRACT) && WimExtractFile_7z(image, index, src, dst)) - || ((wim_flags & WIM_HAS_API_EXTRACT) && WimExtractFile_API(image, index, src, dst)) ); + return ( ((wim_flags & WIM_HAS_7Z_EXTRACT) && WimExtractFile_7z(image, index, src, dst, bSilent)) + || ((wim_flags & WIM_HAS_API_EXTRACT) && WimExtractFile_API(image, index, src, dst, bSilent)) ); } // Apply image functionality