From 23d89d97648621ab9116655eb4e12d5acb64d146 Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Wed, 3 May 2023 16:26:54 +0100 Subject: [PATCH] [misc] apply a timeout when querying drives for letters/type * Some Windows Store reports suggest that the existing call might freeze on CreateFile() leading some users to kill the app. So switch to using a CreateFile() call that times out instead of waiting forever... --- src/drive.c | 9 +++++--- src/rufus.h | 3 +++ src/rufus.rc | 10 ++++----- src/stdio.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 74 insertions(+), 8 deletions(-) diff --git a/src/drive.c b/src/drive.c index cd6e8693..25067af4 100644 --- a/src/drive.c +++ b/src/drive.c @@ -1149,10 +1149,13 @@ static BOOL _GetDriveLettersAndType(DWORD DriveIndex, char* drive_letters, UINT* continue; static_sprintf(logical_drive, "\\\\.\\%c:", toupper(drive[0])); - hDrive = CreateFileA(logical_drive, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + // This call appears to freeze on some systems and we don't want to spend more + // time than needed waiting for unresponsive drives, so use a 3 seconds timeout. + hDrive = CreateFileWithTimeout(logical_drive, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL, 3000); if (hDrive == INVALID_HANDLE_VALUE) { -// uprintf("Warning: could not open drive %c: %s", toupper(drive[0]), WindowsErrorString()); + if (GetLastError() == WAIT_TIMEOUT) + uprintf("Warning: Time-out while trying to query drive %c", toupper(drive[0])); continue; } diff --git a/src/rufus.h b/src/rufus.h index cc260b3d..a65e8ffe 100644 --- a/src/rufus.h +++ b/src/rufus.h @@ -684,6 +684,9 @@ extern BOOL ValidateOpensslSignature(BYTE* pbBuffer, DWORD dwBufferLen, BYTE* pb extern BOOL IsFontAvailable(const char* font_name); extern BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, DWORD nNumRetries); +extern HANDLE CreateFileWithTimeout(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile, DWORD dwTimeOut); extern BOOL SetThreadAffinity(DWORD_PTR* thread_affinity, size_t num_threads); extern BOOL HashFile(const unsigned type, const char* path, uint8_t* sum); extern BOOL HashBuffer(const unsigned type, const uint8_t* buf, const size_t len, uint8_t* sum); diff --git a/src/rufus.rc b/src/rufus.rc index a424cd0f..62087f41 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 4.0.2037" +CAPTION "Rufus 4.0.2038" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -392,8 +392,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 4,0,2037,0 - PRODUCTVERSION 4,0,2037,0 + FILEVERSION 4,0,2038,0 + PRODUCTVERSION 4,0,2038,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -411,13 +411,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "4.0.2037" + VALUE "FileVersion", "4.0.2038" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2023 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-4.0.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "4.0.2037" + VALUE "ProductVersion", "4.0.2038" END END BLOCK "VarFileInfo" diff --git a/src/stdio.c b/src/stdio.c index 9da2f875..3a242042 100644 --- a/src/stdio.c +++ b/src/stdio.c @@ -863,6 +863,66 @@ const char* StrError(DWORD error_code, BOOL use_default_locale) return ret; } +typedef struct +{ + LPCWSTR lpFileName; + DWORD dwDesiredAccess; + DWORD dwShareMode; + DWORD dwCreationDisposition; + DWORD dwFlagsAndAttributes; + HANDLE hFile; + DWORD dwError; +} cfx_params_t; + +// Thread used by CreateFileWithTimeout() below +DWORD WINAPI CreateFileWithTimeoutThread(void* params) +{ + cfx_params_t* cfx_params = (cfx_params_t*)params; + HANDLE hFile = CreateFileW(cfx_params->lpFileName, cfx_params->dwDesiredAccess, + cfx_params->dwShareMode, NULL, cfx_params->dwCreationDisposition, + cfx_params->dwFlagsAndAttributes, NULL); + + cfx_params->dwError = (hFile == INVALID_HANDLE_VALUE) ? GetLastError() : NOERROR; + cfx_params->hFile = hFile; + + return cfx_params->dwError; +} + +// A UTF-8 CreateFile() with timeout +HANDLE CreateFileWithTimeout(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, HANDLE hTemplateFile, DWORD dwTimeOut) +{ + HANDLE hThread; + wconvert(lpFileName); + + cfx_params_t params = { + wlpFileName, + dwDesiredAccess, + dwShareMode, + dwCreationDisposition, + dwFlagsAndAttributes, + INVALID_HANDLE_VALUE, + ERROR_IO_PENDING, + }; + + hThread = CreateThread(NULL, 0, CreateFileWithTimeoutThread, ¶ms, 0, NULL); + if (hThread != NULL) { + if (WaitForSingleObject(hThread, dwTimeOut) == WAIT_TIMEOUT) { + CancelSynchronousIo(hThread); + WaitForSingleObject(hThread, INFINITE); + params.dwError = WAIT_TIMEOUT; + } + CloseHandle(hThread); + } else { + params.dwError = GetLastError(); + } + + wfree(lpFileName); + SetLastError(params.dwError); + return params.hFile; +} + // A WriteFile() equivalent, with up to nNumRetries write attempts on error. BOOL WriteFileWithRetry(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten, DWORD nNumRetries)