diff --git a/src/.clang/rufus.vcxproj b/src/.clang/rufus.vcxproj
index aab1308d..871e78a4 100644
--- a/src/.clang/rufus.vcxproj
+++ b/src/.clang/rufus.vcxproj
@@ -210,6 +210,7 @@
+
@@ -225,6 +226,7 @@
+
diff --git a/src/.clang/rufus.vcxproj.filters b/src/.clang/rufus.vcxproj.filters
index 45f75f62..a2a22b5c 100644
--- a/src/.clang/rufus.vcxproj.filters
+++ b/src/.clang/rufus.vcxproj.filters
@@ -75,6 +75,9 @@
Source Files
+
+ Source Files
+
@@ -143,6 +146,9 @@
Header Files
+
+ Header Files
+
diff --git a/src/.msvc/rufus.vcxproj b/src/.msvc/rufus.vcxproj
index cdf0851c..5ace4593 100644
--- a/src/.msvc/rufus.vcxproj
+++ b/src/.msvc/rufus.vcxproj
@@ -193,6 +193,7 @@
+
@@ -208,6 +209,7 @@
+
diff --git a/src/.msvc/rufus.vcxproj.filters b/src/.msvc/rufus.vcxproj.filters
index 45f75f62..a2a22b5c 100644
--- a/src/.msvc/rufus.vcxproj.filters
+++ b/src/.msvc/rufus.vcxproj.filters
@@ -75,6 +75,9 @@
Source Files
+
+ Source Files
+
@@ -143,6 +146,9 @@
Header Files
+
+ Header Files
+
diff --git a/src/Makefile.am b/src/Makefile.am
index a46a084c..fd26d668 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,8 +11,8 @@ AM_V_WINDRES = $(AM_V_WINDRES_$(V))
$(AM_V_WINDRES) $(AM_RCFLAGS) -i $< -o $@
rufus_SOURCES = badblocks.c checksum.c dev.c dos.c dos_locale.c drive.c format.c icon.c iso.c localization.c \
- net.c parser.c pki.c rufus.c smart.c stdfn.c stdio.c stdlg.c syslinux.c vhd.c
+ net.c parser.c pki.c rufus.c search.c smart.c stdfn.c stdio.c stdlg.c syslinux.c vhd.c
rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS)
rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows
rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \
- libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust -lcomdlg32 -luuid
+ libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust -lcomdlg32 -luuid -lpsapi
diff --git a/src/Makefile.in b/src/Makefile.in
index c306667e..abee2dd9 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -93,10 +93,10 @@ am_rufus_OBJECTS = rufus-badblocks.$(OBJEXT) rufus-checksum.$(OBJEXT) \
rufus-format.$(OBJEXT) rufus-icon.$(OBJEXT) \
rufus-iso.$(OBJEXT) rufus-localization.$(OBJEXT) \
rufus-net.$(OBJEXT) rufus-parser.$(OBJEXT) rufus-pki.$(OBJEXT) \
- rufus-rufus.$(OBJEXT) rufus-smart.$(OBJEXT) \
- rufus-stdfn.$(OBJEXT) rufus-stdio.$(OBJEXT) \
- rufus-stdlg.$(OBJEXT) rufus-syslinux.$(OBJEXT) \
- rufus-vhd.$(OBJEXT)
+ rufus-rufus.$(OBJEXT) rufus-search.$(OBJEXT) \
+ rufus-smart.$(OBJEXT) rufus-stdfn.$(OBJEXT) \
+ rufus-stdio.$(OBJEXT) rufus-stdlg.$(OBJEXT) \
+ rufus-syslinux.$(OBJEXT) rufus-vhd.$(OBJEXT)
rufus_OBJECTS = $(am_rufus_OBJECTS)
rufus_DEPENDENCIES = rufus_rc.o bled/libbled.a ms-sys/libmssys.a \
syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a \
@@ -271,12 +271,12 @@ AM_V_WINDRES_1 = $(WINDRES)
AM_V_WINDRES_ = $(AM_V_WINDRES_$(AM_DEFAULT_VERBOSITY))
AM_V_WINDRES = $(AM_V_WINDRES_$(V))
rufus_SOURCES = badblocks.c checksum.c dev.c dos.c dos_locale.c drive.c format.c icon.c iso.c localization.c \
- net.c parser.c pki.c rufus.c smart.c stdfn.c stdio.c stdlg.c syslinux.c vhd.c
+ net.c parser.c pki.c rufus.c search.c smart.c stdfn.c stdio.c stdlg.c syslinux.c vhd.c
rufus_CFLAGS = -I./ms-sys/inc -I./syslinux/libfat -I./syslinux/libinstaller -I./syslinux/win -I./libcdio $(AM_CFLAGS)
rufus_LDFLAGS = $(AM_LDFLAGS) -mwindows
rufus_LDADD = rufus_rc.o bled/libbled.a ms-sys/libmssys.a syslinux/libfat/libfat.a syslinux/libinstaller/libinstaller.a syslinux/win/libwin.a \
- libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust -lcomdlg32 -luuid
+ libcdio/iso9660/libiso9660.a libcdio/udf/libudf.a libcdio/driver/libdriver.a -lsetupapi -lole32 -lgdi32 -lwininet -lshlwapi -lcrypt32 -lwintrust -lcomdlg32 -luuid -lpsapi
all: all-recursive
@@ -416,6 +416,12 @@ rufus-rufus.o: rufus.c
rufus-rufus.obj: rufus.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-rufus.obj `if test -f 'rufus.c'; then $(CYGPATH_W) 'rufus.c'; else $(CYGPATH_W) '$(srcdir)/rufus.c'; fi`
+rufus-search.o: search.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-search.o `test -f 'search.c' || echo '$(srcdir)/'`search.c
+
+rufus-search.obj: search.c
+ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-search.obj `if test -f 'search.c'; then $(CYGPATH_W) 'search.c'; else $(CYGPATH_W) '$(srcdir)/search.c'; fi`
+
rufus-smart.o: smart.c
$(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(rufus_CFLAGS) $(CFLAGS) -c -o rufus-smart.o `test -f 'smart.c' || echo '$(srcdir)/'`smart.c
diff --git a/src/drive.c b/src/drive.c
index d072f01d..6105c3d9 100644
--- a/src/drive.c
+++ b/src/drive.c
@@ -127,8 +127,7 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr
if ((safe_strlen(Path) < 5) || (Path[0] != '\\') || (Path[1] != '\\') || (Path[3] != '\\'))
goto out;
- // Resolve a device path, so that users can seek for it in Process Explorer
- // in case of access issues.
+ // Resolve a device path, so that we can look for that handle in case of access issues.
if (QueryDosDeviceA(&Path[4], DevPath, sizeof(DevPath)) == 0)
strcpy(DevPath, "???");
@@ -151,6 +150,7 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr
// If we can't seem to get a hold of the drive for some time,
// try to enable FILE_SHARE_WRITE...
uprintf("Warning: Could not obtain exclusive rights. Retrying with write sharing enabled...");
+ SearchProcess(DevPath, TRUE, TRUE);
bWriteShare = TRUE;
}
Sleep(DRIVE_ACCESS_TIMEOUT / DRIVE_ACCESS_RETRIES);
@@ -161,7 +161,7 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr
}
if (bWriteAccess) {
- uprintf("Opened %s [%s] for write access\n", Path, DevPath);
+ uprintf("Opened %s [%s] for write access", Path, DevPath);
}
if (bLockDrive) {
@@ -177,7 +177,10 @@ static HANDLE GetHandle(char* Path, BOOL bLockDrive, BOOL bWriteAccess, BOOL bWr
Sleep(DRIVE_ACCESS_TIMEOUT/DRIVE_ACCESS_RETRIES);
}
// If we reached this section, either we didn't manage to get a lock or the user cancelled
- uprintf("Could not get exclusive access to %s [%s]: %s\n", Path, DevPath, WindowsErrorString());
+ uprintf("Could not get exclusive access to %s: %s", Path, WindowsErrorString());
+ // See if we can tell the user what processes are accessing the drive
+ if (!IS_ERROR(FormatStatus))
+ SearchProcess(DevPath, TRUE, TRUE);
safe_closehandle(hDrive);
}
diff --git a/src/license.h b/src/license.h
index 0fdc08d3..dfc83094 100644
--- a/src/license.h
+++ b/src/license.h
@@ -84,6 +84,10 @@ const char* additional_copyrights =
"http://www.codeguru.com/forum/showthread.php?p=1951973\\line\n"
"Public Domain\\line\n"
"\\line\n"
+"Handle search & process enumeration from Process Hacker by wj32 & dmex:\\line\n"
+"http://processhacker.sourceforge.net/\\line\n"
+"GNU General Public License (GPL) v3 or later\\line\n"
+"\\line\n"
"Decompression support from BusyBox/Bled:\\line\n"
"http://www.busybox.net/\\line\n"
"https://github.com/pbatard/bled\\line\n"
diff --git a/src/msapi_utf8.h b/src/msapi_utf8.h
index 7317def4..9f71a5ff 100644
--- a/src/msapi_utf8.h
+++ b/src/msapi_utf8.h
@@ -31,6 +31,9 @@
#include
#include
#include
+#if !defined(DDKBUILD)
+#include
+#endif
#pragma once
#if defined(_MSC_VER)
@@ -125,6 +128,31 @@ static __inline wchar_t* utf8_to_wchar(const char* str)
return wstr;
}
+/*
+* Converts an non NUL-terminated UTF-16 string of length len to UTF8 (allocate returned string)
+* Returns NULL on error
+*/
+static __inline char* wchar_len_to_utf8(const wchar_t* wstr, int wlen)
+{
+ int size = 0;
+ char* str = NULL;
+
+ // Find out the size we need to allocate for our converted string
+ size = WideCharToMultiByte(CP_UTF8, 0, wstr, wlen, NULL, 0, NULL, NULL);
+ if (size <= 1) // An empty string would be size 1
+ return NULL;
+
+ if ((str = (char*)calloc(size, 1)) == NULL)
+ return NULL;
+
+ if (WideCharToMultiByte(CP_UTF8, 0, wstr, wlen, str, size, NULL, NULL) != size) {
+ sfree(str);
+ return NULL;
+ }
+
+ return str;
+}
+
static __inline DWORD FormatMessageU(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId,
DWORD dwLanguageId, char* lpBuffer, DWORD nSize, va_list *Arguments)
{
@@ -554,6 +582,24 @@ static __inline DWORD GetModuleFileNameU(HMODULE hModule, char* lpFilename, DWOR
return ret;
}
+#if !defined(DDKBUILD)
+static __inline DWORD GetModuleFileNameExU(HANDLE hProcess, HMODULE hModule, char* lpFilename, DWORD nSize)
+{
+ DWORD ret = 0, err = ERROR_INVALID_DATA;
+ // coverity[returned_null]
+ walloc(lpFilename, nSize);
+ ret = GetModuleFileNameExW(hProcess, hModule, wlpFilename, nSize);
+ err = GetLastError();
+ if ((ret != 0)
+ && ((ret = wchar_to_utf8_no_alloc(wlpFilename, lpFilename, nSize)) == 0)) {
+ err = GetLastError();
+ }
+ wfree(lpFilename);
+ SetLastError(err);
+ return ret;
+}
+#endif
+
static __inline DWORD GetFullPathNameU(const char* lpFileName, DWORD nBufferLength, char* lpBuffer, char** lpFilePart)
{
DWORD ret = 0, err = ERROR_INVALID_DATA;
diff --git a/src/rufus.c b/src/rufus.c
index 84c3fe37..ec908f85 100644
--- a/src/rufus.c
+++ b/src/rufus.c
@@ -3469,3 +3469,11 @@ out:
return 0;
}
+
+// The old WDK is showing its age and becoming a pain to support
+#if defined(DDKBUILD)
+BOOL SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf) {
+ uprintf("NOTE: Process search is not implemented on this platform");
+ return FALSE;
+}
+#endif
diff --git a/src/rufus.h b/src/rufus.h
index e9cce68c..c9e548ff 100644
--- a/src/rufus.h
+++ b/src/rufus.h
@@ -498,6 +498,7 @@ extern BOOL IsCurrentProcessElevated(void);
extern char* GetCurrentMUI(void);
extern BOOL SetFormatPromptHook(void);
extern void ClrFormatPromptHook(void);
+extern BOOL SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf);
DWORD WINAPI FormatThread(void* param);
DWORD WINAPI SaveImageThread(void* param);
diff --git a/src/rufus.rc b/src/rufus.rc
index 01d89e23..ebd26728 100644
--- a/src/rufus.rc
+++ b/src/rufus.rc
@@ -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.15.1094"
+CAPTION "Rufus 2.15.1095"
FONT 8, "Segoe UI Symbol", 400, 0, 0x0
BEGIN
LTEXT "Device",IDS_DEVICE_TXT,9,6,200,8
@@ -334,8 +334,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,15,1094,0
- PRODUCTVERSION 2,15,1094,0
+ FILEVERSION 2,15,1095,0
+ PRODUCTVERSION 2,15,1095,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -352,13 +352,13 @@ BEGIN
BEGIN
VALUE "CompanyName", "Akeo Consulting (http://akeo.ie)"
VALUE "FileDescription", "Rufus"
- VALUE "FileVersion", "2.15.1094"
+ VALUE "FileVersion", "2.15.1095"
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.15.1094"
+ VALUE "ProductVersion", "2.15.1095"
END
END
BLOCK "VarFileInfo"
diff --git a/src/search.c b/src/search.c
new file mode 100644
index 00000000..421166b2
--- /dev/null
+++ b/src/search.c
@@ -0,0 +1,358 @@
+/*
+ * Rufus: The Reliable USB Formatting Utility
+ * Search functionality for handles
+ *
+ * Modified from Process Hacker:
+ * https://github.com/processhacker2/processhacker2/
+ * Copyright © 2009-2016 wj32
+ * Copyright © 2017 dmex
+ * Copyright © 2017 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifdef _CRTDBG_MAP_ALLOC
+#include
+#include
+#endif
+
+#include
+
+#include "rufus.h"
+#include "search.h"
+#include "missing.h"
+#include "msapi_utf8.h"
+
+PF_TYPE_DECL(NTAPI, PVOID, RtlCreateHeap, (ULONG, PVOID, SIZE_T, SIZE_T, PVOID, PRTL_HEAP_PARAMETERS));
+PF_TYPE_DECL(NTAPI, PVOID, RtlAllocateHeap, (PVOID, ULONG, SIZE_T));
+PF_TYPE_DECL(NTAPI, BOOLEAN, RtlFreeHeap, (PVOID, ULONG, PVOID));
+
+PF_TYPE_DECL(NTAPI, NTSTATUS, NtQuerySystemInformation, (SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG));
+PF_TYPE_DECL(NTAPI, NTSTATUS, NtQueryObject, (HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG));
+PF_TYPE_DECL(NTAPI, NTSTATUS, NtDuplicateObject, (HANDLE, HANDLE, HANDLE, PHANDLE, ACCESS_MASK, ULONG, ULONG));
+PF_TYPE_DECL(NTAPI, NTSTATUS, NtOpenProcess, (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES, PCLIENT_ID));
+PF_TYPE_DECL(NTAPI, NTSTATUS, NtClose, (HANDLE));
+
+PVOID PhHeapHandle = NULL;
+
+/*
+ * Convert an NT Status to an error message
+ *
+ * \param Status An operattonal status.
+ *
+ * \return An error message string.
+ *
+ */
+static char* NtStatusError(NTSTATUS Status) {
+ static char unknown[32];
+
+ switch (Status) {
+ case STATUS_UNSUCCESSFUL:
+ return "Operation Failed";
+ case STATUS_NOT_IMPLEMENTED:
+ return "Not Implemented";
+ case STATUS_BUFFER_OVERFLOW:
+ return "Buffer Overflow";
+ case STATUS_INVALID_HANDLE:
+ return "Invalid Handle.";
+ case STATUS_INVALID_PARAMETER:
+ return "Invalid Parameter";
+ case STATUS_NO_MEMORY:
+ return "Not Enough Quota";
+ case STATUS_ACCESS_DENIED:
+ return "Access Denied";
+ case STATUS_BUFFER_TOO_SMALL:
+ return "Buffer Too Small";
+ case STATUS_OBJECT_TYPE_MISMATCH:
+ return "Wrong Type";
+ case STATUS_OBJECT_NAME_INVALID:
+ return "Object Name invalid";
+ case STATUS_OBJECT_NAME_NOT_FOUND:
+ return "Object Name not found";
+ case STATUS_SHARING_VIOLATION:
+ return "Sharing Violation";
+ case STATUS_INSUFFICIENT_RESOURCES:
+ return "Insufficient resources";
+ case STATUS_NOT_SUPPORTED:
+ return "Operation is not supported";
+ default:
+ safe_sprintf(unknown, sizeof(unknown), "Unknown error 0x%08lx", Status);
+ return unknown;
+ }
+}
+
+/**
+ * Allocates a block of memory.
+ *
+ * \param Size The number of bytes to allocate.
+ *
+ * \return A pointer to the allocated block of memory.
+ *
+ */
+static PVOID PhAllocate(SIZE_T Size)
+{
+ PF_INIT_OR_OUT(RtlCreateHeap, Ntdll);
+ PF_INIT_OR_OUT(RtlAllocateHeap, Ntdll);
+
+ if (PhHeapHandle == NULL) {
+ PhHeapHandle = pfRtlCreateHeap(HEAP_GROWABLE, NULL, 2 * MB, 1 * MB, NULL, NULL);
+ }
+ return pfRtlAllocateHeap(PhHeapHandle, 0, Size);
+out:
+ return NULL;
+}
+
+/**
+ * Frees a block of memory allocated with PhAllocate().
+ *
+ * \param Memory A pointer to a block of memory.
+ *
+ */
+static VOID PhFree(PVOID Memory)
+{
+ PF_INIT(RtlFreeHeap, Ntdll);
+ if (pfRtlFreeHeap != NULL)
+ pfRtlFreeHeap(PhHeapHandle, 0, Memory);
+}
+
+/**
+ * Enumerates all open handles.
+ *
+ * \param Handles A variable which receives a pointer to a structure containing information about
+ * all opened handles. You must free the structure using PhFree() when you no longer need it.
+ *
+ * \return An NTStatus indicating success or the error code.
+ */
+NTSTATUS PhEnumHandlesEx(PSYSTEM_HANDLE_INFORMATION_EX *Handles)
+{
+ static ULONG initialBufferSize = 0x10000;
+ NTSTATUS status;
+ PVOID buffer;
+ ULONG bufferSize;
+
+ PF_INIT(NtQuerySystemInformation, Ntdll);
+ if (pfNtQuerySystemInformation == NULL)
+ return STATUS_NOT_IMPLEMENTED;
+
+ bufferSize = initialBufferSize;
+ buffer = PhAllocate(bufferSize);
+ if (buffer == NULL)
+ return STATUS_NO_MEMORY;
+
+ while ((status = pfNtQuerySystemInformation(SystemExtendedHandleInformation,
+ buffer, bufferSize, NULL)) == STATUS_INFO_LENGTH_MISMATCH) {
+ PhFree(buffer);
+ bufferSize *= 2;
+
+ // Fail if we're resizing the buffer to something very large.
+ if (bufferSize > PH_LARGE_BUFFER_SIZE)
+ return STATUS_INSUFFICIENT_RESOURCES;
+
+ buffer = PhAllocate(bufferSize);
+ if (buffer == NULL)
+ return STATUS_NO_MEMORY;
+ }
+
+ if (!NT_SUCCESS(status)) {
+ PhFree(buffer);
+ return status;
+ }
+
+ if (bufferSize <= 0x200000)
+ initialBufferSize = bufferSize;
+ *Handles = (PSYSTEM_HANDLE_INFORMATION_EX)buffer;
+
+ return status;
+}
+
+/**
+ * Opens a process.
+ *
+ * \param ProcessHandle A variable which receives a handle to the process.
+ * \param DesiredAccess The desired access to the process.
+ * \param ProcessId The ID of the process.
+ *
+ * \return An NTStatus indicating success or the error code.
+ */
+NTSTATUS PhOpenProcess(PHANDLE ProcessHandle, ACCESS_MASK DesiredAccess, HANDLE ProcessId)
+{
+ NTSTATUS status = STATUS_NOT_IMPLEMENTED;
+ OBJECT_ATTRIBUTES objectAttributes;
+ CLIENT_ID clientId;
+
+ if ((LONG_PTR)ProcessId == (LONG_PTR)GetCurrentProcessId()) {
+ *ProcessHandle = NtCurrentProcess();
+ return 0;
+ }
+
+ PF_INIT_OR_OUT(NtOpenProcess, Ntdll);
+
+ clientId.UniqueProcess = ProcessId;
+ clientId.UniqueThread = NULL;
+
+ InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);
+ status = pfNtOpenProcess(ProcessHandle, DesiredAccess, &objectAttributes, &clientId);
+
+out:
+ 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.
+ *
+ * \return TRUE if matching processes were found, FALSE otherwise.
+ */
+BOOL SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf)
+{
+ NTSTATUS status;
+ PSYSTEM_HANDLE_INFORMATION_EX handles;
+ POBJECT_NAME_INFORMATION buffer;
+ ULONG_PTR i;
+ ULONG bufferSize;
+ USHORT wHandleNameLen;
+ WCHAR *wHandleName;
+ HANDLE dupHandle = NULL;
+ HANDLE processHandle = NULL;
+ BOOLEAN bFound = FALSE;
+ char exe_path[2][MAX_PATH];
+ int cur;
+
+ status = STATUS_NOT_IMPLEMENTED;
+ PF_INIT(NtQueryObject, Ntdll);
+ PF_INIT(NtDuplicateObject, NtDll);
+ PF_INIT(NtClose, NtDll);
+ if ((pfNtQueryObject != NULL) && (pfNtClose != NULL) && (pfNtDuplicateObject != NULL))
+ status = 0;
+
+ if (NT_SUCCESS(status))
+ status = PhEnumHandlesEx(&handles);
+ if (!NT_SUCCESS(status)) {
+ uprintf("Could not enumerate handles: %s", NtStatusError(status));
+ return FALSE;
+ }
+
+
+ exe_path[0][0] = 0;
+ cur = 1;
+
+ wHandleName = utf8_to_wchar(HandleName);
+ wHandleNameLen = (USHORT) wcslen(wHandleName);
+
+ bufferSize = 0x200;
+ buffer = PhAllocate(bufferSize);
+
+ for (i = 0; ; i++) {
+ ULONG attempts = 8;
+ PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo = &handles->Handles[i];
+
+ if ((dupHandle != NULL) && (processHandle != NtCurrentProcess())) {
+ pfNtClose(dupHandle);
+ dupHandle = NULL;
+ }
+ if (processHandle != NULL) {
+ if (processHandle != NtCurrentProcess())
+ pfNtClose(processHandle);
+ processHandle = NULL;
+ }
+
+ CHECK_FOR_USER_CANCEL;
+
+ // Exit loop condition
+ if (i >= handles->NumberOfHandles)
+ break;
+
+ // Get the process that created the handle we are after
+ // TODO: We probably should keep a list of the most recent processes and perform a lookup
+ // instead of Opening the process every time
+ status = PhOpenProcess(&processHandle, PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION,
+ (HANDLE)handleInfo->UniqueProcessId);
+ // There exists some processes we can't access
+ if (!NT_SUCCESS(status))
+ continue;
+
+ // Must duplicate the handle onto our own process, before we can access its properties
+ if (processHandle == NtCurrentProcess()) {
+ if (bIgnoreSelf)
+ continue;
+ dupHandle = (HANDLE)handleInfo->HandleValue;
+ } else {
+ status = pfNtDuplicateObject(processHandle, (HANDLE)handleInfo->HandleValue,
+ NtCurrentProcess(), &dupHandle, 0, 0, 0);
+ // Why does it always work for Process Hacker and not me???
+ if (!NT_SUCCESS(status))
+ continue;
+ }
+
+ // Filter non-storage handles. We're not interested in them and they make NtQueryObject() freeze
+ if (GetFileType(dupHandle) != FILE_TYPE_DISK)
+ continue;
+
+ // A loop is needed because the I/O subsystem likes to give us the wrong return lengths...
+ do {
+ status = pfNtQueryObject(dupHandle, ObjectBasicInformation + 1,
+ buffer, bufferSize, &bufferSize);
+ if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH ||
+ status == STATUS_BUFFER_TOO_SMALL) {
+ PhFree(buffer);
+ buffer = PhAllocate(bufferSize);
+ } else {
+ break;
+ }
+ } while (--attempts);
+ if (!NT_SUCCESS(status))
+ continue;
+
+ // Don't bother comparing if we are looking for full match and the length is different
+ 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))
+ continue;
+
+ // Match against our target string
+ if (wcsncmp(wHandleName, buffer->Name.Buffer, wHandleNameLen) != 0)
+ continue;
+
+ if (!bFound) {
+ uprintf("\r\nNOTE: The following process(es) are accessing %s:", HandleName);
+ bFound = TRUE;
+ }
+
+ // TODO: only list processes with conflicting access rights (ignore "Read attributes" or "Synchronize")
+ if (GetModuleFileNameExU(processHandle, 0, exe_path[cur], MAX_PATH - 1)) {
+ // Avoid printing the same path repeatedly
+ if (strcmp(exe_path[0], exe_path[1]) != 0) {
+ uprintf("o %s", exe_path[cur]);
+ cur = (cur + 1) % 2;
+ }
+ } else {
+ uprintf("o Unknown (Process ID %d)", GetProcessId(processHandle));
+ }
+ }
+
+out:
+ if (bFound)
+ uprintf("You should try to close these applications before attempting to reformat the drive.");
+ else
+ uprintf("NOTE: " APPLICATION_NAME " was not able to identify the process(es) preventing access to %s", HandleName);
+
+ free(wHandleName);
+ PhFree(buffer);
+ return bFound;
+}
diff --git a/src/search.h b/src/search.h
new file mode 100644
index 00000000..92cd8841
--- /dev/null
+++ b/src/search.h
@@ -0,0 +1,186 @@
+/*
+ * Rufus: The Reliable USB Formatting Utility
+ * Search functionality for handles
+ *
+ * Modified from Process Hacker:
+ * https://github.com/processhacker2/processhacker2/
+ * Copyright © 2009-2016 wj32
+ * Copyright © 2017 dmex
+ * Copyright © 2017 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
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include
+
+#pragma once
+
+#define PH_LARGE_BUFFER_SIZE (256 * 1024 * 1024)
+
+#define STATUS_UNSUCCESSFUL ((NTSTATUS)0x80000001L)
+#define STATUS_BUFFER_OVERFLOW ((NTSTATUS)0x80000005L)
+#define STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L)
+#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L)
+//#define STATUS_INVALID_HANDLE ((NTSTATUS)0xC0000008L)
+#define STATUS_ACCESS_DENIED ((NTSTATUS)0xC0000022L)
+#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023L)
+#define STATUS_OBJECT_TYPE_MISMATCH ((NTSTATUS)0xC0000024L)
+#define STATUS_OBJECT_NAME_INVALID ((NTSTATUS)0xC0000033L)
+#define STATUS_OBJECT_NAME_NOT_FOUND ((NTSTATUS)0xC0000034L)
+#define STATUS_SHARING_VIOLATION ((NTSTATUS)0xC0000043L)
+#define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL)
+#define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL)
+
+#define SystemExtendedHandleInformation 64
+
+#define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1)
+
+typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX
+{
+ PVOID Object;
+ ULONG_PTR UniqueProcessId;
+ ULONG_PTR HandleValue;
+ ULONG GrantedAccess;
+ USHORT CreatorBackTraceIndex;
+ USHORT ObjectTypeIndex;
+ ULONG HandleAttributes;
+ ULONG Reserved;
+} SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX;
+
+typedef struct _SYSTEM_HANDLE_INFORMATION_EX
+{
+ ULONG_PTR NumberOfHandles;
+ ULONG_PTR Reserved;
+ SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
+} SYSTEM_HANDLE_INFORMATION_EX, *PSYSTEM_HANDLE_INFORMATION_EX;
+
+#if defined(_MSC_VER)
+typedef struct _OBJECT_NAME_INFORMATION
+{
+ UNICODE_STRING Name;
+} OBJECT_NAME_INFORMATION, *POBJECT_NAME_INFORMATION;
+
+typedef struct _CLIENT_ID
+{
+ HANDLE UniqueProcess;
+ HANDLE UniqueThread;
+} CLIENT_ID, *PCLIENT_ID;
+#endif
+
+// Heaps
+
+typedef struct _RTL_HEAP_ENTRY
+{
+ SIZE_T Size;
+ USHORT Flags;
+ USHORT AllocatorBackTraceIndex;
+ union
+ {
+ struct
+ {
+ SIZE_T Settable;
+ ULONG Tag;
+ } s1;
+ struct
+ {
+ SIZE_T CommittedSize;
+ PVOID FirstBlock;
+ } s2;
+ } u;
+} RTL_HEAP_ENTRY, *PRTL_HEAP_ENTRY;
+
+#define RTL_HEAP_BUSY (USHORT)0x0001
+#define RTL_HEAP_SEGMENT (USHORT)0x0002
+#define RTL_HEAP_SETTABLE_VALUE (USHORT)0x0010
+#define RTL_HEAP_SETTABLE_FLAG1 (USHORT)0x0020
+#define RTL_HEAP_SETTABLE_FLAG2 (USHORT)0x0040
+#define RTL_HEAP_SETTABLE_FLAG3 (USHORT)0x0080
+#define RTL_HEAP_SETTABLE_FLAGS (USHORT)0x00e0
+#define RTL_HEAP_UNCOMMITTED_RANGE (USHORT)0x0100
+#define RTL_HEAP_PROTECTED_ENTRY (USHORT)0x0200
+
+typedef struct _RTL_HEAP_TAG
+{
+ ULONG NumberOfAllocations;
+ ULONG NumberOfFrees;
+ SIZE_T BytesAllocated;
+ USHORT TagIndex;
+ USHORT CreatorBackTraceIndex;
+ WCHAR TagName[24];
+} RTL_HEAP_TAG, *PRTL_HEAP_TAG;
+
+typedef struct _RTL_HEAP_INFORMATION
+{
+ PVOID BaseAddress;
+ ULONG Flags;
+ USHORT EntryOverhead;
+ USHORT CreatorBackTraceIndex;
+ SIZE_T BytesAllocated;
+ SIZE_T BytesCommitted;
+ ULONG NumberOfTags;
+ ULONG NumberOfEntries;
+ ULONG NumberOfPseudoTags;
+ ULONG PseudoTagGranularity;
+ ULONG Reserved[5];
+ PRTL_HEAP_TAG Tags;
+ PRTL_HEAP_ENTRY Entries;
+} RTL_HEAP_INFORMATION, *PRTL_HEAP_INFORMATION;
+
+typedef struct _RTL_PROCESS_HEAPS
+{
+ ULONG NumberOfHeaps;
+ RTL_HEAP_INFORMATION Heaps[1];
+} RTL_PROCESS_HEAPS, *PRTL_PROCESS_HEAPS;
+
+typedef NTSTATUS(NTAPI *PRTL_HEAP_COMMIT_ROUTINE)(
+ _In_ PVOID Base,
+ _Inout_ PVOID *CommitAddress,
+ _Inout_ PSIZE_T CommitSize
+ );
+
+#if defined(_MSC_VER)
+typedef struct _RTL_HEAP_PARAMETERS
+{
+ ULONG Length;
+ SIZE_T SegmentReserve;
+ SIZE_T SegmentCommit;
+ SIZE_T DeCommitFreeBlockThreshold;
+ SIZE_T DeCommitTotalFreeThreshold;
+ SIZE_T MaximumAllocationSize;
+ SIZE_T VirtualMemoryThreshold;
+ SIZE_T InitialCommit;
+ SIZE_T InitialReserve;
+ PRTL_HEAP_COMMIT_ROUTINE CommitRoutine;
+ SIZE_T Reserved[2];
+} RTL_HEAP_PARAMETERS, *PRTL_HEAP_PARAMETERS;
+#endif
+
+#define HEAP_SETTABLE_USER_VALUE 0x00000100
+#define HEAP_SETTABLE_USER_FLAG1 0x00000200
+#define HEAP_SETTABLE_USER_FLAG2 0x00000400
+#define HEAP_SETTABLE_USER_FLAG3 0x00000800
+#define HEAP_SETTABLE_USER_FLAGS 0x00000e00
+
+#define HEAP_CLASS_0 0x00000000 // Process heap
+#define HEAP_CLASS_1 0x00001000 // Private heap
+#define HEAP_CLASS_2 0x00002000 // Kernel heap
+#define HEAP_CLASS_3 0x00003000 // GDI heap
+#define HEAP_CLASS_4 0x00004000 // User heap
+#define HEAP_CLASS_5 0x00005000 // Console heap
+#define HEAP_CLASS_6 0x00006000 // User desktop heap
+#define HEAP_CLASS_7 0x00007000 // CSR shared heap
+#define HEAP_CLASS_8 0x00008000 // CSR port heap
+#define HEAP_CLASS_MASK 0x0000f000
diff --git a/src/stdfn.c b/src/stdfn.c
index 6f3231e3..579571c6 100644
--- a/src/stdfn.c
+++ b/src/stdfn.c
@@ -717,19 +717,19 @@ DWORD WINAPI SetLGPThread(LPVOID param)
// We need an IGroupPolicyObject instance to set a Local Group Policy
hr = CoCreateInstance(&my_CLSID_GroupPolicyObject, NULL, CLSCTX_INPROC_SERVER, &my_IID_IGroupPolicyObject, (LPVOID*)&pLGPO);
if (FAILED(hr)) {
- ubprintf("SetLGP: CoCreateInstance failed; hr = %x", hr);
+ ubprintf("SetLGP: CoCreateInstance failed; hr = %lx", hr);
goto error;
}
hr = pLGPO->lpVtbl->OpenLocalMachineGPO(pLGPO, GPO_OPEN_LOAD_REGISTRY);
if (FAILED(hr)) {
- ubprintf("SetLGP: OpenLocalMachineGPO failed - error %x", hr);
+ ubprintf("SetLGP: OpenLocalMachineGPO failed - error %lx", hr);
goto error;
}
hr = pLGPO->lpVtbl->GetRegistryKey(pLGPO, GPO_SECTION_MACHINE, &path_key);
if (FAILED(hr)) {
- ubprintf("SetLGP: GetRegistryKey failed - error %x", hr);
+ ubprintf("SetLGP: GetRegistryKey failed - error %lx", hr);
goto error;
}
@@ -737,7 +737,7 @@ DWORD WINAPI SetLGPThread(LPVOID param)
r = RegCreateKeyExA(path_key, p->szPath, 0, NULL, 0, KEY_SET_VALUE | KEY_QUERY_VALUE,
NULL, &policy_key, &disp);
if (r != ERROR_SUCCESS) {
- ubprintf("SetLGP: Failed to open LGPO path %s - error %x", p->szPath, hr);
+ ubprintf("SetLGP: Failed to open LGPO path %s - error %lx", p->szPath, hr);
policy_key = NULL;
goto error;
}
@@ -751,7 +751,7 @@ DWORD WINAPI SetLGPThread(LPVOID param)
// The Key exists but not its value, which is OK
*(p->bExistingKey) = FALSE;
} else if (r != ERROR_SUCCESS) {
- ubprintf("SetLGP: Failed to read original %s policy value - error %x", p->szPolicy, r);
+ ubprintf("SetLGP: Failed to read original %s policy value - error %lx", p->szPolicy, r);
}
}
@@ -762,7 +762,7 @@ DWORD WINAPI SetLGPThread(LPVOID param)
r = RegDeleteValueA(policy_key, p->szPolicy);
}
if (r != ERROR_SUCCESS) {
- ubprintf("SetLGP: RegSetValueEx / RegDeleteValue failed - error %x", r);
+ ubprintf("SetLGP: RegSetValueEx / RegDeleteValue failed - error %lx", r);
}
RegCloseKey(policy_key);
policy_key = NULL;
@@ -770,11 +770,11 @@ DWORD WINAPI SetLGPThread(LPVOID param)
// Apply policy
hr = pLGPO->lpVtbl->Save(pLGPO, TRUE, (p->bRestore)?FALSE:TRUE, &ext_guid, &snap_guid);
if (hr != S_OK) {
- ubprintf("SetLGP: Unable to apply %s policy - error %x", p->szPolicy, hr);
+ ubprintf("SetLGP: Unable to apply %s policy - error %lx", p->szPolicy, hr);
goto error;
} else {
if ((!p->bRestore) || (*(p->bExistingKey))) {
- ubprintf("SetLGP: Successfully %s %s policy to 0x%08X", (p->bRestore)?"restored":"set", p->szPolicy, val);
+ ubprintf("SetLGP: Successfully %s %s policy to 0x%08lX", (p->bRestore)?"restored":"set", p->szPolicy, val);
} else {
ubprintf("SetLGP: Successfully removed %s policy key", p->szPolicy);
}
diff --git a/src/stdlg.c b/src/stdlg.c
index 51f0c232..21cd322d 100644
--- a/src/stdlg.c
+++ b/src/stdlg.c
@@ -1855,7 +1855,7 @@ void ClrFormatPromptHook(void) {
}
#ifdef RUFUS_TEST
-static inline LPWORD lpwAlign(LPWORD addr)
+static __inline LPWORD lpwAlign(LPWORD addr)
{
return (LPWORD)((((uintptr_t)addr) + 3) & (~3));
}