diff --git a/src/process.c b/src/process.c index 310b7a8ad6f..65c92074655 100644 --- a/src/process.c +++ b/src/process.c @@ -48,6 +48,7 @@ PF_TYPE_DECL(NTAPI, BOOLEAN, RtlEqualUnicodeString, (PCUNICODE_STRING, PCUNICODE #endif PF_TYPE_DECL(NTAPI, NTSTATUS, NtQuerySystemInformation, (SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG)); +PF_TYPE_DECL(NTAPI, NTSTATUS, NtQueryInformationFile, (HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS)); 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)); @@ -338,6 +339,54 @@ ULONG PhGetObjectTypeNumber(PUNICODE_STRING TypeName) } #endif +/** +* Query processes with open handles to a file, volume or disk. +* +* \param VolumeOrFileHandle The handle to the target. +* \param Information The returned list of processes. +* +* \return An NTStatus indicating success or the error code. +*/ +NTSTATUS PhQueryProcessesUsingVolumeOrFile(HANDLE VolumeOrFileHandle, + PFILE_PROCESS_IDS_USING_FILE_INFORMATION *Information) +{ + static ULONG initialBufferSize = 16 * KB; + NTSTATUS status = STATUS_SUCCESS; + PVOID buffer; + ULONG bufferSize; + IO_STATUS_BLOCK isb; + + PF_INIT_OR_SET_STATUS(NtQueryInformationFile, NtDll); + if (!NT_SUCCESS(status)) + return status; + + bufferSize = initialBufferSize; + buffer = PhAllocate(bufferSize); + if (buffer == NULL) + return STATUS_INSUFFICIENT_RESOURCES; + + while ((status = pfNtQueryInformationFile(VolumeOrFileHandle, &isb, buffer, bufferSize, + FileProcessIdsUsingFileInformation)) == STATUS_INFO_LENGTH_MISMATCH) { + PhFree(buffer); + bufferSize *= 2; + // Fail if we're resizing the buffer to something very large. + if (bufferSize > 64 * MB) + return STATUS_INSUFFICIENT_RESOURCES; + buffer = PhAllocate(bufferSize); + } + + if (!NT_SUCCESS(status)) { + PhFree(buffer); + return status; + } + + if (bufferSize <= 64 * MB) + initialBufferSize = bufferSize; + *Information = (PFILE_PROCESS_IDS_USING_FILE_INFORMATION)buffer; + + return status; +} + /** * Search all the processes and list the ones that have a specific handle open. * @@ -553,6 +602,51 @@ BOOL SearchProcess(char* HandleName, BOOL bPartialMatch, BOOL bIgnoreSelf) return bFound; } +/** + * Alternative search for processes keeping a handle on a specific disk or volume + * Note that this search requires opening the disk or volume, which may not always + * be convenient for our usage (since we might be looking for processes preventing + * us to open said target in exclusive mode). + * + * \param HandleName The name of the handle to look for. + * + * \return TRUE if processes were found, FALSE otherwise. + */ +BOOL SearchProcessAlt(char* HandleName) +{ + NTSTATUS status = STATUS_SUCCESS; + ULONG i; + HANDLE searchHandle = NULL; + BOOLEAN bFound = FALSE; + PFILE_PROCESS_IDS_USING_FILE_INFORMATION info = NULL; + + status = PhCreateHeap(); + if (!NT_SUCCESS(status)) + goto out; + + // Note that the access rights being used with CreateFile() might matter... + searchHandle = CreateFileA(HandleName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + status = PhQueryProcessesUsingVolumeOrFile(searchHandle, &info); + + if (NT_SUCCESS(status) && (info->NumberOfProcessIdsInList > 0)) { + bFound = TRUE; + uprintf("NOTE: The following process(es) or service(s) are accessing %s:", HandleName); + for (i = 0; i < info->NumberOfProcessIdsInList; i++) { + uprintf("o Process with PID %ld", info->ProcessIdList[i]); + } + } + +out: + safe_closehandle(searchHandle); + PhFree(info); + PhDestroyHeap(); + if (!NT_SUCCESS(status)) + uprintf("SearchProcessAlt('%s') failed: %s", HandleName, NtStatusError(status)); + return bFound; +} + /** * Increase the privileges of the current application. * diff --git a/src/process.h b/src/process.h index bfc96263654..e9dc9a2b5e1 100644 --- a/src/process.h +++ b/src/process.h @@ -47,7 +47,8 @@ #define STATUS_INSUFFICIENT_RESOURCES ((NTSTATUS)0xC000009AL) #define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL) -#define SystemExtendedHandleInformation 64 +#define SystemExtendedHandleInformation 64 +#define FileProcessIdsUsingFileInformation 47 #define NtCurrentProcess() ((HANDLE)(LONG_PTR)-1) @@ -118,6 +119,12 @@ typedef struct _OBJECT_TYPES_INFORMATION ULONG NumberOfTypes; } OBJECT_TYPES_INFORMATION, *POBJECT_TYPES_INFORMATION; + +typedef struct _FILE_PROCESS_IDS_USING_FILE_INFORMATION { + ULONG NumberOfProcessIdsInList; + ULONG_PTR ProcessIdList[1]; +} FILE_PROCESS_IDS_USING_FILE_INFORMATION, *PFILE_PROCESS_IDS_USING_FILE_INFORMATION; + #define ALIGN_UP_BY(Address, Align) (((ULONG_PTR)(Address) + (Align) - 1) & ~((Align) - 1)) #define ALIGN_UP(Address, Type) ALIGN_UP_BY(Address, sizeof(Type)) diff --git a/src/rufus.rc b/src/rufus.rc index 79da32befbf..fbc0cde6cc1 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.1106" +CAPTION "Rufus 2.15.1107" 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,1106,0 - PRODUCTVERSION 2,15,1106,0 + FILEVERSION 2,15,1107,0 + PRODUCTVERSION 2,15,1107,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.1106" + VALUE "FileVersion", "2.15.1107" 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.1106" + VALUE "ProductVersion", "2.15.1107" END END BLOCK "VarFileInfo"