[process] add a timeout for the process search

* The process search appears to be blocking on some platform, and we
  also don't want users to have to wait too long on format startup
* Also update the update check for Windows XP SSL errors
This commit is contained in:
Pete Batard 2017-07-20 17:42:53 +01:00
parent 5c3437f6de
commit 4617ba786d
6 changed files with 72 additions and 35 deletions

View File

@ -153,7 +153,7 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr
bWriteShare = TRUE;
// Try to report the process that is locking the drive
// We also use bit 6 as a flag to indicate that SearchProcess was called.
access_mask = SearchProcess(DevPath, TRUE, TRUE, FALSE) | 0x40;
access_mask = SearchProcess(DevPath, 5000, TRUE, TRUE, FALSE) | 0x40;
}
Sleep(DRIVE_ACCESS_TIMEOUT / DRIVE_ACCESS_RETRIES);
}
@ -184,7 +184,7 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr
uprintf("Could not lock access to %s: %s", Path, WindowsErrorString());
// See if we can report the processes are accessing the drive
if (!IS_ERROR(FormatStatus) && (access_mask == 0))
access_mask = SearchProcess(DevPath, TRUE, TRUE, FALSE);
access_mask = SearchProcess(DevPath, 5000, TRUE, TRUE, FALSE);
// Try to continue if the only access rights we saw were for read-only
if ((access_mask & 0x07) != 0x01)
safe_closehandle(hDrive);

View File

@ -175,6 +175,8 @@ const char* WinInetErrorString(void)
return "The header could not be added because it already exists.";
case ERROR_HTTP_REDIRECT_FAILED:
return "The redirection failed because either the scheme changed or all attempts made to redirect failed.";
case ERROR_INTERNET_SECURITY_CHANNEL_ERROR:
return "This system's SSL library is too old to be able to access this website.";
case ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED:
return "Client Authentication certificate needed";
case ERROR_INTERNET_BAD_AUTO_PROXY_SCRIPT:
@ -512,8 +514,10 @@ static DWORD WINAPI CheckForUpdatesThread(LPVOID param)
INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP|INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS|
INTERNET_FLAG_NO_COOKIES|INTERNET_FLAG_NO_UI|INTERNET_FLAG_NO_CACHE_WRITE|INTERNET_FLAG_HYPERLINK|
((UrlParts.nScheme == INTERNET_SCHEME_HTTPS)?INTERNET_FLAG_SECURE:0), (DWORD_PTR)NULL);
if ((hRequest == NULL) || (!HttpSendRequestA(hRequest, NULL, 0, NULL, 0)))
if ((hRequest == NULL) || (!HttpSendRequestA(hRequest, NULL, 0, NULL, 0))) {
uprintf("Unable to send request: %s", WinInetErrorString());
goto out;
}
// Ensure that we get a text file
dwSize = sizeof(dwStatus);

View File

