From d4a663991bf017263b58d1bea1dfe18393c8208e Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Tue, 9 Apr 2019 21:37:08 +0100 Subject: [PATCH] [core] report write errors more explicitly * Also issue a port cycle on ERROR_NOT_READY * Also run a check for conflicting processes during write retries --- src/format.c | 69 ++++++++++++++++++++++++----------------------- src/ms-sys/file.c | 7 +++-- src/process.c | 2 +- src/rufus.c | 39 ++++++++++++++++++++------- src/rufus.h | 4 ++- src/rufus.rc | 10 +++---- src/stdio.c | 22 +++++++++++---- 7 files changed, 95 insertions(+), 58 deletions(-) diff --git a/src/format.c b/src/format.c index 21e1e920..f620b8f2 100644 --- a/src/format.c +++ b/src/format.c @@ -54,7 +54,7 @@ /* * Globals */ -DWORD FormatStatus = 0; +DWORD FormatStatus = 0, LastWriteError = 0; badblocks_report report = { 0 }; static uint64_t LastRefresh = 0; static float format_percent = 0.0f; @@ -843,7 +843,8 @@ static BOOL ClearMBRGPT(HANDLE hPhysicalDrive, LONGLONG DiskSize, DWORD SectorSi if (write_sectors(hPhysicalDrive, SectorSize, i, 1, pBuf) != SectorSize) { if (j < WRITE_RETRIES) { uprintf("Retrying in %d seconds...", WRITE_TIMEOUT / 1000); - Sleep(WRITE_TIMEOUT); + // Don't sit idly but use the downtime to check for conflicting processes... + Sleep(CheckDriveAccess(WRITE_TIMEOUT, FALSE)); } else goto out; } @@ -856,7 +857,7 @@ static BOOL ClearMBRGPT(HANDLE hPhysicalDrive, LONGLONG DiskSize, DWORD SectorSi if (write_sectors(hPhysicalDrive, SectorSize, i, 1, pBuf) != SectorSize) { if (j < WRITE_RETRIES) { uprintf("Retrying in %d seconds...", WRITE_TIMEOUT / 1000); - Sleep(WRITE_TIMEOUT); + Sleep(CheckDriveAccess(WRITE_TIMEOUT, FALSE)); } else { // Windows seems to be an ass about keeping a lock on a backup GPT, // so we try to be lenient about not being able to clear it. @@ -1799,15 +1800,15 @@ DWORD WINAPI FormatThread(void* param) // At this stage we have both a handle and a lock to the physical drive if (!GetDriveLetters(DriveIndex, drive_letters)) { - uprintf("Failed to get a drive letter\n"); + uprintf("Failed to get a drive letter"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_ASSIGN_LETTER); goto out; } if (drive_letters[0] == 0) { - uprintf("No drive letter was assigned...\n"); + uprintf("No drive letter was assigned..."); drive_name[0] = GetUnusedDriveLetter(); if (drive_name[0] == 0) { - uprintf("Could not find a suitable drive letter\n"); + uprintf("Could not find a suitable drive letter"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_ASSIGN_LETTER); goto out; } @@ -1819,18 +1820,18 @@ DWORD WINAPI FormatThread(void* param) if (bt == BT_IMAGE) { // If we are using an image, check that it isn't located on the drive we are trying to format if ((PathGetDriveNumberU(image_path) + 'A') == drive_letters[i-1]) { - uprintf("ABORTED: Cannot use an image that is located on the target drive!\n"); + uprintf("ABORTED: Cannot use an image that is located on the target drive!"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED; goto out; } } if (!DeleteVolumeMountPointA(drive_name)) { - uprintf("Failed to delete mountpoint %s: %s\n", drive_name, WindowsErrorString()); + uprintf("Failed to delete mountpoint %s: %", drive_name, WindowsErrorString()); // Try to continue. We will bail out if this causes an issue. } } } - uprintf("Will use '%c:' as volume mountpoint\n", drive_name[0]); + uprintf("Will use '%c:' as volume mountpoint", drive_name[0]); // It kind of blows, but we have to relinquish access to the physical drive // for VDS to be able to delete the partitions that reside on it... @@ -1848,14 +1849,14 @@ DWORD WINAPI FormatThread(void* param) // ...and get a lock to the logical drive so that we can actually write something hLogicalVolume = GetLogicalHandle(DriveIndex, TRUE, FALSE, !lock_drive); if (hLogicalVolume == INVALID_HANDLE_VALUE) { - uprintf("Could not lock volume\n"); + uprintf("Could not lock volume"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; goto out; } else if (hLogicalVolume == NULL) { // NULL is returned for cases where the drive is not yet partitioned - uprintf("Drive does not appear to be partitioned\n"); + uprintf("Drive does not appear to be partitioned"); } else if (!UnmountVolume(hLogicalVolume)) { - uprintf("Trying to continue regardless...\n"); + uprintf("Trying to continue regardless..."); } CHECK_FOR_USER_CANCEL; @@ -1877,8 +1878,8 @@ DWORD WINAPI FormatThread(void* param) if ((bt != BT_IMAGE) || (img_report.is_iso && !write_as_image)) { if ((!ClearMBRGPT(hPhysicalDrive, SelectedDrive.DiskSize, SelectedDrive.SectorSize, use_large_fat32)) || (!InitializeDisk(hPhysicalDrive))) { - uprintf("Could not reset partitions\n"); - FormatStatus = ERROR_SEVERITY_ERROR | FAC(FACILITY_STORAGE) | ERROR_PARTITION_FAILURE; + uprintf("Could not reset partitions"); + FormatStatus = (LastWriteError != 0) ? LastWriteError : (ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE); goto out; } } @@ -1897,16 +1898,16 @@ DWORD WINAPI FormatThread(void* param) lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond); log_fd = fopenU(logfile, "w+"); if (log_fd == NULL) { - uprintf("Could not create log file for bad blocks check\n"); + uprintf("Could not create log file for bad blocks check"); } else { - fprintf(log_fd, APPLICATION_NAME " bad blocks check started on: %04d.%02d.%02d %02d:%02d:%02d\n", + fprintf(log_fd, APPLICATION_NAME " bad blocks check started on: %04d.%02d.%02d %02d:%02d:%02d", lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond); fflush(log_fd); } if (!BadBlocks(hPhysicalDrive, SelectedDrive.DiskSize, (sel >= 2) ? 4 : sel +1, (sel < 2) ? 0 : sel - 2, &report, log_fd)) { - uprintf("Bad blocks: Check failed.\n"); + uprintf("Bad blocks: Check failed."); if (!IS_ERROR(FormatStatus)) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_BADBLOCKS_FAILURE); ClearMBRGPT(hPhysicalDrive, SelectedDrive.DiskSize, SelectedDrive.SectorSize, FALSE); @@ -1914,7 +1915,7 @@ DWORD WINAPI FormatThread(void* param) DeleteFileU(logfile); goto out; } - uprintf("Bad Blocks: Check completed, %d bad block%s found. (%d/%d/%d errors)\n", + uprintf("Bad Blocks: Check completed, %d bad block%s found. (%d/%d/%d errors)", report.bb_count, (report.bb_count==1)?"":"s", report.num_read_errors, report.num_write_errors, report.num_corruption_errors); r = IDOK; @@ -1923,7 +1924,7 @@ DWORD WINAPI FormatThread(void* param) report.num_corruption_errors); fprintf(log_fd, bb_msg); GetLocalTime(<); - fprintf(log_fd, APPLICATION_NAME " bad blocks check ended on: %04d.%02d.%02d %02d:%02d:%02d\n", + fprintf(log_fd, APPLICATION_NAME " bad blocks check ended on: %04d.%02d.%02d %02d:%02d:%02d", lt.wYear, lt.wMonth, lt.wDay, lt.wHour, lt.wMinute, lt.wSecond); fclose(log_fd); r = MessageBoxExU(hMainDialog, lmprintf(MSG_012, bb_msg, logfile), @@ -1942,7 +1943,7 @@ DWORD WINAPI FormatThread(void* param) // Especially after destructive badblocks test, you must zero the MBR/GPT completely // before repartitioning. Else, all kind of bad things happen. if (!ClearMBRGPT(hPhysicalDrive, SelectedDrive.DiskSize, SelectedDrive.SectorSize, use_large_fat32)) { - uprintf("unable to zero MBR/GPT\n"); + uprintf("unable to zero MBR/GPT"); if (!IS_ERROR(FormatStatus)) FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT; goto out; @@ -1969,7 +1970,7 @@ DWORD WINAPI FormatThread(void* param) if (GetDrivePartitionData(SelectedDrive.DeviceNumber, fs_type, sizeof(fs_type), TRUE)) { guid_volume = GetLogicalName(DriveIndex, TRUE, TRUE); if ((guid_volume != NULL) && (MountVolume(drive_name, guid_volume))) - uprintf("Remounted %s as %C:\n", guid_volume, drive_name[0]); + uprintf("Remounted %s as %C:", guid_volume, drive_name[0]); } goto out; } @@ -1978,7 +1979,7 @@ DWORD WINAPI FormatThread(void* param) CHECK_FOR_USER_CANCEL; if (!CreatePartition(hPhysicalDrive, pt, fs, (pt==PARTITION_STYLE_MBR) && (tt==TT_UEFI), extra_partitions)) { - FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE; + FormatStatus = (LastWriteError != 0) ? LastWriteError : (ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_PARTITION_FAILURE); goto out; } UpdateProgress(OP_PARTITION, -1.0f); @@ -1987,7 +1988,7 @@ DWORD WINAPI FormatThread(void* param) if ((hLogicalVolume != NULL) && (hLogicalVolume != INVALID_HANDLE_VALUE)) { PrintInfoDebug(0, MSG_227); if (!CloseHandle(hLogicalVolume)) { - uprintf("Could not close volume: %s\n", WindowsErrorString()); + uprintf("Could not close volume: %s", WindowsErrorString()); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_ACCESS_DENIED; goto out; } @@ -1995,7 +1996,7 @@ DWORD WINAPI FormatThread(void* param) hLogicalVolume = INVALID_HANDLE_VALUE; // Wait for the logical drive we just created to appear - uprintf("Waiting for logical drive to reappear...\n"); + uprintf("Waiting for logical drive to reappear..."); Sleep(200); if (!WaitForLogical(DriveIndex)) uprintf("Logical drive was not found!"); // We try to continue even if this fails, just in case @@ -2006,7 +2007,7 @@ DWORD WINAPI FormatThread(void* param) ret = use_large_fat32?FormatFAT32(DriveIndex):FormatDrive(DriveIndex); if (!ret) { // Error will be set by FormatDrive() in FormatStatus - uprintf("Format error: %s\n", StrError(FormatStatus, TRUE)); + uprintf("Format error: %s", StrError(FormatStatus, TRUE)); goto out; } @@ -2027,11 +2028,11 @@ DWORD WINAPI FormatThread(void* param) guid_volume = GetLogicalName(DriveIndex, TRUE, TRUE); if (guid_volume == NULL) { - uprintf("Could not get GUID volume name\n"); + uprintf("Could not get GUID volume name"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_NO_VOLUME_ID; goto out; } - uprintf("Found volume GUID %s\n", guid_volume); + uprintf("Found volume GUID %s, guid_volume"); if (!MountVolume(drive_name, guid_volume)) { uprintf("Could not remount %s as %C: %s\n", guid_volume, drive_name[0], WindowsErrorString()); @@ -2076,7 +2077,7 @@ DWORD WINAPI FormatThread(void* param) // => no need to reacquire the lock... hLogicalVolume = GetLogicalHandle(DriveIndex, FALSE, TRUE, FALSE); if ((hLogicalVolume == INVALID_HANDLE_VALUE) || (hLogicalVolume == NULL)) { - uprintf("Could not re-mount volume for partition boot record access\n"); + uprintf("Could not re-mount volume for partition boot record access"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_OPEN_FAILED; goto out; } @@ -2116,7 +2117,7 @@ DWORD WINAPI FormatThread(void* param) } else if (bt == BT_GRUB4DOS) { grub4dos_dst[0] = drive_name[0]; IGNORE_RETVAL(_chdirU(app_dir)); - uprintf("Installing: %s (Grub4DOS loader) %s\n", grub4dos_dst, + uprintf("Installing: %s (Grub4DOS loader) %s", grub4dos_dst, IsFileInDB(FILES_DIR "\\grub4dos-" GRUB4DOS_VERSION "\\grldr")?"✓":"✗"); if (!CopyFileU(FILES_DIR "\\grub4dos-" GRUB4DOS_VERSION "\\grldr", grub4dos_dst, FALSE)) uprintf("Failed to copy file: %s", WindowsErrorString()); @@ -2139,10 +2140,10 @@ DWORD WINAPI FormatThread(void* param) } if (HAS_KOLIBRIOS(img_report)) { kolibri_dst[0] = drive_name[0]; - uprintf("Installing: %s (KolibriOS loader)\n", kolibri_dst); + uprintf("Installing: %s (KolibriOS loader)", kolibri_dst); if (ExtractISOFile(image_path, "HD_Load/USB_Boot/MTLD_F32", kolibri_dst, FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM) == 0) { - uprintf("Warning: loader installation failed - KolibriOS will not boot!\n"); + uprintf("Warning: loader installation failed - KolibriOS will not boot!"); } } // EFI mode selected, with no 'boot###.efi' but Windows 7 x64's 'bootmgr.efi' (bit #0) @@ -2152,12 +2153,12 @@ DWORD WINAPI FormatThread(void* param) efi_dst[0] = drive_name[0]; efi_dst[sizeof(efi_dst) - sizeof("\\bootx64.efi")] = 0; if (!CreateDirectoryA(efi_dst, 0)) { - uprintf("Could not create directory '%s': %s\n", efi_dst, WindowsErrorString()); + uprintf("Could not create directory '%s': %s", efi_dst, WindowsErrorString()); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH); } else { efi_dst[sizeof(efi_dst) - sizeof("\\bootx64.efi")] = '\\'; if (!WimExtractFile(img_report.wininst_path[0], 1, "Windows\\Boot\\EFI\\bootmgfw.efi", efi_dst)) { - uprintf("Failed to setup Win7 EFI boot\n"); + uprintf("Failed to setup Win7 EFI boot"); FormatStatus = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|APPERR(ERROR_CANT_PATCH); } } @@ -2199,7 +2200,7 @@ out: guid_volume = GetLogicalName(DriveIndex, TRUE, FALSE); if (guid_volume != NULL) { if (MountVolume(drive_name, guid_volume)) - uprintf("Re-mounted volume as %C: after error\n", drive_name[0]); + uprintf("Re-mounted volume as %C: after error", drive_name[0]); free(guid_volume); } } diff --git a/src/ms-sys/file.c b/src/ms-sys/file.c index 50aa0991..7758a46b 100644 --- a/src/ms-sys/file.c +++ b/src/ms-sys/file.c @@ -1,6 +1,6 @@ /****************************************************************** Copyright (C) 2009 Henrik Carlqvist - Modified for Rufus/Windows (C) 2011-2016 Pete Batard + Modified for Rufus/Windows (C) 2011-2019 Pete Batard This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -47,8 +47,10 @@ int64_t write_sectors(HANDLE hDrive, uint64_t SectorSize, return -1; } + LastWriteError = 0; if(!WriteFile(hDrive, pBuf, Size, &Size, NULL)) { + LastWriteError = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|GetLastError(); uprintf("write_sectors: Write error %s\n", WindowsErrorString()); uprintf(" StartSector: 0x%08" PRIx64 ", nSectors: 0x%" PRIx64 ", SectorSize: 0x%" PRIx64 "\n", StartSector, nSectors, SectorSize); return -1; @@ -60,7 +62,8 @@ int64_t write_sectors(HANDLE hDrive, uint64_t SectorSize, uprintf("Warning: Possible short write\n"); return 0; } - uprintf("write_sectors:write error\n"); + uprintf("write_sectors: Write error\n"); + LastWriteError = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|ERROR_WRITE_FAULT; uprintf(" Wrote: %d, Expected: %" PRIu64 "\n", Size, nSectors*SectorSize); uprintf(" StartSector: 0x%08" PRIx64 ", nSectors: 0x%" PRIx64 ", SectorSize: 0x%" PRIx64 "\n", StartSector, nSectors, SectorSize); return -1; diff --git a/src/process.c b/src/process.c index 588a5408..c4fd70a8 100644 --- a/src/process.c +++ b/src/process.c @@ -679,7 +679,7 @@ BYTE SearchProcess(char* HandleName, DWORD dwTimeOut, BOOL bPartialMatch, BOOL b if (res == WAIT_TIMEOUT) { // Timeout - kill the thread TerminateThread(handle, 0); - uprintf("Warning: Conflicting process search failed to complete due to timeout"); + uprintf("Warning: Search for conflicting processes was interrupted due to timeout"); } else if (res != WAIT_OBJECT_0) { TerminateThread(handle, 0); uprintf("Warning: Failed to wait for conflicting process search thread: %s", WindowsErrorString()); diff --git a/src/rufus.c b/src/rufus.c index 7f00cb71..aa5e8d82 100755 --- a/src/rufus.c +++ b/src/rufus.c @@ -1783,18 +1783,21 @@ static void SaveISO(void) } } -// Check for conflicting processes accessing the drive, and if any, -// ask the user whether they want to proceed. -// Parameter is the maximum amount of time we allow for this call to execute (in ms) -static BOOL CheckDriveAccess(DWORD dwTimeOut) +// Check for conflicting processes accessing the drive. +// If bPrompt is true, ask the user whether they want to proceed. +// dwTimeOut is the maximum amount of time we allow for this call to execute (in ms) +// If bPrompt is false, the return value is the amount of time remaining before +// dwTimeOut would expire (or zero if we spent more than dwTimeout in this procedure). +// If bPrompt is true, the return value is 0 on error, non-zero on success. +DWORD CheckDriveAccess(DWORD dwTimeOut, BOOL bPrompt) { uint32_t i, j; - BOOL ret = FALSE, proceed = TRUE; + DWORD ret = 0, proceed = TRUE; BYTE access_mask; char *PhysicalPath = NULL, DevPath[MAX_PATH]; char drive_letter[27], drive_name[] = "?:"; char title[128]; - uint64_t cur_time, end_time = GetTickCount64() + dwTimeOut; + uint64_t start_time = GetTickCount64(), cur_time, end_time = start_time + dwTimeOut; // Get the current selected device DWORD DeviceNum = (DWORD)ComboBox_GetItemData(hDeviceList, ComboBox_GetCurSel(hDeviceList)); @@ -1802,7 +1805,8 @@ static BOOL CheckDriveAccess(DWORD dwTimeOut) return FALSE; // "Checking for conflicting processes..." - PrintInfo(0, MSG_278); + if (bPrompt) + PrintInfo(0, MSG_278); // Search for any blocking processes against the physical drive PhysicalPath = GetPhysicalName(DeviceNum); @@ -1839,11 +1843,16 @@ static BOOL CheckDriveAccess(DWORD dwTimeOut) } // Prompt the user if we detected blocking processes - if (!proceed) { + if (bPrompt && !proceed) { ComboBox_GetTextU(hDeviceList, title, sizeof(title)); proceed = Notification(MSG_WARNING_QUESTION, NULL, NULL, title, lmprintf(MSG_132)); } - ret = proceed; + if (bPrompt) { + ret = (DWORD)proceed; + } else { + ret = (DWORD)(GetTickCount64() - start_time); + ret = (dwTimeOut > ret) ? (dwTimeOut - ret) : 0; + } out: PrintInfo(0, MSG_210); @@ -2207,6 +2216,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA // Disable all controls except Cancel EnableControls(FALSE); FormatStatus = 0; + LastWriteError = 0; StrArrayClear(&BlockingProcess); format_op_in_progress = TRUE; no_confirmation_on_cancel = FALSE; @@ -2604,7 +2614,7 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA } } - if (!CheckDriveAccess(2000)) + if (!CheckDriveAccess(CHECK_DRIVE_TIMEOUT, TRUE)) goto aborted_start; GetWindowTextU(hDeviceList, tmp, ARRAYSIZE(tmp)); @@ -2712,10 +2722,19 @@ static INT_PTR CALLBACK MainCallback(HWND hDlg, UINT message, WPARAM wParam, LPA break; } } + if (SCODE_CODE(FormatStatus) == ERROR_NOT_READY) { + // A port cycle usually helps with a device not ready + int index = ComboBox_GetCurSel(hDeviceList); + if (index >= 0) { + uprintf("Device not ready → Trying to cycle port..."); + ResetDevice(index); + } + } Notification(MSG_ERROR, NULL, NULL, lmprintf(MSG_042), lmprintf(MSG_043, StrError(FormatStatus, FALSE))); } } FormatStatus = 0; + LastWriteError = 0; format_op_in_progress = FALSE; return (INT_PTR)TRUE; diff --git a/src/rufus.h b/src/rufus.h index 843758b2..b6d6a466 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -79,6 +79,7 @@ #define WRITE_TIMEOUT 5000 // How long we should wait between write retries (in ms) #define SEARCH_PROCESS_TIMEOUT 10000 // How long we should search for conflicting processes before giving up (in ms) #define NET_SESSION_TIMEOUT 3500 // How long we should wait to connect, send or receive internet data +#define CHECK_DRIVE_TIMEOUT 2000 #define MARQUEE_TIMER_REFRESH 10 // Time between progress bar marquee refreshes, in ms #define FS_DEFAULT FS_FAT32 #define SINGLE_CLUSTERSIZE_DEFAULT 0x00000100 @@ -445,7 +446,7 @@ extern HWND hMainDialog, hLogDialog, hStatus, hDeviceList, hCapacity; extern HWND hPartitionScheme, hTargetSystem, hFileSystem, hClusterSize, hLabel, hBootType, hNBPasses, hLog; extern HWND hInfo, hProgress, hDiskID; extern WORD selected_langid; -extern DWORD FormatStatus, DownloadStatus, MainThreadId; +extern DWORD FormatStatus, DownloadStatus, MainThreadId, LastWriteError; extern BOOL use_own_c32[NB_OLD_C32], detect_fakes, iso_op_in_progress, format_op_in_progress, right_to_left_mode; extern BOOL allow_dual_uefi_bios, large_drive, usb_debug; extern int64_t iso_blocking_status; @@ -571,6 +572,7 @@ extern char* GetCurrentMUI(void); extern void SetAlertPromptMessages(void); extern BOOL SetAlertPromptHook(void); extern void ClrAlertPromptHook(void); +extern DWORD CheckDriveAccess(DWORD dwTimeOut, BOOL bPrompt); extern BYTE SearchProcess(char* HandleName, DWORD dwTimeout, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet); extern BOOL EnablePrivileges(void); extern void FlashTaskbar(HANDLE handle); diff --git a/src/rufus.rc b/src/rufus.rc index fbbd6cca..ba8e622f 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 3.6.1514" +CAPTION "Rufus 3.6.1515" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -394,8 +394,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,6,1514,0 - PRODUCTVERSION 3,6,1514,0 + FILEVERSION 3,6,1515,0 + PRODUCTVERSION 3,6,1515,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -413,13 +413,13 @@ BEGIN VALUE "Comments", "https://akeo.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.6.1514" + VALUE "FileVersion", "3.6.1515" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2019 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/copyleft/gpl.html" VALUE "OriginalFilename", "rufus-3.6.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.6.1514" + VALUE "ProductVersion", "3.6.1515" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index dd749782..7b4202a2 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -1,7 +1,7 @@ /* * Rufus: The Reliable USB Formatting Utility * Standard User I/O Routines (logging, status, etc.) - * Copyright © 2011-2017 Pete Batard + * Copyright © 2011-2019 Pete Batard * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -144,17 +145,18 @@ void DumpBufferHex(void *buf, size_t size) // Convert a windows error to human readable string const char *WindowsErrorString(void) { -static char err_string[256] = {0}; + static char err_string[256] = { 0 }; - DWORD size; + DWORD size, presize; DWORD error_code, format_error; error_code = GetLastError(); static_sprintf(err_string, "[0x%08lX] ", error_code); + presize = (DWORD)strlen(err_string); size = FormatMessageU(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, HRESULT_CODE(error_code), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &err_string[strlen(err_string)], + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), &err_string[presize], sizeof(err_string)-(DWORD)strlen(err_string), NULL); if (size == 0) { format_error = GetLastError(); @@ -163,6 +165,13 @@ static char err_string[256] = {0}; error_code, format_error); else static_sprintf(err_string, "Unknown error 0x%08lX", error_code); + } else { + // Microsoft may suffix CRLF to error messages, which we need to remove... + assert(presize > 2); + size += presize - 2; + // Cannot underflow if the above assert passed since our first char is neither of the following + while ((err_string[size] == 0x0D) || (err_string[size] == 0x0A) || (err_string[size] == 0x20)) + err_string[size--] = 0; } SetLastError(error_code); // Make sure we don't change the errorcode on exit @@ -356,6 +365,7 @@ BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWr break; } if (WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, NULL)) { + LastWriteError = 0; if (nNumberOfBytesToWrite == *lpNumberOfBytesWritten) return TRUE; // Some large drives return 0, even though all the data was written - See github #787 */ @@ -366,13 +376,15 @@ BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWr uprintf("Wrote %d bytes but requested %d", *lpNumberOfBytesWritten, nNumberOfBytesToWrite); } else { uprintf("Write error [0x%08X]", GetLastError()); + LastWriteError = ERROR_SEVERITY_ERROR|FAC(FACILITY_STORAGE)|GetLastError(); } // If we can't reposition for the next run, just abort if (!readFilePointer) break; if (nTry < nNumRetries) { uprintf("Retrying in %d seconds...", WRITE_TIMEOUT / 1000); - Sleep(WRITE_TIMEOUT); + // Don't sit idly but use the downtime to check for conflicting processes... + Sleep(CheckDriveAccess(WRITE_TIMEOUT, FALSE)); } } if (SCODE_CODE(GetLastError()) == ERROR_SUCCESS)