diff dep/animone/src/fd/win32.cc @ 301:b1f625b0227c

*: convert all files CRLF -> LF some files were in DOS format, others were in unix. now everything (that at least is under our control) should all be the same format
author Paper <paper@paper.us.eu.org>
date Mon, 13 May 2024 15:04:51 -0400
parents 65df2813d0de
children a4257370de16
line wrap: on
line diff
--- a/dep/animone/src/fd/win32.cc	Mon May 13 14:56:37 2024 -0400
+++ b/dep/animone/src/fd/win32.cc	Mon May 13 15:04:51 2024 -0400
@@ -1,258 +1,258 @@
-#include "animone/fd/win32.h"
-#include "animone.h"
-#include "animone/util/win32.h"
-
-#include <stdexcept>
-#include <string>
-#include <unordered_map>
-#include <vector>
-
-#include <fileapi.h>
-#include <handleapi.h>
-#include <libloaderapi.h>
-#include <ntdef.h>
-#include <psapi.h>
-#include <shlobj.h>
-#include <stringapiset.h>
-#include <tlhelp32.h>
-#include <windows.h>
-#include <winternl.h>
-
-/* This file is noticably more complex than Unix and Linux, and that's because
- * there is no "simple" way to get the paths of a file. In fact, this thing requires
- * you to use *internal functions* that can't even be linked to, hence why we have to
- * use GetProcAddress and such. What a mess.
- *
- * Speaking of which, because this file uses internal functions of the OS, it is not
- * guaranteed to work far into the future. However, it has worked since NT 6.0 (Vista)
- * at least, so it's unlikely to be changed much ever.
- */
-
-/* SystemExtendedHandleInformation is only available in NT 5.1+ (XP and higher) and provides information for
- * 32-bit PIDs, unlike SystemHandleInformation
- */
-static constexpr SYSTEM_INFORMATION_CLASS SystemExtendedHandleInformation = static_cast<SYSTEM_INFORMATION_CLASS>(0x40);
-static constexpr NTSTATUS STATUS_INFO_LENGTH_MISMATCH = 0xC0000004UL;
-
-/* this is filled in at runtime because it's not guaranteed to be (and isn't)
- * constant between different versions of Windows */
-static unsigned short file_type_index = 0;
-
-struct SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX {
-	PVOID Object;
-	ULONG_PTR UniqueProcessId;
-	HANDLE HandleValue;
-	ACCESS_MASK GrantedAccess;
-	USHORT CreatorBackTraceIndex;
-	USHORT ObjectTypeIndex;
-	ULONG HandleAttributes;
-	ULONG Reserved;
-};
-
-struct SYSTEM_HANDLE_INFORMATION_EX {
-	ULONG_PTR NumberOfHandles;
-	ULONG_PTR Reserved;
-	SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
-};
-
-namespace animone::internal::win32 {
-
-class Ntdll {
-public:
-	Ntdll() {
-		ntdll = ::GetModuleHandleW(L"ntdll.dll");
-		nt_query_system_information = reinterpret_cast<decltype(::NtQuerySystemInformation)*>(
-		    ::GetProcAddress(ntdll, "NtQuerySystemInformation"));
-		nt_query_object = reinterpret_cast<decltype(::NtQueryObject)*>(::GetProcAddress(ntdll, "NtQueryObject"));
-	}
-
-	NTSTATUS QuerySystemInformation(SYSTEM_INFORMATION_CLASS cls, PVOID sysinfo, ULONG len,
-	                                PULONG retlen){
-		return nt_query_system_information(cls, sysinfo, len, retlen);
-	}
-
-	NTSTATUS QueryObject(HANDLE handle, OBJECT_INFORMATION_CLASS cls, PVOID objinf, ULONG objinflen, PULONG retlen) {
-		return nt_query_object(handle, cls, objinf, objinflen, retlen);
-	}
-
-private:
-	HMODULE ntdll;
-	decltype(::NtQuerySystemInformation)* nt_query_system_information;
-	decltype(::NtQueryObject)* nt_query_object;
-};
-
-Ntdll ntdll;
-
-static HANDLE DuplicateHandle(HANDLE process_handle, HANDLE handle) {
-	HANDLE dup_handle = nullptr;
-	const bool result =
-	    ::DuplicateHandle(process_handle, handle, ::GetCurrentProcess(), &dup_handle, 0, false, DUPLICATE_SAME_ACCESS);
-	return result ? dup_handle : nullptr;
-}
-
-static std::vector<SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX> GetSystemHandleInformation() {
-	/* we should really put a cap on this */
-	ULONG cb = 1 << 19;
-	NTSTATUS status = STATUS_NO_MEMORY;
-	std::unique_ptr<SYSTEM_HANDLE_INFORMATION_EX> info;
-
-	do {
-		info.reset(reinterpret_cast<SYSTEM_HANDLE_INFORMATION_EX*>(malloc(cb *= 2)));
-		if (!info)
-			continue;
-
-		status = ntdll.QuerySystemInformation(SystemExtendedHandleInformation, info.get(), cb, &cb);
-	} while (status == STATUS_INFO_LENGTH_MISMATCH);
-
-	if (!NT_SUCCESS(status))
-		return {};
-
-	std::vector<SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX> res;
-
-	ULONG_PTR handles = info->NumberOfHandles;
-	if (!handles)
-		return {};
-
-	res.reserve(handles);
-
-	SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX* entry = info->Handles;
-	do {
-		if (entry)
-			res.push_back(*(entry++));
-	} while (--handles);
-
-	return res;
-}
-
-static std::wstring GetHandleType(HANDLE handle) {
-	OBJECT_TYPE_INFORMATION info = {0};
-	ntdll.QueryObject(handle, ObjectTypeInformation, &info, sizeof(info), NULL);
-	return std::wstring(info.TypeName.Buffer, info.TypeName.Length);
-}
-
-static std::wstring GetFinalPathNameByHandle(HANDLE handle) {
-	std::wstring buffer;
-
-	DWORD size = ::GetFinalPathNameByHandleW(handle, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
-	buffer.resize(size);
-	::GetFinalPathNameByHandleW(handle, &buffer.front(), buffer.size(), FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
-
-	return buffer;
-}
-
-static bool IsFileHandle(HANDLE handle, unsigned short object_type_index) {
-	if (file_type_index)
-		return object_type_index == file_type_index;
-	else if (!handle)
-		return true;
-	else if (GetHandleType(handle) == L"File") {
-		file_type_index = object_type_index;
-		return true;
-	}
-	return false;
-}
-
-static bool IsFileMaskOk(ACCESS_MASK access_mask) {
-	if (!(access_mask & FILE_READ_DATA))
-		return false;
-
-	if ((access_mask & FILE_APPEND_DATA) || (access_mask & FILE_WRITE_EA) || (access_mask & FILE_WRITE_ATTRIBUTES))
-		return false;
-
-	return true;
-}
-
-static bool IsFilePathOk(const std::wstring& path) {
-	if (path.empty())
-		return false;
-
-	if (IsSystemDirectory(path))
-		return false;
-
-	const auto file_attributes = GetFileAttributesW(path.c_str());
-	if ((file_attributes == INVALID_FILE_ATTRIBUTES) || (file_attributes & FILE_ATTRIBUTE_DIRECTORY))
-		return false;
-
-	return true;
-}
-
-bool GetProcessName(pid_t pid, std::string& name) {
-	std::wstring wname = GetProcessPath(pid);
-	if (wname.empty())
-		return false;
-
-	name = ToUtf8String(GetFileNameWithoutExtension(GetFileNameFromPath(wname)));
-	return true;
-}
-
-bool EnumerateOpenProcesses(process_proc_t process_proc) {
-	HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
-	if (hProcessSnap == INVALID_HANDLE_VALUE)
-		return false;
-
-	PROCESSENTRY32 pe32;
-	pe32.dwSize = sizeof(PROCESSENTRY32);
-
-	if (!::Process32First(hProcessSnap, &pe32))
-		return false;
-
-	if (!process_proc({pe32.th32ProcessID, pe32.szExeFile}))
-		return false;
-
-	while (::Process32Next(hProcessSnap, &pe32))
-		if (!process_proc({pe32.th32ProcessID, pe32.szExeFile}))
-			return false;
-
-	::CloseHandle(hProcessSnap);
-
-	return true;
-}
-
-/* this could be changed to being a callback, but... I'm too lazy right now :) */
-bool EnumerateOpenFiles(const std::set<pid_t>& pids, open_file_proc_t open_file_proc) {
-	if (!open_file_proc)
-		return false;
-
-	std::unordered_map<pid_t, Handle> proc_handles;
-
-	for (const pid_t& pid : pids) {
-		const HANDLE handle = ::OpenProcess(PROCESS_DUP_HANDLE, false, pid);
-		if (handle != INVALID_HANDLE_VALUE)
-			proc_handles[pid] = Handle(handle);
-	}
-
-	if (proc_handles.empty())
-		return false;
-
-	std::vector<SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX> info = GetSystemHandleInformation();
-
-	for (const auto& h : info) {
-		const pid_t pid = h.UniqueProcessId;
-		if (!pids.count(pid))
-			continue;
-
-		if (!IsFileHandle(nullptr, h.ObjectTypeIndex))
-			continue;
-
-		if (!IsFileMaskOk(h.GrantedAccess))
-			continue;
-
-		Handle handle(DuplicateHandle(proc_handles[pid].get(), h.HandleValue));
-		if (handle.get() == INVALID_HANDLE_VALUE)
-			continue;
-
-		if (GetFileType(handle.get()) != FILE_TYPE_DISK)
-			continue;
-
-		const std::wstring path = GetFinalPathNameByHandle(handle.get());
-		if (!IsFilePathOk(path))
-			continue;
-
-		if (!open_file_proc({pid, ToUtf8String(path)}))
-			return false;
-	}
-
-	return true;
-}
-
-} // namespace animone::internal::win32
+#include "animone/fd/win32.h"
+#include "animone.h"
+#include "animone/util/win32.h"
+
+#include <stdexcept>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <fileapi.h>
+#include <handleapi.h>
+#include <libloaderapi.h>
+#include <ntdef.h>
+#include <psapi.h>
+#include <shlobj.h>
+#include <stringapiset.h>
+#include <tlhelp32.h>
+#include <windows.h>
+#include <winternl.h>
+
+/* This file is noticably more complex than Unix and Linux, and that's because
+ * there is no "simple" way to get the paths of a file. In fact, this thing requires
+ * you to use *internal functions* that can't even be linked to, hence why we have to
+ * use GetProcAddress and such. What a mess.
+ *
+ * Speaking of which, because this file uses internal functions of the OS, it is not
+ * guaranteed to work far into the future. However, it has worked since NT 6.0 (Vista)
+ * at least, so it's unlikely to be changed much ever.
+ */
+
+/* SystemExtendedHandleInformation is only available in NT 5.1+ (XP and higher) and provides information for
+ * 32-bit PIDs, unlike SystemHandleInformation
+ */
+static constexpr SYSTEM_INFORMATION_CLASS SystemExtendedHandleInformation = static_cast<SYSTEM_INFORMATION_CLASS>(0x40);
+static constexpr NTSTATUS STATUS_INFO_LENGTH_MISMATCH = 0xC0000004UL;
+
+/* this is filled in at runtime because it's not guaranteed to be (and isn't)
+ * constant between different versions of Windows */
+static unsigned short file_type_index = 0;
+
+struct SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX {
+	PVOID Object;
+	ULONG_PTR UniqueProcessId;
+	HANDLE HandleValue;
+	ACCESS_MASK GrantedAccess;
+	USHORT CreatorBackTraceIndex;
+	USHORT ObjectTypeIndex;
+	ULONG HandleAttributes;
+	ULONG Reserved;
+};
+
+struct SYSTEM_HANDLE_INFORMATION_EX {
+	ULONG_PTR NumberOfHandles;
+	ULONG_PTR Reserved;
+	SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX Handles[1];
+};
+
+namespace animone::internal::win32 {
+
+class Ntdll {
+public:
+	Ntdll() {
+		ntdll = ::GetModuleHandleW(L"ntdll.dll");
+		nt_query_system_information = reinterpret_cast<decltype(::NtQuerySystemInformation)*>(
+		    ::GetProcAddress(ntdll, "NtQuerySystemInformation"));
+		nt_query_object = reinterpret_cast<decltype(::NtQueryObject)*>(::GetProcAddress(ntdll, "NtQueryObject"));
+	}
+
+	NTSTATUS QuerySystemInformation(SYSTEM_INFORMATION_CLASS cls, PVOID sysinfo, ULONG len,
+	                                PULONG retlen){
+		return nt_query_system_information(cls, sysinfo, len, retlen);
+	}
+
+	NTSTATUS QueryObject(HANDLE handle, OBJECT_INFORMATION_CLASS cls, PVOID objinf, ULONG objinflen, PULONG retlen) {
+		return nt_query_object(handle, cls, objinf, objinflen, retlen);
+	}
+
+private:
+	HMODULE ntdll;
+	decltype(::NtQuerySystemInformation)* nt_query_system_information;
+	decltype(::NtQueryObject)* nt_query_object;
+};
+
+Ntdll ntdll;
+
+static HANDLE DuplicateHandle(HANDLE process_handle, HANDLE handle) {
+	HANDLE dup_handle = nullptr;
+	const bool result =
+	    ::DuplicateHandle(process_handle, handle, ::GetCurrentProcess(), &dup_handle, 0, false, DUPLICATE_SAME_ACCESS);
+	return result ? dup_handle : nullptr;
+}
+
+static std::vector<SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX> GetSystemHandleInformation() {
+	/* we should really put a cap on this */
+	ULONG cb = 1 << 19;
+	NTSTATUS status = STATUS_NO_MEMORY;
+	std::unique_ptr<SYSTEM_HANDLE_INFORMATION_EX> info;
+
+	do {
+		info.reset(reinterpret_cast<SYSTEM_HANDLE_INFORMATION_EX*>(malloc(cb *= 2)));
+		if (!info)
+			continue;
+
+		status = ntdll.QuerySystemInformation(SystemExtendedHandleInformation, info.get(), cb, &cb);
+	} while (status == STATUS_INFO_LENGTH_MISMATCH);
+
+	if (!NT_SUCCESS(status))
+		return {};
+
+	std::vector<SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX> res;
+
+	ULONG_PTR handles = info->NumberOfHandles;
+	if (!handles)
+		return {};
+
+	res.reserve(handles);
+
+	SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX* entry = info->Handles;
+	do {
+		if (entry)
+			res.push_back(*(entry++));
+	} while (--handles);
+
+	return res;
+}
+
+static std::wstring GetHandleType(HANDLE handle) {
+	OBJECT_TYPE_INFORMATION info = {0};
+	ntdll.QueryObject(handle, ObjectTypeInformation, &info, sizeof(info), NULL);
+	return std::wstring(info.TypeName.Buffer, info.TypeName.Length);
+}
+
+static std::wstring GetFinalPathNameByHandle(HANDLE handle) {
+	std::wstring buffer;
+
+	DWORD size = ::GetFinalPathNameByHandleW(handle, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+	buffer.resize(size);
+	::GetFinalPathNameByHandleW(handle, &buffer.front(), buffer.size(), FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
+
+	return buffer;
+}
+
+static bool IsFileHandle(HANDLE handle, unsigned short object_type_index) {
+	if (file_type_index)
+		return object_type_index == file_type_index;
+	else if (!handle)
+		return true;
+	else if (GetHandleType(handle) == L"File") {
+		file_type_index = object_type_index;
+		return true;
+	}
+	return false;
+}
+
+static bool IsFileMaskOk(ACCESS_MASK access_mask) {
+	if (!(access_mask & FILE_READ_DATA))
+		return false;
+
+	if ((access_mask & FILE_APPEND_DATA) || (access_mask & FILE_WRITE_EA) || (access_mask & FILE_WRITE_ATTRIBUTES))
+		return false;
+
+	return true;
+}
+
+static bool IsFilePathOk(const std::wstring& path) {
+	if (path.empty())
+		return false;
+
+	if (IsSystemDirectory(path))
+		return false;
+
+	const auto file_attributes = GetFileAttributesW(path.c_str());
+	if ((file_attributes == INVALID_FILE_ATTRIBUTES) || (file_attributes & FILE_ATTRIBUTE_DIRECTORY))
+		return false;
+
+	return true;
+}
+
+bool GetProcessName(pid_t pid, std::string& name) {
+	std::wstring wname = GetProcessPath(pid);
+	if (wname.empty())
+		return false;
+
+	name = ToUtf8String(GetFileNameWithoutExtension(GetFileNameFromPath(wname)));
+	return true;
+}
+
+bool EnumerateOpenProcesses(process_proc_t process_proc) {
+	HANDLE hProcessSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+	if (hProcessSnap == INVALID_HANDLE_VALUE)
+		return false;
+
+	PROCESSENTRY32 pe32;
+	pe32.dwSize = sizeof(PROCESSENTRY32);
+
+	if (!::Process32First(hProcessSnap, &pe32))
+		return false;
+
+	if (!process_proc({pe32.th32ProcessID, pe32.szExeFile}))
+		return false;
+
+	while (::Process32Next(hProcessSnap, &pe32))
+		if (!process_proc({pe32.th32ProcessID, pe32.szExeFile}))
+			return false;
+
+	::CloseHandle(hProcessSnap);
+
+	return true;
+}
+
+/* this could be changed to being a callback, but... I'm too lazy right now :) */
+bool EnumerateOpenFiles(const std::set<pid_t>& pids, open_file_proc_t open_file_proc) {
+	if (!open_file_proc)
+		return false;
+
+	std::unordered_map<pid_t, Handle> proc_handles;
+
+	for (const pid_t& pid : pids) {
+		const HANDLE handle = ::OpenProcess(PROCESS_DUP_HANDLE, false, pid);
+		if (handle != INVALID_HANDLE_VALUE)
+			proc_handles[pid] = Handle(handle);
+	}
+
+	if (proc_handles.empty())
+		return false;
+
+	std::vector<SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX> info = GetSystemHandleInformation();
+
+	for (const auto& h : info) {
+		const pid_t pid = h.UniqueProcessId;
+		if (!pids.count(pid))
+			continue;
+
+		if (!IsFileHandle(nullptr, h.ObjectTypeIndex))
+			continue;
+
+		if (!IsFileMaskOk(h.GrantedAccess))
+			continue;
+
+		Handle handle(DuplicateHandle(proc_handles[pid].get(), h.HandleValue));
+		if (handle.get() == INVALID_HANDLE_VALUE)
+			continue;
+
+		if (GetFileType(handle.get()) != FILE_TYPE_DISK)
+			continue;
+
+		const std::wstring path = GetFinalPathNameByHandle(handle.get());
+		if (!IsFilePathOk(path))
+			continue;
+
+		if (!open_file_proc({pid, ToUtf8String(path)}))
+			return false;
+	}
+
+	return true;
+}
+
+} // namespace animone::internal::win32