From 270155ec9879b9ce24b6527ff0088e9ce36e0ee5 Mon Sep 17 00:00:00 2001 From: Maschell Date: Tue, 13 Jan 2026 20:01:45 +0100 Subject: [PATCH 01/12] Use std::recusive_mutex --- src/FSWrapper.cpp | 2 +- src/FSWrapper.h | 4 ++-- src/FileUtils.cpp | 8 ++++---- src/FileUtils.h | 2 +- src/utils/utils.h | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/FSWrapper.cpp b/src/FSWrapper.cpp index cc007a9..8b82f23 100644 --- a/src/FSWrapper.cpp +++ b/src/FSWrapper.cpp @@ -249,7 +249,7 @@ FSError FSWrapper::FSOpenFileWrapper(const char *path, const char *mode, FSFileH if (fd >= 0) { auto fileHandle = getNewFileHandle(); if (fileHandle) { - std::lock_guard lock(openFilesMutex); + std::lock_guard lock(openFilesMutex); fileHandle->handle = (((uint32_t) fileHandle.get()) & 0x0FFFFFFF) | 0x30000000; *handle = fileHandle->handle; diff --git a/src/FSWrapper.h b/src/FSWrapper.h index 84d5280..6163539 100644 --- a/src/FSWrapper.h +++ b/src/FSWrapper.h @@ -134,8 +134,8 @@ class FSWrapper : public IFSWrapper { std::string pPathToReplace; std::string pReplacePathWith; bool pIsWriteable = false; - std::mutex openFilesMutex; - std::mutex openDirsMutex; + std::recursive_mutex openFilesMutex; + std::recursive_mutex openDirsMutex; std::vector> openFiles; std::vector> openDirs; }; diff --git a/src/FileUtils.cpp b/src/FileUtils.cpp index ef23d62..bfce102 100644 --- a/src/FileUtils.cpp +++ b/src/FileUtils.cpp @@ -12,14 +12,14 @@ #include namespace { - std::mutex sWorkingDirMutex; + std::recursive_mutex sWorkingDirMutex; std::map sWorkingDirs; } // namespace -std::mutex gFSLayerMutex; +std::recursive_mutex gFSLayerMutex; std::vector> gFSLayers; -std::string getFullPathGeneric(const FSAClientHandle client, const char *path, std::mutex &mutex, const std::map &map) { +std::string getFullPathGeneric(const FSAClientHandle client, const char *path, std::recursive_mutex &mutex, const std::map &map) { std::lock_guard workingDirLock(mutex); std::string res; @@ -39,7 +39,7 @@ std::string getFullPathGeneric(const FSAClientHandle client, const char *path, s return res; } -void setWorkingDirGeneric(const FSAClientHandle client, const char *path, std::mutex &mutex, std::map &map) { +void setWorkingDirGeneric(const FSAClientHandle client, const char *path, std::recursive_mutex &mutex, std::map &map) { if (!path) { DEBUG_FUNCTION_LINE_WARN("Path was NULL"); return; diff --git a/src/FileUtils.h b/src/FileUtils.h index 5095d4a..36db017 100644 --- a/src/FileUtils.h +++ b/src/FileUtils.h @@ -55,7 +55,7 @@ struct FSShimWrapperMessage { extern bool gThreadsRunning; extern FSIOThreadData gThreadData[3]; -extern std::mutex gFSLayerMutex; +extern std::recursive_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)) diff --git a/src/utils/utils.h b/src/utils/utils.h index ef974ce..d35fbca 100644 --- a/src/utils/utils.h +++ b/src/utils/utils.h @@ -15,8 +15,8 @@ std::shared_ptr make_shared_nothrow(Args &&...args) noexcept(noexcept(T(std:: } template -bool remove_locked_first_if(std::mutex &mutex, std::vector &list, Predicate pred) { - std::lock_guard lock(mutex); +bool remove_locked_first_if(std::recursive_mutex &mutex, std::vector &list, Predicate pred) { + std::lock_guard lock(mutex); auto it = list.begin(); while (it != list.end()) { if (pred(*it)) { From 2d2100c79950a9a406b4035199e39a640b46f174 Mon Sep 17 00:00:00 2001 From: Maschell Date: Tue, 13 Jan 2026 20:02:07 +0100 Subject: [PATCH 02/12] Fix stack allocation test --- src/FileUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FileUtils.cpp b/src/FileUtils.cpp index bfce102..574321b 100644 --- a/src/FileUtils.cpp +++ b/src/FileUtils.cpp @@ -527,7 +527,7 @@ void startFSIOThreads() { continue; } threadData->stack = (uint8_t *) memalign(0x20, stackSize); - if (!threadData->thread) { + if (!threadData->stack) { free(threadData->thread); DEBUG_FUNCTION_LINE_ERR("Failed to allocate threadData stack"); OSFatal("ContentRedirectionModule: Failed to allocate IO Thread stack"); From 57da458fd83024f9e1583208fec3b64434019660 Mon Sep 17 00:00:00 2001 From: Maschell Date: Tue, 13 Jan 2026 20:16:19 +0100 Subject: [PATCH 03/12] Fix compiling with latest wut version --- Makefile | 2 +- src/FSWrapper.cpp | 26 +++++++++++++------------- src/FSWrapperMergeDirsWithParent.cpp | 6 +++--- src/FSWrapperReplaceSingleFile.cpp | 2 +- src/FileUtils.cpp | 8 ++++---- src/utils/utils.cpp | 2 +- 6 files changed, 23 insertions(+), 23 deletions(-) diff --git a/Makefile b/Makefile index c21d96f..da53d2b 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ INCLUDES := src #------------------------------------------------------------------------------- # options for code generation #------------------------------------------------------------------------------- -CFLAGS := -Wall -Wextra -Os -ffunction-sections\ +CFLAGS := -Wall -Werror -Wextra -Os -ffunction-sections\ $(MACHDEP) CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ diff --git a/src/FSWrapper.cpp b/src/FSWrapper.cpp index 8b82f23..f4a0989 100644 --- a/src/FSWrapper.cpp +++ b/src/FSWrapper.cpp @@ -75,7 +75,7 @@ FSError FSWrapper::FSReadDirWrapper(const FSDirectoryHandle handle, FSDirectoryE DIR *dir = dirHandle->dir; FSError result = FS_ERROR_END_OF_DIR; - DEBUG_FUNCTION_LINE_VERBOSE("[%s] readdir %08X (handle %08X)", getName().c_str(), dir, handle); + DEBUG_FUNCTION_LINE_VERBOSE("[%s] readdir %p (handle %08X)", getName().c_str(), dir, handle); do { errno = 0; struct dirent *entry_ = readdir(dir); @@ -128,7 +128,7 @@ FSError FSWrapper::FSReadDirWrapper(const FSDirectoryHandle handle, FSDirectoryE } else { auto err = errno; if (err != 0) { - DEBUG_FUNCTION_LINE_ERR("[%s] Failed to read dir %08X (handle %08X). errno %d (%s)", getName().c_str(), dir, handle, err, strerror(err)); + DEBUG_FUNCTION_LINE_ERR("[%s] Failed to read dir %p (handle %08X). errno %d (%s)", getName().c_str(), dir, handle, err, strerror(err)); result = FS_ERROR_MEDIA_ERROR; } } @@ -146,9 +146,9 @@ FSError FSWrapper::FSCloseDirWrapper(const FSDirectoryHandle handle) { DIR *dir = dirHandle->dir; FSError result = FS_ERROR_OK; - DEBUG_FUNCTION_LINE_VERBOSE("[%s] closedir %08X (handle %08X)", getName().c_str(), dir, handle); + DEBUG_FUNCTION_LINE_VERBOSE("[%s] closedir %p (handle %08X)", getName().c_str(), dir, handle); if (closedir(dir) < 0) { - DEBUG_FUNCTION_LINE_ERR("[%s] Failed to close dir %08X (handle %08X)", getName().c_str(), dir, handle); + DEBUG_FUNCTION_LINE_ERR("[%s] Failed to close dir %p (handle %08X)", getName().c_str(), dir, handle); result = FS_ERROR_MEDIA_ERROR; } dirHandle->dir = nullptr; @@ -164,7 +164,7 @@ FSError FSWrapper::FSRewindDirWrapper(const FSDirectoryHandle handle) { DIR *dir = dirHandle->dir; - DEBUG_FUNCTION_LINE_VERBOSE("[%s] rewinddir %08X (handle %08X)", getName().c_str(), dir, handle); + DEBUG_FUNCTION_LINE_VERBOSE("[%s] rewinddir %p (handle %08X)", getName().c_str(), dir, handle); rewinddir(dir); return FS_ERROR_OK; @@ -397,7 +397,7 @@ FSError FSWrapper::FSReadFileWrapper(void *buffer, const uint32_t size, const ui auto fileHandle = getFileFromHandle(handle); int real_fd = fileHandle->fd; - DEBUG_FUNCTION_LINE_VERBOSE("[%s] Read %u bytes of fd %08X (FSFileHandle %08X) to buffer %08X", getName().c_str(), size * count, real_fd, handle, buffer); + DEBUG_FUNCTION_LINE_VERBOSE("[%s] Read %u bytes of fd %08X (FSFileHandle %08X) to buffer %p", getName().c_str(), size * count, real_fd, handle, buffer); int64_t read = readIntoBuffer(real_fd, buffer, size, count); FSError result; @@ -468,7 +468,7 @@ FSError FSWrapper::FSGetPosFileWrapper(const FSFileHandle handle, uint32_t *pos) DEBUG_FUNCTION_LINE_VERBOSE("[%s] lseek fd %08X (FSFileHandle %08X) to get current position for truncation", getName().c_str(), real_fd, handle); off_t currentPos = lseek(real_fd, (off_t) 0, SEEK_CUR); if (currentPos == -1) { - DEBUG_FUNCTION_LINE_ERR("[%s] Failed to get current position (res: %lld) of fd (handle %08X) to check EoF", getName().c_str(), currentPos, real_fd, handle); + DEBUG_FUNCTION_LINE_ERR("[%s] Failed to get current position (res: %lld) of fd %08X (handle %08X) to check EoF", getName().c_str(), currentPos, real_fd, handle); result = FS_ERROR_MEDIA_ERROR; } else { *pos = currentPos; @@ -493,7 +493,7 @@ FSError FSWrapper::FSIsEofWrapper(const FSFileHandle handle) { if (currentPos == -1 || endPos == -1) { // TODO: check errno - DEBUG_FUNCTION_LINE_ERR("[%s] Failed to get current position (res: %lld) or endPos (res: %lld) of fd (handle %08X) to check EoF", getName().c_str(), currentPos, endPos, real_fd, handle); + DEBUG_FUNCTION_LINE_ERR("[%s] Failed to get current position (res: %lld) or endPos (res: %lld) of fd %08X (handle %08X) to check EoF", getName().c_str(), currentPos, endPos, real_fd, handle); result = FS_ERROR_MEDIA_ERROR; } else if (currentPos == endPos) { DEBUG_FUNCTION_LINE_VERBOSE("[%s] FSIsEof END for %d\n", getName().c_str(), real_fd); @@ -512,7 +512,7 @@ FSError FSWrapper::FSTruncateFileWrapper(const FSFileHandle handle) { return FS_ERROR_FORCE_PARENT_LAYER; } - if (!pIsWriteable) { + if (pIsWriteable) { DEBUG_FUNCTION_LINE_VERBOSE("[%s] Tried to truncate fd %d (handle %08X) but layer is not writeable", getName().c_str(), getFileFromHandle(handle)->fd, handle); return FS_ERROR_ACCESS_ERROR; } @@ -527,7 +527,7 @@ FSError FSWrapper::FSTruncateFileWrapper(const FSFileHandle handle) { off_t currentPos = lseek(real_fd, (off_t) 0, SEEK_CUR); if (currentPos == -1) { // TODO check errno - DEBUG_FUNCTION_LINE_ERR("[%s] Failed to get current position of fd (handle %08X) to truncate file", getName().c_str(), real_fd, handle); + DEBUG_FUNCTION_LINE_ERR("[%s] Failed to get current position of fd %08X (handle %08X) to truncate file", getName().c_str(), real_fd, handle); result = FS_ERROR_MEDIA_ERROR; } else { DEBUG_FUNCTION_LINE_VERBOSE("[%s] Truncate fd %08X (FSFileHandle %08X) to %lld bytes ", getName().c_str(), real_fd, handle, currentPos); @@ -554,11 +554,11 @@ FSError FSWrapper::FSWriteFileWrapper(const uint8_t *buffer, const uint32_t size int real_fd = fileHandle->fd; - DEBUG_FUNCTION_LINE_VERBOSE("[%s] Write %u bytes to fd %08X (FSFileHandle %08X) from buffer %08X", getName().c_str(), count * size, real_fd, handle, buffer); + DEBUG_FUNCTION_LINE_VERBOSE("[%s] Write %u bytes to fd %08X (FSFileHandle %08X) from buffer %p", getName().c_str(), count * size, real_fd, handle, buffer); auto writeRes = writeFromBuffer(real_fd, buffer, size, count); if (writeRes < 0) { auto err = errno; - DEBUG_FUNCTION_LINE_ERR("[%s] Write failed %u bytes to fd %08X (FSFileHandle %08X) from buffer %08X errno %d", getName().c_str(), count * size, real_fd, handle, buffer, err); + DEBUG_FUNCTION_LINE_ERR("[%s] Write failed %u bytes to fd %08X (FSFileHandle %08X) from buffer %p errno %d", getName().c_str(), count * size, real_fd, handle, buffer, err); if (err == EFBIG) { result = FS_ERROR_FILE_TOO_BIG; } else if (err == EACCES) { @@ -640,7 +640,7 @@ FSError FSWrapper::FSFlushFileWrapper(const FSFileHandle handle) { const auto fileHandle = getFileFromHandle(handle); const int real_fd = fileHandle->fd; - DEBUG_FUNCTION_LINE_VERBOSE("[%s] fsync fd %08X (FSFileHandle %08X)", real_fd, handle); + DEBUG_FUNCTION_LINE_VERBOSE("[%s] fsync fd %08X (FSFileHandle %08X)", getName().c_str(), real_fd, handle); FSError result = FS_ERROR_OK; if (fsync(real_fd) < 0) { DEBUG_FUNCTION_LINE_ERR("[%s] fsync failed for fd %08X (FSFileHandle %08X)", getName().c_str(), real_fd, handle); diff --git a/src/FSWrapperMergeDirsWithParent.cpp b/src/FSWrapperMergeDirsWithParent.cpp index 9a2bc91..7c746e1 100644 --- a/src/FSWrapperMergeDirsWithParent.cpp +++ b/src/FSWrapperMergeDirsWithParent.cpp @@ -68,7 +68,7 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSADirectoryHandle handle if (dirHandle->readResultCapacity == 0) { dirHandle->readResult = (FSDirectoryEntryEx *) malloc(sizeof(FSDirectoryEntryEx)); if (dirHandle->readResult == nullptr) { - DEBUG_FUNCTION_LINE_ERR("[%s] Failed to alloc memory for %08X (handle %08X)", getName().c_str(), dirHandle.get(), handle); + DEBUG_FUNCTION_LINE_ERR("[%s] Failed to alloc memory for %p (handle %08X)", getName().c_str(), dirHandle.get(), handle); OSFatal("ContentRedirectionModule: Failed to alloc memory for read result"); } dirHandle->readResultCapacity = 1; @@ -79,7 +79,7 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSADirectoryHandle handle dirHandle->readResult = (FSDirectoryEntryEx *) realloc(dirHandle->readResult, newCapacity * sizeof(FSDirectoryEntryEx)); dirHandle->readResultCapacity = newCapacity; if (dirHandle->readResult == nullptr) { - DEBUG_FUNCTION_LINE_ERR("[%s] Failed to realloc memory for %08X (handle %08X)", getName().c_str(), dirHandle.get(), handle); + DEBUG_FUNCTION_LINE_ERR("[%s] Failed to realloc memory for %p (handle %08X)", getName().c_str(), dirHandle.get(), handle); OSFatal("ContentRedirectionModule: Failed to alloc memory for read result"); } } @@ -242,7 +242,7 @@ FSWrapperMergeDirsWithParent::~FSWrapperMergeDirsWithParent() { if (mClientHandle) { FSError res; if ((res = FSADelClient(mClientHandle)) != FS_ERROR_OK) { - DEBUG_FUNCTION_LINE_ERR("[%s] FSADelClient failed: %s (%d)", FSAGetStatusStr(res), res); + DEBUG_FUNCTION_LINE_ERR("[%s] FSADelClient failed: %s (%d)", pName.c_str(), FSAGetStatusStr(res), res); } mClientHandle = 0; } diff --git a/src/FSWrapperReplaceSingleFile.cpp b/src/FSWrapperReplaceSingleFile.cpp index 640ce9d..f62ede5 100644 --- a/src/FSWrapperReplaceSingleFile.cpp +++ b/src/FSWrapperReplaceSingleFile.cpp @@ -41,7 +41,7 @@ FSWrapperReplaceSingleFile::FSWrapperReplaceSingleFile(const std::string &name, 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); + DEBUG_FUNCTION_LINE_ERR("[%s] FSADelClient failed: %s (%d)", pName.c_str(), FSAGetStatusStr(res), res); } mClientHandle = 0; } diff --git a/src/FileUtils.cpp b/src/FileUtils.cpp index 574321b..f678b4d 100644 --- a/src/FileUtils.cpp +++ b/src/FileUtils.cpp @@ -209,10 +209,10 @@ FSError doForLayer(FSShimWrapper *param) { auto *request = ¶m->shim->request.readFile; if (request->readFlags == FSA_READ_FLAG_NONE) { - DEBUG_FUNCTION_LINE_VERBOSE("[%s] ReadFile: buffer %08X size %08X count %08X handle %08X", layer->getName().c_str(), request->buffer, request->size, request->count, request->handle); + DEBUG_FUNCTION_LINE_VERBOSE("[%s] ReadFile: buffer %p size %08X count %08X handle %08X", layer->getName().c_str(), request->buffer, request->size, request->count, request->handle); layerResult = layer->FSReadFileWrapper(request->buffer, request->size, request->count, request->handle, 0); } else if (request->readFlags == FSA_READ_FLAG_READ_WITH_POS) { - DEBUG_FUNCTION_LINE_VERBOSE("[%s] ReadFileWithPos: buffer %08X size %08X count %08X pos %08X handle %08X", layer->getName().c_str(), request->buffer, request->size, request->count, request->pos, request->handle); + DEBUG_FUNCTION_LINE_VERBOSE("[%s] ReadFileWithPos: buffer %p size %08X count %08X pos %08X handle %08X", layer->getName().c_str(), request->buffer, request->size, request->count, request->pos, request->handle); layerResult = layer->FSReadFileWithPosWrapper(request->buffer, request->size, request->count, request->pos, request->handle, 0); } break; @@ -250,10 +250,10 @@ FSError doForLayer(FSShimWrapper *param) { auto *request = ¶m->shim->request.writeFile; if (request->writeFlags == FSA_WRITE_FLAG_NONE) { - DEBUG_FUNCTION_LINE_VERBOSE("[%s] WriteFile: buffer %08X size %08X count %08X handle %08X", layer->getName().c_str(), request->buffer, request->size, request->count, request->handle); + DEBUG_FUNCTION_LINE_VERBOSE("[%s] WriteFile: buffer %p size %08X count %08X handle %08X", layer->getName().c_str(), request->buffer, request->size, request->count, request->handle); layerResult = layer->FSWriteFileWrapper(request->buffer, request->size, request->count, request->handle, 0); } else if (request->writeFlags == FSA_WRITE_FLAG_READ_WITH_POS) { - DEBUG_FUNCTION_LINE_VERBOSE("[%s] WriteFileWithPos: buffer %08X size %08X count %08X pos %08X handle %08X", layer->getName().c_str(), request->buffer, request->size, request->count, request->pos, request->handle); + DEBUG_FUNCTION_LINE_VERBOSE("[%s] WriteFileWithPos: buffer %p size %08X count %08X pos %08X handle %08X", layer->getName().c_str(), request->buffer, request->size, request->count, request->pos, request->handle); layerResult = layer->FSWriteFileWithPosWrapper(request->buffer, request->size, request->count, request->pos, request->handle, 0); } break; diff --git a/src/utils/utils.cpp b/src/utils/utils.cpp index b141d9f..6d9b876 100644 --- a/src/utils/utils.cpp +++ b/src/utils/utils.cpp @@ -12,7 +12,7 @@ void dumpHex(const void *data, size_t size) { char ascii[17]; size_t i, j; ascii[16] = '\0'; - DEBUG_FUNCTION_LINE("0x%08X (0x0000): ", data); + DEBUG_FUNCTION_LINE("0x%p (0x0000): ", data); for (i = 0; i < size; ++i) { WHBLogWritef("%02X ", ((unsigned char *) data)[i]); if (((unsigned char *) data)[i] >= ' ' && ((unsigned char *) data)[i] <= '~') { From 71b4f9de4163505463368ce1b286d78ba9a718f1 Mon Sep 17 00:00:00 2001 From: Maschell Date: Wed, 18 Mar 2026 20:28:58 +0100 Subject: [PATCH 04/12] Update Dockerfile --- Dockerfile | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index f15b2d9..1127b2f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ -FROM ghcr.io/wiiu-env/devkitppc:20241128 +FROM ghcr.io/wiiu-env/devkitppc:20260225 -COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20230621 /artifacts $DEVKITPRO -COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20250208 /artifacts $DEVKITPRO -COPY --from=ghcr.io/wiiu-env/libcontentredirection:20250208 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20260208 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20260225 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/libcontentredirection:20260131 /artifacts $DEVKITPRO WORKDIR project From 85c480201be3bdda173695fdcfda39ea10543fa5 Mon Sep 17 00:00:00 2001 From: Maschell Date: Sun, 29 Mar 2026 20:47:58 +0200 Subject: [PATCH 05/12] Update Dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 1127b2f..43a30b8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,6 +2,6 @@ FROM ghcr.io/wiiu-env/devkitppc:20260225 COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20260208 /artifacts $DEVKITPRO COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20260225 /artifacts $DEVKITPRO -COPY --from=ghcr.io/wiiu-env/libcontentredirection:20260131 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/libcontentredirection:20260329 /artifacts $DEVKITPRO WORKDIR project From 38a991441270b0aa6444e7931b6edb906e18138a Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 3 Apr 2026 14:00:43 +0200 Subject: [PATCH 06/12] Implement support for adding devices via ContentRedirectionDeviceABI instead of devoptab_t --- Dockerfile | 6 +- src/export.cpp | 49 ++- src/main.cpp | 1 - src/utils/DevoptabTrampoline.cpp | 662 +++++++++++++++++++++++++++++++ src/utils/DevoptabTrampoline.h | 25 ++ 5 files changed, 736 insertions(+), 7 deletions(-) create mode 100644 src/utils/DevoptabTrampoline.cpp create mode 100644 src/utils/DevoptabTrampoline.h diff --git a/Dockerfile b/Dockerfile index 43a30b8..c12eb7f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM ghcr.io/wiiu-env/devkitppc:20260225 -COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20260208 /artifacts $DEVKITPRO -COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20260225 /artifacts $DEVKITPRO -COPY --from=ghcr.io/wiiu-env/libcontentredirection:20260329 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20260331 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:reentfix-dev-20260403-5ca1144 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/libcontentredirection:abisafe-dev-20260403-502a496 /artifacts $DEVKITPRO WORKDIR project diff --git a/src/export.cpp b/src/export.cpp index 7bab400..d9ea4d4 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -3,6 +3,7 @@ #include "FileUtils.h" #include "IFSWrapper.h" #include "malloc.h" +#include "utils/DevoptabTrampoline.h" #include "utils/StringTools.h" #include "utils/logger.h" #include "utils/utils.h" @@ -10,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -209,22 +211,63 @@ ContentRedirectionApiErrorType CRGetVersion(ContentRedirectionVersion *outVersio if (outVersion == nullptr) { return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG; } - *outVersion = 2; + *outVersion = 3; return CONTENT_REDIRECTION_API_ERROR_NONE; } int CRAddDevice(const devoptab_t *device) { + DEBUG_FUNCTION_LINE_WARN("Usage of deprecated \"CRAddDevice\" API detected. Please use latest libcontentredirection."); return AddDevice(device); } int CRRemoveDevice(const char *name) { + DEBUG_FUNCTION_LINE_WARN("Usage deprecated \"CRRemoveDevice\" API. Please use latest libcontentredirection."); return RemoveDevice(name); } +ContentRedirectionApiErrorType CRAddDeviceABI(const ContentRedirectionDeviceABI *device, int *resultOut) { + if (!device || device->magic != CONTENT_REDIRECTION_DEVICE_MAGIC || device->version < CONTENT_REDIRECTION_DEVICE_VERSION || !resultOut) { + return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG; + } + + const auto *host_dev = DevoptabTrampoline::CreateDevoptab(device); + if (!host_dev) { + return CONTENT_REDIRECTION_API_ERROR_NO_MEMORY; + } + + *resultOut = AddDevice(host_dev); + + if (*resultOut < 0) { + DevoptabTrampoline::ClearDevoptab(host_dev); + } + + return CONTENT_REDIRECTION_API_ERROR_NONE; +} + +ContentRedirectionApiErrorType CRRemoveDeviceABI(const char *device_name, int *resultOut) { + if (!device_name || !resultOut) { + return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG; + } + + if (!DevoptabTrampoline::RemoveDevoptab(device_name, resultOut)) { + *resultOut = -1; + return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG; + } + + return CONTENT_REDIRECTION_API_ERROR_NONE; +} + +// API Version 1 WUMS_EXPORT_FUNCTION(CRGetVersion); -WUMS_EXPORT_FUNCTION(CRAddFSLayerEx); WUMS_EXPORT_FUNCTION(CRAddFSLayer); WUMS_EXPORT_FUNCTION(CRRemoveFSLayer); WUMS_EXPORT_FUNCTION(CRSetActive); WUMS_EXPORT_FUNCTION(CRAddDevice); -WUMS_EXPORT_FUNCTION(CRRemoveDevice); \ No newline at end of file +WUMS_EXPORT_FUNCTION(CRRemoveDevice); + +// API Version 2 +WUMS_EXPORT_FUNCTION(CRAddFSLayerEx); + +// API Version 3 +WUMS_EXPORT_FUNCTION(CRAddDeviceABI); +WUMS_EXPORT_FUNCTION(CRRemoveDeviceABI); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index ae44993..32b5b07 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,6 @@ #include "FSAReplacements.h" #include "FSReplacements.h" #include "FileUtils.h" -#include "utils/StringTools.h" #include "utils/logger.h" #include "version.h" #include diff --git a/src/utils/DevoptabTrampoline.cpp b/src/utils/DevoptabTrampoline.cpp new file mode 100644 index 0000000..b75ad38 --- /dev/null +++ b/src/utils/DevoptabTrampoline.cpp @@ -0,0 +1,662 @@ + +#include "logger.h" + + +#include + +#include + +#include +#include +#include +#include + +namespace DevoptabTrampoline { + constexpr int MAX_REDIRECTION_DEVICES = STD_MAX - 3; + + struct RedirectionDeviceSlot { + bool inUse = false; + devoptab_t hostDevoptab = {}; + ContentRedirectionDeviceABI device = {}; + }; + + std::array sDevices; + std::recursive_mutex sDevicesMutex; + + + inline void convert(struct stat *dst, const CR_Stat *src) { + if (!dst || !src) return; + dst->st_dev = src->dev; + dst->st_ino = src->ino; + dst->st_mode = src->mode; + dst->st_nlink = src->nlink; + dst->st_uid = src->uid; + dst->st_gid = src->gid; + dst->st_rdev = src->rdev; + dst->st_size = (off_t) src->size; + dst->st_atime = (time_t) src->atime; + dst->st_mtime = (time_t) src->mtime; + dst->st_ctime = (time_t) src->ctime; + dst->st_blksize = src->blksize; + dst->st_blocks = src->blocks; + } + + inline void convert(struct statvfs *dst, const CR_Statvfs *src) { + if (!dst || !src) return; + dst->f_bsize = src->bsize; + dst->f_frsize = src->frsize; + dst->f_blocks = src->blocks; + dst->f_bfree = src->bfree; + dst->f_bavail = src->bavail; + dst->f_files = src->files; + dst->f_ffree = src->ffree; + dst->f_favail = src->favail; + dst->f_fsid = src->fsid; + dst->f_flag = src->flag; + dst->f_namemax = src->namemax; + } + + static int open_r(_reent *r, void *fileStruct, const char *path, int flags, int mode) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.open) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.open(slot->device.deviceData, fileStruct, path, flags, (uint32_t) mode); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static int close_r(_reent *r, void *fd) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.close) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.close(slot->device.deviceData, fd); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static ssize_t write_r(_reent *r, void *fd, const char *ptr, size_t len) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.write) { + r->_errno = ENOSYS; + return -1; + } + + const ssize_t res = slot->device.write(slot->device.deviceData, fd, ptr, len); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static ssize_t read_r(_reent *r, void *fd, char *ptr, size_t len) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.read) { + r->_errno = ENOSYS; + return -1; + } + + const ssize_t res = slot->device.read(slot->device.deviceData, fd, ptr, len); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static off_t seek_r(_reent *r, void *fd, off_t pos, int dir) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.seek) { + r->_errno = ENOSYS; + return -1; + } + + const int64_t res = slot->device.seek(slot->device.deviceData, fd, (int64_t) pos, dir); + + if (res < 0) { + r->_errno = -(int) res; + return -1; + } + return (off_t) res; + } + + static int fstat_r(_reent *r, void *fd, struct stat *st) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.fstat) { + r->_errno = ENOSYS; + return -1; + } + + CR_Stat abstract_st{}; + const int res = slot->device.fstat(slot->device.deviceData, fd, &abstract_st); + + if (res < 0) { + r->_errno = -res; + return -1; + } + convert(st, &abstract_st); + return res; + } + + static int stat_r(_reent *r, const char *file, struct stat *st) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.stat) { + r->_errno = ENOSYS; + return -1; + } + + CR_Stat abstract_st{}; + const int res = slot->device.stat(slot->device.deviceData, file, &abstract_st); + + if (res < 0) { + r->_errno = -res; + return -1; + } + convert(st, &abstract_st); + return res; + } + + static int link_r(_reent *r, const char *existing, const char *newLink) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.link) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.link(slot->device.deviceData, existing, newLink); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static int unlink_r(_reent *r, const char *name) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.unlink) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.unlink(slot->device.deviceData, name); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static int chdir_r(_reent *r, const char *name) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.chdir) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.chdir(slot->device.deviceData, name); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static int rename_r(_reent *r, const char *oldName, const char *newName) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.rename) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.rename(slot->device.deviceData, oldName, newName); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static int mkdir_r(_reent *r, const char *path, int mode) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.mkdir) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.mkdir(slot->device.deviceData, path, (uint32_t) mode); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static DIR_ITER *diropen_r(_reent *r, DIR_ITER *dirState, const char *path) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.diropen) { + r->_errno = ENOSYS; + return nullptr; + } + + const int res = slot->device.diropen(slot->device.deviceData, dirState->dirStruct, path); + + if (res < 0) { + r->_errno = -res; + return nullptr; + } + return dirState; + } + + static int dirreset_r(_reent *r, DIR_ITER *dirState) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.dirreset) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.dirreset(slot->device.deviceData, dirState->dirStruct); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static int dirnext_r(_reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.dirnext) { + r->_errno = ENOSYS; + return -1; + } + + CR_Stat abstract_st{}; + const int res = slot->device.dirnext(slot->device.deviceData, dirState->dirStruct, filename, &abstract_st); + + if (res < 0) { + r->_errno = -res; + return -1; + } + convert(filestat, &abstract_st); + return res; + } + + static int dirclose_r(_reent *r, DIR_ITER *dirState) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.dirclose) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.dirclose(slot->device.deviceData, dirState->dirStruct); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static int statvfs_r(_reent *r, const char *path, struct statvfs *buf) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.statvfs) { + r->_errno = ENOSYS; + return -1; + } + + CR_Statvfs abstract_buf{}; + const int res = slot->device.statvfs(slot->device.deviceData, path, &abstract_buf); + + if (res < 0) { + r->_errno = -res; + return -1; + } + convert(buf, &abstract_buf); + return res; + } + + static int ftruncate_r(_reent *r, void *fd, off_t len) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.ftruncate) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.ftruncate(slot->device.deviceData, fd, (int64_t) len); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static int fsync_r(_reent *r, void *fd) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.fsync) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.fsync(slot->device.deviceData, fd); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static int chmod_r(_reent *r, const char *path, mode_t mode) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.chmod) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.chmod(slot->device.deviceData, path, (uint32_t) mode); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static int fchmod_r(_reent *r, void *fd, mode_t mode) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.fchmod) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.fchmod(slot->device.deviceData, fd, (uint32_t) mode); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static int rmdir_r(_reent *r, const char *name) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.rmdir) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.rmdir(slot->device.deviceData, name); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static int lstat_r(_reent *r, const char *file, struct stat *st) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.lstat) { + r->_errno = ENOSYS; + return -1; + } + + CR_Stat abstract_st{}; + const int res = slot->device.lstat(slot->device.deviceData, file, &abstract_st); + + if (res < 0) { + r->_errno = -res; + return -1; + } + convert(st, &abstract_st); + return res; + } + + static int utimes_r(_reent *r, const char *filename, const struct timeval times[2]) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.utimes) { + r->_errno = ENOSYS; + return -1; + } + + int res; + if (times) { + CR_Timeval cr_times[2]; + cr_times[0].tv_sec = times[0].tv_sec; + cr_times[0].tv_usec = times[0].tv_usec; + cr_times[1].tv_sec = times[1].tv_sec; + cr_times[1].tv_usec = times[1].tv_usec; + res = slot->device.utimes(slot->device.deviceData, filename, cr_times); + } else { + res = slot->device.utimes(slot->device.deviceData, filename, nullptr); + } + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static long fpathconf_r(_reent *r, void *fd, int name) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.fpathconf) { + r->_errno = ENOSYS; + return -1; + } + + const int64_t res = slot->device.fpathconf(slot->device.deviceData, fd, name); + + if (res < 0) { + r->_errno = -(int) res; + return -1; + } + return (long) res; + } + + static long pathconf_r(_reent *r, const char *path, int name) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.pathconf) { + r->_errno = ENOSYS; + return -1; + } + + const int64_t res = slot->device.pathconf(slot->device.deviceData, path, name); + + if (res < 0) { + r->_errno = -(int) res; + return -1; + } + return (long) res; + } + + static int symlink_r(_reent *r, const char *target, const char *linkpath) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.symlink) { + r->_errno = ENOSYS; + return -1; + } + + const int res = slot->device.symlink(slot->device.deviceData, target, linkpath); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static ssize_t readlink_r(_reent *r, const char *path, char *buf, size_t bufsiz) { + const auto *slot = static_cast(r->deviceData); + if (!slot || !slot->device.readlink) { + r->_errno = ENOSYS; + return -1; + } + + const ssize_t res = slot->device.readlink(slot->device.deviceData, path, buf, bufsiz); + + if (res < 0) { + r->_errno = -res; + return -1; + } + return res; + } + + static void assign(devoptab_t *dev) { + dev->open_r = open_r; + dev->close_r = close_r; + dev->write_r = write_r; + dev->read_r = read_r; + dev->seek_r = seek_r; + dev->fstat_r = fstat_r; + dev->stat_r = stat_r; + dev->link_r = link_r; + dev->unlink_r = unlink_r; + dev->chdir_r = chdir_r; + dev->rename_r = rename_r; + dev->mkdir_r = mkdir_r; + dev->diropen_r = diropen_r; + dev->dirreset_r = dirreset_r; + dev->dirnext_r = dirnext_r; + dev->dirclose_r = dirclose_r; + dev->statvfs_r = statvfs_r; + dev->ftruncate_r = ftruncate_r; + dev->fsync_r = fsync_r; + dev->chmod_r = chmod_r; + dev->fchmod_r = fchmod_r; + dev->rmdir_r = rmdir_r; + dev->lstat_r = lstat_r; + dev->utimes_r = utimes_r; + dev->fpathconf_r = fpathconf_r; + dev->pathconf_r = pathconf_r; + dev->symlink_r = symlink_r; + dev->readlink_r = readlink_r; + } + + devoptab_t *CreateDevoptab(const ContentRedirectionDeviceABI *device) { + if (!device || + device->magic != CONTENT_REDIRECTION_DEVICE_MAGIC || + device->version != CONTENT_REDIRECTION_DEVICE_VERSION) { + return nullptr; + } + + std::lock_guard lock(sDevicesMutex); + + int slot = -1; + for (int i = 0; i < MAX_REDIRECTION_DEVICES; i++) { + if (!sDevices[i].inUse) { + slot = i; + sDevices[i].inUse = true; + break; + } + } + + if (slot == -1) { + return nullptr; + } + + sDevices[slot].device = *device; + + devoptab_t *host_dev = &sDevices[slot].hostDevoptab; + *host_dev = {}; + + host_dev->name = strdup(device->name); + if (!host_dev->name) { + sDevices[slot].inUse = false; + return nullptr; + } + + host_dev->structSize = device->structSize; + host_dev->dirStateSize = device->dirStateSize; + + host_dev->deviceData = &sDevices[slot]; + + assign(host_dev); + + return host_dev; + } + + void ClearDevoptab(const devoptab_t *devoptab) { + if (!devoptab) { + return; + } + + std::lock_guard lock(sDevicesMutex); + + for (size_t i = 0; i < MAX_REDIRECTION_DEVICES; i++) { + if (sDevices[i].inUse && &sDevices[i].hostDevoptab == devoptab) { + if (sDevices[i].hostDevoptab.name) { + free((void *) sDevices[i].hostDevoptab.name); + } + + sDevices[i].inUse = false; + + sDevices[i].hostDevoptab = {}; + sDevices[i].device = {}; + break; + } + } + } + + bool RemoveDevoptab(const char *deviceName, int *resultOut) { + if (!deviceName || !resultOut) { + return false; + } + + DEBUG_FUNCTION_LINE_INFO("Trying to remove devoptab \"%s\"", deviceName); + + const char *separator = strchr(deviceName, ':'); + size_t requested_len = (separator != nullptr) ? (separator - deviceName) : strlen(deviceName); + + std::lock_guard lock(sDevicesMutex); + for (size_t i = 0; i < MAX_REDIRECTION_DEVICES; i++) { + if (sDevices[i].inUse && + sDevices[i].hostDevoptab.name) { + + size_t namelen = strlen(sDevices[i].hostDevoptab.name); + + if (requested_len == namelen) { + if (strncmp(sDevices[i].hostDevoptab.name, deviceName, requested_len) == 0) { + char device_with_colon[64] = {}; + + strncpy(device_with_colon, deviceName, sizeof(device_with_colon) - 2); + strncat(device_with_colon, ":", sizeof(device_with_colon) - strlen(device_with_colon) - 1); + + // Remove Device first because clearing will make it invalid instead. + *resultOut = ::RemoveDevice(device_with_colon); + + ClearDevoptab(&sDevices[i].hostDevoptab); + + return true; + } + } + } + } + + DEBUG_FUNCTION_LINE_WARN("Removing devoptab \"%s\" failed. Not found", deviceName); + + return false; + } +} // namespace DevoptabTrampoline \ No newline at end of file diff --git a/src/utils/DevoptabTrampoline.h b/src/utils/DevoptabTrampoline.h new file mode 100644 index 0000000..54fc5f8 --- /dev/null +++ b/src/utils/DevoptabTrampoline.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +namespace DevoptabTrampoline { + /** + * @brief Takes an ABI device definition, allocates a trampoline slot, and returns a fully wired devoptab_t. + * * Does NOT call AddDevice + * @return A pointer to the configured devoptab_t, or nullptr if validation fails or no slots are available. + */ + devoptab_t *CreateDevoptab(const ContentRedirectionDeviceABI *device); + + /** + * @brief Clears a devoptab to mark it as unused. + */ + void ClearDevoptab(const devoptab_t *devoptab); + + /** + * @brief Removes an device by name if existing. + * Does call RemoveDevice + * @return true if device with name was found, false no device was found. Check resultOut when true was returned. + */ + bool RemoveDevoptab(const char *deviceName, int *resultOut); +} // namespace DevoptabTrampoline \ No newline at end of file From 843ca20bdf4de4eeec3d9d4d7099a89466cd9281 Mon Sep 17 00:00:00 2001 From: Maschell Date: Mon, 6 Apr 2026 10:37:58 +0200 Subject: [PATCH 07/12] Compile with O2 instead of Os --- Makefile | 2 +- src/FSWrapper.cpp | 2 +- src/FSWrapperReplaceSingleFile.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index da53d2b..e38f609 100644 --- a/Makefile +++ b/Makefile @@ -29,7 +29,7 @@ INCLUDES := src #------------------------------------------------------------------------------- # options for code generation #------------------------------------------------------------------------------- -CFLAGS := -Wall -Werror -Wextra -Os -ffunction-sections\ +CFLAGS := -Wall -Werror -Wextra -O2 -ffunction-sections\ $(MACHDEP) CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ diff --git a/src/FSWrapper.cpp b/src/FSWrapper.cpp index f4a0989..8ae9801 100644 --- a/src/FSWrapper.cpp +++ b/src/FSWrapper.cpp @@ -86,7 +86,7 @@ FSError FSWrapper::FSReadDirWrapper(const FSDirectoryHandle handle, FSDirectoryE continue; } entry->name[0] = '\0'; - strncat(entry->name, entry_->d_name, sizeof(entry->name) - 1); + strlcpy(entry->name, entry_->d_name, sizeof(entry->name)); entry->info.mode = (FSMode) FS_MODE_READ_OWNER; if (entry_->d_type == DT_DIR) { entry->info.flags = (FSStatFlags) ((uint32_t) FS_STAT_DIRECTORY); diff --git a/src/FSWrapperReplaceSingleFile.cpp b/src/FSWrapperReplaceSingleFile.cpp index f62ede5..3a27bb8 100644 --- a/src/FSWrapperReplaceSingleFile.cpp +++ b/src/FSWrapperReplaceSingleFile.cpp @@ -115,7 +115,7 @@ FSError FSWrapperReplaceSingleFile::FSReadDirWrapper(const FSADirectoryHandle ha continue; } translate_stat(&path_stat, &dirHandle->directoryEntry.info); - strncpy(dirHandle->directoryEntry.name, mFileNameToReplace.c_str(), sizeof(dirHandle->directoryEntry.name)); + strncpy(dirHandle->directoryEntry.name, mFileNameToReplace.c_str(), sizeof(dirHandle->directoryEntry.name) - 1); memcpy(entry, &dirHandle->directoryEntry, sizeof(FSADirectoryEntry)); dirHandle->entryReadSuccess = true; From 98c4ee0be988e181532bcafcaf44f14b3661a5a4 Mon Sep 17 00:00:00 2001 From: Maschell Date: Mon, 6 Apr 2026 10:38:29 +0200 Subject: [PATCH 08/12] Add support for colored logging --- src/utils/logger.h | 39 ++++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/src/utils/logger.h b/src/utils/logger.h index 14c5db6..562bc43 100644 --- a/src/utils/logger.h +++ b/src/utils/logger.h @@ -8,19 +8,24 @@ extern "C" { #endif -#define LOG_APP_TYPE "M" -#define LOG_APP_NAME "content_redirect" +#define LOG_APP_TYPE "M" +#define LOG_APP_NAME "content_redirect" -#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) -#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) +#define __FILENAME_X__ (strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__) +#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILENAME_X__) -#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX_DEFAULT(LOG_FUNC, "", "", FMT, ##ARGS) +#define LOG(LOG_FUNC, FMT, ARGS...) LOG_EX_DEFAULT(LOG_FUNC, "", "", "", FMT, ##ARGS) -#define LOG_EX_DEFAULT(LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) LOG_EX(__FILENAME__, __FUNCTION__, __LINE__, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ##ARGS) +#define CONSOLE_COLOR_RED "\033[31m" +#define CONSOLE_COLOR_YELLOW "\033[33m" +#define CONSOLE_COLOR_CYAN "\033[36m" +#define CONSOLE_COLOR_RESET "\033[0m" -#define LOG_EX(FILENAME, FUNCTION, LINE, LOG_FUNC, LOG_LEVEL, LINE_END, FMT, ARGS...) \ - do { \ - LOG_FUNC("[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, FILENAME, FUNCTION, LINE, ##ARGS); \ +#define LOG_EX_DEFAULT(LOG_FUNC, LOG_COLOR, LOG_LEVEL, LINE_END, FMT, ARGS...) LOG_EX(__FILENAME__, __FUNCTION__, __LINE__, LOG_FUNC, LOG_COLOR, LOG_LEVEL, LINE_END, FMT, ##ARGS) + +#define LOG_EX(FILENAME, FUNCTION, LINE, LOG_FUNC, LOG_COLOR, LOG_LEVEL, LINE_END, FMT, ARGS...) \ + do { \ + LOG_FUNC(LOG_COLOR "[(%s)%18s][%23s]%30s@L%04d: " LOG_LEVEL "" FMT "" LINE_END, LOG_APP_TYPE, LOG_APP_NAME, FILENAME, FUNCTION, LINE, ##ARGS); \ } while (0) #ifdef DEBUG @@ -37,11 +42,11 @@ extern "C" { #define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) LOG(WHBLogWritef, FMT, ##ARGS) -#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS) -#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##WARN ## ", "", FMT, ##ARGS) -#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, "##INFO ## ", "", FMT, ##ARGS) +#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, CONSOLE_COLOR_RED, "## ERROR## ", CONSOLE_COLOR_RESET, FMT, ##ARGS) +#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, CONSOLE_COLOR_YELLOW, "##WARN ## ", CONSOLE_COLOR_RESET, FMT, ##ARGS) +#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(WHBLogPrintf, CONSOLE_COLOR_CYAN, "##INFO ## ", CONSOLE_COLOR_RESET, FMT, ##ARGS) -#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, "##ERROR## ", "", FMT, ##ARGS); +#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, WHBLogPrintf, CONSOLE_COLOR_RED, "##ERROR## ", CONSOLE_COLOR_RESET, FMT, ##ARGS); #else @@ -53,11 +58,11 @@ extern "C" { #define DEBUG_FUNCTION_LINE_WRITE(FMT, ARGS...) while (0) -#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##ERROR## ", "\n", FMT, ##ARGS) -#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##WARN ## ", "\n", FMT, ##ARGS) -#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, "##INFO ## ", "\n", FMT, ##ARGS) +#define DEBUG_FUNCTION_LINE_ERR(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, CONSOLE_COLOR_RED, "##ERROR## ", CONSOLE_COLOR_RESET "\n", FMT, ##ARGS) +#define DEBUG_FUNCTION_LINE_WARN(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, CONSOLE_COLOR_YELLOW, "##WARN ## ", CONSOLE_COLOR_RESET "\n", FMT, ##ARGS) +#define DEBUG_FUNCTION_LINE_INFO(FMT, ARGS...) LOG_EX_DEFAULT(OSReport, CONSOLE_COLOR_CYAN, "##INFO ## ", CONSOLE_COLOR_RESET "\n", FMT, ##ARGS) -#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, "##ERROR## ", "\n", FMT, ##ARGS); +#define DEBUG_FUNCTION_LINE_ERR_LAMBDA(FILENAME, FUNCTION, LINE, FMT, ARGS...) LOG_EX(FILENAME, FUNCTION, LINE, OSReport, CONSOLE_COLOR_RED, "##ERROR## ", CONSOLE_COLOR_RESET "\n", FMT, ##ARGS); #endif From fecb802236debc4bcf14391680951ef31490b32b Mon Sep 17 00:00:00 2001 From: Maschell Date: Mon, 6 Apr 2026 10:39:26 +0200 Subject: [PATCH 09/12] Update CRRemoveFSLayer to only returns errors it layer system is active --- src/export.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/export.cpp b/src/export.cpp index d9ea4d4..264409e 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -187,6 +187,9 @@ ContentRedirectionApiErrorType CRAddFSLayerEx(CRLayerHandle *handle, const char ContentRedirectionApiErrorType CRRemoveFSLayer(CRLayerHandle handle) { + if (!gThreadsRunning) { // if no threads a running we have removed the layers anyway + return CONTENT_REDIRECTION_API_ERROR_NONE; + } 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; @@ -238,6 +241,7 @@ ContentRedirectionApiErrorType CRAddDeviceABI(const ContentRedirectionDeviceABI *resultOut = AddDevice(host_dev); if (*resultOut < 0) { + DEBUG_FUNCTION_LINE_WARN("AddDevice failed: %d", *resultOut); DevoptabTrampoline::ClearDevoptab(host_dev); } @@ -250,7 +254,6 @@ ContentRedirectionApiErrorType CRRemoveDeviceABI(const char *device_name, int *r } if (!DevoptabTrampoline::RemoveDevoptab(device_name, resultOut)) { - *resultOut = -1; return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG; } From c6220b7a2c6dcc7cf964c82470289e3b35a8a5b8 Mon Sep 17 00:00:00 2001 From: Maschell Date: Mon, 6 Apr 2026 10:39:37 +0200 Subject: [PATCH 10/12] Bump version --- src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.cpp b/src/main.cpp index 32b5b07..594de05 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,7 +9,7 @@ WUMS_MODULE_EXPORT_NAME("homebrew_content_redirection"); WUMS_USE_WUT_DEVOPTAB(); WUMS_DEPENDS_ON(homebrew_functionpatcher); -#define VERSION "v0.2.8" +#define VERSION "v0.2.9" DECL_FUNCTION(void, OSCancelThread, OSThread *thread) { if (thread == gThreadData[0].thread || thread == gThreadData[1].thread || thread == gThreadData[2].thread) { From 2cc94a8278d3704cc34af777c035ee22b284e703 Mon Sep 17 00:00:00 2001 From: Maschell Date: Fri, 17 Apr 2026 19:59:31 +0200 Subject: [PATCH 11/12] Increase thread io message queue size --- src/FileUtils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FileUtils.h b/src/FileUtils.h index 36db017..98c66e1 100644 --- a/src/FileUtils.h +++ b/src/FileUtils.h @@ -13,7 +13,7 @@ struct FSIOThreadData { OSThread *thread; void *stack; OSMessageQueue queue; - OSMessage messages[0x10]; + OSMessage messages[0x40]; bool setup; char threadName[0x50]; }; From 9bc1fbc452b256df81484ac1d03ae7da2498b102 Mon Sep 17 00:00:00 2001 From: Maschell Date: Sat, 18 Apr 2026 19:08:37 +0200 Subject: [PATCH 12/12] Update Dockerifle --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index c12eb7f..79dac72 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM ghcr.io/wiiu-env/devkitppc:20260225 COPY --from=ghcr.io/wiiu-env/libfunctionpatcher:20260331 /artifacts $DEVKITPRO -COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:reentfix-dev-20260403-5ca1144 /artifacts $DEVKITPRO -COPY --from=ghcr.io/wiiu-env/libcontentredirection:abisafe-dev-20260403-502a496 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/wiiumodulesystem:20260418 /artifacts $DEVKITPRO +COPY --from=ghcr.io/wiiu-env/libcontentredirection:20260418 /artifacts $DEVKITPRO WORKDIR project