From dbf824972decbbbd31ba623db3ef9fc2347ea717 Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 7 Feb 2025 18:31:22 +0100 Subject: [PATCH 1/7] Bump version to 0.2.8 --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 224fb7f..ae44993 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -10,7 +10,7 @@ WUMS_MODULE_EXPORT_NAME("homebrew_content_redirection"); WUMS_USE_WUT_DEVOPTAB(); WUMS_DEPENDS_ON(homebrew_functionpatcher); -#define VERSION "v0.2.7" +#define VERSION "v0.2.8" DECL_FUNCTION(void, OSCancelThread, OSThread *thread) { if (thread == gThreadData[0].thread || thread == gThreadData[1].thread || thread == gThreadData[2].thread) { From 888f534a09c82de673559c7348528b4b50ad04fa Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 7 Feb 2025 15:53:14 +0100 Subject: [PATCH 2/7] Clean up --- src/FSWrapper.cpp | 43 +++++++++++++----------- src/FSWrapper.h | 18 +++++----- src/FSWrapperMergeDirsWithParent.cpp | 37 +++++++++++--------- src/FSWrapperMergeDirsWithParent.h | 8 ++--- src/FileUtils.cpp | 50 +++++++++++++++------------- src/FileUtils.h | 4 +-- src/IFSWrapper.h | 14 +++++--- src/export.cpp | 13 ++++---- src/utils/StringTools.h | 4 +-- src/utils/utils.cpp | 2 +- src/utils/utils.h | 2 +- 11 files changed, 107 insertions(+), 88 deletions(-) diff --git a/src/FSWrapper.cpp b/src/FSWrapper.cpp index 5a151c1..49da6cc 100644 --- a/src/FSWrapper.cpp +++ b/src/FSWrapper.cpp @@ -3,12 +3,15 @@ #include "utils/StringTools.h" #include "utils/logger.h" #include "utils/utils.h" -#include + + #include #include -#include -#include + +#include #include + +#include #include #include #include @@ -139,7 +142,7 @@ FSError FSWrapper::FSReadDirWrapper(FSDirectoryHandle handle, FSDirectoryEntry * return result; } -FSError FSWrapper::FSCloseDirWrapper(FSDirectoryHandle handle) { +FSError FSWrapper::FSCloseDirWrapper(const FSDirectoryHandle handle) { if (!isValidDirHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } @@ -158,7 +161,7 @@ FSError FSWrapper::FSCloseDirWrapper(FSDirectoryHandle handle) { return result; } -FSError FSWrapper::FSRewindDirWrapper(FSDirectoryHandle handle) { +FSError FSWrapper::FSRewindDirWrapper(const FSDirectoryHandle handle) { if (!isValidDirHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } @@ -295,7 +298,7 @@ FSError FSWrapper::FSOpenFileWrapper(const char *path, const char *mode, FSFileH return result; } -FSError FSWrapper::FSCloseFileWrapper(FSFileHandle handle) { +FSError FSWrapper::FSCloseFileWrapper(const FSFileHandle handle) { if (!isValidFileHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } @@ -360,7 +363,7 @@ FSError FSWrapper::FSGetStatWrapper(const char *path, FSStat *stats) { return result; } -FSError FSWrapper::FSGetStatFileWrapper(FSFileHandle handle, FSStat *stats) { +FSError FSWrapper::FSGetStatFileWrapper(const FSFileHandle handle, FSStat *stats) { if (!isValidFileHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } @@ -382,7 +385,7 @@ FSError FSWrapper::FSGetStatFileWrapper(FSFileHandle handle, FSStat *stats) { return result; } -FSError FSWrapper::FSReadFileWrapper(void *buffer, uint32_t size, uint32_t count, FSFileHandle handle, [[maybe_unused]] uint32_t unk1) { +FSError FSWrapper::FSReadFileWrapper(void *buffer, const uint32_t size, const uint32_t count, const FSFileHandle handle, [[maybe_unused]] uint32_t unk1) { if (!isValidFileHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } @@ -417,7 +420,7 @@ FSError FSWrapper::FSReadFileWrapper(void *buffer, uint32_t size, uint32_t count return result; } -FSError FSWrapper::FSReadFileWithPosWrapper(void *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, int32_t unk1) { +FSError FSWrapper::FSReadFileWithPosWrapper(void *buffer, const uint32_t size, const uint32_t count, const uint32_t pos, const FSFileHandle handle, const int32_t unk1) { if (!isValidFileHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } @@ -432,7 +435,7 @@ FSError FSWrapper::FSReadFileWithPosWrapper(void *buffer, uint32_t size, uint32_ return result; } -FSError FSWrapper::FSSetPosFileWrapper(FSFileHandle handle, uint32_t pos) { +FSError FSWrapper::FSSetPosFileWrapper(const FSFileHandle handle, const uint32_t pos) { if (!isValidFileHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } @@ -457,7 +460,7 @@ FSError FSWrapper::FSSetPosFileWrapper(FSFileHandle handle, uint32_t pos) { return result; } -FSError FSWrapper::FSGetPosFileWrapper(FSFileHandle handle, uint32_t *pos) { +FSError FSWrapper::FSGetPosFileWrapper(const FSFileHandle handle, uint32_t *pos) { if (!isValidFileHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } @@ -478,7 +481,7 @@ FSError FSWrapper::FSGetPosFileWrapper(FSFileHandle handle, uint32_t *pos) { return result; } -FSError FSWrapper::FSIsEofWrapper(FSFileHandle handle) { +FSError FSWrapper::FSIsEofWrapper(const FSFileHandle handle) { if (!isValidFileHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } @@ -509,7 +512,7 @@ FSError FSWrapper::FSIsEofWrapper(FSFileHandle handle) { return result; } -FSError FSWrapper::FSTruncateFileWrapper(FSFileHandle handle) { +FSError FSWrapper::FSTruncateFileWrapper(const FSFileHandle handle) { if (!isValidFileHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } @@ -542,7 +545,7 @@ FSError FSWrapper::FSTruncateFileWrapper(FSFileHandle handle) { return result; } -FSError FSWrapper::FSWriteFileWrapper(const uint8_t *buffer, uint32_t size, uint32_t count, FSFileHandle handle, [[maybe_unused]] uint32_t unk1) { +FSError FSWrapper::FSWriteFileWrapper(const uint8_t *buffer, const uint32_t size, const uint32_t count, const FSFileHandle handle, [[maybe_unused]] uint32_t unk1) { if (!isValidFileHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } @@ -569,7 +572,7 @@ FSError FSWrapper::FSWriteFileWrapper(const uint8_t *buffer, uint32_t size, uint result = FS_ERROR_MEDIA_ERROR; } } else { - result = static_cast(((uint32_t) writeRes) / size); + result = static_cast(static_cast(writeRes) / size); } return result; @@ -717,8 +720,8 @@ std::shared_ptr FSWrapper::getNewDirHandle() { return make_shared_nothrow(); } -std::shared_ptr FSWrapper::getFileFromHandle(FSFileHandle handle) { - std::lock_guard lock(openFilesMutex); +std::shared_ptr FSWrapper::getFileFromHandle(const FSFileHandle handle) { + std::lock_guard lock(openFilesMutex); for (auto &file : openFiles) { if (file->handle == handle) { return file; @@ -730,7 +733,7 @@ std::shared_ptr FSWrapper::getFileFromHandle(FSFileHandle handle) { } std::shared_ptr FSWrapper::getDirFromHandle(FSDirectoryHandle handle) { - std::lock_guard lock(openDirsMutex); + std::lock_guard lock(openDirsMutex); for (auto &dir : openDirs) { if (dir->handle == handle) { return dir; @@ -742,13 +745,13 @@ std::shared_ptr FSWrapper::getDirFromHandle(FSDirectoryHandle handle) { } void FSWrapper::deleteDirHandle(FSDirectoryHandle handle) { - if (!remove_locked_first_if(openDirsMutex, openDirs, [handle](auto &cur) { return (FSFileHandle) cur->handle == handle; })) { + if (!remove_locked_first_if(openDirsMutex, openDirs, [handle](auto &cur) { return static_cast(cur->handle) == handle; })) { DEBUG_FUNCTION_LINE_ERR("[%s] Delete failed because the handle %08X was not found", getName().c_str(), handle); } } void FSWrapper::deleteFileHandle(FSFileHandle handle) { - if (!remove_locked_first_if(openFilesMutex, openFiles, [handle](auto &cur) { return (FSFileHandle) cur->handle == handle; })) { + if (!remove_locked_first_if(openFilesMutex, openFiles, [handle](auto &cur) { return static_cast(cur->handle) == handle; })) { DEBUG_FUNCTION_LINE_ERR("[%s] Delete failed because the handle %08X was not found", getName().c_str(), handle); } } diff --git a/src/FSWrapper.h b/src/FSWrapper.h index b9a2eb6..b3a2005 100644 --- a/src/FSWrapper.h +++ b/src/FSWrapper.h @@ -1,16 +1,19 @@ #pragma once + #include "DirInfo.h" #include "FileInfo.h" #include "IFSWrapper.h" #include "utils/logger.h" + #include -#include + +#include #include #include class FSWrapper : public IFSWrapper { public: - FSWrapper(const std::string &name, const std::string &pathToReplace, const std::string &replacePathWith, bool fallbackOnError, bool isWriteable) { + FSWrapper(const std::string &name, const std::string &pathToReplace, const std::string &replacePathWith, const bool fallbackOnError, const bool isWriteable) { this->pName = name; this->pPathToReplace = pathToReplace; this->pReplacePathWith = replacePathWith; @@ -18,16 +21,16 @@ class FSWrapper : public IFSWrapper { this->pIsWriteable = isWriteable; this->pCheckIfDeleted = fallbackOnError; - std::replace(pPathToReplace.begin(), pPathToReplace.end(), '\\', '/'); - std::replace(pReplacePathWith.begin(), pReplacePathWith.end(), '\\', '/'); + std::ranges::replace(pPathToReplace, '\\', '/'); + std::ranges::replace(pReplacePathWith, '\\', '/'); } ~FSWrapper() override { { - std::lock_guard lockFiles(openFilesMutex); + std::lock_guard lockFiles(openFilesMutex); openFiles.clear(); } { - std::lock_guard lockDirs(openDirsMutex); + std::lock_guard lockDirs(openDirsMutex); openDirs.clear(); } } @@ -35,7 +38,6 @@ class FSWrapper : public IFSWrapper { FSError FSOpenDirWrapper(const char *path, FSDirectoryHandle *handle) override; - FSError FSReadDirWrapper(FSDirectoryHandle handle, FSDirectoryEntry *entry) override; @@ -96,7 +98,7 @@ class FSWrapper : public IFSWrapper { FSError FSFlushFileWrapper(FSFileHandle handle) override; uint32_t getLayerId() override { - return (uint32_t) this; + return getHandle(); } protected: diff --git a/src/FSWrapperMergeDirsWithParent.cpp b/src/FSWrapperMergeDirsWithParent.cpp index df82c5b..a641bd0 100644 --- a/src/FSWrapperMergeDirsWithParent.cpp +++ b/src/FSWrapperMergeDirsWithParent.cpp @@ -2,9 +2,11 @@ #include "utils/StringTools.h" #include "utils/logger.h" #include "utils/utils.h" + #include #include #include + #include FSError FSWrapperMergeDirsWithParent::FSOpenDirWrapper(const char *path, @@ -27,11 +29,11 @@ FSError FSWrapperMergeDirsWithParent::FSOpenDirWrapper(const char *path, dirHandle->readResultNumberOfEntries = 0; dirHandle->realDirHandle = 0; - if (clientHandle) { + if (mClientHandle) { FSADirectoryHandle realHandle = 0; DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSAOpenDir with %s for parent layer", getName().c_str(), path); FSError err; - if ((err = FSAOpenDir(clientHandle, path, &realHandle)) == FS_ERROR_OK) { + if ((err = FSAOpenDir(mClientHandle, path, &realHandle)) == FS_ERROR_OK) { dirHandle->realDirHandle = realHandle; } else { DEBUG_FUNCTION_LINE_ERR("[%s] Failed to open real dir %s. %s (%d)", getName().c_str(), path, FSAGetStatusStr(err), err); @@ -58,6 +60,10 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSADirectoryHandle handle return FS_ERROR_INVALID_DIRHANDLE; } auto dirHandle = getDirExFromHandle(handle); + if (!dirHandle) { + DEBUG_FUNCTION_LINE_ERR("[%s] No valid dir handle %08X", getName().c_str(), handle); + return FS_ERROR_INVALID_DIRHANDLE; + } if (res == FS_ERROR_OK) { if (dirHandle->readResultCapacity == 0) { dirHandle->readResult = (FSDirectoryEntryEx *) malloc(sizeof(FSDirectoryEntryEx)); @@ -92,16 +98,15 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSADirectoryHandle handle } OSMemoryBarrier(); - } else if (res == FS_ERROR_END_OF_DIR) { // Read the real directory. if (dirHandle->realDirHandle != 0) { - if (clientHandle) { + if (mClientHandle) { FSADirectoryEntry realDirEntry; FSError readDirResult; while (true) { DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSReadDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle); - readDirResult = FSAReadDir(clientHandle, dirHandle->realDirHandle, &realDirEntry); + readDirResult = FSAReadDir(mClientHandle, dirHandle->realDirHandle, &realDirEntry); if (readDirResult == FS_ERROR_OK) { bool found = false; auto nameDeleted = deletePrefix + realDirEntry.name; @@ -156,9 +161,9 @@ FSError FSWrapperMergeDirsWithParent::FSCloseDirWrapper(FSADirectoryHandle handl } auto dirHandle = getDirExFromHandle(handle); if (dirHandle->realDirHandle != 0) { - if (clientHandle) { + if (mClientHandle) { DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSCloseDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle); - auto realResult = FSACloseDir(clientHandle, dirHandle->realDirHandle); + auto realResult = FSACloseDir(mClientHandle, dirHandle->realDirHandle); if (realResult == FS_ERROR_OK) { dirHandle->realDirHandle = 0; } else { @@ -201,10 +206,10 @@ FSError FSWrapperMergeDirsWithParent::FSRewindDirWrapper(FSADirectoryHandle hand } if (dirHandle->realDirHandle != 0) { - if (clientHandle) { + if (mClientHandle) { DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSARewindDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle); FSError err; - if ((err = FSARewindDir(clientHandle, dirHandle->realDirHandle)) == FS_ERROR_OK) { + if ((err = FSARewindDir(mClientHandle, dirHandle->realDirHandle)) == FS_ERROR_OK) { dirHandle->realDirHandle = 0; } else { DEBUG_FUNCTION_LINE_ERR("[%s] Failed to rewind dir for realDirHandle %08X. %s (%d)", getName().c_str(), dirHandle->realDirHandle, FSAGetStatusStr(err), err); @@ -229,20 +234,20 @@ FSWrapperMergeDirsWithParent::FSWrapperMergeDirsWithParent(const std::string &na fallbackOnError, false) { FSAInit(); - this->clientHandle = FSAAddClient(nullptr); - if (clientHandle < 0) { - DEBUG_FUNCTION_LINE_ERR("[%s] FSAClientHandle failed: %s (%d)", name.c_str(), FSAGetStatusStr(static_cast(clientHandle)), clientHandle); - clientHandle = 0; + this->mClientHandle = FSAAddClient(nullptr); + if (mClientHandle < 0) { + DEBUG_FUNCTION_LINE_ERR("[%s] FSAClientHandle failed: %s (%d)", name.c_str(), FSAGetStatusStr(static_cast(mClientHandle)), mClientHandle); + mClientHandle = 0; } } FSWrapperMergeDirsWithParent::~FSWrapperMergeDirsWithParent() { - if (clientHandle) { + if (mClientHandle) { FSError res; - if ((res = FSADelClient(clientHandle)) != FS_ERROR_OK) { + if ((res = FSADelClient(mClientHandle)) != FS_ERROR_OK) { DEBUG_FUNCTION_LINE_ERR("[%s] FSADelClient failed: %s (%d)", FSAGetStatusStr(res), res); } - clientHandle = 0; + mClientHandle = 0; } } diff --git a/src/FSWrapperMergeDirsWithParent.h b/src/FSWrapperMergeDirsWithParent.h index 24a56f1..0458d71 100644 --- a/src/FSWrapperMergeDirsWithParent.h +++ b/src/FSWrapperMergeDirsWithParent.h @@ -1,10 +1,10 @@ #pragma once #include "DirInfoEx.h" #include "FSWrapper.h" + #include -#include -class FSWrapperMergeDirsWithParent : public FSWrapper { +class FSWrapperMergeDirsWithParent final : public FSWrapper { public: FSWrapperMergeDirsWithParent(const std::string &name, const std::string &pathToReplace, @@ -28,11 +28,11 @@ class FSWrapperMergeDirsWithParent : public FSWrapper { bool SkipDeletedFilesInReadDir() override; uint32_t getLayerId() override { - return (uint32_t) clientHandle; + return static_cast(mClientHandle); } private: - FSAClientHandle clientHandle; + FSAClientHandle mClientHandle; std::shared_ptr getDirExFromHandle(FSDirectoryHandle handle); }; diff --git a/src/FileUtils.cpp b/src/FileUtils.cpp index 1165536..ef23d62 100644 --- a/src/FileUtils.cpp +++ b/src/FileUtils.cpp @@ -11,39 +11,41 @@ #include #include -std::mutex workingDirMutex; -std::map workingDirs; +namespace { + std::mutex sWorkingDirMutex; + std::map sWorkingDirs; +} // namespace -std::mutex fsLayerMutex; -std::vector> fsLayers; +std::mutex gFSLayerMutex; +std::vector> gFSLayers; -std::string getFullPathGeneric(FSAClientHandle client, const char *path, std::mutex &mutex, std::map &map) { - std::lock_guard workingDirLock(mutex); +std::string getFullPathGeneric(const FSAClientHandle client, const char *path, std::mutex &mutex, const std::map &map) { + std::lock_guard workingDirLock(mutex); std::string res; if (path[0] != '/' && path[0] != '\\') { if (map.count(client) == 0) { DEBUG_FUNCTION_LINE_WARN("No working dir found for client %08X, fallback to \"/\"", client); - workingDirs[client] = "/"; + sWorkingDirs[client] = "/"; } res = string_format("%s%s", map.at(client).c_str(), path); } else { res = path; } - std::replace(res.begin(), res.end(), '\\', '/'); + std::ranges::replace(res, '\\', '/'); return res; } -void setWorkingDirGeneric(FSAClientHandle client, const char *path, std::mutex &mutex, std::map &map) { +void setWorkingDirGeneric(const FSAClientHandle client, const char *path, std::mutex &mutex, std::map &map) { if (!path) { DEBUG_FUNCTION_LINE_WARN("Path was NULL"); return; } - std::lock_guard workingDirLock(mutex); + std::lock_guard workingDirLock(mutex); std::string cwd(path); if (cwd.empty() || cwd.back() != '/') { @@ -54,22 +56,22 @@ void setWorkingDirGeneric(FSAClientHandle client, const char *path, std::mutex & } -std::string getFullPath(FSAClientHandle pClient, const char *path) { - return getFullPathGeneric(pClient, path, workingDirMutex, workingDirs); +std::string getFullPath(const FSAClientHandle pClient, const char *path) { + return getFullPathGeneric(pClient, path, sWorkingDirMutex, sWorkingDirs); } -void setWorkingDir(FSAClientHandle client, const char *path) { - setWorkingDirGeneric(client, path, workingDirMutex, workingDirs); +void setWorkingDir(const FSAClientHandle client, const char *path) { + setWorkingDirGeneric(client, path, sWorkingDirMutex, sWorkingDirs); } void clearFSLayer() { { - std::lock_guard workingDirLock(workingDirMutex); - workingDirs.clear(); + std::lock_guard workingDirLock(sWorkingDirMutex); + sWorkingDirs.clear(); } { - std::lock_guard layerLock(fsLayerMutex); - fsLayers.clear(); + std::lock_guard layerLock(gFSLayerMutex); + gFSLayers.clear(); } } @@ -93,11 +95,11 @@ bool sendMessageToThread(FSShimWrapperMessage *param) { } FSError doForLayer(FSShimWrapper *param) { - std::lock_guard lock(fsLayerMutex); - if (!fsLayers.empty()) { - uint32_t startIndex = fsLayers.size(); - for (uint32_t i = fsLayers.size(); i > 0; i--) { - if ((uint32_t) fsLayers[i - 1]->getLayerId() == param->shim->clientHandle) { + std::lock_guard lock(gFSLayerMutex); + if (!gFSLayers.empty()) { + uint32_t startIndex = gFSLayers.size(); + for (uint32_t i = gFSLayers.size(); i > 0; i--) { + if (gFSLayers[i - 1]->getLayerId() == param->shim->clientHandle) { startIndex = i - 1; break; } @@ -105,7 +107,7 @@ FSError doForLayer(FSShimWrapper *param) { if (startIndex > 0) { for (uint32_t i = startIndex; i > 0; i--) { - auto &layer = fsLayers[i - 1]; + auto &layer = gFSLayers[i - 1]; if (!layer->isActive()) { continue; } diff --git a/src/FileUtils.h b/src/FileUtils.h index f31f5df..5095d4a 100644 --- a/src/FileUtils.h +++ b/src/FileUtils.h @@ -55,8 +55,8 @@ struct FSShimWrapperMessage { extern bool gThreadsRunning; extern FSIOThreadData gThreadData[3]; -extern std::mutex fsLayerMutex; -extern std::vector> fsLayers; +extern std::mutex gFSLayerMutex; +extern std::vector> gFSLayers; #define fsaShimPrepareRequestReadFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, uint8_t * buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, FSAReadFlag readFlags))(0x101C400 + 0x436cc)) #define fsaShimPrepareRequestWriteFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, FSAWriteFlag writeFlags))(0x101C400 + 0x437f4)) diff --git a/src/IFSWrapper.h b/src/IFSWrapper.h index 528709d..6d2faa7 100644 --- a/src/IFSWrapper.h +++ b/src/IFSWrapper.h @@ -1,6 +1,7 @@ #pragma once #include -#include +#include + #include #define FS_ERROR_EXTRA_MASK 0xFFF00000 @@ -53,7 +54,6 @@ class IFSWrapper { return FS_ERROR_FORCE_PARENT_LAYER; } - virtual FSError FSGetStatFileWrapper(FSAFileHandle handle, FSAStat *stats) { return FS_ERROR_FORCE_PARENT_LAYER; @@ -151,11 +151,17 @@ class IFSWrapper { virtual uint32_t getLayerId() = 0; virtual uint32_t getHandle() { - return (uint32_t) this; + return reinterpret_cast(this); + } + + IFSWrapper() { + // Abuse this as a stable handle that references itself and survives std::move + *mHandle = reinterpret_cast(mHandle.get()); } private: - bool pIsActive = true; + bool pIsActive = true; + std::unique_ptr mHandle = std::make_unique(); protected: bool pFallbackOnError = false; diff --git a/src/export.cpp b/src/export.cpp index a2d6c24..363ca78 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -15,6 +15,7 @@ struct AOCTitle { WUT_UNKNOWN_BYTES(0x68); }; + WUT_CHECK_SIZE(AOCTitle, 0x68); bool getAOCPath(std::string &outStr) { @@ -90,7 +91,7 @@ bool getAOCPath(std::string &outStr) { return result; } -ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *layerName, const char *replacementDir, FSLayerType layerType) { +ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *layerName, const char *replacementDir, const FSLayerType layerType) { if (!handle || layerName == nullptr || replacementDir == nullptr) { DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_INVALID_ARG"); return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG; @@ -132,9 +133,9 @@ ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *l } if (ptr) { DEBUG_FUNCTION_LINE_VERBOSE("Added new layer (%s). Replacement dir: %s Type:%d", layerName, replacementDir, layerType); - std::lock_guard lock(fsLayerMutex); + std::lock_guard lock(gFSLayerMutex); *handle = (CRLayerHandle) ptr->getHandle(); - fsLayers.push_back(std::move(ptr)); + gFSLayers.push_back(std::move(ptr)); return CONTENT_REDIRECTION_API_ERROR_NONE; } DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory"); @@ -142,7 +143,7 @@ ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *l } ContentRedirectionApiErrorType CRRemoveFSLayer(CRLayerHandle handle) { - if (!remove_locked_first_if(fsLayerMutex, fsLayers, [handle](auto &cur) { return (CRLayerHandle) cur->getHandle() == handle; })) { + if (!remove_locked_first_if(gFSLayerMutex, gFSLayers, [handle](auto &cur) { return (CRLayerHandle) cur->getHandle() == handle; })) { DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle); return CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND; } @@ -150,8 +151,8 @@ ContentRedirectionApiErrorType CRRemoveFSLayer(CRLayerHandle handle) { } ContentRedirectionApiErrorType CRSetActive(CRLayerHandle handle, bool active) { - std::lock_guard lock(fsLayerMutex); - for (auto &cur : fsLayers) { + std::lock_guard lock(gFSLayerMutex); + for (auto &cur : gFSLayers) { if ((CRLayerHandle) cur->getHandle() == handle) { cur->setActive(active); return CONTENT_REDIRECTION_API_ERROR_NONE; diff --git a/src/utils/StringTools.h b/src/utils/StringTools.h index 78ec91a..996072a 100644 --- a/src/utils/StringTools.h +++ b/src/utils/StringTools.h @@ -13,12 +13,12 @@ std::string string_format(const std::string &format, Args... args) { return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside } -static inline bool starts_with_case_insensitive(std::string_view str, std::string_view prefix) { +static inline bool starts_with_case_insensitive(const std::string_view str, const std::string_view prefix) { if (str.size() < prefix.size()) return false; return std::equal(prefix.begin(), prefix.end(), str.begin(), - [](char a, char b) { + [](const char a, const char b) { return std::tolower(a) == std::tolower(b); }); } diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index 5d338bf..b141d9f 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -54,7 +54,7 @@ FSTime translate_time(time_t timeValue) { return adjustedTimeValue * 1000000; } -void translate_stat(struct stat *posStat, FSStat *fsStat) { +void translate_stat(const struct stat *posStat, FSStat *fsStat) { memset(fsStat, 0, sizeof(FSStat)); fsStat->size = posStat->st_size; diff --git a/src/utils/utils.h b/src/utils/utils.h index a9d7a6f..ef974ce 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -32,4 +32,4 @@ bool remove_locked_first_if(std::mutex &mutex, std::vector &list, #define ROUNDDOWN(val, align) ((val) & ~(align - 1)) #define ROUNDUP(val, align) ROUNDDOWN(((val) + (align - 1)), align) -void translate_stat(struct stat *posStat, FSStat *fsStat); \ No newline at end of file +void translate_stat(const struct stat *posStat, FSStat *fsStat); \ No newline at end of file From 6fee4613f9c08c6c15a6950f3b310d6416a86919 Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 7 Feb 2025 16:16:44 +0100 Subject: [PATCH 3/7] Fix FSWrapperMergeDirsWithParent::FSRewindDirWrapper implementation --- src/FSWrapperMergeDirsWithParent.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/FSWrapperMergeDirsWithParent.cpp b/src/FSWrapperMergeDirsWithParent.cpp index a641bd0..72a5df0 100644 --- a/src/FSWrapperMergeDirsWithParent.cpp +++ b/src/FSWrapperMergeDirsWithParent.cpp @@ -208,10 +208,7 @@ FSError FSWrapperMergeDirsWithParent::FSRewindDirWrapper(FSADirectoryHandle hand if (dirHandle->realDirHandle != 0) { if (mClientHandle) { DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSARewindDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle); - FSError err; - if ((err = FSARewindDir(mClientHandle, dirHandle->realDirHandle)) == FS_ERROR_OK) { - dirHandle->realDirHandle = 0; - } else { + if (FSError err = FSARewindDir(mClientHandle, dirHandle->realDirHandle); err != FS_ERROR_OK) { DEBUG_FUNCTION_LINE_ERR("[%s] Failed to rewind dir for realDirHandle %08X. %s (%d)", getName().c_str(), dirHandle->realDirHandle, FSAGetStatusStr(err), err); } } else { From e9cfc1c0846ef1aa9bc0524942d3fce1b1c8c6b3 Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 7 Feb 2025 16:30:51 +0100 Subject: [PATCH 4/7] Clean up --- src/FSWrapper.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/FSWrapper.cpp b/src/FSWrapper.cpp index 49da6cc..e9ba5c9 100644 --- a/src/FSWrapper.cpp +++ b/src/FSWrapper.cpp @@ -71,7 +71,7 @@ FSError FSWrapper::FSOpenDirWrapper(const char *path, FSDirectoryHandle *handle) return result; } -FSError FSWrapper::FSReadDirWrapper(FSDirectoryHandle handle, FSDirectoryEntry *entry) { +FSError FSWrapper::FSReadDirWrapper(const FSDirectoryHandle handle, FSDirectoryEntry *entry) { if (!isValidDirHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } @@ -633,7 +633,7 @@ FSError FSWrapper::FSRenameWrapper(const char *oldPath, const char *newPath) { return FS_ERROR_OK; } -FSError FSWrapper::FSFlushFileWrapper(FSFileHandle handle) { +FSError FSWrapper::FSFlushFileWrapper(const FSFileHandle handle) { if (!isValidFileHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } @@ -642,8 +642,8 @@ FSError FSWrapper::FSFlushFileWrapper(FSFileHandle handle) { return FS_ERROR_ACCESS_ERROR; } - auto fileHandle = getFileFromHandle(handle); - int real_fd = fileHandle->fd; + const auto fileHandle = getFileFromHandle(handle); + const int real_fd = fileHandle->fd; DEBUG_FUNCTION_LINE_VERBOSE("[%s] fsync fd %08X (FSFileHandle %08X)", real_fd, handle); FSError result = FS_ERROR_OK; @@ -685,7 +685,7 @@ std::string FSWrapper::GetNewPath(const std::string_view &path) { auto subStr = path.substr(this->pPathToReplace.length()); auto res = string_format("%s%.*s", this->pReplacePathWith.c_str(), int(subStr.length()), subStr.data()); - std::replace(res.begin(), res.end(), '\\', '/'); + std::ranges::replace(res, '\\', '/'); uint32_t length = res.size(); @@ -703,15 +703,16 @@ std::string FSWrapper::GetNewPath(const std::string_view &path) { } bool FSWrapper::isValidFileHandle(FSFileHandle handle) { - std::lock_guard lock(openFilesMutex); + std::lock_guard lock(openFilesMutex); return std::ranges::any_of(openFiles, [handle](auto &cur) { return cur->handle == handle; }); } bool FSWrapper::isValidDirHandle(FSDirectoryHandle handle) { - std::lock_guard lock(openDirsMutex); + std::lock_guard lock(openDirsMutex); return std::ranges::any_of(openDirs, [handle](auto &cur) { return cur->handle == handle; }); } + std::shared_ptr FSWrapper::getNewFileHandle() { return make_shared_nothrow(); } @@ -732,7 +733,7 @@ std::shared_ptr FSWrapper::getFileFromHandle(const FSFileHandle handle return nullptr; } -std::shared_ptr FSWrapper::getDirFromHandle(FSDirectoryHandle handle) { +std::shared_ptr FSWrapper::getDirFromHandle(const FSDirectoryHandle handle) { std::lock_guard lock(openDirsMutex); for (auto &dir : openDirs) { if (dir->handle == handle) { From e0f094c57d65227f1fe1124889ea148bb7c69832 Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 7 Feb 2025 18:26:27 +0100 Subject: [PATCH 5/7] Update string replace function in FSWrapper::;GetNewPath --- src/FSWrapper.cpp | 7 +++---- src/FSWrapper.h | 2 +- src/utils/StringTools.cpp | 16 ++++++++++++++++ src/utils/StringTools.h | 3 ++- 4 files changed, 22 insertions(+), 6 deletions(-) create mode 100644 src/utils/StringTools.cpp diff --git a/src/FSWrapper.cpp b/src/FSWrapper.cpp index e9ba5c9..6bd913e 100644 --- a/src/FSWrapper.cpp +++ b/src/FSWrapper.cpp @@ -676,14 +676,13 @@ bool FSWrapper::IsFileModeAllowed(const char *mode) { return false; } - bool FSWrapper::IsPathToReplace(const std::string_view &path) { return starts_with_case_insensitive(path, pPathToReplace); } -std::string FSWrapper::GetNewPath(const std::string_view &path) { - auto subStr = path.substr(this->pPathToReplace.length()); - auto res = string_format("%s%.*s", this->pReplacePathWith.c_str(), int(subStr.length()), subStr.data()); +std::string FSWrapper::GetNewPath(const std::string_view &path) const { + auto res = std::string(path); + SafeReplaceInString(res, this->pPathToReplace, this->pReplacePathWith); std::ranges::replace(res, '\\', '/'); diff --git a/src/FSWrapper.h b/src/FSWrapper.h index b3a2005..518d64f 100644 --- a/src/FSWrapper.h +++ b/src/FSWrapper.h @@ -106,7 +106,7 @@ class FSWrapper : public IFSWrapper { virtual bool IsPathToReplace(const std::string_view &path); - std::string GetNewPath(const std::string_view &path); + [[nodiscard]] virtual std::string GetNewPath(const std::string_view &path) const; std::shared_ptr getDirFromHandle(FSDirectoryHandle handle); std::shared_ptr getFileFromHandle(FSFileHandle handle); diff --git a/src/utils/StringTools.cpp b/src/utils/StringTools.cpp new file mode 100644 index 0000000..fd551a2 --- /dev/null +++ b/src/utils/StringTools.cpp @@ -0,0 +1,16 @@ +#include "StringTools.h" +#include + +void SafeReplaceInString(std::string &subject, std::string search, const std::string &replace) { + if (search.empty() || search == replace) { + return; // Avoid infinite loops and invalid input + } + std::string lowerSubject = subject; + + std::ranges::transform(subject, lowerSubject.begin(), ::tolower); + std::ranges::transform(search, search.begin(), ::tolower); + + if (const size_t pos = lowerSubject.find(search); pos != std::string::npos) { + subject.replace(pos, search.length(), replace); + } +} \ No newline at end of file diff --git a/src/utils/StringTools.h b/src/utils/StringTools.h index 996072a..08d3b47 100644 --- a/src/utils/StringTools.h +++ b/src/utils/StringTools.h @@ -2,7 +2,6 @@ #include #include -#include template std::string string_format(const std::string &format, Args... args) { @@ -13,6 +12,8 @@ std::string string_format(const std::string &format, Args... args) { return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside } +void SafeReplaceInString(std::string &subject, std::string search, const std::string &replace); + static inline bool starts_with_case_insensitive(const std::string_view str, const std::string_view prefix) { if (str.size() < prefix.size()) return false; From 1ac6f0246fc321d953ca71b681c771cb5bdab7be Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 7 Feb 2025 17:18:53 +0100 Subject: [PATCH 6/7] Introduce DirInfoBase to FSWrapper --- src/DirInfo.h | 8 ++++++-- src/DirInfoEx.h | 3 +-- src/FSWrapper.cpp | 21 +++++++++++++++------ src/FSWrapper.h | 7 ++++--- src/FSWrapperMergeDirsWithParent.cpp | 12 ++++++------ src/FSWrapperMergeDirsWithParent.h | 4 ++-- 6 files changed, 34 insertions(+), 21 deletions(-) diff --git a/src/DirInfo.h b/src/DirInfo.h index 13fc292..dfaf416 100644 --- a/src/DirInfo.h +++ b/src/DirInfo.h @@ -2,9 +2,13 @@ #include #include -struct DirInfo { - virtual ~DirInfo() = default; +struct DirInfoBase { + virtual ~DirInfoBase() = default; FSDirectoryHandle handle{}; +}; + +struct DirInfo : DirInfoBase { + ~DirInfo() override = default; DIR *dir{}; char path[0x280]{}; }; diff --git a/src/DirInfoEx.h b/src/DirInfoEx.h index b5884cd..c682d3a 100644 --- a/src/DirInfoEx.h +++ b/src/DirInfoEx.h @@ -7,8 +7,7 @@ typedef struct FSDirectoryEntryEx { bool isMarkedAsDeleted = false; } FSDirectoryEntryEx; -struct DirInfoEx : public DirInfo { -public: +struct DirInfoEx final : DirInfo { FSDirectoryEntryEx *readResult = nullptr; int readResultCapacity = 0; int readResultNumberOfEntries = 0; diff --git a/src/FSWrapper.cpp b/src/FSWrapper.cpp index 6bd913e..96affaf 100644 --- a/src/FSWrapper.cpp +++ b/src/FSWrapper.cpp @@ -4,7 +4,6 @@ #include "utils/logger.h" #include "utils/utils.h" - #include #include @@ -31,7 +30,7 @@ FSError FSWrapper::FSOpenDirWrapper(const char *path, FSDirectoryHandle *handle) FSError result = FS_ERROR_OK; - auto dirHandle = getNewDirHandle(); + const auto dirHandle = getNewDirInfoHandle(); if (dirHandle) { DIR *dir; auto newPath = GetNewPath(path); @@ -75,7 +74,7 @@ FSError FSWrapper::FSReadDirWrapper(const FSDirectoryHandle handle, FSDirectoryE if (!isValidDirHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } - auto dirHandle = getDirFromHandle(handle); + const auto dirHandle = getDirInfoFromHandle(handle); DIR *dir = dirHandle->dir; @@ -146,7 +145,7 @@ FSError FSWrapper::FSCloseDirWrapper(const FSDirectoryHandle handle) { if (!isValidDirHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } - auto dirHandle = getDirFromHandle(handle); + const auto dirHandle = getDirInfoFromHandle(handle); DIR *dir = dirHandle->dir; @@ -165,7 +164,7 @@ FSError FSWrapper::FSRewindDirWrapper(const FSDirectoryHandle handle) { if (!isValidDirHandle(handle)) { return FS_ERROR_FORCE_PARENT_LAYER; } - auto dirHandle = getDirFromHandle(handle); + const auto dirHandle = getDirInfoFromHandle(handle); DIR *dir = dirHandle->dir; @@ -716,7 +715,7 @@ std::shared_ptr FSWrapper::getNewFileHandle() { return make_shared_nothrow(); } -std::shared_ptr FSWrapper::getNewDirHandle() { +std::shared_ptr FSWrapper::getNewDirInfoHandle() { return make_shared_nothrow(); } @@ -759,3 +758,13 @@ void FSWrapper::deleteFileHandle(FSFileHandle handle) { bool FSWrapper::SkipDeletedFilesInReadDir() { return true; } + +std::shared_ptr FSWrapper::getDirInfoFromHandle(const FSDirectoryHandle handle) { + auto dir = std::dynamic_pointer_cast(getDirFromHandle(handle)); + + if (!dir) { + DEBUG_FUNCTION_LINE_ERR("[%s] dynamic_pointer_cast(%08X) failed", getName().c_str(), handle); + OSFatal("ContentRedirectionModule: dynamic_pointer_cast failed"); + } + return dir; +} diff --git a/src/FSWrapper.h b/src/FSWrapper.h index 518d64f..cb052ef 100644 --- a/src/FSWrapper.h +++ b/src/FSWrapper.h @@ -108,7 +108,7 @@ class FSWrapper : public IFSWrapper { [[nodiscard]] virtual std::string GetNewPath(const std::string_view &path) const; - std::shared_ptr getDirFromHandle(FSDirectoryHandle handle); + std::shared_ptr getDirFromHandle(FSDirectoryHandle handle); std::shared_ptr getFileFromHandle(FSFileHandle handle); bool isValidDirHandle(FSDirectoryHandle handle) override; @@ -120,7 +120,7 @@ class FSWrapper : public IFSWrapper { virtual bool CheckFileShouldBeIgnored(std::string &path); virtual std::shared_ptr getNewFileHandle(); - virtual std::shared_ptr getNewDirHandle(); + virtual std::shared_ptr getNewDirInfoHandle(); virtual bool SkipDeletedFilesInReadDir(); @@ -129,11 +129,12 @@ class FSWrapper : public IFSWrapper { std::string deletePrefix = ".deleted_"; private: + std::shared_ptr getDirInfoFromHandle(FSDirectoryHandle handle); std::string pPathToReplace; std::string pReplacePathWith; bool pIsWriteable = false; std::mutex openFilesMutex; std::mutex openDirsMutex; std::vector> openFiles; - std::vector> openDirs; + std::vector> openDirs; }; diff --git a/src/FSWrapperMergeDirsWithParent.cpp b/src/FSWrapperMergeDirsWithParent.cpp index 72a5df0..9a2bc91 100644 --- a/src/FSWrapperMergeDirsWithParent.cpp +++ b/src/FSWrapperMergeDirsWithParent.cpp @@ -23,7 +23,7 @@ FSError FSWrapperMergeDirsWithParent::FSOpenDirWrapper(const char *path, DEBUG_FUNCTION_LINE_ERR("[%s] No valid dir handle %08X", getName().c_str(), *handle); return FS_ERROR_INVALID_DIRHANDLE; } - auto dirHandle = getDirExFromHandle(*handle); + auto dirHandle = getDirInfoExFromHandle(*handle); if (dirHandle != nullptr) { dirHandle->readResultCapacity = 0; dirHandle->readResultNumberOfEntries = 0; @@ -59,7 +59,7 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSADirectoryHandle handle DEBUG_FUNCTION_LINE_ERR("[%s] No valid dir handle %08X", getName().c_str(), handle); return FS_ERROR_INVALID_DIRHANDLE; } - auto dirHandle = getDirExFromHandle(handle); + auto dirHandle = getDirInfoExFromHandle(handle); if (!dirHandle) { DEBUG_FUNCTION_LINE_ERR("[%s] No valid dir handle %08X", getName().c_str(), handle); return FS_ERROR_INVALID_DIRHANDLE; @@ -159,7 +159,7 @@ FSError FSWrapperMergeDirsWithParent::FSCloseDirWrapper(FSADirectoryHandle handl DEBUG_FUNCTION_LINE_ERR("[%s] No valid dir handle %08X", getName().c_str(), handle); return FS_ERROR_INVALID_DIRHANDLE; } - auto dirHandle = getDirExFromHandle(handle); + auto dirHandle = getDirInfoExFromHandle(handle); if (dirHandle->realDirHandle != 0) { if (mClientHandle) { DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSCloseDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle); @@ -196,7 +196,7 @@ FSError FSWrapperMergeDirsWithParent::FSRewindDirWrapper(FSADirectoryHandle hand DEBUG_FUNCTION_LINE_ERR("[%s] No valid dir handle %08X", getName().c_str(), handle); return FS_ERROR_INVALID_DIRHANDLE; } - auto dirHandle = getDirExFromHandle(handle); + auto dirHandle = getDirInfoExFromHandle(handle); if (dirHandle->readResult != nullptr) { dirHandle->readResultNumberOfEntries = 0; #pragma GCC diagnostic push @@ -248,7 +248,7 @@ FSWrapperMergeDirsWithParent::~FSWrapperMergeDirsWithParent() { } } -std::shared_ptr FSWrapperMergeDirsWithParent::getDirExFromHandle(FSADirectoryHandle handle) { +std::shared_ptr FSWrapperMergeDirsWithParent::getDirInfoExFromHandle(FSADirectoryHandle handle) { auto dir = std::dynamic_pointer_cast(getDirFromHandle(handle)); if (!dir) { @@ -258,6 +258,6 @@ std::shared_ptr FSWrapperMergeDirsWithParent::getDirExFromHandle(FSAD return dir; } -std::shared_ptr FSWrapperMergeDirsWithParent::getNewDirHandle() { +std::shared_ptr FSWrapperMergeDirsWithParent::getNewDirInfoHandle() { return make_shared_nothrow(); } diff --git a/src/FSWrapperMergeDirsWithParent.h b/src/FSWrapperMergeDirsWithParent.h index 0458d71..6f8c753 100644 --- a/src/FSWrapperMergeDirsWithParent.h +++ b/src/FSWrapperMergeDirsWithParent.h @@ -23,7 +23,7 @@ class FSWrapperMergeDirsWithParent final : public FSWrapper { FSError FSRewindDirWrapper(FSDirectoryHandle handle) override; - std::shared_ptr getNewDirHandle() override; + std::shared_ptr getNewDirInfoHandle() override; bool SkipDeletedFilesInReadDir() override; @@ -34,5 +34,5 @@ class FSWrapperMergeDirsWithParent final : public FSWrapper { private: FSAClientHandle mClientHandle; - std::shared_ptr getDirExFromHandle(FSDirectoryHandle handle); + std::shared_ptr getDirInfoExFromHandle(FSDirectoryHandle handle); }; From 5923009f5f8f37cf25cb5267da96627d60d029c5 Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 7 Feb 2025 18:25:00 +0100 Subject: [PATCH 7/7] Implement FSWrapperReplaceSingleFile --- Dockerfile | 4 +- src/DirInfoEx.h | 13 +- src/FSWrapper.cpp | 12 +- src/FSWrapper.h | 1 + src/FSWrapperReplaceSingleFile.cpp | 247 +++++++++++++++++++++++++++++ src/FSWrapperReplaceSingleFile.h | 52 ++++++ src/export.cpp | 45 +++++- 7 files changed, 363 insertions(+), 11 deletions(-) create mode 100644 src/FSWrapperReplaceSingleFile.cpp create mode 100644 src/FSWrapperReplaceSingleFile.h diff --git a/Dockerfile b/Dockerfile index 98ad2a7..dd17e43 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ -FROM ghcr.io/wiiu-env/devkitppc:20240505 +FROM ghcr.io/wiiu-env/devkitppc:20241128 COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230621 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20240424 /artifacts $DEVKITPRO -COPY --from=ghcr.io/wiiu-env/libcontentredirection:20240428 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/libcontentredirection:1.2-dev-20250207-b11c3c8 /artifacts $DEVKITPRO WORKDIR project diff --git a/src/DirInfoEx.h b/src/DirInfoEx.h index c682d3a..648ac7e 100644 --- a/src/DirInfoEx.h +++ b/src/DirInfoEx.h @@ -3,8 +3,8 @@ #include typedef struct FSDirectoryEntryEx { - FSADirectoryEntry realEntry{}; - bool isMarkedAsDeleted = false; + FSADirectoryEntry realEntry = {}; + bool isMarkedAsDeleted = false; } FSDirectoryEntryEx; struct DirInfoEx final : DirInfo { @@ -12,4 +12,11 @@ struct DirInfoEx final : DirInfo { int readResultCapacity = 0; int readResultNumberOfEntries = 0; FSDirectoryHandle realDirHandle = 0; -}; \ No newline at end of file +}; + +struct DirInfoExSingleFile final : DirInfoBase { + FSADirectoryEntry directoryEntry = {}; + bool entryRead = false; + bool entryReadSuccess = false; + FSDirectoryHandle realDirHandle = 0; +}; diff --git a/src/FSWrapper.cpp b/src/FSWrapper.cpp index 96affaf..cc007a9 100644 --- a/src/FSWrapper.cpp +++ b/src/FSWrapper.cpp @@ -42,11 +42,7 @@ FSError FSWrapper::FSOpenDirWrapper(const char *path, FSDirectoryHandle *handle) dirHandle->path[0] = '\0'; strncat(dirHandle->path, newPath.c_str(), sizeof(dirHandle->path) - 1); - { - std::lock_guard lock(openDirsMutex); - openDirs.push_back(dirHandle); - OSMemoryBarrier(); - } + addDirHandle(dirHandle); } else { auto err = errno; if (err == ENOENT) { @@ -743,6 +739,12 @@ std::shared_ptr FSWrapper::getDirFromHandle(const FSDirectoryHandle return nullptr; } +void FSWrapper::addDirHandle(const std::shared_ptr &dirHandle) { + std::lock_guard lock(openDirsMutex); + openDirs.push_back(dirHandle); + OSMemoryBarrier(); +} + void FSWrapper::deleteDirHandle(FSDirectoryHandle handle) { if (!remove_locked_first_if(openDirsMutex, openDirs, [handle](auto &cur) { return static_cast(cur->handle) == handle; })) { DEBUG_FUNCTION_LINE_ERR("[%s] Delete failed because the handle %08X was not found", getName().c_str(), handle); diff --git a/src/FSWrapper.h b/src/FSWrapper.h index cb052ef..84d5280 100644 --- a/src/FSWrapper.h +++ b/src/FSWrapper.h @@ -114,6 +114,7 @@ class FSWrapper : public IFSWrapper { bool isValidDirHandle(FSDirectoryHandle handle) override; bool isValidFileHandle(FSFileHandle handle) override; + void addDirHandle(const std::shared_ptr &dirHandle); void deleteDirHandle(FSDirectoryHandle handle) override; void deleteFileHandle(FSFileHandle handle) override; diff --git a/src/FSWrapperReplaceSingleFile.cpp b/src/FSWrapperReplaceSingleFile.cpp new file mode 100644 index 0000000..640ce9d --- /dev/null +++ b/src/FSWrapperReplaceSingleFile.cpp @@ -0,0 +1,247 @@ +#include "FSWrapperReplaceSingleFile.h" +#include "utils/StringTools.h" +#include "utils/logger.h" +#include "utils/utils.h" + +#include +#include +#include + +#include + +FSWrapperReplaceSingleFile::FSWrapperReplaceSingleFile(const std::string &name, + const std::string &fileToReplace, + const std::string &replaceWithPath, + const bool fallbackOnError) : FSWrapper(name, + fileToReplace, + replaceWithPath, + fallbackOnError, + false) { + auto strCpy = fileToReplace; + std::ranges::replace(strCpy, '\\', '/'); + auto asPath = std::filesystem::path(strCpy); + mPathToReplace = asPath.parent_path(); + mFileNameToReplace = asPath.filename(); + mFullPathToReplace = fileToReplace; + + strCpy = replaceWithPath; + std::ranges::replace(strCpy, '\\', '/'); + asPath = std::filesystem::path(strCpy); + mReplacedWithPath = asPath.parent_path(); + mReplacedWithFileName = asPath.filename(); + + FSAInit(); + this->mClientHandle = FSAAddClient(nullptr); + if (mClientHandle < 0) { + DEBUG_FUNCTION_LINE_ERR("[%s] FSAClientHandle failed: %s (%d)", name.c_str(), FSAGetStatusStr(static_cast(mClientHandle)), mClientHandle); + mClientHandle = 0; + } +} + +FSWrapperReplaceSingleFile::~FSWrapperReplaceSingleFile() { + if (mClientHandle) { + if (const FSError res = FSADelClient(mClientHandle); res != FS_ERROR_OK) { + DEBUG_FUNCTION_LINE_ERR("[%s] FSADelClient failed: %s (%d)", FSAGetStatusStr(res), res); + } + mClientHandle = 0; + } +} + +FSError FSWrapperReplaceSingleFile::FSOpenDirWrapper(const char *path, + FSADirectoryHandle *handle) { + if (!IsDirPathToReplace(path)) { + return FS_ERROR_FORCE_PARENT_LAYER; + } + if (handle == nullptr) { + DEBUG_FUNCTION_LINE_ERR("[%s] handle was NULL", getName().c_str()); + return FS_ERROR_INVALID_PARAM; + } + if (const auto dirInfo = make_shared_nothrow()) { + dirInfo->handle = (reinterpret_cast(dirInfo.get()) & 0x0FFFFFFF) | 0x30000000; + *handle = dirInfo->handle; + addDirHandle(dirInfo); + if (!isValidDirHandle(*handle)) { + FSWrapper::FSCloseDirWrapper(*handle); + DEBUG_FUNCTION_LINE_ERR("[%s] No valid dir handle %08X", getName().c_str(), *handle); + return FS_ERROR_INVALID_DIRHANDLE; + } + if (const auto dirHandle = getDirExFromHandle(*handle); dirHandle != nullptr) { + dirHandle->entryRead = false; + dirHandle->entryReadSuccess = false; + dirHandle->directoryEntry = {}; + dirHandle->realDirHandle = 0; + + if (mClientHandle) { + FSADirectoryHandle realHandle = 0; + DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSAOpenDir with %s for parent layer", getName().c_str(), path); + if (const FSError err = FSAOpenDir(mClientHandle, path, &realHandle); err == FS_ERROR_OK) { + dirHandle->realDirHandle = realHandle; + } else { + DEBUG_FUNCTION_LINE_ERR("[%s] Failed to open real dir %s. %s (%d)", getName().c_str(), path, FSAGetStatusStr(err), err); + } + } else { + DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str()); + } + OSMemoryBarrier(); + } + } else { + DEBUG_FUNCTION_LINE_ERR("[%s] Failed to alloc dir handle", getName().c_str()); + return FS_ERROR_MAX_DIRS; + } + return FS_ERROR_OK; +} + +FSError FSWrapperReplaceSingleFile::FSReadDirWrapper(const FSADirectoryHandle handle, FSADirectoryEntry *entry) { + if (!isValidDirHandle(handle)) { + return FS_ERROR_FORCE_PARENT_LAYER; + } + const auto dirHandle = getDirExFromHandle(handle); + if (!dirHandle) { + DEBUG_FUNCTION_LINE_ERR("[%s] No valid dir handle %08X", getName().c_str(), handle); + return FS_ERROR_INVALID_DIRHANDLE; + } + FSError res = FS_ERROR_OK; + do { + if (!dirHandle->entryRead) { + dirHandle->entryRead = true; + const auto newPath = GetNewPath(mFullPathToReplace); + + struct stat path_stat {}; + + DEBUG_FUNCTION_LINE_VERBOSE("[%s] dir read of %s (%s)", getName().c_str(), mFullPathToReplace.c_str(), newPath.c_str()); + if (stat(newPath.c_str(), &path_stat) < 0) { + DEBUG_FUNCTION_LINE_WARN("[%s] Path %s (%s) for dir read not found ", getName().c_str(), mFullPathToReplace.c_str(), newPath.c_str()); + dirHandle->entryReadSuccess = false; + continue; + } + translate_stat(&path_stat, &dirHandle->directoryEntry.info); + strncpy(dirHandle->directoryEntry.name, mFileNameToReplace.c_str(), sizeof(dirHandle->directoryEntry.name)); + memcpy(entry, &dirHandle->directoryEntry, sizeof(FSADirectoryEntry)); + + dirHandle->entryReadSuccess = true; + OSMemoryBarrier(); + } else { + // Read the real directory. + if (dirHandle->realDirHandle != 0) { + if (mClientHandle) { + FSADirectoryEntry realDirEntry; + while (true) { + DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSReadDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle); + if (const FSError readDirResult = FSAReadDir(mClientHandle, dirHandle->realDirHandle, &realDirEntry); readDirResult == FS_ERROR_OK) { + // Skip already read new files + if (dirHandle->entryRead && dirHandle->entryReadSuccess && strcmp(dirHandle->directoryEntry.name, realDirEntry.name) == 0) { + continue; + } + + // But use new entries! + memcpy(entry, &realDirEntry, sizeof(FSADirectoryEntry)); + res = FS_ERROR_OK; + break; + } else if (readDirResult == FS_ERROR_END_OF_DIR) { + res = FS_ERROR_END_OF_DIR; + break; + } else { + DEBUG_FUNCTION_LINE_ERR("[%s] real_FSReadDir returned an unexpected error: %s (%d)", getName().c_str(), FSAGetStatusStr(readDirResult), readDirResult); + res = FS_ERROR_END_OF_DIR; + break; + } + } + } else { + DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str()); + } + } + } + return res; + } while (true); +} + +FSError FSWrapperReplaceSingleFile::FSCloseDirWrapper(const FSADirectoryHandle handle) { + if (!isValidDirHandle(handle)) { + return FS_ERROR_FORCE_PARENT_LAYER; + } + const auto dirHandle = getDirExFromHandle(handle); + if (dirHandle->realDirHandle != 0) { + if (mClientHandle) { + DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSCloseDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle); + auto realResult = FSACloseDir(mClientHandle, dirHandle->realDirHandle); + if (realResult == FS_ERROR_OK) { + dirHandle->realDirHandle = 0; + } else { + DEBUG_FUNCTION_LINE_ERR("[%s] Failed to close realDirHandle %d: res %s (%d)", getName().c_str(), dirHandle->realDirHandle, FSAGetStatusStr(realResult), realResult); + return realResult == FS_ERROR_CANCELLED ? FS_ERROR_CANCELLED : FS_ERROR_MEDIA_ERROR; + } + } else { + DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str()); + } + } else { + DEBUG_FUNCTION_LINE_VERBOSE("[%s] dirHandle->realDirHandle was 0", getName().c_str()); + } + dirHandle->entryRead = false; + dirHandle->entryReadSuccess = false; + + OSMemoryBarrier(); + return FS_ERROR_OK; +} + +FSError FSWrapperReplaceSingleFile::FSRewindDirWrapper(const FSADirectoryHandle handle) { + if (!isValidDirHandle(handle)) { + return FS_ERROR_FORCE_PARENT_LAYER; + } + const auto dirHandle = getDirExFromHandle(handle); + dirHandle->entryRead = false; + dirHandle->entryReadSuccess = false; + if (dirHandle->realDirHandle != 0) { + if (mClientHandle) { + DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSARewindDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle); + if (const FSError err = FSARewindDir(mClientHandle, dirHandle->realDirHandle); err != FS_ERROR_OK) { + DEBUG_FUNCTION_LINE_ERR("[%s] Failed to rewind dir for realDirHandle %08X. %s (%d)", getName().c_str(), dirHandle->realDirHandle, FSAGetStatusStr(err), err); + } + } else { + DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str()); + } + } else { + DEBUG_FUNCTION_LINE_VERBOSE("[%s] dirHandle->realDirHandle was 0", getName().c_str()); + } + OSMemoryBarrier(); + + return FS_ERROR_OK; +} + +bool FSWrapperReplaceSingleFile::SkipDeletedFilesInReadDir() { + return false; +} + +bool FSWrapperReplaceSingleFile::IsDirPathToReplace(const std::string_view &path) const { + return starts_with_case_insensitive(path, mPathToReplace); +} + +std::string FSWrapperReplaceSingleFile::GetNewPath(const std::string_view &path) const { + auto pathCpy = std::string(path); + SafeReplaceInString(pathCpy, this->mPathToReplace, this->mReplacedWithPath); + SafeReplaceInString(pathCpy, this->mFileNameToReplace, this->mReplacedWithFileName); + std::ranges::replace(pathCpy, '\\', '/'); + + uint32_t length = pathCpy.size(); + + //! clear path of double slashes + for (uint32_t i = 1; i < length; ++i) { + if (pathCpy[i - 1] == '/' && pathCpy[i] == '/') { + pathCpy.erase(i, 1); + i--; + length--; + } + } + + DEBUG_FUNCTION_LINE_VERBOSE("[%s] Redirect %.*s -> %s", getName().c_str(), int(path.length()), path.data(), pathCpy.c_str()); + return pathCpy; +} + +std::shared_ptr FSWrapperReplaceSingleFile::getDirExFromHandle(FSADirectoryHandle handle) { + auto dir = std::dynamic_pointer_cast(getDirFromHandle(handle)); + + if (!dir) { + DEBUG_FUNCTION_LINE_ERR("[%s] dynamic_pointer_cast(%08X) failed", getName().c_str(), handle); + OSFatal("ContentRedirectionModule: dynamic_pointer_cast failed"); + } + return dir; +} \ No newline at end of file diff --git a/src/FSWrapperReplaceSingleFile.h b/src/FSWrapperReplaceSingleFile.h new file mode 100644 index 0000000..c14dcf5 --- /dev/null +++ b/src/FSWrapperReplaceSingleFile.h @@ -0,0 +1,52 @@ +#pragma once +#include "DirInfoEx.h" +#include "FSWrapper.h" + +#include + +class FSWrapperReplaceSingleFile final : public FSWrapper { +public: + FSWrapperReplaceSingleFile(const std::string &name, + const std::string &fileToReplace, + const std::string &replaceWithPath, + bool fallbackOnError); + + ~FSWrapperReplaceSingleFile() override; + + FSError FSOpenDirWrapper(const char *path, + FSDirectoryHandle *handle) override; + + FSError FSReadDirWrapper(FSDirectoryHandle handle, + FSDirectoryEntry *entry) override; + + FSError FSCloseDirWrapper(FSDirectoryHandle handle) override; + + FSError FSRewindDirWrapper(FSDirectoryHandle handle) override; + + bool SkipDeletedFilesInReadDir() override; + + uint32_t getLayerId() override { + return static_cast(mClientHandle); + } + + +protected: + [[nodiscard]] std::string GetNewPath(const std::string_view &path) const override; + + std::shared_ptr getNewDirInfoHandle() override { + OSFatal("FSWrapperReplaceSingleFile::getNewDirInfoHandle. Not implemented"); + return {}; + } + +private: + bool IsDirPathToReplace(const std::string_view &path) const; + + std::shared_ptr getDirExFromHandle(FSDirectoryHandle handle); + + FSAClientHandle mClientHandle; + std::string mPathToReplace; + std::string mFileNameToReplace; + std::string mFullPathToReplace; + std::string mReplacedWithPath; + std::string mReplacedWithFileName; +}; diff --git a/src/export.cpp b/src/export.cpp index 363ca78..7bab400 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -6,6 +6,8 @@ #include "utils/StringTools.h" #include "utils/logger.h" #include "utils/utils.h" + +#include #include #include #include @@ -142,6 +144,46 @@ ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *l return CONTENT_REDIRECTION_API_ERROR_NO_MEMORY; } +ContentRedirectionApiErrorType CRAddFSLayerEx(CRLayerHandle *handle, const char *layerName, const char *targetPath, const char *replacementPath, const FSLayerTypeEx layerType) { + if (!handle || layerName == nullptr || replacementPath == nullptr || targetPath == nullptr) { + DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_INVALID_ARG"); + return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG; + } + std::unique_ptr ptr; + switch (layerType) { + case FS_LAYER_TYPE_EX_REPLACE_DIRECTORY: { + DEBUG_FUNCTION_LINE_INFO("[AddFSLayerEx] Redirecting \"%s\" to \"%s\", mode: \"replace\"", targetPath, replacementPath); + ptr = make_unique_nothrow(layerName, targetPath, replacementPath, false, false); + break; + } + case FS_LAYER_TYPE_EX_MERGE_DIRECTORY: { + DEBUG_FUNCTION_LINE_INFO("[AddFSLayerEx] Redirecting \"%s\" to \"%s\", mode: \"merge\"", targetPath, replacementPath); + ptr = make_unique_nothrow(layerName, targetPath, replacementPath, true); + break; + } + case FS_LAYER_TYPE_EX_REPLACE_FILE: { + DEBUG_FUNCTION_LINE_INFO("[AddFSLayerEx] Redirecting file \"%s\" to \"%s\"", targetPath, replacementPath); + ptr = make_unique_nothrow(layerName, targetPath, replacementPath, true); + break; + } + default: { + DEBUG_FUNCTION_LINE_ERR("[AddFSLayerEx] CONTENT_REDIRECTION_API_ERROR_UNKNOWN_LAYER_DIR_TYPE: %s %s %d", layerName, replacementPath, layerType); + return CONTENT_REDIRECTION_API_ERROR_UNKNOWN_FS_LAYER_TYPE; + } + } + + if (ptr) { + DEBUG_FUNCTION_LINE_VERBOSE("[AddFSLayerEx] Added new layer (%s). Target path: %s Replacement dir: %s Type:%d", layerName, targetPath, replacementPath, layerType); + std::lock_guard lock(gFSLayerMutex); + *handle = ptr->getHandle(); + gFSLayers.emplace_back(std::move(ptr)); + return CONTENT_REDIRECTION_API_ERROR_NONE; + } + DEBUG_FUNCTION_LINE_ERR("[AddFSLayerEx] Failed to allocate memory"); + return CONTENT_REDIRECTION_API_ERROR_NO_MEMORY; +} + + ContentRedirectionApiErrorType CRRemoveFSLayer(CRLayerHandle handle) { if (!remove_locked_first_if(gFSLayerMutex, gFSLayers, [handle](auto &cur) { return (CRLayerHandle) cur->getHandle() == handle; })) { DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle); @@ -167,7 +209,7 @@ ContentRedirectionApiErrorType CRGetVersion(ContentRedirectionVersion *outVersio if (outVersion == nullptr) { return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG; } - *outVersion = 1; + *outVersion = 2; return CONTENT_REDIRECTION_API_ERROR_NONE; } @@ -180,6 +222,7 @@ int CRRemoveDevice(const char *name) { } WUMS_EXPORT_FUNCTION(CRGetVersion); +WUMS_EXPORT_FUNCTION(CRAddFSLayerEx); WUMS_EXPORT_FUNCTION(CRAddFSLayer); WUMS_EXPORT_FUNCTION(CRRemoveFSLayer); WUMS_EXPORT_FUNCTION(CRSetActive);