@ -52,6 +52,9 @@ PF_TYPE_DECL(NTAPI, NTSTATUS, NtClose, (HANDLE));
PF_TYPE_DECL(WINAPI, BOOL, QueryFullProcessImageNameW, (HANDLE, DWORD, LPWSTR, PDWORD));
static PVOID PhHeapHandle = NULL;
static char* _HandleName;
static BOOL _bPartialMatch, _bIgnoreSelf, _bQuiet;
static BYTE access_mask;
extern StrArray BlockingProcess;
/*
@ -307,18 +310,8 @@ NTSTATUS PhQueryProcessesUsingVolumeOrFile(HANDLE VolumeOrFileHandle,
return status;
}
/**
* Search all the processes and list the ones that have a specific handle open.
*
* \param HandleName The name of the handle to look for.
* \param bPartialMatch Whether partial matches should be allowed.
* \param bIgnoreSelf Whether the current process should be listed.
* \param bQuiet Prints minimal output.
*
* \return a byte containing the cummulated access rights (f----xwr) from all the handles found
* with bit 7 ('f') also set if at least one process was found.
*/
BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet)
static DWORD WINAPI SearchProcessThread(LPVOID param)
{
const char *access_rights_str[8] = { "n", "r", "w", "rw", "x", "rx", "wx", "rwx" };
char tmp[MAX_PATH];
@ -333,9 +326,8 @@ BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL
WCHAR *wHandleName = NULL;
HANDLE dupHandle = NULL;
HANDLE processHandle = NULL;
BOOLEAN bFound = FALSE, bGotExePath, verbose = !bQuiet;
BOOLEAN bFound = FALSE, bGotExePath, verbose = !_bQuiet;
ULONG access_rights = 0;
BYTE access_mask = 0;
DWORD size;
char exe_path[MAX_PATH] = { 0 };
wchar_t wexe_path[MAX_PATH];
@ -361,7 +353,7 @@ BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL
pid[0] = (ULONG_PTR)0;
cur_pid = 1;
wHandleName = utf8_to_wchar(HandleName);
wHandleName = utf8_to_wchar(_HandleName);
wHandleNameLen = (USHORT)wcslen(wHandleName);
bufferSize = 0x200;
@ -435,7 +427,7 @@ BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL
// Now duplicate this handle onto our own process, so that we can access its properties
if (processHandle == NtCurrentProcess()) {
if (bIgnoreSelf)
if (_bIgnoreSelf)
continue;
dupHandle = (HANDLE)handleInfo->HandleValue;
} else {
@ -471,11 +463,11 @@ BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL
}
// Don't bother comparing if we are looking for full match and the length is different
if ((!bPartialMatch) && (wHandleNameLen != buffer->Name.Length))
if ((!_bPartialMatch) && (wHandleNameLen != buffer->Name.Length))
continue;
// Likewise, if we are looking for a partial match and the current length is smaller
if ((bPartialMatch) && (wHandleNameLen > buffer->Name.Length))
if ((_bPartialMatch) && (wHandleNameLen > buffer->Name.Length))
continue;
// Match against our target string
@ -494,7 +486,7 @@ BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL
// If this is the very first process we find, print a header
if (exe_path[0] == 0)
vuprintf("WARNING: The following process(es) or service(s) are accessing %s:", HandleName);
vuprintf("WARNING: The following process(es) or service(s) are accessing %s:", _HandleName);
// First, we try to get the executable path using GetModuleFileNameEx
bGotExePath = (GetModuleFileNameExU(processHandle, 0, exe_path, MAX_PATH - 1) != 0);
@ -508,10 +500,12 @@ BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL
wchar_to_utf8_no_alloc(wexe_path, exe_path, sizeof(exe_path));
}
// Still nothing? Try GetProcessImageFileName (but don't bother about Unicode)
// Note that GetProcessImageFileName uses '\Device\Harddisk#\Partition#' instead drive letters
if (!bGotExePath)
bGotExePath = (GetProcessImageFileNameA(processHandle, exe_path, MAX_PATH) != 0);
// Still nothing? Try GetProcessImageFileName. Note that GetProcessImageFileName uses
// '\Device\Harddisk#\Partition#\' instead drive letters
if (!bGotExePath) {
if (bGotExePath = (GetProcessImageFileNameW(processHandle, wexe_path, MAX_PATH) != 0))
wchar_to_utf8_no_alloc(wexe_path, exe_path, sizeof(exe_path));
}
// Complete failure => Just craft a default process name that includes the PID
if (!bGotExePath) {
@ -524,12 +518,51 @@ out:
if (exe_path[0] != 0)
vuprintf("You should close these applications before attempting to reformat the drive.");
else
vuprintf("NOTE: Could not identify the process(es) or service(s) accessing %s", HandleName);
vuprintf("NOTE: Could not identify the process(es) or service(s) accessing %s", _HandleName);
free(wHandleName);
PhFree(buffer);
PhFree(handles);
PhDestroyHeap();
ExitThread((DWORD)access_mask);
}
/**
* Search all the processes and list the ones that have a specific handle open.
*
* \param HandleName The name of the handle to look for.
* \param dwTimeOut The maximum amounf of time (ms) that may be spent searching
* \param bPartialMatch Whether partial matches should be allowed.
* \param bIgnoreSelf Whether the current process should be listed.
* \param bQuiet Prints minimal output.
*
* \return a byte containing the cummulated access rights (f----xwr) from all the handles found
* with bit 7 ('f') also set if at least one process was found.
*/
BYTE SearchProcess(char* HandleName, DWORD dwTimeOut, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet)
{
HANDLE handle;
DWORD dw = 0;
_HandleName = HandleName;
_bPartialMatch = bPartialMatch;
_bIgnoreSelf = bIgnoreSelf;
_bQuiet = bQuiet;
access_mask = 0;
handle = CreateThread(NULL, 0, SearchProcessThread, NULL, 0, NULL);
if (handle == NULL) {
uprintf("Unable to create process search thread");
return 0x00;
}
dw = WaitForSingleObject(handle, dwTimeOut);
if (dw == WAIT_TIMEOUT) {
// Timeout - kill the thread
TerminateThread(handle, 0);
uprintf("Warning: Killed process search thread");
} else if (dw != WAIT_OBJECT_0) {
uprintf("Failed to wait for process search thread: %s", WindowsErrorString());
}
return access_mask;
}

