From 94970d689ce626684d14cd72997836b9b315a0ca Mon Sep 17 00:00:00 2001 From: Jamie Reece Wilson Date: Tue, 24 Sep 2024 18:53:54 +0100 Subject: [PATCH] [*] Refactor some APIs to use string views instead of strings [+] Added new shell dirs API [+] AuOptional GetUserDocuments() [+] AuOptional GetUserDownloads() [+] AuOptional GetUserDesktop() [+] AuOptional GetUserPhotos() [+] AuOptional GetUserVideos() [+] AuOptional GetUserMusic() [*] Amend IPCHandle::InitFromSharing (use string view) [*] AuFS devices API should now use string views [*] AuProcess, Process APIs now use string views (ModuleLoadRequest, LoadModule, GetProcAddressEx, etc) [*] AuProcess, Paths APIs now use string views (GetProcessDirectory, GetProcessFullPath, etc) [*] Fix XP using common my documents vs local user documents --- Include/Aurora/IO/FS/Devices.hpp | 28 +- Include/Aurora/IO/FS/Resources.hpp | 71 ++-- Include/Aurora/IO/IOHandle.hpp | 2 +- Include/Aurora/Process/Paths.hpp | 6 +- Include/Aurora/Process/Process.hpp | 124 +++++-- Source/Async/AsyncApp.cpp | 1 + Source/Debug/ExceptionWatcher.Win32.cpp | 2 +- Source/IO/AuIOHandle.cpp | 2 +- Source/IO/AuIOHandle.hpp | 2 +- Source/IO/FS/FS.cpp | 19 +- Source/IO/FS/FSPlatformDevices.Linux.cpp | 108 ++++--- Source/IO/FS/FSPlatformDevices.NT.cpp | 29 +- Source/IO/FS/FSPlatformDevices.cpp | 6 +- Source/IO/FS/Resources.cpp | 394 +++++++++++++++-------- Source/Process/AuPaths.cpp | 6 +- Source/Process/AuProcess.cpp | 240 +++++++++----- 16 files changed, 704 insertions(+), 336 deletions(-) diff --git a/Include/Aurora/IO/FS/Devices.hpp b/Include/Aurora/IO/FS/Devices.hpp index 45a1c236..d1e2a67f 100644 --- a/Include/Aurora/IO/FS/Devices.hpp +++ b/Include/Aurora/IO/FS/Devices.hpp @@ -107,53 +107,53 @@ namespace Aurora::IO::FS * Provides the best-fit FSLogicalPartition::filesystemMountPoints of a string. * Sometimes the platform shell can help, some platforms need to pull the fs devices cache. */ - AUKN_SYM AuString GetRootFromPath(const AuString &fileOrDirPath); + AUKN_SYM AuString GetRootFromPath(const AuROString &fileOrDirPath); /** * Provides a FSDevice::devicePath of a file or directory. */ - AUKN_SYM AuResult GetDeviceFromPath(const AuString &fileOrDirPath); + AUKN_SYM AuResult GetDeviceFromPath(const AuROString &fileOrDirPath); /** * Provides a FSDevice::devicePath of a root mountpoint. */ - AUKN_SYM AuResult GetDeviceFromRoot(const AuString &root); + AUKN_SYM AuResult GetDeviceFromRoot(const AuROString &root); /** * Provides the FSLogicalPartition::logicalMount of a file or directory. */ - AUKN_SYM AuResult GetLogicalMountFromPath(const AuString &fileOrDirPath); + AUKN_SYM AuResult GetLogicalMountFromPath(const AuROString &fileOrDirPath); - AUKN_SYM AuString TrySimplifyDevicePath(const AuString &deviceOrLogicalMountPath); + AUKN_SYM AuString TrySimplifyDevicePath(const AuROString &deviceOrLogicalMountPath); // max: unbuffered pipe io - AUKN_SYM AuUInt32 GetPerformanceBufferSizeFromPath(const AuString &fileOrDirPath); + AUKN_SYM AuUInt32 GetPerformanceBufferSizeFromPath(const AuROString &fileOrDirPath); // min: unbuffered pipe io - AUKN_SYM AuUInt32 GetPhysicalSectorSizeFromPath(const AuString &fileOrDirPath); + AUKN_SYM AuUInt32 GetPhysicalSectorSizeFromPath(const AuROString &fileOrDirPath); // min viable sector size with abstractions on top of the disk - AUKN_SYM AuUInt32 GetLogicalSectorSizeFromPath(const AuString &fileOrDirPath); + AUKN_SYM AuUInt32 GetLogicalSectorSizeFromPath(const AuROString &fileOrDirPath); /** * Provides a FSLogicalPartition::space of a file or directory. */ - AUKN_SYM LogicalUsedResponse GetLogicalUsedFromPath(const AuString &fileOrDirPath); + AUKN_SYM LogicalUsedResponse GetLogicalUsedFromPath(const AuROString &fileOrDirPath); /** * Provides a FSLogicalPartition::space of a logical volume path / FSLogicalPartition::logicalMount string. */ - AUKN_SYM LogicalUsedResponse GetLogicalUsedFromLogicalDevice(const AuString &logicalMountPath); + AUKN_SYM LogicalUsedResponse GetLogicalUsedFromLogicalDevice(const AuROString &logicalMountPath); // Convenience function - AUKN_SYM AuUInt64 GetDeviceSizeInBytes(const AuString& physicalDevicePath); + AUKN_SYM AuUInt64 GetDeviceSizeInBytes(const AuROString &physicalDevicePath); // Convenience function - AUKN_SYM AuResult GetDeviceModel(const AuString& physicalDevicePath); + AUKN_SYM AuResult GetDeviceModel(const AuROString &physicalDevicePath); // Convenience function - AUKN_SYM AuResult GetFSDeviceByFilePath(const AuString &fileOrDirPath); + AUKN_SYM AuResult GetFSDeviceByFilePath(const AuROString &fileOrDirPath); // Convenience function - AUKN_SYM AuResult GetFSDeviceByDevice(const AuString &physicalDevicePath); + AUKN_SYM AuResult GetFSDeviceByDevice(const AuROString &physicalDevicePath); /* * Provides a copy of the internal FSDevice cache under lock diff --git a/Include/Aurora/IO/FS/Resources.hpp b/Include/Aurora/IO/FS/Resources.hpp index 9f276413..07050db4 100644 --- a/Include/Aurora/IO/FS/Resources.hpp +++ b/Include/Aurora/IO/FS/Resources.hpp @@ -10,17 +10,19 @@ namespace Aurora::IO::FS { /** - * @brief Provides an application specific storage path for sharing data amongst Aurora applications sharing the same branding info (defer to the init structure) + * @brief Provides an application specific storage path for sharing data amongst Aurora applications sharing the same branding info (defer to the init structure). + * This should be used for machine local configs and caches. */ - AUKN_SYM AuOptional GetSystemDomain(); + AUKN_SYM AuOptional GetSystemDomain(); /** - * @brief Provides an application specific storage path for user-local application data, isolated with respect to your Aurora application brand info (defer to the init structure) - */ - AUKN_SYM AuOptional GetProfileDomain(); + * @brief Provides an application specific storage path for user-local application data, isolated with respect to your Aurora application brand info (defer to the init structure). + * This should be used for storing private user configs under an application data subdirectory. + */ + AUKN_SYM AuOptional GetProfileDomain(); - AUKN_SYM bool GetSystemResourcePath(const AuString &fileName, AuString &path); + AUKN_SYM bool GetSystemResourcePath(const AuROString &fileName, AuString &path); /** * @brief Get package path @@ -31,39 +33,64 @@ namespace Aurora::IO::FS * ...on platforms with read-only application specific data directories * @param path * @return - */ - AUKN_SYM AuOptional GetPackagePath(); + */ + AUKN_SYM AuOptional GetPackagePath(); /** - * @brief Pulls the application directory as defined by the operating system standard file system hierarchy - * Otherwise, XDG_CONFIG_CONFIG or %appdata%. + * @brief Pulls the application directory as defined by the operating system standard file system hierarchy. + * This is often $XDG_CONFIG_HOME or %APPDATA%. * This directory might be sandboxed to the user or application by the operating system. - */ - AUKN_SYM AuOptional GetAppData(); + * Are you looking for GetProfileDomain()/GetSystemDomain()? These will provide better paths for storing configs and caches respectively. + */ + AUKN_SYM AuOptional GetAppData(); /** * @brief Pulls the users home directory, untouched - */ - AUKN_SYM AuOptional GetUserHome(); + */ + AUKN_SYM AuOptional GetUserHome(); + + AUKN_SYM AuOptional GetUserDocuments(); + + AUKN_SYM AuOptional GetUserDownloads(); + + AUKN_SYM AuOptional GetUserDesktop(); + + AUKN_SYM AuOptional GetUserPhotos(); + + AUKN_SYM AuOptional GetUserVideos(); + + AUKN_SYM AuOptional GetUserMusic(); /** * @brief Global application data that requires no special permissions to access. * This could be an SD-Card or user profile. * This could be the root of the user managable aplication directory. - */ - AUKN_SYM AuOptional GetWritableAppdata(); + */ + AUKN_SYM AuOptional GetWritableAppdata(); /** * @brief Global application data that requires special permissions to access, usually configured by a system account during installation - */ - AUKN_SYM AuOptional GetRootAppdata(); + */ + AUKN_SYM AuOptional GetRootAppdata(); /** * @brief Get user installable application directory - */ - AUKN_SYM AuOptional GetUserProgramsFolder(); + */ + AUKN_SYM AuOptional GetUserProgramsFolder(); - AUKN_SYM AuOptional NewTempFile(); + /** + * @brief Creates an empty temp file and returns its' path. + * It should be marked for deletion on shutdown, or be located in a directory marked for auto-deletion, or be located on a temporary ramdisk, or exist in a temporary file system mount. + * If you can delete it for us, even better. + * Windows XP warning: this does not use C:\Windows\Temp. Check documents instead. + */ + AUKN_SYM AuOptional NewTempFile(); - AUKN_SYM AuOptional NewTempDirectory(); + /** + * @brief Creates an empty temp directory and returns its' path. + * It should be marked for deletion on shutdown, or be located in a directory marked for auto-deletion, or be located on a temporary ramdisk, or exist in a temporary file system mount. + * If you can delete it for us, even better. + * Windows XP warning: this does not use C:\Windows\Temp. Check documents instead. + */ + AUKN_SYM AuOptional NewTempDirectory(); } \ No newline at end of file diff --git a/Include/Aurora/IO/IOHandle.hpp b/Include/Aurora/IO/IOHandle.hpp index 7c5a3680..7c16c5fa 100644 --- a/Include/Aurora/IO/IOHandle.hpp +++ b/Include/Aurora/IO/IOHandle.hpp @@ -129,7 +129,7 @@ namespace Aurora::IO virtual bool InitFromStreamEnum(EStandardStream eStream) = 0; - virtual bool InitFromSharing(const AuString &handle) = 0; + virtual bool InitFromSharing(const AuROString &handle) = 0; virtual AuUInt64 GetOSHandle() const = 0; diff --git a/Include/Aurora/Process/Paths.hpp b/Include/Aurora/Process/Paths.hpp index b71af0c8..6d23b157 100644 --- a/Include/Aurora/Process/Paths.hpp +++ b/Include/Aurora/Process/Paths.hpp @@ -20,17 +20,17 @@ namespace Aurora::Process * @brief Fetches the applications binary or package directory * @return */ - AUKN_SYM AuOptional GetProcessDirectory(); + AUKN_SYM AuOptional GetProcessDirectory(); /** * @brief Fetches the full-path of the applications binary, if known * @return */ - AUKN_SYM AuOptional GetProcessFullPath(); + AUKN_SYM AuOptional GetProcessFullPath(); /** * @brief Fetches the applications primary module name * @return */ - AUKN_SYM AuOptional GetProcessName(); + AUKN_SYM AuOptional GetProcessName(); } \ No newline at end of file diff --git a/Include/Aurora/Process/Process.hpp b/Include/Aurora/Process/Process.hpp index ec793d1b..ca8d4a11 100644 --- a/Include/Aurora/Process/Process.hpp +++ b/Include/Aurora/Process/Process.hpp @@ -48,50 +48,136 @@ namespace Aurora::Process static AuList kCWDPath = { EModulePath::eModulePathCWD }; static AuList kProcPath = { EModulePath::eProcessDirectory }; + // Binding warning: this object takes references to references/pointers within the full-expressions (we live here) to parent scope[s] (your callframe lives here, with the provided temp string views). + // this object is therefore not expected to outlive any references you pass at it. + // we should only exist in the scope of FULL-EXPRESSION := { LoadModule({ ModuleLoadRequest: { temp raw string pointer view to anywhere valid throughout the call }}) } + // binders will need to create a derived type to contain two AuStrings to fill mod and version. struct ModuleLoadRequest { - inline ModuleLoadRequest(const AuList &directories, const AuString &mod) : mod(mod), specifiedSearchPaths(&directories), searchPath(&kSpecifiedPathStrict) + inline ModuleLoadRequest() : + searchPath(&kSpecifiedPathStrict) + { + + } + + inline ModuleLoadRequest(const AuList &directories, + const AuString &mod) : + mod(mod), + specifiedSearchPaths(&directories), + searchPath(&kSpecifiedPathStrict) {} - inline ModuleLoadRequest(const AuList &directories, const AuString &mod, const AuString &version) : mod(mod), version(version), specifiedSearchPaths(&directories), searchPath(&kSpecifiedPathStrict) + inline ModuleLoadRequest(const AuList &directories, + const AuROString &mod, + const AuROString &version) : + mod(mod), version(version), + specifiedSearchPaths(&directories), + searchPath(&kSpecifiedPathStrict) {} - inline ModuleLoadRequest(const AuString &mod) : mod(mod), searchPath(&kAdminOverloadableSearchPath) + inline ModuleLoadRequest(const AuROString &mod) : + mod(mod), + searchPath(&kAdminOverloadableSearchPath) {} - inline ModuleLoadRequest(const AuString &mod, const AuString &version) : mod(mod), version(version), searchPath(&kAdminOverloadableSearchPath) + inline ModuleLoadRequest(const AuROString &mod, + const AuROString &version) : + mod(mod), + version(version), + searchPath(&kAdminOverloadableSearchPath) {} - AuString mod; - AuString version; + AuROString mod; + AuROString version; AuList const * specifiedSearchPaths {}; AuList const * searchPath {}; bool verify {}; // always effectively true if the executable is signed and enableMitigations is true bool unixCheckPlusX { true }; bool enableMitigations { true }; bool forceMitigations { false }; + char padZero[128] { 0 }; }; - /** - * @brief Loads a dynamic link module into cache, by the name of 'mod', somewhere in the directories specified by 'searchPath'. - * You should not provide a suffix, platform extension, or the full aurora dll string. Path resolution will take care of - * resolving the Aurora ABI, falling back to mod.platformext. - * @param request - * @return - */ + /// Provides a scriptability style DLL suffix including the relevant file extension. + /// I do not recommend trying to build DLL filenames yourself, use LoadModule instead. + /// Different version, file extension, and unique suffix order and values may apply. + AUKN_SYM AuROString GetViewOfAuroraDLLSuffix(); + + /// Provides the platform extension for dynamically linked objects. + /// This may become before or after the version string, depending on the host platform style. + /// I do not recommend trying to build DLL filenames yourself, use LoadModule instead. + AUKN_SYM AuROString GetViewOfDynamicLibraryExtensionSuffix(); + + /// Provides the scriptability style architecture string for platform local build artefects. + AUKN_SYM AuROString GetViewOfArchitectureSuffix(); + + /// @brief Loads a dynamic link module into cache, by the name of 'mod', somewhere in the directories specified by 'searchPath'. + /// You should not provide a suffix, platform extension, or the full aurora dll string. Path resolution will take care of + /// resolving the Aurora build ABI strings, falling back to "${request.mod}.${GetViewOfDynamicLibraryExtensionSuffix()}". + /// @param request + /// @return AUKN_SYM bool LoadModule(const ModuleLoadRequest &request); + /// Updated version of LoadModule. + /// Returns a VOID* handle to be used as a replacement for win32 LoadLibraryW(...) / posix dlopen(...), to be followed up by a/multiple GetProcessAddress / dlsym calls. + /// GetProcAddressEx is to be used with this VOID* handle. AUKN_SYM void *LoadModuleEx(const ModuleLoadRequest &request); - AUKN_SYM void *GetProcHandle(const AuString &name); + /// Safe (without unloads) handle fetch of LoadModuleEx. + AUKN_SYM void *GetProcHandle(const AuROString &name); - AUKN_SYM AuMach GetProcAddress(const AuString &mod, const AuString &symbol); + /// Safe process address fetch a symbol inside of a nammed LoadModule object. + AUKN_SYM AuMach GetProcAddress(const AuROString &mod, const AuRONString &symbol); - AUKN_SYM AuMach GetProcAddressEx(void *pHandle, const AuString &symbol); + /// Safe (without unloads) process address fetch a symbol inside of LoadModuleEx object. + AUKN_SYM AuMach GetProcAddressEx(void *pHandle, const AuRONString &symbol); + /// Returns a copy of the directories in which the requests of LoadModule can be fulfilled. AUKN_SYM AuList GetBinaryClassPath(); - AUKN_SYM bool SetBinaryClassPath(const AuList &list, bool preloadAll = false); - - AUKN_SYM bool AddBinaryClassPath(const AuString &dir, bool preloadAll = false); + /// Warning: in production applications, becareful about preloading binaries of unknown origin. + /// + /// Consider every directory in "list" to be within the perview of the plugin-write user group. + /// Anybody, presumably the local user and all its processes, can write/install plugins, is capable of loading any arbitrary code whatsoever. + /// On Windows, the local user will have these user-write permissions in these plugin-write areas, to write any arbitrary DLL to inject. At best, you can try to limit yourself to read-only directories of admin-assisted origin. + /// On Linux, the local user is king, with sandboxing being a joke and almost every system is full of holes. btw freebsd has native POSIX ACL and jail support. + /// On Android, the local user will NOT have these write permissions, so that no unwanted dynamic code objects can be loaded through the hardened libc and selinux sandbox (see: application.android:extractNativeLibs). + /// On UWP and WinRT-Likes, LoadPackagedLibrary will ensure we're sandboxed from dynamic attacks. + /// Therefore, on some platforms it is possible for any library to get accidentally preloaded or hit (loaded, tls init code hit, static init code hit, etc). + /// DRM and sandboxing solutions should be monitoring the APIs we use, so it shouldn't be too much of a problem, if your application is packed properly. + /// + /// This is relevant for DRMs, anticheats, web browsers, and sandboxes that want to prevent arbitrary code injections. + /// Historically software such as FireFox (against malware/adware), Chrome (against malware/adware), anticheats (skids CreateRemoteThread at kernel32::LoadLibraryW attempts), + /// sandboxes of arxan nature (Microsoft Playready, Widevine, Xbox Live game ports to PC, GTA V, et al), EasyAnticheat, all care for the tiniest bit of process isolation security. + /// When packing such software, be careful not to allow for arbitrary LoadLibraryW from trusted code locations, because we could be just loading everything... Even tho we try not to. We even have WinTrust checks. + /// + /// This is intended for loading widgets, plugins, and various static extensions on relatively static platforms. + /// If shared modules exist on a platform within directories we have file iterate permissions to read, and we're capable of loading dynamic modules (sometimes prevetted), this function will work. + /// This includes some environments such as WinRT/UWP-Likes (incl packaged modules?) and Android where ApplicationInfo#nativeLibraryDir since API9 instantiated by "application.android:extractNativeLibs" is allowed through the sandbox. + AUKN_SYM bool SetBinaryClassPath(const AuList &list, AuOptional optBoolPreloadAll = { false }); + + /// Warning: in production applications, becareful about preloading binaries of unknown origin. + /// + /// Consider every directory in "list" to be within the perview of the plugin-write user group. + /// Anybody, the local user and its processes, who can write/install plugins, is capable of loading any arbitrary code whatsoever. + /// On Windows, the local user will have these user-write permissions in these plugin-write areas, to write any arbitrary DLL to inject. At best, you can try to limit yourself to read-only directories of admin-assisted origin. + /// On Linux, the local user is king, with sandboxing being a joke and almost every system is full of holes. btw freebsd has native POSIX ACL and jail support. + /// On Android, the local user will NOT have these write permissions, so that no unwanted dynamic code objects can be loaded through the hardened libc and selinux sandbox (see: application.android:extractNativeLibs). + /// On UWP and WinRT-Likes, LoadPackagedLibrary will ensure we're sandboxed from dynamic attacks. + /// Therefore, on some platforms it is possible for any library to get accidentally preloaded or hit (loaded, tls init code hit, static init code hit, etc). + /// DRM and sandboxing solutions should be monitoring the APIs we use, so it shouldn't be too much of a problem, if your application is packed properly. + /// + /// This is relevant for DRMs, anticheats, web browsers, and sandboxes that want to prevent arbitrary code injections. + /// Historically software such as FireFox (against malware/adware), Chrome (against malware/adware), anticheats (skids CreateRemoteThread at kernel32::LoadLibraryW attempts), + /// sandboxes of arxan nature (Microsoft Playready, Widevine, Xbox Live game ports to PC, GTA V, et al), EasyAnticheat, all care for the tiniest bit of process isolation security. + /// When packing such software, be careful not to allow for arbitrary LoadLibraryW from trusted code locations, because we could be just loading everything... Even tho we try not to. We even have WinTrust checks. + /// + /// This is intended for loading widgets, plugins, and various static extensions on relatively static platforms. + /// If shared modules exist on a platform within directories we have file iterate permissions to read, and we're capable of loading dynamic modules (sometimes prevetted), this function will work. + /// This includes some environments such as WinRT/UWP-Likes (incl packaged modules?) and Android where ApplicationInfo#nativeLibraryDir since API9 instantiated by "application.android:extractNativeLibs" is allowed through the sandbox. + AUKN_SYM bool AddBinaryClassPath(const AuROString &dir, AuOptional optBoolPreloadAll = { false }); + + /// TODO: Most platforms *hate* unloading dynamic linked libraries. on the otherhand, artists writing native scripts love them. + /// At some point, we'll probably add an API for unloading handles, and flushing out the internal cache table. + /// If the platform ignores it, and we just load the old internal handle from the os loader, oh well... guess we dont have dynamic code reloading. } \ No newline at end of file diff --git a/Source/Async/AsyncApp.cpp b/Source/Async/AsyncApp.cpp index 9fd5b40c..a8dfe12b 100644 --- a/Source/Async/AsyncApp.cpp +++ b/Source/Async/AsyncApp.cpp @@ -29,6 +29,7 @@ namespace Aurora::Async { gAsyncAppMem->Shutdown(); AuResetMember(gAsyncAppMem); + AuResetMember(gAsyncApp); } } diff --git a/Source/Debug/ExceptionWatcher.Win32.cpp b/Source/Debug/ExceptionWatcher.Win32.cpp index c267b06c..4eb2a98f 100644 --- a/Source/Debug/ExceptionWatcher.Win32.cpp +++ b/Source/Debug/ExceptionWatcher.Win32.cpp @@ -562,7 +562,7 @@ namespace Aurora::Debug return; } - auto procNameWide = AuLocale::ConvertFromUTF8(pProcName->c_str()); + auto procNameWide = AuLocale::ConvertFromUTF8(*pProcName); HKEY hKey; if (pRegOpenKeyExW && diff --git a/Source/IO/AuIOHandle.cpp b/Source/IO/AuIOHandle.cpp index 8c88aea4..97c80425 100644 --- a/Source/IO/AuIOHandle.cpp +++ b/Source/IO/AuIOHandle.cpp @@ -359,7 +359,7 @@ namespace Aurora::IO return FS::UnapplyFileSectionLock(AuUnsafeRaiiToShared(this), uOffset, uLength); } - bool AFileHandle::InitFromSharing(const AuString &handle) + bool AFileHandle::InitFromSharing(const AuROString &handle) { AU_LOCK_GUARD(this); diff --git a/Source/IO/AuIOHandle.hpp b/Source/IO/AuIOHandle.hpp index c92e6402..2727cf63 100644 --- a/Source/IO/AuIOHandle.hpp +++ b/Source/IO/AuIOHandle.hpp @@ -36,7 +36,7 @@ namespace Aurora::IO bool InitFromHandleCopy(const IIOHandle *pHandle) override; - bool InitFromSharing(const AuString &handle) override; + bool InitFromSharing(const AuROString &handle) override; bool InitFromPath(HandleCreate create) override; diff --git a/Source/IO/FS/FS.cpp b/Source/IO/FS/FS.cpp index d6627f10..5e398186 100644 --- a/Source/IO/FS/FS.cpp +++ b/Source/IO/FS/FS.cpp @@ -279,27 +279,38 @@ namespace Aurora::IO::FS //for (auto &character : str) for (auto itr = str.begin(); itr != str.end(); - itr++) + ) { auto &character = *itr; auto holding = *itr; if ((character == '\\') || (character == '/')) { + // AuFS::Devices will break if this is not correct + // Turns out POSIX files can have valid NT separators #if defined(AURORA_IS_POSIX_DERIVED) if (character == '\\' && prevC == '\\') { - *(itr - 1) = '\\'; itr = str.erase(itr); + doubleSlash--; } - #endif - + else + { + itr++; + doubleSlash++; + } + character = kPathSplitter; + #else + itr++; character = kPathSplitter; doubleSlash++; + #endif + } else { + itr++; doubleSlash = 0; } diff --git a/Source/IO/FS/FSPlatformDevices.Linux.cpp b/Source/IO/FS/FSPlatformDevices.Linux.cpp index ec492097..5bf9f79c 100644 --- a/Source/IO/FS/FSPlatformDevices.Linux.cpp +++ b/Source/IO/FS/FSPlatformDevices.Linux.cpp @@ -29,7 +29,7 @@ namespace Aurora::IO::FS bool SpecialsInDirectory(const AuROString &string, AuList &dirs); - static AuOptional ReadLink(const AuString &path) + static AuOptional ReadLink(const AuROString &path) { AuString ret; ret.resize(4096); @@ -39,8 +39,12 @@ namespace Aurora::IO::FS { return {}; } + else + { + ret.resize(count); + } - if (ret[0] != '/') + if (ret.size() && ret[0] != '/') { AuROString dir; AuString path2 = path; @@ -70,44 +74,52 @@ namespace Aurora::IO::FS // to a handful of in thread IPC and intraprocess memcpy. posix and derived systems are // going to suck regardless. its not like there some magic database with a nice little // pnp or wsock api that'll just dump all the related fields in a handful of API calls. - static int CachedStat(const AuString &path, struct stat *pstat) + static int CachedStat(const AuROString &path, struct stat *pstat) { AU_LOCK_GUARD(gMutex); - auto itr = gCachedStat.find(path); - if (itr == gCachedStat.end()) + try { - int err = ::stat(path.c_str(), pstat); - if (-1 == err) + // TODO: use roxtl het lookup instead of allocating AuString + auto itr = gCachedStat.find(AuString(path)); + if (itr == gCachedStat.end()) { - gCachedStat[path] = {}; - errno = 0; + int err = ::stat(path.c_str(), pstat); + if (-1 == err) + { + gCachedStat[path] = {}; + errno = 0; + } + else + { + gCachedStat[path] = *pstat; + } + return err; } else { - gCachedStat[path] = *pstat; + auto &that = itr->second; + if (that) + { + *pstat = that.Value(); + return 0; + } + else + { + return -1; + } } - return err; } - else + catch (...) { - auto &that = itr->second; - if (that) - { - *pstat = that.Value(); - return 0; - } - else - { - return -1; - } + return -1; } } - static bool BlockExists(const AuString &path) + static bool BlockExists(const AuROString &path) { struct stat s; - int err = CachedStat(path.c_str(), &s); + int err = CachedStat(path, &s); if (-1 == err) { return false; @@ -115,7 +127,7 @@ namespace Aurora::IO::FS return S_ISBLK(s.st_mode); } - static AuString _DevFromPath(const AuString &path) + static AuString _DevFromPath(const AuROString &path) { auto pos = path.find_last_of('/'); if (pos == AuString::npos) @@ -132,7 +144,7 @@ namespace Aurora::IO::FS return dev; } - static AuString GetDevDevPathFromSysDev(const AuString &path) + static AuString GetDevDevPathFromSysDev(const AuROString &path) { if (AuStartsWith(path, "/sys/block/")) { @@ -160,7 +172,7 @@ namespace Aurora::IO::FS } } - static AuPair ReadIDPair(const AuString &path) + static AuPair ReadIDPair(const AuROString &path) { struct stat s; if (path.empty()) @@ -168,7 +180,7 @@ namespace Aurora::IO::FS return {}; } - auto err = CachedStat(path.c_str(), &s); + auto err = CachedStat(path, &s); if (err == -1) { return {}; @@ -182,7 +194,7 @@ namespace Aurora::IO::FS return AuMakePair(major(s.st_rdev), minor(s.st_rdev)); } - static AuPair ReadIDPairSym(const AuString &path) + static AuPair ReadIDPairSym(const AuROString &path) { if (auto optLink = ReadLink(path)) { @@ -194,7 +206,7 @@ namespace Aurora::IO::FS } } - static AuString GetSysDevFromPathLogical(const AuString &path) + static AuString GetSysDevFromPathLogical(const AuROString &path) { struct stat s; auto pathEx = NormalizePathRet(path); @@ -203,7 +215,7 @@ namespace Aurora::IO::FS return {}; } - auto err = CachedStat(pathEx.c_str(), &s); + auto err = CachedStat(pathEx, &s); if (err == -1) { return {}; @@ -212,7 +224,7 @@ namespace Aurora::IO::FS return AuString(fmt::format("/sys/dev/block/{}:{}", major(s.st_dev), minor(s.st_dev))); } - static AuString GetSysDevFromDev(const AuString &path) + static AuString GetSysDevFromDev(const AuROString &path) { struct stat s; if (path.empty()) @@ -220,7 +232,7 @@ namespace Aurora::IO::FS return {}; } - auto err = CachedStat(path.c_str(), &s); + auto err = CachedStat(path, &s); if (err == -1) { return {}; @@ -234,7 +246,7 @@ namespace Aurora::IO::FS return AuString(fmt::format("/sys/dev/block/{}:{}", major(s.st_rdev), minor(s.st_rdev))); } - static AuString MagicPathRd(const AuString &shortLogical) + static AuString MagicPathRd(const AuROString &shortLogical) { if (auto optLink = ReadLink(shortLogical)) { @@ -257,7 +269,7 @@ namespace Aurora::IO::FS } } - static AuString MagicPath(const AuString &path) + static AuString MagicPath(const AuROString &path) { auto shortLogical = GetSysDevFromPathLogical(path); if (shortLogical.empty()) @@ -269,7 +281,7 @@ namespace Aurora::IO::FS } // isnt posshit a nice family of os? - static AuString GetSysDevFromPathPhysical(const AuString &path) + static AuString GetSysDevFromPathPhysical(const AuROString &path) { if (AuStartsWith(path, "/dev/")) { @@ -311,7 +323,7 @@ namespace Aurora::IO::FS return {}; } - static AuString GetDevParent(const AuString &str) + static AuString GetDevParent(const AuROString &str) { auto b = GetSysDevFromDev(str); auto slavesDir = fmt::format("{}/slaves", b); @@ -418,7 +430,7 @@ namespace Aurora::IO::FS return ret; } - static bool ReadIsROFromPartition(const AuString &path) + static bool ReadIsROFromPartition(const AuROString &path) { if (auto optFile = ReadPosixFile(fmt::format("{}/ro", path))) { @@ -520,7 +532,7 @@ namespace Aurora::IO::FS return uuids::uuid(hash.begin(), hash.end()); } - AUKN_SYM AuResult GetDeviceFromPath(const AuString &path) + AUKN_SYM AuResult GetDeviceFromPath(const AuROString &path) { try { @@ -551,7 +563,7 @@ namespace Aurora::IO::FS } } - AUKN_SYM AuResult GetLogicalMountFromPath(const AuString &fileOrDirPath) + AUKN_SYM AuResult GetLogicalMountFromPath(const AuROString &fileOrDirPath) { try { @@ -576,7 +588,7 @@ namespace Aurora::IO::FS } } - AUKN_SYM AuResult GetDeviceFromRoot(const AuString &root) + AUKN_SYM AuResult GetDeviceFromRoot(const AuROString &root) { try { @@ -589,7 +601,7 @@ namespace Aurora::IO::FS } } - AUKN_SYM AuUInt32 GetLogicalSectorSizeFromPath(const AuString &path) + AUKN_SYM AuUInt32 GetLogicalSectorSizeFromPath(const AuROString &path) { struct statvfs data; @@ -608,7 +620,7 @@ namespace Aurora::IO::FS return data.f_bsize; } - AUKN_SYM AuUInt32 GetPhysicalSectorSizeFromPath(const AuString &path) + AUKN_SYM AuUInt32 GetPhysicalSectorSizeFromPath(const AuROString &path) { try { @@ -638,7 +650,7 @@ namespace Aurora::IO::FS } } - AUKN_SYM LogicalUsedResponse GetLogicalUsedFromLogicalDevice(const AuString &logicalMountPath) + AUKN_SYM LogicalUsedResponse GetLogicalUsedFromLogicalDevice(const AuROString &logicalMountPath) { try { @@ -677,7 +689,7 @@ namespace Aurora::IO::FS } } - AUKN_SYM AuUInt64 GetDeviceSizeInBytes(const AuString &physicalDevicePath) + AUKN_SYM AuUInt64 GetDeviceSizeInBytes(const AuROString &physicalDevicePath) { try { @@ -716,7 +728,7 @@ namespace Aurora::IO::FS } } - AUKN_SYM AuUInt32 GetPerformanceBufferSizeFromPath(const AuString &path) + AUKN_SYM AuUInt32 GetPerformanceBufferSizeFromPath(const AuROString &path) { try { @@ -747,7 +759,7 @@ namespace Aurora::IO::FS } } - AUKN_SYM LogicalUsedResponse GetLogicalUsedFromPath(const AuString &path) + AUKN_SYM LogicalUsedResponse GetLogicalUsedFromPath(const AuROString &path) { struct statvfs data; @@ -1583,7 +1595,7 @@ namespace Aurora::IO::FS return devices; } - AUKN_SYM AuString GetRootFromPath(const AuString &path) + AUKN_SYM AuString GetRootFromPath(const AuROString &path) { AuString ret; diff --git a/Source/IO/FS/FSPlatformDevices.NT.cpp b/Source/IO/FS/FSPlatformDevices.NT.cpp index a1e42d28..9d07fd19 100644 --- a/Source/IO/FS/FSPlatformDevices.NT.cpp +++ b/Source/IO/FS/FSPlatformDevices.NT.cpp @@ -36,7 +36,7 @@ namespace Aurora::IO::FS static AuString PathToMount(const AuString &root); - AUKN_SYM AuString GetRootFromPath(const AuString &path) + AUKN_SYM AuString GetRootFromPath(const AuROString &path) { auto widePath = Locale::ConvertFromUTF8(NormalizePathRet(path)); #if defined(AURORA_PLATFORM_WIN32) @@ -61,12 +61,12 @@ namespace Aurora::IO::FS #endif } - AUKN_SYM AuResult GetDeviceFromPath(const AuString &path) + AUKN_SYM AuResult GetDeviceFromPath(const AuROString &path) { return GetDeviceFromRoot(GetRootFromPath(path)); } - AUKN_SYM AuResult GetLogicalMountFromPath(const AuString &fileOrDirPath) + AUKN_SYM AuResult GetLogicalMountFromPath(const AuROString &fileOrDirPath) { auto root = GetRootFromPath(fileOrDirPath); @@ -91,7 +91,7 @@ namespace Aurora::IO::FS return AuString(utf8Root); } - AUKN_SYM AuResult GetDeviceFromRoot(const AuString& root) + AUKN_SYM AuResult GetDeviceFromRoot(const AuROString &root) { VOLUME_DISK_EXTENTS extents; DWORD dwBytesWritten {}; @@ -104,6 +104,11 @@ namespace Aurora::IO::FS } auto widePath = Locale::ConvertFromUTF8(utf8Root); + if (widePath.empty() && utf8Root.size()) + { + SysPushErrorMemory(); + return {}; + } if (::GetDriveTypeW(Locale::ConvertFromUTF8(utf8Root2).data()) != DRIVE_FIXED) { @@ -161,7 +166,7 @@ namespace Aurora::IO::FS } } - static AuUInt32 GetSectorSizeFromPathFromDevice(const AuString &path, bool bIsLogical) + static AuUInt32 GetSectorSizeFromPathFromDevice(const AuROString &path, bool bIsLogical) { DISK_GEOMETRY_EX geo {}; DWORD cbBytesReturned; @@ -256,7 +261,7 @@ namespace Aurora::IO::FS } } - AUKN_SYM AuUInt32 GetPerformanceBufferSizeFromPath(const AuString &path) + AUKN_SYM AuUInt32 GetPerformanceBufferSizeFromPath(const AuROString &path) { if (kBUsePerformantIoRecommendation) { @@ -289,12 +294,12 @@ namespace Aurora::IO::FS } } - AUKN_SYM AuUInt32 GetPhysicalSectorSizeFromPath(const AuString &path) + AUKN_SYM AuUInt32 GetPhysicalSectorSizeFromPath(const AuROString &path) { return GetSectorSizeFromPathFromDevice(path, false); } - AUKN_SYM LogicalUsedResponse GetLogicalUsedFromPath(const AuString &path) + AUKN_SYM LogicalUsedResponse GetLogicalUsedFromPath(const AuROString &path) { auto rootPath = GetLogicalMountFromPath(path); if (!rootPath) @@ -305,7 +310,7 @@ namespace Aurora::IO::FS return GetLogicalUsedFromLogicalDevice(rootPath.GetResult()); } - AUKN_SYM LogicalUsedResponse GetLogicalUsedFromLogicalDevice(const AuString &logicalMountPath) + AUKN_SYM LogicalUsedResponse GetLogicalUsedFromLogicalDevice(const AuROString &logicalMountPath) { auto widePath = Locale::ConvertFromUTF8(logicalMountPath); @@ -1035,12 +1040,12 @@ namespace Aurora::IO::FS } #endif - AUKN_SYM AuString TrySimplifyDevicePath(const AuString &deviceOrLogicalMountPath) + AUKN_SYM AuString TrySimplifyDevicePath(const AuROString &deviceOrLogicalMountPath) { #if defined(AURORA_PLATFORM_WIN32) - return ResolveObjSymLink(deviceOrLogicalMountPath); + return ResolveObjSymLink(AuString(deviceOrLogicalMountPath)); #else - return deviceOrLogicalMountPath; + return AuString(deviceOrLogicalMountPath); #endif } diff --git a/Source/IO/FS/FSPlatformDevices.cpp b/Source/IO/FS/FSPlatformDevices.cpp index b9ca6fe6..cd597892 100644 --- a/Source/IO/FS/FSPlatformDevices.cpp +++ b/Source/IO/FS/FSPlatformDevices.cpp @@ -22,7 +22,7 @@ namespace Aurora::IO::FS }); } - AUKN_SYM AuResult GetDeviceModel(const AuString &physicalDevicePath) + AUKN_SYM AuResult GetDeviceModel(const AuROString &physicalDevicePath) { InitPlatformFSCacheAtLoad(); @@ -39,7 +39,7 @@ namespace Aurora::IO::FS return {}; } - AUKN_SYM AuResult GetFSDeviceByFilePath(const AuString &path) + AUKN_SYM AuResult GetFSDeviceByFilePath(const AuROString &path) { AuPair lastDev = AuMakePair(0, nullptr); @@ -87,7 +87,7 @@ namespace Aurora::IO::FS return gCachedDevices; } - AUKN_SYM AuResult GetFSDeviceByDevice(const AuString &physicalDevicePath) + AUKN_SYM AuResult GetFSDeviceByDevice(const AuROString &physicalDevicePath) { InitPlatformFSCacheAtLoad(); diff --git a/Source/IO/FS/Resources.cpp b/Source/IO/FS/Resources.cpp index 280c47c6..b7c7bdee 100644 --- a/Source/IO/FS/Resources.cpp +++ b/Source/IO/FS/Resources.cpp @@ -32,6 +32,12 @@ namespace Aurora::IO::FS static AuString gAdminWritableAppDirectory; static AuString gProgramsFolder; static AuString gApplicationData; + static AuString gUserShellDocuments; + static AuString gUserShellDownloads; + static AuString gUserShellPhotos; + static AuString gUserShellVideos; + static AuString gUserShellMusic; + static AuString gUserShellDesktop; static AuOptional gSystemLibPath; static AuOptional gSystemLibPath2; static AuOptional gUserLibPath; @@ -48,21 +54,21 @@ namespace Aurora::IO::FS // we don't have any good examples of home family computer-esc posix machines static const char * kUnixAppData {"/var"}; - AUKN_SYM AuOptional GetSystemDomain() + AUKN_SYM AuOptional GetSystemDomain() { return gApplicationData.size() ? gApplicationData : - AuOptional {}; + AuOptional {}; } - AUKN_SYM AuOptional GetProfileDomain() + AUKN_SYM AuOptional GetProfileDomain() { return gHomeDirectory.size() ? gHomeDirectory : - AuOptional {}; + AuOptional {}; } - AUKN_SYM bool GetSystemResourcePath(const AuString &fileName, AuString &path) + AUKN_SYM bool GetSystemResourcePath(const AuROString &fileName, AuString &path) { path.clear(); @@ -72,44 +78,52 @@ namespace Aurora::IO::FS return false; } - #if defined(AU_CFG_ID_INTERNAL) || defined(AU_CFG_ID_DEBUG) + try { - AuString tempPath; - if (Process::GetWorkingDirectory(tempPath)) + #if defined(AU_CFG_ID_INTERNAL) || defined(AU_CFG_ID_DEBUG) { - tempPath += "/" + fileName; - if (FileExists(tempPath)) + AuString tempPath; + if (Process::GetWorkingDirectory(tempPath)) { - path = tempPath; - return true; + tempPath += "/" + fileName; + if (FileExists(tempPath)) + { + path = tempPath; + return true; + } } } - } - #endif + #endif - { - if (auto pProcPath = Process::GetProcessDirectory()) { - auto tempPath = *pProcPath + "/" + fileName; - if (FileExists(tempPath)) - { - path = tempPath; - return true; - } - } - } - - { - if (auto optPackagePath = GetPackagePath()) - { - auto tempPath = *optPackagePath + "/" + fileName; - if (auto pProcPath = Process::GetProcessDirectory()) { - auto tempPath2 = *pProcPath + "/" + fileName; - if (tempPath2 == tempPath) + auto tempPath = AuString(*pProcPath) + "/" + AuString(fileName); + if (FileExists(tempPath)) { - // nop + path = tempPath; + return true; + } + } + } + + { + if (auto optPackagePath = GetPackagePath()) + { + auto tempPath = AuString(*optPackagePath) + "/" + AuString(fileName); + + if (auto pProcPath = Process::GetProcessDirectory()) + { + auto tempPath2 = AuString(*pProcPath) + "/" + AuString(fileName); + if (tempPath2 == tempPath) + { + // nop + } + else if (FileExists(tempPath)) + { + path = tempPath; + return true; + } } else if (FileExists(tempPath)) { @@ -117,45 +131,44 @@ namespace Aurora::IO::FS return true; } } - else if (FileExists(tempPath)) - { - path = tempPath; - return true; - } } - } - #if defined(AU_CFG_ID_SHIP) - { - AuString tempPath; - if (Process::GetWorkingDirectory(tempPath)) + #if defined(AU_CFG_ID_SHIP) { - tempPath += "/" + fileName; - if (FileExists(tempPath)) + AuString tempPath; + if (Process::GetWorkingDirectory(tempPath)) { - path = tempPath; + tempPath += "/" + fileName; + if (FileExists(tempPath)) + { + path = tempPath; + return true; + } + } + } + #endif + + { + auto systemPath = gHomeDirectory + AuString(fileName); + if (FileExists(systemPath)) + { + path = systemPath; + return true; + } + } + + { + auto systemPath = gApplicationData + AuString(fileName); + if (FileExists(systemPath)) + { + path = systemPath; return true; } } } - #endif - + catch (...) { - auto systemPath = gHomeDirectory + fileName; - if (FileExists(systemPath)) - { - path = systemPath; - return true; - } - } - - { - auto systemPath = gApplicationData + fileName; - if (FileExists(systemPath)) - { - path = systemPath; - return true; - } + SysPushErrorCatch(); } return false; @@ -175,9 +188,30 @@ namespace Aurora::IO::FS return CSIDL_COMMON_APPDATA; } - if (rfid == FOLDERID_Documents) + if (rfid == FOLDERID_Documents || + rfid == FOLDERID_Downloads) { - return CSIDL_COMMON_DOCUMENTS; + return CSIDL_MYDOCUMENTS; + } + + if (rfid == FOLDERID_Music) + { + return CSIDL_MYMUSIC; + } + + if (rfid == FOLDERID_Pictures) + { + return CSIDL_MYPICTURES; + } + + if (rfid == FOLDERID_Desktop) + { + return CSIDL_DESKTOP; + } + + if (rfid == FOLDERID_Videos) + { + return CSIDL_MYVIDEO; } if (rfid == FOLDERID_System || @@ -194,7 +228,6 @@ namespace Aurora::IO::FS return {}; } - static AuString GetSpecialDirOldOS(REFKNOWNFOLDERID rfid) { if (!pSHGetFolderPathA) @@ -214,7 +247,7 @@ namespace Aurora::IO::FS return ""; } - static AuString GetSpecialDir(REFKNOWNFOLDERID rfid) + static AuString GetSpecialDir(REFKNOWNFOLDERID rfid, bool bNoThrow = false) { PWSTR directory; @@ -231,10 +264,11 @@ namespace Aurora::IO::FS return str; } - if (rfid == FOLDERID_UserProgramFiles) + if (rfid == FOLDERID_UserProgramFiles || bNoThrow) { return ""; } + 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]); } @@ -250,17 +284,17 @@ namespace Aurora::IO::FS static void SetNamespaceDirectories() { - gHomeDirectory = GetSpecialDir(FOLDERID_RoamingAppData); - gApplicationData = GetSpecialDir(FOLDERID_ProgramData); + gHomeDirectory = GetSpecialDir(FOLDERID_RoamingAppData); + gApplicationData = GetSpecialDir(FOLDERID_ProgramData); if constexpr (AuBuild::IsPlatformX32()) { - gSystemLibPath = GetSpecialDir(FOLDERID_SystemX86); + gSystemLibPath = GetSpecialDir(FOLDERID_SystemX86); } else { - gSystemLibPath = GetSpecialDir(FOLDERID_System); + gSystemLibPath = GetSpecialDir(FOLDERID_System); } - gUserHomeDirectory = GetSpecialDir(FOLDERID_Profile); + gUserHomeDirectory = GetSpecialDir(FOLDERID_Profile); gAdminWritableAppDirectory = gApplicationData; gUserWritableAppData = gHomeDirectory; gProgramsFolder = AuSwInfo::IsWindows7OrGreater() ? GetSpecialDir(FOLDERID_UserProgramFiles) : ""; @@ -278,6 +312,13 @@ namespace Aurora::IO::FS } } + gUserShellDocuments = GetSpecialDir(FOLDERID_Documents, true); + gUserShellDownloads = GetSpecialDir(FOLDERID_Downloads, true); + gUserShellPhotos = GetSpecialDir(FOLDERID_Pictures, true); + gUserShellVideos = GetSpecialDir(FOLDERID_Videos, true); + gUserShellMusic = GetSpecialDir(FOLDERID_Music, true); + gUserShellDesktop = GetSpecialDir(FOLDERID_Desktop, true); + if (pGetTempPathW) { wchar_t tempPath[2048]; @@ -341,6 +382,20 @@ namespace Aurora::IO::FS } } + static void SetPosixOptionalUserShellDir(AuString &str, const AuROString &suffix) + { + AuString strA = gUserHomeDirectory + "/" + AuString({ AuToUpper(suffix[0]) }) + AuString(suffix.SubStr(1)); + AuString strB = gUserHomeDirectory + "/" + AuString({ AuToLower(suffix[0]) }) + AuString(suffix.SubStr(1)); + if (AuFS::DirExists(strA)) + { + str = strA; + } + else if (AuFS::DirExists(strB)) + { + str = strB; + } + } + static void SetNamespaceDirectories() { const char *homedir; @@ -371,6 +426,17 @@ namespace Aurora::IO::FS gAdminWritableAppDirectory = kUnixAppData; gUserWritableAppData = gApplicationData; + SetPosixOptionalUserShellDir(gUserShellDocuments, "Documents"); + SetPosixOptionalUserShellDir(gUserShellDownloads, "Downloads"); + SetPosixOptionalUserShellDir(gUserShellPhotos, "Pictures"); + SetPosixOptionalUserShellDir(gUserShellVideos, "Videos"); + SetPosixOptionalUserShellDir(gUserShellMusic, "Music"); + SetPosixOptionalUserShellDir(gUserShellDesktop, "Desktop"); + + // Android: gApplicationData = ANativeActivity::internalDataPath + // Android: gHomeDirectory = ANativeActivity::externalDataPath (?) + // Android: SetPosixOptionalUserShellDir maybe overload the home path with emulated 0 DCIM if we have external file permissions? externalDataPath? + // iOS Package Dir: CFBundleCopyResourcesDirectoryURL // iOS/MacOS : NSTemporaryDirectory #if defined(AURORA_PLATFORM_ANDROID) gTempDir = "/data/local/tmp/"; @@ -504,21 +570,21 @@ namespace Aurora::IO::FS gApplicationData.clear(); } - AUKN_SYM AuOptional GetAppData() + AUKN_SYM AuOptional GetAppData() { return gUserWritableAppData.size() ? gUserWritableAppData : - AuOptional {}; + AuOptional {}; } - AUKN_SYM AuOptional GetUserHome() + AUKN_SYM AuOptional GetUserHome() { return gUserHomeDirectory.size() ? gUserHomeDirectory : - AuOptional {}; + AuOptional {}; } - AUKN_SYM AuOptional GetPackagePath() + AUKN_SYM AuOptional GetPackagePath() { // TODO: iOS/mac OS -> CFBundleCopyResourcesDirectoryURL if (auto optProcessDirectory = Process::GetProcessDirectory()) @@ -526,86 +592,156 @@ namespace Aurora::IO::FS return optProcessDirectory; } - return AuOptional{}; + return AuOptional{}; } - AUKN_SYM AuOptional GetWritableAppdata() + AUKN_SYM AuOptional GetWritableAppdata() { return gGlobalWritableAppDirectory.size() ? gGlobalWritableAppDirectory : - AuOptional {}; + AuOptional {}; } - AUKN_SYM AuOptional GetRootAppdata() + AUKN_SYM AuOptional GetRootAppdata() { return gAdminWritableAppDirectory.size() ? gAdminWritableAppDirectory : - AuOptional {}; + AuOptional {}; } - AUKN_SYM AuOptional GetUserProgramsFolder() + AUKN_SYM AuOptional GetUserProgramsFolder() { return gProgramsFolder.size() ? gProgramsFolder : - AuOptional {}; + AuOptional {}; + } + + AUKN_SYM AuOptional GetUserDocuments() + { + return gUserShellDocuments.size() ? + gUserShellDocuments : + AuOptional {}; + } + + AUKN_SYM AuOptional GetUserDesktop() + { + return gUserShellDesktop.size() ? + gUserShellDesktop : + AuOptional {}; + } + + AUKN_SYM AuOptional GetUserPhotos() + { + return gUserShellPhotos.size() ? + gUserShellPhotos : + AuOptional {}; + } + + AUKN_SYM AuOptional GetUserVideos() + { + return gUserShellVideos.size() ? + gUserShellVideos : + AuOptional {}; + } + + AUKN_SYM AuOptional GetUserMusic() + { + return gUserShellMusic.size() ? + gUserShellMusic : + AuOptional {}; + } + + AUKN_SYM AuOptional GetUserDownloads() + { + return gUserShellDownloads.size() ? + gUserShellDownloads : + GetUserDocuments(); } AUKN_SYM AuOptional NewTempFile() { - AuString path; - - path = gTempDir; - if (path.empty()) + try { - SysPushErrorUninitialized(); + AuString path; + + path = gTempDir; + if (path.empty()) + { + SysPushErrorUninitialized(); + return {}; + } + + path += fmt::format("TempFile_{}", AuRNG::ReadString(64, AuRNG::ERngStringCharacters::eAlphaNumericCharacters)); + + if (!AuFS::WriteNewFile(path, {})) + { + SysPushErrorIO(); + return {}; + } + + auto normalizedPath = AuFS::NormalizePathRet(path); + if (normalizedPath.empty() && path.size()) + { + SysPushErrorMemory(); + return {}; + } + + #if defined(AURORA_PLATFORM_WIN32) + auto widePath = AuLocale::ConvertFromUTF8(normalizedPath); + MoveFileExW(widePath.c_str(), nullptr, MOVEFILE_DELAY_UNTIL_REBOOT); + #endif + + return normalizedPath; + } + catch (...) + { + // I hate C++ strings + SysPushErrorCatch(); return {}; } - - path += fmt::format("TempFile_{}", AuRNG::ReadString(64, AuRNG::ERngStringCharacters::eAlphaNumericCharacters)); - - if (!AuFS::WriteNewFile(path, {})) - { - SysPushErrorIO(); - return {}; - } - - auto normalizedPath = AuFS::NormalizePathRet(path); - - #if defined(AURORA_PLATFORM_WIN32) - auto widePath = AuLocale::ConvertFromUTF8(normalizedPath); - MoveFileExW(widePath.c_str(), nullptr, MOVEFILE_DELAY_UNTIL_REBOOT); - #endif - - return normalizedPath; } AUKN_SYM AuOptional NewTempDirectory() { - AuString path; - - path = gTempDir; - if (path.empty()) + try { - SysPushErrorUninitialized(); + AuString path; + + path = gTempDir; + if (path.empty()) + { + SysPushErrorUninitialized(); + return {}; + } + + path += fmt::format("TempDirectory_{}", AuRNG::ReadString(32, AuRNG::ERngStringCharacters::eAlphaNumericCharacters)); + + if (!_MkDir(path)) + { + SysPushErrorIO(); + return {}; + } + + auto normalizedPath = AuFS::NormalizePathRet(path); + if (normalizedPath.empty() && path.size()) + { + SysPushErrorMemory(); + return {}; + } + + #if defined(AURORA_PLATFORM_WIN32) + auto widePath = AuLocale::ConvertFromUTF8(normalizedPath); + MoveFileExW(widePath.c_str(), nullptr, MOVEFILE_DELAY_UNTIL_REBOOT); + #endif + + return normalizedPath + AuString(1, kPathSplitter); + } + catch (...) + { + // I hate C++ strings + SysPushErrorCatch(); return {}; } - - path += fmt::format("TempDirectory_{}", AuRNG::ReadString(32, AuRNG::ERngStringCharacters::eAlphaNumericCharacters)); - - if (!_MkDir(path)) - { - SysPushErrorIO(); - return {}; - } - - auto normalizedPath = AuFS::NormalizePathRet(path); - - #if defined(AURORA_PLATFORM_WIN32) - auto widePath = AuLocale::ConvertFromUTF8(normalizedPath); - MoveFileExW(widePath.c_str(), nullptr, MOVEFILE_DELAY_UNTIL_REBOOT); - #endif - - return normalizedPath + AuString(1, kPathSplitter); } #if defined(AURORA_PLATFORM_WIN32) diff --git a/Source/Process/AuPaths.cpp b/Source/Process/AuPaths.cpp index a362c955..9c4ab539 100644 --- a/Source/Process/AuPaths.cpp +++ b/Source/Process/AuPaths.cpp @@ -259,7 +259,7 @@ namespace Aurora::Process return true; } - AUKN_SYM AuOptional GetProcessName() + AUKN_SYM AuOptional GetProcessName() { const AuString *pModule, *pPartial, *pFull; @@ -280,7 +280,7 @@ namespace Aurora::Process return {}; } - AUKN_SYM AuOptional GetProcessDirectory() + AUKN_SYM AuOptional GetProcessDirectory() { const AuString *pModule, *pPartial, *pFull; @@ -316,7 +316,7 @@ namespace Aurora::Process return {}; } - AUKN_SYM AuOptional GetProcessFullPath() + AUKN_SYM AuOptional GetProcessFullPath() { const AuString *pModule, *pPartial, *pFull; diff --git a/Source/Process/AuProcess.cpp b/Source/Process/AuProcess.cpp index 135738ee..e71251cf 100644 --- a/Source/Process/AuProcess.cpp +++ b/Source/Process/AuProcess.cpp @@ -39,6 +39,10 @@ namespace Aurora::Process { + // Because we're only protecting gModuleHandles in practice, and we cannot fuck up any iterator handles, we can use renterable mutexes. + // We only use AuTryFind/AuTryInsert for the most part. + // The only iterators created for gModuleHandles call out to apis that should not allow for further recursion. + // So we should be fine. static AuCriticalSection gSpinLock; static AuList gClassPath; static AuHashMap gModuleHandles; @@ -102,18 +106,18 @@ namespace Aurora::Process static AuString ConstructAuDllSuffixUncached() { - auto platform = GetPlatformString(Build::kCurrentPlatform); + auto platform = GetPlatformString(Build::kCurrentPlatform); auto architecture = GetArchString(Build::kCurrentArchitecture); - auto ext = GetPlatformExt(Build::kCurrentPlatform); + auto ext = GetPlatformExt(Build::kCurrentPlatform); AuString ret; #if defined(DEBUG) - ret += ".Debug"; + ret = ".Debug"; #elif defined(STAGING) - ret += ".Stage"; + ret = ".Stage"; #elif defined(SHIP) - ret += ".Ship"; + ret = ".Ship"; #endif if (platform) @@ -134,28 +138,47 @@ namespace Aurora::Process return ret; } - AUKN_SYM const AuString& ConstructAuDllSuffix() + AUKN_SYM AuROString GetViewOfAuroraDLLSuffix() { static AuString dllSuffixString {}; static AuInitOnce gInitOnce; - gInitOnce.Call([] + gInitOnce.TryCall([] { - dllSuffixString = ConstructAuDllSuffixUncached(); + try + { + dllSuffixString = ConstructAuDllSuffixUncached(); + return true; + } + catch (...) + { + // I hate C++ strings so much + return false; + } }); return dllSuffixString; } + AUKN_SYM AuROString GetViewOfDynamicLibraryExtensionSuffix() + { + return GetPlatformExt(Build::kCurrentPlatform); + } + + AUKN_SYM AuROString GetViewOfArchitectureSuffix() + { + return GetArchString(Build::kCurrentArchitecture); + } + static AuString GetModuleNameFromFileName(const AuString &filename) { - static const auto &kStringSuffixA = ConstructAuDllSuffix(); + static const auto kStringSuffixA = GetViewOfAuroraDLLSuffix(); static const auto kStringSuffixB = GetPlatformExt(Build::kCurrentPlatform); - if (filename.ends_with(kStringSuffixA)) + if (AuEndsWith(filename, kStringSuffixA)) { return filename.substr(0, filename.size() - kStringSuffixA.size()); } - if (filename.ends_with(kStringSuffixB)) + if (AuEndsWith(filename, kStringSuffixB)) { return filename.substr(0, filename.size() - strlen(kStringSuffixB)); } @@ -292,12 +315,13 @@ namespace Aurora::Process } #endif - static void *LoadModule(const AuString &name, const AuString &path) + static void *LoadModule(const AuROString &name, const AuROString &path) { - auto itr = gModuleHandles.find(path); - if (itr != gModuleHandles.end()) + void *pFound {}; + + if (AuTryFind(gModuleHandles, path, pFound)) { - return itr->second; + return pFound; } #if defined(AURORA_IS_MODERNNT_DERIVED) @@ -322,8 +346,8 @@ namespace Aurora::Process #endif auto pRet = (void *)handle; - gModuleHandles.insert(AuMakePair(name, pRet)); - gModuleHandles.insert(AuMakePair(path, pRet)); + gModuleHandles.insert(AuMakePair(AuMove(AuString(name)), AuConstReference(pRet))); + gModuleHandles.insert(AuMakePair(AuMove(AuString(path)), AuConstReference(pRet))); return pRet; } @@ -338,9 +362,20 @@ namespace Aurora::Process fail = false; auto pathNrml = AuIOFS::NormalizePathRet(path); + if (pathNrml.empty() && path.size()) + { + SysPushErrorMemory(); + return nullptr; + } #if defined(AURORA_IS_MODERNNT_DERIVED) auto widePath = Locale::ConvertFromUTF8(pathNrml); + if (widePath.empty() && pathNrml.size()) + { + SysPushErrorMemory(); + return nullptr; + } + auto mitigateTimeOfUse = Win32Open(widePath.c_str(), GENERIC_READ, FILE_SHARE_READ, false, OPEN_EXISTING, 0, 0); if (mitigateTimeOfUse == INVALID_HANDLE_VALUE) @@ -351,6 +386,11 @@ namespace Aurora::Process } auto absPath = AuIOFS::NormalizePathRet(abs); + if (absPath.empty() && abs.size()) + { + SysPushErrorMemory(); + return nullptr; + } #endif if (request.verify || ((kIsMainSigned || request.forceMitigations) && request.enableMitigations)) @@ -404,10 +444,10 @@ namespace Aurora::Process return returnValue; } - static void *TryLoadModule(const AuString &path, const AuString &auDll, const AuString &genericDll, const ModuleLoadRequest &request, bool &fail) + static void *TryLoadModuleNTC(const AuString &path, const AuString &auDll, const AuString &genericDll, const ModuleLoadRequest &request, bool &fail) { - AuString a = path + AuString({ AuFS::kPathSplitter }) + auDll; - AuString b = path + AuString({ AuFS::kPathSplitter }) + genericDll; + AuString a = AuString(path) + AuString({ AuFS::kPathSplitter }) + AuString(auDll); + AuString b = AuString(path) + AuString({ AuFS::kPathSplitter }) + AuString(genericDll); #if defined(AURORA_IS_MODERNNT_DERIVED) #if defined(AURORA_PLATFORM_WIN32) @@ -430,8 +470,8 @@ namespace Aurora::Process } #endif - AuString aAbs = path + AuString({ AuFS::kPathSplitter }) + auDll + "."; - AuString bAbs = path + AuString({ AuFS::kPathSplitter }) + genericDll + "."; + AuString aAbs = AuString(path) + /*SOO save us pls*/ AuString({ AuFS::kPathSplitter }) + auDll + "."; + AuString bAbs = AuString(path) + /*SOO save us pls*/ AuString({ AuFS::kPathSplitter }) + genericDll + "."; #endif if (AuIOFS::FileExists(a)) @@ -459,17 +499,29 @@ namespace Aurora::Process return {}; } + static void *TryLoadModule(const AuString &path, const AuString &auDll, const AuString &genericDll, const ModuleLoadRequest &request, bool &fail) + { + // TODO: need safe string container + try + { + return TryLoadModuleNTC(path, auDll, genericDll, request, fail); + } + catch (...) + { + return {}; + } + } + static void *TryLoadModule(EModulePath path, const AuString &auDll, const AuString &genericDll, const ModuleLoadRequest &request) { AuString pathA, pathB; - AuList arrayPaths; + AuList *pArrayPaths {}; switch (path) { case EModulePath::eClassPath: { - AU_LOCK_GLOBAL_GUARD(gSpinLock); - arrayPaths = gClassPath; + pArrayPaths = &gClassPath; break; } case EModulePath::eModulePathCWD: @@ -553,16 +605,21 @@ namespace Aurora::Process } } - for (const auto &dir : arrayPaths) + if (pArrayPaths) { - if (auto pRet = TryLoadModule(dir, auDll, genericDll, request, fail)) - { - return pRet; - } + AU_LOCK_GLOBAL_GUARD(gSpinLock); - if (fail) + for (const auto &dir : *pArrayPaths) { - return {}; + if (auto pRet = TryLoadModule(dir, auDll, genericDll, request, fail)) + { + return pRet; + } + + if (fail) + { + return {}; + } } } @@ -593,33 +650,46 @@ namespace Aurora::Process AUKN_SYM void *LoadModuleEx(const ModuleLoadRequest &request) { AU_LOCK_GLOBAL_GUARD(gSpinLock); - - auto h = gModuleHandles.find(request.mod); - if (h != gModuleHandles.end()) + + void *pFound {}; + + if (AuTryFind(gModuleHandles, request.mod, pFound)) { - return h->second; + return pFound; } - auto au = request.mod + ConstructAuDllSuffix(); - auto base = request.mod; - auto ext = GetPlatformExt(Build::kCurrentPlatform); - - if (ext && !Build::kIsNtDerived) + // TODO: need safe string container + AuString base, au; + const char *ext {}; + try { - base += ext; + base = AuString(request.mod); + au = base + AuString(GetViewOfAuroraDLLSuffix()); + ext = GetPlatformExt(Build::kCurrentPlatform); + + if (ext && !Build::kIsNtDerived) + { + base += ext; + } + + if (request.version.size()) + { + au += "." + request.version; + base += "." + request.version; + } + + if (ext && Build::kIsNtDerived) + { + base += ext; + } + } + catch (...) + { + // stupid unsafe strings + SysPushErrorMemory(); + return {}; } - if (request.version.size()) - { - au += "." + request.version; - base += "." + request.version; - } - - if (ext && Build::kIsNtDerived) - { - base += ext; - } - auto searchPath = request.searchPath ? request.searchPath : &kUserOverloadableSearchPath; for (EModulePath path : *searchPath) { @@ -632,7 +702,7 @@ namespace Aurora::Process return {}; } - AUKN_SYM AuMach GetProcAddressEx(void *pHandle, const AuString &symbol) + AUKN_SYM AuMach GetProcAddressEx(void *pHandle, const AuRONString &symbol) { AuMach ret {}; @@ -706,21 +776,22 @@ namespace Aurora::Process return ret; } - AUKN_SYM void *GetProcHandle(const AuString &name) + AUKN_SYM void *GetProcHandle(const AuROString &name) { AU_LOCK_GLOBAL_GUARD(gSpinLock); - auto h = gModuleHandles.find(name); - if (h == gModuleHandles.end()) + void *pFound {}; + + if (!AuTryFind(gModuleHandles, name, pFound)) { SysPushErrorGen("Module {} is not loaded", name); return {}; } - return h->second; + return pFound; } - AUKN_SYM AuMach GetProcAddress(const AuString &mod, const AuString &symbol) + AUKN_SYM AuMach GetProcAddress(const AuROString &mod, const AuRONString &symbol) { if (mod.empty()) { @@ -771,10 +842,14 @@ namespace Aurora::Process AuList cookieList; #if defined(AURORA_PLATFORM_WIN32) - for (const auto dir : dirs) + for (const auto &dir : dirs) { void *pCookie {}; + // Yay I love required nevis era plugin load fighting + // MSDN still states this function should be dynamically loaded for some KB that probably wont work on Vista or 7. + // Also, GNU LibC - the architectures ld linker, cannot keep track of preload directory lists. + // So for older Win32 targets, and POSIX, we have to.... if (pRemoveDllDirectory) { if (pAddDllDirectory) @@ -787,7 +862,10 @@ namespace Aurora::Process } #endif - for (const auto dir : dirs) + // ...just try to probe every file manually. + // ...and later on, try to load each file again manually by full real path + // This makes sure we have future basic dependencies loaded of LoadModuleXXX calls, at the very least, we hope. + for (const auto &dir : dirs) { AuList files; AuList sharedObjects; @@ -798,13 +876,13 @@ namespace Aurora::Process continue; } - auto endingPattern = ConstructAuDllSuffix(); + auto endingPattern = GetViewOfAuroraDLLSuffix(); auto endingAlt = GetPlatformExt(Build::kCurrentPlatform); for (const auto &file : files) { - if (!(file.ends_with(endingPattern.c_str()) || - file.ends_with(endingAlt))) + if (!(AuEndsWith(file, endingPattern) || + AuEndsWith(file, endingAlt))) { continue; } @@ -840,7 +918,10 @@ namespace Aurora::Process } auto modName = GetModuleNameFromFileName(sharedDLL); - AuLogDbg("[attempt] Loading shared object: {} (path: {})", modName, sharedDLL); + //AuLogDbg("[attempt] Loading shared object: {} (path: {})", modName, sharedDLL); + //This got really spammy some time + //Best just keep dynamic loads as a singular verbose, "hey dipshit, this file actually managed to get into our address space" + //... bool fail {}; ModuleLoadRequest request { AuList{ dir }, modName }; @@ -855,7 +936,8 @@ namespace Aurora::Process { if (!fail) { - AuLogDbg("[attempt] Loaded shared object: {} (path: {})", modName, sharedDLL); + //..here + AuLogDbg("[attempt] Loaded shared object: {} (path: {})", modName, sharedDLL); //get hacked retard uSuccess++; itr = sharedObjects.erase(itr); } @@ -888,7 +970,7 @@ namespace Aurora::Process #endif } - static void PreloadDLLs(const AuString &dir) + static void PreloadDLLs(const AuROString &dir) { AU_DEBUG_MEMCRUNCH; if (gRuntimeConfig.processConfig.bAlwaysPreloadEntireClassPath) @@ -897,17 +979,17 @@ namespace Aurora::Process } else { - PreloadDLLsDoOnce({ dir }); + PreloadDLLsDoOnce({ AuString(dir) }); } } - AUKN_SYM bool SetBinaryClassPath(const AuList &list, bool preloadAll) + AUKN_SYM bool SetBinaryClassPath(const AuList &list, AuOptional optBoolPreloadAll) { AU_DEBUG_MEMCRUNCH; AU_LOCK_GLOBAL_GUARD(gSpinLock); AuExchange(gClassPath, list); - if (((preloadAll && gRuntimeConfig.processConfig.bEnablePreload)) || + if (((optBoolPreloadAll.ValueOr(false) && gRuntimeConfig.processConfig.bEnablePreload)) || (gRuntimeConfig.processConfig.bForcePreload)) { if (gRuntimeConfig.processConfig.bAlwaysPreloadEntireClassPath) @@ -923,16 +1005,16 @@ namespace Aurora::Process return true; } - AUKN_SYM bool AddBinaryClassPath(const AuString &dir, bool preloadAll) + AUKN_SYM bool AddBinaryClassPath(const AuROString &dir, AuOptional optBoolPreloadAll) { AU_LOCK_GLOBAL_GUARD(gSpinLock); - if (!AuTryInsert(gClassPath, dir)) + if (!AuTryInsert(gClassPath, AuString(dir))) { return false; } - if (((preloadAll && gRuntimeConfig.processConfig.bEnablePreload)) || + if (((optBoolPreloadAll.ValueOr(false) && gRuntimeConfig.processConfig.bEnablePreload)) || (gRuntimeConfig.processConfig.bForcePreload)) { PreloadDLLs(dir); @@ -943,8 +1025,16 @@ namespace Aurora::Process AUKN_SYM AuList GetBinaryClassPath() { - AU_LOCK_GLOBAL_GUARD(gSpinLock); - return gClassPath; + try + { + AU_LOCK_GLOBAL_GUARD(gSpinLock); + return gClassPath; + } + catch (...) + { + SysPushErrorMemory(); + return {}; + } } void InitProcess()