mirror of
				https://github.com/pbatard/rufus.git
				synced 2024-08-14 23:57:05 +00:00 
			
		
		
		
	[vhd] add backup to uncompressed VHD image
* Part of #321 * NOTE: This feature will be enabled after the 1.4.8 release
This commit is contained in:
		
							parent
							
								
									1e121d2025
								
							
						
					
					
						commit
						04bd5116a7
					
				
					 5 changed files with 329 additions and 51 deletions
				
			
		
							
								
								
									
										101
									
								
								src/format.c
									
										
									
									
									
								
							
							
						
						
									
										101
									
								
								src/format.c
									
										
									
									
									
								
							|  | @ -1397,12 +1397,12 @@ DWORD WINAPI FormatThread(void* param) | |||
| 				PrintStatus(0, FALSE, MSG_261, format_percent); | ||||
| 				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<WRITE_RETRIES; i++) { | ||||
| 				CHECK_FOR_USER_CANCEL; | ||||
| 				s = WriteFile(hPhysicalDrive, buffer, rSize, &wSize, NULL); | ||||
| 				if ((s) && (wSize == rSize)) | ||||
| 					break; | ||||
|  | @ -1631,3 +1631,102 @@ out: | |||
| 	PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0); | ||||
| 	ExitThread(0); | ||||
| } | ||||
| 
 | ||||
| DWORD WINAPI SaveImageThread(void* param) | ||||
| { | ||||
| 	BOOL s; | ||||
| 	DWORD rSize, wSize, LastRefresh = 0, DriveIndex = (DWORD)(uintptr_t)param; | ||||
| 	HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE; | ||||
| 	HANDLE hDestImage = INVALID_HANDLE_VALUE; | ||||
| 	LARGE_INTEGER li; | ||||
| 	uint8_t *buffer = NULL; | ||||
| 	uint64_t wb; | ||||
| 	int i; | ||||
| 
 | ||||
| 	PrintStatus(0, TRUE, MSG_225); | ||||
| 	hPhysicalDrive = GetPhysicalHandle(DriveIndex, FALSE, TRUE); | ||||
| 	if (hPhysicalDrive == INVALID_HANDLE_VALUE) { | ||||
| 		FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	// Write an image file
 | ||||
| 	// We poked the MBR and other stuff, so we need to rewind
 | ||||
| 	li.QuadPart = 0; | ||||
| 	if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN)) | ||||
| 		uprintf("Warning: Unable to rewind device position - wrong data might be copied!"); | ||||
| 	hDestImage = CreateFileU(image_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL); | ||||
| 	if (hDestImage == INVALID_HANDLE_VALUE) { | ||||
| 		uprintf("Could not open image '%s': %s", image_path, WindowsErrorString()); | ||||
| 		FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	uprintf("Saving to image '%s'...", image_path); | ||||
| 	buffer = (uint8_t*)malloc(DD_BUFFER_SIZE); | ||||
| 	if (buffer == NULL) { | ||||
| 		FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_ENOUGH_MEMORY; | ||||
| 		uprintf("could not allocate buffer"); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	// Don't bother trying for something clever, using double buffering overlapped and whatnot:
 | ||||
| 	// With Windows' default optimizations, sync read + sync write for sequential operations
 | ||||
| 	// will be as fast, if not faster, than whatever async scheme you can come up with.
 | ||||
| 	for (wb = 0; ; wb += wSize) { | ||||
| 		s = ReadFile(hPhysicalDrive, buffer,  | ||||
| 			(DWORD)MIN(DD_BUFFER_SIZE, SelectedDrive.DiskSize - wb), &rSize, NULL); | ||||
| 		if (!s) { | ||||
| 			FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_READ_FAULT; | ||||
| 			uprintf("read error: %s", WindowsErrorString()); | ||||
| 			goto out; | ||||
| 		} | ||||
| 		if (rSize == 0) | ||||
| 			break; | ||||
| 		if (GetTickCount() > LastRefresh + 25) { | ||||
| 			LastRefresh = GetTickCount(); | ||||
| 			format_percent = (100.0f*wb)/(1.0f*SelectedDrive.DiskSize); | ||||
| 			PrintStatus(0, FALSE, MSG_261, format_percent); | ||||
| 			UpdateProgress(OP_FORMAT, format_percent); | ||||
| 		} | ||||
| 		for (i=0; i<WRITE_RETRIES; i++) { | ||||
| 			CHECK_FOR_USER_CANCEL; | ||||
| 			s = WriteFile(hDestImage, buffer, rSize, &wSize, NULL); | ||||
| 			if ((s) && (wSize == rSize)) | ||||
| 				break; | ||||
| 			if (s) | ||||
| 				uprintf("write error: Wrote %d bytes, expected %d bytes\n", wSize, rSize); | ||||
| 			else | ||||
| 				uprintf("write error: %s", WindowsErrorString()); | ||||
| 			if (i < WRITE_RETRIES-1) { | ||||
| 				li.QuadPart = wb; | ||||
| 				SetFilePointerEx(hDestImage, li, NULL, FILE_BEGIN); | ||||
| 				uprintf("  RETRYING...\n"); | ||||
| 			} else { | ||||
| 				FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT; | ||||
| 				goto out; | ||||
| 			} | ||||
| 		} | ||||
| 		if (i >= WRITE_RETRIES) goto out; | ||||
| 	} | ||||
| 	if (wb != SelectedDrive.DiskSize) { | ||||
| 		uprintf("Error: wrote %llu bytes, expected %llu", wb, SelectedDrive.DiskSize); | ||||
| 		FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT; | ||||
| 		goto out; | ||||
| 	} | ||||
| 	uprintf("%llu bytes written", wb); | ||||
| 	uprintf("Appending VHD footer..."); | ||||
| 	if (!AppendVHDFooter(image_path)) { | ||||
| 		FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT; | ||||
| 		goto out; | ||||
| 	} | ||||
| 	uprintf("Done"); | ||||
| 
 | ||||
| out: | ||||
| 	safe_free(buffer); | ||||
| 	SendMessage(hISOProgressDlg, UM_PROGRESS_EXIT, 0, 0); | ||||
| 	safe_closehandle(hDestImage); | ||||
| 	safe_unlockclose(hPhysicalDrive); | ||||
| 	PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0); | ||||
| 	ExitThread(0); | ||||
| } | ||||
|  |  | |||
							
								
								
									
										126
									
								
								src/rufus.c
									
										
									
									
									
								
							
							
						
						
									
										126
									
								
								src/rufus.c
									
										
									
									
									
								
							|  | @ -610,57 +610,58 @@ static BOOL PopulateProperties(int ComboIndex) | |||
