/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: Resources.cpp Date: 2021-6-16 Author: Reece ***/ #include #include "FS.hpp" #include "Resources.hpp" #if defined(AURORA_PLATFORM_LINUX) #include #include #include #elif defined(AURORA_PLATFORM_WIN32) #include #endif namespace Aurora::IO::FS { static AuString gHomeDirectory; static AuString gApplicationData; static AuOptional gSystemLibPath; static AuOptional gSystemLibPath2; static AuOptional gUserLibPath; static AuOptional gUserLibPath2; static const AuString kUnixAppData {"/opt"}; AUKN_SYM bool GetSystemDomain(AuString &path) { path = gApplicationData; return true; } AUKN_SYM bool GetProfileDomain(AuString &path) { path = gHomeDirectory; return true; } AUKN_SYM bool GetSystemResourcePath(const AuString &fileName, AuString &path) { path.clear(); if (fileName.find("..") != AuString::npos) { LogWarn("Exploit Attempt? A system resource path may not contain relative directory move tokens: {}", fileName); return false; } { AuString tempPath; if (Process::GetWorkingDirectory(tempPath)) { tempPath += "/" + fileName; if (FileExists(tempPath)) { path = tempPath; return true; } } } { AuString tempPath; if (Process::GetProcPath(tempPath)) { tempPath += "/" + fileName; if (FileExists(tempPath)) { path = tempPath; return true; } } } { auto systemPath = gHomeDirectory + fileName; if (FileExists(systemPath)) { path = systemPath; return true; } } { auto systemPath = gApplicationData + fileName; if (FileExists(systemPath)) { path = systemPath; return true; } } return false; } #if defined(AURORA_PLATFORM_WIN32) static AuString GetSpecialDir(REFKNOWNFOLDERID rfid) { PWSTR directory; if (SHGetKnownFolderPath(rfid, KF_FLAG_DEFAULT, NULL, &directory) != S_OK) { SysPanic("Couldn't get known special directory path of [MS:{}-{}-{}-{}{}{}{}{}{}{}{}] with a NULL access token", rfid.Data1, rfid.Data2, rfid.Data3, rfid.Data4[0], rfid.Data4[1], rfid.Data4[2], rfid.Data4[3], rfid.Data4[4], rfid.Data4[5], rfid.Data4[6], rfid.Data4[7]); } return Locale::ConvertFromWChar(directory); } static void SetNamespaceDirectories() { gHomeDirectory = GetSpecialDir(FOLDERID_RoamingAppData); gApplicationData = GetSpecialDir(FOLDERID_ProgramData); gSystemLibPath = GetSpecialDir(FOLDERID_System); } #elif defined(AURORA_PLATFORM_LINUX) || defined(AURORA_PLATFORM_BSD) static void SetUnixPaths(AuOptional &primary, AuOptional &secondary, const AuString &base) { primary = base; if (Aurora::Build::IsPlatformX32()) { secondary = base + "32"; } else { secondary = base + "64"; } if (DirExists(*secondary)) { std::swap(secondary, primary); } else { secondary.reset(); } if (!DirExists(*primary)) { primary.reset(); } } static void SetXdg(AuString &out, const char *envvar, const char *home, const char *defaultHomeExt, const char *fallback) { auto value = getenv(envvar); if (value) { out = value; } else if (home) { out = AuString(home) + defaultHomeExt; } else { out = fallback; } } static void SetNamespaceDirectories() { const char *homedir; homedir = getenv("HOME"); if (!homedir) { homedir = getpwuid(getuid())->pw_dir; } // XDG Base Directory Specification // $XDG_CONFIG_HOME defines the base directory relative to which user-specific configuration files should be stored. If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME/.config should be used. // $XDG_DATA_HOME defines the base directory relative to which user-specific data files should be stored SetXdg(gApplicationData, "XDG_CONFIG_HOME", homedir, "/.config", kUnixAppData); SetXdg(gHomeDirectory, "XDG_DATA_HOME", homedir, "/.local/share", "."); SetUnixPaths(gUserLibPath, gUserLibPath2, "/usr/lib"); SetUnixPaths(gSystemLibPath, gSystemLibPath2, "/lib"); } #else static void SetNamespaceDirectories() { gHomeDirectory = "."; gApplicationData = "."; } #endif AuOptional GetSystemLibPath() { return gSystemLibPath; } AuOptional GetUserLibPath() { return gUserLibPath; } AuOptional GetSystemLibPath2() { return gSystemLibPath2; } AuOptional GetUserLibPath2() { return gUserLibPath2; } static void ChangeDir() { #if !defined(AU_NO_AU_HOME_BRANDING) if (gRuntimeConfig.fio.defaultBrand.size()) { gApplicationData += "/" + gRuntimeConfig.fio.defaultBrand; gHomeDirectory += "/" + gRuntimeConfig.fio.defaultBrand; } #endif NormalizePath(gApplicationData); NormalizePath(gHomeDirectory); if (gApplicationData == gHomeDirectory) { gApplicationData += kPathSplitter; gHomeDirectory += kPathSplitter; gApplicationData += "System"; gHomeDirectory += "Profile"; } // Noting we append a path splitter to prevent hair pulling over missing path delimiters // Eg: GetHome() + "myAwesomeApp/Config" = %HOME%/Aurora/ProfilemyAwsomeApp/Config gApplicationData += kPathSplitter; gHomeDirectory += kPathSplitter; } void InitResources() { SetNamespaceDirectories(); ChangeDir(); } }