Bläddra i källkod

linux: Implement `Process` methods and `Path.GetActualPathName`

disarray2077 2 månader sedan
förälder
incheckning
53c248c453
1 ändrade filer med 257 tillägg och 7 borttagningar
  1. 257 7
      BeefySysLib/platform/posix/PosixCommon.cpp

+ 257 - 7
BeefySysLib/platform/posix/PosixCommon.cpp

@@ -832,6 +832,17 @@ BFP_EXPORT void BFP_CALLTYPE BfpSystem_GetComputerName(char* outStr, int* inOutS
 
 // BfpProcess
 
+struct BfpProcess
+{
+    pid_t mProcessId;
+    String mImageName;
+
+    BfpProcess()
+    {
+        mProcessId = -1;
+    }
+};
+
 BFP_EXPORT intptr BFP_CALLTYPE BfpProcess_GetCurrentId()
 {
     return getpid();
@@ -844,18 +855,87 @@ BFP_EXPORT bool BFP_CALLTYPE BfpProcess_IsRemoteMachine(const char* machineName)
 
 BFP_EXPORT BfpProcess* BFP_CALLTYPE BfpProcess_GetById(const char* machineName, int processId, BfpProcessResult* outResult)
 {
+#ifdef BF_PLATFORM_LINUX
+    pid_t pid = static_cast<pid_t>(processId);
+
+    char proc_dir[64];
+    snprintf(proc_dir, sizeof(proc_dir), "/proc/%d", pid);
+
+    if (access(proc_dir, F_OK) != 0)
+    {
+        OUTRESULT(BfpProcessResult_NotFound);
+        return NULL;
+    }
+
+    BfpProcess* process = new BfpProcess();
+    process->mProcessId = pid;
+    return process;
+#else
     NOT_IMPL;
     return NULL;
+#endif
 }
 
 BFP_EXPORT void BFP_CALLTYPE BfpProcess_Enumerate(const char* machineName, BfpProcess** outProcesses, int* inOutProcessesSize, BfpProcessResult* outResult)
 {
+#ifdef BF_PLATFORM_LINUX
+    DIR* procDir = opendir("/proc");
+    if (!procDir)
+    {
+        *inOutProcessesSize = 0;
+        return;
+    }
+
+    Beefy::Array<BfpProcess*> processList;
+    struct dirent* entry;
+    while ((entry = readdir(procDir)) != NULL)
+    {
+        const char* name = entry->d_name;
+        bool is_pid = name[0] != '\0';
+        for (const char* p = name; *p; ++p)
+        {
+            if (*p < '0' || *p > '9')
+            {
+                is_pid = false;
+                break;
+            }
+        }
+
+        if (is_pid)
+        {
+            pid_t pid = static_cast<pid_t>(atoi(name));
+            if (pid == 0)
+                continue;
+
+            BfpProcess* proc = new BfpProcess();
+            proc->mProcessId = pid;
+            processList.Add(proc);
+        }
+    }
+
+    closedir(procDir);
+
+    if (static_cast<int>(processList.size()) > *inOutProcessesSize)
+    {
+        *inOutProcessesSize = static_cast<int>(processList.size());
+        OUTRESULT(BfpProcessResult_InsufficientBuffer);
+        for (BfpProcess* p_del : processList)
+            delete p_del;
+        return;
+    }
+
+    for (size_t i = 0; i < processList.size(); ++i)
+        outProcesses[i] = processList[i];
+    *inOutProcessesSize = static_cast<int>(processList.size());
+	OUTRESULT(BfpProcessResult_Ok);
+#else
     NOT_IMPL;
+#endif
 }
 
 BFP_EXPORT void BFP_CALLTYPE BfpProcess_Release(BfpProcess* process)
 {
-    NOT_IMPL;
+    delete process;
 }
 
 BFP_EXPORT bool BFP_CALLTYPE BfpProcess_WaitFor(BfpProcess* process, int waitMS, int* outExitCode, BfpProcessResult* outResult)
@@ -865,18 +945,49 @@ BFP_EXPORT bool BFP_CALLTYPE BfpProcess_WaitFor(BfpProcess* process, int waitMS,
 
 BFP_EXPORT void BFP_CALLTYPE BfpProcess_GetMainWindowTitle(BfpProcess* process, char* outTitle, int* inOutTitleSize, BfpProcessResult* outResult)
 {
-    NOT_IMPL;
+    String title;
+    TryStringOut(title, outTitle, inOutTitleSize, (BfpResult*)outResult);
 }
 
 BFP_EXPORT void BFP_CALLTYPE BfpProcess_GetProcessName(BfpProcess* process, char* outName, int* inOutNameSize, BfpProcessResult* outResult)
 {
-    NOT_IMPL;
+    if (process->mImageName.IsEmpty())
+    {
+#ifdef BF_PLATFORM_LINUX
+        char path[PATH_MAX];
+        snprintf(path, sizeof(path), "/proc/%d/exe", process->mProcessId);
+        char name_buf[PATH_MAX] = {0};
+        ssize_t len = readlink(path, name_buf, sizeof(name_buf) - 1);
+        if (len != -1)
+        {
+            name_buf[len] = '\0';
+            process->mImageName.Append(basename(name_buf));
+        }
+        else
+        {
+            // Only 15 characters of the process name are returned by this, but it works for all processes.
+            snprintf(path, sizeof(path), "/proc/%d/comm", process->mProcessId);
+            FILE* fp = fopen(path, "r");
+            if (fp)
+            {
+                if (fgets(name_buf, sizeof(name_buf), fp)) {
+                    size_t len = strcspn(name_buf, "\n");
+                    name_buf[len] = '\0';
+                    process->mImageName.Append(name_buf, len);
+                }
+                fclose(fp);
+            }
+        }
+#else
+        NOT_IMPL;
+#endif
+    }
+    TryStringOut(process->mImageName, outName, inOutNameSize, (BfpResult*)outResult);
 }
 
 BFP_EXPORT int BFP_CALLTYPE BfpProcess_GetProcessId(BfpProcess* process)
 {
-    NOT_IMPL;
-    return 0;
+    return process->mProcessId;
 }
 
 // BfpSpawn
@@ -2392,9 +2503,148 @@ BFP_EXPORT void BFP_CALLTYPE BfpFile_GetFullPath(const char* inPath, char* outPa
     TryStringOut(str, outPath, inOutPathSize, (BfpResult*)outResult);
 }
 
-BFP_EXPORT void BFP_CALLTYPE BfpFile_GetActualPath(const char* inPath, char* outPath, int* inOutPathSize, BfpFileResult* outResult)
+BFP_EXPORT void BFP_CALLTYPE BfpFile_GetActualPath(const char* inPathC, char* outPathC, int* inOutPathSize, BfpFileResult* outResult)
 {
-    NOT_IMPL;
+    String inPath = inPathC;
+    String outPath;
+
+    // Check for '/../' backtracking - handle those first
+    {
+        int i = 0;
+        int32 lastComponentStart = -1;
+
+        while (i < inPath.mLength)
+        {
+            // Skip until path separator
+            while ((i < inPath.mLength) && (inPath[i] != DIR_SEP_CHAR) && (inPath[i] != DIR_SEP_CHAR_ALT))
+                ++i;
+
+            if (lastComponentStart != -1)
+            {
+                if ((i - lastComponentStart == 2) && (inPath[lastComponentStart] == '.') && (inPath[lastComponentStart + 1] == '.'))
+                {
+                    // Backtrack
+                    while ((lastComponentStart > 0) &&
+                        ((inPath[lastComponentStart - 1] == DIR_SEP_CHAR) || (inPath[lastComponentStart - 1] == DIR_SEP_CHAR_ALT)))
+                        lastComponentStart--;
+                    while ((lastComponentStart > 0) && (inPath[lastComponentStart - 1] != DIR_SEP_CHAR) && (inPath[lastComponentStart - 1] != DIR_SEP_CHAR_ALT))
+                        lastComponentStart--;
+                    inPath.Remove(lastComponentStart, i - lastComponentStart + 1);
+                    i = lastComponentStart;
+                    continue;
+                }
+                else if ((i - lastComponentStart == 1) && (inPath[lastComponentStart] == '.'))
+                {
+                    inPath.Remove(lastComponentStart, i - lastComponentStart + 1);
+                    i = lastComponentStart;
+                    continue;
+                }
+            }
+
+            ++i;
+            // Ignore multiple slashes in a row
+            while ((i < inPath.mLength) && ((inPath[i] == DIR_SEP_CHAR) || (inPath[i] == DIR_SEP_CHAR_ALT)))
+                ++i;
+
+            lastComponentStart = i;
+        }
+    }
+
+    int32 i = 0;
+    int length = (int)inPath.length();
+
+    if (length >= 1)
+    {
+        // Handle root paths starting with '/' or '\'
+        if ((inPath[0] == DIR_SEP_CHAR) || (inPath[0] == DIR_SEP_CHAR_ALT))
+        {
+            i++; // start after initial slash
+            outPath.Append(DIR_SEP_CHAR);
+        }
+        else
+        {
+            // Relative path - prepend current working directory
+            char cwd[PATH_MAX];
+            if (getcwd(cwd, PATH_MAX) != NULL)
+            {
+                outPath.Append(cwd);
+                if (outPath[outPath.length() - 1] != DIR_SEP_CHAR)
+                    outPath.Append(DIR_SEP_CHAR);
+            }
+        }
+    }
+
+    int32 lastComponentStart = i;
+    bool addSeparator = false;
+    String subName;
+
+    while (i < length)
+    {
+        // skip until path separator
+        while ((i < length) && (inPath[i] != DIR_SEP_CHAR) && (inPath[i] != DIR_SEP_CHAR_ALT))
+            ++i;
+
+        if (addSeparator)
+            outPath.Append(DIR_SEP_CHAR);
+
+        subName.Clear();
+        subName = inPath.Substring(0, i);
+        for (int j = 0; j < (int)subName.length(); j++)
+            if (subName[j] == DIR_SEP_CHAR_ALT)
+                subName[j] = DIR_SEP_CHAR;
+
+        String parentPath;
+        String componentName;
+        int32 lastSep = subName.LastIndexOf(DIR_SEP_CHAR);
+        
+        if (lastSep != -1)
+        {
+            parentPath = subName.Substring(0, lastSep);
+            if (parentPath.length() == 0)
+                parentPath = "/";
+            componentName = subName.Substring(lastSep + 1);
+        }
+        else
+        {
+            parentPath = ".";
+            componentName = subName;
+        }
+
+        bool found = false;
+        DIR* dir = opendir(parentPath.c_str());
+        if (dir != NULL)
+        {
+            struct dirent* entry = NULL;
+            while ((entry = readdir(dir)) != NULL)
+            {
+                // Linux is case-sensitive, but we do a case-insensitive comparison 
+                // to help find the correct case for the file
+                if (strcasecmp(entry->d_name, componentName.c_str()) == 0)
+                {
+                    outPath.Append(entry->d_name);
+                    found = true;
+                    break;
+                }
+            }
+            closedir(dir);
+        }
+
+        if (!found)
+        {
+            // If not found, use the original component name
+            outPath.Append(inPath.Substring(lastComponentStart, i - lastComponentStart));
+        }
+
+        ++i;
+        // Ignore multiple slashes in a row
+        while ((i < length) && ((inPath[i] == DIR_SEP_CHAR) || (inPath[i] == DIR_SEP_CHAR_ALT)))
+            ++i;
+
+        lastComponentStart = i;
+        addSeparator = true;
+    }
+
+    TryStringOut(outPath, outPathC, inOutPathSize, (BfpResult*)outResult);
 }
 
 // BfpFindFileData