From bfa1656488a86cbd146860fe26c3256cbffb8149 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Thu, 22 May 2014 01:52:25 +0100 Subject: [PATCH] [core] Add VHD source image support * As part of #321 * Also improve FileDialog so that it can support multiple extensions * Also fix a typo in rufus.loc --- res/localization/rufus.loc | 2 +- src/format.c | 19 ++++--- src/rufus.c | 87 +++++++++++++------------------- src/rufus.h | 15 +++++- src/rufus.rc | 12 ++--- src/stdlg.c | 70 +++++++++++++++---------- src/vhd.c | 101 +++++++++++++++++++++++++++++++++++-- 7 files changed, 207 insertions(+), 99 deletions(-) diff --git a/res/localization/rufus.loc b/res/localization/rufus.loc index ea662a32..2250a37f 100644 --- a/res/localization/rufus.loc +++ b/res/localization/rufus.loc @@ -264,7 +264,7 @@ t MSG_096 "Only FAT/FAT32 is supported for this type of ISO. Please select FAT/F t MSG_097 "Only 'bootmgr' or 'WinPE' based ISO images can currently be used with NTFS." t MSG_098 "FAT/FAT32 can only be used for isolinux based ISO images or when the Target Type is UEFI." t MSG_099 "Filesystem limitation" -t MSG_100 "This ISO image contains a file larger than 4GB file, which is more than the " +t MSG_100 "This ISO image contains a file larger than 4GB, which is more than the " "maximum size allowed for a FAT or FAT32 file system." t MSG_101 "Missing WIM support" t MSG_102 "Your platform cannot extract files from WIM archives. WIM extraction " diff --git a/src/format.c b/src/format.c index f4201e7d..bdf04111 100644 --- a/src/format.c +++ b/src/format.c @@ -1360,12 +1360,13 @@ DWORD WINAPI FormatThread(void* param) // Write an image file if (dt == DT_IMG) { - // We poked the MBR, so we need to rewind + // We poked the MBR and other stuff, so we need to rewind li.QuadPart = 0; - SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN); - hSourceImage = CreateFileU(iso_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); + if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN)) + uprintf("Warning: Unable to rewind image position - wrong data might be copied!"); + hSourceImage = CreateFileU(image_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (hSourceImage == INVALID_HANDLE_VALUE) { - uprintf("Could not open image '%s': %s", iso_path, WindowsErrorString()); + uprintf("Could not open image '%s': %s", image_path, WindowsErrorString()); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; goto out; } @@ -1397,6 +1398,10 @@ DWORD WINAPI FormatThread(void* param) UpdateProgress(OP_FORMAT, format_percent); } CHECK_FOR_USER_CANCEL; + // Don't overflow our projected size (mostly for VHDs) + if (wb + rSize > iso_report.projected_size) { + rSize = (DWORD)(iso_report.projected_size - wb); + } for (i=0; i use a thread DWORD WINAPI ISOScanThread(LPVOID param) { @@ -940,21 +915,24 @@ DWORD WINAPI ISOScanThread(LPVOID param) BOOL r; char isolinux_str[16] = "No"; - if (iso_path == NULL) + if (image_path == NULL) goto out; PrintStatus(0, TRUE, MSG_202); user_notified = FALSE; EnableControls(FALSE); - r = ExtractISO(iso_path, "", TRUE) || IsImage(iso_path); + r = ExtractISO(image_path, "", TRUE) || IsHDImage(image_path); EnableControls(TRUE); if (!r) { SendMessage(hISOProgressDlg, UM_PROGRESS_EXIT, 0, 0); PrintStatus(0, TRUE, MSG_203); - safe_free(iso_path); + safe_free(image_path); goto out; } - if (!iso_report.is_bootable_img) { + if (iso_report.is_bootable_img) { + uprintf("Using bootable %s image: '%s'", iso_report.is_vhd?"VHD":"disk", image_path); + selection_default = DT_IMG; + } else { if (HAS_SYSLINUX(iso_report)) { safe_sprintf(isolinux_str, sizeof(isolinux_str), "Yes (%s)", iso_report.sl_version_str); } @@ -974,7 +952,7 @@ DWORD WINAPI ISOScanThread(LPVOID param) if ( (!iso_report.has_bootmgr) && (!HAS_SYSLINUX(iso_report)) && (!IS_WINPE(iso_report.winpe)) && (!iso_report.has_efi) && (!IS_REACTOS(iso_report) && (!iso_report.has_kolibrios) && (!iso_report.is_bootable_img)) ) { MessageBoxU(hMainDialog, lmprintf(MSG_082), lmprintf(MSG_081), MB_OK|MB_ICONINFORMATION|MB_IS_RTL); - safe_free(iso_path); + safe_free(image_path); SetMBRProps(); } else { // Enable bootable and set Target System and FS accordingly @@ -992,8 +970,8 @@ DWORD WINAPI ISOScanThread(LPVOID param) SendMessage(hMainDialog, WM_COMMAND, (CBN_SELCHANGE<<16) | IDC_FILESYSTEM, ComboBox_GetCurSel(hFileSystem)); } - for (i=(int)safe_strlen(iso_path); (i>0)&&(iso_path[i]!='\\'); i--); - PrintStatus(0, TRUE, MSG_205, &iso_path[i+1]); + for (i=(int)safe_strlen(image_path); (i>0)&&(image_path[i]!='\\'); i--); + PrintStatus(0, TRUE, MSG_205, &image_path[i+1]); // Lose the focus on the select ISO (but place it on Close) SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)FALSE, 0); // Lose the focus from Close and set it back to Start @@ -1100,7 +1078,7 @@ static BOOL BootCheck(void) syslinux_ldlinux_len[0] = 0; syslinux_ldlinux_len[1] = 0; dt = (int)ComboBox_GetItemData(hBootType, ComboBox_GetCurSel(hBootType)); if ((dt == DT_ISO) || (dt == DT_IMG)) { - if (iso_path == NULL) { + if (image_path == NULL) { // Please click on the disc button to select a bootable ISO MessageBoxU(hMainDialog, lmprintf(MSG_087), lmprintf(MSG_086), MB_OK|MB_ICONERROR|MB_IS_RTL); return FALSE; @@ -1530,6 +1508,13 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA static LPITEMIDLIST pidlDesktop = NULL; static MY_SHChangeNotifyEntry NotifyEntry; loc_cmd* lcmd = NULL; + // TODO: Add "*.img;*.vhd" / "All Supported Images" to the list below and use a generic "%s Image" in the .loc + const char* img_x[] = { "*.img", "*.vhd" }; + const char* img_d[] = { lmprintf(MSG_095), "VHD Image" }; + ext_t img_ext = {ARRAYSIZE(img_x), NULL, img_x, img_d}; + const char* iso_x[] = { "*.iso" }; + const char* iso_d[] = { lmprintf(MSG_036) }; + ext_t iso_ext = {ARRAYSIZE(iso_x), NULL, iso_x, iso_d }; switch (message) { @@ -1809,7 +1794,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA EnableAdvancedBootOptions(TRUE, TRUE); ToggleImage(!IsChecked(IDC_BOOT) || (selection_default != DT_IMG)); if ((selection_default == DT_ISO) || (selection_default == DT_IMG)) { - if ((iso_path == NULL) || (iso_report.label[0] == 0)) { + if ((image_path == NULL) || (iso_report.label[0] == 0)) { // Set focus to the Select ISO button SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)FALSE, 0); SendMessage(hMainDialog, WM_NEXTDLGCTL, (WPARAM)hSelectISO, TRUE); @@ -1830,21 +1815,21 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA return (INT_PTR)TRUE; case IDC_SELECT_ISO: if (iso_provided) { - uprintf("Image provided: '%s'\n", iso_path); + uprintf("Image provided: '%s'\n", image_path); iso_provided = FALSE; // One off thing... } else { - safe_free(iso_path); + safe_free(image_path); if (selection_default == DT_IMG) - iso_path = FileDialog(FALSE, NULL, "*.img", "img", "DD Image", 0); + image_path = FileDialog(FALSE, NULL, &img_ext, 0); else - iso_path = FileDialog(FALSE, NULL, "*.iso", "iso", lmprintf(MSG_036), 0); - if (iso_path == NULL) { + image_path = FileDialog(FALSE, NULL, &iso_ext, 0); + if (image_path == NULL) { CreateTooltip(hSelectISO, lmprintf(MSG_173), -1); break; } } selection_default = DT_ISO; - CreateTooltip(hSelectISO, iso_path, -1); + CreateTooltip(hSelectISO, image_path, -1); FormatStatus = 0; if (CreateThread(NULL, 0, ISOScanThread, NULL, 0, NULL) == NULL) { uprintf("Unable to start ISO scanning thread"); @@ -2095,7 +2080,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine break; case 'i': if (_access(optarg, 0) != -1) { - iso_path = safe_strdup(optarg); + image_path = safe_strdup(optarg); iso_provided = TRUE; } else { printf("Could not find ISO image '%s'\n", optarg); @@ -2282,7 +2267,7 @@ relaunch: if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'I')) { enable_iso = !enable_iso; PrintStatus2000(lmprintf(MSG_262), enable_iso); - if (iso_path != NULL) { + if (image_path != NULL) { iso_provided = TRUE; PostMessage(hDlg, WM_COMMAND, IDC_SELECT_ISO, 0); } @@ -2354,7 +2339,7 @@ out: DeleteFileU(loc_file); DestroyAllTooltips(); exit_localization(); - safe_free(iso_path); + safe_free(image_path); safe_free(locale_name); safe_free(update.download_url); safe_free(update.release_notes); diff --git a/src/rufus.h b/src/rufus.h index 2201b4e8..02e9d457 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -247,6 +247,7 @@ typedef struct { BOOL has_kolibrios; BOOL uses_minint; BOOL is_bootable_img; + BOOL is_vhd; uint16_t sl_version; // Syslinux/Isolinux version char sl_version_str[12]; } RUFUS_ISO_REPORT; @@ -285,6 +286,15 @@ enum WindowsVersion { WINDOWS_MAX }; +/* Extensions structure used by FileDialog() */ +typedef struct ext_t { + const size_t count; + const char* filename; + const char** extension; + const char** description; +} ext_t; + + /* * Globals */ @@ -294,7 +304,7 @@ extern HWND hPartitionScheme, hFileSystem, hClusterSize, hLabel, hBootType, hNBP extern HWND hISOProgressDlg, hISOProgressBar, hISOFileName, hDiskID; extern float fScale; extern char szFolderPath[MAX_PATH], app_dir[MAX_PATH]; -extern char* iso_path; +extern char* image_path; extern DWORD FormatStatus; extern DWORD syslinux_ldlinux_len[2]; extern RUFUS_DRIVE_INFO SelectedDrive; @@ -342,7 +352,7 @@ extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter); DWORD WINAPI FormatThread(void* param); extern BOOL CreateProgress(void); extern BOOL SetAutorun(const char* path); -extern char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_desc, DWORD options); +extern char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options); extern BOOL FileIO(BOOL save, char* path, char** buffer, DWORD* size); extern unsigned char* GetResource(HMODULE module, char* name, char* type, const char* desc, DWORD* len, BOOL duplicate); extern BOOL GetUSBDevices(DWORD devnum); @@ -362,6 +372,7 @@ extern char* replace_in_token_data(const char* filename, const char* token, cons extern void parse_update(char* buf, size_t len); extern BOOL WimExtractCheck(void); extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst); +extern BOOL IsHDImage(const char* path); extern int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid); static __inline BOOL UnlockDrive(HANDLE hDrive) diff --git a/src/rufus.rc b/src/rufus.rc index 6c0ea47a..b58d2ff6 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 206, 329 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU -CAPTION "Rufus 1.4.8.479" +CAPTION "Rufus 1.4.8.480" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "Start",IDC_START,94,291,50,14 @@ -165,7 +165,7 @@ END RTL_IDD_DIALOG DIALOGEX 12, 12, 206, 329 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL -CAPTION "Rufus 1.4.8.479" +CAPTION "Rufus 1.4.8.480" FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN DEFPUSHBUTTON "Start",IDC_START,94,291,50,14 @@ -427,8 +427,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,4,8,479 - PRODUCTVERSION 1,4,8,479 + FILEVERSION 1,4,8,480 + PRODUCTVERSION 1,4,8,480 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -445,13 +445,13 @@ BEGIN BEGIN VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "1.4.8.479" + VALUE "FileVersion", "1.4.8.480" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "1.4.8.479" + VALUE "ProductVersion", "1.4.8.480" END END BLOCK "VarFileInfo" diff --git a/src/stdlg.c b/src/stdlg.c index 10680c87..a735cda3 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -237,13 +237,13 @@ fallback: * CoInitializeEx() for *EACH* thread you invoke FileDialog from, as * GetDisplayName() will return error 0x8001010E otherwise. */ -char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_desc, DWORD options) +char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options) { DWORD tmp; OPENFILENAMEA ofn; char selected_name[MAX_PATH]; char *ext_string = NULL, *all_files = NULL; - size_t i, ext_strlen; + size_t i, j, ext_strlen; BOOL r; char* filepath = NULL; @@ -251,25 +251,26 @@ char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_des HRESULT hr = FALSE; IFileDialog *pfd = NULL; IShellItem *psiResult; - COMDLG_FILTERSPEC filter_spec[2]; - char* ext_filter; + COMDLG_FILTERSPEC* filter_spec; wchar_t *wpath = NULL, *wfilename = NULL; IShellItem *si_path = NULL; // Automatically freed +#endif + if ((ext == NULL) || (ext->count == 0) || (ext->extension == NULL) || (ext->description == NULL)) + return NULL; dialog_showing++; - memset(filter_spec, 0, sizeof(filter_spec)); + +#if (_WIN32_WINNT >= 0x0600) // Vista and later INIT_VISTA_SHELL32; - if (IS_VISTA_SHELL32_AVAILABLE) { + filter_spec = (COMDLG_FILTERSPEC*)calloc(ext->count + 1, sizeof(COMDLG_FILTERSPEC)); + if ((IS_VISTA_SHELL32_AVAILABLE) && (filter_spec != NULL)) { // Setup the file extension filter table - ext_filter = (char*)malloc(safe_strlen(ext)+3); - if (ext_filter != NULL) { - safe_sprintf(ext_filter, safe_strlen(ext)+3, "*.%s", ext); - filter_spec[0].pszSpec = utf8_to_wchar(ext_filter); - safe_free(ext_filter); - filter_spec[0].pszName = utf8_to_wchar(ext_desc); - filter_spec[1].pszSpec = L"*.*"; - filter_spec[1].pszName = utf8_to_wchar(lmprintf(MSG_107)); + for (i=0; icount; i++) { + filter_spec[i].pszSpec = utf8_to_wchar(ext->extension[i]); + filter_spec[i].pszName = utf8_to_wchar(ext->description[i]); } + filter_spec[i].pszSpec = L"*.*"; + filter_spec[i].pszName = utf8_to_wchar(lmprintf(MSG_107)); hr = CoCreateInstance(save?&CLSID_FileSaveDialog:&CLSID_FileOpenDialog, NULL, CLSCTX_INPROC, &IID_IFileDialog, (LPVOID)&pfd); @@ -282,7 +283,7 @@ char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_des } // Set the file extension filters - pfd->lpVtbl->SetFileTypes(pfd, 2, filter_spec); + pfd->lpVtbl->SetFileTypes(pfd, ext->count+1, filter_spec); // Set the default directory wpath = utf8_to_wchar(path); @@ -293,7 +294,7 @@ char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_des safe_free(wpath); // Set the default filename - wfilename = utf8_to_wchar(filename); + wfilename = utf8_to_wchar((ext->filename == NULL)?ext->extension[0]:ext->filename); if (wfilename != NULL) { pfd->lpVtbl->SetFileName(pfd, wfilename); } @@ -303,9 +304,12 @@ char* FileDialog(BOOL save, char* path, char* filename, char* ext, char* ext_des // Cleanup safe_free(wfilename); - safe_free(filter_spec[0].pszSpec); - safe_free(filter_spec[0].pszName); - safe_free(filter_spec[1].pszName); + for (i=0; icount; i++) { + safe_free(filter_spec[i].pszSpec); + safe_free(filter_spec[i].pszName); + } + safe_free(filter_spec[i].pszName); + safe_free(filter_spec); if (SUCCEEDED(hr)) { // Obtain the result of the user's interaction with the dialog. @@ -336,24 +340,30 @@ fallback: if (pfd != NULL) { pfd->lpVtbl->Release(pfd); } -#else - dialog_showing++; #endif memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = hMainDialog; - // File name - safe_strcpy(selected_name, MAX_PATH, filename); + // Selected File name + static_sprintf(selected_name, "%s", (ext->filename == NULL)?ext->extension[0]:ext->filename); ofn.lpstrFile = selected_name; ofn.nMaxFile = MAX_PATH; // Set the file extension filters all_files = lmprintf(MSG_107); - ext_strlen = safe_strlen(ext_desc) + 2*safe_strlen(ext) + sizeof(" (*.)\0*.\0 (*.*)\0*.*\0\0") + safe_strlen(all_files); - ext_string = (char*)malloc(ext_strlen); + ext_strlen = 0; + for (i=0; icount; i++) { + ext_strlen += safe_strlen(ext->description[i]) + 2*safe_strlen(ext->extension[i]) + sizeof(" ()\r\r"); + } + ext_strlen += safe_strlen(all_files) + sizeof(" (*.*)\r*.*\r"); + ext_string = (char*)malloc(ext_strlen+1); + ext_string[0] = 0; if (ext_string == NULL) return NULL; - safe_sprintf(ext_string, ext_strlen, "%s (*.%s)\r*.%s\r%s (*.*)\r*.*\r\0", ext_desc, ext, ext, all_files); + for (i=0, j=0; icount; i++) { + j += _snprintf(&ext_string[j], ext_strlen-j, "%s (%s)\r%s\r", ext->description[i], ext->extension[i], ext->extension[i]); + } + j = _snprintf(&ext_string[j], ext_strlen-j, "%s (*.*)\r*.*\r", all_files); // Microsoft could really have picked a better delimiter! for (i=0; i0)&&(update.download_url[i]!='/'); i--); - filepath = FileDialog(TRUE, app_dir, (char*)&update.download_url[i+1], "exe", lmprintf(MSG_037), OFN_NOCHANGEDIR); + dl_ext.filename = &update.download_url[i+1]; + filepath = FileDialog(TRUE, app_dir, &dl_ext, OFN_NOCHANGEDIR); if (filepath == NULL) { uprintf("Could not get save path\n"); break; diff --git a/src/vhd.c b/src/vhd.c index fc6e7766..dec41d8b 100644 --- a/src/vhd.c +++ b/src/vhd.c @@ -18,17 +18,56 @@ */ #include +#include #include #include "rufus.h" #include "msapi_utf8.h" +#include "drive.h" #include "registry.h" -static BOOL has_wimgapi = FALSE, has_7z = FALSE; -static char sevenzip_path[MAX_PATH]; +#if defined(_MSC_VER) +#define bswap_uint64 _byteswap_uint64 +#define bswap_uint32 _byteswap_ulong +#define bswap_uint16 _byteswap_ushort +#else +#define bswap_uint64 __builtin_bswap64 +#define bswap_uint32 __builtin_bswap32 +#define bswap_uint16 __builtin_bswap16 +#endif -// TODO: Add a call to generate a Fixed Hard Disk VHD footer, This would allow the saving of an existing USB to VHD. See VHD specs at: -// http://download.microsoft.com/download/f/f/e/ffef50a5-07dd-4cf8-aaa3-442c0673a029/Virtual%20Hard%20Disk%20Format%20Spec_10_18_06.doc +#define VHD_FOOTER_COOKIE { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x' } + +#define VHD_FOOTER_FILE_FORMAT_V1_0 0x00010000 + +#define VHD_FOOTER_TYPE_FIXED_HARD_DISK 0x00000002 +#define VHD_FOOTER_TYPE_DYNAMIC_HARD_DISK 0x00000003 +#define VHD_FOOTER_TYPE_DIFFER_HARD_DISK 0x00000004 + +/* + * 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 + */ +#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; + uint32_t creator_app; + uint32_t creator_version; + uint32_t creator_host_os; + uint64_t original_size; + uint64_t current_size; + uint32_t 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 @@ -39,6 +78,9 @@ PF_TYPE_DECL(WINAPI, HANDLE, WIMLoadImage, (HANDLE, DWORD)); PF_TYPE_DECL(WINAPI, BOOL, WIMExtractImagePath, (HANDLE, PWSTR, PWSTR, DWORD)); PF_TYPE_DECL(WINAPI, BOOL, WIMCloseHandle, (HANDLE)); +static BOOL has_wimgapi = FALSE, has_7z = FALSE; +static char sevenzip_path[MAX_PATH]; + static BOOL Get7ZipPath(void) { if ( (GetRegistryKeyStr(REGKEY_HKCU, "7-Zip\\Path", sevenzip_path, sizeof(sevenzip_path))) @@ -49,6 +91,57 @@ static BOOL Get7ZipPath(void) return FALSE; } +BOOL IsHDImage(const char* path) +{ + const char conectix_str[] = VHD_FOOTER_COOKIE; + HANDLE handle = INVALID_HANDLE_VALUE; + LARGE_INTEGER liImageSize; + vhd_footer* footer = NULL; + DWORD size; + LARGE_INTEGER ptr; + + handle = CreateFileU(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if (handle == INVALID_HANDLE_VALUE) { + uprintf("Could not open image '%s'", path); + goto out; + } + iso_report.is_bootable_img = AnalyzeMBR(handle, "Image"); + + if (!GetFileSizeEx(handle, &liImageSize)) { + uprintf("Could not get image size: %s", WindowsErrorString()); + goto out; + } + iso_report.projected_size = (uint64_t)liImageSize.QuadPart; + + size = sizeof(vhd_footer); + if (iso_report.projected_size >= (512 + size)) { + footer = (vhd_footer*)malloc(size); + ptr.QuadPart = iso_report.projected_size - size; + if ( (footer == NULL) || (!SetFilePointerEx(handle, ptr, NULL, FILE_BEGIN)) || + (!ReadFile(handle, footer, size, &size, NULL)) || (size != sizeof(vhd_footer)) ) { + uprintf("Could not read VHD footer"); + goto out; + } + if (memcmp(footer->cookie, conectix_str, sizeof(footer->cookie)) == 0) { + iso_report.projected_size -= sizeof(vhd_footer); + if ( (bswap_uint32(footer->file_format_version) != VHD_FOOTER_FILE_FORMAT_V1_0) + || (bswap_uint32(footer->disk_type) != VHD_FOOTER_TYPE_FIXED_HARD_DISK)) { + uprintf("Unsupported type of VHD image"); + iso_report.is_bootable_img = FALSE; + goto out; + } + // Need to remove the footer from our payload + uprintf("Image is a Fixed Hard Disk VHD file"); + iso_report.is_vhd = TRUE; + } + } + +out: + safe_free(footer); + safe_closehandle(handle); + return iso_report.is_bootable_img; +} + // Find out if we have any way to extract WIM files on this platform BOOL WimExtractCheck(void) {