339 lines
8.4 KiB
C++
339 lines
8.4 KiB
C++
/***
|
|
Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved.
|
|
|
|
File: AuPaths.cpp
|
|
Date: 2021-7-14
|
|
Author: Reece
|
|
***/
|
|
#include <Source/RuntimeInternal.hpp>
|
|
#include "AuPaths.hpp"
|
|
|
|
#if defined(AURORA_IS_POSIX_DERIVED)
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#define _USE_GET_CWD
|
|
#endif
|
|
|
|
#include <Source/IO/FS/FS.hpp>
|
|
|
|
namespace Aurora::Process
|
|
{
|
|
static AuString gCachedModule, gCachedPartialPath, gCachedFullPath;
|
|
static AuInitOnce gInitOnce;
|
|
|
|
void ForceReplacePathHack(const AuString &path)
|
|
{
|
|
static AuInitOnce gInitOnce2;
|
|
gInitOnce2.Call([&]()
|
|
{
|
|
AuResetMember(gCachedModule);
|
|
AuResetMember(gCachedPartialPath);
|
|
AuResetMember(gCachedFullPath, path);
|
|
AuResetMember(gInitOnce);
|
|
});
|
|
}
|
|
|
|
AUKN_SYM bool GetWorkingDirectory(AuString &path)
|
|
{
|
|
#if !defined(AURORA_IS_MODERNNT_DERIVED)
|
|
|
|
if (!AuTryResize(path, 0x4000))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
|
|
|
std::wstring eh;
|
|
if (!AuTryResize(eh, 0x4000))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
auto length = ::GetCurrentDirectoryW(eh.size(), eh.data());
|
|
if (length == 0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
path = AuMove(Locale::ConvertFromWChar(eh.data(), length));
|
|
|
|
try
|
|
{
|
|
if (!path.ends_with(AuFS::kPathSplitter))
|
|
{
|
|
path += AuFS::kPathSplitter;
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
SysPushErrorCatch();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
|
|
#elif defined(AURORA_PLATFORM_ANDROID)
|
|
|
|
// TODO: consider pulling internal storage package directory
|
|
return false;
|
|
|
|
#elif defined(_USE_GET_CWD)
|
|
|
|
if (getcwd(path.data(), path.size()) == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
path.resize(strlen(path.data())); // downsize shouldn't throw
|
|
|
|
if (!path.ends_with(AuFS::kPathSplitter))
|
|
{
|
|
path += AuFS::kPathSplitter;
|
|
}
|
|
|
|
return true;
|
|
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
static bool GetModulePathSlow(AuString &path, char &splitter)
|
|
{
|
|
path.clear();
|
|
splitter = 0;
|
|
|
|
// TODO: BSD alternative sysctl CTL_KERN KERN_PROC KERN_PROC_PATHNAME -1
|
|
#if defined(AURORA_IS_MODERNNT_DERIVED)
|
|
|
|
wchar_t chungus[0x4000];
|
|
auto len = GetModuleFileNameW(
|
|
NULL,
|
|
chungus,
|
|
AuArraySize(chungus)
|
|
);
|
|
|
|
if (!len)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
path = Aurora::Locale::ConvertFromWChar(chungus, len);
|
|
splitter = '\\';
|
|
|
|
if (AuEndsWith(path, ".dll"))
|
|
{
|
|
path.clear();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
|
|
#elif defined(AURORA_IS_XNU_DERIVED)
|
|
// TODO: _NSGetExecutablePath() or CFBundleCopyExecutableURL?
|
|
// i think it would make sense to use NS over CoreFoundation
|
|
// i think we're also going to have to use CF's libevent abstraction - runloop source
|
|
// to pass through kqueue structures with the mach window message loop, like how
|
|
// user32 has MsgWaitMultipleObjects.
|
|
// t. windows and loonix dev
|
|
//
|
|
// TODO: if macos >= 10.12 || quarantine xattr
|
|
// /Applications/<app name>
|
|
CFURLRef bundleURL = CFBundleCopyExecutableURL(CFBundleGetMainBundle());
|
|
CFStringRef pathRef = CFURLCopyFileSystemPath(bundleURL, kCFURLPOSIXPathStyle);
|
|
|
|
auto utf16length = CFStringGetLength(pathRef);
|
|
auto maxUtf8len = CFStringGetMaximumSizeForEncoding(utf16length, kCFStringEncodingUTF8);
|
|
|
|
path.resize(maxUtf8len);
|
|
|
|
if (!CFStringGetCString(pathRef, path.data(), maxUtf8len, kCFStringEncodingUTF8))
|
|
{
|
|
path.clear();
|
|
return false;
|
|
}
|
|
|
|
path.resize(std::strlen(path.c_str()));
|
|
splitter = '/';
|
|
|
|
#elif defined(AURORA_PLATFORM_ANDROID)
|
|
|
|
// SELinux gets in the way in some instances
|
|
// There is no reason we should be searching for the jre binary
|
|
// I'm also not convined pulling a cached apk path is the best thing to do here
|
|
// Why should we even bother pulling /system/bin/app_process?
|
|
|
|
return false;
|
|
|
|
#elif defined(AURORA_IS_POSIX_DERIVED)
|
|
|
|
static const AuList<AuString> procFsPaths = {
|
|
"/proc/self/exe",
|
|
"/proc/self/file",
|
|
"/proc/curproc/exe",
|
|
"/proc/curproc/file"
|
|
};
|
|
|
|
if (!AuTryResize(path, 8192))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for (const auto &name : procFsPaths)
|
|
{
|
|
ssize_t count;
|
|
if ((count = readlink(name.c_str(), &path[0], path.size())) > 0)
|
|
{
|
|
if (!AuTryResize(path, count))
|
|
{
|
|
return false;
|
|
}
|
|
splitter = '/';
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
|
|
#endif
|
|
}
|
|
|
|
static bool GetModulePath(const AuString *&module, const AuString *&partialPath, const AuString *&fullPath)
|
|
{
|
|
if (!AuThreading::InitOnceLocker::TryLock(&gInitOnce, true))
|
|
{
|
|
gInitOnce.Wait();
|
|
}
|
|
else
|
|
{
|
|
bool bFailed {};
|
|
|
|
try
|
|
{
|
|
char spitter;
|
|
|
|
if (gCachedFullPath.size() ||
|
|
GetModulePathSlow(gCachedFullPath, spitter))
|
|
{
|
|
auto indexA = gCachedFullPath.find_last_of(spitter);
|
|
if (indexA != AuString::npos)
|
|
{
|
|
gCachedModule = gCachedFullPath.substr(indexA + 1);
|
|
gCachedPartialPath = gCachedFullPath.substr(0, indexA);
|
|
|
|
if (!gCachedPartialPath.ends_with(AuFS::kPathSplitter))
|
|
{
|
|
gCachedPartialPath += AuFS::kPathSplitter;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bFailed = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
bFailed = true;
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
bFailed = true;
|
|
SysPushErrorCatch();
|
|
}
|
|
|
|
AuThreading::InitOnceLocker::Finish(&gInitOnce, bFailed);
|
|
}
|
|
|
|
if (gInitOnce.IsUninitialized())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
module = &gCachedModule;
|
|
fullPath = &gCachedFullPath;
|
|
partialPath = &gCachedPartialPath;
|
|
return true;
|
|
}
|
|
|
|
AUKN_SYM AuOptional<const AuString &> GetProcessName()
|
|
{
|
|
const AuString *pModule, *pPartial, *pFull;
|
|
|
|
try
|
|
{
|
|
if (GetModulePath(pModule, pPartial, pFull) &&
|
|
pModule &&
|
|
pModule->size())
|
|
{
|
|
return *pModule;
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
SysPushErrorCatch();
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
AUKN_SYM AuOptional<const AuString &> GetProcessDirectory()
|
|
{
|
|
const AuString *pModule, *pPartial, *pFull;
|
|
|
|
try
|
|
{
|
|
if (GetModulePath(pModule, pPartial, pFull) &&
|
|
pPartial &&
|
|
pPartial->size())
|
|
{
|
|
return *pPartial;
|
|
}
|
|
|
|
{
|
|
static AuString cwd;
|
|
static AuInitOnce gInitOnce;
|
|
|
|
gInitOnce.Call([]()
|
|
{
|
|
GetWorkingDirectory(cwd);
|
|
});
|
|
|
|
if (cwd.size())
|
|
{
|
|
return cwd;
|
|
}
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
SysPushErrorCatch();
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
AUKN_SYM AuOptional<const AuString &> GetProcessFullPath()
|
|
{
|
|
const AuString *pModule, *pPartial, *pFull;
|
|
|
|
try
|
|
{
|
|
if (GetModulePath(pModule, pPartial, pFull) &&
|
|
pFull &&
|
|
pFull->size())
|
|
{
|
|
return *pFull;
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
SysPushErrorCatch();
|
|
}
|
|
|
|
return {};
|
|
}
|
|
} |