| /*
 | ||||
|  * Set up progress bar real estate allocation | ||||
|  */ | ||||
| static void InitProgress(void) | ||||
| static void InitProgress(BOOL bOnlyFormat) | ||||
| { | ||||
| 	int i, fs; | ||||
| 	float last_end = 0.0f, slots_discrete = 0.0f, slots_analog = 0.0f; | ||||
| 
 | ||||
| 	fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem)); | ||||
| 	memset(&nb_slots, 0, sizeof(nb_slots)); | ||||
| 	memset(&slot_end, 0, sizeof(slot_end)); | ||||
| 	previous_end = 0.0f; | ||||
| 
 | ||||
| 	memset(nb_slots, 0, sizeof(nb_slots)); | ||||
| 	memset(slot_end, 0, sizeof(slot_end)); | ||||
| 	previous_end = 0.0f; | ||||
| 
 | ||||
| 	nb_slots[OP_ANALYZE_MBR] = 1; | ||||
| 	if (IsChecked(IDC_BADBLOCKS)) { | ||||
| 		nb_slots[OP_BADBLOCKS] = -1; | ||||
| 	} | ||||
| 	if (IsChecked(IDC_BOOT)) { | ||||
| 		// 1 extra slot for PBR writing
 | ||||
| 		switch (selection_default) { | ||||
| 		case DT_WINME: | ||||
| 			nb_slots[OP_DOS] = 3+1; | ||||
| 			break; | ||||
| 		case DT_FREEDOS: | ||||
| 			nb_slots[OP_DOS] = 5+1; | ||||
| 			break; | ||||
| 		case DT_IMG: | ||||
| 			nb_slots[OP_DOS] = 0; | ||||
| 			break; | ||||
| 		case DT_ISO: | ||||
| 			nb_slots[OP_DOS] = -1; | ||||
| 			break; | ||||
| 		default: | ||||
| 			nb_slots[OP_DOS] = 2+1; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if (selection_default == DT_IMG) { | ||||
| 	if (bOnlyFormat) { | ||||
| 		nb_slots[OP_FORMAT] = -1; | ||||
| 	} else { | ||||
| 		nb_slots[OP_ZERO_MBR] = 1; | ||||
| 		nb_slots[OP_PARTITION] = 1; | ||||
| 		nb_slots[OP_FIX_MBR] = 1; | ||||
| 		nb_slots[OP_CREATE_FS] = | ||||
| 			nb_steps[ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))]; | ||||
| 		if ( (!IsChecked(IDC_QUICKFORMAT)) | ||||
| 		  || ((fs == FS_FAT32) && ((SelectedDrive.DiskSize >= LARGE_FAT32_SIZE) || (force_large_fat32))) ) { | ||||
| 			nb_slots[OP_FORMAT] = -1; | ||||
| 		nb_slots[OP_ANALYZE_MBR] = 1; | ||||
| 		if (IsChecked(IDC_BADBLOCKS)) { | ||||
| 			nb_slots[OP_BADBLOCKS] = -1; | ||||
| 		} | ||||
| 		if (IsChecked(IDC_BOOT)) { | ||||
| 			// 1 extra slot for PBR writing
 | ||||
| 			switch (selection_default) { | ||||
| 			case DT_WINME: | ||||
| 				nb_slots[OP_DOS] = 3+1; | ||||
| 				break; | ||||
| 			case DT_FREEDOS: | ||||
| 				nb_slots[OP_DOS] = 5+1; | ||||
| 				break; | ||||
| 			case DT_IMG: | ||||
| 				nb_slots[OP_DOS] = 0; | ||||
| 				break; | ||||
| 			case DT_ISO: | ||||
| 				nb_slots[OP_DOS] = -1; | ||||
| 				break; | ||||
| 			default: | ||||
| 				nb_slots[OP_DOS] = 2+1; | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		if (selection_default == DT_IMG) { | ||||
| 			nb_slots[OP_FORMAT] = -1; | ||||
| 		} else { | ||||
| 			nb_slots[OP_ZERO_MBR] = 1; | ||||
| 			nb_slots[OP_PARTITION] = 1; | ||||
| 			nb_slots[OP_FIX_MBR] = 1; | ||||
| 			nb_slots[OP_CREATE_FS] = | ||||
| 				nb_steps[ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))]; | ||||
| 			if ( (!IsChecked(IDC_QUICKFORMAT)) | ||||
| 			  || ((fs == FS_FAT32) && ((SelectedDrive.DiskSize >= LARGE_FAT32_SIZE) || (force_large_fat32))) ) { | ||||
| 				nb_slots[OP_FORMAT] = -1; | ||||
| 			} | ||||
| 			nb_slots[OP_FINALIZE] = ((selection_default == DT_ISO) && (fs == FS_NTFS))?3:2; | ||||
| 		} | ||||
| 		nb_slots[OP_FINALIZE] = ((selection_default == DT_ISO) && (fs == FS_NTFS))?3:2; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i=0; i<OP_MAX; i++) { | ||||
|  | @ -1687,6 +1688,53 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA | |||
| 			break; | ||||
| #ifdef RUFUS_TEST | ||||
| 		case IDC_TEST: | ||||
| 			if (format_thid != NULL) { | ||||
| 				return (INT_PTR)TRUE; | ||||
| 			} | ||||
| 			FormatStatus = 0; | ||||
| 			format_op_in_progress = TRUE; | ||||
| 			// Reset all progress bars
 | ||||
| 			SendMessage(hProgress, PBM_SETSTATE, (WPARAM)PBST_NORMAL, 0); | ||||
| 			SetTaskbarProgressState(TASKBAR_NORMAL); | ||||
| 			SetTaskbarProgressValue(0, MAX_PROGRESS); | ||||
| 			SendMessage(hProgress, PBM_SETPOS, 0, 0); | ||||
| 			nDeviceIndex = ComboBox_GetCurSel(hDeviceList); | ||||
| 			if (nDeviceIndex != CB_ERR) { | ||||
| 				if ((IsChecked(IDC_BOOT)) && (!BootCheck())) { | ||||
| 					format_op_in_progress = FALSE; | ||||
| 					break; | ||||
| 				} | ||||
| 
 | ||||
| 				GetWindowTextU(hDeviceList, tmp, ARRAYSIZE(tmp)); | ||||
| 				if (MessageBoxU(hMainDialog, lmprintf(MSG_003, tmp), | ||||
| 					APPLICATION_NAME, MB_OKCANCEL|MB_ICONWARNING|MB_IS_RTL) == IDCANCEL) { | ||||
| 					format_op_in_progress = FALSE; | ||||
| 					break; | ||||
| 				} | ||||
| 				safe_free(image_path); | ||||
| 				image_path = strdup("C:\\Downloads\\my.vhd"); | ||||
| 
 | ||||
| 				// Disable all controls except cancel
 | ||||
| 				EnableControls(FALSE); | ||||
| 				DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex); | ||||
| 				FormatStatus = 0; | ||||
| 				InitProgress(TRUE); | ||||
| 				format_thid = CreateThread(NULL, 0, SaveImageThread, (LPVOID)(uintptr_t)DeviceNum, 0, NULL); | ||||
| 				if (format_thid == NULL) { | ||||
| 					uprintf("Unable to start saving thread"); | ||||
| 					FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_START_THREAD); | ||||
| 					PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0); | ||||
| 				} | ||||
| 				uprintf("\r\nSave to image operation started"); | ||||
| 				PrintStatus(0, FALSE, -1); | ||||
| 				timer = 0; | ||||
| 				safe_sprintf(szTimer, sizeof(szTimer), "00:00:00"); | ||||
| 				SendMessageA(GetDlgItem(hMainDialog, IDC_STATUS), SB_SETTEXTA, | ||||
| 					SBT_OWNERDRAW | 1, (LPARAM)szTimer); | ||||
| 				SetTimer(hMainDialog, TID_APP_TIMER, 1000, ClockTimer); | ||||
| 			} | ||||
| 			if (format_thid == NULL) | ||||
| 				format_op_in_progress = FALSE; | ||||
| 			break; | ||||
| #endif | ||||
| 		case IDC_LANG: | ||||
|  | @ -1889,7 +1937,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA | |||
| 				EnableControls(FALSE); | ||||
| 				DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex); | ||||
| 				FormatStatus = 0; | ||||
| 				InitProgress(); | ||||
| 				InitProgress(FALSE); | ||||
| 				format_thid = CreateThread(NULL, 0, FormatThread, (LPVOID)(uintptr_t)DeviceNum, 0, NULL); | ||||
| 				if (format_thid == NULL) { | ||||
| 					uprintf("Unable to start formatting thread"); | ||||
|  |  | |||
|  | @ -364,7 +364,6 @@ extern BOOL ExtractDOS(const char* path); | |||
| extern BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan); | ||||
| extern int64_t ExtractISOFile(const char* iso, const char* iso_file, const char* dest_file, DWORD attributes); | ||||
| 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, const ext_t* ext, DWORD options); | ||||
|  | @ -388,8 +387,12 @@ 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 BOOL AppendVHDFooter(const char* image_path); | ||||
| extern int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid); | ||||
| 
 | ||||
