From ca1dc895da48794467a8aa92f85d383be3fc6d42 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Thu, 12 Oct 2017 16:07:44 +0100 Subject: [PATCH 01/20] Add format.h to vcxproj This header is included by format.c so it's relevant to our interests. --- src/endless/EndlessUsbTool.vcxproj | 1 + src/endless/EndlessUsbTool.vcxproj.filters | 3 +++ 2 files changed, 4 insertions(+) diff --git a/src/endless/EndlessUsbTool.vcxproj b/src/endless/EndlessUsbTool.vcxproj index be80e0fd012..e692514f5f2 100644 --- a/src/endless/EndlessUsbTool.vcxproj +++ b/src/endless/EndlessUsbTool.vcxproj @@ -271,6 +271,7 @@ + diff --git a/src/endless/EndlessUsbTool.vcxproj.filters b/src/endless/EndlessUsbTool.vcxproj.filters index ca181979f9f..bb287e110a4 100644 --- a/src/endless/EndlessUsbTool.vcxproj.filters +++ b/src/endless/EndlessUsbTool.vcxproj.filters @@ -90,6 +90,9 @@ Header Files\Rufus Headers + + Header Files\Rufus Headers + Header Files From d900fed13fe35a3a88e14634055407e48a06ff58 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 Oct 2017 16:31:37 +0100 Subject: [PATCH 02/20] Fully fork FormatDrive() If you peer through the #ifdef soup, this is all there is to it. We will make further changes so that it accepts a path rather than formatting the first basic data partition on the drive, so best make a clean break. Rather annoyingly, FormatEx accepts non-const strings as parameters. Fine: we can copy them. (In practice Rufus itself passes literals for these two parameters at one call site so it would probably be okay to just cast away the const.) --- src/endless/EndlessUsbToolDlg.cpp | 25 +++++++----- src/endless/EndlessUsbToolDlg.h | 2 +- src/format.c | 64 +++++++++++++++++++------------ src/rufus.h | 2 + 4 files changed, 59 insertions(+), 34 deletions(-) diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index 0275da4c474..ba0a34eb440 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -80,8 +80,6 @@ PF_TYPE_DECL(WINAPI, BOOL, SHChangeNotifyDeregister, (ULONG)); PF_TYPE_DECL(WINAPI, ULONG, SHChangeNotifyRegister, (HWND, int, LONG, UINT, int, const SHChangeNotifyEntry *)); PF_TYPE_DECL(WINAPI, BOOL, ChangeWindowMessageFilterEx, (HWND, UINT, DWORD, PCHANGEFILTERSTRUCT)); -BOOL FormatDrive(DWORD DriveIndex, int fsToUse, const wchar_t *partLabel); - // Added by us so we don't go through the hastle of getting device speed again // Rufus code already does it DWORD usbDeviceSpeed[128]; @@ -4048,6 +4046,9 @@ const GUID PARTITION_BIOS_BOOT_GUID = #define EXFAT_PARTITION_NAME_IMAGES L"eosimages" #define EXFAT_PARTITION_NAME_LIVE L"eoslive" +#define EXFAT_CLUSTER_SIZE 0x8000 +#define ESP_CLUSTER_SIZE 0x200 + // Used in ReformatterUsb mode, after the eosinstaller image has been written // to the target device. Appends an exFAT partition (renumbered to be logically // first) and copies the OS image, signature, and language preset across. @@ -4117,7 +4118,7 @@ DWORD WINAPI CEndlessUsbToolDlg::FileCopyThread(void* param) // Check if user cancelled IFFALSE_GOTOERROR(WaitForSingleObject(dlg->m_cancelOperationEvent, 0) == WAIT_TIMEOUT, "User cancel."); // Format the partition - IFFALSE_GOTOERROR(FormatFirstPartitionOnDrive(DriveIndex, FS_EXFAT, dlg->m_cancelOperationEvent, EXFAT_PARTITION_NAME_IMAGES), "Error on FormatFirstPartitionOnDrive"); + IFFALSE_GOTOERROR(FormatFirstPartitionOnDrive(DriveIndex, L"exFAT", EXFAT_CLUSTER_SIZE, dlg->m_cancelOperationEvent, EXFAT_PARTITION_NAME_IMAGES), "Error on FormatFirstPartitionOnDrive"); // Mount it IFFALSE_GOTOERROR(MountFirstPartitionOnDrive(DriveIndex, driveDestination), "Error on MountFirstPartitionOnDrive"); @@ -4746,7 +4747,7 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) CHECK_IF_CANCELLED; // Format and mount ESP - IFFALSE_GOTOERROR(FormatFirstPartitionOnDrive(DriveIndex, FS_FAT32, dlg->m_cancelOperationEvent, L""), "Error on FormatFirstPartitionOnDrive"); + IFFALSE_GOTOERROR(FormatFirstPartitionOnDrive(DriveIndex, L"FAT32", ESP_CLUSTER_SIZE, dlg->m_cancelOperationEvent, L""), "Error on FormatFirstPartitionOnDrive"); CHECK_IF_CANCELLED; @@ -4772,7 +4773,7 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) CHECK_IF_CANCELLED; // Format and mount exFAT - IFFALSE_GOTOERROR(FormatFirstPartitionOnDrive(DriveIndex, FS_EXFAT, dlg->m_cancelOperationEvent, EXFAT_PARTITION_NAME_LIVE), "Error on FormatFirstPartitionOnDrive"); + IFFALSE_GOTOERROR(FormatFirstPartitionOnDrive(DriveIndex, L"exFAT", EXFAT_CLUSTER_SIZE, dlg->m_cancelOperationEvent, EXFAT_PARTITION_NAME_LIVE), "Error on FormatFirstPartitionOnDrive"); CHECK_IF_CANCELLED; @@ -4903,10 +4904,14 @@ bool CEndlessUsbToolDlg::CreateCorrectPartitionLayout(HANDLE hPhysical, PBYTE la return returnValue; } -bool CEndlessUsbToolDlg::FormatFirstPartitionOnDrive(DWORD DriveIndex, int fsToUse, HANDLE cancelEvent, const wchar_t *partLabel) +bool CEndlessUsbToolDlg::FormatFirstPartitionOnDrive(DWORD DriveIndex, const wchar_t *kFSType, ULONG ulClusterSize, HANDLE cancelEvent, const wchar_t *kPartLabel) { FUNCTION_ENTER; + // FormatPartition() requires these to be non-const + wchar_t *wFSType = _wcsdup(kFSType); + wchar_t *wPartLabel = _wcsdup(kPartLabel); + BOOL result; int formatRetries = 5; bool returnValue = false; @@ -4920,16 +4925,16 @@ bool CEndlessUsbToolDlg::FormatFirstPartitionOnDrive(DWORD DriveIndex, int fsToU // Clear any leftover error state FormatStatus = 0; - if ((result = FormatDrive(DriveIndex, fsToUse, partLabel))) { + if ((result = FormatPartition(DriveIndex, wFSType, wPartLabel, ulClusterSize))) { break; } - uprintf("FormatDrive failed; FormatStatus = 0x%x %s\n", FormatStatus, StrError(FormatStatus, TRUE)); + uprintf("FormatPartition failed; FormatStatus = 0x%x %s\n", FormatStatus, StrError(FormatStatus, TRUE)); Sleep(200); // Radu: check if this is needed, that's what rufus does; I hate sync using sleep // Check if user cancelled IFFALSE_GOTOERROR(WaitForSingleObject(cancelEvent, 0) == WAIT_TIMEOUT, "User cancel."); } - IFFALSE_GOTOERROR(result, "FormatDrive failed too many times"); + IFFALSE_GOTOERROR(result, "FormatPartition failed too many times"); Sleep(200); // Radu: check if this is needed, that's what rufus does; I hate sync using sleep IFFALSE_PRINTERROR(WaitForLogical(DriveIndex), "Warning: Logical drive was not found after format!"); @@ -4937,6 +4942,8 @@ bool CEndlessUsbToolDlg::FormatFirstPartitionOnDrive(DWORD DriveIndex, int fsToU returnValue = true; error: + safe_free(wFSType); + safe_free(wPartLabel); return returnValue; } diff --git a/src/endless/EndlessUsbToolDlg.h b/src/endless/EndlessUsbToolDlg.h index cf5b8c248a1..b434e4a3f25 100644 --- a/src/endless/EndlessUsbToolDlg.h +++ b/src/endless/EndlessUsbToolDlg.h @@ -400,7 +400,7 @@ class CEndlessUsbToolDlg : public CDHtmlDialog static DWORD WINAPI CreateUSBStick(LPVOID param); static bool CreateFakePartitionLayout(HANDLE hPhysical, PBYTE layout, PBYTE geometry); - static bool FormatFirstPartitionOnDrive(DWORD DriveIndex, int fsToUse, HANDLE m_cancelOperationEvent, const wchar_t *partLabel); + static bool FormatFirstPartitionOnDrive(DWORD DriveIndex, const wchar_t *kFSType, ULONG ulClusterSize, HANDLE cancelEvent, const wchar_t *kPartLabel); static bool MountFirstPartitionOnDrive(DWORD DriveIndex, CString &driveLetter); static bool CreateCorrectPartitionLayout(HANDLE hPhysical, PBYTE layout, PBYTE geometry); diff --git a/src/format.c b/src/format.c index 5c943c7955b..d985ae3b141 100644 --- a/src/format.c +++ b/src/format.c @@ -673,14 +673,49 @@ static BOOL FormatFAT32(DWORD DriveIndex) return r; } +/* + * Call on fmifs.dll's FormatEx() to format a partition. Returns FALSE with FormatStatus set on error. + */ +BOOL FormatPartition(DWORD DriveIndex, wchar_t *wFSType, wchar_t *partLabel, ULONG ulClusterSize) +{ + BOOL r = FALSE; + PF_DECL(FormatEx); + char *locale, *VolumeName = NULL; + WCHAR* wVolumeName = NULL; + + VolumeName = GetLogicalName(DriveIndex, FALSE, TRUE); + wVolumeName = utf8_to_wchar(VolumeName); + if (wVolumeName == NULL) { + uprintf("Could not read volume name\n"); + FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_GEN_FAILURE; + goto out; + } + + // LoadLibrary("fmifs.dll") appears to changes the locale, which can lead to + // problems with tolower(). Make sure we restore the locale. For more details, + // see http://comments.gmane.org/gmane.comp.gnu.mingw.user/39300 + locale = setlocale(LC_ALL, NULL); + PF_INIT_OR_OUT(FormatEx, Fmifs); + setlocale(LC_ALL, locale); + + pfFormatEx(wVolumeName, SelectedDrive.Geometry.MediaType, wFSType, partLabel, + /* quick format */ TRUE, ulClusterSize, FormatExCallback); + + if (!IS_ERROR(FormatStatus)) { + uprintf("Format completed.\n"); + r = TRUE; + } + +out: + safe_free(VolumeName); + safe_free(wVolumeName); + return r; +} + /* * Call on fmifs.dll's FormatEx() to format the drive */ -#ifdef ENDLESSUSB_TOOL -BOOL FormatDrive(DWORD DriveIndex, int fsToUse, const wchar_t *partLabel) -#else static BOOL FormatDrive(DWORD DriveIndex) -#endif // ENDLESSUSB_TOOL { BOOL r = FALSE; PF_DECL(FormatEx); @@ -694,11 +729,6 @@ static BOOL FormatDrive(DWORD DriveIndex) size_t i; int fs; -#ifdef ENDLESSUSB_TOOL - fs = fsToUse; - strcpy_s(FSType, sizeof(FSType), fs == FS_EXFAT ? "exFAT" : "FAT32"); - UNREFERENCED_PARAMETER(i); -#else GetWindowTextU(hFileSystem, FSType, ARRAYSIZE(FSType)); // Might have a (Default) suffix => remove it for (i=strlen(FSType); i>2; i--) { @@ -713,7 +743,6 @@ static BOOL FormatDrive(DWORD DriveIndex) } else { PrintInfoDebug(0, MSG_222, FSType); } -#endif // ENDLESSUSB_TOOL VolumeName = GetLogicalName(DriveIndex, TRUE, TRUE); wVolumeName = utf8_to_wchar(VolumeName); if (wVolumeName == NULL) { @@ -733,11 +762,6 @@ static BOOL FormatDrive(DWORD DriveIndex) PF_INIT(EnableVolumeCompression, Fmifs); setlocale(LC_ALL, locale); -#ifdef ENDLESSUSB_TOOL - wcscpy_s(wFSType, 64, fs == FS_EXFAT ? L"exFAT" : L"FAT32"); - wcscpy_s(wLabel, 64, partLabel); - ulClusterSize = fs == FS_EXFAT ? 0x8000 : 0x200; -#else GetWindowTextW(hFileSystem, wFSType, ARRAYSIZE(wFSType)); // We may have a " (Default)" trail for (i=0; i32 GB) use // large FAT32 format, else use MS's FormatEx. -#ifdef ENDLESSUSB_TOOL - ret = use_large_fat32?FormatFAT32(DriveIndex):FormatDrive(DriveIndex, fs, L""); -#else ret = use_large_fat32 ? FormatFAT32(DriveIndex) : FormatDrive(DriveIndex); -#endif // ENDLESSUSB_TOOL if (!ret) { // Error will be set by FormatDrive() in FormatStatus uprintf("Format error: %s\n", StrError(FormatStatus, TRUE)); diff --git a/src/rufus.h b/src/rufus.h index 8c149470c7f..963f594869c 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -453,6 +453,8 @@ extern BOOL SetThreadAffinity(DWORD_PTR* thread_affinity, size_t num_threads); #define printbitslz(x) _printbits(sizeof(x), &x, 1) extern char* _printbits(size_t const size, void const * const ptr, int leading_zeroes); +BOOL FormatPartition(DWORD DriveIndex, wchar_t *wFSType, wchar_t *partLabel, ULONG ulClusterSize); + DWORD WINAPI FormatThread(void* param); DWORD WINAPI SaveImageThread(void* param); DWORD WINAPI SumThread(void* param); From 7e12173f3a5083a5701a4e551fac16537c3aa93e Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 Oct 2017 16:31:42 +0100 Subject: [PATCH 03/20] FormatPartition: accept path, not drive index --- src/endless/EndlessUsbToolDlg.cpp | 7 ++++++- src/format.c | 6 ++---- src/rufus.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index ba0a34eb440..cdf5ee9bf0e 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -4915,17 +4915,21 @@ bool CEndlessUsbToolDlg::FormatFirstPartitionOnDrive(DWORD DriveIndex, const wch BOOL result; int formatRetries = 5; bool returnValue = false; + char *name = NULL; // Wait for the logical drive we just created to appear uprintf("Waiting for logical drive to reappear...\n"); Sleep(200); // Radu: check if this is needed, that's what rufus does; I hate sync using sleep IFFALSE_PRINTERROR(WaitForLogical(DriveIndex), "Warning: Logical drive was not found!"); // We try to continue even if this fails, just in case + name = GetLogicalName(DriveIndex, FALSE, TRUE); + IFFALSE_GOTOERROR(name != NULL, "GetLogicalName failed"); + while (formatRetries-- > 0) { // Clear any leftover error state FormatStatus = 0; - if ((result = FormatPartition(DriveIndex, wFSType, wPartLabel, ulClusterSize))) { + if ((result = FormatPartition(name, wFSType, wPartLabel, ulClusterSize))) { break; } @@ -4944,6 +4948,7 @@ bool CEndlessUsbToolDlg::FormatFirstPartitionOnDrive(DWORD DriveIndex, const wch error: safe_free(wFSType); safe_free(wPartLabel); + safe_free(name); return returnValue; } diff --git a/src/format.c b/src/format.c index d985ae3b141..91a2c9a7598 100644 --- a/src/format.c +++ b/src/format.c @@ -676,14 +676,13 @@ static BOOL FormatFAT32(DWORD DriveIndex) /* * Call on fmifs.dll's FormatEx() to format a partition. Returns FALSE with FormatStatus set on error. */ -BOOL FormatPartition(DWORD DriveIndex, wchar_t *wFSType, wchar_t *partLabel, ULONG ulClusterSize) +BOOL FormatPartition(const char *VolumeName, wchar_t *wFSType, wchar_t *partLabel, ULONG ulClusterSize) { BOOL r = FALSE; PF_DECL(FormatEx); - char *locale, *VolumeName = NULL; + char *locale; WCHAR* wVolumeName = NULL; - VolumeName = GetLogicalName(DriveIndex, FALSE, TRUE); wVolumeName = utf8_to_wchar(VolumeName); if (wVolumeName == NULL) { uprintf("Could not read volume name\n"); @@ -707,7 +706,6 @@ BOOL FormatPartition(DWORD DriveIndex, wchar_t *wFSType, wchar_t *partLabel, ULO } out: - safe_free(VolumeName); safe_free(wVolumeName); return r; } diff --git a/src/rufus.h b/src/rufus.h index 963f594869c..47bdc80b2b3 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -453,7 +453,7 @@ extern BOOL SetThreadAffinity(DWORD_PTR* thread_affinity, size_t num_threads); #define printbitslz(x) _printbits(sizeof(x), &x, 1) extern char* _printbits(size_t const size, void const * const ptr, int leading_zeroes); -BOOL FormatPartition(DWORD DriveIndex, wchar_t *wFSType, wchar_t *partLabel, ULONG ulClusterSize); +BOOL FormatPartition(const char *VolumeName, wchar_t *wFSType, wchar_t *partLabel, ULONG ulClusterSize); DWORD WINAPI FormatThread(void* param); DWORD WINAPI SaveImageThread(void* param); From 2715beada66834e228d3a7b2dc997478ad95a1b9 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 Oct 2017 16:31:44 +0100 Subject: [PATCH 04/20] Avoid USB partition layout switcheroo There is no need to perform this juggling act: if you can address a drive, you can format it. We know how to address a non-basic-data partition on a disk, even though it doesn't get assigned a Volume{GUID}-style path (on Windows versions prior to 1703 "Creators Update", that is...). Previously, on error we would unmount whichever partition was mounted at the time; on success, eoslive would remain mounted. Instead, we now unconditionally unmount the ESP at the end of the process, and leave the image partition mounted (if indeed it is). --- src/drive.c | 6 +- src/endless/EndlessUsbToolDlg.cpp | 186 +++++++++++++++--------------- src/endless/EndlessUsbToolDlg.h | 6 +- 3 files changed, 97 insertions(+), 101 deletions(-) diff --git a/src/drive.c b/src/drive.c index be4cad3d91f..2eaada09ad4 100644 --- a/src/drive.c +++ b/src/drive.c @@ -889,8 +889,10 @@ BOOL MountVolume(char* drive_name, char *drive_guid) } /* - * Mount partition #part_nr, residing on the same disk as drive_name to an available - * drive letter. Returns the newly allocated drive string. + * Mount partition #part_nr, residing on the same disk as drive_name (which must be + * of the form "X:" with no trailing slash) to an available + * drive letter. Returns a borrowed pointer to the newly-allocated drive letter of + * the form "Y:", which must not be freed, or NULL on error. * We need to do this because, for instance, EFI System partitions are not assigned * Volume GUIDs by the OS, and we need to have a letter assigned, for when we invoke * bcdtool for Windows To Go. All in all, the process looks like this: diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index cdf5ee9bf0e..4da79cb97bc 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -4067,7 +4067,7 @@ DWORD WINAPI CEndlessUsbToolDlg::FileCopyThread(void* param) PDISK_GEOMETRY_EX DiskGeometry = (PDISK_GEOMETRY_EX)(void*)geometry; PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)(void*)layout; CString driveDestination, fileDestination, liveFileName; - CStringA iniLanguage = INI_LOCALE_EN; + CStringA driveDestinationA, iniLanguage = INI_LOCALE_EN; // Radu: why do we do this? memset(&SelectedDrive, 0, sizeof(SelectedDrive)); @@ -4120,7 +4120,8 @@ DWORD WINAPI CEndlessUsbToolDlg::FileCopyThread(void* param) // Format the partition IFFALSE_GOTOERROR(FormatFirstPartitionOnDrive(DriveIndex, L"exFAT", EXFAT_CLUSTER_SIZE, dlg->m_cancelOperationEvent, EXFAT_PARTITION_NAME_IMAGES), "Error on FormatFirstPartitionOnDrive"); // Mount it - IFFALSE_GOTOERROR(MountFirstPartitionOnDrive(DriveIndex, driveDestination), "Error on MountFirstPartitionOnDrive"); + IFFALSE_GOTOERROR(MountFirstPartitionOnDrive(DriveIndex, driveDestinationA), "Error on MountFirstPartitionOnDrive"); + driveDestination = driveDestinationA; // Copy Files liveFileName = CSTRING_GET_LAST(dlg->m_localFile, L'\\'); @@ -4680,8 +4681,10 @@ void CEndlessUsbToolDlg::SetJSONDownloadState(JSONDownloadState state) // Below defines need to be in this order #define USB_PROGRESS_UNPACK_BOOT_ZIP 2 #define USB_PROGRESS_MBR_SBR_DONE 4 -#define USB_PROGRESS_ESP_CREATION_DONE 6 -#define USB_PROGRESS_EXFAT_PREPARED 10 +#define USB_PROGRESS_EXFAT_PREPARED 6 +#define USB_PROGRESS_ESP_PREPARED 8 +#define USB_PROGRESS_ESP_CREATION_DONE 10 +#define USB_PROGRESS_IMG_COPY_STARTED 10 #define USB_PROGRESS_IMG_COPY_DONE 98 #define USB_PROGRESS_ALL_DONE 100 @@ -4696,12 +4699,12 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) BOOL result; DWORD size; HANDLE hPhysical = INVALID_HANDLE_VALUE; - BYTE geometry[256] = { 0 }, layout[4096] = { 0 }; CREATE_DISK createDiskData; - CString driveLetter; CString bootFilesPath = CEndlessUsbToolApp::TempFilePath(CString(BOOT_COMPONENTS_FOLDER)) + L"\\"; CString usbFilesPath; - PDISK_GEOMETRY_EX DiskGeometry = (PDISK_GEOMETRY_EX)(void*)geometry; + DWORD BytesPerSector = 0; + CStringA eosliveDriveLetter, espDriveLetter; + const char *cszEspDriveLetter; UpdateProgress(OP_NEW_LIVE_CREATION, 0); @@ -4728,63 +4731,59 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) result = DeviceIoControl(hPhysical, IOCTL_DISK_CREATE_DISK, &createDiskData, sizeof(createDiskData), NULL, 0, &size, NULL); IFFALSE_GOTOERROR(result != 0, "Error when calling IOCTL_DISK_CREATE_DISK"); - // get disk geometry information - result = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, geometry, sizeof(geometry), &size, NULL); - IFFALSE_GOTOERROR(result != 0 && size > 0, "Error on querying disk geometry."); - - // set initial drive layout data - memset(layout, 0, sizeof(layout)); - IFFALSE_GOTOERROR(CreateFakePartitionLayout(hPhysical, layout, geometry), "Error on CreateFakePartitionLayout"); + // create partitions. + IFFALSE_GOTOERROR(CreateUSBPartitionLayout(hPhysical, BytesPerSector), "Error on CreateUSBPartitionLayout"); CHECK_IF_CANCELLED; + // Wait for the logical drive we just created to appear + uprintf("Waiting for logical drive to reappear...\n"); + Sleep(200); // Radu: check if this is needed, that's what rufus does; I hate sync using sleep + IFFALSE_PRINTERROR(WaitForLogical(DriveIndex), "Warning: Logical drive was not found!"); // We try to continue even if this fails, just in case + // Write MBR and SBR to disk - IFFALSE_GOTOERROR(WriteMBRAndSBRToUSB(hPhysical, bootFilesPath, DiskGeometry->Geometry.BytesPerSector), "Error on WriteMBRAndSBRToUSB"); + IFFALSE_GOTOERROR(WriteMBRAndSBRToUSB(hPhysical, bootFilesPath, BytesPerSector), "Error on WriteMBRAndSBRToUSB"); safe_closehandle(hPhysical); UpdateProgress(OP_NEW_LIVE_CREATION, USB_PROGRESS_MBR_SBR_DONE); CHECK_IF_CANCELLED; - // Format and mount ESP - IFFALSE_GOTOERROR(FormatFirstPartitionOnDrive(DriveIndex, L"FAT32", ESP_CLUSTER_SIZE, dlg->m_cancelOperationEvent, L""), "Error on FormatFirstPartitionOnDrive"); + // Format and mount exFAT + IFFALSE_GOTOERROR(FormatFirstPartitionOnDrive(DriveIndex, L"exFAT", EXFAT_CLUSTER_SIZE, dlg->m_cancelOperationEvent, EXFAT_PARTITION_NAME_LIVE), "Error formatting eoslive"); CHECK_IF_CANCELLED; - IFFALSE_GOTOERROR(MountFirstPartitionOnDrive(DriveIndex, driveLetter), "Error on MountFirstPartitionOnDrive"); + IFFALSE_GOTOERROR(MountFirstPartitionOnDrive(DriveIndex, eosliveDriveLetter), "Error mounting eoslive"); - // Copy files to the ESP partition - IFFALSE_GOTOERROR(CopyFilesToESP(bootFilesPath, driveLetter), "Error when trying to copy files to ESP partition."); + UpdateProgress(OP_NEW_LIVE_CREATION, USB_PROGRESS_EXFAT_PREPARED); + CHECK_IF_CANCELLED; - // Unmount ESP - if (!DeleteVolumeMountPoint(driveLetter)) uprintf("Failed to unmount volume: %s", WindowsErrorString()); + // Mount and format ESP. (Yes, you can assign a drive letter to an unformatted volume!) + cszEspDriveLetter = AltMountVolume(eosliveDriveLetter.Left(2), 2); + IFFALSE_GOTOERROR(cszEspDriveLetter != NULL, "Error mounting ESP"); + // The pointer returned by AltMountVolume() is to a static buffer... + espDriveLetter = cszEspDriveLetter; - UpdateProgress(OP_NEW_LIVE_CREATION, USB_PROGRESS_ESP_CREATION_DONE); CHECK_IF_CANCELLED; - // get disk handle again - hPhysical = GetPhysicalHandle(DriveIndex, TRUE, TRUE); - IFFALSE_GOTOERROR(hPhysical != INVALID_HANDLE_VALUE, "Error on acquiring disk handle."); - - // fix partition types and layout - IFFALSE_GOTOERROR(CreateCorrectPartitionLayout(hPhysical, layout, geometry), "Error on CreateCorrectPartitionLayout"); - safe_closehandle(hPhysical); + IFFALSE_GOTOERROR(FormatPartitionWithRetry(espDriveLetter, L"FAT32", ESP_CLUSTER_SIZE, dlg->m_cancelOperationEvent, L""), "Error formatting ESP"); + UpdateProgress(OP_NEW_LIVE_CREATION, USB_PROGRESS_ESP_PREPARED); CHECK_IF_CANCELLED; - // Format and mount exFAT - IFFALSE_GOTOERROR(FormatFirstPartitionOnDrive(DriveIndex, L"exFAT", EXFAT_CLUSTER_SIZE, dlg->m_cancelOperationEvent, EXFAT_PARTITION_NAME_LIVE), "Error on FormatFirstPartitionOnDrive"); + // Copy files to the ESP partition + IFFALSE_GOTOERROR(CopyFilesToESP(bootFilesPath, CString(espDriveLetter) + L"\\"), "Error when trying to copy files to ESP partition."); - CHECK_IF_CANCELLED; + // Unmount ESP (but continue if this fails) + IFFALSE_PRINTERROR(AltUnmountVolume(espDriveLetter), "Failed to unmount ESP"); + espDriveLetter = ""; - IFFALSE_GOTOERROR(MountFirstPartitionOnDrive(DriveIndex, driveLetter), "Error on MountFirstPartitionOnDrive"); + UpdateProgress(OP_NEW_LIVE_CREATION, USB_PROGRESS_ESP_CREATION_DONE); + CHECK_IF_CANCELLED; - UpdateProgress(OP_NEW_LIVE_CREATION, USB_PROGRESS_EXFAT_PREPARED); // Copy files to the exFAT partition - IFFALSE_GOTOERROR(CopyFilesToexFAT(dlg, bootFilesPath, driveLetter), "Error on CopyFilesToexFAT"); - - // Unmount exFAT - if (!DeleteVolumeMountPoint(driveLetter)) uprintf("Failed to unmount volume: %s", WindowsErrorString()); + IFFALSE_GOTOERROR(CopyFilesToexFAT(dlg, bootFilesPath, UTF8ToCString(eosliveDriveLetter)), "Error on CopyFilesToexFAT"); UpdateProgress(OP_NEW_LIVE_CREATION, USB_PROGRESS_ALL_DONE); CHECK_IF_CANCELLED; @@ -4797,10 +4796,12 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) dlg->m_lastErrorCause = ErrorCause_t::ErrorCauseWriteFailed; } - // Unmount exFAT - if (!DeleteVolumeMountPoint(driveLetter)) uprintf("Failed to unmount volume: %s", WindowsErrorString()); - done: + // Unmount ESP + if (espDriveLetter.GetLength() > 0) { + IFFALSE_PRINTERROR(AltUnmountVolume(espDriveLetter), "Failed to unmount ESP"); + } + RemoveNonEmptyDirectory(bootFilesPath); safe_closehandle(hPhysical); dlg->PostMessage(WM_FINISHED_ALL_OPERATIONS, 0, 0); @@ -4808,13 +4809,21 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) } -bool CEndlessUsbToolDlg::CreateFakePartitionLayout(HANDLE hPhysical, PBYTE layout, PBYTE geometry) +bool CEndlessUsbToolDlg::CreateUSBPartitionLayout(HANDLE hPhysical, DWORD &BytesPerSector) { FUNCTION_ENTER; + BYTE layout[4096] = { 0 }, geometry[256] = { 0 }; PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)(void*)layout; PDISK_GEOMETRY_EX DiskGeometry = (PDISK_GEOMETRY_EX)(void*)geometry; PARTITION_INFORMATION_EX *currentPartition; + DWORD result, size; + + // get disk geometry information + result = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, geometry, sizeof(geometry), &size, NULL); + IFFALSE_GOTOERROR(result != 0 && size > 0, "Error on querying disk geometry."); + BytesPerSector = DiskGeometry->Geometry.BytesPerSector; + // the EFI spec says the GPT will take the first and last two sectors of // the disk, plus however much is allocated for partition entries. there // must be at least 128 entries of at least 128 in size - in practice this @@ -4822,8 +4831,7 @@ bool CEndlessUsbToolDlg::CreateFakePartitionLayout(HANDLE hPhysical, PBYTE layou // sector size which is at least 512, but a hypothetical GIANT SECTOR disk // would need three sectors reserved for the whole partition table, so we // use max() - LONGLONG gptLength = (2 * DiskGeometry->Geometry.BytesPerSector) + - max((128 * 128), DiskGeometry->Geometry.BytesPerSector); + LONGLONG gptLength = (2 * BytesPerSector) + max((128 * 128), BytesPerSector); bool returnValue = false; DriveLayout->PartitionStyle = PARTITION_STYLE_GPT; @@ -4831,21 +4839,26 @@ bool CEndlessUsbToolDlg::CreateFakePartitionLayout(HANDLE hPhysical, PBYTE layou IGNORE_RETVAL(CoCreateGuid(&DriveLayout->Gpt.DiskId)); LONGLONG partitionStart[EXPECTED_NUMBER_OF_PARTITIONS] = { - ESP_PART_STARTING_SECTOR * DiskGeometry->Geometry.BytesPerSector, - MBR_PART_STARTING_SECTOR * DiskGeometry->Geometry.BytesPerSector, - EXFAT_PART_STARTING_SECTOR * DiskGeometry->Geometry.BytesPerSector + EXFAT_PART_STARTING_SECTOR * BytesPerSector, + ESP_PART_STARTING_SECTOR * BytesPerSector, + MBR_PART_STARTING_SECTOR * BytesPerSector }; LONGLONG partitionSize[EXPECTED_NUMBER_OF_PARTITIONS] = { - ESP_PART_LENGTH_BYTES, - MBR_PART_LENGTH_BYTES, // there is a 2nd copy of the GPT at the end of the disk so we // subtract the length here to avoid the operation failing - DiskGeometry->DiskSize.QuadPart - gptLength - partitionStart[2] + DiskGeometry->DiskSize.QuadPart - gptLength - partitionStart[0], + ESP_PART_LENGTH_BYTES, + MBR_PART_LENGTH_BYTES }; GUID partitionType[EXPECTED_NUMBER_OF_PARTITIONS] = { - PARTITION_BASIC_DATA_GUID, // will become PARTITION_SYSTEM_GUID later - PARTITION_BIOS_BOOT_GUID, - PARTITION_BASIC_DATA_GUID + PARTITION_BASIC_DATA_GUID, + PARTITION_SYSTEM_GUID, + PARTITION_BIOS_BOOT_GUID + }; + wchar_t *partitionName[EXPECTED_NUMBER_OF_PARTITIONS] = { + EXFAT_PARTITION_NAME_LIVE, + L"", + L"" }; for (int partIndex = 0; partIndex < EXPECTED_NUMBER_OF_PARTITIONS; partIndex++) { @@ -4857,14 +4870,13 @@ bool CEndlessUsbToolDlg::CreateFakePartitionLayout(HANDLE hPhysical, PBYTE layou currentPartition->RewritePartition = TRUE; currentPartition->Gpt.PartitionType = partitionType[partIndex]; IGNORE_RETVAL(CoCreateGuid(¤tPartition->Gpt.PartitionId)); - - if (partIndex == EXPECTED_NUMBER_OF_PARTITIONS - 1) wcscpy(currentPartition->Gpt.Name, EXFAT_PARTITION_NAME_LIVE); + wcscpy(currentPartition->Gpt.Name, partitionName[partIndex]); } // push partition information to drive - DWORD size = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + DriveLayout->PartitionCount * sizeof(PARTITION_INFORMATION_EX); + size = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + DriveLayout->PartitionCount * sizeof(PARTITION_INFORMATION_EX); IFFALSE_GOTOERROR(DeviceIoControl(hPhysical, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, layout, size, NULL, 0, &size, NULL), "Could not set drive layout."); - DWORD result = RefreshDriveLayout(hPhysical); + result = RefreshDriveLayout(hPhysical); IFFALSE_PRINTERROR(result != 0, "Warning: failure on IOCTL_DISK_UPDATE_PROPERTIES"); // not returning here, maybe formatting will still work although IOCTL_DISK_UPDATE_PROPERTIES failed returnValue = true; @@ -4872,41 +4884,36 @@ bool CEndlessUsbToolDlg::CreateFakePartitionLayout(HANDLE hPhysical, PBYTE layou return returnValue; } -bool CEndlessUsbToolDlg::CreateCorrectPartitionLayout(HANDLE hPhysical, PBYTE layout, PBYTE geometry) +bool CEndlessUsbToolDlg::FormatFirstPartitionOnDrive(DWORD DriveIndex, const wchar_t *kFSType, ULONG ulClusterSize, HANDLE cancelEvent, const wchar_t *kPartLabel) { FUNCTION_ENTER; - PARTITION_INFORMATION_EX exfatPartition; - PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = (PDRIVE_LAYOUT_INFORMATION_EX)(void*)layout; - PDISK_GEOMETRY_EX DiskGeometry = (PDISK_GEOMETRY_EX)(void*)geometry; bool returnValue = false; + char *name = NULL; - // save the exFAT partition data - memcpy(&exfatPartition, &(DriveLayout->PartitionEntry[2]), sizeof(PARTITION_INFORMATION_EX)); - exfatPartition.PartitionNumber = 1; - // move ESP and MBR - memcpy(&(DriveLayout->PartitionEntry[2]), &(DriveLayout->PartitionEntry[1]), sizeof(PARTITION_INFORMATION_EX)); - DriveLayout->PartitionEntry[2].PartitionNumber = 3; - memcpy(&(DriveLayout->PartitionEntry[1]), &(DriveLayout->PartitionEntry[0]), sizeof(PARTITION_INFORMATION_EX)); - DriveLayout->PartitionEntry[1].PartitionNumber = 2; - DriveLayout->PartitionEntry[1].Gpt.PartitionType = PARTITION_SYSTEM_GUID; - // copy exFAT to first position - memcpy(&(DriveLayout->PartitionEntry[0]), &exfatPartition, sizeof(PARTITION_INFORMATION_EX)); + // Wait for the logical drive we just created to appear + uprintf("Waiting for logical drive to reappear...\n"); + Sleep(200); // Radu: check if this is needed, that's what rufus does; I hate sync using sleep + IFFALSE_PRINTERROR(WaitForLogical(DriveIndex), "Warning: Logical drive was not found!"); // We try to continue even if this fails, just in case - // push partition information to drive - DWORD size = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + DriveLayout->PartitionCount * sizeof(PARTITION_INFORMATION_EX); - IFFALSE_GOTOERROR(DeviceIoControl(hPhysical, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, layout, size, NULL, 0, &size, NULL), "Could not set drive layout."); - DWORD result = RefreshDriveLayout(hPhysical); - IFFALSE_PRINTERROR(result != 0, "Warning: failure on IOCTL_DISK_UPDATE_PROPERTIES"); // not returning here, maybe formatting will still work although IOCTL_DISK_UPDATE_PROPERTIES failed + name = GetLogicalName(DriveIndex, FALSE, TRUE); + IFFALSE_GOTOERROR(name != NULL, "GetLogicalName failed"); + + IFFALSE_GOTOERROR(FormatPartitionWithRetry(name, kFSType, ulClusterSize, cancelEvent, kPartLabel), "Couldn't format partition"); + + Sleep(200); // Radu: check if this is needed, that's what rufus does; I hate sync using sleep + IFFALSE_PRINTERROR(WaitForLogical(DriveIndex), "Warning: Logical drive was not found after format!"); returnValue = true; + error: + safe_free(name); return returnValue; } -bool CEndlessUsbToolDlg::FormatFirstPartitionOnDrive(DWORD DriveIndex, const wchar_t *kFSType, ULONG ulClusterSize, HANDLE cancelEvent, const wchar_t *kPartLabel) +bool CEndlessUsbToolDlg::FormatPartitionWithRetry(const char *partition, const wchar_t *kFSType, ULONG ulClusterSize, HANDLE cancelEvent, const wchar_t *kPartLabel) { - FUNCTION_ENTER; + FUNCTION_ENTER_FMT("%s (label '%ls')", partition, kPartLabel); // FormatPartition() requires these to be non-const wchar_t *wFSType = _wcsdup(kFSType); @@ -4915,21 +4922,12 @@ bool CEndlessUsbToolDlg::FormatFirstPartitionOnDrive(DWORD DriveIndex, const wch BOOL result; int formatRetries = 5; bool returnValue = false; - char *name = NULL; - - // Wait for the logical drive we just created to appear - uprintf("Waiting for logical drive to reappear...\n"); - Sleep(200); // Radu: check if this is needed, that's what rufus does; I hate sync using sleep - IFFALSE_PRINTERROR(WaitForLogical(DriveIndex), "Warning: Logical drive was not found!"); // We try to continue even if this fails, just in case - - name = GetLogicalName(DriveIndex, FALSE, TRUE); - IFFALSE_GOTOERROR(name != NULL, "GetLogicalName failed"); while (formatRetries-- > 0) { // Clear any leftover error state FormatStatus = 0; - if ((result = FormatPartition(name, wFSType, wPartLabel, ulClusterSize))) { + if ((result = FormatPartition(partition, wFSType, wPartLabel, ulClusterSize))) { break; } @@ -4940,19 +4938,15 @@ bool CEndlessUsbToolDlg::FormatFirstPartitionOnDrive(DWORD DriveIndex, const wch } IFFALSE_GOTOERROR(result, "FormatPartition failed too many times"); - Sleep(200); // Radu: check if this is needed, that's what rufus does; I hate sync using sleep - IFFALSE_PRINTERROR(WaitForLogical(DriveIndex), "Warning: Logical drive was not found after format!"); - returnValue = true; error: safe_free(wFSType); safe_free(wPartLabel); - safe_free(name); return returnValue; } -bool CEndlessUsbToolDlg::MountFirstPartitionOnDrive(DWORD DriveIndex, CString &driveLetter) +bool CEndlessUsbToolDlg::MountFirstPartitionOnDrive(DWORD DriveIndex, CStringA &driveLetter) { FUNCTION_ENTER; @@ -5096,7 +5090,7 @@ bool CEndlessUsbToolDlg::CopyFilesToexFAT(CEndlessUsbToolDlg *dlg, const CString IFFALSE_GOTOERROR(createDirResult == ERROR_SUCCESS || createDirResult == ERROR_FILE_EXISTS, "Error creating directory on USB drive."); CEndlessUsbToolDlg::ImageUnpackOperation = OP_NEW_LIVE_CREATION; - CEndlessUsbToolDlg::ImageUnpackPercentStart = USB_PROGRESS_EXFAT_PREPARED; + CEndlessUsbToolDlg::ImageUnpackPercentStart = USB_PROGRESS_IMG_COPY_STARTED; CEndlessUsbToolDlg::ImageUnpackPercentEnd = USB_PROGRESS_IMG_COPY_DONE; CEndlessUsbToolDlg::ImageUnpackFileSize = dlg->m_selectedFileSize; diff --git a/src/endless/EndlessUsbToolDlg.h b/src/endless/EndlessUsbToolDlg.h index b434e4a3f25..f849b33b29f 100644 --- a/src/endless/EndlessUsbToolDlg.h +++ b/src/endless/EndlessUsbToolDlg.h @@ -399,10 +399,10 @@ class CEndlessUsbToolDlg : public CDHtmlDialog void ChangeDriveAutoRunAndMount(bool setEndlessValues); static DWORD WINAPI CreateUSBStick(LPVOID param); - static bool CreateFakePartitionLayout(HANDLE hPhysical, PBYTE layout, PBYTE geometry); + static bool CreateUSBPartitionLayout(HANDLE hPhysical, DWORD &BytesPerSector); static bool FormatFirstPartitionOnDrive(DWORD DriveIndex, const wchar_t *kFSType, ULONG ulClusterSize, HANDLE cancelEvent, const wchar_t *kPartLabel); - static bool MountFirstPartitionOnDrive(DWORD DriveIndex, CString &driveLetter); - static bool CreateCorrectPartitionLayout(HANDLE hPhysical, PBYTE layout, PBYTE geometry); + static bool FormatPartitionWithRetry(const char *partition, const wchar_t *kFSType, ULONG ulClusterSize, HANDLE cancelEvent, const wchar_t *kPartLabel); + static bool MountFirstPartitionOnDrive(DWORD DriveIndex, CStringA &driveLetter); static bool UnpackZip(const CComBSTR source, const CComBSTR dest); static void RemoveNonEmptyDirectory(const CString directoryPath); From 7f56a1211560a58f2df2fee0f8ea6528598619a3 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 Oct 2017 16:31:46 +0100 Subject: [PATCH 05/20] Refactor reading & writing BIOS GRUB to USB WriteFileWithRetry is from Rufus. Who knows if the retry will help, but it can't hurt. --- src/endless/EndlessUsbTool.vcxproj | 2 + src/endless/EndlessUsbTool.vcxproj.filters | 6 +++ src/endless/EndlessUsbToolDlg.cpp | 44 ++++++----------- src/endless/IOUtil.cpp | 56 ++++++++++++++++++++++ src/endless/IOUtil.h | 5 ++ 5 files changed, 84 insertions(+), 29 deletions(-) create mode 100644 src/endless/IOUtil.cpp create mode 100644 src/endless/IOUtil.h diff --git a/src/endless/EndlessUsbTool.vcxproj b/src/endless/EndlessUsbTool.vcxproj index e692514f5f2..7a83aab334b 100644 --- a/src/endless/EndlessUsbTool.vcxproj +++ b/src/endless/EndlessUsbTool.vcxproj @@ -290,6 +290,7 @@ + @@ -514,6 +515,7 @@ NotUsing + NotUsing diff --git a/src/endless/EndlessUsbTool.vcxproj.filters b/src/endless/EndlessUsbTool.vcxproj.filters index bb287e110a4..0f5c3f61c94 100644 --- a/src/endless/EndlessUsbTool.vcxproj.filters +++ b/src/endless/EndlessUsbTool.vcxproj.filters @@ -156,6 +156,9 @@ Header Files + + Header Files + @@ -260,6 +263,9 @@ Source Files + + Source Files + diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index 4da79cb97bc..7865db2fdc8 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -20,6 +20,7 @@ #include "WindowsUsbDefines.h" #include "StringHelperMethods.h" #include "Images.h" +#include "IOUtil.h" #include "Log2LL.h" #include "UEFIBootSetup.h" #include "WMI.h" @@ -5149,41 +5150,31 @@ bool CEndlessUsbToolDlg::WriteMBRAndSBRToUSB(HANDLE hPhysical, const CString &bo FAKE_FD fake_fd = { 0 }; FILE* fp = (FILE*)&fake_fd; - FILE *bootImgFile = NULL, *coreImgFile = NULL; CString bootImgFilePath = bootFilesPath + LIVE_BOOT_IMG_FILE; CString coreImgFilePath = bootFilesPath + LIVE_CORE_IMG_FILE; - unsigned char endlessMBRData[MAX_BOOT_IMG_FILE_SIZE + 1]; - unsigned char *endlessSBRData = NULL; + unsigned char endlessMBRData[MAX_BOOT_IMG_FILE_SIZE]; + unsigned char *endlessSBRData = (unsigned char *) malloc(MBR_PART_LENGTH_BYTES); bool retResult = false; size_t countRead, coreImgSize; + DWORD coreImgBytesWritten = 0; size_t mbrPartitionStart = bytesPerSector * MBR_PART_STARTING_SECTOR; + LARGE_INTEGER lMbrPartitionStart; - // Load boot.img from file - IFFALSE_GOTOERROR(0 == _wfopen_s(&bootImgFile, bootImgFilePath, L"rb"), "Error opening boot.img file"); - countRead = fread(endlessMBRData, 1, sizeof(endlessMBRData), bootImgFile); - IFFALSE_GOTOERROR(countRead == MAX_BOOT_IMG_FILE_SIZE, "Size of boot.img is not what is expected."); + lMbrPartitionStart.QuadPart = mbrPartitionStart; - // write boot.img to USB drive + // Read boot.img and write it to USB drive + countRead = ReadEntireFile(bootImgFilePath, endlessMBRData, sizeof(endlessMBRData)); + IFFALSE_GOTOERROR(countRead == MAX_BOOT_IMG_FILE_SIZE, "Size of boot.img is not what is expected."); fake_fd._handle = (char*)hPhysical; set_bytes_per_sector(SelectedDrive.Geometry.BytesPerSector); IFFALSE_GOTOERROR(write_data(fp, 0x0, endlessMBRData, MAX_BOOT_IMG_FILE_SIZE) != 0, "Error on write_data with boot.img contents."); // Read core.img data and write it to USB drive - IFFALSE_GOTOERROR(0 == _wfopen_s(&coreImgFile, coreImgFilePath, L"rb"), "Error opening core.img file"); - fseek(coreImgFile, 0L, SEEK_END); - coreImgSize = ftell(coreImgFile); - rewind(coreImgFile); - uprintf("Size of SBR is %d bytes from %ls", coreImgSize, coreImgFilePath); - IFFALSE_GOTOERROR(coreImgSize <= MBR_PART_LENGTH_BYTES, "Error: SBR found in core.img is too big."); - - endlessSBRData = (unsigned char*)malloc(bytesPerSector); - coreImgSize = 0; - while (!feof(coreImgFile) && coreImgSize < MBR_PART_LENGTH_BYTES) { - countRead = fread(endlessSBRData, 1, bytesPerSector, coreImgFile); - IFFALSE_GOTOERROR(write_data(fp, mbrPartitionStart + coreImgSize, endlessSBRData, countRead) != 0, "Error on write data with core.img contents."); - coreImgSize += countRead; - uprintf("Wrote %d bytes", coreImgSize); - } + coreImgSize = ReadEntireFile(coreImgFilePath, endlessSBRData, MBR_PART_LENGTH_BYTES); + IFFALSE_GOTOERROR(coreImgSize, "Couldn't read core.img"); + IFFALSE_GOTOERROR(SetFilePointerEx(hPhysical, lMbrPartitionStart, NULL, FILE_BEGIN), "Error setting handle position"); + IFFALSE_GOTOERROR(WriteFileWithRetry(hPhysical, endlessSBRData, coreImgSize, &coreImgBytesWritten, WRITE_RETRIES), + "Error writing BIOS boot partition"); retResult = true; @@ -5193,12 +5184,7 @@ bool CEndlessUsbToolDlg::WriteMBRAndSBRToUSB(HANDLE hPhysical, const CString &bo uprintf("Failed to notify system about disk properties update: %s\n", WindowsErrorString()); error: - safe_closefile(bootImgFile); - safe_closefile(coreImgFile); - - if (endlessSBRData != NULL) { - safe_free(endlessSBRData); - } + safe_free(endlessSBRData); return retResult; } diff --git a/src/endless/IOUtil.cpp b/src/endless/IOUtil.cpp new file mode 100644 index 00000000000..8d87aacf222 --- /dev/null +++ b/src/endless/IOUtil.cpp @@ -0,0 +1,56 @@ +#include "stdafx.h" + +#include +#include + +#include "GeneralCode.h" + +#define PERROR(_err, msg) do { \ + if (_err != 0) { \ + uprintf("%s:%d %s: %s",__FILE__, __LINE__, msg, strerror(_err)); \ + goto error; \ + } \ +} while (0) + +// Reads 'path', in its entirety, into 'buffer'. +// Returns the number of bytes read, or 0 if the file is larger than +// 'buffer_size' or an error occurred. +size_t ReadEntireFile(const wchar_t *path, unsigned char *buffer, size_t buffer_size) { + FILE *fp = NULL; + long size = 0; + size_t size_read = 0; + errno_t err; + + FUNCTION_ENTER_FMT("%ls", path); + + err = _wfopen_s(&fp, path, L"rb"); + PERROR(err, "_wfopen_s failed"); + + err = fseek(fp, 0L, SEEK_END); + PERROR(err, "fseek(SEEK_END) failed"); + + size = ftell(fp); + rewind(fp); + + IFFALSE_GOTOERROR(size >= 0, "ftell returned negative"); + if ((size_t) size > buffer_size) { + uprintf("%ls is %ld bytes long; supplied buffer is only %Id bytes", path, size, buffer_size); + goto error; + } + buffer_size = size; + + while (!feof(fp) && !ferror(fp) && size_read < buffer_size) { + size_t count = fread(buffer + size_read, 1, 512, fp); + size_read += count; + } + + err = ferror(fp); + if (err != 0) { + size_read = 0; + PERROR(err, "fread failed"); + } + +error: + safe_closefile(fp); + return size_read; +} diff --git a/src/endless/IOUtil.h b/src/endless/IOUtil.h new file mode 100644 index 00000000000..f56aa0f1fba --- /dev/null +++ b/src/endless/IOUtil.h @@ -0,0 +1,5 @@ +#pragma once + +#include + +size_t ReadEntireFile(const wchar_t *path, unsigned char *buffer, size_t buffer_size); From a96d24dd5f6df59c5e84f5e0e21fe211554822e2 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 Oct 2017 16:31:49 +0100 Subject: [PATCH 06/20] Split writing MBR and BIOS boot partition --- src/endless/EndlessUsbToolDlg.cpp | 43 ++++++++++++++++++++----------- src/endless/EndlessUsbToolDlg.h | 3 ++- 2 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index 7865db2fdc8..81f7869f632 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -4743,7 +4743,8 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) IFFALSE_PRINTERROR(WaitForLogical(DriveIndex), "Warning: Logical drive was not found!"); // We try to continue even if this fails, just in case // Write MBR and SBR to disk - IFFALSE_GOTOERROR(WriteMBRAndSBRToUSB(hPhysical, bootFilesPath, BytesPerSector), "Error on WriteMBRAndSBRToUSB"); + IFFALSE_GOTOERROR(WriteMBRToUSB(hPhysical, bootFilesPath), "Error on WriteMBRToUSB"); + IFFALSE_GOTOERROR(WriteBIOSBootPartitionToUSB(hPhysical, bootFilesPath, BytesPerSector), "Error on WriteBIOSBootPartitionToUSB"); safe_closehandle(hPhysical); @@ -5144,23 +5145,16 @@ bool CEndlessUsbToolDlg::CopyMultipleItems(const CString &from, const CString &t return result == 0; } -bool CEndlessUsbToolDlg::WriteMBRAndSBRToUSB(HANDLE hPhysical, const CString &bootFilesPath, DWORD bytesPerSector) +bool CEndlessUsbToolDlg::WriteMBRToUSB(HANDLE hPhysical, const CString &bootFilesPath) { FUNCTION_ENTER; FAKE_FD fake_fd = { 0 }; FILE* fp = (FILE*)&fake_fd; CString bootImgFilePath = bootFilesPath + LIVE_BOOT_IMG_FILE; - CString coreImgFilePath = bootFilesPath + LIVE_CORE_IMG_FILE; unsigned char endlessMBRData[MAX_BOOT_IMG_FILE_SIZE]; - unsigned char *endlessSBRData = (unsigned char *) malloc(MBR_PART_LENGTH_BYTES); bool retResult = false; - size_t countRead, coreImgSize; - DWORD coreImgBytesWritten = 0; - size_t mbrPartitionStart = bytesPerSector * MBR_PART_STARTING_SECTOR; - LARGE_INTEGER lMbrPartitionStart; - - lMbrPartitionStart.QuadPart = mbrPartitionStart; + size_t countRead; // Read boot.img and write it to USB drive countRead = ReadEntireFile(bootImgFilePath, endlessMBRData, sizeof(endlessMBRData)); @@ -5169,6 +5163,30 @@ bool CEndlessUsbToolDlg::WriteMBRAndSBRToUSB(HANDLE hPhysical, const CString &bo set_bytes_per_sector(SelectedDrive.Geometry.BytesPerSector); IFFALSE_GOTOERROR(write_data(fp, 0x0, endlessMBRData, MAX_BOOT_IMG_FILE_SIZE) != 0, "Error on write_data with boot.img contents."); + retResult = true; + + DWORD size; + // Tell the system we've updated the disk properties + if (!DeviceIoControl(hPhysical, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &size, NULL)) + uprintf("Failed to notify system about disk properties update: %s\n", WindowsErrorString()); + +error: + return retResult; +} + +bool CEndlessUsbToolDlg::WriteBIOSBootPartitionToUSB(HANDLE hPhysical, const CString &bootFilesPath, DWORD bytesPerSector) +{ + FUNCTION_ENTER; + + CString coreImgFilePath = bootFilesPath + LIVE_CORE_IMG_FILE; + unsigned char *endlessSBRData = (unsigned char *) malloc(MBR_PART_LENGTH_BYTES); + bool retResult = false; + size_t coreImgSize; + DWORD coreImgBytesWritten = 0; + LARGE_INTEGER lMbrPartitionStart; + + lMbrPartitionStart.QuadPart = bytesPerSector * MBR_PART_STARTING_SECTOR; + // Read core.img data and write it to USB drive coreImgSize = ReadEntireFile(coreImgFilePath, endlessSBRData, MBR_PART_LENGTH_BYTES); IFFALSE_GOTOERROR(coreImgSize, "Couldn't read core.img"); @@ -5178,11 +5196,6 @@ bool CEndlessUsbToolDlg::WriteMBRAndSBRToUSB(HANDLE hPhysical, const CString &bo retResult = true; - DWORD size; - // Tell the system we've updated the disk properties - if (!DeviceIoControl(hPhysical, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &size, NULL)) - uprintf("Failed to notify system about disk properties update: %s\n", WindowsErrorString()); - error: safe_free(endlessSBRData); diff --git a/src/endless/EndlessUsbToolDlg.h b/src/endless/EndlessUsbToolDlg.h index f849b33b29f..8787b2fe632 100644 --- a/src/endless/EndlessUsbToolDlg.h +++ b/src/endless/EndlessUsbToolDlg.h @@ -410,7 +410,8 @@ class CEndlessUsbToolDlg : public CDHtmlDialog static void ImageUnpackCallback(const uint64_t read_bytes); static void UpdateUnpackProgress(const uint64_t current_bytes, const uint64_t total_bytes); static bool CopyFilesToexFAT(CEndlessUsbToolDlg *dlg, const CString &fromFolder, const CString &driveLetter); - static bool WriteMBRAndSBRToUSB(HANDLE hPhysical, const CString &bootFilesPath, DWORD bytesPerSector); + static bool WriteMBRToUSB(HANDLE hPhysical, const CString &bootFilesPath); + static bool WriteBIOSBootPartitionToUSB(HANDLE hPhysical, const CString &bootFilesPath, DWORD bytesPerSector); static DWORD WINAPI SetupDualBoot(LPVOID param); static bool SetupDualBootFiles(CEndlessUsbToolDlg *dlg, const CString &systemDriveLetter, const CString &bootFilesPath, ErrorCause &errorCause); From a403162d90a2479b094efff496146d963808d4f9 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 Oct 2017 16:31:51 +0100 Subject: [PATCH 07/20] Make references to BIOS boot partition consistent It's not the "MBR part[ition]"; it does have a proper name. --- src/endless/EndlessUsbToolDlg.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index 81f7869f632..c4ac7684c83 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -4651,8 +4651,8 @@ void CEndlessUsbToolDlg::SetJSONDownloadState(JSONDownloadState state) #define GPT_MAX_PARTITION_COUNT 128 #define ESP_PART_STARTING_SECTOR 2048 #define ESP_PART_LENGTH_BYTES 65011712 -#define MBR_PART_STARTING_SECTOR 129024 -#define MBR_PART_LENGTH_BYTES 1048576 +#define BIOS_BOOT_PART_STARTING_SECTOR 129024 +#define BIOS_BOOT_PART_LENGTH_BYTES 1048576 #define EXFAT_PART_STARTING_SECTOR 131072 #define EFI_BOOT_SUBDIRECTORY L"EFI\\BOOT" @@ -4742,7 +4742,7 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) Sleep(200); // Radu: check if this is needed, that's what rufus does; I hate sync using sleep IFFALSE_PRINTERROR(WaitForLogical(DriveIndex), "Warning: Logical drive was not found!"); // We try to continue even if this fails, just in case - // Write MBR and SBR to disk + // Write MBR and BIOS boot partition to disk IFFALSE_GOTOERROR(WriteMBRToUSB(hPhysical, bootFilesPath), "Error on WriteMBRToUSB"); IFFALSE_GOTOERROR(WriteBIOSBootPartitionToUSB(hPhysical, bootFilesPath, BytesPerSector), "Error on WriteBIOSBootPartitionToUSB"); @@ -4843,14 +4843,14 @@ bool CEndlessUsbToolDlg::CreateUSBPartitionLayout(HANDLE hPhysical, DWORD &Bytes LONGLONG partitionStart[EXPECTED_NUMBER_OF_PARTITIONS] = { EXFAT_PART_STARTING_SECTOR * BytesPerSector, ESP_PART_STARTING_SECTOR * BytesPerSector, - MBR_PART_STARTING_SECTOR * BytesPerSector + BIOS_BOOT_PART_STARTING_SECTOR * BytesPerSector }; LONGLONG partitionSize[EXPECTED_NUMBER_OF_PARTITIONS] = { // there is a 2nd copy of the GPT at the end of the disk so we // subtract the length here to avoid the operation failing DiskGeometry->DiskSize.QuadPart - gptLength - partitionStart[0], ESP_PART_LENGTH_BYTES, - MBR_PART_LENGTH_BYTES + BIOS_BOOT_PART_LENGTH_BYTES }; GUID partitionType[EXPECTED_NUMBER_OF_PARTITIONS] = { PARTITION_BASIC_DATA_GUID, @@ -5179,25 +5179,25 @@ bool CEndlessUsbToolDlg::WriteBIOSBootPartitionToUSB(HANDLE hPhysical, const CSt FUNCTION_ENTER; CString coreImgFilePath = bootFilesPath + LIVE_CORE_IMG_FILE; - unsigned char *endlessSBRData = (unsigned char *) malloc(MBR_PART_LENGTH_BYTES); + unsigned char *coreImg = (unsigned char *) malloc(BIOS_BOOT_PART_LENGTH_BYTES); bool retResult = false; size_t coreImgSize; DWORD coreImgBytesWritten = 0; LARGE_INTEGER lMbrPartitionStart; - lMbrPartitionStart.QuadPart = bytesPerSector * MBR_PART_STARTING_SECTOR; + lMbrPartitionStart.QuadPart = bytesPerSector * BIOS_BOOT_PART_STARTING_SECTOR; // Read core.img data and write it to USB drive - coreImgSize = ReadEntireFile(coreImgFilePath, endlessSBRData, MBR_PART_LENGTH_BYTES); + coreImgSize = ReadEntireFile(coreImgFilePath, coreImg, BIOS_BOOT_PART_LENGTH_BYTES); IFFALSE_GOTOERROR(coreImgSize, "Couldn't read core.img"); IFFALSE_GOTOERROR(SetFilePointerEx(hPhysical, lMbrPartitionStart, NULL, FILE_BEGIN), "Error setting handle position"); - IFFALSE_GOTOERROR(WriteFileWithRetry(hPhysical, endlessSBRData, coreImgSize, &coreImgBytesWritten, WRITE_RETRIES), + IFFALSE_GOTOERROR(WriteFileWithRetry(hPhysical, coreImg, coreImgSize, &coreImgBytesWritten, WRITE_RETRIES), "Error writing BIOS boot partition"); retResult = true; error: - safe_free(endlessSBRData); + safe_free(coreImg); return retResult; } From 90809190a2332147903f8bc7ae3ac73804973427 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 Oct 2017 16:41:39 +0100 Subject: [PATCH 08/20] Zero USB drive's partition tables more thoroughly Our fork of Rufus performs these steps the other way round but upstream commit 258a4f7ca071a3ff3e2a9cbe0995be5c951d48a3 explains that calling CREATE_DISK with PARTITION_STYLE_RAW leaves GPT artefacts on the disk, and can render it unusable on Windows. I've seen this happen! You can recover only by zeroing it more thoroughly (or writing a new partition table) on Linux or Mac. I have found that, if this step completes successfully, the rest of the process is much much more likely to work. Unfortunately this step fails pretty reliably for me when re-writing a combined USB; re-trying works so hooray. Tempted to put a retry loop around ClearMBRGPT(). I do not know why Rufus upstream does not have this problem. --- src/endless/EndlessUsbToolDlg.cpp | 17 ++++------------- src/format.c | 2 +- src/rufus.h | 1 + 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index c4ac7684c83..b4cfcba82a4 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -4697,13 +4697,9 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) CEndlessUsbToolDlg *dlg = (CEndlessUsbToolDlg*)param; DWORD DriveIndex = SelectedDrive.DeviceNumber; - BOOL result; - DWORD size; HANDLE hPhysical = INVALID_HANDLE_VALUE; - CREATE_DISK createDiskData; CString bootFilesPath = CEndlessUsbToolApp::TempFilePath(CString(BOOT_COMPONENTS_FOLDER)) + L"\\"; - CString usbFilesPath; - DWORD BytesPerSector = 0; + DWORD BytesPerSector = SelectedDrive.Geometry.BytesPerSector; CStringA eosliveDriveLetter, espDriveLetter; const char *cszEspDriveLetter; @@ -4719,18 +4715,13 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) UpdateProgress(OP_NEW_LIVE_CREATION, USB_PROGRESS_UNPACK_BOOT_ZIP); CHECK_IF_CANCELLED; - // initialize create disk data - memset(&createDiskData, 0, sizeof(createDiskData)); - createDiskData.PartitionStyle = PARTITION_STYLE_GPT; - createDiskData.Gpt.MaxPartitionCount = GPT_MAX_PARTITION_COUNT; - // get disk handle hPhysical = GetPhysicalHandle(DriveIndex, TRUE, TRUE); IFFALSE_GOTOERROR(hPhysical != INVALID_HANDLE_VALUE, "Error on acquiring disk handle."); - // initialize the disk - result = DeviceIoControl(hPhysical, IOCTL_DISK_CREATE_DISK, &createDiskData, sizeof(createDiskData), NULL, 0, &size, NULL); - IFFALSE_GOTOERROR(result != 0, "Error when calling IOCTL_DISK_CREATE_DISK"); + // erase any existing partition + IFFALSE_GOTOERROR(ClearMBRGPT(hPhysical, SelectedDrive.DiskSize, BytesPerSector, FALSE), "ClearMBRGPT failed"); + IFFALSE_GOTOERROR(DeletePartitions(hPhysical), "ErasePartitions failed"); // create partitions. IFFALSE_GOTOERROR(CreateUSBPartitionLayout(hPhysical, BytesPerSector), "Error on CreateUSBPartitionLayout"); diff --git a/src/format.c b/src/format.c index 91a2c9a7598..41d8bb7f2cd 100644 --- a/src/format.c +++ b/src/format.c @@ -842,7 +842,7 @@ static BOOL CheckDisk(char DriveLetter) return r; } -static BOOL ClearMBRGPT(HANDLE hPhysicalDrive, LONGLONG DiskSize, DWORD SectorSize, BOOL add1MB) +BOOL ClearMBRGPT(HANDLE hPhysicalDrive, LONGLONG DiskSize, DWORD SectorSize, BOOL add1MB) { BOOL r = FALSE; uint64_t i, last_sector = DiskSize/SectorSize; diff --git a/src/rufus.h b/src/rufus.h index 47bdc80b2b3..1b0cb6e1271 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -454,6 +454,7 @@ extern BOOL SetThreadAffinity(DWORD_PTR* thread_affinity, size_t num_threads); extern char* _printbits(size_t const size, void const * const ptr, int leading_zeroes); BOOL FormatPartition(const char *VolumeName, wchar_t *wFSType, wchar_t *partLabel, ULONG ulClusterSize); +BOOL ClearMBRGPT(HANDLE hPhysicalDrive, LONGLONG DiskSize, DWORD SectorSize, BOOL add1MB); DWORD WINAPI FormatThread(void* param); DWORD WINAPI SaveImageThread(void* param); From a739ab539934831fbbf70c38155179fb33ba56a8 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 Oct 2017 16:45:05 +0100 Subject: [PATCH 09/20] Write BIOS boot partition before partitioning drive There's some rationale in the comment. Some further rationale is that Rufus actually does the same thing when writing its NTFS-UEFI partition (a VFAT partition containing a UEFI bootloader that loads an NTFS driver, then chainloads the real bootloader from an NTFS partition). I believe that writing to the MBR causes Windows to rescan the drive, so we continue to do that just before we are about to sleep and wait for the logical volumes to re-appear. --- src/endless/EndlessUsbToolDlg.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index b4cfcba82a4..9d7f3758e18 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -4723,6 +4723,14 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) IFFALSE_GOTOERROR(ClearMBRGPT(hPhysical, SelectedDrive.DiskSize, BytesPerSector, FALSE), "ClearMBRGPT failed"); IFFALSE_GOTOERROR(DeletePartitions(hPhysical), "ErasePartitions failed"); + // write BIOS boot partition before partitioning the drive. + // https://msdn.microsoft.com/en-us/library/windows/desktop/aa365747%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396 says: + // A write on a disk handle will succeed if one of the following conditions is true: + // * The sectors to be written to do not fall within a volume's extents. + // * [some other conditions] + // Having zeroed the partition table, this first condition is surely true. + IFFALSE_GOTOERROR(WriteBIOSBootPartitionToUSB(hPhysical, bootFilesPath, BytesPerSector), "Error on WriteBIOSBootPartitionToUSB"); + // create partitions. IFFALSE_GOTOERROR(CreateUSBPartitionLayout(hPhysical, BytesPerSector), "Error on CreateUSBPartitionLayout"); @@ -4733,9 +4741,8 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) Sleep(200); // Radu: check if this is needed, that's what rufus does; I hate sync using sleep IFFALSE_PRINTERROR(WaitForLogical(DriveIndex), "Warning: Logical drive was not found!"); // We try to continue even if this fails, just in case - // Write MBR and BIOS boot partition to disk + // Write MBR to disk IFFALSE_GOTOERROR(WriteMBRToUSB(hPhysical, bootFilesPath), "Error on WriteMBRToUSB"); - IFFALSE_GOTOERROR(WriteBIOSBootPartitionToUSB(hPhysical, bootFilesPath, BytesPerSector), "Error on WriteBIOSBootPartitionToUSB"); safe_closehandle(hPhysical); From 799a899c57044ad14971ca9c06a3033bd0e0b34b Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Thu, 12 Oct 2017 16:40:54 +0100 Subject: [PATCH 10/20] Improve bled error handling Compared to our previous version of this change, this has a number of advantages: * handle negative return values from bled_uncompress_with_handles besides -1, since at least the unxz decompressor can return * log the error code returned * return FALSE from WriteDrive on error (even though no call site checks it) * use ERROR_WRITE_FAULT rather than ERROR_NO_MEDIA_IN_DRIVE, which seems closer to the likely truth * accepted upstreamed as 88631806da52d883f30c7feb656bdfc9afcc1235: > [cmp] propagate decompression errors from bled > > If, for example, you have a truncated gz-compressed file and try to > write it to disk, bled_uncompress_with_handles() will return an error. > Previously, this was not reported back to the user. --- src/format.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/format.c b/src/format.c index 41d8bb7f2cd..ebd562079ad 100644 --- a/src/format.c +++ b/src/format.c @@ -1502,6 +1502,7 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage) LARGE_INTEGER li; DWORD rSize, wSize, BufSize; uint64_t wb, target_size = hSourceImage?img_report.projected_size:SelectedDrive.DiskSize; + int64_t bled_ret; uint8_t *buffer = NULL, *aligned_buffer; int i; @@ -1512,19 +1513,16 @@ static BOOL WriteDrive(HANDLE hPhysicalDrive, HANDLE hSourceImage) LastRefresh = 0; if (img_report.compression_type != BLED_COMPRESSION_NONE) { - uprintf("Writing Compressed Image..."); + uprintf("Writing compressed image..."); bled_init(_uprintf, update_progress, &FormatStatus); -#ifndef ENDLESSUSB_TOOL - bled_uncompress_with_handles(hSourceImage, hPhysicalDrive, img_report.compression_type); -#else -/// RADU: propose this change to rufus - if (-1 == bled_uncompress_with_handles(hSourceImage, hPhysicalDrive, img_report.compression_type)) { - if (SCODE_CODE(FormatStatus) != ERROR_CANCELLED) { - FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_NO_MEDIA_IN_DRIVE; - } - } -#endif // !ENDLESSUSB_TOOL + bled_ret = bled_uncompress_with_handles(hSourceImage, hPhysicalDrive, img_report.compression_type); bled_exit(); + if ((bled_ret < 0) && (SCODE_CODE(FormatStatus) != ERROR_CANCELLED)) { + // Unfortunately, different compression backends return different negative error codes + uprintf("Could not write compressed image: %" PRIi64, bled_ret); + FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_WRITE_FAULT; + goto out; + } } else { uprintf(hSourceImage?"Writing Image...":"Zeroing drive..."); // Our buffer size must be a multiple of the sector size From 2191fb52e9e21e6f81e620db53e69eeb750e3237 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 18 Oct 2017 10:33:13 +0100 Subject: [PATCH 11/20] [ui] improve Windows format prompt autoclose Manually-applied cherry-pick of upstream commit 9dd06e93bc8aed921b11bed4ab65e460ed4a7b06. Signed-off-by: Will Thompson --- src/format.c | 45 ------------------------- src/msapi_utf8.h | 24 ++++++++++++++ src/rufus.c | 5 +++ src/rufus.h | 4 +++ src/stdfn.c | 60 +++++++++++++++++++++++++++++++++ src/stdlg.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 178 insertions(+), 46 deletions(-) diff --git a/src/format.c b/src/format.c index ebd562079ad..88c55f82323 100644 --- a/src/format.c +++ b/src/format.c @@ -1440,50 +1440,6 @@ static BOOL SetupWinToGo(const char* drive_name, BOOL use_ms_efi) return TRUE; } -/* - * Detect if a Windows Format prompt is active, by enumerating the - * whole Windows tree and looking for the relevant popup - */ -static BOOL CALLBACK FormatPromptCallback(HWND hWnd, LPARAM lParam) -{ - char str_buf[MAX_PATH]; - HWND *hFound = (HWND*)lParam; - static const char* security_string = "Microsoft Windows"; - - // The format prompt has the popup window style - if (GetWindowLong(hWnd, GWL_STYLE) & WS_POPUPWINDOW) { - str_buf[0] = 0; - GetWindowTextA(hWnd, str_buf, MAX_PATH); - str_buf[MAX_PATH-1] = 0; - if (safe_strcmp(str_buf, security_string) == 0) { - *hFound = hWnd; - return TRUE; - } - } - return TRUE; -} - -/* - * When we format a drive that doesn't have any existing partitions, we can't lock it - * prior to partitioning, which means that Windows will display a "You need to format the - * disk in drive X: before you can use it'. You will also get that popup if you start a - * bad blocks check and cancel it before it completes. We have to close that popup manually. - */ -static DWORD WINAPI CloseFormatPromptThread(LPVOID param) { - HWND hFormatPrompt; - - while(format_op_in_progress) { - hFormatPrompt = NULL; - EnumChildWindows(GetDesktopWindow(), FormatPromptCallback, (LPARAM)&hFormatPrompt); - if (hFormatPrompt != NULL) { - SendMessage(hFormatPrompt, WM_COMMAND, (WPARAM)IDCANCEL, (LPARAM)0); - uprintf("Closed Windows format prompt\n"); - } - Sleep(100); - } - ExitThread(0); -} - static void update_progress(const uint64_t processed_bytes) { if (_GetTickCount64() > LastRefresh + MAX_REFRESH) { @@ -1728,7 +1684,6 @@ DWORD WINAPI FormatThread(void* param) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE; goto out; } - CreateThread(NULL, 0, CloseFormatPromptThread, NULL, 0, NULL); if (zero_drive) { WriteDrive(hPhysicalDrive, NULL); diff --git a/src/msapi_utf8.h b/src/msapi_utf8.h index 3377ca3ef17..0fc75e7b1c7 100644 --- a/src/msapi_utf8.h +++ b/src/msapi_utf8.h @@ -223,6 +223,21 @@ static __inline int MessageBoxExU(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UI return ret; } +static __inline int LoadStringU(HINSTANCE hInstance, UINT uID, LPSTR lpBuffer, int nBufferMax) +{ + int ret; + DWORD err = ERROR_INVALID_DATA; + walloc(lpBuffer, nBufferMax); + ret = LoadStringW(hInstance, uID, wlpBuffer, nBufferMax); + err = GetLastError(); + if ((ret > 0) && ((ret = wchar_to_utf8_no_alloc(wlpBuffer, lpBuffer, nBufferMax)) == 0)) { + err = GetLastError(); + } + wfree(lpBuffer); + SetLastError(err); + return ret; +} + static __inline int DrawTextU(HDC hDC, LPCSTR lpText, int nCount, LPRECT lpRect, UINT uFormat) { int ret; @@ -863,6 +878,15 @@ static __inline int _mkdirU(const char* dirname) return ret; } +static __inline HMODULE LoadLibraryU(LPCSTR lpFileName) +{ + HMODULE h; + wconvert(lpFileName); + h = LoadLibraryW(wlpFileName); + wfree(lpFileName); + return h; +} + #ifdef __cplusplus } #endif diff --git a/src/rufus.c b/src/rufus.c index e2af2f716fc..313a751e652 100644 --- a/src/rufus.c +++ b/src/rufus.c @@ -3056,6 +3056,10 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine } } + // Set the hook to automatically close Windows' "You need to format the disk in drive..." prompt + if (!SetFormatPromptHook()) + uprintf("Warning:Could not set 'Format Disk' prompt auto-close"); + ShowWindow(hDlg, SW_SHOWNORMAL); UpdateWindow(hDlg); @@ -3268,6 +3272,7 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine if ((!external_loc_file) && (loc_file[0] != 0)) DeleteFileU(loc_file); DestroyAllTooltips(); + ClrFormatPromptHook(); exit_localization(); safe_free(image_path); safe_free(locale_name); diff --git a/src/rufus.h b/src/rufus.h index 1b0cb6e1271..5d1e246607a 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -452,6 +452,10 @@ extern BOOL SetThreadAffinity(DWORD_PTR* thread_affinity, size_t num_threads); #define printbits(x) _printbits(sizeof(x), &x, 0) #define printbitslz(x) _printbits(sizeof(x), &x, 1) extern char* _printbits(size_t const size, void const * const ptr, int leading_zeroes); +extern BOOL IsCurrentProcessElevated(void); +extern char* GetCurrentMUI(void); +extern BOOL SetFormatPromptHook(void); +extern void ClrFormatPromptHook(void); BOOL FormatPartition(const char *VolumeName, wchar_t *wFSType, wchar_t *partLabel, ULONG ulClusterSize); BOOL ClearMBRGPT(HANDLE hPhysicalDrive, LONGLONG DiskSize, DWORD SectorSize, BOOL add1MB); diff --git a/src/stdfn.c b/src/stdfn.c index 47648b43b81..059a31f53da 100644 --- a/src/stdfn.c +++ b/src/stdfn.c @@ -36,6 +36,8 @@ extern BOOL usb_debug; // For uuprintf int nWindowsVersion = WINDOWS_UNDEFINED; char WindowsVersionStr[128] = "Windows "; +PF_TYPE_DECL(WINAPI, int, LCIDToLocaleName, (LCID, LPWSTR, int, DWORD)); + /* * Hash table functions - modified From glibc 2.3.2: * [Aho,Sethi,Ullman] Compilers: Principles, Techniques and Tools, 1986 @@ -847,3 +849,61 @@ BOOL SetThreadAffinity(DWORD_PTR* thread_affinity, size_t num_threads) uuprintf(" thr_%d:\t%s", i, printbitslz(thread_affinity[i])); return TRUE; } + +/* + * Returns true if: + * 1. The OS supports UAC, UAC is on, and the current process runs elevated, or + * 2. The OS doesn't support UAC or UAC is off, and the process is being run by a member of the admin group + */ +BOOL IsCurrentProcessElevated(void) +{ + BOOL r = FALSE; + DWORD size; + HANDLE token = INVALID_HANDLE_VALUE; + TOKEN_ELEVATION te; + SID_IDENTIFIER_AUTHORITY auth = { SECURITY_NT_AUTHORITY }; + PSID psid; + + if (ReadRegistryKey32(REGKEY_HKLM, "Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\EnableLUA") == 1) { + uprintf("Note: UAC is active"); + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { + uprintf("Could not get current process token: %s", WindowsErrorString()); + goto out; + } + if (!GetTokenInformation(token, TokenElevation, &te, sizeof(te), &size)) { + uprintf("Could not get token information: %s", WindowsErrorString()); + goto out; + } + r = (te.TokenIsElevated != 0); + } + else { + uprintf("Note: UAC is either disabled or not available"); + if (!AllocateAndInitializeSid(&auth, 2, SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &psid)) + goto out; + if (!CheckTokenMembership(NULL, psid, &r)) + r = FALSE; + FreeSid(psid); + } + +out: + safe_closehandle(token); + return r; +} + +char* GetCurrentMUI(void) +{ + static char mui_str[LOCALE_NAME_MAX_LENGTH]; + wchar_t wmui_str[LOCALE_NAME_MAX_LENGTH]; + + // Of course LCIDToLocaleName() is not available on XP... grrrr! + PF_INIT(LCIDToLocaleName, kernel32); + + if ( (pfLCIDToLocaleName != NULL) && + (pfLCIDToLocaleName(GetUserDefaultUILanguage(), wmui_str, LOCALE_NAME_MAX_LENGTH, 0) > 0) ) { + wchar_to_utf8_no_alloc(wmui_str, mui_str, LOCALE_NAME_MAX_LENGTH); + } else { + safe_strcpy(mui_str, LOCALE_NAME_MAX_LENGTH, "en-US"); + } + return mui_str; +} diff --git a/src/stdlg.c b/src/stdlg.c index aa7514d5d53..74d4910b8ec 100644 --- a/src/stdlg.c +++ b/src/stdlg.c @@ -63,6 +63,8 @@ static BOOL notification_is_question; static const notification_info* notification_more_info; static BOOL settings_commcheck = FALSE; static WNDPROC update_original_proc = NULL; +static HWINEVENTHOOK fp_weh = NULL; +static char *fp_title_str = "Microsoft Windows", *fp_button_str = "Format disk"; extern loc_cmd* selected_locale; @@ -1727,4 +1729,86 @@ INT_PTR MyDialogBox(HINSTANCE hInstance, int Dialog_ID, HWND hWndParent, DLGPROC safe_free(rcTemplate); return ret; } -#endif // !ENDLESSUSB_TOOL \ No newline at end of file +#endif // !ENDLESSUSB_TOOL + +/* + * The following function calls are used to automatically detect and close the native + * Windows format prompt "You must format the disk in drive X:". To do that, we use an + * event hook that gets triggered whenever a window is placed in the foreground. + * In that hook, we look for a dialog that has style WS_POPUPWINDOW and has the relevant + * title. However, because the title in itself is too generic (the expectation is that + * it will be "Microsoft Windows") we also enumerate all the child controls from that + * prompt, using another callback, until we find one that contains the text we expect + * for the "Format disk" button. + * Oh, and since all of these strings are localized, we must first pick them up from + * the relevant mui (something like "C:\Windows\System32\en-GB\shell32.dll.mui") + */ +static BOOL CALLBACK FormatPromptCallback(HWND hWnd, LPARAM lParam) +{ + char str[128]; + BOOL *found = (BOOL*)lParam; + + if (GetWindowTextU(hWnd, str, sizeof(str)) == 0) + return TRUE; + if (safe_strcmp(str, fp_button_str) == 0) + *found = TRUE; + return TRUE; +} + +static void CALLBACK FormatPromptHook(HWINEVENTHOOK hWinEventHook, DWORD Event, HWND hWnd, LONG idObject, LONG idChild, DWORD dwEventThread, DWORD dwmsEventTime) +{ + char str[128]; + BOOL found; + + if (Event == EVENT_SYSTEM_FOREGROUND) { + if (GetWindowLong(hWnd, GWL_STYLE) & WS_POPUPWINDOW) { + str[0] = 0; + GetWindowTextU(hWnd, str, sizeof(str)); + if (safe_strcmp(str, fp_title_str) == 0) { + found = FALSE; + EnumChildWindows(hWnd, FormatPromptCallback, (LPARAM)&found); + if (found) { + SendMessage(hWnd, WM_COMMAND, (WPARAM)IDCANCEL, (LPARAM)0); + uprintf("Closed Windows format prompt"); + } + } + } + } +} + +BOOL SetFormatPromptHook(void) +{ + HMODULE mui_lib; + char mui_path[MAX_PATH]; + static char title_str[128], button_str[128]; + + if (fp_weh != NULL) + return TRUE; // No need to set again if active + + // Fetch the localized strings in the relevant + static_sprintf(mui_path, "%s\\%s\\shell32.dll.mui", system_dir, GetCurrentMUI()); + mui_lib = LoadLibraryU(mui_path); + if (mui_lib != NULL) { + // 4097 = "You need to format the disk in drive %c: before you can use it." (dialog text) + // 4125 = "Microsoft Windows" (dialog title) + // 4126 = "Format disk" (button) + if (LoadStringU(mui_lib, 4125, title_str, sizeof(title_str)) > 0) + fp_title_str = title_str; + else + uprintf("Warning: Could not locate localized format prompt title string in '%s': %s", mui_path, WindowsErrorString()); + if (LoadStringU(mui_lib, 4126, button_str, sizeof(button_str)) > 0) + fp_button_str = button_str; + else + uprintf("Warning: Could not locate localized format prompt button string in '%s': %s", mui_path, WindowsErrorString()); + FreeLibrary(mui_lib); + } + + fp_weh = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, NULL, + FormatPromptHook, 0, 0, WINEVENT_OUTOFCONTEXT | WINEVENT_SKIPOWNPROCESS); + return (fp_weh != NULL); +} + +void ClrFormatPromptHook(void) { + UnhookWinEvent(fp_weh); + fp_weh = NULL; +} \ No newline at end of file From efca6db443f31a3f512075263e94772d36ab74f8 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Wed, 18 Oct 2017 13:05:12 +0100 Subject: [PATCH 12/20] Close Windows' 'Format Disk' prompts --- src/endless/EndlessUsbToolDlg.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index 9d7f3758e18..74f4945cab2 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -1395,6 +1395,9 @@ LRESULT CEndlessUsbToolDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lPara BOOL result = (BOOL)wParam; m_operationThread = INVALID_HANDLE_VALUE; if (result) { + IFFALSE_PRINTERROR(SetFormatPromptHook(), + "Could not set 'Format Disk' prompt auto-close"); + if (IsDualBootOrCombinedUsb()) { m_cancelImageUnpack = 0; if (m_selectedInstallMethod == InstallMethod_t::CombinedUsb) { @@ -1437,6 +1440,7 @@ LRESULT CEndlessUsbToolDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lPara m_operationThread = INVALID_HANDLE_VALUE; m_currentStep = OP_NO_OPERATION_IN_PROGRESS; + ClrFormatPromptHook(); EnableHibernate(); if (m_selectedInstallMethod != InstallMethod_t::InstallDualBoot) ChangeDriveAutoRunAndMount(false); From 005ba2f86a9b9a023fe96980db4c93dcd2fcd585 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 17 Oct 2017 16:18:29 +0100 Subject: [PATCH 13/20] Remove drive letters for disk to be written --- src/endless/EndlessUsbToolDlg.cpp | 35 +++++++++++++++++++++++++++++++ src/endless/EndlessUsbToolDlg.h | 1 + 2 files changed, 36 insertions(+) diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index 74f4945cab2..9a1d3c633f5 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -4723,6 +4723,10 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) hPhysical = GetPhysicalHandle(DriveIndex, TRUE, TRUE); IFFALSE_GOTOERROR(hPhysical != INVALID_HANDLE_VALUE, "Error on acquiring disk handle."); + // Remove drive letters for existing volumes + IFFALSE_GOTOERROR(DeleteMountpointsForDrive(DriveIndex), "Couldn't delete mountpoints"); + CHECK_IF_CANCELLED; + // erase any existing partition IFFALSE_GOTOERROR(ClearMBRGPT(hPhysical, SelectedDrive.DiskSize, BytesPerSector, FALSE), "ClearMBRGPT failed"); IFFALSE_GOTOERROR(DeletePartitions(hPhysical), "ErasePartitions failed"); @@ -4812,6 +4816,37 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) return 0; } +// Lifted from Rufus' FormatThread +bool CEndlessUsbToolDlg::DeleteMountpointsForDrive(DWORD DriveIndex) +{ + FUNCTION_ENTER; + + char drive_name[] = "?:\\"; + char drive_letters[27]; + int i; + + IFFALSE_RETURN_VALUE(GetDriveLetters(DriveIndex, drive_letters), + "Failed to get drive letters", false); + + if (drive_letters[0] == 0) { + uprintf("No drive letters were assigned"); + return true; + } + + // Unmount all mounted volumes that belong to this drive + // Do it in reverse so that we always end on the first volume letter + for (i=(int)safe_strlen(drive_letters); i>0; i--) { + drive_name[0] = drive_letters[i - 1]; + + // TODO: check image is not on this drive + uprintf("Deleting mountpoint %s", drive_name); + // Try to continue on error. We will fail later if this causes an issue. + IFFALSE_PRINTERROR(DeleteVolumeMountPointA(drive_name), "Failed to delete mountpoint"); + } + + return true; +} + bool CEndlessUsbToolDlg::CreateUSBPartitionLayout(HANDLE hPhysical, DWORD &BytesPerSector) { diff --git a/src/endless/EndlessUsbToolDlg.h b/src/endless/EndlessUsbToolDlg.h index 8787b2fe632..b921fe15979 100644 --- a/src/endless/EndlessUsbToolDlg.h +++ b/src/endless/EndlessUsbToolDlg.h @@ -399,6 +399,7 @@ class CEndlessUsbToolDlg : public CDHtmlDialog void ChangeDriveAutoRunAndMount(bool setEndlessValues); static DWORD WINAPI CreateUSBStick(LPVOID param); + static bool DeleteMountpointsForDrive(DWORD DriveIndex); static bool CreateUSBPartitionLayout(HANDLE hPhysical, DWORD &BytesPerSector); static bool FormatFirstPartitionOnDrive(DWORD DriveIndex, const wchar_t *kFSType, ULONG ulClusterSize, HANDLE cancelEvent, const wchar_t *kPartLabel); static bool FormatPartitionWithRetry(const char *partition, const wchar_t *kFSType, ULONG ulClusterSize, HANDLE cancelEvent, const wchar_t *kPartLabel); From f6cca3018f0f361c8a31640430a51cd56fbadbf1 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Wed, 18 Oct 2017 13:18:45 +0100 Subject: [PATCH 14/20] Lock and disappear logical volume before formatting This appears to improve the reliability of the process (and it's what upstream does). --- src/endless/EndlessUsbToolDlg.cpp | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index 9a1d3c633f5..44f15f2f098 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -4702,6 +4702,7 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) CEndlessUsbToolDlg *dlg = (CEndlessUsbToolDlg*)param; DWORD DriveIndex = SelectedDrive.DeviceNumber; HANDLE hPhysical = INVALID_HANDLE_VALUE; + HANDLE hLogicalVolume = INVALID_HANDLE_VALUE; CString bootFilesPath = CEndlessUsbToolApp::TempFilePath(CString(BOOT_COMPONENTS_FOLDER)) + L"\\"; DWORD BytesPerSector = SelectedDrive.Geometry.BytesPerSector; CStringA eosliveDriveLetter, espDriveLetter; @@ -4727,6 +4728,18 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) IFFALSE_GOTOERROR(DeleteMountpointsForDrive(DriveIndex), "Couldn't delete mountpoints"); CHECK_IF_CANCELLED; + // Lock and disappear the logical volume, if any, as per FormatThread. + // TODO: what if there's more than one logical volume? + hLogicalVolume = GetLogicalHandle(DriveIndex, FALSE, TRUE); + IFFALSE_GOTOERROR(hLogicalVolume != INVALID_HANDLE_VALUE, "Could not lock volume"); + if (hLogicalVolume == NULL) { + // NULL is returned for cases where the drive is not yet partitioned + uprintf("Drive does not appear to be partitioned\n"); + } else if (!UnmountVolume(hLogicalVolume)) { + uprintf("Trying to continue regardless...\n"); + } + CHECK_IF_CANCELLED; + // erase any existing partition IFFALSE_GOTOERROR(ClearMBRGPT(hPhysical, SelectedDrive.DiskSize, BytesPerSector, FALSE), "ClearMBRGPT failed"); IFFALSE_GOTOERROR(DeletePartitions(hPhysical), "ErasePartitions failed"); @@ -4742,13 +4755,19 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) // create partitions. IFFALSE_GOTOERROR(CreateUSBPartitionLayout(hPhysical, BytesPerSector), "Error on CreateUSBPartitionLayout"); - CHECK_IF_CANCELLED; + if (hLogicalVolume != NULL && hLogicalVolume != INVALID_HANDLE_VALUE) { + uprintf("Closing old volume"); + IFFALSE_GOTOERROR(CloseHandle(hLogicalVolume), "Could not close old volume"); + hLogicalVolume = INVALID_HANDLE_VALUE; + } // Wait for the logical drive we just created to appear uprintf("Waiting for logical drive to reappear...\n"); Sleep(200); // Radu: check if this is needed, that's what rufus does; I hate sync using sleep IFFALSE_PRINTERROR(WaitForLogical(DriveIndex), "Warning: Logical drive was not found!"); // We try to continue even if this fails, just in case + CHECK_IF_CANCELLED; + // Write MBR to disk IFFALSE_GOTOERROR(WriteMBRToUSB(hPhysical, bootFilesPath), "Error on WriteMBRToUSB"); @@ -4811,7 +4830,8 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) } RemoveNonEmptyDirectory(bootFilesPath); - safe_closehandle(hPhysical); + safe_unlockclose(hLogicalVolume); + safe_unlockclose(hPhysical); dlg->PostMessage(WM_FINISHED_ALL_OPERATIONS, 0, 0); return 0; } From 17abfdb35d69cd61bf3b63a4fb803ac672def191 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Fri, 20 Oct 2017 14:55:19 +0100 Subject: [PATCH 15/20] Don't needlessly change volume mount point We do not care where the image partition is mounted; we just want it mounted *somewhere*. Remounting it is relatively harmless but causes Windows to pop up more spurious Explorer windows. --- src/drive.c | 52 +++++++++++++++++++++++++++++++ src/drive.h | 1 + src/endless/EndlessUsbToolDlg.cpp | 5 ++- 3 files changed, 55 insertions(+), 3 deletions(-) diff --git a/src/drive.c b/src/drive.c index 2eaada09ad4..7ff2ecee90b 100644 --- a/src/drive.c +++ b/src/drive.c @@ -888,6 +888,58 @@ BOOL MountVolume(char* drive_name, char *drive_guid) return TRUE; } +/* + * Mount the volume identified by drive_guid on a drive letter, if it is not already, and return the mount point in drive_guid. + * drive_guid should be initialized to "?:\"; the first character will be overwritten with the mounted drive letter. + */ +BOOL EnsureVolumeMounted(char* drive_name, char *drive_guid) +{ + char mounted_guid[52]; // You need at least 51 characters on XP + char mounted_letter[16] = {0}; + DWORD size; + + if (drive_name[0] != '?') + return FALSE; + + // For fixed disks, Windows may already have remounted the volume. + if ( (GetVolumePathNamesForVolumeNameA(drive_guid, mounted_letter, sizeof(mounted_letter), &size)) + && (size > 1) ) { + uprintf("Volume is already mounted at %c", mounted_letter[0]); + drive_name[0] = mounted_letter[0]; + return TRUE; + } + + drive_name[0] = GetUnusedDriveLetter(); + if (drive_name[0] == 0) { + uprintf("Could not find an unused drive letter"); + return FALSE; + } + + if (SetVolumeMountPointA(drive_name, drive_guid)) { + uprintf("%s mounted as %s", drive_guid, drive_name); + return TRUE; + } else { + // If the OS mounted something on that letter in parallel, this operation can fail + // with ERROR_DIR_NOT_EMPTY. If that's the case, just check that mountpoints match + if (GetLastError() == ERROR_DIR_NOT_EMPTY) { + if (!GetVolumeNameForVolumeMountPointA(drive_name, mounted_guid, sizeof(mounted_guid))) { + uprintf("%s already mounted, but volume GUID could not be checked: %s", + drive_name, WindowsErrorString()); + return FALSE; + } + if (safe_strcmp(drive_guid, mounted_guid) != 0) { + uprintf("%s already mounted, but volume GUID doesn't match. Hoped for %s, got %s", + drive_name, drive_guid, mounted_guid); + return FALSE; + } + uprintf("%s was already mounted as %s\n", drive_guid, drive_name); + return TRUE; + } else { + return FALSE; + } + } +} + /* * Mount partition #part_nr, residing on the same disk as drive_name (which must be * of the form "X:" with no trailing slash) to an available diff --git a/src/drive.h b/src/drive.h index dd6de5e952d..25f075adaf8 100644 --- a/src/drive.h +++ b/src/drive.h @@ -93,6 +93,7 @@ BOOL AnalyzePBR(HANDLE hLogicalVolume); BOOL GetDrivePartitionData(DWORD DriveIndex, char* FileSystemName, DWORD FileSystemNameSize, BOOL bSilent); BOOL UnmountVolume(HANDLE hDrive); BOOL MountVolume(char* drive_name, char *drive_guid); +BOOL EnsureVolumeMounted(char* drive_name, char *drive_guid); BOOL AltUnmountVolume(const char* drive_name); char* AltMountVolume(const char* drive_name, uint8_t part_nr); BOOL RemountVolume(char* drive_name); diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index 44f15f2f098..831fea6ddab 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -5018,9 +5018,8 @@ bool CEndlessUsbToolDlg::MountFirstPartitionOnDrive(DWORD DriveIndex, CStringA & // Mount partition char drive_name[] = "?:\\"; - drive_name[0] = GetUnusedDriveLetter(); - IFFALSE_GOTOERROR(drive_name[0] != 0, "Could not find an unused drive letter"); - IFFALSE_GOTOERROR(MountVolume(drive_name, guid_volume), "Could not mount volume."); + IFFALSE_GOTOERROR(EnsureVolumeMounted(drive_name, guid_volume), "Could not mount volume."); + IFFALSE_GOTOERROR(drive_name[0] != 0, "EnsureVolumeMounted succeeded but did not return a drive name..."); driveLetter = drive_name; returnValue = true; From dafde9756c681e4e593225573c53cf86e1c81309 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Wed, 25 Oct 2017 15:21:04 +0100 Subject: [PATCH 16/20] ErrorOccured: ensure all error codes are handled If not, a generic error is shown, which is not the end of the world. But it's nice to get a bit of computer-aided assistance to do better. --- src/endless/EndlessUsbToolDlg.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index 831fea6ddab..7cb2ea99cdb 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -1717,6 +1717,9 @@ void CEndlessUsbToolDlg::ErrorOccured(ErrorCause_t errorCause) uint32_t recoverButtonMsgId = 0, suggestionMsgId = 0, headlineMsgId = IsCoding() ? MSG_381 : MSG_370; bool driveLetterInHeading = false; +// Require all error causes to be handled +#pragma warning( push ) +#pragma warning( error : 4061 ) switch (errorCause) { case ErrorCause_t::ErrorCauseDownloadFailed: recoverButtonMsgId = MSG_RECOVER_RESUME; @@ -1740,6 +1743,8 @@ void CEndlessUsbToolDlg::ErrorOccured(ErrorCause_t errorCause) case ErrorCause_t::ErrorCauseGeneric: case ErrorCause_t::ErrorCauseWriteFailed: case ErrorCause_t::ErrorCauseSuspended: // TODO: new string here + case ErrorCause_t::ErrorCauseCantUnpackBootZip: + case ErrorCause_t::ErrorCauseInstallEosldrFailed: recoverButtonMsgId = MSG_RECOVER_TRY_AGAIN; suggestionMsgId = m_selectedInstallMethod == InstallMethod_t::InstallDualBoot ? (IsCoding() ? MSG_385 : MSG_358) @@ -1768,10 +1773,16 @@ void CEndlessUsbToolDlg::ErrorOccured(ErrorCause_t errorCause) // TODO: new string here; or, better, eliminate this failure mode suggestionMsgId = MSG_358; break; + case ErrorCause_t::ErrorCauseNonEndlessMBR: + case ErrorCause_t::ErrorCauseUninstallEosldrFailed: + uprintf("Uninstall-specific error cause %ls", ErrorCauseToStr(errorCause)); + break; + case ErrorCause_t::ErrorCauseNone: default: uprintf("Unhandled error cause %ls(%d)", ErrorCauseToStr(errorCause), errorCause); break; } +#pragma warning( pop ) // Update the error button text if it's a "recoverable" error case or hide it otherwise if (recoverButtonMsgId != 0) { From 449c5eca4cec8bb11334e0fff0e9b2e1e95974ed Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 10 Oct 2017 17:33:59 +0100 Subject: [PATCH 17/20] Add very specific error codes for USB creation This will allow us to see from analytics data what errors occur in the wild, and the relative impact of each. --- src/endless/EndlessUsbToolDlg.cpp | 62 +++++++++++++++++++++++++++---- src/endless/EndlessUsbToolDlg.h | 12 ++++++ 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index 7cb2ea99cdb..99f21d0d10d 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -418,6 +418,18 @@ static LPCTSTR ErrorCauseToStr(ErrorCause_t errorCause) TOSTR(ErrorCauseInstallEosldrFailed); TOSTR(ErrorCauseUninstallEosldrFailed); TOSTR(ErrorCauseCantUnpackBootZip); + TOSTR(ErrorCauseGetPhysicalHandleFailed); + TOSTR(ErrorCauseDisappearingExistingVolumesFailed); + TOSTR(ErrorCauseErasePartitionsFailed); + TOSTR(ErrorCauseWriteBiosBootFailed); + TOSTR(ErrorCauseCreatePartitionsFailed); + TOSTR(ErrorCauseWriteMBRFailed); + TOSTR(ErrorCauseFormatExfatFailed); + TOSTR(ErrorCauseMountExfatFailed); + TOSTR(ErrorCauseMountESPFailed); + TOSTR(ErrorCauseFormatESPFailed); + TOSTR(ErrorCausePopulateESPFailed); + TOSTR(ErrorCausePopulateExfatFailed); default: return _T("Error Cause Unknown"); } } @@ -1744,7 +1756,21 @@ void CEndlessUsbToolDlg::ErrorOccured(ErrorCause_t errorCause) case ErrorCause_t::ErrorCauseWriteFailed: case ErrorCause_t::ErrorCauseSuspended: // TODO: new string here case ErrorCause_t::ErrorCauseCantUnpackBootZip: + // Dual-boot errors case ErrorCause_t::ErrorCauseInstallEosldrFailed: + // Combined USB errors + case ErrorCause_t::ErrorCauseGetPhysicalHandleFailed: + case ErrorCause_t::ErrorCauseDisappearingExistingVolumesFailed: + case ErrorCause_t::ErrorCauseErasePartitionsFailed: + case ErrorCause_t::ErrorCauseWriteBiosBootFailed: + case ErrorCause_t::ErrorCauseCreatePartitionsFailed: + case ErrorCause_t::ErrorCauseWriteMBRFailed: + case ErrorCause_t::ErrorCauseFormatExfatFailed: + case ErrorCause_t::ErrorCauseMountExfatFailed: + case ErrorCause_t::ErrorCauseMountESPFailed: + case ErrorCause_t::ErrorCauseFormatESPFailed: + case ErrorCause_t::ErrorCausePopulateESPFailed: + case ErrorCause_t::ErrorCausePopulateExfatFailed: recoverButtonMsgId = MSG_RECOVER_TRY_AGAIN; suggestionMsgId = m_selectedInstallMethod == InstallMethod_t::InstallDualBoot ? (IsCoding() ? MSG_385 : MSG_358) @@ -3727,6 +3753,19 @@ HRESULT CEndlessUsbToolDlg::OnRecoverErrorButtonClicked(IHTMLElement* pElement) StartInstallationProcess(); break; case ErrorCause_t::ErrorCauseWriteFailed: + case ErrorCause_t::ErrorCauseCantUnpackBootZip: + case ErrorCause_t::ErrorCauseGetPhysicalHandleFailed: + case ErrorCause_t::ErrorCauseDisappearingExistingVolumesFailed: + case ErrorCause_t::ErrorCauseErasePartitionsFailed: + case ErrorCause_t::ErrorCauseWriteBiosBootFailed: + case ErrorCause_t::ErrorCauseCreatePartitionsFailed: + case ErrorCause_t::ErrorCauseWriteMBRFailed: + case ErrorCause_t::ErrorCauseFormatExfatFailed: + case ErrorCause_t::ErrorCauseMountExfatFailed: + case ErrorCause_t::ErrorCauseMountESPFailed: + case ErrorCause_t::ErrorCauseFormatESPFailed: + case ErrorCause_t::ErrorCausePopulateESPFailed: + case ErrorCause_t::ErrorCausePopulateExfatFailed: OnSelectFileNextClicked(NULL); break; case ErrorCause_t::ErrorCauseVerificationFailed: @@ -4718,24 +4757,24 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) DWORD BytesPerSector = SelectedDrive.Geometry.BytesPerSector; CStringA eosliveDriveLetter, espDriveLetter; const char *cszEspDriveLetter; + ErrorCause errorCause = ErrorCause::ErrorCauseWriteFailed; UpdateProgress(OP_NEW_LIVE_CREATION, 0); // Unpack boot components - if (!UnpackBootComponents(dlg->m_bootArchive, bootFilesPath)) { - PRINT_ERROR_MSG("Error unpacking boot components."); - dlg->m_lastErrorCause = ErrorCauseCantUnpackBootZip; - goto error; - } + errorCause = ErrorCauseCantUnpackBootZip; + IFFALSE_GOTOERROR(UnpackBootComponents(dlg->m_bootArchive, bootFilesPath), "Error unpacking boot components."); UpdateProgress(OP_NEW_LIVE_CREATION, USB_PROGRESS_UNPACK_BOOT_ZIP); CHECK_IF_CANCELLED; // get disk handle + errorCause = ErrorCauseGetPhysicalHandleFailed; hPhysical = GetPhysicalHandle(DriveIndex, TRUE, TRUE); IFFALSE_GOTOERROR(hPhysical != INVALID_HANDLE_VALUE, "Error on acquiring disk handle."); // Remove drive letters for existing volumes + errorCause = ErrorCauseDisappearingExistingVolumesFailed; IFFALSE_GOTOERROR(DeleteMountpointsForDrive(DriveIndex), "Couldn't delete mountpoints"); CHECK_IF_CANCELLED; @@ -4752,6 +4791,7 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) CHECK_IF_CANCELLED; // erase any existing partition + errorCause = ErrorCauseErasePartitionsFailed; IFFALSE_GOTOERROR(ClearMBRGPT(hPhysical, SelectedDrive.DiskSize, BytesPerSector, FALSE), "ClearMBRGPT failed"); IFFALSE_GOTOERROR(DeletePartitions(hPhysical), "ErasePartitions failed"); @@ -4761,9 +4801,11 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) // * The sectors to be written to do not fall within a volume's extents. // * [some other conditions] // Having zeroed the partition table, this first condition is surely true. + errorCause = ErrorCauseWriteBiosBootFailed; IFFALSE_GOTOERROR(WriteBIOSBootPartitionToUSB(hPhysical, bootFilesPath, BytesPerSector), "Error on WriteBIOSBootPartitionToUSB"); // create partitions. + errorCause = ErrorCauseCreatePartitionsFailed; IFFALSE_GOTOERROR(CreateUSBPartitionLayout(hPhysical, BytesPerSector), "Error on CreateUSBPartitionLayout"); if (hLogicalVolume != NULL && hLogicalVolume != INVALID_HANDLE_VALUE) { @@ -4780,6 +4822,7 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) CHECK_IF_CANCELLED; // Write MBR to disk + errorCause = ErrorCauseWriteMBRFailed; IFFALSE_GOTOERROR(WriteMBRToUSB(hPhysical, bootFilesPath), "Error on WriteMBRToUSB"); safe_closehandle(hPhysical); @@ -4788,16 +4831,18 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) CHECK_IF_CANCELLED; // Format and mount exFAT + errorCause = ErrorCauseFormatExfatFailed; IFFALSE_GOTOERROR(FormatFirstPartitionOnDrive(DriveIndex, L"exFAT", EXFAT_CLUSTER_SIZE, dlg->m_cancelOperationEvent, EXFAT_PARTITION_NAME_LIVE), "Error formatting eoslive"); CHECK_IF_CANCELLED; - + errorCause = ErrorCauseMountExfatFailed; IFFALSE_GOTOERROR(MountFirstPartitionOnDrive(DriveIndex, eosliveDriveLetter), "Error mounting eoslive"); UpdateProgress(OP_NEW_LIVE_CREATION, USB_PROGRESS_EXFAT_PREPARED); CHECK_IF_CANCELLED; // Mount and format ESP. (Yes, you can assign a drive letter to an unformatted volume!) + errorCause = ErrorCauseMountESPFailed; cszEspDriveLetter = AltMountVolume(eosliveDriveLetter.Left(2), 2); IFFALSE_GOTOERROR(cszEspDriveLetter != NULL, "Error mounting ESP"); // The pointer returned by AltMountVolume() is to a static buffer... @@ -4805,12 +4850,14 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) CHECK_IF_CANCELLED; + errorCause = ErrorCauseFormatESPFailed; IFFALSE_GOTOERROR(FormatPartitionWithRetry(espDriveLetter, L"FAT32", ESP_CLUSTER_SIZE, dlg->m_cancelOperationEvent, L""), "Error formatting ESP"); UpdateProgress(OP_NEW_LIVE_CREATION, USB_PROGRESS_ESP_PREPARED); CHECK_IF_CANCELLED; // Copy files to the ESP partition + errorCause = ErrorCausePopulateESPFailed; IFFALSE_GOTOERROR(CopyFilesToESP(bootFilesPath, CString(espDriveLetter) + L"\\"), "Error when trying to copy files to ESP partition."); // Unmount ESP (but continue if this fails) @@ -4821,6 +4868,7 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) CHECK_IF_CANCELLED; // Copy files to the exFAT partition + errorCause = ErrorCausePopulateExfatFailed; IFFALSE_GOTOERROR(CopyFilesToexFAT(dlg, bootFilesPath, UTF8ToCString(eosliveDriveLetter)), "Error on CopyFilesToexFAT"); UpdateProgress(OP_NEW_LIVE_CREATION, USB_PROGRESS_ALL_DONE); @@ -4831,7 +4879,7 @@ DWORD WINAPI CEndlessUsbToolDlg::CreateUSBStick(LPVOID param) error: uprintf("CreateUSBStick exited with error."); if (dlg->m_lastErrorCause == ErrorCause_t::ErrorCauseNone) { - dlg->m_lastErrorCause = ErrorCause_t::ErrorCauseWriteFailed; + dlg->m_lastErrorCause = errorCause; } done: diff --git a/src/endless/EndlessUsbToolDlg.h b/src/endless/EndlessUsbToolDlg.h index b921fe15979..5b98c854064 100644 --- a/src/endless/EndlessUsbToolDlg.h +++ b/src/endless/EndlessUsbToolDlg.h @@ -62,6 +62,18 @@ typedef enum ErrorCause { ErrorCauseInstallEosldrFailed, ErrorCauseUninstallEosldrFailed, ErrorCauseCantUnpackBootZip, + ErrorCauseGetPhysicalHandleFailed, + ErrorCauseDisappearingExistingVolumesFailed, + ErrorCauseErasePartitionsFailed, + ErrorCauseWriteBiosBootFailed, + ErrorCauseCreatePartitionsFailed, + ErrorCauseWriteMBRFailed, + ErrorCauseFormatExfatFailed, + ErrorCauseMountExfatFailed, + ErrorCauseMountESPFailed, + ErrorCauseFormatESPFailed, + ErrorCausePopulateESPFailed, + ErrorCausePopulateExfatFailed, } ErrorCause_t; typedef struct RemoteImageEntry { From 369dd95ce63a2553982b5ee6a4dd3d93b4023762 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 24 Oct 2017 19:17:14 +0100 Subject: [PATCH 18/20] Hide error recovery suggestion if there isn't one Previously, we'd just display whatever the previous suggestion was, or the untranslated English placeholder string from the template if there was no previous suggestion. --- src/endless/EndlessUsbToolDlg.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index 99f21d0d10d..a286986cf28 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -1857,8 +1857,8 @@ void CEndlessUsbToolDlg::ErrorOccured(ErrorCause_t errorCause) SetElementText(_T(ELEMENT_ERROR_DELETE_TEXT), deleteFilesText); // Update the error description and "recovery" suggestion + CComBSTR message(""); if (suggestionMsgId != 0) { - CComBSTR message; if (suggestionMsgId == MSG_334 || suggestionMsgId == MSG_303) { // Not enough space to download const CStringA downloadDriveA = ConvertUnicodeToUTF8(CEndlessUsbToolApp::m_imageDir.Left(3)); @@ -1883,8 +1883,8 @@ void CEndlessUsbToolDlg::ErrorOccured(ErrorCause_t errorCause) } else { message = UTF8ToBSTR(lmprintf(suggestionMsgId)); } - SetElementText(_T(ELEMENT_ERROR_SUGGESTION), message); } + SetElementText(_T(ELEMENT_ERROR_SUGGESTION), message); if (m_taskbarProgress != NULL) { m_taskbarProgress->SetProgressState(m_hWnd, TBPF_ERROR); From e9c52e913d86bc6b205444d244a87f017d26b28f Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Tue, 24 Oct 2017 19:18:23 +0100 Subject: [PATCH 19/20] Assume errors are fatal iff we show no recover button This means we don't have to remember to update this switch when we add new recoverable errors. I don't really look at the exceptionTracking data but since it's here... --- src/endless/EndlessUsbToolDlg.cpp | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index a286986cf28..9226ce9b52d 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -1898,17 +1898,7 @@ void CEndlessUsbToolDlg::ErrorOccured(ErrorCause_t errorCause) else TrackEvent(_T("Failed"), ErrorCauseToStr(errorCause)); - bool fatal = FALSE; - switch (errorCause) { - case ErrorCause_t::ErrorCauseDownloadFailed: - case ErrorCause_t::ErrorCauseVerificationFailed: - case ErrorCause_t::ErrorCauseWriteFailed: - fatal = FALSE; - break; - default: - fatal = TRUE; - break; - } + bool fatal = recoverButtonMsgId == 0; Analytics::instance()->exceptionTracking(ErrorCauseToStr(errorCause), fatal); } From 49c84ee48ee49e00bc084ea4a5b6e129560b22c1 Mon Sep 17 00:00:00 2001 From: Will Thompson Date: Mon, 30 Oct 2017 11:12:18 +0000 Subject: [PATCH 20/20] FileCopyThread: fix mixed whitespace --- src/endless/EndlessUsbToolDlg.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/endless/EndlessUsbToolDlg.cpp b/src/endless/EndlessUsbToolDlg.cpp index 9226ce9b52d..dc46cecf6f0 100644 --- a/src/endless/EndlessUsbToolDlg.cpp +++ b/src/endless/EndlessUsbToolDlg.cpp @@ -4102,7 +4102,7 @@ DWORD WINAPI CEndlessUsbToolDlg::FileCopyThread(void* param) FUNCTION_ENTER; CEndlessUsbToolDlg *dlg = (CEndlessUsbToolDlg*)param; - + HANDLE hPhysical = INVALID_HANDLE_VALUE; DWORD size; DWORD DriveIndex = SelectedDrive.DeviceNumber; @@ -4114,19 +4114,19 @@ DWORD WINAPI CEndlessUsbToolDlg::FileCopyThread(void* param) CString driveDestination, fileDestination, liveFileName; CStringA driveDestinationA, iniLanguage = INI_LOCALE_EN; - // Radu: why do we do this? + // Radu: why do we do this? memset(&SelectedDrive, 0, sizeof(SelectedDrive)); // Query for disk and partition data hPhysical = GetPhysicalHandle(DriveIndex, TRUE, TRUE); IFFALSE_GOTOERROR(hPhysical != INVALID_HANDLE_VALUE, "Error on acquiring disk handle."); - + result = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, geometry, sizeof(geometry), &size, NULL); IFFALSE_GOTOERROR(result != 0 && size > 0, "Error on querying disk geometry."); result = DeviceIoControl(hPhysical, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0, layout, sizeof(layout), &size, NULL); IFFALSE_GOTOERROR(result != 0 && size > 0, "Error on querying disk layout."); - + IFFALSE_GOTOERROR(DriveLayout->PartitionStyle == PARTITION_STYLE_GPT, "Unexpected partition type."); IFFALSE_GOTOERROR(DriveLayout->PartitionCount == EXPECTED_NUMBER_OF_PARTITIONS, "Error: Unexpected number of partitions."); @@ -4162,19 +4162,19 @@ DWORD WINAPI CEndlessUsbToolDlg::FileCopyThread(void* param) // Check if user cancelled IFFALSE_GOTOERROR(WaitForSingleObject(dlg->m_cancelOperationEvent, 0) == WAIT_TIMEOUT, "User cancel."); - // Format the partition - IFFALSE_GOTOERROR(FormatFirstPartitionOnDrive(DriveIndex, L"exFAT", EXFAT_CLUSTER_SIZE, dlg->m_cancelOperationEvent, EXFAT_PARTITION_NAME_IMAGES), "Error on FormatFirstPartitionOnDrive"); + // Format the partition + IFFALSE_GOTOERROR(FormatFirstPartitionOnDrive(DriveIndex, L"exFAT", EXFAT_CLUSTER_SIZE, dlg->m_cancelOperationEvent, EXFAT_PARTITION_NAME_IMAGES), "Error on FormatFirstPartitionOnDrive"); // Mount it - IFFALSE_GOTOERROR(MountFirstPartitionOnDrive(DriveIndex, driveDestinationA), "Error on MountFirstPartitionOnDrive"); + IFFALSE_GOTOERROR(MountFirstPartitionOnDrive(DriveIndex, driveDestinationA), "Error on MountFirstPartitionOnDrive"); driveDestination = driveDestinationA; // Copy Files - liveFileName = CSTRING_GET_LAST(dlg->m_localFile, L'\\'); - if (liveFileName == ENDLESS_IMG_FILE_NAME) { - fileDestination = driveDestination + CSTRING_GET_PATH(CSTRING_GET_LAST(dlg->m_localFileSig, L'\\'), L'.'); - } else { - fileDestination = driveDestination + liveFileName; - } + liveFileName = CSTRING_GET_LAST(dlg->m_localFile, L'\\'); + if (liveFileName == ENDLESS_IMG_FILE_NAME) { + fileDestination = driveDestination + CSTRING_GET_PATH(CSTRING_GET_LAST(dlg->m_localFileSig, L'\\'), L'.'); + } else { + fileDestination = driveDestination + liveFileName; + } result = CopyFileEx(dlg->m_localFile, fileDestination, CEndlessUsbToolDlg::CopyProgressRoutine, dlg, NULL, 0); IFFALSE_GOTOERROR(result, "Copying live image failed/cancelled.");