aboutsummaryrefslogtreecommitdiff
path: root/src/zencore/process.cpp
diff options
context:
space:
mode:
authorDan Engelbrecht <[email protected]>2026-04-20 14:04:57 +0200
committerGitHub Enterprise <[email protected]>2026-04-20 14:04:57 +0200
commit015db1c80865eabd28f98378610a9eca6798a7d4 (patch)
tree469e42410ff18a98f8cae727292f0d19fcef9752 /src/zencore/process.cpp
parentzen: remove unused 'copy' and 'run' subcommands (#986) (diff)
downloadarchived-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.cpp136
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")