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);
|
PrintStatus(0, FALSE, MSG_261, format_percent);
|
||||||
UpdateProgress(OP_FORMAT, format_percent);
|
UpdateProgress(OP_FORMAT, format_percent);
|
||||||
}
|
}
|
||||||
CHECK_FOR_USER_CANCEL;
|
|
||||||
// Don't overflow our projected size (mostly for VHDs)
|
// Don't overflow our projected size (mostly for VHDs)
|
||||||
if (wb + rSize > iso_report.projected_size) {
|
if (wb + rSize > iso_report.projected_size) {
|
||||||
rSize = (DWORD)(iso_report.projected_size - wb);
|
rSize = (DWORD)(iso_report.projected_size - wb);
|
||||||
}
|
}
|
||||||
for (i=0; i<WRITE_RETRIES; i++) {
|
for (i=0; i<WRITE_RETRIES; i++) {
|
||||||
|
CHECK_FOR_USER_CANCEL;
|
||||||
s = WriteFile(hPhysicalDrive, buffer, rSize, &wSize, NULL);
|
s = WriteFile(hPhysicalDrive, buffer, rSize, &wSize, NULL);
|
||||||
if ((s) && (wSize == rSize))
|
if ((s) && (wSize == rSize))
|
||||||
break;
|
break;
|
||||||
|
@ -1631,3 +1631,102 @@ out:
|
||||||
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
|
PostMessage(hMainDialog, UM_FORMAT_COMPLETED, 0, 0);
|
||||||
ExitThread(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);
|
||||||
|
}
|
||||||
|
|
126
src/rufus.c
126
src/rufus.c
|
@ -610,57 +610,58 @@ static BOOL PopulateProperties(int ComboIndex)
|
||||||
/*
|
/*
|
||||||
* Set up progress bar real estate allocation
|
* Set up progress bar real estate allocation
|
||||||
*/
|
*/
|
||||||
static void InitProgress(void)
|
static void InitProgress(BOOL bOnlyFormat)
|
||||||
{
|
{
|
||||||
int i, fs;
|
int i, fs;
|
||||||
float last_end = 0.0f, slots_discrete = 0.0f, slots_analog = 0.0f;
|
float last_end = 0.0f, slots_discrete = 0.0f, slots_analog = 0.0f;
|
||||||
|
|
||||||
fs = (int)ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem));
|
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(nb_slots, 0, sizeof(nb_slots));
|
||||||
memset(slot_end, 0, sizeof(slot_end));
|
memset(slot_end, 0, sizeof(slot_end));
|
||||||
previous_end = 0.0f;
|
previous_end = 0.0f;
|
||||||
|
|
||||||
nb_slots[OP_ANALYZE_MBR] = 1;
|
if (bOnlyFormat) {
|
||||||
if (IsChecked(IDC_BADBLOCKS)) {
|
|
||||||
nb_slots[OP_BADBLOCKS] = -1;
|
|
||||||
}
|
|
||||||
if (IsChecked(IDC_BOOT)) {
|
|
||||||
// 1 extra slot for PBR writing
|
|
||||||
switch (selection_default) {
|
|
||||||
case DT_WINME:
|
|
||||||
nb_slots[OP_DOS] = 3+1;
|
|
||||||
break;
|
|
||||||
case DT_FREEDOS:
|
|
||||||
nb_slots[OP_DOS] = 5+1;
|
|
||||||
break;
|
|
||||||
case DT_IMG:
|
|
||||||
nb_slots[OP_DOS] = 0;
|
|
||||||
break;
|
|
||||||
case DT_ISO:
|
|
||||||
nb_slots[OP_DOS] = -1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
nb_slots[OP_DOS] = 2+1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (selection_default == DT_IMG) {
|
|
||||||
nb_slots[OP_FORMAT] = -1;
|
nb_slots[OP_FORMAT] = -1;
|
||||||
} else {
|
} else {
|
||||||
nb_slots[OP_ZERO_MBR] = 1;
|
nb_slots[OP_ANALYZE_MBR] = 1;
|
||||||
nb_slots[OP_PARTITION] = 1;
|
if (IsChecked(IDC_BADBLOCKS)) {
|
||||||
nb_slots[OP_FIX_MBR] = 1;
|
nb_slots[OP_BADBLOCKS] = -1;
|
||||||
nb_slots[OP_CREATE_FS] =
|
}
|
||||||
nb_steps[ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))];
|
if (IsChecked(IDC_BOOT)) {
|
||||||
if ( (!IsChecked(IDC_QUICKFORMAT))
|
// 1 extra slot for PBR writing
|
||||||
|| ((fs == FS_FAT32) && ((SelectedDrive.DiskSize >= LARGE_FAT32_SIZE) || (force_large_fat32))) ) {
|
switch (selection_default) {
|
||||||
nb_slots[OP_FORMAT] = -1;
|
case DT_WINME:
|
||||||
|
nb_slots[OP_DOS] = 3+1;
|
||||||
|
break;
|
||||||
|
case DT_FREEDOS:
|
||||||
|
nb_slots[OP_DOS] = 5+1;
|
||||||
|
break;
|
||||||
|
case DT_IMG:
|
||||||
|
nb_slots[OP_DOS] = 0;
|
||||||
|
break;
|
||||||
|
case DT_ISO:
|
||||||
|
nb_slots[OP_DOS] = -1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
nb_slots[OP_DOS] = 2+1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selection_default == DT_IMG) {
|
||||||
|
nb_slots[OP_FORMAT] = -1;
|
||||||
|
} else {
|
||||||
|
nb_slots[OP_ZERO_MBR] = 1;
|
||||||
|
nb_slots[OP_PARTITION] = 1;
|
||||||
|
nb_slots[OP_FIX_MBR] = 1;
|
||||||
|
nb_slots[OP_CREATE_FS] =
|
||||||
|
nb_steps[ComboBox_GetItemData(hFileSystem, ComboBox_GetCurSel(hFileSystem))];
|
||||||
|
if ( (!IsChecked(IDC_QUICKFORMAT))
|
||||||
|
|| ((fs == FS_FAT32) && ((SelectedDrive.DiskSize >= LARGE_FAT32_SIZE) || (force_large_fat32))) ) {
|
||||||
|
nb_slots[OP_FORMAT] = -1;
|
||||||
|
}
|
||||||
|
nb_slots[OP_FINALIZE] = ((selection_default == DT_ISO) && (fs == FS_NTFS))?3:2;
|
||||||
}
|
}
|
||||||
nb_slots[OP_FINALIZE] = ((selection_default == DT_ISO) && (fs == FS_NTFS))?3:2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i=0; i<OP_MAX; i++) {
|
for (i=0; i<OP_MAX; i++) {
|
||||||
|
@ -1687,6 +1688,53 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
|
||||||
break;
|
break;
|
||||||
#ifdef RUFUS_TEST
|
#ifdef RUFUS_TEST
|
||||||
case IDC_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;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case IDC_LANG:
|
case IDC_LANG:
|
||||||
|
@ -1889,7 +1937,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA
|
||||||
EnableControls(FALSE);
|
EnableControls(FALSE);
|
||||||
DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex);
|
DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, nDeviceIndex);
|
||||||
FormatStatus = 0;
|
FormatStatus = 0;
|
||||||
InitProgress();
|
InitProgress(FALSE);
|
||||||
format_thid = CreateThread(NULL, 0, FormatThread, (LPVOID)(uintptr_t)DeviceNum, 0, NULL);
|
format_thid = CreateThread(NULL, 0, FormatThread, (LPVOID)(uintptr_t)DeviceNum, 0, NULL);
|
||||||
if (format_thid == NULL) {
|
if (format_thid == NULL) {
|
||||||
uprintf("Unable to start formatting thread");
|
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 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 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);
|
extern BOOL InstallSyslinux(DWORD drive_index, char drive_letter);
|
||||||
DWORD WINAPI FormatThread(void* param);
|
|
||||||
extern BOOL CreateProgress(void);
|
extern BOOL CreateProgress(void);
|
||||||
extern BOOL SetAutorun(const char* path);
|
extern BOOL SetAutorun(const char* path);
|
||||||
extern char* FileDialog(BOOL save, char* path, const ext_t* ext, DWORD options);
|
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 WimExtractCheck(void);
|
||||||
extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst);
|
extern BOOL WimExtractFile(const char* wim_image, int index, const char* src, const char* dst);
|
||||||
extern BOOL IsHDImage(const char* path);
|
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);
|
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) {
|
static __inline BOOL UnlockDrive(HANDLE hDrive) {
|
||||||
DWORD size;
|
DWORD size;
|
||||||
return DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &size, NULL);
|
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
|
IDD_DIALOG DIALOGEX 12, 12, 206, 329
|
||||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
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
|
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||||
BEGIN
|
BEGIN
|
||||||
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
|
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
|
||||||
|
@ -165,7 +165,7 @@ END
|
||||||
RTL_IDD_DIALOG DIALOGEX 12, 12, 206, 329
|
RTL_IDD_DIALOG DIALOGEX 12, 12, 206, 329
|
||||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
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
|
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
|
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||||
BEGIN
|
BEGIN
|
||||||
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
|
DEFPUSHBUTTON "Start",IDC_START,94,291,50,14
|
||||||
|
@ -427,8 +427,8 @@ END
|
||||||
//
|
//
|
||||||
|
|
||||||
VS_VERSION_INFO VERSIONINFO
|
VS_VERSION_INFO VERSIONINFO
|
||||||
FILEVERSION 1,4,8,483
|
FILEVERSION 1,4,8,484
|
||||||
PRODUCTVERSION 1,4,8,483
|
PRODUCTVERSION 1,4,8,484
|
||||||
FILEFLAGSMASK 0x3fL
|
FILEFLAGSMASK 0x3fL
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
FILEFLAGS 0x1L
|
FILEFLAGS 0x1L
|
||||||
|
@ -445,13 +445,13 @@ BEGIN
|
||||||
BEGIN
|
BEGIN
|
||||||
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
|
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
|
||||||
VALUE "FileDescription", "Rufus"
|
VALUE "FileDescription", "Rufus"
|
||||||
VALUE "FileVersion", "1.4.8.483"
|
VALUE "FileVersion", "1.4.8.484"
|
||||||
VALUE "InternalName", "Rufus"
|
VALUE "InternalName", "Rufus"
|
||||||
VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)"
|
VALUE "LegalCopyright", "© 2011-2014 Pete Batard (GPL v3)"
|
||||||
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
|
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
|
||||||
VALUE "OriginalFilename", "rufus.exe"
|
VALUE "OriginalFilename", "rufus.exe"
|
||||||
VALUE "ProductName", "Rufus"
|
VALUE "ProductName", "Rufus"
|
||||||
VALUE "ProductVersion", "1.4.8.483"
|
VALUE "ProductVersion", "1.4.8.484"
|
||||||
END
|
END
|
||||||
END
|
END
|
||||||
BLOCK "VarFileInfo"
|
BLOCK "VarFileInfo"
|
||||||
|
|
136
src/vhd.c
136
src/vhd.c
|
@ -20,6 +20,8 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
#include <rpc.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "rufus.h"
|
#include "rufus.h"
|
||||||
#include "msapi_utf8.h"
|
#include "msapi_utf8.h"
|
||||||
|
@ -38,15 +40,28 @@
|
||||||
|
|
||||||
#define VHD_FOOTER_COOKIE { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x' }
|
#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_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_FIXED_HARD_DISK 0x00000002
|
||||||
#define VHD_FOOTER_TYPE_DYNAMIC_HARD_DISK 0x00000003
|
#define VHD_FOOTER_TYPE_DYNAMIC_HARD_DISK 0x00000003
|
||||||
#define VHD_FOOTER_TYPE_DIFFER_HARD_DISK 0x00000004
|
#define VHD_FOOTER_TYPE_DIFFER_HARD_DISK 0x00000004
|
||||||
|
|
||||||
|
#define SECONDS_SINCE_JAN_1ST_2000 946684800
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VHD Fixed HD footer (Big Endian)
|
* 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
|
* 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)
|
#pragma pack(push, 1)
|
||||||
typedef struct vhd_footer {
|
typedef struct vhd_footer {
|
||||||
|
@ -55,12 +70,19 @@ typedef struct vhd_footer {
|
||||||
uint32_t file_format_version;
|
uint32_t file_format_version;
|
||||||
uint64_t data_offset;
|
uint64_t data_offset;
|
||||||
uint32_t timestamp;
|
uint32_t timestamp;
|
||||||
uint32_t creator_app;
|
char creator_app[4];
|
||||||
uint32_t creator_version;
|
uint32_t creator_version;
|
||||||
uint32_t creator_host_os;
|
char creator_host_os[4];
|
||||||
uint64_t original_size;
|
uint64_t original_size;
|
||||||
uint64_t current_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 disk_type;
|
||||||
uint32_t checksum;
|
uint32_t checksum;
|
||||||
uuid_t unique_id;
|
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, HANDLE, WIMLoadImage, (HANDLE, DWORD));
|
||||||
PF_TYPE_DECL(WINAPI, BOOL, WIMExtractImagePath, (HANDLE, PWSTR, PWSTR, DWORD));
|
PF_TYPE_DECL(WINAPI, BOOL, WIMExtractImagePath, (HANDLE, PWSTR, PWSTR, DWORD));
|
||||||
PF_TYPE_DECL(WINAPI, BOOL, WIMCloseHandle, (HANDLE));
|
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 BOOL has_wimgapi = FALSE, has_7z = FALSE;
|
||||||
static char sevenzip_path[MAX_PATH];
|
static char sevenzip_path[MAX_PATH];
|
||||||
|
static const char conectix_str[] = VHD_FOOTER_COOKIE;
|
||||||
|
|
||||||
static BOOL Get7ZipPath(void)
|
static BOOL Get7ZipPath(void)
|
||||||
{
|
{
|
||||||
|
@ -91,13 +115,109 @@ static BOOL Get7ZipPath(void)
|
||||||
return FALSE;
|
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)
|
BOOL IsHDImage(const char* path)
|
||||||
{
|
{
|
||||||
const char conectix_str[] = VHD_FOOTER_COOKIE;
|
|
||||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||||
LARGE_INTEGER liImageSize;
|
LARGE_INTEGER liImageSize;
|
||||||
vhd_footer* footer = NULL;
|
vhd_footer* footer = NULL;
|
||||||
DWORD size;
|
DWORD size;
|
||||||
|
size_t i;
|
||||||
|
uint32_t checksum, old_checksum;
|
||||||
LARGE_INTEGER ptr;
|
LARGE_INTEGER ptr;
|
||||||
|
|
||||||
handle = CreateFileU(path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
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;
|
iso_report.is_bootable_img = FALSE;
|
||||||
goto out;
|
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
|
// Need to remove the footer from our payload
|
||||||
uprintf("Image is a Fixed Hard Disk VHD file");
|
uprintf("Image is a Fixed Hard Disk VHD file");
|
||||||
iso_report.is_vhd = TRUE;
|
iso_report.is_vhd = TRUE;
|
||||||
|
|
Loading…
Reference in a new issue