mirror of
				https://github.com/pbatard/rufus.git
				synced 2024-08-14 23:57:05 +00:00 
			
		
		
		
	[togo] Add Windows To Go support - part 1
* Add apply support to WIM image handling * Requires Windows 8 or later (Windows 7+ for WIM API support but Windows 8+ for ISO mount) * Also fix an issue for Windows 7 x64 EFI mode
This commit is contained in:
		
							parent
							
								
									99c24d6c88
								
							
						
					
					
						commit
						295650a8b4
					
				
					 6 changed files with 245 additions and 43 deletions
				
			
		
							
								
								
									
										28
									
								
								src/format.c
									
										
									
									
									
								
							
							
						
						
									
										28
									
								
								src/format.c
									
										
									
									
									
								
							|  | @ -1305,10 +1305,10 @@ DWORD WINAPI FormatThread(void* param) | ||||||
| 	LARGE_INTEGER li; | 	LARGE_INTEGER li; | ||||||
| 	uint64_t wb; | 	uint64_t wb; | ||||||
| 	uint8_t *buffer = NULL, *aligned_buffer; | 	uint8_t *buffer = NULL, *aligned_buffer; | ||||||
| 	char *bb_msg, *guid_volume = NULL; | 	char *bb_msg, *guid_volume = NULL, *mounted_iso; | ||||||
| 	char drive_name[] = "?:\\"; | 	char drive_name[] = "?:\\"; | ||||||
| 	char drive_letters[27]; | 	char drive_letters[27]; | ||||||
| 	char logfile[MAX_PATH], *userdir; | 	char logfile[MAX_PATH], image[128], *userdir; | ||||||
| 	char wim_image[] = "?:\\sources\\install.wim"; | 	char wim_image[] = "?:\\sources\\install.wim"; | ||||||
| 	char efi_dst[] = "?:\\efi\\boot\\bootx64.efi"; | 	char efi_dst[] = "?:\\efi\\boot\\bootx64.efi"; | ||||||
| 	char kolibri_dst[] = "?:\\MTLD_F32"; | 	char kolibri_dst[] = "?:\\MTLD_F32"; | ||||||
|  | @ -1693,7 +1693,26 @@ DWORD WINAPI FormatThread(void* param) | ||||||
| 				UpdateProgress(OP_DOS, 0.0f); | 				UpdateProgress(OP_DOS, 0.0f); | ||||||
| 				PrintInfoDebug(0, MSG_231); | 				PrintInfoDebug(0, MSG_231); | ||||||
| 				drive_name[2] = 0; | 				drive_name[2] = 0; | ||||||
| 				if (!ExtractISO(image_path, drive_name, FALSE)) { | 				// TODO: Check that we have apply-wim support
 | ||||||
|  | 				if (HAS_TOGO(iso_report) && (Button_GetCheck(GetDlgItem(hMainDialog, IDC_WINDOWS_TO_GO)) == BST_CHECKED)) { | ||||||
|  | 					uprintf("Windows To Go mode selected"); | ||||||
|  | 					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); | ||||||
|  | 					} else { | ||||||
|  | 						uprintf("Mounted ISO as '%s'", mounted_iso); | ||||||
|  | 						static_sprintf(image, "%s\\sources\\install.wim", mounted_iso); | ||||||
|  | 						if (!WimApplyImage(image, 1, drive_name)) { | ||||||
|  | 							uprintf("Failed to setup Windows To Go"); | ||||||
|  | 							if (!IS_ERROR(FormatStatus)) | ||||||
|  | 								FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_ISO_EXTRACT); | ||||||
|  | 						} | ||||||
|  | 						UnMountISO(); | ||||||
|  | 					} | ||||||
|  | 					if (IS_ERROR(FormatStatus)) | ||||||
|  | 						goto out; | ||||||
|  | 				} else if (!ExtractISO(image_path, drive_name, FALSE)) { | ||||||
| 					if (!IS_ERROR(FormatStatus)) | 					if (!IS_ERROR(FormatStatus)) | ||||||
| 						FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY; | 						FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_CANNOT_COPY; | ||||||
| 					goto out; | 					goto out; | ||||||
|  | @ -1706,7 +1725,8 @@ DWORD WINAPI FormatThread(void* param) | ||||||
| 						uprintf("Warning: loader installation failed - KolibriOS will not boot!\n"); | 						uprintf("Warning: loader installation failed - KolibriOS will not boot!\n"); | ||||||
| 					} | 					} | ||||||
| 				} | 				} | ||||||
| 				if ((bt == BT_UEFI) && (!iso_report.has_efi)) { | 				// EFI mode selected, with no 'bootx64.efi' (bit #2) but Windows 7 x64's 'bootmgr.efi' (bit #0)
 | ||||||
|  | 				if ((bt == BT_UEFI) && (!(iso_report.has_efi & 4)) && (iso_report.has_efi & 1)) { | ||||||
| 					PrintInfoDebug(0, MSG_232); | 					PrintInfoDebug(0, MSG_232); | ||||||
| 					wim_image[0] = drive_name[0]; | 					wim_image[0] = drive_name[0]; | ||||||
| 					efi_dst[0] = drive_name[0]; | 					efi_dst[0] = drive_name[0]; | ||||||
|  |  | ||||||
|  | @ -290,6 +290,7 @@ static void print_extracted_file(char* psz_fullpath, int64_t i_file_length) | ||||||
| 	safe_sprintf(&psz_fullpath[nul_pos], 24, " (%s)", SizeToHumanReadable(i_file_length, TRUE, FALSE)); | 	safe_sprintf(&psz_fullpath[nul_pos], 24, " (%s)", SizeToHumanReadable(i_file_length, TRUE, FALSE)); | ||||||
| 	uprintf("Extracting: %s\n", psz_fullpath); | 	uprintf("Extracting: %s\n", psz_fullpath); | ||||||
| 	safe_sprintf(&psz_fullpath[nul_pos], 24, " (%s)", SizeToHumanReadable(i_file_length, FALSE, FALSE)); | 	safe_sprintf(&psz_fullpath[nul_pos], 24, " (%s)", SizeToHumanReadable(i_file_length, FALSE, FALSE)); | ||||||
|  | 	// TODO: I don't think we need both of these...
 | ||||||
| 	SendMessageLU(GetDlgItem(hMainDialog, IDC_STATUS), SB_SETTEXTW, SBT_OWNERDRAW, psz_fullpath); | 	SendMessageLU(GetDlgItem(hMainDialog, IDC_STATUS), SB_SETTEXTW, SBT_OWNERDRAW, psz_fullpath); | ||||||
| 	PrintStatus(0, MSG_000, psz_fullpath);	// MSG_000 is "%s"
 | 	PrintStatus(0, MSG_000, psz_fullpath);	// MSG_000 is "%s"
 | ||||||
| 	// ISO9660 cannot handle backslashes
 | 	// ISO9660 cannot handle backslashes
 | ||||||
|  |  | ||||||
|  | @ -1960,8 +1960,6 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA | ||||||
| 			break; | 			break; | ||||||
| #ifdef RUFUS_TEST | #ifdef RUFUS_TEST | ||||||
| 		case IDC_TEST: | 		case IDC_TEST: | ||||||
| 			uprintf("Mounted ISO: '%s'", MountISO("D:\\ISOs\\archlinux-2012.08.04-dual.iso")); |  | ||||||
| #if 0 |  | ||||||
| 			if (format_thid != NULL) { | 			if (format_thid != NULL) { | ||||||
| 				return (INT_PTR)TRUE; | 				return (INT_PTR)TRUE; | ||||||
| 			} | 			} | ||||||
|  | @ -2009,7 +2007,6 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA | ||||||
| 			} | 			} | ||||||
| 			if (format_thid == NULL) | 			if (format_thid == NULL) | ||||||
| 				format_op_in_progress = FALSE; | 				format_op_in_progress = FALSE; | ||||||
| #endif |  | ||||||
| 			break; | 			break; | ||||||
| #endif | #endif | ||||||
| 		case IDC_LANG: | 		case IDC_LANG: | ||||||
|  |  | ||||||
|  | @ -411,8 +411,9 @@ extern char* insert_section_data(const char* filename, const char* section, cons | ||||||
| extern char* replace_in_token_data(const char* filename, const char* token, const char* src, const char* rep, BOOL dos2unix); | extern char* replace_in_token_data(const char* filename, const char* token, const char* src, const char* rep, BOOL dos2unix); | ||||||
| extern char* replace_char(const char* src, const char c, const char* rep); | extern char* replace_char(const char* src, const char c, const char* rep); | ||||||
| extern void parse_update(char* buf, size_t len); | extern void parse_update(char* buf, size_t len); | ||||||
| extern BOOL WimExtractCheck(void); | extern uint8_t WimExtractCheck(void); | ||||||
| extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst); | extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst); | ||||||
|  | extern BOOL WimApplyImage(const char* image, int index, const char* dst); | ||||||
| extern BOOL IsHDImage(const char* path); | extern BOOL IsHDImage(const char* path); | ||||||
| extern BOOL AppendVHDFooter(const char* vhd_path); | extern BOOL AppendVHDFooter(const char* vhd_path); | ||||||
| extern int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid); | extern int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid); | ||||||
|  |  | ||||||
							
								
								
									
										16
									
								
								src/rufus.rc
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								src/rufus.rc
									
										
									
									
									
								
							|  | @ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL | ||||||