| DWORD WINAPI FormatThread(void* param); | ||||
| DWORD WINAPI SaveImageThread(void* param); | ||||
| 
 | ||||
| static __inline BOOL UnlockDrive(HANDLE hDrive) { | ||||
| 	DWORD size; | ||||
| 	return DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &size, NULL); | ||||
|  |  | |||
							
								
								
									
										12
									
								
								src/rufus.rc
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								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.483" | ||||
| CAPTION "Rufus 1.4.8.484" | ||||
| 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.483" | ||||
| CAPTION "Rufus 1.4.8.484" | ||||
| 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,483 | ||||
|  PRODUCTVERSION 1,4,8,483 | ||||
|  FILEVERSION 1,4,8,484 | ||||
|  PRODUCTVERSION 1,4,8,484 | ||||
|  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.483" | ||||
|             VALUE "FileVersion", "1.4.8.484" | ||||
|             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.483" | ||||
|             VALUE "ProductVersion", "1.4.8.484" | ||||
|         END | ||||
|     END | ||||
|     BLOCK "VarFileInfo" | ||||
|  |  | |||
							
								
								
									
										136
									
								
								src/vhd.c
									
										
									
									
									
								
							
							
						
						
									
										136
									
								
								src/vhd.c
									
										
									
									
									
								
							|  | @ -20,6 +20,8 @@ | |||
