diff --git a/src/format.c b/src/format.c index bdf04111..69d5d64b 100644 --- a/src/format.c +++ b/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 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) 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); +} diff --git a/src/rufus.c b/src/rufus.c index 1aa36574..3c7c9db8 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -610,57 +610,58 @@ 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; - nb_slots[OP_ANALYZE_MBR] = 1; - 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) { + if (bOnlyFormat) { 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_ANALYZE_MBR] = 1; + 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; + } 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 #include #include +#include +#include #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; ichecksum = 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