| 
 | 
 | ||||||
| IDD_DIALOG DIALOGEX 12, 12, 242, 376 | IDD_DIALOG DIALOGEX 12, 12, 242, 376 | ||||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | ||||||
| CAPTION "Rufus 2.0.0.573" | CAPTION "Rufus 2.0.0.574" | ||||||
| FONT 8, "Segoe UI", 400, 0, 0x1 | FONT 8, "Segoe UI", 400, 0, 0x1 | ||||||
| BEGIN | BEGIN | ||||||
|     DEFPUSHBUTTON   "Start",IDC_START,127,339,50,14 |     DEFPUSHBUTTON   "Start",IDC_START,127,339,50,14 | ||||||
|  | @ -157,7 +157,7 @@ END | ||||||
| 
 | 
 | ||||||
| IDD_DIALOG_XP DIALOGEX 12, 12, 242, 376 | IDD_DIALOG_XP DIALOGEX 12, 12, 242, 376 | ||||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | ||||||
| CAPTION "Rufus 2.0.0.573" | CAPTION "Rufus 2.0.0.574" | ||||||
| FONT 8, "MS Shell Dlg", 400, 0, 0x1 | FONT 8, "MS Shell Dlg", 400, 0, 0x1 | ||||||
| BEGIN | BEGIN | ||||||
|     DEFPUSHBUTTON   "Start",IDC_START,127,339,50,14 |     DEFPUSHBUTTON   "Start",IDC_START,127,339,50,14 | ||||||
|  | @ -283,7 +283,7 @@ END | ||||||
| IDD_DIALOG_RTL DIALOGEX 12, 12, 242, 376 | IDD_DIALOG_RTL DIALOGEX 12, 12, 242, 376 | ||||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | ||||||
| EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL | EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL | ||||||
| CAPTION "Rufus 2.0.0.573" | CAPTION "Rufus 2.0.0.574" | ||||||
| FONT 8, "Segoe UI", 400, 0, 0x1 | FONT 8, "Segoe UI", 400, 0, 0x1 | ||||||
| BEGIN | BEGIN | ||||||
|     DEFPUSHBUTTON   "Start",IDC_START,127,339,50,14 |     DEFPUSHBUTTON   "Start",IDC_START,127,339,50,14 | ||||||
|  | @ -415,7 +415,7 @@ END | ||||||
| IDD_DIALOG_RTL_XP DIALOGEX 12, 12, 242, 376 | IDD_DIALOG_RTL_XP DIALOGEX 12, 12, 242, 376 | ||||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU | ||||||
| EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL | EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL | ||||||
| CAPTION "Rufus 2.0.0.573" | CAPTION "Rufus 2.0.0.574" | ||||||
| FONT 8, "MS Shell Dlg", 400, 0, 0x1 | FONT 8, "MS Shell Dlg", 400, 0, 0x1 | ||||||
| BEGIN | BEGIN | ||||||
|     DEFPUSHBUTTON   "Start",IDC_START,127,339,50,14 |     DEFPUSHBUTTON   "Start",IDC_START,127,339,50,14 | ||||||
|  | @ -669,8 +669,8 @@ END | ||||||
| // | // | ||||||
| 
 | 
 | ||||||
