mirror of
				https://github.com/pbatard/rufus.git
				synced 2024-08-14 23:57:05 +00:00 
			
		
		
		
	[vhd] add write support for .vhdx and .ffu images
* Also move VHD mounting function calls from iso.c to vhd.c and remove unused VHD footer elements.
This commit is contained in:
		
							parent
							
								
									f411d526d6
								
							
						
					
					
						commit
						5bbcba8534
					
				
					 10 changed files with 226 additions and 223 deletions
				
			
		
							
								
								
									
										40
									
								
								src/format.c
									
										
									
									
									
								
							
							
						
						
									
										40
									
								
								src/format.c
									
										
									
									
									
								
							|  | @ -36,6 +36,7 @@ | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| #include "rufus.h" | #include "rufus.h" | ||||||
|  | #include "format.h" | ||||||
| #include "missing.h" | #include "missing.h" | ||||||
| #include "resource.h" | #include "resource.h" | ||||||
| #include "settings.h" | #include "settings.h" | ||||||
|  | @ -73,7 +74,7 @@ extern const int nb_steps[FS_MAX]; | ||||||
| extern uint32_t dur_mins, dur_secs; | extern uint32_t dur_mins, dur_secs; | ||||||
| extern uint32_t wim_nb_files, wim_proc_files, wim_extra_files; | extern uint32_t wim_nb_files, wim_proc_files, wim_extra_files; | ||||||
| extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive, fast_zeroing, enable_file_indexing; | extern BOOL force_large_fat32, enable_ntfs_compression, lock_drive, zero_drive, fast_zeroing, enable_file_indexing; | ||||||
| extern BOOL write_as_image, use_vds, write_as_esp, is_vds_available; | extern BOOL write_as_image, use_vds, write_as_esp, is_vds_available, has_ffu_support; | ||||||
| uint8_t *grub2_buf = NULL, *sec_buf = NULL; | uint8_t *grub2_buf = NULL, *sec_buf = NULL; | ||||||
| long grub2_len; | long grub2_len; | ||||||
| 
 | 
 | ||||||
|  | @ -1154,6 +1155,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive) | ||||||
| 	int64_t bled_ret; | 	int64_t bled_ret; | ||||||
| 	uint8_t* buffer = NULL; | 	uint8_t* buffer = NULL; | ||||||
| 	uint32_t zero_data, *cmp_buffer = NULL; | 	uint32_t zero_data, *cmp_buffer = NULL; | ||||||
|  | 	char* vhd_path = NULL; | ||||||
| 	int throttle_fast_zeroing = 0, read_bufnum = 0, proc_bufnum = 1; | 	int throttle_fast_zeroing = 0, read_bufnum = 0, proc_bufnum = 1; | ||||||
| 
 | 
 | ||||||
| 	if (SelectedDrive.SectorSize < 512) { | 	if (SelectedDrive.SectorSize < 512) { | ||||||
|  | @ -1273,7 +1275,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive) | ||||||
| 			if (i > WRITE_RETRIES) | 			if (i > WRITE_RETRIES) | ||||||
| 				goto out; | 				goto out; | ||||||
| 		} | 		} | ||||||
| 	} else if (img_report.compression_type != BLED_COMPRESSION_NONE) { | 	} else if (img_report.compression_type != BLED_COMPRESSION_NONE && img_report.compression_type < BLED_COMPRESSION_MAX) { | ||||||
| 		uprintf("Writing compressed image:"); | 		uprintf("Writing compressed image:"); | ||||||
| 		hSourceImage = CreateFileU(image_path, GENERIC_READ, FILE_SHARE_READ, NULL, | 		hSourceImage = CreateFileU(image_path, GENERIC_READ, FILE_SHARE_READ, NULL, | ||||||
| 			OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); | 			OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL); | ||||||
|  | @ -1310,8 +1312,17 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive) | ||||||
| 			goto out; | 			goto out; | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		hSourceImage = CreateFileAsync(image_path, GENERIC_READ, FILE_SHARE_READ, | 		assert(img_report.compression_type != IMG_COMPRESSION_FFU); | ||||||
| 			OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN); | 		// VHD/VHDX require mounting the image first
 | ||||||
|  | 		if (img_report.compression_type == IMG_COMPRESSION_VHD || | ||||||
|  | 			img_report.compression_type == IMG_COMPRESSION_VHDX) { | ||||||
|  | 			vhd_path = VhdMountImage(image_path); | ||||||
|  | 			if (vhd_path == NULL) | ||||||
|  | 				goto out; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		hSourceImage = CreateFileAsync(vhd_path != NULL ? vhd_path : image_path, GENERIC_READ, | ||||||
|  | 			FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN); | ||||||
| 		if (hSourceImage == NULL) { | 		if (hSourceImage == NULL) { | ||||||
| 			uprintf("Could not open image '%s': %s", image_path, WindowsErrorString()); | 			uprintf("Could not open image '%s': %s", image_path, WindowsErrorString()); | ||||||
| 			FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_OPEN_FAILED; | 			FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_OPEN_FAILED; | ||||||
|  | @ -1397,10 +1408,12 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive) | ||||||
| 	RefreshDriveLayout(hPhysicalDrive); | 	RefreshDriveLayout(hPhysicalDrive); | ||||||
| 	ret = TRUE; | 	ret = TRUE; | ||||||
| out: | out: | ||||||
| 	if (img_report.compression_type != BLED_COMPRESSION_NONE) | 	if (img_report.compression_type != BLED_COMPRESSION_NONE && img_report.compression_type < BLED_COMPRESSION_MAX) | ||||||
| 		safe_closehandle(hSourceImage); | 		safe_closehandle(hSourceImage); | ||||||
| 	else | 	else | ||||||
| 		CloseFileAsync(hSourceImage); | 		CloseFileAsync(hSourceImage); | ||||||
|  | 	if (vhd_path != NULL) | ||||||
|  | 		VhdUnmountImage(); | ||||||
| 	safe_mm_free(buffer); | 	safe_mm_free(buffer); | ||||||
| 	safe_mm_free(cmp_buffer); | 	safe_mm_free(cmp_buffer); | ||||||
| 	return ret; | 	return ret; | ||||||
|  | @ -1627,7 +1640,24 @@ DWORD WINAPI FormatThread(void* param) | ||||||
| 
 | 
 | ||||||
| 	// Write an image file
 | 	// Write an image file
 | ||||||
| 	if ((boot_type == BT_IMAGE) && write_as_image) { | 	if ((boot_type == BT_IMAGE) && write_as_image) { | ||||||
|  | 		// Special case for FFU images
 | ||||||
|  | 		if (img_report.compression_type == IMG_COMPRESSION_FFU) { | ||||||
|  | 			char cmd[MAX_PATH + 128], *physical; | ||||||
|  | 			// Should have been filtered out beforehand
 | ||||||
|  | 			assert(has_ffu_support); | ||||||
|  | 			safe_unlockclose(hPhysicalDrive); | ||||||
|  | 			physical = GetPhysicalName(SelectedDrive.DeviceNumber); | ||||||
|  | 			static_sprintf(cmd, "dism /Apply-Ffu /ApplyDrive:%s /ImageFile:\"%s\"", physical, image_path); | ||||||
|  | 			uprintf("Running command: '%s", cmd); | ||||||
|  | 			cr = RunCommandWithProgress(cmd, sysnative_dir, TRUE, MSG_261); | ||||||
|  | 			if (cr != 0 && !IS_ERROR(FormatStatus)) { | ||||||
|  | 				SetLastError(cr); | ||||||
|  | 				uprintf("Failed to apply FFU image: %s", WindowsErrorString()); | ||||||
|  | 				FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_WINDOWS) | SCODE_CODE(cr); | ||||||
|  | 			} | ||||||
|  | 		} else { | ||||||
| 			WriteDrive(hPhysicalDrive, FALSE); | 			WriteDrive(hPhysicalDrive, FALSE); | ||||||
|  | 		} | ||||||
| 		goto out; | 		goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,7 +1,7 @@ | ||||||
| /*
 | /*
 | ||||||
|  * Rufus: The Reliable USB Formatting Utility |  * Rufus: The Reliable USB Formatting Utility | ||||||
|  * Formatting function calls |  * Formatting function calls | ||||||
|  * Copyright © 2011-2020 Pete Batard <pete@akeo.ie> |  * Copyright © 2011-2023 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 | ||||||
|  | @ -111,6 +111,10 @@ typedef BOOLEAN (WINAPI* EnableVolumeCompression_t)( | ||||||
| 	ULONG                CompressionFlags	// FILE_SYSTEM_PROP_FLAG
 | 	ULONG                CompressionFlags	// FILE_SYSTEM_PROP_FLAG
 | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
|  | #define IMG_COMPRESSION_FFU     (BLED_COMPRESSION_MAX) | ||||||
|  | #define IMG_COMPRESSION_VHD     (BLED_COMPRESSION_MAX + 1) | ||||||
|  | #define IMG_COMPRESSION_VHDX    (BLED_COMPRESSION_MAX + 2) | ||||||
|  | 
 | ||||||
| BOOL WritePBR(HANDLE hLogicalDrive); | BOOL WritePBR(HANDLE hLogicalDrive); | ||||||
| BOOL FormatLargeFAT32(DWORD DriveIndex, uint64_t PartitionOffset, DWORD ClusterSize, LPCSTR FSName, LPCSTR Label, DWORD Flags); | BOOL FormatLargeFAT32(DWORD DriveIndex, uint64_t PartitionOffset, DWORD ClusterSize, LPCSTR FSName, LPCSTR Label, DWORD Flags); | ||||||
| BOOL FormatExtFs(DWORD DriveIndex, uint64_t PartitionOffset, DWORD BlockSize, LPCSTR FSName, LPCSTR Label, DWORD Flags); | BOOL FormatExtFs(DWORD DriveIndex, uint64_t PartitionOffset, DWORD BlockSize, LPCSTR FSName, LPCSTR Label, DWORD Flags); | ||||||
|  |  | ||||||
							
								
								
									
										81
									
								
								src/iso.c
									
										
									
									
									
								
							
							
						
						
									
										81
									
								
								src/iso.c
									
										
									
									
									
								
							|  | @ -1726,83 +1726,8 @@ out: | ||||||
| 	return ret; | 	return ret; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // VirtDisk API Prototypes since we can't use delay-loading because of MinGW
 |  | ||||||
| // See https://github.com/pbatard/rufus/issues/2272#issuecomment-1615976013
 |  | ||||||
| PF_TYPE_DECL(WINAPI, DWORD, OpenVirtualDisk, (PVIRTUAL_STORAGE_TYPE, PCWSTR, |  | ||||||
| 	VIRTUAL_DISK_ACCESS_MASK, OPEN_VIRTUAL_DISK_FLAG, POPEN_VIRTUAL_DISK_PARAMETERS, PHANDLE)); |  | ||||||
| PF_TYPE_DECL(WINAPI, DWORD, AttachVirtualDisk, (HANDLE, PSECURITY_DESCRIPTOR, |  | ||||||
| 	ATTACH_VIRTUAL_DISK_FLAG, ULONG, PATTACH_VIRTUAL_DISK_PARAMETERS, LPOVERLAPPED)); |  | ||||||
| PF_TYPE_DECL(WINAPI, DWORD, DetachVirtualDisk, (HANDLE, DETACH_VIRTUAL_DISK_FLAG, ULONG)); |  | ||||||
| PF_TYPE_DECL(WINAPI, DWORD, GetVirtualDiskPhysicalPath, (HANDLE, PULONG, PWSTR)); |  | ||||||
| 
 |  | ||||||
| static char physical_path[128] = ""; |  | ||||||
| static HANDLE mounted_handle = INVALID_HANDLE_VALUE; |  | ||||||
| 
 |  | ||||||
| char* MountISO(const char* path) |  | ||||||
| { |  | ||||||
| 	VIRTUAL_STORAGE_TYPE vtype = { VIRTUAL_STORAGE_TYPE_DEVICE_ISO, VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT }; |  | ||||||
| 	ATTACH_VIRTUAL_DISK_PARAMETERS vparams = { 0 }; |  | ||||||
| 	DWORD r; |  | ||||||
| 	wchar_t wtmp[128]; |  | ||||||
| 	ULONG size = ARRAYSIZE(wtmp); |  | ||||||
| 	wconvert(path); |  | ||||||
| 	char* ret = NULL; |  | ||||||
| 
 |  | ||||||
| 	PF_INIT_OR_OUT(OpenVirtualDisk, VirtDisk); |  | ||||||
| 	PF_INIT_OR_OUT(AttachVirtualDisk, VirtDisk); |  | ||||||
| 	PF_INIT_OR_OUT(GetVirtualDiskPhysicalPath, VirtDisk); |  | ||||||
| 
 |  | ||||||
| 	if ((mounted_handle != NULL) && (mounted_handle != INVALID_HANDLE_VALUE)) |  | ||||||
| 		UnMountISO(); |  | ||||||
| 
 |  | ||||||
| 	r = pfOpenVirtualDisk(&vtype, wpath, VIRTUAL_DISK_ACCESS_READ | VIRTUAL_DISK_ACCESS_GET_INFO, |  | ||||||
| 		OPEN_VIRTUAL_DISK_FLAG_NONE, NULL, &mounted_handle); |  | ||||||
| 	if (r != ERROR_SUCCESS) { |  | ||||||
| 		SetLastError(r); |  | ||||||
| 		uprintf("Could not open ISO '%s': %s", path, WindowsErrorString()); |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	vparams.Version = ATTACH_VIRTUAL_DISK_VERSION_1; |  | ||||||
| 	r = pfAttachVirtualDisk(mounted_handle, NULL, ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY | |  | ||||||
| 		ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER, 0, &vparams, NULL); |  | ||||||
| 	if (r != ERROR_SUCCESS) { |  | ||||||
| 		SetLastError(r); |  | ||||||
| 		uprintf("Could not mount ISO '%s': %s", path, WindowsErrorString()); |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	r = pfGetVirtualDiskPhysicalPath(mounted_handle, &size, wtmp); |  | ||||||
| 	if (r != ERROR_SUCCESS) { |  | ||||||
| 		SetLastError(r); |  | ||||||
| 		uprintf("Could not obtain physical path for mounted ISO '%s': %s", path, WindowsErrorString()); |  | ||||||
| 		goto out; |  | ||||||
| 	} |  | ||||||
| 	wchar_to_utf8_no_alloc(wtmp, physical_path, sizeof(physical_path)); |  | ||||||
| 	ret = physical_path; |  | ||||||
| 
 |  | ||||||
| out: |  | ||||||
| 	if (ret == NULL) |  | ||||||
| 		UnMountISO(); |  | ||||||
| 	wfree(path); |  | ||||||
| 	return ret; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void UnMountISO(void) |  | ||||||
| { |  | ||||||
| 	PF_INIT_OR_OUT(DetachVirtualDisk, VirtDisk); |  | ||||||
| 
 |  | ||||||
| 	if ((mounted_handle == NULL) || (mounted_handle == INVALID_HANDLE_VALUE)) |  | ||||||
| 		goto out; |  | ||||||
| 
 |  | ||||||
| 	pfDetachVirtualDisk(mounted_handle, DETACH_VIRTUAL_DISK_FLAG_NONE, 0); |  | ||||||
| 	safe_closehandle(mounted_handle); |  | ||||||
| out: |  | ||||||
| 	physical_path[0] = 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // TODO: If we can't get save to ISO from virtdisk, we might as well drop this
 | // TODO: If we can't get save to ISO from virtdisk, we might as well drop this
 | ||||||
| static DWORD WINAPI SaveISOThread(void* param) | static DWORD WINAPI IsoSaveImageThread(void* param) | ||||||
| { | { | ||||||
| 	BOOL s; | 	BOOL s; | ||||||
| 	DWORD rSize, wSize; | 	DWORD rSize, wSize; | ||||||
|  | @ -1908,7 +1833,7 @@ out: | ||||||
| 	ExitThread(0); | 	ExitThread(0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void SaveISO(void) | void IsoSaveImage(void) | ||||||
| { | { | ||||||
| 	static IMG_SAVE img_save = { 0 }; | 	static IMG_SAVE img_save = { 0 }; | ||||||
| 	char filename[33] = "disc_image.iso"; | 	char filename[33] = "disc_image.iso"; | ||||||
|  | @ -1939,7 +1864,7 @@ void SaveISO(void) | ||||||
| 	// Disable all controls except cancel
 | 	// Disable all controls except cancel
 | ||||||
| 	EnableControls(FALSE, FALSE); | 	EnableControls(FALSE, FALSE); | ||||||
| 	InitProgress(TRUE); | 	InitProgress(TRUE); | ||||||
| 	format_thread = CreateThread(NULL, 0, SaveISOThread, &img_save, 0, NULL); | 	format_thread = CreateThread(NULL, 0, IsoSaveImageThread, &img_save, 0, NULL); | ||||||
| 	if (format_thread != NULL) { | 	if (format_thread != NULL) { | ||||||
| 		uprintf("\r\nSave to ISO operation started"); | 		uprintf("\r\nSave to ISO operation started"); | ||||||
| 		PrintInfo(0, -1); | 		PrintInfo(0, -1); | ||||||
|  |  | ||||||
							
								
								
									
										14
									
								
								src/rufus.c
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								src/rufus.c
									
										
									
									
									
								
							|  | @ -128,7 +128,7 @@ BOOL advanced_mode_device, advanced_mode_format, allow_dual_uefi_bios, detect_fa | ||||||
| BOOL usb_debug, use_fake_units, preserve_timestamps = FALSE, fast_zeroing = FALSE, app_changed_size = FALSE; | BOOL usb_debug, use_fake_units, preserve_timestamps = FALSE, fast_zeroing = FALSE, app_changed_size = FALSE; | ||||||
| BOOL zero_drive = FALSE, list_non_usb_removable_drives = FALSE, enable_file_indexing, large_drive = FALSE; | BOOL zero_drive = FALSE, list_non_usb_removable_drives = FALSE, enable_file_indexing, large_drive = FALSE; | ||||||
| BOOL write_as_image = FALSE, write_as_esp = FALSE, use_vds = FALSE, ignore_boot_marker = FALSE; | BOOL write_as_image = FALSE, write_as_esp = FALSE, use_vds = FALSE, ignore_boot_marker = FALSE; | ||||||
| BOOL appstore_version = FALSE, is_vds_available = TRUE, persistent_log = FALSE; | BOOL appstore_version = FALSE, is_vds_available = TRUE, persistent_log = FALSE, has_ffu_support = FALSE; | ||||||
| float fScale = 1.0f; | float fScale = 1.0f; | ||||||
| int dialog_showing = 0, selection_default = BT_IMAGE, persistence_unit_selection = -1, imop_win_sel = 0; | int dialog_showing = 0, selection_default = BT_IMAGE, persistence_unit_selection = -1, imop_win_sel = 0; | ||||||
| int default_fs, fs_type, boot_type, partition_type, target_type; | int default_fs, fs_type, boot_type, partition_type, target_type; | ||||||
|  | @ -2588,8 +2588,11 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA | ||||||
| 					img_provided = FALSE;	// One off thing...
 | 					img_provided = FALSE;	// One off thing...
 | ||||||
| 				} else { | 				} else { | ||||||
| 					char* old_image_path = image_path; | 					char* old_image_path = image_path; | ||||||
|  | 					char extensions[128] = "*.iso;*.img;*.vhd;*.vhdx;*.usb;*.bz2;*.bzip2;*.gz;*.lzma;*.xz;*.Z;*.zip;*.wim;*.esd;*.vtsi"; | ||||||
|  | 					if (has_ffu_support) | ||||||
|  | 						strcat(extensions, ";*.ffu"); | ||||||
| 					// If declared globaly, lmprintf(MSG_036) would be called on each message...
 | 					// If declared globaly, lmprintf(MSG_036) would be called on each message...
 | ||||||
| 					EXT_DECL(img_ext, NULL, __VA_GROUP__("*.iso;*.img;*.vhd;*.usb;*.bz2;*.bzip2;*.gz;*.lzma;*.xz;*.Z;*.zip;*.wim;*.esd;*.vtsi"), | 					EXT_DECL(img_ext, NULL, __VA_GROUP__(extensions), | ||||||
| 						__VA_GROUP__(lmprintf(MSG_036))); | 						__VA_GROUP__(lmprintf(MSG_036))); | ||||||
| 					image_path = FileDialog(FALSE, NULL, &img_ext, 0); | 					image_path = FileDialog(FALSE, NULL, &img_ext, 0); | ||||||
| 					if (image_path == NULL) { | 					if (image_path == NULL) { | ||||||
|  | @ -2684,7 +2687,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA | ||||||
| 			} | 			} | ||||||
| 			break; | 			break; | ||||||
| 		case IDC_SAVE: | 		case IDC_SAVE: | ||||||
| 			SaveVHD(); | 			VhdSaveImage(); | ||||||
| 			break; | 			break; | ||||||
| 		case IDM_SELECT: | 		case IDM_SELECT: | ||||||
| 		case IDM_DOWNLOAD: | 		case IDM_DOWNLOAD: | ||||||
|  | @ -3695,6 +3698,9 @@ skip_args_processing: | ||||||
| 	// Detect CPU acceleration for SHA-1/SHA-256
 | 	// Detect CPU acceleration for SHA-1/SHA-256
 | ||||||
| 	cpu_has_sha1_accel = DetectSHA1Acceleration(); | 	cpu_has_sha1_accel = DetectSHA1Acceleration(); | ||||||
| 	cpu_has_sha256_accel = DetectSHA256Acceleration(); | 	cpu_has_sha256_accel = DetectSHA256Acceleration(); | ||||||
|  | 	// FFU support started with Windows 10 1709 (through FfuProvider.dll)
 | ||||||
|  | 	static_sprintf(tmp_path, "%s\\dism\\FfuProvider.dll", sysnative_dir); | ||||||
|  | 	has_ffu_support = (_accessU(tmp_path, 0) == 0); | ||||||
| 
 | 
 | ||||||
| relaunch: | relaunch: | ||||||
| 	ubprintf("Localization set to '%s'", selected_locale->txt[0]); | 	ubprintf("Localization set to '%s'", selected_locale->txt[0]); | ||||||
|  | @ -3964,7 +3970,7 @@ extern int TestHashes(void); | ||||||
| 			} | 			} | ||||||
| 			// Alt-O => Save from Optical drive to ISO
 | 			// Alt-O => Save from Optical drive to ISO
 | ||||||
| 			if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'O')) { | 			if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'O')) { | ||||||
| 				SaveISO(); | 				IsoSaveImage(); | ||||||
| 				continue; | 				continue; | ||||||
| 			} | 			} | ||||||
| 			// Alt-P => Toggle GPT ESP to and from Basic Data type (Windows 10 or later)
 | 			// Alt-P => Toggle GPT ESP to and from Basic Data type (Windows 10 or later)
 | ||||||
|  |  | ||||||
|  | @ -652,8 +652,6 @@ extern int64_t ExtractISOFile(const char* iso, const char* iso_file, const char* | ||||||
| extern BOOL CopySKUSiPolicy(const char* drive_name); | extern BOOL CopySKUSiPolicy(const char* drive_name); | ||||||
| extern BOOL HasEfiImgBootLoaders(void); | extern BOOL HasEfiImgBootLoaders(void); | ||||||
| extern BOOL DumpFatDir(const char* path, int32_t cluster); | extern BOOL DumpFatDir(const char* path, int32_t cluster); | ||||||
| extern char* MountISO(const char* path); |  | ||||||
| extern void UnMountISO(void); |  | ||||||
| extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs); | extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter, int fs); | ||||||
| extern uint16_t GetSyslinuxVersion(char* buf, size_t buf_size, char** ext); | extern uint16_t GetSyslinuxVersion(char* buf, size_t buf_size, char** ext); | ||||||
| extern BOOL SetAutorun(const char* path); | extern BOOL SetAutorun(const char* path); | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								src/rufus.rc
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								src/rufus.rc
									
										
									
									
									
								
							|  | @ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL | ||||||
| IDD_DIALOG DIALOGEX 12, 12, 232, 326 | IDD_DIALOG DIALOGEX 12, 12, 232, 326 | ||||||
| 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_ACCEPTFILES | EXSTYLE WS_EX_ACCEPTFILES | ||||||
| CAPTION "Rufus 4.2.2067" | CAPTION "Rufus 4.2.2068" | ||||||
| FONT 9, "Segoe UI Symbol", 400, 0, 0x0 | FONT 9, "Segoe UI Symbol", 400, 0, 0x0 | ||||||
| BEGIN | BEGIN | ||||||
|     LTEXT           "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP |     LTEXT           "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP | ||||||
|  | @ -392,8 +392,8 @@ END | ||||||
| // | // | ||||||
| 
 | 
 | ||||||
| VS_VERSION_INFO VERSIONINFO | VS_VERSION_INFO VERSIONINFO | ||||||
|  FILEVERSION 4,2,2067,0 |  FILEVERSION 4,2,2068,0 | ||||||
|  PRODUCTVERSION 4,2,2067,0 |  PRODUCTVERSION 4,2,2068,0 | ||||||
|  FILEFLAGSMASK 0x3fL |  FILEFLAGSMASK 0x3fL | ||||||
| #ifdef _DEBUG | #ifdef _DEBUG | ||||||
|  FILEFLAGS 0x1L |  FILEFLAGS 0x1L | ||||||
|  | @ -411,13 +411,13 @@ BEGIN | ||||||
|             VALUE "Comments", "https://rufus.ie" |             VALUE "Comments", "https://rufus.ie" | ||||||
|             VALUE "CompanyName", "Akeo Consulting" |             VALUE "CompanyName", "Akeo Consulting" | ||||||
|             VALUE "FileDescription", "Rufus" |             VALUE "FileDescription", "Rufus" | ||||||
|             VALUE "FileVersion", "4.2.2067" |             VALUE "FileVersion", "4.2.2068" | ||||||
|             VALUE "InternalName", "Rufus" |             VALUE "InternalName", "Rufus" | ||||||
|             VALUE "LegalCopyright", "© 2011-2023 Pete Batard (GPL v3)" |             VALUE "LegalCopyright", "© 2011-2023 Pete Batard (GPL v3)" | ||||||
|             VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" |             VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" | ||||||
|             VALUE "OriginalFilename", "rufus-4.2.exe" |             VALUE "OriginalFilename", "rufus-4.2.exe" | ||||||
|             VALUE "ProductName", "Rufus" |             VALUE "ProductName", "Rufus" | ||||||
|             VALUE "ProductVersion", "4.2.2067" |             VALUE "ProductVersion", "4.2.2068" | ||||||
|         END |         END | ||||||
|     END |     END | ||||||
|     BLOCK "VarFileInfo" |     BLOCK "VarFileInfo" | ||||||
|  |  | ||||||
|  | @ -1235,7 +1235,7 @@ uint32_t ResolveDllAddress(dll_resolver_t* resolver) | ||||||
| 	// Check settings to see if we have existing data for these DLL calls.
 | 	// Check settings to see if we have existing data for these DLL calls.
 | ||||||
| 	for (i = 0; i < resolver->count; i++) { | 	for (i = 0; i < resolver->count; i++) { | ||||||
| 		static_sprintf(saved_id, "%s@%s%x:%s", _filenameU(resolver->path), | 		static_sprintf(saved_id, "%s@%s%x:%s", _filenameU(resolver->path), | ||||||
| 			GuidToString(&info->Guid, FALSE), info->Age, resolver->name[i]); | 			GuidToString(&info->Guid, FALSE), (int)info->Age, resolver->name[i]); | ||||||
| 		resolver->address[i] = ReadSetting32(saved_id); | 		resolver->address[i] = ReadSetting32(saved_id); | ||||||
| 		if (resolver->address[i] == 0) | 		if (resolver->address[i] == 0) | ||||||
| 			break; | 			break; | ||||||
|  | @ -1253,7 +1253,7 @@ uint32_t ResolveDllAddress(dll_resolver_t* resolver) | ||||||
| 		goto out; | 		goto out; | ||||||
| 	static_sprintf(path, "%s\\%s", temp_dir, info->PdbName); | 	static_sprintf(path, "%s\\%s", temp_dir, info->PdbName); | ||||||
| 	static_sprintf(url, "http://msdl.microsoft.com/download/symbols/%s/%s%x/%s", | 	static_sprintf(url, "http://msdl.microsoft.com/download/symbols/%s/%s%x/%s", | ||||||
| 		info->PdbName, GuidToString(&info->Guid, FALSE), info->Age, info->PdbName); | 		info->PdbName, GuidToString(&info->Guid, FALSE), (int)info->Age, info->PdbName); | ||||||
| 	if (DownloadToFileOrBufferEx(url, path, SYMBOL_SERVER_USER_AGENT, NULL, hMainDialog, FALSE) < 200 * KB) | 	if (DownloadToFileOrBufferEx(url, path, SYMBOL_SERVER_USER_AGENT, NULL, hMainDialog, FALSE) < 200 * KB) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
|  | @ -1280,7 +1280,7 @@ uint32_t ResolveDllAddress(dll_resolver_t* resolver) | ||||||
| 	r = 0; | 	r = 0; | ||||||
| 	for (i = 0; i < resolver->count; i++) { | 	for (i = 0; i < resolver->count; i++) { | ||||||
| 		static_sprintf(saved_id, "%s@%s%x:%s", _filenameU(resolver->path), | 		static_sprintf(saved_id, "%s@%s%x:%s", _filenameU(resolver->path), | ||||||
| 			GuidToString(&info->Guid, FALSE), info->Age, resolver->name[i]); | 			GuidToString(&info->Guid, FALSE), (int)info->Age, resolver->name[i]); | ||||||
| 		if (resolver->address[i] != 0) { | 		if (resolver->address[i] != 0) { | ||||||
| 			WriteSetting32(saved_id, resolver->address[i]); | 			WriteSetting32(saved_id, resolver->address[i]); | ||||||
| 			r++; | 			r++; | ||||||
|  |  | ||||||
							
								
								
									
										209
									
								
								src/vhd.c
									
										
									
									
									
								
							
							
						
						
									
										209
									
								
								src/vhd.c
									
										
									
									
									
								
							|  | @ -58,7 +58,7 @@ typedef struct { | ||||||
| uint32_t wim_nb_files, wim_proc_files, wim_extra_files; | uint32_t wim_nb_files, wim_proc_files, wim_extra_files; | ||||||
| HANDLE wim_thread = NULL; | HANDLE wim_thread = NULL; | ||||||
| extern int default_thread_priority; | extern int default_thread_priority; | ||||||
| extern BOOL ignore_boot_marker; | extern BOOL ignore_boot_marker, has_ffu_support; | ||||||
| extern RUFUS_DRIVE rufus_drive[MAX_DRIVES]; | extern RUFUS_DRIVE rufus_drive[MAX_DRIVES]; | ||||||
| extern HANDLE format_thread; | extern HANDLE format_thread; | ||||||
| 
 | 
 | ||||||
|  | @ -67,7 +67,6 @@ static uint32_t progress_report_mask; | ||||||
| static uint64_t progress_offset = 0, progress_total = 100; | static uint64_t progress_offset = 0, progress_total = 100; | ||||||
| static wchar_t wmount_path[MAX_PATH] = { 0 }, wmount_track[MAX_PATH] = { 0 }; | static wchar_t wmount_path[MAX_PATH] = { 0 }, wmount_track[MAX_PATH] = { 0 }; | ||||||
| static char sevenzip_path[MAX_PATH]; | static char sevenzip_path[MAX_PATH]; | ||||||
| static const char conectix_str[] = VHD_FOOTER_COOKIE; |  | ||||||
| static BOOL count_files; | static BOOL count_files; | ||||||
| static int progress_op = OP_FILE_COPY, progress_msg = MSG_267; | static int progress_op = OP_FILE_COPY, progress_msg = MSG_267; | ||||||
| 
 | 
 | ||||||
|  | @ -83,7 +82,7 @@ static BOOL Get7ZipPath(void) | ||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
| 	const char* ext; | 	const char* ext; | ||||||
| 	bled_compression_type type; | 	uint8_t type; | ||||||
| } comp_assoc; | } comp_assoc; | ||||||
| 
 | 
 | ||||||
| static comp_assoc file_assoc[] = { | static comp_assoc file_assoc[] = { | ||||||
|  | @ -94,33 +93,75 @@ static comp_assoc file_assoc[] = { | ||||||
| 	{ ".bz2", BLED_COMPRESSION_BZIP2 }, | 	{ ".bz2", BLED_COMPRESSION_BZIP2 }, | ||||||
| 	{ ".xz", BLED_COMPRESSION_XZ }, | 	{ ".xz", BLED_COMPRESSION_XZ }, | ||||||
| 	{ ".vtsi", BLED_COMPRESSION_VTSI }, | 	{ ".vtsi", BLED_COMPRESSION_VTSI }, | ||||||
|  | 	{ ".ffu", BLED_COMPRESSION_MAX }, | ||||||
|  | 	{ ".vhd", BLED_COMPRESSION_MAX + 1 }, | ||||||
|  | 	{ ".vhdx", BLED_COMPRESSION_MAX + 2 }, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // For now we consider that an image that matches a known extension is bootable
 | // Look for a boot marker in the MBR area of the image
 | ||||||
| static BOOL IsCompressedBootableImage(const char* path) | static BOOL IsCompressedBootableImage(const char* path) | ||||||
| { | { | ||||||
| 	char *p; | 	char *ext = NULL, *physical_disk = NULL; | ||||||
| 	unsigned char *buf = NULL; | 	unsigned char *buf = NULL; | ||||||
| 	int i; | 	int i; | ||||||
|  | 	FILE* fd = NULL; | ||||||
| 	BOOL r = FALSE; | 	BOOL r = FALSE; | ||||||
| 	int64_t dc; | 	int64_t dc = 0; | ||||||
| 
 | 
 | ||||||
| 	img_report.compression_type = BLED_COMPRESSION_NONE; | 	img_report.compression_type = BLED_COMPRESSION_NONE; | ||||||
| 	for (p = (char*)&path[strlen(path)-1]; (*p != '.') && (p != path); p--); | 	if (safe_strlen(path) > 4) | ||||||
|  | 		for (ext = (char*)&path[safe_strlen(path) - 1]; (*ext != '.') && (ext != path); ext--); | ||||||
| 
 | 
 | ||||||
| 	if (p == path) | 	for (i = 0; i < ARRAYSIZE(file_assoc); i++) { | ||||||
| 		return FALSE; | 		if (safe_stricmp(ext, file_assoc[i].ext) == 0) { | ||||||
| 
 |  | ||||||
| 	for (i = 0; i<ARRAYSIZE(file_assoc); i++) { |  | ||||||
| 		if (strcmp(p, file_assoc[i].ext) == 0) { |  | ||||||
| 			img_report.compression_type = file_assoc[i].type; | 			img_report.compression_type = file_assoc[i].type; | ||||||
| 			buf = malloc(MBR_SIZE); | 			buf = malloc(MBR_SIZE); | ||||||
| 			if (buf == NULL) | 			if (buf == NULL) | ||||||
| 				return FALSE; | 				return FALSE; | ||||||
| 			FormatStatus = 0; | 			FormatStatus = 0; | ||||||
|  | 			if (img_report.compression_type < BLED_COMPRESSION_MAX) { | ||||||
| 				bled_init(0, uprintf, NULL, NULL, NULL, NULL, &FormatStatus); | 				bled_init(0, uprintf, NULL, NULL, NULL, NULL, &FormatStatus); | ||||||
| 				dc = bled_uncompress_to_buffer(path, (char*)buf, MBR_SIZE, file_assoc[i].type); | 				dc = bled_uncompress_to_buffer(path, (char*)buf, MBR_SIZE, file_assoc[i].type); | ||||||
| 				bled_exit(); | 				bled_exit(); | ||||||
|  | 			} else if (img_report.compression_type == BLED_COMPRESSION_MAX) { | ||||||
|  | 				// Dism, through FfuProvider.dll, can mount a .ffu as a physicaldrive, which we
 | ||||||
|  | 				// could then use to poke the MBR as we do for VHD... Except Microsoft did design
 | ||||||
|  | 				// dism to FAIL AND EXIT, after mounting the ffu as a virtual drive, if it doesn't
 | ||||||
|  | 				// find something that looks like Windows at the specified image index... which it
 | ||||||
|  | 				// usually won't in our case. So, curse Microsoft and their incredible short-
 | ||||||
|  | 				// sightedness (or, most likely in this case, intentional malice, by BREACHING the
 | ||||||
|  | 				// OS contract to keep useful disk APIs for their usage, and their usage only).
 | ||||||
|  | 				// Then again, considering that .ffu's are GPT based, the marker should always be
 | ||||||
|  | 				// present, so just check for the FFU signature and pretend there's a marker then.
 | ||||||
|  | 				if (has_ffu_support) { | ||||||
|  | 					fd = fopenU(path, "rb"); | ||||||
|  | 					if (fd != NULL) { | ||||||
|  | 						dc = fread(buf, 1, MBR_SIZE, fd); | ||||||
|  | 						fclose(fd); | ||||||
|  | 						// The signature may not be constant, but since the only game in town to
 | ||||||
|  | 						// create FFU is dism, and dism appears to use "SignedImage " always,.we
 | ||||||
|  | 						// might as well use this to our advantage.
 | ||||||
|  | 						if (strncmp(&buf[4], "SignedImage ", 12) == 0) { | ||||||
|  | 							// At this stage, the buffer is only used for marker validation.
 | ||||||
|  | 							buf[0x1FE] = 0x55; | ||||||
|  | 							buf[0x1FF] = 0xAA; | ||||||
|  | 						} | ||||||
|  | 					} else | ||||||
|  | 						uprintf("Could not open %s: %d", path, errno); | ||||||
|  | 				} else { | ||||||
|  | 					uprintf("  An FFU image was selected, but this system does not have FFU support!"); | ||||||
|  | 				} | ||||||
|  | 			} else { | ||||||
|  | 				physical_disk = VhdMountImage(path); | ||||||
|  | 				if (physical_disk != NULL) { | ||||||
|  | 					fd = fopenU(physical_disk, "rb"); | ||||||
|  | 					if (fd != NULL) { | ||||||
|  | 						dc = fread(buf, 1, MBR_SIZE, fd); | ||||||
|  | 						fclose(fd); | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				VhdUnmountImage(); | ||||||
|  | 			} | ||||||
| 			if (dc != MBR_SIZE) { | 			if (dc != MBR_SIZE) { | ||||||
| 				free(buf); | 				free(buf); | ||||||
| 				return FALSE; | 				return FALSE; | ||||||
|  | @ -139,10 +180,7 @@ int8_t IsBootableImage(const char* path) | ||||||
| { | { | ||||||
| 	HANDLE handle = INVALID_HANDLE_VALUE; | 	HANDLE handle = INVALID_HANDLE_VALUE; | ||||||
| 	LARGE_INTEGER liImageSize; | 	LARGE_INTEGER liImageSize; | ||||||
| 	vhd_footer* footer = NULL; |  | ||||||
| 	DWORD size; | 	DWORD size; | ||||||
| 	size_t i; |  | ||||||
| 	uint32_t checksum, old_checksum; |  | ||||||
| 	uint64_t wim_magic = 0; | 	uint64_t wim_magic = 0; | ||||||
| 	LARGE_INTEGER ptr = { 0 }; | 	LARGE_INTEGER ptr = { 0 }; | ||||||
| 	int8_t is_bootable_img; | 	int8_t is_bootable_img; | ||||||
|  | @ -171,40 +209,7 @@ int8_t IsBootableImage(const char* path) | ||||||
| 	if (img_report.is_windows_img) | 	if (img_report.is_windows_img) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	size = sizeof(vhd_footer); |  | ||||||
| 	if ((img_report.compression_type == BLED_COMPRESSION_NONE) && (img_report.image_size >= (512 + size))) { |  | ||||||
| 		footer = (vhd_footer*)malloc(size); |  | ||||||
| 		ptr.QuadPart = img_report.image_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"); |  | ||||||
| 			is_bootable_img = -3; |  | ||||||
| 			goto out; |  | ||||||
| 		} |  | ||||||
| 		if (memcmp(footer->cookie, conectix_str, sizeof(footer->cookie)) == 0) { |  | ||||||
| 			img_report.image_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"); |  | ||||||
| 				is_bootable_img = 0; |  | ||||||
| 				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"); |  | ||||||
| 			img_report.is_vhd = TRUE; |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| out: | out: | ||||||
| 	safe_free(footer); |  | ||||||
| 	safe_closehandle(handle); | 	safe_closehandle(handle); | ||||||
| 	return is_bootable_img; | 	return is_bootable_img; | ||||||
| } | } | ||||||
|  | @ -405,7 +410,7 @@ char* WimMountImage(const char* image, int index) | ||||||
| 	mp.index = index; | 	mp.index = index; | ||||||
| 
 | 
 | ||||||
| 	// Try to unmount an existing stale image, if there is any
 | 	// Try to unmount an existing stale image, if there is any
 | ||||||
| 	mount_path = GetExistingMountPoint(image, index); | 	mount_path = WimGetExistingMountPoint(image, index); | ||||||
| 	if (mount_path != NULL) { | 	if (mount_path != NULL) { | ||||||
| 		uprintf("WARNING: Found stale '%s [%d]' image mounted on '%s' - Attempting to unmount it...", | 		uprintf("WARNING: Found stale '%s [%d]' image mounted on '%s' - Attempting to unmount it...", | ||||||
| 			image, index, mount_path); | 			image, index, mount_path); | ||||||
|  | @ -499,7 +504,7 @@ BOOL WimUnmountImage(const char* image, int index, BOOL commit) | ||||||
| // This basically parses HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WIMMount\Mounted Images
 | // This basically parses HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WIMMount\Mounted Images
 | ||||||
| // to see if an instance exists with the image/index passed as parameter and returns
 | // to see if an instance exists with the image/index passed as parameter and returns
 | ||||||
| // the mount point of this image if found, or NULL otherwise.
 | // the mount point of this image if found, or NULL otherwise.
 | ||||||
| char* GetExistingMountPoint(const char* image, int index) | char* WimGetExistingMountPoint(const char* image, int index) | ||||||
| { | { | ||||||
| 	static char path[MAX_PATH]; | 	static char path[MAX_PATH]; | ||||||
| 	char class[MAX_PATH] = "", guid[40], key_name[MAX_PATH]; | 	char class[MAX_PATH] = "", guid[40], key_name[MAX_PATH]; | ||||||
|  | @ -886,17 +891,102 @@ BOOL WimApplyImage(const char* image, int index, const char* dst) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // VirtDisk API Prototypes since we can't use delay-loading because of MinGW
 | // VirtDisk API Prototypes since we can't use delay-loading because of MinGW
 | ||||||
|  | // See https://github.com/pbatard/rufus/issues/2272#issuecomment-1615976013
 | ||||||
| PF_TYPE_DECL(WINAPI, DWORD, CreateVirtualDisk, (PVIRTUAL_STORAGE_TYPE, PCWSTR, | PF_TYPE_DECL(WINAPI, DWORD, CreateVirtualDisk, (PVIRTUAL_STORAGE_TYPE, PCWSTR, | ||||||
| 	VIRTUAL_DISK_ACCESS_MASK, PSECURITY_DESCRIPTOR, CREATE_VIRTUAL_DISK_FLAG, ULONG, | 	VIRTUAL_DISK_ACCESS_MASK, PSECURITY_DESCRIPTOR, CREATE_VIRTUAL_DISK_FLAG, ULONG, | ||||||
| 	PCREATE_VIRTUAL_DISK_PARAMETERS, LPOVERLAPPED, PHANDLE)); | 	PCREATE_VIRTUAL_DISK_PARAMETERS, LPOVERLAPPED, PHANDLE)); | ||||||
|  | PF_TYPE_DECL(WINAPI, DWORD, OpenVirtualDisk, (PVIRTUAL_STORAGE_TYPE, PCWSTR, | ||||||
|  | 	VIRTUAL_DISK_ACCESS_MASK, OPEN_VIRTUAL_DISK_FLAG, POPEN_VIRTUAL_DISK_PARAMETERS, PHANDLE)); | ||||||
|  | PF_TYPE_DECL(WINAPI, DWORD, AttachVirtualDisk, (HANDLE, PSECURITY_DESCRIPTOR, | ||||||
|  | 	ATTACH_VIRTUAL_DISK_FLAG, ULONG, PATTACH_VIRTUAL_DISK_PARAMETERS, LPOVERLAPPED)); | ||||||
|  | PF_TYPE_DECL(WINAPI, DWORD, DetachVirtualDisk, (HANDLE, DETACH_VIRTUAL_DISK_FLAG, ULONG)); | ||||||
|  | PF_TYPE_DECL(WINAPI, DWORD, GetVirtualDiskPhysicalPath, (HANDLE, PULONG, PWSTR)); | ||||||
| PF_TYPE_DECL(WINAPI, DWORD, GetVirtualDiskOperationProgress, (HANDLE, LPOVERLAPPED, | PF_TYPE_DECL(WINAPI, DWORD, GetVirtualDiskOperationProgress, (HANDLE, LPOVERLAPPED, | ||||||
| 	PVIRTUAL_DISK_PROGRESS)); | 	PVIRTUAL_DISK_PROGRESS)); | ||||||
| 
 | 
 | ||||||
|  | static char physical_path[128] = ""; | ||||||
|  | static HANDLE mounted_handle = INVALID_HANDLE_VALUE; | ||||||
|  | 
 | ||||||
|  | // Mount an ISO or a VHD/VHDX image
 | ||||||
|  | // Returns the physical path of the mounted image or NULL on error.
 | ||||||
|  | char* VhdMountImage(const char* path) | ||||||
|  | { | ||||||
|  | 	VIRTUAL_STORAGE_TYPE vtype = { VIRTUAL_STORAGE_TYPE_DEVICE_ISO, VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT }; | ||||||
|  | 	ATTACH_VIRTUAL_DISK_PARAMETERS vparams = { 0 }; | ||||||
|  | 	DWORD r; | ||||||
|  | 	wchar_t wtmp[128]; | ||||||
|  | 	ULONG size = ARRAYSIZE(wtmp); | ||||||
|  | 	wconvert(path); | ||||||
|  | 	char *ret = NULL, *ext = NULL; | ||||||
|  | 
 | ||||||
|  | 	PF_INIT_OR_OUT(OpenVirtualDisk, VirtDisk); | ||||||
|  | 	PF_INIT_OR_OUT(AttachVirtualDisk, VirtDisk); | ||||||
|  | 	PF_INIT_OR_OUT(GetVirtualDiskPhysicalPath, VirtDisk); | ||||||
|  | 
 | ||||||
|  | 	if (wpath == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	if ((mounted_handle != NULL) && (mounted_handle != INVALID_HANDLE_VALUE)) | ||||||
|  | 		VhdUnmountImage(); | ||||||
|  | 
 | ||||||
|  | 	if (safe_strlen(path) > 4) | ||||||
|  | 		for (ext = (char*)&path[safe_strlen(path) - 1]; (*ext != '.') && (ext != path); ext--); | ||||||
|  | 	if (safe_stricmp(ext, ".vhdx") == 0) | ||||||
|  | 		vtype.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_VHDX; | ||||||
|  | 	else if (safe_stricmp(ext, ".vhdx") == 0) | ||||||
|  | 		vtype.DeviceId = VIRTUAL_STORAGE_TYPE_DEVICE_VHD; | ||||||
|  | 
 | ||||||
|  | 	r = pfOpenVirtualDisk(&vtype, wpath, VIRTUAL_DISK_ACCESS_READ | VIRTUAL_DISK_ACCESS_GET_INFO, | ||||||
|  | 		OPEN_VIRTUAL_DISK_FLAG_NONE, NULL, &mounted_handle); | ||||||
|  | 	if (r != ERROR_SUCCESS) { | ||||||
|  | 		SetLastError(r); | ||||||
|  | 		uprintf("Could not open image '%s': %s", path, WindowsErrorString()); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	vparams.Version = ATTACH_VIRTUAL_DISK_VERSION_1; | ||||||
|  | 	r = pfAttachVirtualDisk(mounted_handle, NULL, ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY | | ||||||
|  | 		ATTACH_VIRTUAL_DISK_FLAG_NO_DRIVE_LETTER, 0, &vparams, NULL); | ||||||
|  | 	if (r != ERROR_SUCCESS) { | ||||||
|  | 		SetLastError(r); | ||||||
|  | 		uprintf("Could not mount image '%s': %s", path, WindowsErrorString()); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	r = pfGetVirtualDiskPhysicalPath(mounted_handle, &size, wtmp); | ||||||
|  | 	if (r != ERROR_SUCCESS) { | ||||||
|  | 		SetLastError(r); | ||||||
|  | 		uprintf("Could not obtain physical path for mounted image '%s': %s", path, WindowsErrorString()); | ||||||
|  | 		goto out; | ||||||
|  | 	} | ||||||
|  | 	wchar_to_utf8_no_alloc(wtmp, physical_path, sizeof(physical_path)); | ||||||
|  | 	ret = physical_path; | ||||||
|  | 
 | ||||||
|  | out: | ||||||
|  | 	if (ret == NULL) | ||||||
|  | 		VhdUnmountImage(); | ||||||
|  | 	wfree(path); | ||||||
|  | 	return ret; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void VhdUnmountImage(void) | ||||||
|  | { | ||||||
|  | 	PF_INIT_OR_OUT(DetachVirtualDisk, VirtDisk); | ||||||
|  | 
 | ||||||
|  | 	if ((mounted_handle == NULL) || (mounted_handle == INVALID_HANDLE_VALUE)) | ||||||
|  | 		goto out; | ||||||
|  | 
 | ||||||
|  | 	pfDetachVirtualDisk(mounted_handle, DETACH_VIRTUAL_DISK_FLAG_NONE, 0); | ||||||
|  | 	safe_closehandle(mounted_handle); | ||||||
|  | out: | ||||||
|  | 	physical_path[0] = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // Since we no longer have to deal with Windows 7, we can call on CreateVirtualDisk()
 | // Since we no longer have to deal with Windows 7, we can call on CreateVirtualDisk()
 | ||||||
| // to backup a physical disk to VHD/VHDX. Now if this could also be used to create an
 | // to backup a physical disk to VHD/VHDX. Now if this could also be used to create an
 | ||||||
| // ISO from optical media that would be swell, but no matter what I tried, it didn't
 | // ISO from optical media that would be swell, but no matter what I tried, it didn't
 | ||||||
| // seem possible...
 | // seem possible...
 | ||||||
| static DWORD WINAPI SaveVHDThread(void* param) | static DWORD WINAPI VhdSaveImageThread(void* param) | ||||||
| { | { | ||||||
| 	IMG_SAVE* img_save = (IMG_SAVE*)param; | 	IMG_SAVE* img_save = (IMG_SAVE*)param; | ||||||
| 	HANDLE handle = INVALID_HANDLE_VALUE; | 	HANDLE handle = INVALID_HANDLE_VALUE; | ||||||
|  | @ -984,21 +1074,21 @@ out: | ||||||
| // calls, as well as how to properly hook into the DLL for every arch/every release
 | // calls, as well as how to properly hook into the DLL for every arch/every release
 | ||||||
| // of Windows, would be a massive timesink, we just take a shortcut by calling dism
 | // of Windows, would be a massive timesink, we just take a shortcut by calling dism
 | ||||||
| // directly, as imperfect as such a solution might be...
 | // directly, as imperfect as such a solution might be...
 | ||||||
| static DWORD WINAPI SaveFFUThread(void* param) | static DWORD WINAPI FfuSaveImageThread(void* param) | ||||||
| { | { | ||||||
| 	DWORD r; | 	DWORD r; | ||||||
| 	IMG_SAVE* img_save = (IMG_SAVE*)param; | 	IMG_SAVE* img_save = (IMG_SAVE*)param; | ||||||
| 	char cmd[MAX_PATH + 128], *letter = "", *label; | 	char cmd[MAX_PATH + 128], *letter = "", *label; | ||||||
| 
 | 
 | ||||||
| 	GetDriveLabel(SelectedDrive.DeviceNumber, letter, &label, TRUE); | 	GetDriveLabel(SelectedDrive.DeviceNumber, letter, &label, TRUE); | ||||||
| 	static_sprintf(cmd, "dism /capture-ffu /capturedrive=%s /imagefile=\"%s\" " | 	static_sprintf(cmd, "dism /Capture-Ffu /CaptureDrive:%s /ImageFile:\"%s\" " | ||||||
| 		"/name:\"%s\" /description:\"Created by %s (%s)\"", | 		"/Name:\"%s\" /Description:\"Created by %s (%s)\"", | ||||||
| 		img_save->DevicePath, img_save->ImagePath, label, APPLICATION_NAME, RUFUS_URL); | 		img_save->DevicePath, img_save->ImagePath, label, APPLICATION_NAME, RUFUS_URL); | ||||||
| 	uprintf("Running command: '%s", cmd); | 	uprintf("Running command: '%s", cmd); | ||||||
| 	r = RunCommandWithProgress(cmd, sysnative_dir, TRUE, MSG_261); | 	r = RunCommandWithProgress(cmd, sysnative_dir, TRUE, MSG_261); | ||||||
| 	if (r != 0 && !IS_ERROR(FormatStatus)) { | 	if (r != 0 && !IS_ERROR(FormatStatus)) { | ||||||
| 		SetLastError(r); | 		SetLastError(r); | ||||||
| 		uprintf("Failed to create FFU image: %s", WindowsErrorString()); | 		uprintf("Failed to capture FFU image: %s", WindowsErrorString()); | ||||||
| 		FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_WINDOWS) | SCODE_CODE(r); | 		FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_WINDOWS) | SCODE_CODE(r); | ||||||
| 	} | 	} | ||||||
| 	safe_free(img_save->DevicePath); | 	safe_free(img_save->DevicePath); | ||||||
|  | @ -1007,7 +1097,7 @@ static DWORD WINAPI SaveFFUThread(void* param) | ||||||
| 	ExitThread(r); | 	ExitThread(r); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void SaveVHD(void) | void VhdSaveImage(void) | ||||||
| { | { | ||||||
| 	static IMG_SAVE img_save = { 0 }; | 	static IMG_SAVE img_save = { 0 }; | ||||||
| 	char filename[128]; | 	char filename[128]; | ||||||
|  | @ -1023,9 +1113,8 @@ void SaveVHD(void) | ||||||
| 	static_sprintf(filename, "%s.vhdx", rufus_drive[DriveIndex].label); | 	static_sprintf(filename, "%s.vhdx", rufus_drive[DriveIndex].label); | ||||||
| 	img_save.DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, DriveIndex); | 	img_save.DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, DriveIndex); | ||||||
| 	img_save.DevicePath = GetPhysicalName(img_save.DeviceNum); | 	img_save.DevicePath = GetPhysicalName(img_save.DeviceNum); | ||||||
| 	// FFU support started with Windows 10 1709 (through FfuProvider.dll) and requires GPT
 | 	// FFU support requires GPT
 | ||||||
| 	static_sprintf(path, "%s\\dism\\FfuProvider.dll", sysnative_dir); | 	if (!has_ffu_support || SelectedDrive.PartitionStyle != PARTITION_STYLE_GPT) | ||||||
| 	if ((_accessU(path, 0) != 0) || SelectedDrive.PartitionStyle != PARTITION_STYLE_GPT) |  | ||||||
| 		img_ext.count = 2; | 		img_ext.count = 2; | ||||||
| 	img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, 0); | 	img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, 0); | ||||||
| 	img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_VHD; | 	img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_VHD; | ||||||
|  | @ -1048,7 +1137,7 @@ void SaveVHD(void) | ||||||
| 			FormatStatus = 0; | 			FormatStatus = 0; | ||||||
| 			InitProgress(TRUE); | 			InitProgress(TRUE); | ||||||
| 			format_thread = CreateThread(NULL, 0, img_save.Type == VIRTUAL_STORAGE_TYPE_DEVICE_FFU ? | 			format_thread = CreateThread(NULL, 0, img_save.Type == VIRTUAL_STORAGE_TYPE_DEVICE_FFU ? | ||||||
| 				SaveFFUThread : SaveVHDThread, &img_save, 0, NULL); | 				FfuSaveImageThread : VhdSaveImageThread, &img_save, 0, NULL); | ||||||
| 			if (format_thread != NULL) { | 			if (format_thread != NULL) { | ||||||
| 				uprintf("\r\nSave to VHD operation started"); | 				uprintf("\r\nSave to VHD operation started"); | ||||||
| 				PrintInfo(0, -1); | 				PrintInfo(0, -1); | ||||||
|  |  | ||||||
							
								
								
									
										59
									
								
								src/vhd.h
									
										
									
									
									
								
							
							
						
						
									
										59
									
								
								src/vhd.h
									
										
									
									
									
								
							|  | @ -23,23 +23,6 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #define VHD_FOOTER_COOKIE					{ 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x' } |  | ||||||
| 
 |  | ||||||
| #define VHD_FOOTER_FEATURES_NONE			0x00000000 |  | ||||||
| #define VHD_FOOTER_FEATURES_TEMPORARY		0x00000001 |  | ||||||
| #define VHD_FOOTER_FEATURES_RESERVED		0x00000002 |  | ||||||
| 
 |  | ||||||
| #define VHD_FOOTER_FILE_FORMAT_V1_0			0x00010000 |  | ||||||
| 
 |  | ||||||
| #define VHD_FOOTER_DATA_OFFSET_FIXED_DISK	0xFFFFFFFFFFFFFFFFULL |  | ||||||
| 
 |  | ||||||
| #define VHD_FOOTER_CREATOR_HOST_OS_WINDOWS	{ 'W', 'i', '2', 'k' } |  | ||||||
| #define VHD_FOOTER_CREATOR_HOST_OS_MAC		{ 'M', 'a', 'c', ' ' } |  | ||||||
| 
 |  | ||||||
| #define VHD_FOOTER_TYPE_FIXED_HARD_DISK		0x00000002 |  | ||||||
| #define VHD_FOOTER_TYPE_DYNAMIC_HARD_DISK	0x00000003 |  | ||||||
| #define VHD_FOOTER_TYPE_DIFFER_HARD_DISK	0x00000004 |  | ||||||
| 
 |  | ||||||
| #define WIM_MAGIC							0x0000004D4957534DULL	// "MSWIM\0\0\0"
 | #define WIM_MAGIC							0x0000004D4957534DULL	// "MSWIM\0\0\0"
 | ||||||
| #define WIM_HAS_API_EXTRACT					1 | #define WIM_HAS_API_EXTRACT					1 | ||||||
| #define WIM_HAS_7Z_EXTRACT					2 | #define WIM_HAS_7Z_EXTRACT					2 | ||||||
|  | @ -142,40 +125,6 @@ enum WIMMessage { | ||||||
| 	WIM_MSG_ABORT_IMAGE = -1 | 	WIM_MSG_ABORT_IMAGE = -1 | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /*
 |  | ||||||
|  * VHD Fixed HD footer (Big Endian) |  | ||||||
|  * http://download.microsoft.com/download/f/f/e/ffef50a5-07dd-4cf8-aaa3-442c0673a029/Virtual%20Hard%20Disk%20Format%20Spec_10_18_06.doc
 |  | ||||||
|  * NB: If a dymamic implementation is needed, check the GPL v3 compatible C++ implementation from: |  | ||||||
|  * https://sourceforge.net/p/urbackup/backend/ci/master/tree/fsimageplugin/
 |  | ||||||
|  */ |  | ||||||
| #pragma pack(push, 1) |  | ||||||
| typedef struct vhd_footer { |  | ||||||
| 	char		cookie[8]; |  | ||||||
| 	uint32_t	features; |  | ||||||
| 	uint32_t	file_format_version; |  | ||||||
| 	uint64_t	data_offset; |  | ||||||
| 	uint32_t	timestamp; |  | ||||||
| 	char		creator_app[4]; |  | ||||||
| 	uint32_t	creator_version; |  | ||||||
| 	char		creator_host_os[4]; |  | ||||||
| 	uint64_t	original_size; |  | ||||||
| 	uint64_t	current_size; |  | ||||||
| 	union { |  | ||||||
| 		uint32_t	geometry; |  | ||||||
| 		struct { |  | ||||||
| 			uint16_t	cylinders; |  | ||||||
| 			uint8_t		heads; |  | ||||||
| 			uint8_t		sectors; |  | ||||||
| 		} chs; |  | ||||||
| 	} disk_geometry; |  | ||||||
| 	uint32_t	disk_type; |  | ||||||
| 	uint32_t	checksum; |  | ||||||
| 	uuid_t		unique_id; |  | ||||||
| 	uint8_t		saved_state; |  | ||||||
| 	uint8_t		reserved[427]; |  | ||||||
| } vhd_footer; |  | ||||||
| #pragma pack(pop) |  | ||||||
| 
 |  | ||||||
| extern uint8_t WimExtractCheck(BOOL bSilent); | extern uint8_t WimExtractCheck(BOOL bSilent); | ||||||
| extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst, BOOL bSilent); | extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst, BOOL bSilent); | ||||||
| extern BOOL WimExtractFile_API(const char* image, int index, const char* src, const char* dst, BOOL bSilent); | extern BOOL WimExtractFile_API(const char* image, int index, const char* src, const char* dst, BOOL bSilent); | ||||||
|  | @ -183,8 +132,10 @@ extern BOOL WimExtractFile_7z(const char* image, int index, const char* src, con | ||||||
| extern BOOL WimApplyImage(const char* image, int index, const char* dst); | extern BOOL WimApplyImage(const char* image, int index, const char* dst); | ||||||
| extern char* WimMountImage(const char* image, int index); | extern char* WimMountImage(const char* image, int index); | ||||||
| extern BOOL WimUnmountImage(const char* image, int index, BOOL commit); | extern BOOL WimUnmountImage(const char* image, int index, BOOL commit); | ||||||
| extern char* GetExistingMountPoint(const char* image, int index); | extern char* WimGetExistingMountPoint(const char* image, int index); | ||||||
| extern BOOL WimIsValidIndex(const char* image, int index); | extern BOOL WimIsValidIndex(const char* image, int index); | ||||||
| extern int8_t IsBootableImage(const char* path); | extern int8_t IsBootableImage(const char* path); | ||||||
| extern void SaveVHD(void); | extern char* VhdMountImage(const char* path); | ||||||
| extern void SaveISO(void); | extern void VhdUnmountImage(void); | ||||||
|  | extern void VhdSaveImage(void); | ||||||
|  | extern void IsoSaveImage(void); | ||||||
|  |  | ||||||
							
								
								
									
										14
									
								
								src/wue.c
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								src/wue.c
									
										
									
									
									
								
							|  | @ -440,7 +440,7 @@ BOOL PopulateWindowsVersion(void) | ||||||
| 
 | 
 | ||||||
| 	// If we're not using a straight install.wim, we need to mount the ISO to access it
 | 	// If we're not using a straight install.wim, we need to mount the ISO to access it
 | ||||||
| 	if (!img_report.is_windows_img) { | 	if (!img_report.is_windows_img) { | ||||||
| 		mounted_iso = MountISO(image_path); | 		mounted_iso = VhdMountImage(image_path); | ||||||
| 		if (mounted_iso == NULL) { | 		if (mounted_iso == NULL) { | ||||||
| 			uprintf("Could not mount Windows ISO for build number detection"); | 			uprintf("Could not mount Windows ISO for build number detection"); | ||||||
| 			return FALSE; | 			return FALSE; | ||||||
|  | @ -468,7 +468,7 @@ BOOL PopulateWindowsVersion(void) | ||||||
| out: | out: | ||||||
| 	DeleteFileU(xml_file); | 	DeleteFileU(xml_file); | ||||||
| 	if (!img_report.is_windows_img) | 	if (!img_report.is_windows_img) | ||||||
| 		UnMountISO(); | 		VhdUnmountImage(); | ||||||
| 
 | 
 | ||||||
| 	return ((img_report.win_version.major != 0) && (img_report.win_version.build != 0)); | 	return ((img_report.win_version.major != 0) && (img_report.win_version.build != 0)); | ||||||
| } | } | ||||||
|  | @ -532,7 +532,7 @@ int SetWinToGoIndex(void) | ||||||
| 
 | 
 | ||||||
| 	// If we're not using a straight install.wim, we need to mount the ISO to access it
 | 	// If we're not using a straight install.wim, we need to mount the ISO to access it
 | ||||||
| 	if (!img_report.is_windows_img) { | 	if (!img_report.is_windows_img) { | ||||||
| 		mounted_iso = MountISO(image_path); | 		mounted_iso = VhdMountImage(image_path); | ||||||
| 		if (mounted_iso == NULL) { | 		if (mounted_iso == NULL) { | ||||||
| 			uprintf("Could not mount ISO for Windows To Go selection"); | 			uprintf("Could not mount ISO for Windows To Go selection"); | ||||||
| 			return -1; | 			return -1; | ||||||
|  | @ -613,7 +613,7 @@ int SetWinToGoIndex(void) | ||||||
| out: | out: | ||||||
| 	DeleteFileU(xml_file); | 	DeleteFileU(xml_file); | ||||||
| 	if (!img_report.is_windows_img) | 	if (!img_report.is_windows_img) | ||||||
| 		UnMountISO(); | 		VhdUnmountImage(); | ||||||
| 	return wintogo_index; | 	return wintogo_index; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -640,7 +640,7 @@ BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (!img_report.is_windows_img) { | 	if (!img_report.is_windows_img) { | ||||||
| 		mounted_iso = MountISO(image_path); | 		mounted_iso = VhdMountImage(image_path); | ||||||
| 		if (mounted_iso == NULL) { | 		if (mounted_iso == NULL) { | ||||||
| 			uprintf("Could not mount ISO for Windows To Go installation"); | 			uprintf("Could not mount ISO for Windows To Go installation"); | ||||||
| 			FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_ISO_EXTRACT); | 			FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_ISO_EXTRACT); | ||||||
|  | @ -656,11 +656,11 @@ BOOL SetupWinToGo(DWORD DriveIndex, const char* drive_name, BOOL use_esp) | ||||||
| 		if (!IS_ERROR(FormatStatus)) | 		if (!IS_ERROR(FormatStatus)) | ||||||
| 			FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_ISO_EXTRACT); | 			FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_ISO_EXTRACT); | ||||||
| 		if (!img_report.is_windows_img) | 		if (!img_report.is_windows_img) | ||||||
| 			UnMountISO(); | 			VhdUnmountImage(); | ||||||
| 		return FALSE; | 		return FALSE; | ||||||
| 	} | 	} | ||||||
| 	if (!img_report.is_windows_img) | 	if (!img_report.is_windows_img) | ||||||
| 		UnMountISO(); | 		VhdUnmountImage(); | ||||||
| 
 | 
 | ||||||
| 	if (use_esp) { | 	if (use_esp) { | ||||||
| 		uprintf("Setting up EFI System Partition"); | 		uprintf("Setting up EFI System Partition"); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue