From 8738e7a7de847ab0f630c6889e15bf78337f2c6b Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Mon, 4 Mar 2024 00:41:40 +0000 Subject: [PATCH] [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. --- src/format.c | 25 +++++++++++++------------ src/rufus.rc | 10 +++++----- src/vhd.c | 25 +++++++++++++++++++++---- src/vhd.h | 5 +++-- 4 files changed, 42 insertions(+), 23 deletions(-) diff --git a/src/format.c b/src/format.c index e8430272..6257a38b 100644 --- a/src/format.c +++ b/src/format.c @@ -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 diff --git a/src/rufus.rc b/src/rufus.rc index cd00d562..de6da44c 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -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" diff --git a/src/vhd.c b/src/vhd.c index 9340079b..1e475a91 100644 --- a/src/vhd.c +++ b/src/vhd.c @@ -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: diff --git a/src/vhd.h b/src/vhd.h index 65ac06d9..45a332b2 100644 --- a/src/vhd.h +++ b/src/vhd.h @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Virtual Disk Handling definitions and prototypes - * Copyright © 2022 Pete Batard + * Copyright © 2022-2024 Pete Batard * * 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);