| VS_VERSION_INFO VERSIONINFO | VS_VERSION_INFO VERSIONINFO | ||||||
|  FILEVERSION 2,0,0,573 |  FILEVERSION 2,0,0,574 | ||||||
|  PRODUCTVERSION 2,0,0,573 |  PRODUCTVERSION 2,0,0,574 | ||||||
|  FILEFLAGSMASK 0x3fL |  FILEFLAGSMASK 0x3fL | ||||||
| #ifdef _DEBUG | #ifdef _DEBUG | ||||||
|  FILEFLAGS 0x1L |  FILEFLAGS 0x1L | ||||||
|  | @ -687,13 +687,13 @@ BEGIN | ||||||
|         BEGIN |         BEGIN | ||||||
|             VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" |             VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)" | ||||||
|             VALUE "FileDescription", "Rufus" |             VALUE "FileDescription", "Rufus" | ||||||
|             VALUE "FileVersion", "2.0.0.573" |             VALUE "FileVersion", "2.0.0.574" | ||||||
|             VALUE "InternalName", "Rufus" |             VALUE "InternalName", "Rufus" | ||||||
|             VALUE "LegalCopyright", "© 2011-2015 Pete Batard (GPL v3)" |             VALUE "LegalCopyright", "© 2011-2015 Pete Batard (GPL v3)" | ||||||
|             VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" |             VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html" | ||||||
|             VALUE "OriginalFilename", "rufus.exe" |             VALUE "OriginalFilename", "rufus.exe" | ||||||
|             VALUE "ProductName", "Rufus" |             VALUE "ProductName", "Rufus" | ||||||
|             VALUE "ProductVersion", "2.0.0.573" |             VALUE "ProductVersion", "2.0.0.574" | ||||||
|         END |         END | ||||||
|     END |     END | ||||||
|     BLOCK "VarFileInfo" |     BLOCK "VarFileInfo" | ||||||
|  |  | ||||||
							
								
								
									
										237
									
								
								src/vhd.c
									
										
									
									
									
								
							
							
						
						
									
										237
									
								
								src/vhd.c
									
										
									
									
									
								
							|  | @ -1,7 +1,7 @@ | ||||||
