Skip to content

Commit

Permalink
[vhd] add write support for .vhdx and .ffu images
Browse files Browse the repository at this point in the history
* Also move VHD mounting function calls from iso.c to vhd.c and remove unused VHD footer elements.
  • Loading branch information
pbatard committed Jul 6, 2023
1 parent f411d52 commit 5bbcba8
Show file tree
Hide file tree
Showing 10 changed files with 226 additions and 223 deletions.
42 changes: 36 additions & 6 deletions src/format.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#endif

#include "rufus.h"
#include "format.h"
#include "missing.h"
#include "resource.h"
#include "settings.h"
Expand Down Expand Up @@ -73,7 +74,7 @@ extern const int nb_steps[FS_MAX];
extern uint32_t dur_mins, dur_secs;
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 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;
long grub2_len;

Expand Down Expand Up @@ -1154,6 +1155,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
int64_t bled_ret;
uint8_t* buffer = NULL;
uint32_t zero_data, *cmp_buffer = NULL;
char* vhd_path = NULL;
int throttle_fast_zeroing = 0, read_bufnum = 0, proc_bufnum = 1;

if (SelectedDrive.SectorSize < 512) {
Expand Down Expand Up @@ -1273,7 +1275,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
if (i > WRITE_RETRIES)
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:");
hSourceImage = CreateFileU(image_path, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
Expand Down Expand Up @@ -1310,8 +1312,17 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
goto out;
}
} else {
hSourceImage = CreateFileAsync(image_path, GENERIC_READ, FILE_SHARE_READ,
OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN);
assert(img_report.compression_type != IMG_COMPRESSION_FFU);
// 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) {
uprintf("Could not open image '%s': %s", image_path, WindowsErrorString());
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_OPEN_FAILED;
Expand Down Expand Up @@ -1397,10 +1408,12 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, BOOL bZeroDrive)
RefreshDriveLayout(hPhysicalDrive);
ret = TRUE;
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);
else
CloseFileAsync(hSourceImage);
if (vhd_path != NULL)
VhdUnmountImage();
safe_mm_free(buffer);
safe_mm_free(cmp_buffer);
return ret;
Expand Down Expand Up @@ -1627,7 +1640,24 @@ DWORD WINAPI FormatThread(void* param)

// Write an image file
if ((boot_type == BT_IMAGE) && write_as_image) {
WriteDrive(hPhysicalDrive, FALSE);
// 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);
}
goto out;
}

Expand Down
6 changes: 5 additions & 1 deletion src/format.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Rufus: The Reliable USB Formatting Utility
* 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
* it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -111,6 +111,10 @@ typedef BOOLEAN (WINAPI* EnableVolumeCompression_t)(
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 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);
Expand Down
81 changes: 3 additions & 78 deletions src/iso.c
Original file line number Diff line number Diff line change
Expand Up @@ -1726,83 +1726,8 @@ BOOL DumpFatDir(const char* path, int32_t cluster)
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
static DWORD WINAPI SaveISOThread(void* param)
static DWORD WINAPI IsoSaveImageThread(void* param)
{
BOOL s;
DWORD rSize, wSize;
Expand Down Expand Up @@ -1908,7 +1833,7 @@ static DWORD WINAPI SaveISOThread(void* param)
ExitThread(0);
}

void SaveISO(void)
void IsoSaveImage(void)
{
static IMG_SAVE img_save = { 0 };
char filename[33] = "disc_image.iso";
Expand Down Expand Up @@ -1939,7 +1864,7 @@ void SaveISO(void)
// Disable all controls except cancel
EnableControls(FALSE, FALSE);
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) {
uprintf("\r\nSave to ISO operation started");
PrintInfo(0, -1);
Expand Down
14 changes: 10 additions & 4 deletions src/rufus.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 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 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;
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;
Expand Down Expand Up @@ -2588,8 +2588,11 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
img_provided = FALSE; // One off thing...
} else {
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...
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)));
image_path = FileDialog(FALSE, NULL, &img_ext, 0);
if (image_path == NULL) {
Expand Down Expand Up @@ -2684,7 +2687,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
}
break;
case IDC_SAVE:
SaveVHD();
VhdSaveImage();
break;
case IDM_SELECT:
case IDM_DOWNLOAD:
Expand Down Expand Up @@ -3695,6 +3698,9 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine
// Detect CPU acceleration for SHA-1/SHA-256
cpu_has_sha1_accel = DetectSHA1Acceleration();
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:
ubprintf("Localization set to '%s'", selected_locale->txt[0]);
Expand Down Expand Up @@ -3964,7 +3970,7 @@ extern int TestHashes(void);
}
// Alt-O => Save from Optical drive to ISO
if ((msg.message == WM_SYSKEYDOWN) && (msg.wParam == 'O')) {
SaveISO();
IsoSaveImage();
continue;
}
// Alt-P => Toggle GPT ESP to and from Basic Data type (Windows 10 or later)
Expand Down
2 changes: 0 additions & 2 deletions src/rufus.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 HasEfiImgBootLoaders(void);
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 uint16_t GetSyslinuxVersion(char* buf, size_t buf_size, char** ext);
extern BOOL SetAutorun(const char* path);
Expand Down
10 changes: 5 additions & 5 deletions src/rufus.rc
Original file line number Diff line number Diff line change
Expand Up @@ -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.2.2067"
CAPTION "Rufus 4.2.2068"
FONT 9, "Segoe UI Symbol", 400, 0, 0x0
BEGIN
LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP
Expand Down Expand Up @@ -392,8 +392,8 @@ END
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION 4,2,2067,0
PRODUCTVERSION 4,2,2067,0
FILEVERSION 4,2,2068,0
PRODUCTVERSION 4,2,2068,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
Expand All @@ -411,13 +411,13 @@ BEGIN
VALUE "Comments", "https://rufus.ie"
VALUE "CompanyName", "Akeo Consulting"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "4.2.2067"
VALUE "FileVersion", "4.2.2068"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "� 2011-2023 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html"
VALUE "OriginalFilename", "rufus-4.2.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "4.2.2067"
VALUE "ProductVersion", "4.2.2068"
END
END
BLOCK "VarFileInfo"
Expand Down
6 changes: 3 additions & 3 deletions src/stdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -1235,7 +1235,7 @@ uint32_t ResolveDllAddress(dll_resolver_t* resolver)
// Check settings to see if we have existing data for these DLL calls.
for (i = 0; i < resolver->count; i++) {
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);
if (resolver->address[i] == 0)
break;
Expand All @@ -1253,7 +1253,7 @@ uint32_t ResolveDllAddress(dll_resolver_t* resolver)
goto out;
static_sprintf(path, "%s\\%s", temp_dir, info->PdbName);
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)
goto out;

Expand All @@ -1280,7 +1280,7 @@ uint32_t ResolveDllAddress(dll_resolver_t* resolver)
r = 0;
for (i = 0; i < resolver->count; i++) {
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) {
WriteSetting32(saved_id, resolver->address[i]);
r++;
Expand Down
Loading

0 comments on commit 5bbcba8

Please sign in to comment.