From fbad63666efc43118e8a0050d0393e71562a1479 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 2 Aug 2022 20:14:29 +0100 Subject: [PATCH] [wue] add fallback to index 1 if boot.wim index 2 is not available * Some "unofficial" Windows ISOs use a custom boot.wim that only includes the Setup image at index 1, rather than at index 2, after the PE image, for official ISOs. * Also refactor to add a long needed vhd.h header. * Also fix a MinGW warning. --- .vs/rufus.vcxproj | 1 + .vs/rufus.vcxproj.filters | 3 + configure | 2 +- configure.ac | 2 +- src/format.c | 1 + src/rufus.c | 6 +- src/rufus.h | 9 -- src/rufus.rc | 10 +-- src/vhd.c | 179 +++++++++++++++----------------------- src/vhd.h | 141 ++++++++++++++++++++++++++++++ src/wue.c | 23 +++-- 11 files changed, 243 insertions(+), 134 deletions(-) create mode 100644 src/vhd.h diff --git a/.vs/rufus.vcxproj b/.vs/rufus.vcxproj index 11b65194d1d..15e929708e8 100644 --- a/.vs/rufus.vcxproj +++ b/.vs/rufus.vcxproj @@ -405,6 +405,7 @@ + diff --git a/.vs/rufus.vcxproj.filters b/.vs/rufus.vcxproj.filters index d42d286702d..2e10c9d3924 100644 --- a/.vs/rufus.vcxproj.filters +++ b/.vs/rufus.vcxproj.filters @@ -188,6 +188,9 @@ Header Files + + Header Files + diff --git a/configure b/configure index 299b44704b7..627864841ed 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 -Wbidi-chars=none $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 -Wno-array-bounds -Werror-implicit-function-declaration -Wbidi-chars=none $nopointersign_cflags" diff --git a/configure.ac b/configure.ac index 9cecadb7fa0..c5624f6718b 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 -Wbidi-chars=none $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 -Wno-array-bounds -Werror-implicit-function-declaration -Wbidi-chars=none $nopointersign_cflags" AC_SUBST([VISIBILITY_CFLAGS]) AC_SUBST([AM_CFLAGS]) diff --git a/src/format.c b/src/format.c index c2383a37972..155390bf46d 100644 --- a/src/format.c +++ b/src/format.c @@ -44,6 +44,7 @@ #include "localization.h" #include "br.h" +#include "vhd.h" #include "wue.h" #include "fat16.h" #include "fat32.h" diff --git a/src/rufus.c b/src/rufus.c index 71e77450429..d95fc9f93e6 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -47,6 +47,7 @@ #include "ui.h" #include "re.h" +#include "vhd.h" #include "wue.h" #include "drive.h" #include "settings.h" @@ -3770,9 +3771,8 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine // Ctrl-T => Alternate Test mode that doesn't require a full rebuild if ((ctrl_without_focus || ((GetKeyState(VK_CONTROL) & 0x8000) && (msg.message == WM_KEYDOWN))) && (msg.wParam == 'T')) { - //extern int TestChecksum(void); - //TestChecksum(); - ListVdsVolumes(FALSE); + int index = 2; + uprintf("Index %d is %s", index, WimIsValidIndex("C:\\tmp\\boot1.wim", index) ? "valid" : "invalid"); continue; } #endif diff --git a/src/rufus.h b/src/rufus.h index 63f1d42b4a6..c96f8c9ddf4 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -629,15 +629,6 @@ 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(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 char* WimMountImage(const char* image, int index); -extern BOOL WimUnmountImage(const char* image, int index); -extern int8_t IsBootableImage(const char* path); -extern BOOL AppendVHDFooter(const char* vhd_path); extern int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid); extern char* GetSignatureName(const char* path, const char* country_code, BOOL bSilent); extern uint64_t GetSignatureTimeStamp(const char* path); diff --git a/src/rufus.rc b/src/rufus.rc index e9a00350a53..3496684e6ae 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.20.1927" +CAPTION "Rufus 3.20.1928" 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,20,1927,0 - PRODUCTVERSION 3,20,1927,0 + FILEVERSION 3,20,1928,0 + PRODUCTVERSION 3,20,1928,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.20.1927" + VALUE "FileVersion", "3.20.1928" 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.20.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.20.1927" + VALUE "ProductVersion", "3.20.1928" END END BLOCK "VarFileInfo" diff --git a/src/vhd.c b/src/vhd.c index c64101916c7..ab41746bc2b 100644 --- a/src/vhd.c +++ b/src/vhd.c @@ -23,6 +23,7 @@ #include #include +#include "vhd.h" #include "rufus.h" #include "missing.h" #include "resource.h" @@ -32,110 +33,7 @@ #include "registry.h" #include "bled/bled.h" -#define VHD_FOOTER_COOKIE { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x' } - -#define VHD_FOOTER_FEATURES_NONE 0x00000000 -#define VHD_FOOTER_FEATURES_TEMPORARY 0x00000001 -#define VHD_FOOTER_FEATURES_RESERVED 0x00000002 - -#define VHD_FOOTER_FILE_FORMAT_V1_0 0x00010000 - -#define VHD_FOOTER_DATA_OFFSET_FIXED_DISK 0xFFFFFFFFFFFFFFFFULL - -#define VHD_FOOTER_CREATOR_HOST_OS_WINDOWS { 'W', 'i', '2', 'k' } -#define VHD_FOOTER_CREATOR_HOST_OS_MAC { 'M', 'a', 'c', ' ' } - -#define VHD_FOOTER_TYPE_FIXED_HARD_DISK 0x00000002 -#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 - -#define INVALID_CALLBACK_VALUE 0xFFFFFFFF - -#define WIM_FLAG_RESERVED 0x00000001 -#define WIM_FLAG_VERIFY 0x00000002 -#define WIM_FLAG_INDEX 0x00000004 -#define WIM_FLAG_NO_APPLY 0x00000008 -#define WIM_FLAG_NO_DIRACL 0x00000010 -#define WIM_FLAG_NO_FILEACL 0x00000020 -#define WIM_FLAG_SHARE_WRITE 0x00000040 -#define WIM_FLAG_FILEINFO 0x00000080 -#define WIM_FLAG_NO_RP_FIX 0x00000100 - -// Bitmask for the kind of progress we want to report in the WIM progress callback -#define WIM_REPORT_PROGRESS 0x00000001 -#define WIM_REPORT_PROCESS 0x00000002 -#define WIM_REPORT_FILEINFO 0x00000004 - -// From https://docs.microsoft.com/en-us/previous-versions/msdn10/dd834960(v=msdn.10) -// as well as https://msfn.org/board/topic/150700-wimgapi-wimmountimage-progressbar/ -enum WIMMessage { - WIM_MSG = WM_APP + 0x1476, - WIM_MSG_TEXT, - WIM_MSG_PROGRESS, // Indicates an update in the progress of an image application. - WIM_MSG_PROCESS, // Enables the caller to prevent a file or a directory from being captured or applied. - WIM_MSG_SCANNING, // Indicates that volume information is being gathered during an image capture. - WIM_MSG_SETRANGE, // Indicates the number of files that will be captured or applied. - WIM_MSG_SETPOS, // Indicates the number of files that have been captured or applied. - WIM_MSG_STEPIT, // Indicates that a file has been either captured or applied. - WIM_MSG_COMPRESS, // Enables the caller to prevent a file resource from being compressed during a capture. - WIM_MSG_ERROR, // Alerts the caller that an error has occurred while capturing or applying an image. - WIM_MSG_ALIGNMENT, // Enables the caller to align a file resource on a particular alignment boundary. - WIM_MSG_RETRY, // Sent when the file is being reapplied because of a network timeout. - WIM_MSG_SPLIT, // Enables the caller to align a file resource on a particular alignment boundary. - WIM_MSG_FILEINFO, // Used in conjunction with WimApplyImages()'s WIM_FLAG_FILEINFO flag to provide detailed file info. - WIM_MSG_INFO, // Sent when an info message is available. - WIM_MSG_WARNING, // Sent when a warning message is available. - WIM_MSG_CHK_PROCESS, - WIM_MSG_SUCCESS = 0, - WIM_MSG_ABORT_IMAGE = -1 -}; - -/* - * VHD Fixed HD footer (Big Endian) - * http://download.microsoft.com/download/f/f/e/ffef50a5-07dd-4cf8-aaa3-442c0673a029/Virtual%20Hard%20Disk%20Format%20Spec_10_18_06.doc - * NB: If a dymamic implementation is needed, check the GPL v3 compatible C++ implementation from: - * https://sourceforge.net/p/urbackup/backend/ci/master/tree/fsimageplugin/ - */ -#pragma pack(push, 1) -typedef struct vhd_footer { - char cookie[8]; - uint32_t features; - uint32_t file_format_version; - uint64_t data_offset; - uint32_t timestamp; - char creator_app[4]; - uint32_t creator_version; - char creator_host_os[4]; - uint64_t original_size; - uint64_t current_size; - union { - uint32_t geometry; - struct { - uint16_t cylinders; - uint8_t heads; - uint8_t sectors; - } chs; - } disk_geometry; - uint32_t disk_type; - uint32_t checksum; - uuid_t unique_id; - uint8_t saved_state; - uint8_t reserved[427]; -} vhd_footer; -#pragma pack(pop) - // WIM API Prototypes -#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)); @@ -287,8 +185,7 @@ static comp_assoc file_assoc[] = { }; // For now we consider that an image that matches a known extension is bootable -#define MBR_SIZE 512 // Might need to review this once we see bootable 4k systems -BOOL IsCompressedBootableImage(const char* path) +static BOOL IsCompressedBootableImage(const char* path) { char *p; unsigned char *buf = NULL; @@ -566,7 +463,7 @@ static DWORD WINAPI WimMountImageThread(LPVOID param) uprintf("Could not mount '%S [%d]' on '%S': %s", wimage, _index, wmount_path, WindowsErrorString()); goto out; } - uprintf("mounted '%S [%d]' on '%S'", wimage, _index, wmount_path); + uprintf("Mounted '%S [%d]' on '%S'", wimage, _index, wmount_path); out: if (!r) { @@ -677,11 +574,11 @@ BOOL WimExtractFile_API(const char* image, int index, const char* src, const cha HANDLE hWim = NULL; HANDLE hImage = NULL; HANDLE hFile = NULL; - wchar_t wtemp[MAX_PATH] = {0}; + wchar_t wtemp[MAX_PATH] = { 0 }; wchar_t* wimage = utf8_to_wchar(image); wchar_t* wsrc = utf8_to_wchar(src); wchar_t* wdst = utf8_to_wchar(dst); - char* wim_info; + wchar_t* wim_info; PF_INIT_OR_OUT(WIMCreateFile, Wimgapi); PF_INIT_OR_OUT(WIMSetTemporaryPath, Wimgapi); @@ -713,7 +610,7 @@ BOOL WimExtractFile_API(const char* image, int index, const char* src, const cha suprintf("Extracting: %s (From %s)", dst, src); if (safe_strcmp(src, index_name) == 0) { - if (!pfWIMGetImageInformation(hWim, &wim_info, &dw)) { + if (!pfWIMGetImageInformation(hWim, &wim_info, &dw) || (dw == 0)) { uprintf(" Could not access WIM info: %s", WindowsErrorString()); goto out; } @@ -823,6 +720,70 @@ BOOL WimExtractFile(const char* image, int index, const char* src, const char* d || ((wim_flags & WIM_HAS_API_EXTRACT) && WimExtractFile_API(image, index, src, dst, bSilent)) ); } +/// +/// Find if a specific index belongs to a WIM image. +/// +/// The path to the WIM file. +/// The (non-zero) value of the index to check. +/// TRUE if the index was found in the image, FALSE otherwise. +BOOL WimIsValidIndex(const char* image, int index) +{ + int i = 1; + BOOL r = FALSE; + DWORD dw = 0; + HANDLE hWim = NULL; + HANDLE hFile = NULL; + char xml_file[MAX_PATH] = { 0 }; + char* str; + wchar_t* wimage = utf8_to_wchar(image); + wchar_t* wim_info; + + PF_INIT_OR_OUT(WIMCreateFile, Wimgapi); + PF_INIT_OR_OUT(WIMGetImageInformation, Wimgapi); + PF_INIT_OR_OUT(WIMCloseHandle, Wimgapi); + + // Zero indexes are invalid + if (index == 0) + return FALSE; + + 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; + } + + if (!pfWIMGetImageInformation(hWim, &wim_info, &dw) || (dw == 0)) { + uprintf(" Could not access WIM info: %s", WindowsErrorString()); + goto out; + } + + if ((GetTempFileNameU(temp_dir, APPLICATION_NAME, 0, xml_file) == 0) || (xml_file[0] == 0)) + static_strcpy(xml_file, ".\\RufVXml.tmp"); + DeleteFileU(xml_file); + hFile = CreateFileU(xml_file, 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))) + goto out; + + while ((str = get_token_data_file_indexed("IMAGE INDEX", xml_file, i)) != NULL) { + if (atoi(str) == index) { + r = TRUE; + break; + } + i++; + } + +out: + if (hWim != NULL) + pfWIMCloseHandle(hWim); + safe_closehandle(hFile); + if (xml_file[0] != 0) + DeleteFileU(xml_file); + safe_free(wimage); + return r; +} + // Apply a WIM image using wimgapi.dll (Windows 7 or later) // https://docs.microsoft.com/en-us/previous-versions/msdn10/dd851944(v=msdn.10) // To get progress, we must run this call within its own thread diff --git a/src/vhd.h b/src/vhd.h new file mode 100644 index 00000000000..e5f1f86f9f1 --- /dev/null +++ b/src/vhd.h @@ -0,0 +1,141 @@ +/* + * Rufus: The Reliable USB Formatting Utility + * Virtual Disk Handling definitions and prototypes + * Copyright © 2022 Pete Batard + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#pragma once + +#define VHD_FOOTER_COOKIE { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x' } + +#define VHD_FOOTER_FEATURES_NONE 0x00000000 +#define VHD_FOOTER_FEATURES_TEMPORARY 0x00000001 +#define VHD_FOOTER_FEATURES_RESERVED 0x00000002 + +#define VHD_FOOTER_FILE_FORMAT_V1_0 0x00010000 + +#define VHD_FOOTER_DATA_OFFSET_FIXED_DISK 0xFFFFFFFFFFFFFFFFULL + +#define VHD_FOOTER_CREATOR_HOST_OS_WINDOWS { 'W', 'i', '2', 'k' } +#define VHD_FOOTER_CREATOR_HOST_OS_MAC { 'M', 'a', 'c', ' ' } + +#define VHD_FOOTER_TYPE_FIXED_HARD_DISK 0x00000002 +#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 + +#define INVALID_CALLBACK_VALUE 0xFFFFFFFF + +#define WIM_FLAG_RESERVED 0x00000001 +#define WIM_FLAG_VERIFY 0x00000002 +#define WIM_FLAG_INDEX 0x00000004 +#define WIM_FLAG_NO_APPLY 0x00000008 +#define WIM_FLAG_NO_DIRACL 0x00000010 +#define WIM_FLAG_NO_FILEACL 0x00000020 +#define WIM_FLAG_SHARE_WRITE 0x00000040 +#define WIM_FLAG_FILEINFO 0x00000080 +#define WIM_FLAG_NO_RP_FIX 0x00000100 + +// Bitmask for the kind of progress we want to report in the WIM progress callback +#define WIM_REPORT_PROGRESS 0x00000001 +#define WIM_REPORT_PROCESS 0x00000002 +#define WIM_REPORT_FILEINFO 0x00000004 + +#define WIM_GENERIC_READ GENERIC_READ +#define WIM_OPEN_EXISTING OPEN_EXISTING +#define WIM_UNDOCUMENTED_BULLSHIT 0x20000000 + +#define MBR_SIZE 512 // Might need to review this once we see bootable 4k systems + + +// From https://docs.microsoft.com/en-us/previous-versions/msdn10/dd834960(v=msdn.10) +// as well as https://msfn.org/board/topic/150700-wimgapi-wimmountimage-progressbar/ +enum WIMMessage { + WIM_MSG = WM_APP + 0x1476, + WIM_MSG_TEXT, + WIM_MSG_PROGRESS, // Indicates an update in the progress of an image application. + WIM_MSG_PROCESS, // Enables the caller to prevent a file or a directory from being captured or applied. + WIM_MSG_SCANNING, // Indicates that volume information is being gathered during an image capture. + WIM_MSG_SETRANGE, // Indicates the number of files that will be captured or applied. + WIM_MSG_SETPOS, // Indicates the number of files that have been captured or applied. + WIM_MSG_STEPIT, // Indicates that a file has been either captured or applied. + WIM_MSG_COMPRESS, // Enables the caller to prevent a file resource from being compressed during a capture. + WIM_MSG_ERROR, // Alerts the caller that an error has occurred while capturing or applying an image. + WIM_MSG_ALIGNMENT, // Enables the caller to align a file resource on a particular alignment boundary. + WIM_MSG_RETRY, // Sent when the file is being reapplied because of a network timeout. + WIM_MSG_SPLIT, // Enables the caller to align a file resource on a particular alignment boundary. + WIM_MSG_FILEINFO, // Used in conjunction with WimApplyImages()'s WIM_FLAG_FILEINFO flag to provide detailed file info. + WIM_MSG_INFO, // Sent when an info message is available. + WIM_MSG_WARNING, // Sent when a warning message is available. + WIM_MSG_CHK_PROCESS, + WIM_MSG_SUCCESS = 0, + WIM_MSG_ABORT_IMAGE = -1 +}; + +/* + * VHD Fixed HD footer (Big Endian) + * http://download.microsoft.com/download/f/f/e/ffef50a5-07dd-4cf8-aaa3-442c0673a029/Virtual%20Hard%20Disk%20Format%20Spec_10_18_06.doc + * NB: If a dymamic implementation is needed, check the GPL v3 compatible C++ implementation from: + * https://sourceforge.net/p/urbackup/backend/ci/master/tree/fsimageplugin/ + */ +#pragma pack(push, 1) +typedef struct vhd_footer { + char cookie[8]; + uint32_t features; + uint32_t file_format_version; + uint64_t data_offset; + uint32_t timestamp; + char creator_app[4]; + uint32_t creator_version; + char creator_host_os[4]; + uint64_t original_size; + uint64_t current_size; + union { + uint32_t geometry; + struct { + uint16_t cylinders; + uint8_t heads; + uint8_t sectors; + } chs; + } disk_geometry; + uint32_t disk_type; + uint32_t checksum; + uuid_t unique_id; + uint8_t saved_state; + uint8_t reserved[427]; +} vhd_footer; +#pragma pack(pop) + +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 char* WimMountImage(const char* image, int index); +extern BOOL WimUnmountImage(const char* image, int index); +extern BOOL WimIsValidIndex(const char* image, int index); +extern int8_t IsBootableImage(const char* path); +extern BOOL AppendVHDFooter(const char* vhd_path); diff --git a/src/wue.c b/src/wue.c index 1f19abfc468..5eb51d98558 100644 --- a/src/wue.c +++ b/src/wue.c @@ -24,6 +24,7 @@ #include #include "rufus.h" +#include "vhd.h" #include "drive.h" #include "format.h" #include "missing.h" @@ -359,7 +360,7 @@ BOOL SetupWinPE(char drive_letter) /// -2 on user cancel, -1 on other error, >=0 on success. int SetWinToGoIndex(void) { - char* mounted_iso, * val, mounted_image_path[128]; + char* mounted_iso, *val, mounted_image_path[128]; char xml_file[MAX_PATH] = ""; char* install_names[MAX_WININST]; StrArray version_name, version_index; @@ -619,8 +620,7 @@ BOOL ApplyWindowsCustomization(char drive_letter, int flags) // NB: Work with a copy of unattend_xml_flags as a paremeter since we will modify it. { BOOL r = FALSE, is_hive_mounted = FALSE; - int i; - const int wim_index = 2; + int i, wim_index = 2; const char* offline_hive_name = "RUFUS_OFFLINE_HIVE"; char boot_wim_path[] = "?:\\sources\\boot.wim", key_path[64]; char appraiserres_dll_src[] = "?:\\sources\\appraiserres.dll"; @@ -653,12 +653,16 @@ BOOL ApplyWindowsCustomization(char drive_letter, int flags) // appraiserres.dll otherwise setup.exe extracts its own. appraiserres_dll_src[0] = drive_letter; appraiserres_dll_dst[0] = drive_letter; - if (!MoveFileExU(appraiserres_dll_src, appraiserres_dll_dst, MOVEFILE_REPLACE_EXISTING)) + if (!MoveFileExU(appraiserres_dll_src, appraiserres_dll_dst, MOVEFILE_REPLACE_EXISTING) + && GetLastError() != ERROR_FILE_NOT_FOUND) { uprintf("Could not rename '%s': %s", appraiserres_dll_src, WindowsErrorString()); - else + } else { + if (GetLastError() == ERROR_SUCCESS) + uprintf("Renamed '%s' → '%s'", appraiserres_dll_src, appraiserres_dll_dst); CloseHandle(CreateFileU(appraiserres_dll_src, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)); - uprintf("Renamed '%s' → '%s'", appraiserres_dll_src, appraiserres_dll_dst); + uprintf("Created '%s' placeholder", appraiserres_dll_src); + } } UpdateProgressWithInfoForce(OP_PATCH, MSG_325, 0, PATCH_PROGRESS_TOTAL); @@ -666,6 +670,13 @@ BOOL ApplyWindowsCustomization(char drive_letter, int flags) // not, we can just copy our unattend.xml in \sources\$OEM$\$$\Panther\. if (flags & UNATTEND_WINPE_SETUP_MASK) { uprintf("Mounting '%s'...", boot_wim_path); + // Some "unofficial" ISOs have a modified boot.wim that doesn't have Windows Setup at index 2... + if (!WimIsValidIndex(boot_wim_path, wim_index)) { + uprintf("WARNING: This image appears to be an UNOFFICIAL Windows ISO!"); + uprintf("Rufus recommends that you only use OFFICIAL retail Microsoft Windows images, such as"); + uprintf("the ones that can be downloaded through the download facility of this application."); + wim_index = 1; + } mount_path = WimMountImage(boot_wim_path, wim_index); if (mount_path == NULL) goto out;