Mercurial > minori
diff dep/animone/src/fd/win32.cc @ 340:74e2365326c6
dep/animone: add experimental accessibility strategy
I also moved most of the functions out of util/win32.cc, because that
file is meant for things that are shared between the different functions,
and currently that is only wide string conversion helpers.
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Wed, 19 Jun 2024 23:13:55 -0400 |
parents | a7d4e5107531 |
children | adb79bdde329 |
line wrap: on
line diff
--- a/dep/animone/src/fd/win32.cc Wed Jun 19 14:02:11 2024 -0400 +++ b/dep/animone/src/fd/win32.cc Wed Jun 19 23:13:55 2024 -0400 @@ -32,15 +32,10 @@ #include <winternl.h> /* SystemExtendedHandleInformation is only available in NT 5.1+ (XP and higher) and provides information for - * 32-bit PIDs, unlike SystemHandleInformation - */ + * 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; @@ -136,22 +131,58 @@ static std::wstring GetFinalPathNameByHandle(HANDLE handle) { std::wstring buffer; - DWORD size = ::GetFinalPathNameByHandleW(handle, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS); + DWORD size = ::GetFinalPathNameByHandleW(handle, nullptr, 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 GetSystemDirectory(std::wstring& str) { + PWSTR path_wch; + + if (FAILED(::SHGetFolderPathW(NULL, CSIDL_WINDOWS, NULL, SHGFP_TYPE_CURRENT, &path_wch))) + return false; + + str.assign(path_wch); + + ::CoTaskMemFree(path_wch); + return true; +} + +static bool IsSystemDirectory(const std::string& path) { + return IsSystemDirectory(ToWstring(path)); +} + +static bool IsSystemDirectory(std::wstring path) { + std::wstring windir; + if (!GetSystemDirectory(windir)) + return false; + + ::CharUpperBuffW(&path.front(), path.length()); + ::CharUpperBuffW(&windir.front(), windir.length()); + + // XXX wtf is 4? + return path.find(windir) == 4; +} + static bool IsFileHandle(HANDLE handle, unsigned short object_type_index) { - if (file_type_index) - return object_type_index == file_type_index; - else if (!handle) + /* this is filled in at runtime because it's not guaranteed to be (and isn't) + * constant between different versions of Windows */ + static std::optional<unsigned short> file_type_index; + + if (file_type_index.has_value()) { + return object_type_index == file_type_index.value(); + } else if (!handle) { + /* XXX what? */ return true; - else if (GetHandleType(handle) == L"File") { - file_type_index = object_type_index; + } else if (GetHandleType(handle) == L"File") { + file_type_index.reset(object_type_index); return true; } + return false; } @@ -179,13 +210,72 @@ return true; } +/* ------------------------------------------------------------------- */ + +static std::string GetProcessPath(DWORD process_id) { + // If we try to open a SYSTEM process, this function fails and the last error + // code is ERROR_ACCESS_DENIED. + // + // Note that if we requested PROCESS_QUERY_INFORMATION access right instead + // of PROCESS_QUERY_LIMITED_INFORMATION, this function would fail when used + // to open an elevated process. + Handle process_handle(::OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, process_id)); + + if (!process_handle) + return std::wstring(); + + std::wstring buffer(MAX_PATH, L'\0'); + DWORD buf_size = buffer.length(); + + // Note that this function requires Windows Vista or above. You may use + // GetProcessImageFileName or GetModuleFileNameEx on earlier versions. + if (!::QueryFullProcessImageNameW(process_handle.get(), 0, &buffer.front(), &buf_size)) + return std::wstring(); + + buffer.resize(buf_size); + return ToUtf8String(buffer); +} + +static std::string GetFilenameFromPath(const std::string& path) { + const auto pos = path.find_last_of(L"/\\"); + return pos != std::wstring::npos ? path.substr(pos + 1) : path; +} + +static bool VerifyProcessPath(const std::string& path) { + return !path.empty() && !IsSystemDirectory(path); +} + +static bool VerifyProcessFilename(const std::string& name) { + static const std::set<std::string> invalid_names = { + // System files + "explorer.exe", // Windows Explorer + "taskeng.exe", // Task Scheduler Engine + "taskhost.exe", // Host Process for Windows Tasks + "taskhostex.exe", // Host Process for Windows Tasks + "taskmgr.exe", // Task Manager + "services.exe", // Service Control Manager + }; + + if (name.empty()) + return false; + + for (const auto& invalid_name : invalid_names) + if (util::EqualStrings(name, invalid_name)) + return false; + + return true; +} + +/* ------------------------------------------------------------------- */ +/* extern functions */ + bool GetProcessName(pid_t pid, std::string& name) { std::string path = GetProcessPath(pid); if (path.empty() || !VerifyProcessPath(path)) return false; - name = GetFileNameFromPath(path); - if (!VerifyProcessFileName(name)) + name = GetFilenameFromPath(path); + if (!VerifyProcessFilename(name)) return false; return true; @@ -214,7 +304,6 @@ 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; @@ -247,7 +336,7 @@ if (handle.get() == INVALID_HANDLE_VALUE) continue; - if (GetFileType(handle.get()) != FILE_TYPE_DISK) + if (::GetFileType(handle.get()) != FILE_TYPE_DISK) continue; const std::wstring path = GetFinalPathNameByHandle(handle.get());