mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[vhd] add backup to uncompressed VHD image
* Part of #321 * NOTE: This feature will be enabled after the 1.4.8 release
This commit is contained in:
parent
1e121d2025
commit
04bd5116a7
5 changed files with 329 additions and 51 deletions
101
src/format.c
101
src/format.c
|
@ -1397,12 +1397,12 @@ DWORD WINAPI FormatThread(void* param)
|
|||
PrintStatus(0, FALSE, MSG_261, format_percent);
|
||||
UpdateProgress(OP_FORMAT, format_percent);
|
||||
}
|
||||
CHECK_FOR_USER_CANCEL;
|
||||
// Don't overflow our projected size (mostly for VHDs)
|
||||
if (wb + rSize > iso_report.projected_size) {
|
||||
rSize = (DWORD)(iso_report.projected_size - wb);
|
||||
}
|
||||
for (i=0; i<WRITE_RETRIES; i++) {
|
||||
CHECK_FOR_USER_CANCEL;
|
||||
s = WriteFile(hPhysicalDrive, buffer, rSize, &wSize, NULL);
|
||||
if ((s) && (wSize == rSize))
|
||||
break;
|
||||
|
@ -1631,3 +1631,102 @@ out:
|
|||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
|
||||
ExitThread(0);
|
||||
}
|
||||
|
||||
DWORD WINAPI SaveImageThread(void* param)
|
||||
{
|
||||
BOOL s;
|
||||
DWORD rSize, wSize, LastRefresh = 0, DriveIndex = (DWORD)(uintptr_t)param;
|
||||
HANDLE hPhysicalDrive = INVALID_HANDLE_VALUE;
|
||||
HANDLE hDestImage = INVALID_HANDLE_VALUE;
|
||||
LARGE_INTEGER li;
|
||||
uint8_t *buffer = NULL;
|
||||
uint64_t wb;
|
||||
int i;
|
||||
|
||||
PrintStatus(0, TRUE, MSG_225);
|
||||
hPhysicalDrive = GetPhysicalHandle(DriveIndex, FALSE, TRUE);
|
||||
if (hPhysicalDrive == INVALID_HANDLE_VALUE) {
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// Write an image file
|
||||
// We poked the MBR and other stuff, so we 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(image_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if (hDestImage == INVALID_HANDLE_VALUE) {
|
||||
uprintf("Could not open image '%s': %s", image_path, WindowsErrorString());
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED;
|
||||
goto out;
|
||||
}
|
||||
|
||||
uprintf("Saving to image '%s'...", image_path);
|
||||
buffer = (uint8_t*)malloc(DD_BUFFER_SIZE);
|
||||
if (buffer == NULL) {
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NOT_ENOUGH_MEMORY;
|
||||
uprintf("could not allocate buffer");
|
||||
goto out;
|
||||
}
|
||||
|
||||
// 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.
|
||||
for (wb = 0; ; wb += wSize) {
|
||||
s = ReadFile(hPhysicalDrive, buffer,
|
||||
(DWORD)MIN(DD_BUFFER_SIZE, SelectedDrive.DiskSize - 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;
|
||||
if (GetTickCount() > LastRefresh + 25) {
|
||||
LastRefresh = GetTickCount();
|
||||
format_percent = (100.0f*wb)/(1.0f*SelectedDrive.DiskSize);
|
||||
PrintStatus(0, FALSE, MSG_261, format_percent);
|
||||
UpdateProgress(OP_FORMAT, format_percent);
|
||||
}
|
||||
for (i=0; 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\n", wSize, rSize);
|
||||
else
|
||||
uprintf("write error: %s", WindowsErrorString());
|
||||
if (i < WRITE_RETRIES-1) {
|
||||
li.QuadPart = wb;
|
||||
SetFilePointerEx(hDestImage, li, NULL, FILE_BEGIN);
|
||||
uprintf(" RETRYING...\n");
|
||||
} else {
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (i >= WRITE_RETRIES) goto out;
|
||||
}
|
||||
if (wb != SelectedDrive.DiskSize) {
|
||||
uprintf("Error: wrote %llu bytes, expected %llu", wb, SelectedDrive.DiskSize);
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
||||
goto out;
|
||||
}
|
||||
uprintf("%llu bytes written", wb);
|
||||
uprintf("Appending VHD footer...");
|
||||
if (!AppendVHDFooter(image_path)) {
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT;
|
||||
goto out;
|
||||
}
|
||||
uprintf("Done");
|
||||
|
||||
out:
|
||||
safe_free(buffer);
|
||||
SendMessage(hISOProgressDlg, UM_PROGRESS_EXIT, 0, 0);
|
||||
safe_closehandle(hDestImage);
|
||||
safe_unlockclose(hPhysicalDrive);
|
||||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
|
||||
ExitThread(0);
|
||||
}
|
||||
|
|
58
src/rufus.c
58
src/rufus.c
|
@ -610,20 +610,20 @@ static BOOL PopulateProperties(int ComboIndex)
|
|||
/*
|
||||
* Set up progress bar real estate allocation
|
||||
*/
|
||||
static void InitProgress(void)
|
||||
static void InitProgress(BOOL bOnlyFormat)
|
||||
{
|
||||
int i, fs;
|
||||
float last_end = 0.0f, slots_discrete = 0.0f, slots_analog = 0.0f;
|
||||
|
||||
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
|
||||
memset(&nb_slots, 0, sizeof(nb_slots));
|
||||
memset(&slot_end, 0, sizeof(slot_end));
|
||||
previous_end = 0.0f;
|
||||
|
||||
memset(nb_slots, 0, sizeof(nb_slots));
|
||||
memset(slot_end, 0, sizeof(slot_end));
|
||||
previous_end = 0.0f;
|
||||
|
||||
if (bOnlyFormat) {
|
||||
nb_slots[OP_FORMAT] = -1;
|
||||
} else {
|
||||
nb_slots[OP_ANALYZE_MBR] = 1;
|
||||
if (IsChecked(IDC_BADBLOCKS)) {
|
||||
nb_slots[OP_BADBLOCKS] = -1;
|
||||
|
@ -662,6 +662,7 @@ static void InitProgress(void)
|
|||
}
|
||||
nb_slots[OP_FINALIZE] = ((selection_default == DT_ISO) && (fs == FS_NTFS))?3:2;
|
||||
}
|
||||
}
|
||||
|
||||
for (i=0; i<OP_MAX; i++) {
|
||||
if (nb_slots[i] > 0) {
|
||||
|
@ -1687,6 +1688,53 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
|
|||
break;
|
||||
#ifdef RUFUS_TEST
|
||||
case IDC_TEST:
|
||||
if (format_thid != NULL) {
|
||||
return (INT_PTR)TRUE;
|
||||
}
|
||||
FormatStatus = 0;
|
||||
format_op_in_progress = TRUE;
|
||||
// Reset all progress bars
|
||||
SendMessage(hProgress, PBM_SETSTATE, (WPARAM)PBST_NORMAL, 0);
|
||||
SetTaskbarProgressState(TASKBAR_NORMAL);
|
||||
SetTaskbarProgressValue(0, MAX_PROGRESS);
|
||||
SendMessage(hProgress, PBM_SETPOS, 0, 0);
|
||||
nDeviceIndex = ComboBox_GetCurSel(hDeviceList);
|
||||
if (nDeviceIndex != CB_ERR) {
|
||||
if ((IsChecked(IDC_BOOT)) && (!BootCheck())) {
|
||||
format_op_in_progress = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
GetWindowTextU(hDeviceList, tmp, ARRAYSIZE(tmp));
|
||||
if (MessageBoxU(hMainDialog, lmprintf(MSG_003, tmp),
|
||||
APPLICATION_NAME, MB_OKCANCEL|MB_ICONWARNING|MB_IS_RTL) == IDCANCEL) {
|
||||
format_op_in_progress = FALSE;
|
||||
break;
|
||||
}
|
||||
safe_free(image_path);
|
||||
image_path = strdup("C:\\Downloads\\my.vhd");
|
||||
|
||||
// Disable all controls except cancel
|
||||
EnableControls(FALSE);
|
||||
DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex);
|
||||
FormatStatus = 0;
|
||||
InitProgress(TRUE);
|
||||
format_thid = CreateThread(NULL, 0, SaveImageThread, (LPVOID)(uintptr_t)DeviceNum, 0, NULL);
|
||||
if (format_thid == NULL) {
|
||||
uprintf("Unable to start saving thread");
|
||||
FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_START_THREAD);
|
||||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
|
||||
}
|
||||
uprintf("\r\nSave to image operation started");
|
||||
PrintStatus(0, FALSE, -1);
|
||||
timer = 0;
|
||||
safe_sprintf(szTimer, sizeof(szTimer), "00:00:00");
|
||||
SendMessageA(GetDlgItem(hMainDialog, IDC_STATUS), SB_SETTEXTA,
|
||||
SBT_OWNERDRAW | 1, (LPARAM)szTimer);
|
||||
SetTimer(hMainDialog, TID_APP_TIMER, 1000, ClockTimer);
|
||||
}
|
||||
if (format_thid == NULL)
|
||||
format_op_in_progress = FALSE;
|
||||
break;
|
||||
#endif
|
||||
case IDC_LANG:
|
||||
|
@ -1889,7 +1937,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
|
|||
EnableControls(FALSE);
|
||||
DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex);
|
||||
FormatStatus = 0;
|
||||
InitProgress();
|
||||
InitProgress(FALSE);
|
||||
format_thid = CreateThread(NULL, 0, FormatThread, (LPVOID)(uintptr_t)DeviceNum, 0, NULL);
|
||||
if (format_thid == NULL) {
|
||||
uprintf("Unable to start formatting thread");
|
||||
|
|
|
@ -364,7 +364,6 @@ extern BOOL ExtractDOS(const char* path);
|
|||
extern BOOL ExtractISO(const char* src_iso, const char* dest_dir, BOOL scan);
|
||||
extern int64_t ExtractISOFile(const char* iso, const char* iso_file, const char* dest_file, DWORD attributes);
|
||||
extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter);
|
||||
DWORD WINAPI FormatThread(void* param);
|
||||
extern BOOL CreateProgress(void);
|
||||
extern BOOL SetAutorun(const char* path);
|
||||
extern char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options);
|
||||
|
@ -388,8 +387,12 @@ extern void parse_update(char* buf, size_t len);
|
|||
extern BOOL WimExtractCheck(void);
|
||||
extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst);
|
||||
extern BOOL IsHDImage(const char* path);
|
||||
extern BOOL AppendVHDFooter(const char* image_path);
|
||||
extern int IsHDD(DWORD DriveIndex, uint16_t vid, uint16_t pid, const char* strid);
|
||||
|
||||
DWORD WINAPI FormatThread(void* param);
|
||||
DWORD WINAPI SaveImageThread(void* param);
|
||||
|
||||
static __inline BOOL UnlockDrive(HANDLE hDrive) {
|
||||
DWORD size;
|
||||
return DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &size, NULL);
|
||||
|
|
12
src/rufus.rc
12
src/rufus.rc
|
@ -32,7 +32,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
|
|||
|
||||
IDD_DIALOG DIALOGEX 12, 12, 206, 329
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Rufus 1.4.8.483"
|
||||
CAPTION "Rufus 1.4.8.484"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
|
||||
|
@ -165,7 +165,7 @@ END
|
|||
RTL_IDD_DIALOG DIALOGEX 12, 12, 206, 329
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
EXSTYLE WS_EX_RTLREADING | WS_EX_APPWINDOW | WS_EX_LAYOUTRTL
|
||||
CAPTION "Rufus 1.4.8.483"
|
||||
CAPTION "Rufus 1.4.8.484"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
|
||||
|
@ -427,8 +427,8 @@ END
|
|||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,4,8,483
|
||||
PRODUCTVERSION 1,4,8,483
|
||||
FILEVERSION 1,4,8,484
|
||||
PRODUCTVERSION 1,4,8,484
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
@ -445,13 +445,13 @@ BEGIN
|
|||
BEGIN
|
||||
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
|
||||
VALUE "FileDescription", "Rufus"
|
||||
VALUE "FileVersion", "1.4.8.483"
|
||||
VALUE "FileVersion", "1.4.8.484"
|
||||
VALUE "InternalName", "Rufus"
|
||||
VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)"
|
||||
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
|
||||
VALUE "OriginalFilename", "rufus.exe"
|
||||
VALUE "ProductName", "Rufus"
|
||||
VALUE "ProductVersion", "1.4.8.483"
|
||||
VALUE "ProductVersion", "1.4.8.484"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
|
|
136
src/vhd.c
136
src/vhd.c
|
@ -20,6 +20,8 @@
|
|||
#include <windows.h>
|
||||
#include <stdlib.h>
|
||||
#include <io.h>
|
||||
#include <rpc.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "rufus.h"
|
||||
#include "msapi_utf8.h"
|
||||
|
@ -38,15 +40,28 @@
|
|||
|
||||
#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 SECONDS_SINCE_JAN_1ST_2000 946684800
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
|
@ -55,12 +70,19 @@ typedef struct vhd_footer {
|
|||
uint32_t file_format_version;
|
||||
uint64_t data_offset;
|
||||
uint32_t timestamp;
|
||||
uint32_t creator_app;
|
||||
char creator_app[4];
|
||||
uint32_t creator_version;
|
||||
uint32_t creator_host_os;
|
||||
char creator_host_os[4];
|
||||
uint64_t original_size;
|
||||
uint64_t current_size;
|
||||
uint32_t disk_geometry;
|
||||
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;
|
||||
|
@ -77,9 +99,11 @@ PF_TYPE_DECL(WINAPI, BOOL, WIMSetTemporaryPath, (HANDLE, PWSTR));
|
|||
PF_TYPE_DECL(WINAPI, HANDLE, WIMLoadImage, (HANDLE, DWORD));
|
||||
PF_TYPE_DECL(WINAPI, BOOL, WIMExtractImagePath, (HANDLE, PWSTR, PWSTR, DWORD));
|
||||
PF_TYPE_DECL(WINAPI, BOOL, WIMCloseHandle, (HANDLE));
|
||||
PF_TYPE_DECL(RPC_ENTRY, RPC_STATUS, UuidCreate, (UUID __RPC_FAR*));
|
||||
|
||||
static BOOL has_wimgapi = FALSE, has_7z = FALSE;
|
||||
static char sevenzip_path[MAX_PATH];
|
||||
static const char conectix_str[] = VHD_FOOTER_COOKIE;
|
||||
|
||||
static BOOL Get7ZipPath(void)
|
||||
{
|
||||
|
@ -91,13 +115,109 @@ static BOOL Get7ZipPath(void)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL AppendVHDFooter(const char* image_path)
|
||||
{
|
||||
const char creator_os[4] = VHD_FOOTER_CREATOR_HOST_OS_WINDOWS;
|
||||
const char creator_app[4] = { 'r', 'u', 'f', 'u' };
|
||||
BOOL r = FALSE;
|
||||
DWORD size;
|
||||
LARGE_INTEGER li;
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
vhd_footer* footer;
|
||||
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(image_path, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
|
||||
li.QuadPart = 0;
|
||||
if ((handle == INVALID_HANDLE_VALUE) || (!SetFilePointerEx(handle, li, &li, FILE_END))) {
|
||||
uprintf("Could not open image '%s': %s", image_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(_time32(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 (!WriteFile(handle, footer, sizeof(vhd_footer), &size, NULL) || (size != sizeof(vhd_footer))) {
|
||||
uprintf("Could not write VHD footer: %s", WindowsErrorString());
|
||||
goto out;
|
||||
}
|
||||
r = TRUE;
|
||||
|
||||
out:
|
||||
safe_free(footer);
|
||||
safe_closehandle(handle);
|
||||
return r;
|
||||
}
|
||||
|
||||
BOOL IsHDImage(const char* path)
|
||||
{
|
||||
const char conectix_str[] = VHD_FOOTER_COOKIE;
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
LARGE_INTEGER liImageSize;
|
||||
vhd_footer* footer = NULL;
|
||||
DWORD size;
|
||||
size_t i;
|
||||
uint32_t checksum, old_checksum;
|
||||
LARGE_INTEGER ptr;
|
||||
|
||||
handle = CreateFileU(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
@ -130,6 +250,14 @@ BOOL IsHDImage(const char* path)
|
|||
iso_report.is_bootable_img = FALSE;
|
||||
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");
|
||||
iso_report.is_vhd = TRUE;
|
||||
|
|
Loading…
Reference in a new issue