diff options
| author | Dan Engelbrecht <[email protected]> | 2026-04-20 14:04:57 +0200 |
|---|---|---|
| committer | GitHub Enterprise <[email protected]> | 2026-04-20 14:04:57 +0200 |
| commit | 015db1c80865eabd28f98378610a9eca6798a7d4 (patch) | |
| tree | 469e42410ff18a98f8cae727292f0d19fcef9752 /src/zencore/process.cpp | |
| parent | zen: remove unused 'copy' and 'run' subcommands (#986) (diff) | |
| download | archived-zen-015db1c80865eabd28f98378610a9eca6798a7d4.tar.xz archived-zen-015db1c80865eabd28f98378610a9eca6798a7d4.zip | |
add --pid och --executable till zen down command (#988)
Diffstat (limited to 'src/zencore/process.cpp')
| -rw-r--r-- | src/zencore/process.cpp | 136 |
1 files changed, 116 insertions, 20 deletions
diff --git a/src/zencore/process.cpp b/src/zencore/process.cpp index b95e706d5..4708f15cf 100644 --- a/src/zencore/process.cpp +++ b/src/zencore/process.cpp @@ -2044,9 +2044,41 @@ GetProcessCommandLine(int Pid, std::error_code& OutEc) #endif } +#if ZEN_PLATFORM_WINDOWS +static const wchar_t* +StripExtendedLengthPrefix(const wchar_t* S) +{ + // "\\?\C:\foo" -> "C:\foo"; "\\?\UNC\srv\share" -> "UNC\srv\share". + // UNC stripping is asymmetric vs a bare "\\srv\share" form, so this helper only normalizes + // the "\\?\" prefix itself. Comparing a "\\?\UNC\..." path to a bare "\\..." path is not + // expected for FindProcess inputs (zenserver installs are local paths). + if (S[0] == L'\\' && S[1] == L'\\' && S[2] == L'?' && S[3] == L'\\') + { + return S + 4; + } + return S; +} +#endif + +static bool +IsSameNativePath(const std::filesystem::path& A, const std::filesystem::path& B) +{ +#if ZEN_PLATFORM_WINDOWS + // Windows filesystem is case-insensitive; std::filesystem::path::operator== is not. + // CompareStringOrdinal is Microsoft's recommended API for filename/resource comparison: + // ordinal (no locale sensitivity) and case-insensitive when bIgnoreCase is TRUE. + // Strip "\\?\" extended-length prefix first so paths produced by MakeSafeAbsolutePath + // compare equal to paths from GetProcessExecutablePath which do not carry the prefix. + return CompareStringOrdinal(StripExtendedLengthPrefix(A.c_str()), -1, StripExtendedLengthPrefix(B.c_str()), -1, TRUE) == CSTR_EQUAL; +#else + return A == B; +#endif +} + std::error_code FindProcess(const std::filesystem::path& ExecutableImage, ProcessHandle& OutHandle, bool IncludeSelf) { + const bool MatchFullPath = ExecutableImage.has_parent_path(); #if ZEN_PLATFORM_WINDOWS HANDLE ProcessSnapshotHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (ProcessSnapshotHandle == INVALID_HANDLE_VALUE) @@ -2063,29 +2095,41 @@ FindProcess(const std::filesystem::path& ExecutableImage, ProcessHandle& OutHand { do { - if ((IncludeSelf || (Entry.th32ProcessID != ThisProcessId)) && (ExecutableImage.filename() == Entry.szExeFile)) + if ((IncludeSelf || (Entry.th32ProcessID != ThisProcessId)) && IsSameNativePath(ExecutableImage.filename(), Entry.szExeFile)) { - std::error_code Ec; - std::filesystem::path EntryPath = GetProcessExecutablePath(Entry.th32ProcessID, Ec); - if (!Ec) + HANDLE Handle = OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, Entry.th32ProcessID); + if (Handle == NULL) + { + // Skip processes we can't open (access denied, exited between snapshot and open, etc.) + continue; + } + // Close on all exits from this iteration unless ownership transfers to OutHandle (Handle set to NULL). + auto HandleGuard = MakeGuard([&]() { + if (Handle != NULL) + { + CloseHandle(Handle); + Handle = NULL; + } + }); + DWORD ExitCode = 0; + bool Match = false; + if (GetExitCodeProcess(Handle, &ExitCode) && ExitCode == STILL_ACTIVE) { - if (EntryPath == ExecutableImage) + // Re-verify executable path post-open so PID reuse between snapshot and open is caught. + std::error_code Ec; + std::filesystem::path EntryPath = GetProcessExecutablePath(Entry.th32ProcessID, Ec); + if (!Ec) { - HANDLE Handle = - OpenProcess(PROCESS_TERMINATE | SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, Entry.th32ProcessID); - if (Handle == NULL) - { - return MakeErrorCodeFromLastError(); - } - DWORD ExitCode = 0; - GetExitCodeProcess(Handle, &ExitCode); - if (ExitCode == STILL_ACTIVE) - { - OutHandle.Initialize((void*)Handle); - return {}; - } + Match = MatchFullPath ? IsSameNativePath(EntryPath, ExecutableImage) + : IsSameNativePath(EntryPath.filename(), ExecutableImage.filename()); } } + if (Match) + { + OutHandle.Initialize((void*)Handle); + Handle = NULL; + return {}; + } } } while (::Process32Next(ProcessSnapshotHandle, (LPPROCESSENTRY32)&Entry)); return {}; @@ -2135,7 +2179,9 @@ FindProcess(const std::filesystem::path& ExecutableImage, ProcessHandle& OutHand std::filesystem::path EntryPath = GetProcessExecutablePath(Pid, Ec); if (!Ec) { - if (EntryPath == ExecutableImage) + const bool Match = MatchFullPath ? IsSameNativePath(EntryPath, ExecutableImage) + : IsSameNativePath(EntryPath.filename(), ExecutableImage.filename()); + if (Match) { if (Processes[ProcIndex].kp_proc.p_stat != SZOMB) { @@ -2173,7 +2219,9 @@ FindProcess(const std::filesystem::path& ExecutableImage, ProcessHandle& OutHand std::filesystem::path EntryPath = GetProcessExecutablePath((int)Pid, Ec); if (!Ec) { - if (EntryPath == ExecutableImage) + const bool Match = MatchFullPath ? IsSameNativePath(EntryPath, ExecutableImage) + : IsSameNativePath(EntryPath.filename(), ExecutableImage.filename()); + if (Match) { char Status = GetPidStatus(Pid, Ec); if (!Ec) @@ -2438,6 +2486,54 @@ TEST_CASE("FindProcess") CHECK(!Ec); CHECK(!Process.IsValid()); } + { + ProcessHandle Process; + std::filesystem::path BareName = GetRunningExecutablePath().filename(); + std::error_code Ec = FindProcess(BareName, Process, /*IncludeSelf*/ true); + CHECK(!Ec); + CHECK(Process.IsValid()); + } + { + ProcessHandle Process; + std::error_code Ec = FindProcess("this-executable-definitely-does-not-exist.xyz", Process, /*IncludeSelf*/ true); + CHECK(!Ec); + CHECK(!Process.IsValid()); + } + { + // Correct filename but wrong directory must not match when a parent path is supplied. + std::filesystem::path WrongPath = std::filesystem::path("nonexistent-dir-7f3a9c1e") / GetRunningExecutablePath().filename(); + ProcessHandle Process; + std::error_code Ec = FindProcess(WrongPath, Process, /*IncludeSelf*/ true); + CHECK(!Ec); + CHECK(!Process.IsValid()); + } +# if ZEN_PLATFORM_WINDOWS + { + // On Windows, filename match is case-insensitive (filesystem is case-insensitive). + std::filesystem::path::string_type Upper = GetRunningExecutablePath().filename().native(); + for (auto& Ch : Upper) + { + Ch = towupper(Ch); + } + ProcessHandle Process; + std::error_code Ec = FindProcess(std::filesystem::path(Upper), Process, /*IncludeSelf*/ true); + CHECK(!Ec); + CHECK(Process.IsValid()); + } + { + // "\\?\"-prefixed absolute path must still match a running process whose reported path is unprefixed. + std::filesystem::path AbsPath = MakeSafeAbsolutePath(GetRunningExecutablePath()); + std::filesystem::path::string_type Prefixed = AbsPath.native(); + if (Prefixed.rfind(L"\\\\?\\", 0) != 0) + { + Prefixed.insert(0, L"\\\\?\\"); + } + ProcessHandle Process; + std::error_code Ec = FindProcess(std::filesystem::path(Prefixed), Process, /*IncludeSelf*/ true); + CHECK(!Ec); + CHECK(Process.IsValid()); + } +# endif } TEST_CASE("GetProcessMetrics") |