| #include <windows.h> | ||||
| #include <stdlib.h> | ||||
| #include <io.h> | ||||
| #include <rpc.h> | ||||
| #include <time.h> | ||||
| 
 | ||||
| #include "rufus.h" | ||||
| #include "msapi_utf8.h" | ||||
|  | @ -38,15 +40,28 @@ | |||
| 
 | ||||
| #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 SECONDS_SINCE_JAN_1ST_2000			946684800 | ||||
| 
 | ||||
| /*
 | ||||
|  * 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 { | ||||
|  | @ -55,12 +70,19 @@ typedef struct vhd_footer { | |||
| 	uint32_t	file_format_version; | ||||
| 	uint64_t	data_offset; | ||||
| 	uint32_t	timestamp; | ||||
| 	uint32_t	creator_app; | ||||
| 	char		creator_app[4]; | ||||
| 	uint32_t	creator_version; | ||||
| 	uint32_t	creator_host_os; | ||||
| 	char		creator_host_os[4]; | ||||
| 	uint64_t	original_size; | ||||
| 	uint64_t	current_size; | ||||
| 	uint32_t	disk_geometry; | ||||
| 	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; | ||||
|  | @ -77,9 +99,11 @@ PF_TYPE_DECL(WINAPI, BOOL, WIMSetTemporaryPath, (HANDLE, PWSTR)); | |||
| 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)); | ||||
| PF_TYPE_DECL(RPC_ENTRY, RPC_STATUS, UuidCreate, (UUID __RPC_FAR*)); | ||||
| 
 | ||||
| static BOOL has_wimgapi = FALSE, has_7z = FALSE; | ||||
| static char sevenzip_path[MAX_PATH]; | ||||
| static const char conectix_str[] = VHD_FOOTER_COOKIE; | ||||
| 
 | ||||
| static BOOL Get7ZipPath(void) | ||||
| { | ||||
|  | @ -91,13 +115,109 @@ static BOOL Get7ZipPath(void) | |||
| 	return FALSE; | ||||
| } | ||||
| 
 | ||||
| BOOL AppendVHDFooter(const char* image_path) | ||||
| { | ||||
| 	const char creator_os[4] = VHD_FOOTER_CREATOR_HOST_OS_WINDOWS; | ||||
| 	const char creator_app[4] = { 'r', 'u', 'f', 'u' }; | ||||
| 	BOOL r = FALSE; | ||||
| 	DWORD size; | ||||
| 	LARGE_INTEGER li; | ||||
| 	HANDLE handle = INVALID_HANDLE_VALUE; | ||||
| 	vhd_footer* footer; | ||||
| 	uint64_t totalSectors; | ||||
| 	uint16_t cylinders = 0; | ||||
| 	uint8_t heads, sectorsPerTrack; | ||||
| 	uint32_t cylinderTimesHeads; | ||||
| 	uint32_t checksum; | ||||
| 	size_t i; | ||||
| 
 | ||||
| 	PF_INIT(UuidCreate, Rpcrt4); | ||||
| 	handle = CreateFileU(image_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); | ||||
| 	li.QuadPart = 0; | ||||
| 	if ((handle == INVALID_HANDLE_VALUE) || (!SetFilePointerEx(handle, li, &li, FILE_END))) { | ||||
| 		uprintf("Could not open image '%s': %s", image_path, WindowsErrorString()); | ||||
| 		goto out; | ||||
| 	} | ||||
| 	footer = (vhd_footer*)calloc(1, sizeof(vhd_footer)); | ||||
| 	if (footer == NULL) { | ||||
| 		uprintf("Could not allocate VHD footer"); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	memcpy(footer->cookie, conectix_str, sizeof(footer->cookie)); | ||||
| 	footer->features = bswap_uint32(VHD_FOOTER_FEATURES_RESERVED); | ||||
| 	footer->file_format_version = bswap_uint32(VHD_FOOTER_FILE_FORMAT_V1_0); | ||||
| 	footer->data_offset = bswap_uint64(VHD_FOOTER_DATA_OFFSET_FIXED_DISK); | ||||
| 	footer->timestamp = bswap_uint32(_time32(NULL) - SECONDS_SINCE_JAN_1ST_2000); | ||||
| 	memcpy(footer->creator_app, creator_app, sizeof(creator_app)); | ||||
| 	footer->creator_version = bswap_uint32((rufus_version[0]<<16)|rufus_version[1]); | ||||
| 	memcpy(footer->creator_host_os, creator_os, sizeof(creator_os)); | ||||
| 	footer->original_size = bswap_uint64(li.QuadPart); | ||||
| 	footer->current_size = footer->original_size; | ||||
| 	footer->disk_type = bswap_uint32(VHD_FOOTER_TYPE_FIXED_HARD_DISK); | ||||
| 	if ((pfUuidCreate == NULL) || (pfUuidCreate(&footer->unique_id) != RPC_S_OK)) | ||||
| 		uprintf("Warning: could not set VHD UUID"); | ||||
| 
 | ||||
| 	// Compute CHS, as per the VHD specs
 | ||||
| 	totalSectors = li.QuadPart / 512; | ||||
| 	if (totalSectors > 65535 * 16 * 255) { | ||||
| 		totalSectors = 65535 * 16 * 255; | ||||
| 	} | ||||
| 
 | ||||
| 	if (totalSectors >= 65535 * 16 * 63) { | ||||
| 		sectorsPerTrack = 255; | ||||
| 		heads = 16; | ||||
| 		cylinderTimesHeads = (uint32_t)(totalSectors / sectorsPerTrack); | ||||
| 	} else { | ||||
| 		sectorsPerTrack = 17;  | ||||
| 		cylinderTimesHeads = (uint32_t)(totalSectors / sectorsPerTrack); | ||||
| 
 | ||||
| 		heads = (cylinderTimesHeads + 1023) / 1024; | ||||
| 
 | ||||
| 		if (heads < 4) { | ||||
| 			heads = 4; | ||||
| 		} | ||||
| 		if (cylinderTimesHeads >= ((uint32_t)heads * 1024) || heads > 16) { | ||||
| 			sectorsPerTrack = 31; | ||||
| 			heads = 16; | ||||
| 			cylinderTimesHeads = (uint32_t)(totalSectors / sectorsPerTrack); | ||||
| 		} | ||||
| 		if (cylinderTimesHeads >= ((uint32_t)heads * 1024)) { | ||||
| 			sectorsPerTrack = 63; | ||||
| 			heads = 16; | ||||
| 			cylinderTimesHeads = (uint32_t)(totalSectors / sectorsPerTrack); | ||||
| 		} | ||||
| 	} | ||||
| 	cylinders = cylinderTimesHeads / heads; | ||||
| 	footer->disk_geometry.chs.cylinders = bswap_uint16(cylinders); | ||||
| 	footer->disk_geometry.chs.heads = heads; | ||||
| 	footer->disk_geometry.chs.sectors = sectorsPerTrack; | ||||
| 
 | ||||
| 	// Compute the VHD footer checksum
 | ||||
| 	for (checksum=0, i=0; i<sizeof(vhd_footer); i++) | ||||
| 		checksum += ((uint8_t*)footer)[i]; | ||||
| 	footer->checksum = bswap_uint32(~checksum); | ||||
| 
 | ||||
| 	if (!WriteFile(handle, footer, sizeof(vhd_footer), &size, NULL) || (size != sizeof(vhd_footer))) { | ||||
| 		uprintf("Could not write VHD footer: %s", WindowsErrorString()); | ||||
| 		goto out; | ||||
| 	} | ||||
| 	r = TRUE; | ||||
| 	 | ||||
| out: | ||||
| 	safe_free(footer); | ||||
| 	safe_closehandle(handle); | ||||
| 	return r; | ||||
| } | ||||
| 
 | ||||
| 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; | ||||
| 	size_t i; | ||||
| 	uint32_t checksum, old_checksum; | ||||
| 	LARGE_INTEGER ptr; | ||||
| 
 | ||||
| 	handle = CreateFileU(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); | ||||
|  | @ -130,6 +250,14 @@ BOOL IsHDImage(const char* path) | |||
| 				iso_report.is_bootable_img = FALSE; | ||||
| 				goto out; | ||||
| 			} | ||||
| 			// Might as well validate the checksum while we're at it
 | ||||
| 			old_checksum = bswap_uint32(footer->checksum); | ||||
| 			footer->checksum = 0; | ||||
| 			for (checksum=0, i=0; i<sizeof(vhd_footer); i++) | ||||
| 				checksum += ((uint8_t*)footer)[i]; | ||||
| 			checksum = ~checksum; | ||||
| 			if (checksum != old_checksum) | ||||
| 				uprintf("Warning: VHD footer seems corrupted (checksum: %04X, expected: %04X)", old_checksum, checksum); | ||||
| 			// Need to remove the footer from our payload
 | ||||
| 			uprintf("Image is a Fixed Hard Disk VHD file"); | ||||
| 			iso_report.is_vhd = TRUE; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue