[vhd] fix truncated write operation when using a VHDX image as source

* The legacy code we used for writing disk images used the size of the source image as
  the maximum number of bytes we should copy, which is fine for uncompressed DD or VHD
  images, but not so much for compressed VHDX ones. So we now make sure to use the
  actual size of the virtual disk, which we obtain when mounting the VHD/VHDX.
* Also fix log progress update as well as a MinGW warning.
This commit is contained in:
Pete Batard 2024-03-04 00:41:40 +00:00
parent 026afa7e3d
commit 8738e7a7de
No known key found for this signature in database
GPG Key ID: 38E0CF5E69EDD671
4 changed files with 42 additions and 23 deletions

View File

@ -1151,7 +1151,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
HANDLE hSourceImage = INVALID_HANDLE_VALUE;
DWORD i, read_size[NUM_BUFFERS], write_size, comp_size, buf_size;
uint64_t wb, target_size = bZeroDrive ? SelectedDrive.DiskSize : img_report.image_size;
uint64_t cur_value, last_value = UINT64_MAX;
uint64_t cur_value, last_value = 0;
int64_t bled_ret;
uint8_t* buffer = NULL;
uint32_t zero_data, *cmp_buffer = NULL;
@ -1197,11 +1197,9 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
read_size[0] = buf_size;
for (wb = 0, write_size = 0; wb < target_size; wb += write_size) {
UpdateProgressWithInfo(OP_FORMAT, fast_zeroing ? MSG_306 : MSG_286, wb, target_size);
cur_value = (wb * min(80, target_size)) / target_size;
if (cur_value != last_value) {
last_value = cur_value;
cur_value = (wb * 80) / target_size;
for (; cur_value > last_value && last_value < 80; last_value++)
uprintfs("+");
}
// Don't overflow our projected size (mostly for VHDs)
if (wb + read_size[0] > target_size)
read_size[0] = (DWORD)(target_size - wb);
@ -1275,6 +1273,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
if (i > WRITE_RETRIES)
goto out;
}
uprintfs("\r\n");
} else if (img_report.compression_type != BLED_COMPRESSION_NONE && img_report.compression_type < BLED_COMPRESSION_MAX) {
uprintf("Writing compressed image:");
hSourceImage = CreateFileU(image_path, GENERIC_READ, FILE_SHARE_READ, NULL,
@ -1316,8 +1315,9 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
// 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)
// Since VHDX images are compressed, we need to obtain the actual size
vhd_path = VhdMountImageAndGetSize(image_path, &target_size);
if (vhd_path == NULL || target_size == 0)
goto out;
}
@ -1346,11 +1346,12 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
for (wb = 0; read_size[proc_bufnum] != 0; wb += read_size[proc_bufnum]) {
// 0. Update the progress
UpdateProgressWithInfo(OP_FORMAT, MSG_261, wb, target_size);
cur_value = (wb * min(80, target_size)) / target_size;
if (cur_value != last_value) {
last_value = cur_value;
cur_value = (wb * 80) / target_size;
for ( ; cur_value > last_value && last_value < 80; last_value++)
uprintfs("+");
}
if (wb >= target_size)
break;
// 1. Wait for the current read operation to complete (and update the read size)
if ((!WaitFileAsync(hSourceImage, DRIVE_ACCESS_TIMEOUT)) ||
@ -1467,7 +1468,7 @@ DWORD WINAPI FormatThread(void* param)
extra_partitions |= XP_ESP | XP_MSR;
// If we have a bootable image with UEFI bootloaders and the target file system is NTFS or exFAT
// or the UEFI:NTFS option is selected, we add the UEFI:NTFS partition...
else if (((boot_type == BT_IMAGE) && IS_EFI_BOOTABLE(img_report)) && ((fs_type == FS_NTFS) || (fs_type == FS_EXFAT)) ||
else if ((((boot_type == BT_IMAGE) && IS_EFI_BOOTABLE(img_report)) && ((fs_type == FS_NTFS) || (fs_type == FS_EXFAT))) ||
(boot_type == BT_UEFI_NTFS)) {
extra_partitions |= XP_UEFI_NTFS;
// ...but only if we're not dealing with a Windows image in installer mode with target

View File

@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 232, 326
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES
CAPTION "Rufus 4.5.2113"
CAPTION "Rufus 4.5.2114"
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
BEGIN
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
@ -392,8 +392,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,5,2113,0
PRODUCTVERSION 4,5,2113,0
FILEVERSION 4,5,2114,0
PRODUCTVERSION 4,5,2114,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -411,13 +411,13 @@ BEGIN
VALUE "Comments", "https://rufus.ie"
VALUE "CompanyName", "Akeo Consulting"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "4.5.2113"
VALUE "FileVersion", "4.5.2114"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2024 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
VALUE "OriginalFilename", "rufus-4.5.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "4.5.2113"
VALUE "ProductVersion", "4.5.2114"
END
END
BLOCK "VarFileInfo"

View File

@ -908,18 +908,19 @@ 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,
PVIRTUAL_DISK_PROGRESS));
PF_TYPE_DECL(WINAPI, DWORD, GetVirtualDiskOperationProgress, (HANDLE, LPOVERLAPPED, PVIRTUAL_DISK_PROGRESS));
PF_TYPE_DECL(WINAPI, DWORD, GetVirtualDiskInformation, (HANDLE, PULONG, PGET_VIRTUAL_DISK_INFO, PULONG));
static char physical_path[128] = "";
static HANDLE mounted_handle = INVALID_HANDLE_VALUE;
// Mount an ISO or a VHD/VHDX image
// Mount an ISO or a VHD/VHDX image and provide its size
// Returns the physical path of the mounted image or NULL on error.
char* VhdMountImage(const char* path)
char* VhdMountImageAndGetSize(const char* path, uint64_t* disk_size)
{
VIRTUAL_STORAGE_TYPE vtype = { VIRTUAL_STORAGE_TYPE_DEVICE_ISO, VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT };
ATTACH_VIRTUAL_DISK_PARAMETERS vparams = { 0 };
GET_VIRTUAL_DISK_INFO disk_info = { 0 };
DWORD r;
wchar_t wtmp[128];
ULONG size = ARRAYSIZE(wtmp);
@ -929,6 +930,8 @@ char* VhdMountImage(const char* path)
PF_INIT_OR_OUT(OpenVirtualDisk, VirtDisk);
PF_INIT_OR_OUT(AttachVirtualDisk, VirtDisk);
PF_INIT_OR_OUT(GetVirtualDiskPhysicalPath, VirtDisk);
if (disk_size != NULL)
PF_INIT_OR_OUT(GetVirtualDiskInformation, VirtDisk);
if (wpath == NULL)
return NULL;
@ -967,6 +970,20 @@ char* VhdMountImage(const char* path)
goto out;
}
wchar_to_utf8_no_alloc(wtmp, physical_path, sizeof(physical_path));
if (disk_size != NULL) {
*disk_size = 0;
disk_info.Version = GET_VIRTUAL_DISK_INFO_SIZE;
size = sizeof(disk_info);
r = pfGetVirtualDiskInformation(mounted_handle, &size, &disk_info, NULL);
if (r != ERROR_SUCCESS) {
SetLastError(r);
uprintf("Could not obtain virtual size of mounted image '%s': %s", path, WindowsErrorString());
goto out;
}
*disk_size = disk_info.Size.VirtualSize;
}
ret = physical_path;
out:

View File

@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* Virtual Disk Handling definitions and prototypes
* Copyright © 2022 Pete Batard <pete@akeo.ie>
* Copyright © 2022-2024 Pete Batard <pete@akeo.ie>
*
* 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
@ -135,7 +135,8 @@ extern BOOL WimUnmountImage(const char* image, int index, BOOL commit);
extern char* WimGetExistingMountPoint(const char* image, int index);
extern BOOL WimIsValidIndex(const char* image, int index);
extern int8_t IsBootableImage(const char* path);
extern char* VhdMountImage(const char* path);
extern char* VhdMountImageAndGetSize(const char* path, uint64_t* disksize);
#define VhdMountImage(path) VhdMountImageAndGetSize(path, NULL)
extern void VhdUnmountImage(void);
extern void VhdSaveImage(void);
extern void IsoSaveImage(void);