Mercurial > minori
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