View File

@ -2172,7 +2172,7 @@ static BOOL CheckDriveAccess(void)
// Search for any blocking processes against the physical drive
PhysicalPath = GetPhysicalName(DeviceNum);
QueryDosDeviceA(&PhysicalPath[4], DevPath, sizeof(DevPath));
access_mask = SearchProcess(DevPath, TRUE, TRUE, TRUE);
access_mask = SearchProcess(DevPath, 2000, TRUE, TRUE, TRUE);
if (access_mask != 0) {
bProceed = FALSE;
uprintf("Found potentially blocking process(es) against %s:", &PhysicalPath[4]);
@ -2187,7 +2187,7 @@ static BOOL CheckDriveAccess(void)
drive_name[0] = drive_letter[i];
if (QueryDosDeviceA(drive_name, DevPath, sizeof(DevPath)) != 0) {
StrArrayClear(&BlockingProcess);
access_mask = SearchProcess(DevPath, TRUE, TRUE, TRUE);
access_mask = SearchProcess(DevPath, 2000, TRUE, TRUE, TRUE);
// Ignore if all we have is read-only
if ((access_mask & 0x06) || (access_mask == 0x80)) {
bProceed = FALSE;

View File

@ -497,7 +497,7 @@ extern char* GetCurrentMUI(void);
extern char* GetMuiString(char* szModuleName, UINT uID);
extern BOOL SetFormatPromptHook(void);
extern void ClrFormatPromptHook(void);
extern BYTE SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet);
extern BYTE SearchProcess(char* HandleName, DWORD dwTimeout, BOOL bPartialMatch, BOOL bIgnoreSelf, BOOL bQuiet);
extern BOOL EnablePrivileges(void);
extern void FlashTaskbar(HANDLE handle);

View File

@ -33,7 +33,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
IDD_DIALOG DIALOGEX 12, 12, 242, 376
STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
EXSTYLE WS_EX_ACCEPTFILES
CAPTION "Rufus 2.16.1145"
CAPTION "Rufus 2.16.1146"
FONT 8, "Segoe UI Symbol", 400, 0, 0x0
BEGIN
LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8
@ -366,8 +366,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 2,16,1145,0
PRODUCTVERSION 2,16,1145,0
FILEVERSION 2,16,1146,0
PRODUCTVERSION 2,16,1146,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@ -384,13 +384,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus"
VALUE "FileVersion", "2.16.1145"
VALUE "FileVersion", "2.16.1146"
VALUE "InternalName", "Rufus"
VALUE "LegalCopyright", "© 2011-2017 Pete Batard (GPL v3)"
VALUE "LegalTrademarks", "http://www.gnu.org/copyleft/gpl.html"
VALUE "OriginalFilename", "rufus.exe"
VALUE "ProductName", "Rufus"
VALUE "ProductVersion", "2.16.1145"
VALUE "ProductVersion", "2.16.1146"
END
END
BLOCK "VarFileInfo"