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); | 				PrintStatus(0, FALSE, MSG_261, format_percent); | ||||||
| 				UpdateProgress(OP_FORMAT, format_percent); | 				UpdateProgress(OP_FORMAT, format_percent); | ||||||
| 			} | 			} | ||||||
| 			CHECK_FOR_USER_CANCEL; |  | ||||||
| 			// Don't overflow our projected size (mostly for VHDs)
 | 			// Don't overflow our projected size (mostly for VHDs)
 | ||||||
| 			if (wb + rSize > iso_report.projected_size) { | 			if (wb + rSize > iso_report.projected_size) { | ||||||
| 				rSize = (DWORD)(iso_report.projected_size - wb); | 				rSize = (DWORD)(iso_report.projected_size - wb); | ||||||
| 			} | 			} | ||||||
| 			for (i=0; i<WRITE_RETRIES; i++) { | 			for (i=0; i<WRITE_RETRIES; i++) { | ||||||
|  | 				CHECK_FOR_USER_CANCEL; | ||||||
| 				s = WriteFile(hPhysicalDrive, buffer, rSize, &wSize, NULL); | 				s = WriteFile(hPhysicalDrive, buffer, rSize, &wSize, NULL); | ||||||
| 				if ((s) && (wSize == rSize)) | 				if ((s) && (wSize == rSize)) | ||||||
| 					break; | 					break; | ||||||
|  | @ -1631,3 +1631,102 @@ out: | ||||||
| 	PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0); | 	PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0); | ||||||
| 	ExitThread(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 |  * Set up progress bar real estate allocation | ||||||
|  */ |  */ | ||||||
| static void InitProgress(void) | static void InitProgress(BOOL bOnlyFormat) | ||||||
| { | { | ||||||
| 	int i, fs; | 	int i, fs; | ||||||
| 	float last_end = 0.0f, slots_discrete = 0.0f, slots_analog = 0.0f; | 	float last_end = 0.0f, slots_discrete = 0.0f, slots_analog = 0.0f; | ||||||
| 
 | 
 | ||||||
| 	fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem)); | 	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(nb_slots, 0, sizeof(nb_slots)); | ||||||
| 	memset(slot_end, 0, sizeof(slot_end)); | 	memset(slot_end, 0, sizeof(slot_end)); | ||||||
| 	previous_end = 0.0f; | 	previous_end = 0.0f; | ||||||
| 
 | 
 | ||||||
| 	nb_slots[OP_ANALYZE_MBR] = 1; | 	if (bOnlyFormat) { | ||||||
| 	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; | 		nb_slots[OP_FORMAT] = -1; | ||||||
| 	} else { | 	} else { | ||||||
| 		nb_slots[OP_ZERO_MBR] = 1; | 		nb_slots[OP_ANALYZE_MBR] = 1; | ||||||
| 		nb_slots[OP_PARTITION] = 1; | 		if (IsChecked(IDC_BADBLOCKS)) { | ||||||
| 		nb_slots[OP_FIX_MBR] = 1; | 			nb_slots[OP_BADBLOCKS] = -1; | ||||||
| 		nb_slots[OP_CREATE_FS] = | 		} | ||||||
| 			nb_steps[ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))]; | 		if (IsChecked(IDC_BOOT)) { | ||||||
| 		if ( (!IsChecked(IDC_QUICKFORMAT)) | 			// 1 extra slot for PBR writing
 | ||||||
| 		  || ((fs == FS_FAT32) && ((SelectedDrive.DiskSize >= LARGE_FAT32_SIZE) || (force_large_fat32))) ) { | 			switch (selection_default) { | ||||||
| 			nb_slots[OP_FORMAT] = -1; | 			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++) { | 	for (i=0; i<OP_MAX; i++) { | ||||||
|  | @ -1687,6 +1688,53 @@ 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: | ||||||
|  | 			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; | 			break; | ||||||
| #endif | #endif | ||||||
| 		case IDC_LANG: | 		case IDC_LANG: | ||||||
|  | @ -1889,7 +1937,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA | ||||||
| 				EnableControls(FALSE); | 				EnableControls(FALSE); | ||||||
| 				DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex); | 				DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex); | ||||||
| 				FormatStatus = 0; | 				FormatStatus = 0; | ||||||
| 				InitProgress(); | 				InitProgress(FALSE); | ||||||
| 				format_thid = CreateThread(NULL, 0, FormatThread, (LPVOID)(uintptr_t)DeviceNum, 0, NULL); | 				format_thid = CreateThread(NULL, 0, FormatThread, (LPVOID)(uintptr_t)DeviceNum, 0, NULL); | ||||||
| 				if (format_thid == NULL) { | 				if (format_thid == NULL) { | ||||||
| 					uprintf("Unable to start formatting thread"); | 					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 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 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); | extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter); | ||||||
| DWORD WINAPI FormatThread(void* param); |  | ||||||
| extern BOOL CreateProgress(void); | extern BOOL CreateProgress(void); | ||||||
| extern BOOL SetAutorun(const char* path); | extern BOOL SetAutorun(const char* path); | ||||||
| extern char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options); | 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 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 IsHDImage(const char* path); | 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); | 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) { | static __inline BOOL UnlockDrive(HANDLE hDrive) { | ||||||
| 	DWORD size; | 	DWORD size; | ||||||
| 	return DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &size, NULL); | 	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 | IDD_DIALOG DIALOGEX 12, 12, 206, 329 | ||||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | 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 | FONT 8, "MS Shell Dlg", 400, 0, 0x1 | ||||||
| BEGIN | BEGIN | ||||||
|     DEFPUSHBUTTON   "Start",IDC_START,94,291,50,14 |     DEFPUSHBUTTON   "Start",IDC_START,94,291,50,14 | ||||||
|  | @ -165,7 +165,7 @@ END | ||||||
| RTL_IDD_DIALOG DIALOGEX 12, 12, 206, 329 | RTL_IDD_DIALOG DIALOGEX 12, 12, 206, 329 | ||||||
| STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | 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 | 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 | FONT 8, "MS Shell Dlg", 400, 0, 0x1 | ||||||
| BEGIN | BEGIN | ||||||
|     DEFPUSHBUTTON   "Start",IDC_START,94,291,50,14 |     DEFPUSHBUTTON   "Start",IDC_START,94,291,50,14 | ||||||
|  | @ -427,8 +427,8 @@ END | ||||||
| // | // | ||||||
| 
 | 
 | ||||||
| VS_VERSION_INFO VERSIONINFO | VS_VERSION_INFO VERSIONINFO | ||||||
|  FILEVERSION 1,4,8,483 |  FILEVERSION 1,4,8,484 | ||||||
|  PRODUCTVERSION 1,4,8,483 |  PRODUCTVERSION 1,4,8,484 | ||||||
|  FILEFLAGSMASK 0x3fL |  FILEFLAGSMASK 0x3fL | ||||||
| #ifdef _DEBUG | #ifdef _DEBUG | ||||||
|  FILEFLAGS 0x1L |  FILEFLAGS 0x1L | ||||||
|  | @ -445,13 +445,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", "1.4.8.483" |             VALUE "FileVersion", "1.4.8.484" | ||||||
|             VALUE "InternalName", "Rufus" |             VALUE "InternalName", "Rufus" | ||||||
|             VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)" |             VALUE "LegalCopyright", "© 2011-2014 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", "1.4.8.483" |             VALUE "ProductVersion", "1.4.8.484" | ||||||
|         END |         END | ||||||
|     END |     END | ||||||
|     BLOCK "VarFileInfo" |     BLOCK "VarFileInfo" | ||||||
|  |  | ||||||
							
								
								
									
										136
									
								
								src/vhd.c
									
										
									
									
									
								
							
							
						
						
									
										136
									
								
								src/vhd.c
									
										
									
									
									
								
							|  | @ -20,6 +20,8 @@ | ||||||