| /*
 | /*
 | ||||||
|  * Rufus: The Reliable USB Formatting Utility |  * Rufus: The Reliable USB Formatting Utility | ||||||
|  * Virtual Disk Handling functions |  * Virtual Disk Handling functions | ||||||
|  * Copyright © 2013-2014 Pete Batard <pete@akeo.ie> |  * Copyright © 2013-2015 Pete Batard <pete@akeo.ie> | ||||||
|  * |  * | ||||||
|  * This program is free software: you can redistribute it and/or modify |  * 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 |  * it under the terms of the GNU General Public License as published by | ||||||
|  | @ -24,6 +24,7 @@ | ||||||
| #include <time.h> | #include <time.h> | ||||||
| 
 | 
 | ||||||
| #include "rufus.h" | #include "rufus.h" | ||||||
|  | #include "resource.h" | ||||||
| #include "msapi_utf8.h" | #include "msapi_utf8.h" | ||||||
| #include "drive.h" | #include "drive.h" | ||||||
| #include "registry.h" | #include "registry.h" | ||||||
|  | @ -98,11 +99,14 @@ typedef struct vhd_footer { | ||||||
| PF_TYPE_DECL(WINAPI, HANDLE, WIMCreateFile, (PWSTR, DWORD, DWORD, DWORD, DWORD, PDWORD)); | PF_TYPE_DECL(WINAPI, HANDLE, WIMCreateFile, (PWSTR, DWORD, DWORD, DWORD, DWORD, PDWORD)); | ||||||
| PF_TYPE_DECL(WINAPI, BOOL, WIMSetTemporaryPath, (HANDLE, PWSTR)); | PF_TYPE_DECL(WINAPI, BOOL, WIMSetTemporaryPath, (HANDLE, PWSTR)); | ||||||
| PF_TYPE_DECL(WINAPI, HANDLE, WIMLoadImage, (HANDLE, DWORD)); | PF_TYPE_DECL(WINAPI, HANDLE, WIMLoadImage, (HANDLE, DWORD)); | ||||||
|  | PF_TYPE_DECL(WINAPI, BOOL, WIMApplyImage, (HANDLE, PCWSTR, DWORD)); | ||||||
| PF_TYPE_DECL(WINAPI, BOOL, WIMExtractImagePath, (HANDLE, PWSTR, PWSTR, DWORD)); | PF_TYPE_DECL(WINAPI, BOOL, WIMExtractImagePath, (HANDLE, PWSTR, PWSTR, DWORD)); | ||||||
| PF_TYPE_DECL(WINAPI, BOOL, WIMCloseHandle, (HANDLE)); | PF_TYPE_DECL(WINAPI, BOOL, WIMCloseHandle, (HANDLE)); | ||||||
|  | PF_TYPE_DECL(WINAPI, DWORD, WIMRegisterMessageCallback, (HANDLE, FARPROC, PVOID)); | ||||||
|  | PF_TYPE_DECL(WINAPI, DWORD, WIMUnregisterMessageCallback, (HANDLE, FARPROC)); | ||||||
| PF_TYPE_DECL(RPC_ENTRY, RPC_STATUS, UuidCreate, (UUID __RPC_FAR*)); | PF_TYPE_DECL(RPC_ENTRY, RPC_STATUS, UuidCreate, (UUID __RPC_FAR*)); | ||||||
| 
 | 
 | ||||||
| static BOOL has_wimgapi = FALSE, has_7z = FALSE; | static uint8_t wim_flags = 0; | ||||||
| static char sevenzip_path[MAX_PATH]; | static char sevenzip_path[MAX_PATH]; | ||||||
| static const char conectix_str[] = VHD_FOOTER_COOKIE; | static const char conectix_str[] = VHD_FOOTER_COOKIE; | ||||||
| 
 | 
 | ||||||
|  | @ -313,21 +317,36 @@ out: | ||||||
| 	return iso_report.is_bootable_img; | 	return iso_report.is_bootable_img; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Find out if we have any way to extract WIM files on this platform
 | #define WIM_HAS_API_EXTRACT 1 | ||||||
| BOOL WimExtractCheck(void) | #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) | ||||||
| { | { | ||||||
| 	PF_INIT(WIMCreateFile, Wimgapi); | 	PF_INIT(WIMCreateFile, Wimgapi); | ||||||
| 	PF_INIT(WIMSetTemporaryPath, Wimgapi); | 	PF_INIT(WIMSetTemporaryPath, Wimgapi); | ||||||
| 	PF_INIT(WIMLoadImage, Wimgapi); | 	PF_INIT(WIMLoadImage, Wimgapi); | ||||||
|  | 	PF_INIT(WIMApplyImage, Wimgapi); | ||||||
| 	PF_INIT(WIMExtractImagePath, Wimgapi); | 	PF_INIT(WIMExtractImagePath, Wimgapi); | ||||||
|  | 	PF_INIT(WIMRegisterMessageCallback, Wimgapi); | ||||||
|  | 	PF_INIT(WIMUnregisterMessageCallback, Wimgapi); | ||||||
| 	PF_INIT(WIMCloseHandle, Wimgapi); | 	PF_INIT(WIMCloseHandle, Wimgapi); | ||||||
| 
 | 
 | ||||||
| 	has_wimgapi = (pfWIMCreateFile && pfWIMSetTemporaryPath && pfWIMLoadImage && pfWIMExtractImagePath && pfWIMCloseHandle); | 	if (pfWIMCreateFile && pfWIMSetTemporaryPath && pfWIMLoadImage && pfWIMExtractImagePath && pfWIMCloseHandle) | ||||||
| 	has_7z = Get7ZipPath(); | 		wim_flags |= WIM_HAS_API_EXTRACT; | ||||||
|  | 	if (Get7ZipPath()) | ||||||
|  | 		wim_flags |= WIM_HAS_7Z_EXTRACT; | ||||||
|  | 	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\n", has_7z?"7z":(has_wimgapi?"":"NONE"), | 	uprintf("WIM extraction method(s) supported: %s%s%s", (wim_flags & WIM_HAS_7Z_EXTRACT)?"7-Zip": | ||||||
| 		(has_wimgapi && has_7z)?", ":"", has_wimgapi?"wimgapi.dll":""); | 		((wim_flags & WIM_HAS_API_EXTRACT)?"":"NONE"), | ||||||
| 	return (has_wimgapi || has_7z); | 		(WIM_HAS_EXTRACT(wim_flags))?", ":"", (wim_flags & WIM_HAS_API_EXTRACT)?"wimgapi.dll":""); | ||||||
|  | 	uprintf("WIM apply method supported: %s", (wim_flags & WIM_HAS_API_APPLY)?"wimgapi.dll":"NONE"); | ||||||
|  | 	return wim_flags; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | @ -351,32 +370,32 @@ static BOOL WimExtractFile_API(const char* image, int index, const char* src, co | ||||||
| 	PF_INIT_OR_OUT(WIMExtractImagePath, Wimgapi); | 	PF_INIT_OR_OUT(WIMExtractImagePath, Wimgapi); | ||||||
| 	PF_INIT_OR_OUT(WIMCloseHandle, Wimgapi); | 	PF_INIT_OR_OUT(WIMCloseHandle, Wimgapi); | ||||||
| 
 | 
 | ||||||
| 	uprintf("Opening: %s:[%d] (API)\n", image, index); | 	uprintf("Opening: %s:[%d] (API)", image, index); | ||||||
| 	if (GetTempPathW(ARRAYSIZE(wtemp), wtemp) == 0) { | 	if (GetTempPathW(ARRAYSIZE(wtemp), wtemp) == 0) { | ||||||
| 		uprintf("  Could not fetch temp path: %s\n", WindowsErrorString()); | 		uprintf("  Could not fetch temp path: %s", WindowsErrorString()); | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	hWim = pfWIMCreateFile(wimage, WIM_GENERIC_READ, WIM_OPEN_EXISTING, 0, 0, &dw); | 	hWim = pfWIMCreateFile(wimage, WIM_GENERIC_READ, WIM_OPEN_EXISTING, 0, 0, &dw); | ||||||
| 	if (hWim == NULL) { | 	if (hWim == NULL) { | ||||||
| 		uprintf("  Could not access image: %s\n", WindowsErrorString()); | 		uprintf("  Could not access image: %s", WindowsErrorString()); | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!pfWIMSetTemporaryPath(hWim, wtemp)) { | 	if (!pfWIMSetTemporaryPath(hWim, wtemp)) { | ||||||
| 		uprintf("  Could not set temp path: %s\n", WindowsErrorString()); | 		uprintf("  Could not set temp path: %s", WindowsErrorString()); | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	hImage = pfWIMLoadImage(hWim, (DWORD)index); | 	hImage = pfWIMLoadImage(hWim, (DWORD)index); | ||||||
| 	if (hImage == NULL) { | 	if (hImage == NULL) { | ||||||
| 		uprintf("  Could not set index: %s\n", WindowsErrorString()); | 		uprintf("  Could not set index: %s", WindowsErrorString()); | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	uprintf("Extracting: %s (From %s)\n", dst, src); | 	uprintf("Extracting: %s (From %s)", dst, src); | ||||||
| 	if (!pfWIMExtractImagePath(hImage, wsrc, wdst, 0)) { | 	if (!pfWIMExtractImagePath(hImage, wsrc, wdst, 0)) { | ||||||
| 		uprintf("  Could not extract file: %s\n", WindowsErrorString()); | 		uprintf("  Could not extract file: %s", WindowsErrorString()); | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 	r = TRUE; | 	r = TRUE; | ||||||
|  | @ -384,10 +403,10 @@ static BOOL WimExtractFile_API(const char* image, int index, const char* src, co | ||||||
| 
 | 
 | ||||||
| out: | out: | ||||||
| 	if ((hImage != NULL) || (hWim != NULL)) { | 	if ((hImage != NULL) || (hWim != NULL)) { | ||||||
| 		uprintf("Closing: %s\n", image); | 		uprintf("Closing: %s", image); | ||||||
|  | 		if (hImage != NULL) pfWIMCloseHandle(hImage); | ||||||
|  | 		if (hWim != NULL) pfWIMCloseHandle(hWim); | ||||||
| 	} | 	} | ||||||
| 	if (hImage != NULL) pfWIMCloseHandle(hImage); |  | ||||||
| 	if (hWim != NULL) pfWIMCloseHandle(hWim); |  | ||||||
| 	safe_free(wimage); | 	safe_free(wimage); | ||||||
| 	safe_free(wsrc); | 	safe_free(wsrc); | ||||||
| 	safe_free(wdst); | 	safe_free(wdst); | ||||||
|  | @ -403,7 +422,7 @@ static BOOL WimExtractFile_7z(const char* image, int index, const char* src, con | ||||||
| 	char cmdline[MAX_PATH]; | 	char cmdline[MAX_PATH]; | ||||||
| 	char tmpdst[MAX_PATH]; | 	char tmpdst[MAX_PATH]; | ||||||
| 
 | 
 | ||||||
| 	uprintf("Opening: %s:[%d] (7-Zip)\n", image, index); | 	uprintf("Opening: %s:[%d] (7-Zip)", image, index); | ||||||
| 	safe_strcpy(tmpdst, sizeof(tmpdst), dst); | 	safe_strcpy(tmpdst, sizeof(tmpdst), dst); | ||||||
| 	for (i=safe_strlen(tmpdst); i>0; i--) { | 	for (i=safe_strlen(tmpdst); i>0; i--) { | ||||||
| 		if (tmpdst[i] == '\\') | 		if (tmpdst[i] == '\\') | ||||||
|  | @ -413,9 +432,9 @@ static BOOL WimExtractFile_7z(const char* image, int index, const char* src, con | ||||||
| 
 | 
 | ||||||
| 	si.cb = sizeof(si); | 	si.cb = sizeof(si); | ||||||
| 	safe_sprintf(cmdline, sizeof(cmdline), "7z -y e \"%s\" %d\\%s", image, index, src); | 	safe_sprintf(cmdline, sizeof(cmdline), "7z -y e \"%s\" %d\\%s", image, index, src); | ||||||
| 	uprintf("Extracting: %s (From %s)\n", dst, src); | 	uprintf("Extracting: %s (From %s)", dst, src); | ||||||
| 	if (!CreateProcessU(sevenzip_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, tmpdst, &si, &pi)) { | 	if (!CreateProcessU(sevenzip_path, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, tmpdst, &si, &pi)) { | ||||||
| 		uprintf("  Could not launch 7z.exe: %s\n", WindowsErrorString()); | 		uprintf("  Could not launch 7z.exe: %s", WindowsErrorString()); | ||||||
| 		return FALSE; | 		return FALSE; | ||||||
| 	} | 	} | ||||||
| 	WaitForSingleObject(pi.hProcess, INFINITE); | 	WaitForSingleObject(pi.hProcess, INFINITE); | ||||||
|  | @ -425,12 +444,12 @@ static BOOL WimExtractFile_7z(const char* image, int index, const char* src, con | ||||||
| 
 | 
 | ||||||
| 	safe_strcat(tmpdst, sizeof(tmpdst), "\\bootmgfw.efi"); | 	safe_strcat(tmpdst, sizeof(tmpdst), "\\bootmgfw.efi"); | ||||||
| 	if (_access(tmpdst, 0) == -1) { | 	if (_access(tmpdst, 0) == -1) { | ||||||
| 		uprintf("  7z.exe did not extract %s\n", tmpdst); | 		uprintf("  7z.exe did not extract %s", tmpdst); | ||||||
| 		return FALSE; | 		return FALSE; | ||||||
| 	} | 	} | ||||||
| 	// coverity[toctou]
 | 	// coverity[toctou]
 | ||||||
| 	if (rename(tmpdst, dst) != 0) { | 	if (rename(tmpdst, dst) != 0) { | ||||||
| 		uprintf("  Could not rename %s to %s\n", tmpdst, dst); | 		uprintf("  Could not rename %s to %s", tmpdst, dst); | ||||||
| 		return FALSE; | 		return FALSE; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -440,13 +459,177 @@ static BOOL WimExtractFile_7z(const char* image, int index, const char* src, con | ||||||
| // Extract a file from a WIM image
 | // 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) | ||||||
| { | { | ||||||
| 	if ((!has_wimgapi) && (!has_7z) && (!WimExtractCheck())) | 	if ((wim_flags == 0) && (!WIM_HAS_EXTRACT(WimExtractCheck()))) | ||||||
| 		return FALSE; | 		return FALSE; | ||||||
| 	if ((image == NULL) || (src == NULL) || (dst == NULL)) | 	if ((image == NULL) || (src == NULL) || (dst == NULL)) | ||||||
| 		return FALSE; | 		return FALSE; | ||||||
| 
 | 
 | ||||||
| 	// Prefer 7-Zip as, unsurprisingly, it's faster than the Microsoft way,
 | 	// Prefer 7-Zip as, unsurprisingly, it's faster than the Microsoft way,
 | ||||||
| 	// but allow fallback if 7-Zip doesn't succeed
 | 	// but allow fallback if 7-Zip doesn't succeed
 | ||||||
| 	return ( (has_7z && WimExtractFile_7z(image, index, src, dst)) | 	return ( ((wim_flags & WIM_HAS_7Z_EXTRACT) && WimExtractFile_7z(image, index, src, dst)) | ||||||
| 		  || (has_wimgapi && WimExtractFile_API(image, index, src, dst)) ); | 		  || ((wim_flags & WIM_HAS_API_EXTRACT) && WimExtractFile_API(image, index, src, dst)) ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Apply image functionality
 | ||||||
|  | static const char *_image, *_dst; | ||||||
|  | static int _index; | ||||||
|  | 
 | ||||||
|  | // From http://msdn.microsoft.com/en-us/library/windows/desktop/dd834960.aspx
 | ||||||
|  | // as well as http://www.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_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 = 0x00000000, | ||||||
|  | 	WIM_MSG_ABORT_IMAGE = 0xFFFFFFFF | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #define INVALID_CALLBACK_VALUE 0xFFFFFFFF | ||||||
|  | 
 | ||||||
|  | // Progress callback
 | ||||||
|  | DWORD WINAPI WimProgressCallback(DWORD dwMsgId, WPARAM wParam, LPARAM lParam, PVOID pvIgnored) | ||||||
|  | { | ||||||
|  | 	PBOOL pbCancel = NULL; | ||||||
|  | 	char* str = NULL; | ||||||
|  | 	const char* level = NULL; | ||||||
|  | 
 | ||||||
|  | 	switch (dwMsgId) { | ||||||
|  | 	case WIM_MSG_PROGRESS: | ||||||
|  | 		uprintf("  %d%% completed", (DWORD)wParam); | ||||||
|  | 		UpdateProgress(OP_DOS, 1.0f*(DWORD)wParam); | ||||||
|  | 		break; | ||||||
|  | 	case WIM_MSG_PROCESS: | ||||||
|  | 		// The amount of files processed is a bit overwhelming, and displaying it all slows us down
 | ||||||
|  | //#define WIM_DISPLAY_INDIVIDUAL_FILES
 | ||||||
|  | #if WIM_DISPLAY_INDIVIDUAL_FILES | ||||||
|  | 		str = wchar_to_utf8((PWSTR)wParam); | ||||||
|  | 		uprintf("Applying: '%s'", str); | ||||||
|  | 		PrintStatus(0, MSG_000, str);	// MSG_000 is "%s"
 | ||||||
|  | #endif | ||||||
|  | 		if (IS_ERROR(FormatStatus)) { | ||||||
|  | 			pbCancel = (PBOOL)lParam; | ||||||
|  | 			*pbCancel = TRUE; | ||||||
|  | 		} | ||||||
|  | 		break; | ||||||
|  | 	case WIM_MSG_RETRY: | ||||||
|  | 		level = "retry"; | ||||||
|  | 		// fall through
 | ||||||
|  | 	case WIM_MSG_INFO: | ||||||
|  | 		if (level == NULL) level = "info"; | ||||||
|  | 		// fall through
 | ||||||
|  | 	case WIM_MSG_WARNING: | ||||||
|  | 		if (level == NULL) level = "warning"; | ||||||
|  | 		// fall through
 | ||||||
|  | 	case WIM_MSG_ERROR: | ||||||
|  | 		if (level == NULL) level = "error"; | ||||||
|  | 		str = wchar_to_utf8((PWSTR)wParam); | ||||||
|  | 		SetLastError((DWORD)lParam); | ||||||
|  | 		uprintf("Apply %s: %s [err = %d]\n", level, str, WindowsErrorString()); | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 	safe_free(str); | ||||||
|  | 
 | ||||||
|  | 	return IS_ERROR(FormatStatus)?WIM_MSG_ABORT_IMAGE:WIM_MSG_SUCCESS; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Apply a WIM image using wimgapi.dll (Windows 7 or later)
 | ||||||
|  | // http://msdn.microsoft.com/en-us/library/windows/desktop/dd851944.aspx
 | ||||||
|  | // To get progress, we must run this call within its own thread
 | ||||||
|  | static DWORD WINAPI WimApplyImageThread(LPVOID param) | ||||||
|  | { | ||||||
|  | 	BOOL r = FALSE; | ||||||
|  | 	DWORD dw = 0; | ||||||
|  | 	HANDLE hWim = NULL; | ||||||
|  | 	HANDLE hImage = NULL; | ||||||
|  | 	wchar_t wtemp[MAX_PATH] = {0}; | ||||||
|  | 	wchar_t* wimage = utf8_to_wchar(_image); | ||||||
|  | 	wchar_t* wdst = utf8_to_wchar(_dst); | ||||||
|  | 
 | ||||||
|  | 	PF_INIT_OR_OUT(WIMRegisterMessageCallback, Wimgapi); | ||||||
|  | 	PF_INIT_OR_OUT(WIMCreateFile, Wimgapi); | ||||||
|  | 	PF_INIT_OR_OUT(WIMSetTemporaryPath, Wimgapi); | ||||||
|  | 	PF_INIT_OR_OUT(WIMLoadImage, Wimgapi); | ||||||
|  | 	PF_INIT_OR_OUT(WIMApplyImage, Wimgapi); | ||||||
|  | 	PF_INIT_OR_OUT(WIMCloseHandle, Wimgapi); | ||||||
|  | 	PF_INIT_OR_OUT(WIMUnregisterMessageCallback, Wimgapi); | ||||||
|  | 
 | ||||||
|  | 	uprintf("Opening: %s:[%d]", _image, _index); | ||||||
|  | 
 | ||||||
|  | 	if (pfWIMRegisterMessageCallback(NULL, (FARPROC)WimProgressCallback, NULL) == INVALID_CALLBACK_VALUE) { | ||||||
|  | 		uprintf("  Could not set progress callback: %s", WindowsErrorString()); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (GetTempPathW(ARRAYSIZE(wtemp), wtemp) == 0) { | ||||||
|  | 		uprintf("  Could not fetch temp path: %s", WindowsErrorString()); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	hWim = pfWIMCreateFile(wimage, WIM_GENERIC_READ, WIM_OPEN_EXISTING, 0, 0, &dw); | ||||||
|  | 	if (hWim == NULL) { | ||||||
|  | 		uprintf("  Could not access image: %s", WindowsErrorString()); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	if (!pfWIMSetTemporaryPath(hWim, wtemp)) { | ||||||
|  | 		uprintf("  Could not set temp path: %s", WindowsErrorString()); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	hImage = pfWIMLoadImage(hWim, (DWORD)_index); | ||||||
|  | 	if (hImage == NULL) { | ||||||
|  | 		uprintf("  Could not set index: %s", WindowsErrorString()); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	uprintf("Applying image..."); | ||||||
|  | 	if (!pfWIMApplyImage(hImage, wdst, 0)) { | ||||||
|  | 		uprintf("  Could not apply image: %s", WindowsErrorString()); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	r = TRUE; | ||||||
|  | 	UpdateProgress(OP_FINALIZE, -1.0f); | ||||||
|  | 
 | ||||||
|  | out: | ||||||
|  | 	if ((hImage != NULL) || (hWim != NULL)) { | ||||||
|  | 		uprintf("Closing: %s", _image); | ||||||
|  | 		if (hImage != NULL) pfWIMCloseHandle(hImage); | ||||||
|  | 		if (hWim != NULL) pfWIMCloseHandle(hWim); | ||||||
|  | 	} | ||||||
|  | 	pfWIMUnregisterMessageCallback(NULL, (FARPROC)WimProgressCallback); | ||||||
|  | 	safe_free(wimage); | ||||||
|  | 	safe_free(wdst); | ||||||
|  | 	ExitThread((DWORD)r); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | BOOL WimApplyImage(const char* image, int index, const char* dst) | ||||||
|  | { | ||||||
|  | 	_image = image; | ||||||
|  | 	_index = index; | ||||||
|  | 	_dst = dst; | ||||||
|  | 	HANDLE handle; | ||||||
|  | 	DWORD dw = 0; | ||||||
|  | 
 | ||||||
|  | 	handle = CreateThread(NULL, 0, WimApplyImageThread, NULL, 0, NULL); | ||||||
|  | 	if (handle == NULL) { | ||||||
|  | 		uprintf("Unable to start apply-image thread"); | ||||||
|  | 		return FALSE; | ||||||
|  | 	} | ||||||
|  | 	WaitForSingleObject(handle, INFINITE); | ||||||
|  | 	GetExitCodeThread(handle, &dw); | ||||||
|  | 	return (BOOL)dw; | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue