mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[vhd] enable saving device to compressed VHDX
* Now that we don't have to deal with Windows 7, we can use CreateVirtualDisk() to automatically dump a physical disk to VHD/VHDX, so do just that * Also move the relevant VHD/ISO imaging call to the appropriate source.
This commit is contained in:
parent
1476e9cd8b
commit
d4c9f2dfa1
12 changed files with 361 additions and 339 deletions
|
@ -3,3 +3,5 @@ EXPORTS
|
|||
GetVirtualDiskPhysicalPath@12
|
||||
DetachVirtualDisk@12
|
||||
OpenVirtualDisk@24
|
||||
CreateVirtualDisk@36
|
||||
GetVirtualDiskOperationProgress@12
|
||||
|
|
|
@ -603,6 +603,8 @@ t MSG_339 "Rufus detected that the ISO you have selected contains a UEFI bootloa
|
|||
"- If you obtained it from a trusted source, you should try to locate a more up to date version, that will not produce this warning."
|
||||
t MSG_340 "a \"Security Violation\" screen"
|
||||
t MSG_341 "a Windows Recovery Screen (BSOD) with '%s'"
|
||||
t MSG_342 "Compressed VHDX Image"
|
||||
t MSG_343 "Uncompressed VHD Image"
|
||||
# The following messages are for the Windows Store listing only and are not used by the application
|
||||
t MSG_900 "Rufus is a utility that helps format and create bootable USB flash drives, such as USB keys/pendrives, memory sticks, etc."
|
||||
t MSG_901 "Official site: %s"
|
||||
|
|
123
src/format.c
123
src/format.c
|
@ -1977,126 +1977,3 @@ out:
|
|||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)TRUE, 0);
|
||||
ExitThread(0);
|
||||
}
|
||||
|
||||
DWORD WINAPI SaveImageThread(void* param)
|
||||
{
|
||||
BOOL s;
|
||||
DWORD rSize, wSize;
|
||||
IMG_SAVE *img_save = (IMG_SAVE*)param;
|
||||
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
|
||||
HANDLE hDestImage = INVALID_HANDLE_VALUE;
|
||||
LARGE_INTEGER li;
|
||||
uint8_t *buffer = NULL;
|
||||
uint64_t wb;
|
||||
int i;
|
||||
|
||||
PrintInfoDebug(0, MSG_225);
|
||||
switch (img_save->Type) {
|
||||
case IMG_SAVE_TYPE_VHD:
|
||||
hPhysicalDrive = GetPhysicalHandle(img_save->DeviceNum, TRUE, FALSE, FALSE);
|
||||
break;
|
||||
case IMG_SAVE_TYPE_ISO:
|
||||
hPhysicalDrive = CreateFileA(img_save->DevicePath, GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||
break;
|
||||
default:
|
||||
uprintf("Invalid image type");
|
||||
}
|
||||
if (hPhysicalDrive == INVALID_HANDLE_VALUE) {
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Write an image file
|
||||
// We may have poked the MBR and other stuff, so 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(img_save->ImagePath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hDestImage == INVALID_HANDLE_VALUE) {
|
||||
uprintf("Could not open image '%s': %s", img_save->ImagePath, WindowsErrorString());
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buffer = (uint8_t*)_mm_malloc(img_save->BufSize, 16);
|
||||
if (buffer == NULL) {
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_ENOUGH_MEMORY;
|
||||
uprintf("could not allocate buffer");
|
||||
goto out;
|
||||
}
|
||||
|
||||
uprintf("Will use a buffer size of %s", SizeToHumanReadable(img_save->BufSize, FALSE, FALSE));
|
||||
uprintf("Saving to image '%s'...", img_save->ImagePath);
|
||||
|
||||
// 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.
|
||||
UpdateProgressWithInfoInit(NULL, FALSE);
|
||||
for (wb = 0; ; wb += wSize) {
|
||||
if (img_save->Type == IMG_SAVE_TYPE_ISO) {
|
||||
// Optical drives do not appear to increment the sectors to read automatically
|
||||
li.QuadPart = wb;
|
||||
if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN))
|
||||
uprintf("Warning: Unable to set device position - wrong data might be copied!");
|
||||
}
|
||||
s = ReadFile(hPhysicalDrive, buffer,
|
||||
(DWORD)MIN(img_save->BufSize, img_save->DeviceSize - 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;
|
||||
UpdateProgressWithInfo(OP_FORMAT, MSG_261, wb, img_save->DeviceSize);
|
||||
for (i = 1; 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", wSize, rSize);
|
||||
else
|
||||
uprintf("Write error: %s", WindowsErrorString());
|
||||
if (i < WRITE_RETRIES) {
|
||||
li.QuadPart = wb;
|
||||
uprintf("Retrying in %d seconds...", WRITE_TIMEOUT / 1000);
|
||||
Sleep(WRITE_TIMEOUT);
|
||||
if (!SetFilePointerEx(hDestImage, li, NULL, FILE_BEGIN)) {
|
||||
uprintf("Write error: Could not reset position - %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
||||
goto out;
|
||||
}
|
||||
Sleep(200);
|
||||
}
|
||||
if (i > WRITE_RETRIES)
|
||||
goto out;
|
||||
}
|
||||
if (wb != img_save->DeviceSize) {
|
||||
uprintf("Error: wrote %s, expected %s", SizeToHumanReadable(wb, FALSE, FALSE),
|
||||
SizeToHumanReadable(img_save->DeviceSize, FALSE, FALSE));
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
||||
goto out;
|
||||
}
|
||||
if (img_save->Type == IMG_SAVE_TYPE_VHD) {
|
||||
uprintf("Appending VHD footer...");
|
||||
if (!AppendVHDFooter(img_save->ImagePath)) {
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
uprintf("Operation complete (Wrote %s).", SizeToHumanReadable(wb, FALSE, FALSE));
|
||||
|
||||
out:
|
||||
safe_free(img_save->ImagePath);
|
||||
safe_mm_free(buffer);
|
||||
safe_closehandle(hDestImage);
|
||||
safe_unlockclose(hPhysicalDrive);
|
||||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)TRUE, 0);
|
||||
ExitThread(0);
|
||||
}
|
||||
|
|
156
src/iso.c
156
src/iso.c
|
@ -43,6 +43,8 @@
|
|||
#include <cdio/udf.h>
|
||||
|
||||
#include "rufus.h"
|
||||
#include "ui.h"
|
||||
#include "drive.h"
|
||||
#include "libfat.h"
|
||||
#include "missing.h"
|
||||
#include "resource.h"
|
||||
|
@ -82,6 +84,7 @@ RUFUS_IMG_REPORT img_report;
|
|||
int64_t iso_blocking_status = -1;
|
||||
extern BOOL preserve_timestamps, enable_ntfs_compression;
|
||||
extern char* archive_path;
|
||||
extern HANDLE format_thread;
|
||||
BOOL enable_iso = TRUE, enable_joliet = TRUE, enable_rockridge = TRUE, has_ldlinux_c32;
|
||||
#define ISO_BLOCKING(x) do {x; iso_blocking_status++; } while(0)
|
||||
static const char* psz_extract_dir;
|
||||
|
@ -1713,7 +1716,7 @@ static HANDLE mounted_handle = INVALID_HANDLE_VALUE;
|
|||
char* MountISO(const char* path)
|
||||
{
|
||||
VIRTUAL_STORAGE_TYPE vtype = { 1, VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT };
|
||||
ATTACH_VIRTUAL_DISK_PARAMETERS vparams = {0};
|
||||
ATTACH_VIRTUAL_DISK_PARAMETERS vparams = { 0 };
|
||||
DWORD r;
|
||||
wchar_t wtmp[128];
|
||||
ULONG size = ARRAYSIZE(wtmp);
|
||||
|
@ -1766,3 +1769,154 @@ void UnMountISO(void)
|
|||
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)
|
||||
{
|
||||
BOOL s;
|
||||
DWORD rSize, wSize;
|
||||
IMG_SAVE* img_save = (IMG_SAVE*)param;
|
||||
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
|
||||
HANDLE hDestImage = INVALID_HANDLE_VALUE;
|
||||
LARGE_INTEGER li;
|
||||
uint8_t* buffer = NULL;
|
||||
uint64_t wb;
|
||||
int i;
|
||||
|
||||
assert(img_save->Type == VIRTUAL_STORAGE_TYPE_DEVICE_ISO);
|
||||
|
||||
PrintInfoDebug(0, MSG_225);
|
||||
hPhysicalDrive = CreateFileA(img_save->DevicePath, GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
|
||||
if (hPhysicalDrive == INVALID_HANDLE_VALUE) {
|
||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_OPEN_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// In case someone poked the disc before us
|
||||
li.QuadPart = 0;
|
||||
if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN))
|
||||
uprintf("Warning: Unable to rewind device position - wrong data might be copied!");
|
||||
hDestImage = CreateFileU(img_save->ImagePath, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
|
||||
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hDestImage == INVALID_HANDLE_VALUE) {
|
||||
uprintf("Could not open image '%s': %s", img_save->ImagePath, WindowsErrorString());
|
||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_OPEN_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
buffer = (uint8_t*)_mm_malloc(img_save->BufSize, 16);
|
||||
if (buffer == NULL) {
|
||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_NOT_ENOUGH_MEMORY;
|
||||
uprintf("Could not allocate buffer");
|
||||
goto out;
|
||||
}
|
||||
|
||||
uprintf("Will use a buffer size of %s", SizeToHumanReadable(img_save->BufSize, FALSE, FALSE));
|
||||
uprintf("Saving to image '%s'...", img_save->ImagePath);
|
||||
|
||||
// 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.
|
||||
UpdateProgressWithInfoInit(NULL, FALSE);
|
||||
for (wb = 0; ; wb += wSize) {
|
||||
// Optical drives do not appear to increment the sectors to read automatically
|
||||
li.QuadPart = wb;
|
||||
if (!SetFilePointerEx(hPhysicalDrive, li, NULL, FILE_BEGIN))
|
||||
uprintf("Warning: Unable to set device position - wrong data might be copied!");
|
||||
s = ReadFile(hPhysicalDrive, buffer,
|
||||
(DWORD)MIN(img_save->BufSize, img_save->DeviceSize - 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;
|
||||
UpdateProgressWithInfo(OP_FORMAT, MSG_261, wb, img_save->DeviceSize);
|
||||
for (i = 1; 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", wSize, rSize);
|
||||
else
|
||||
uprintf("Write error: %s", WindowsErrorString());
|
||||
if (i < WRITE_RETRIES) {
|
||||
li.QuadPart = wb;
|
||||
uprintf("Retrying in %d seconds...", WRITE_TIMEOUT / 1000);
|
||||
Sleep(WRITE_TIMEOUT);
|
||||
if (!SetFilePointerEx(hDestImage, li, NULL, FILE_BEGIN)) {
|
||||
uprintf("Write error: Could not reset position - %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_WRITE_FAULT;
|
||||
goto out;
|
||||
}
|
||||
Sleep(200);
|
||||
}
|
||||
if (i > WRITE_RETRIES)
|
||||
goto out;
|
||||
}
|
||||
if (wb != img_save->DeviceSize) {
|
||||
uprintf("Error: wrote %s, expected %s", SizeToHumanReadable(wb, FALSE, FALSE),
|
||||
SizeToHumanReadable(img_save->DeviceSize, FALSE, FALSE));
|
||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_WRITE_FAULT;
|
||||
goto out;
|
||||
}
|
||||
uprintf("Operation complete (Wrote %s).", SizeToHumanReadable(wb, FALSE, FALSE));
|
||||
|
||||
out:
|
||||
safe_free(img_save->ImagePath);
|
||||
safe_mm_free(buffer);
|
||||
safe_closehandle(hDestImage);
|
||||
safe_unlockclose(hPhysicalDrive);
|
||||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)TRUE, 0);
|
||||
ExitThread(0);
|
||||
}
|
||||
|
||||
void SaveISO(void)
|
||||
{
|
||||
static IMG_SAVE img_save = { 0 };
|
||||
char filename[33] = "disc_image.iso";
|
||||
EXT_DECL(img_ext, filename, __VA_GROUP__("*.iso"), __VA_GROUP__(lmprintf(MSG_036)));
|
||||
|
||||
if (op_in_progress || (format_thread != NULL))
|
||||
return;
|
||||
|
||||
img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_ISO;
|
||||
if (!GetOpticalMedia(&img_save)) {
|
||||
uprintf("No dumpable optical media found.");
|
||||
return;
|
||||
}
|
||||
// Adjust the buffer size according to the disc size so that we get a decent speed.
|
||||
for (img_save.BufSize = 32 * MB;
|
||||
(img_save.BufSize > 8 * MB) && (img_save.DeviceSize <= img_save.BufSize * 64);
|
||||
img_save.BufSize /= 2);
|
||||
if ((img_save.Label != NULL) && (img_save.Label[0] != 0))
|
||||
static_sprintf(filename, "%s.iso", img_save.Label);
|
||||
|
||||
img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, 0);
|
||||
if (img_save.ImagePath == NULL)
|
||||
return;
|
||||
|
||||
uprintf("ISO media size %s", SizeToHumanReadable(img_save.DeviceSize, FALSE, FALSE));
|
||||
SendMessage(hMainDialog, UM_PROGRESS_INIT, 0, 0);
|
||||
FormatStatus = 0;
|
||||
// Disable all controls except cancel
|
||||
EnableControls(FALSE, FALSE);
|
||||
InitProgress(TRUE);
|
||||
format_thread = CreateThread(NULL, 0, SaveISOThread, &img_save, 0, NULL);
|
||||
if (format_thread != NULL) {
|
||||
uprintf("\r\nSave to ISO operation started");
|
||||
PrintInfo(0, -1);
|
||||
SendMessage(hMainDialog, UM_TIMER_START, 0, 0);
|
||||
} else {
|
||||
uprintf("Unable to start ISO save thread");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD);
|
||||
safe_free(img_save.ImagePath);
|
||||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -185,10 +185,6 @@ static __inline uint16_t remap16(uint16_t src, uint16_t* map, const BOOL reverse
|
|||
#define ERROR_OFFSET_ALIGNMENT_VIOLATION 327
|
||||
#endif
|
||||
|
||||
/* The following is used for native ISO mounting in Windows 8 or later */
|
||||
#define VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT \
|
||||
{ 0xEC984AECL, 0xA0F9, 0x47e9, { 0x90, 0x1F, 0x71, 0x41, 0x5A, 0x66, 0x34, 0x5B } }
|
||||
|
||||
/* RISC-V is still bleeding edge */
|
||||
#ifndef IMAGE_FILE_MACHINE_RISCV32
|
||||
#define IMAGE_FILE_MACHINE_RISCV32 0x5032
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <assert.h>
|
||||
#include <virtdisk.h>
|
||||
|
||||
#include "rufus.h"
|
||||
#include "missing.h"
|
||||
|
@ -1038,7 +1039,7 @@ static DWORD WINAPI DownloadISOThread(LPVOID param)
|
|||
#pragma warning(default: 6386)
|
||||
#endif
|
||||
EXT_DECL(img_ext, GetShortName(url), __VA_GROUP__("*.iso"), __VA_GROUP__(lmprintf(MSG_036)));
|
||||
img_save.Type = IMG_SAVE_TYPE_ISO;
|
||||
img_save.Type = VIRTUAL_STORAGE_TYPE_DEVICE_ISO;
|
||||
img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, 0);
|
||||
if (img_save.ImagePath == NULL) {
|
||||
goto out;
|
||||
|
|
104
src/rufus.c
104
src/rufus.c
|
@ -87,7 +87,6 @@ static int selected_pt = -1, selected_fs = FS_UNKNOWN, preselected_fs = FS_UNKNO
|
|||
static int image_index = 0, select_index = 0;
|
||||
static RECT relaunch_rc = { -65536, -65536, 0, 0};
|
||||
static UINT uMBRChecked = BST_UNCHECKED;
|
||||
static HANDLE format_thread = NULL;
|
||||
static HWND hSelectImage = NULL, hStart = NULL;
|
||||
static char szTimer[12] = "00:00:00";
|
||||
static unsigned int timer;
|
||||
|
@ -121,7 +120,7 @@ WORD selected_langid = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
|
|||
DWORD MainThreadId;
|
||||
HWND hDeviceList, hPartitionScheme, hTargetSystem, hFileSystem, hClusterSize, hLabel, hBootType, hNBPasses, hLog = NULL;
|
||||
HWND hImageOption, hLogDialog = NULL, hProgress = NULL, hDiskID;
|
||||
HANDLE dialog_handle = NULL;
|
||||
HANDLE dialog_handle = NULL, format_thread = NULL;
|
||||
BOOL is_x86_64, use_own_c32[NB_OLD_C32] = { FALSE, FALSE }, mbr_selected_by_user = FALSE, lock_drive = TRUE;
|
||||
BOOL op_in_progress = TRUE, right_to_left_mode = FALSE, has_uefi_csm = FALSE, its_a_me_mario = FALSE;
|
||||
BOOL enable_HDDs = FALSE, enable_VHDs = TRUE, enable_ntfs_compression = FALSE, no_confirmation_on_cancel = FALSE;
|
||||
|
@ -862,7 +861,7 @@ static void EnableBootOptions(BOOL enable, BOOL remove_checkboxes)
|
|||
}
|
||||
|
||||
// Toggle controls according to operation
|
||||
static void EnableControls(BOOL enable, BOOL remove_checkboxes)
|
||||
void EnableControls(BOOL enable, BOOL remove_checkboxes)
|
||||
{
|
||||
op_in_progress = !enable;
|
||||
|
||||
|
@ -2161,104 +2160,6 @@ static void PrintStatusTimeout(const char* str, BOOL val)
|
|||
PrintStatus(STATUS_MSG_TIMEOUT, (val)?MSG_250:MSG_251, str);
|
||||
}
|
||||
|
||||
static void SaveVHD(void)
|
||||
{
|
||||
static IMG_SAVE img_save = { 0 };
|
||||
char filename[128];
|
||||
char path[MAX_PATH];
|
||||
int DriveIndex = ComboBox_GetCurSel(hDeviceList);
|
||||
EXT_DECL(img_ext, filename, __VA_GROUP__("*.vhd"), __VA_GROUP__(lmprintf(MSG_095)));
|
||||
ULARGE_INTEGER free_space;
|
||||
|
||||
if ((DriveIndex < 0) || (format_thread != NULL))
|
||||
return;
|
||||
|
||||
static_sprintf(filename, "%s.vhd", rufus_drive[DriveIndex].label);
|
||||
img_save.Type = IMG_SAVE_TYPE_VHD;
|
||||
img_save.DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, DriveIndex);
|
||||
img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, 0);
|
||||
img_save.BufSize = DD_BUFFER_SIZE;
|
||||
img_save.DeviceSize = SelectedDrive.DiskSize;
|
||||
if (img_save.ImagePath != NULL) {
|
||||
// Reset all progress bars
|
||||
SendMessage(hMainDialog, UM_PROGRESS_INIT, 0, 0);
|
||||
FormatStatus = 0;
|
||||
free_space.QuadPart = 0;
|
||||
if ((GetVolumePathNameA(img_save.ImagePath, path, sizeof(path)))
|
||||
&& (GetDiskFreeSpaceExA(path, &free_space, NULL, NULL))
|
||||
&& ((LONGLONG)free_space.QuadPart > (SelectedDrive.DiskSize + 512))) {
|
||||
// Disable all controls except cancel
|
||||
EnableControls(FALSE, FALSE);
|
||||
FormatStatus = 0;
|
||||
InitProgress(TRUE);
|
||||
format_thread = CreateThread(NULL, 0, SaveImageThread, &img_save, 0, NULL);
|
||||
if (format_thread != NULL) {
|
||||
uprintf("\r\nSave to VHD operation started");
|
||||
PrintInfo(0, -1);
|
||||
SendMessage(hMainDialog, UM_TIMER_START, 0, 0);
|
||||
} else {
|
||||
uprintf("Unable to start VHD save thread");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD);
|
||||
safe_free(img_save.ImagePath);
|
||||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
|
||||
}
|
||||
} else {
|
||||
if (free_space.QuadPart == 0) {
|
||||
uprintf("Unable to isolate drive name for VHD save");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_PATH_NOT_FOUND;
|
||||
} else {
|
||||
uprintf("The VHD size is too large for the target drive");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_FILE_TOO_LARGE;
|
||||
}
|
||||
safe_free(img_save.ImagePath);
|
||||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void SaveISO(void)
|
||||
{
|
||||
static IMG_SAVE img_save = { 0 };
|
||||
char filename[33] = "disc_image.iso";
|
||||
EXT_DECL(img_ext, filename, __VA_GROUP__("*.iso"), __VA_GROUP__(lmprintf(MSG_036)));
|
||||
|
||||
if (op_in_progress || (format_thread != NULL))
|
||||
return;
|
||||
|
||||
img_save.Type = IMG_SAVE_TYPE_ISO;
|
||||
if (!GetOpticalMedia(&img_save)) {
|
||||
uprintf("No dumpable optical media found.");
|
||||
return;
|
||||
}
|
||||
// Adjust the buffer size according to the disc size so that we get a decent speed.
|
||||
for (img_save.BufSize = 32 * MB;
|
||||
(img_save.BufSize > 8 * MB) && (img_save.DeviceSize <= img_save.BufSize * 64);
|
||||
img_save.BufSize /= 2);
|
||||
if ((img_save.Label != NULL) && (img_save.Label[0] != 0))
|
||||
static_sprintf(filename, "%s.iso", img_save.Label);
|
||||
uprintf("ISO media size %s", SizeToHumanReadable(img_save.DeviceSize, FALSE, FALSE));
|
||||
|
||||
img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, 0);
|
||||
if (img_save.ImagePath == NULL)
|
||||
return;
|
||||
SendMessage(hMainDialog, UM_PROGRESS_INIT, 0, 0);
|
||||
FormatStatus = 0;
|
||||
// Disable all controls except cancel
|
||||
EnableControls(FALSE, FALSE);
|
||||
InitProgress(TRUE);
|
||||
format_thread = CreateThread(NULL, 0, SaveImageThread, &img_save, 0, NULL);
|
||||
if (format_thread != NULL) {
|
||||
uprintf("\r\nSave to ISO operation started");
|
||||
PrintInfo(0, -1);
|
||||
SendMessage(hMainDialog, UM_TIMER_START, 0, 0);
|
||||
} else {
|
||||
uprintf("Unable to start ISO save thread");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD);
|
||||
safe_free(img_save.ImagePath);
|
||||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for conflicting processes accessing the drive.
|
||||
// If bPrompt is true, ask the user whether they want to proceed.
|
||||
// dwTimeOut is the maximum amount of time we allow for this call to execute (in ms)
|
||||
|
@ -2764,6 +2665,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
|
|||
MyDialogBox(hMainInstance, IDD_UPDATE_POLICY, hDlg, UpdateCallback);
|
||||
break;
|
||||
case IDC_HASH:
|
||||
// TODO: Move this as a fn call in hash.c?
|
||||
if ((format_thread == NULL) && (image_path != NULL)) {
|
||||
FormatStatus = 0;
|
||||
no_confirmation_on_cancel = TRUE;
|
||||
|
|
|
@ -71,6 +71,7 @@
|
|||
#define PATCH_PROGRESS_TOTAL 207
|
||||
#define MAX_LOG_SIZE 0x7FFFFFFE
|
||||
#define MAX_REFRESH 25 // How long we should wait to refresh UI elements (in ms)
|
||||
#define MARQUEE_TIMER_REFRESH 10 // Time between progress bar marquee refreshes, in ms
|
||||
#define MAX_GUID_STRING_LENGTH 40
|
||||
#define MAX_PARTITIONS 16 // Maximum number of partitions we handle
|
||||
#define MAX_ESP_TOGGLE 8 // Maximum number of entries we record to toggle GPT ESP back and forth
|
||||
|
@ -88,7 +89,6 @@
|
|||
#define WRITE_TIMEOUT 5000 // How long we should wait between write retries (in ms)
|
||||
#define SEARCH_PROCESS_TIMEOUT 10000 // How long we should search for conflicting processes before giving up (in ms)
|
||||
#define NET_SESSION_TIMEOUT 3500 // How long we should wait to connect, send or receive internet data
|
||||
#define MARQUEE_TIMER_REFRESH 10 // Time between progress bar marquee refreshes, in ms
|
||||
#define FS_DEFAULT FS_FAT32
|
||||
#define SINGLE_CLUSTERSIZE_DEFAULT 0x00000100
|
||||
#define BADLOCKS_PATTERN_TYPES 5
|
||||
|
@ -433,9 +433,6 @@ typedef struct {
|
|||
char* release_notes;
|
||||
} RUFUS_UPDATE;
|
||||
|
||||
#define IMG_SAVE_TYPE_VHD 1
|
||||
#define IMG_SAVE_TYPE_ISO 2
|
||||
|
||||
typedef struct {
|
||||
DWORD Type;
|
||||
DWORD DeviceNum;
|
||||
|
@ -726,7 +723,6 @@ extern HANDLE CreatePreallocatedFile(const char* lpFileName, DWORD dwDesiredAcce
|
|||
DWORD dwFlagsAndAttributes, LONGLONG fileSize);
|
||||
#define GetTextWidth(hDlg, id) GetTextSize(GetDlgItem(hDlg, id), NULL).cx
|
||||
|
||||
DWORD WINAPI SaveImageThread(void* param);
|
||||
DWORD WINAPI HashThread(void* param);
|
||||
|
||||
/* Hash tables */
|
||||
|
|
10
src/rufus.rc
10
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.2.2059"
|
||||
CAPTION "Rufus 4.2.2060"
|
||||
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,2,2059,0
|
||||
PRODUCTVERSION 4,2,2059,0
|
||||
FILEVERSION 4,2,2060,0
|
||||
PRODUCTVERSION 4,2,2060,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.2.2059"
|
||||
VALUE "FileVersion", "4.2.2060"
|
||||
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.2059"
|
||||
VALUE "ProductVersion", "4.2.2060"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
2
src/ui.h
2
src/ui.h
|
@ -20,6 +20,7 @@
|
|||
#include <windows.h>
|
||||
#include <stdint.h>
|
||||
#include "resource.h"
|
||||
#include "localization.h"
|
||||
|
||||
#pragma once
|
||||
|
||||
|
@ -99,6 +100,7 @@ extern void ToggleAdvancedFormatOptions(BOOL enable);
|
|||
extern void ToggleImageOptions(void);
|
||||
extern void CreateSmallButtons(HWND hDlg);
|
||||
extern void CreateAdditionalControls(HWND hDlg);
|
||||
extern void EnableControls(BOOL enable, BOOL remove_checkboxes);
|
||||
extern void InitProgress(BOOL bOnlyFormat);
|
||||
extern void ShowLanguageMenu(RECT rcExclude);
|
||||
extern void SetPassesTooltip(void);
|
||||
|
|
241
src/vhd.c
241
src/vhd.c
|
@ -18,13 +18,15 @@
|
|||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <stdlib.h>
|
||||
#include <io.h>
|
||||
#include <rpc.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "vhd.h"
|
||||
#include "rufus.h"
|
||||
#include "ui.h"
|
||||
#include "vhd.h"
|
||||
#include "missing.h"
|
||||
#include "resource.h"
|
||||
#include "msapi_utf8.h"
|
||||
|
@ -45,7 +47,6 @@ PF_TYPE_DECL(WINAPI, BOOL, WIMGetImageInformation, (HANDLE, PVOID, PDWORD));
|
|||
PF_TYPE_DECL(WINAPI, BOOL, WIMCloseHandle, (HANDLE));
|
||||
PF_TYPE_DECL(WINAPI, DWORD, WIMRegisterMessageCallback, (HANDLE, FARPROC, PVOID));
|
||||
PF_TYPE_DECL(WINAPI, DWORD, WIMUnregisterMessageCallback, (HANDLE, FARPROC));
|
||||
PF_TYPE_DECL(RPC_ENTRY, RPC_STATUS, UuidCreate, (UUID __RPC_FAR*));
|
||||
|
||||
typedef struct {
|
||||
int index;
|
||||
|
@ -58,6 +59,8 @@ uint32_t wim_nb_files, wim_proc_files, wim_extra_files;
|
|||
HANDLE wim_thread = NULL;
|
||||
extern int default_thread_priority;
|
||||
extern BOOL ignore_boot_marker;
|
||||
extern RUFUS_DRIVE rufus_drive[MAX_DRIVES];
|
||||
extern HANDLE format_thread;
|
||||
|
||||
static uint8_t wim_flags = 0;
|
||||
static uint32_t progress_report_mask;
|
||||
|
@ -78,102 +81,6 @@ static BOOL Get7ZipPath(void)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL AppendVHDFooter(const char* vhd_path)
|
||||
{
|
||||
const char creator_os[4] = VHD_FOOTER_CREATOR_HOST_OS_WINDOWS;
|
||||
const char creator_app[4] = { 'r', 'u', 'f', 's' };
|
||||
BOOL r = FALSE;
|
||||
DWORD size;
|
||||
LARGE_INTEGER li;
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
vhd_footer* footer = NULL;
|
||||
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(vhd_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
li.QuadPart = 0;
|
||||
if ((handle == INVALID_HANDLE_VALUE) || (!SetFilePointerEx(handle, li, &li, FILE_END))) {
|
||||
uprintf("Could not open image '%s': %s", vhd_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((uint32_t)(_time64(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 (!WriteFileWithRetry(handle, footer, sizeof(vhd_footer), &size, WRITE_RETRIES)) {
|
||||
uprintf("Could not write VHD footer: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
r = TRUE;
|
||||
|
||||
out:
|
||||
safe_free(footer);
|
||||
safe_closehandle(handle);
|
||||
return r;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
const char* ext;
|
||||
bled_compression_type type;
|
||||
|
@ -977,3 +884,141 @@ BOOL WimApplyImage(const char* image, int index, const char* dst)
|
|||
wim_thread = NULL;
|
||||
return dw;
|
||||
}
|
||||
|
||||
// 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
|
||||
// ISO from optical media that would be swell, but no matter what I tried, it didn't
|
||||
// seem possible...
|
||||
static DWORD WINAPI SaveImageThread(void* param)
|
||||
{
|
||||
IMG_SAVE* img_save = (IMG_SAVE*)param;
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
WCHAR* wDst = utf8_to_wchar(img_save->ImagePath);
|
||||
WCHAR* wSrc = utf8_to_wchar(GetPhysicalName(img_save->DeviceNum));
|
||||
VIRTUAL_STORAGE_TYPE vtype = { img_save->Type, VIRTUAL_STORAGE_TYPE_VENDOR_MICROSOFT };
|
||||
STOPGAP_CREATE_VIRTUAL_DISK_PARAMETERS vparams = { 0 };
|
||||
VIRTUAL_DISK_PROGRESS vprogress = { 0 };
|
||||
OVERLAPPED overlapped = { 0 };
|
||||
DWORD result, flags;
|
||||
|
||||
assert(img_save->Type == VIRTUAL_STORAGE_TYPE_DEVICE_VHD ||
|
||||
img_save->Type == VIRTUAL_STORAGE_TYPE_DEVICE_VHDX);
|
||||
|
||||
UpdateProgressWithInfoInit(NULL, FALSE);
|
||||
|
||||
vparams.Version = CREATE_VIRTUAL_DISK_VERSION_2;
|
||||
vparams.Version2.UniqueId = GUID_NULL;
|
||||
vparams.Version2.BlockSizeInBytes = CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_BLOCK_SIZE;
|
||||
vparams.Version2.SectorSizeInBytes = CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_SECTOR_SIZE;
|
||||
vparams.Version2.PhysicalSectorSizeInBytes = SelectedDrive.SectorSize;
|
||||
vparams.Version2.SourcePath = wSrc;
|
||||
|
||||
// When CREATE_VIRTUAL_DISK_FLAG_CREATE_BACKING_STORAGE is specified with
|
||||
// a source path, CreateVirtualDisk() automatically clones the source to
|
||||
// the virtual disk.
|
||||
flags = CREATE_VIRTUAL_DISK_FLAG_CREATE_BACKING_STORAGE;
|
||||
// The following ensures that VHD images are stored uncompressed and can
|
||||
// be used as DD images.
|
||||
if (img_save->Type != VIRTUAL_STORAGE_TYPE_DEVICE_VHDX)
|
||||
flags |= CREATE_VIRTUAL_DISK_FLAG_FULL_PHYSICAL_ALLOCATION;
|
||||
// TODO: Use CREATE_VIRTUAL_DISK_FLAG_PREVENT_WRITES_TO_SOURCE_DISK?
|
||||
|
||||
overlapped.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
// CreateVirtualDisk() does not have an overwrite flag...
|
||||
DeleteFileW(wDst);
|
||||
|
||||
result = CreateVirtualDisk(&vtype, wDst, VIRTUAL_DISK_ACCESS_NONE, NULL,
|
||||
flags, 0, (PCREATE_VIRTUAL_DISK_PARAMETERS)&vparams, &overlapped, &handle);
|
||||
if (result != ERROR_SUCCESS && result != ERROR_IO_PENDING) {
|
||||
SetLastError(result);
|
||||
uprintf("Could not create virtual disk: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (result == ERROR_IO_PENDING) {
|
||||
while ((result = WaitForSingleObject(overlapped.hEvent, 100)) == WAIT_TIMEOUT) {
|
||||
if (IS_ERROR(FormatStatus) && (SCODE_CODE(FormatStatus) == ERROR_CANCELLED)) {
|
||||
CancelIoEx(handle, &overlapped);
|
||||
goto out;
|
||||
}
|
||||
if (GetVirtualDiskOperationProgress(handle, &overlapped, &vprogress) == ERROR_SUCCESS) {
|
||||
if (vprogress.OperationStatus == ERROR_IO_PENDING)
|
||||
UpdateProgressWithInfo(OP_FORMAT, MSG_261, vprogress.CurrentValue, vprogress.CompletionValue);
|
||||
}
|
||||
}
|
||||
if (result != WAIT_OBJECT_0) {
|
||||
uprintf("Could not save virtual disk: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
UpdateProgressWithInfo(OP_FORMAT, MSG_261, SelectedDrive.DiskSize, SelectedDrive.DiskSize);
|
||||
uprintf("Operation complete.");
|
||||
|
||||
out:
|
||||
safe_closehandle(handle);
|
||||
safe_closehandle(overlapped.hEvent);
|
||||
safe_free(wDst);
|
||||
safe_free(wSrc);
|
||||
safe_free(img_save->ImagePath);
|
||||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)TRUE, 0);
|
||||
ExitThread(0);
|
||||
}
|
||||
|
||||
void SaveVHD(void)
|
||||
{
|
||||
static IMG_SAVE img_save = { 0 };
|
||||
char filename[128];
|
||||
char path[MAX_PATH];
|
||||
int DriveIndex = ComboBox_GetCurSel(hDeviceList);
|
||||
EXT_DECL(img_ext, filename, __VA_GROUP__("*.vhdx", "*.vhd"), __VA_GROUP__(lmprintf(MSG_342), lmprintf(MSG_343)));
|
||||
ULARGE_INTEGER free_space;
|
||||
|
||||
if ((DriveIndex < 0) || (format_thread != NULL))
|
||||
return;
|
||||
|
||||
static_sprintf(filename, "%s.vhdx", rufus_drive[DriveIndex].label);
|
||||
img_save.DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, DriveIndex);
|
||||
img_save.ImagePath = FileDialog(TRUE, NULL, &img_ext, 0);
|
||||
img_save.Type = safe_strstr(img_save.ImagePath, ".vhdx") != NULL ?
|
||||
VIRTUAL_STORAGE_TYPE_DEVICE_VHDX : VIRTUAL_STORAGE_TYPE_DEVICE_VHD;
|
||||
img_save.BufSize = DD_BUFFER_SIZE;
|
||||
img_save.DeviceSize = SelectedDrive.DiskSize;
|
||||
if (img_save.ImagePath != NULL) {
|
||||
// Reset all progress bars
|
||||
SendMessage(hMainDialog, UM_PROGRESS_INIT, 0, 0);
|
||||
FormatStatus = 0;
|
||||
free_space.QuadPart = 0;
|
||||
if ((GetVolumePathNameA(img_save.ImagePath, path, sizeof(path)))
|
||||
&& (GetDiskFreeSpaceExA(path, &free_space, NULL, NULL))
|
||||
&& ((LONGLONG)free_space.QuadPart > (SelectedDrive.DiskSize + 512))) {
|
||||
// Disable all controls except cancel
|
||||
EnableControls(FALSE, FALSE);
|
||||
FormatStatus = 0;
|
||||
InitProgress(TRUE);
|
||||
format_thread = CreateThread(NULL, 0, SaveImageThread, &img_save, 0, NULL);
|
||||
if (format_thread != NULL) {
|
||||
uprintf("\r\nSave to VHD operation started");
|
||||
PrintInfo(0, -1);
|
||||
SendMessage(hMainDialog, UM_TIMER_START, 0, 0);
|
||||
} else {
|
||||
uprintf("Unable to start VHD save thread");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | APPERR(ERROR_CANT_START_THREAD);
|
||||
safe_free(img_save.ImagePath);
|
||||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
|
||||
}
|
||||
} else {
|
||||
if (free_space.QuadPart == 0) {
|
||||
uprintf("Unable to isolate drive name for VHD save");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_PATH_NOT_FOUND;
|
||||
} else {
|
||||
// TODO: Might be salvageable for compressed VHDX
|
||||
uprintf("The VHD size is too large for the target drive");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_FILE_TOO_LARGE;
|
||||
}
|
||||
safe_free(img_save.ImagePath);
|
||||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, (WPARAM)FALSE, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
47
src/vhd.h
47
src/vhd.h
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
#include <virtdisk.h>
|
||||
|
||||
#pragma once
|
||||
|
||||
|
@ -70,6 +71,49 @@
|
|||
|
||||
#define MBR_SIZE 512 // Might need to review this once we see bootable 4k systems
|
||||
|
||||
// TODO: Remove this once MinGW has been updated
|
||||
#define VIRTUAL_STORAGE_TYPE_DEVICE_VHDX 3
|
||||
#define CREATE_VIRTUAL_DISK_VERSION_2 2
|
||||
#define CREATE_VIRTUAL_DISK_FLAG_CREATE_BACKING_STORAGE 8
|
||||
|
||||
#ifndef CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_BLOCK_SIZE
|
||||
#define CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_BLOCK_SIZE 0
|
||||
#endif
|
||||
|
||||
#ifndef CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_SECTOR_SIZE
|
||||
#define CREATE_VIRTUAL_DISK_PARAMETERS_DEFAULT_SECTOR_SIZE 0
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CREATE_VIRTUAL_DISK_VERSION Version;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
GUID UniqueId;
|
||||
ULONGLONG MaximumSize;
|
||||
ULONG BlockSizeInBytes;
|
||||
ULONG SectorSizeInBytes;
|
||||
PCWSTR ParentPath;
|
||||
PCWSTR SourcePath;
|
||||
} Version1;
|
||||
struct
|
||||
{
|
||||
GUID UniqueId;
|
||||
ULONGLONG MaximumSize;
|
||||
ULONG BlockSizeInBytes;
|
||||
ULONG SectorSizeInBytes;
|
||||
ULONG PhysicalSectorSizeInBytes;
|
||||
PCWSTR ParentPath;
|
||||
PCWSTR SourcePath;
|
||||
OPEN_VIRTUAL_DISK_FLAG OpenFlags;
|
||||
VIRTUAL_STORAGE_TYPE ParentVirtualStorageType;
|
||||
VIRTUAL_STORAGE_TYPE SourceVirtualStorageType;
|
||||
GUID ResiliencyGuid;
|
||||
} Version2;
|
||||
};
|
||||
} STOPGAP_CREATE_VIRTUAL_DISK_PARAMETERS;
|
||||
|
||||
// From https://docs.microsoft.com/en-us/previous-versions/msdn10/dd834960(v=msdn.10)
|
||||
// as well as https://msfn.org/board/topic/150700-wimgapi-wimmountimage-progressbar/
|
||||
|
@ -139,4 +183,5 @@ extern BOOL WimUnmountImage(const char* image, int index, BOOL commit);
|
|||
extern char* GetExistingMountPoint(const char* image, int index);
|
||||
extern BOOL WimIsValidIndex(const char* image, int index);
|
||||
extern int8_t IsBootableImage(const char* path);
|
||||
extern BOOL AppendVHDFooter(const char* vhd_path);
|
||||
extern void SaveVHD(void);
|
||||
extern void SaveISO(void);
|
||||
|
|
Loading…
Reference in a new issue