[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:
Pete Batard 2014-05-23 01:03:01 +01:00
parent 1e121d2025
commit 04bd5116a7
5 changed files with 329 additions and 51 deletions

View file

@ -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);
}