| #include <windows.h> | #include <windows.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #include <io.h> | #include <io.h> | ||||||
|  | #include <rpc.h> | ||||||
|  | #include <time.h> | ||||||
| 
 | 
 | ||||||
| #include "rufus.h" | #include "rufus.h" | ||||||
| #include "msapi_utf8.h" | #include "msapi_utf8.h" | ||||||
|  | @ -38,15 +40,28 @@ | ||||||
| 
 | 
 | ||||||
| #define VHD_FOOTER_COOKIE					{ 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x' } | #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_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_FIXED_HARD_DISK		0x00000002 | ||||||
| #define VHD_FOOTER_TYPE_DYNAMIC_HARD_DISK	0x00000003 | #define VHD_FOOTER_TYPE_DYNAMIC_HARD_DISK	0x00000003 | ||||||
| #define VHD_FOOTER_TYPE_DIFFER_HARD_DISK	0x00000004 | #define VHD_FOOTER_TYPE_DIFFER_HARD_DISK	0x00000004 | ||||||
| 
 | 
 | ||||||
|  | #define SECONDS_SINCE_JAN_1ST_2000			946684800 | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * VHD Fixed HD footer (Big Endian) |  * 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
 |  * 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) | #pragma pack(push, 1) | ||||||
| typedef struct vhd_footer { | typedef struct vhd_footer { | ||||||
|  | @ -55,12 +70,19 @@ typedef struct vhd_footer { | ||||||
| 	uint32_t	file_format_version; | 	uint32_t	file_format_version; | ||||||
| 	uint64_t	data_offset; | 	uint64_t	data_offset; | ||||||
| 	uint32_t	timestamp; | 	uint32_t	timestamp; | ||||||
| 	uint32_t	creator_app; | 	char		creator_app[4]; | ||||||
| 	uint32_t	creator_version; | 	uint32_t	creator_version; | ||||||
| 	uint32_t	creator_host_os; | 	char		creator_host_os[4]; | ||||||
| 	uint64_t	original_size; | 	uint64_t	original_size; | ||||||
| 	uint64_t	current_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	disk_type; | ||||||
| 	uint32_t	checksum; | 	uint32_t	checksum; | ||||||
| 	uuid_t		unique_id; | 	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, HANDLE, WIMLoadImage, (HANDLE, 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(RPC_ENTRY, RPC_STATUS, UuidCreate, (UUID __RPC_FAR*)); | ||||||
| 
 | 
 | ||||||
| static BOOL has_wimgapi = FALSE, has_7z = FALSE; | static BOOL has_wimgapi = FALSE, has_7z = FALSE; | ||||||
| static char sevenzip_path[MAX_PATH]; | static char sevenzip_path[MAX_PATH]; | ||||||
|  | static const char conectix_str[] = VHD_FOOTER_COOKIE; | ||||||
| 
 | 
 | ||||||
| static BOOL Get7ZipPath(void) | static BOOL Get7ZipPath(void) | ||||||
| { | { | ||||||
|  | @ -91,13 +115,109 @@ static BOOL Get7ZipPath(void) | ||||||
| 	return FALSE; | 	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) | BOOL IsHDImage(const char* path) | ||||||
| { | { | ||||||
| 	const char conectix_str[] = VHD_FOOTER_COOKIE; |  | ||||||
| 	HANDLE handle = INVALID_HANDLE_VALUE; | 	HANDLE handle = INVALID_HANDLE_VALUE; | ||||||
| 	LARGE_INTEGER liImageSize; | 	LARGE_INTEGER liImageSize; | ||||||
| 	vhd_footer* footer = NULL; | 	vhd_footer* footer = NULL; | ||||||
| 	DWORD size; | 	DWORD size; | ||||||
|  | 	size_t i; | ||||||
|  | 	uint32_t checksum, old_checksum; | ||||||
| 	LARGE_INTEGER ptr; | 	LARGE_INTEGER ptr; | ||||||
| 
 | 
 | ||||||
| 	handle = CreateFileU(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); | 	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; | 				iso_report.is_bootable_img = FALSE; | ||||||
| 				goto out; | 				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
 | 			// Need to remove the footer from our payload
 | ||||||
| 			uprintf("Image is a Fixed Hard Disk VHD file"); | 			uprintf("Image is a Fixed Hard Disk VHD file"); | ||||||
| 			iso_report.is_vhd = TRUE; | 			iso_report.is_vhd = TRUE; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue