From f5266db61310ebf2e645d51a21f62efdc69a8ce7 Mon Sep 17 00:00:00 2001 From: Maschell Date: Mon, 10 Oct 2022 19:38:51 +0200 Subject: [PATCH] Add support for /vol/aoc redirection --- Dockerfile | 2 +- src/export.cpp | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 7f7d391..b866654 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,6 @@ FROM wiiuenv/devkitppc:20220917 COPY --from=wiiuenv/libfunctionpatcher:20220904 /artifacts $DEVKITPRO COPY --from=wiiuenv/wiiumodulesystem:20220904 /artifacts $DEVKITPRO COPY --from=wiiuenv/libromfs_wiiu:20220904 /artifacts $DEVKITPRO -COPY --from=wiiuenv/libcontentredirection:20220916 /artifacts $DEVKITPRO +COPY --from=wiiuenv/libcontentredirection:20221010 /artifacts $DEVKITPRO WORKDIR project diff --git a/src/export.cpp b/src/export.cpp index 2fc72d9..1d5988e 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -2,12 +2,92 @@ #include "FSWrapperMergeDirsWithParent.h" #include "FileUtils.h" #include "IFSWrapper.h" +#include "malloc.h" #include "utils/logger.h" #include "utils/utils.h" #include +#include #include #include +struct AOCTitle { + WUT_UNKNOWN_BYTES(0x68); +}; +WUT_CHECK_SIZE(AOCTitle, 0x68); + +bool getAOCPath(std::string &outStr) { + int32_t (*AOC_Initialize)() = nullptr; + int32_t (*AOC_Finalize)() = nullptr; + int32_t (*AOC_ListTitle)(uint32_t * titleCountOut, AOCTitle * titleList, uint32_t maxCount, void *workBuffer, uint32_t workBufferSize) = nullptr; + int32_t (*AOC_OpenTitle)(char *pathOut, AOCTitle *aocTitleInfo, void *workBuffer, uint32_t workBufferSize) = nullptr; + int32_t (*AOC_CalculateWorkBufferSize)(uint32_t count) = nullptr; + int32_t (*AOC_CloseTitle)(AOCTitle * aocTitleInfo) = nullptr; + + AOCTitle title{}; + char aocPath[256]; + aocPath[0] = '\0'; + uint32_t outCount = 0; + uint32_t workBufferSize = 0; + void *workBuffer = nullptr; + bool result = false; + + OSDynLoad_Module aoc_handle; + if (OSDynLoad_Acquire("nn_aoc.rpl", &aoc_handle) != OS_DYNLOAD_OK) { + DEBUG_FUNCTION_LINE_WARN("OSDynLoad_Acquire failed"); + return false; + } + if (OSDynLoad_FindExport(aoc_handle, false, "AOC_Initialize", reinterpret_cast(&AOC_Initialize)) != OS_DYNLOAD_OK) { + DEBUG_FUNCTION_LINE_WARN("OSDynLoad_FindExport failed"); + goto end; + } + if (OSDynLoad_FindExport(aoc_handle, false, "AOC_Finalize", reinterpret_cast(&AOC_Finalize)) != OS_DYNLOAD_OK) { + DEBUG_FUNCTION_LINE_WARN("OSDynLoad_FindExport failed"); + goto end; + } + if (OSDynLoad_FindExport(aoc_handle, false, "AOC_OpenTitle", reinterpret_cast(&AOC_OpenTitle)) != OS_DYNLOAD_OK) { + DEBUG_FUNCTION_LINE_WARN("OSDynLoad_FindExport failed"); + goto end; + } + if (OSDynLoad_FindExport(aoc_handle, false, "AOC_ListTitle", reinterpret_cast(&AOC_ListTitle)) != OS_DYNLOAD_OK) { + DEBUG_FUNCTION_LINE_WARN("OSDynLoad_FindExport failed"); + goto end; + } + if (OSDynLoad_FindExport(aoc_handle, false, "AOC_CalculateWorkBufferSize", reinterpret_cast(&AOC_CalculateWorkBufferSize)) != OS_DYNLOAD_OK) { + DEBUG_FUNCTION_LINE_WARN("OSDynLoad_FindExport failed"); + goto end; + } + if (OSDynLoad_FindExport(aoc_handle, false, "AOC_CloseTitle", reinterpret_cast(&AOC_CloseTitle)) != OS_DYNLOAD_OK) { + DEBUG_FUNCTION_LINE_WARN("OSDynLoad_FindExport failed"); + goto end; + } + + AOC_Initialize(); + + workBufferSize = AOC_CalculateWorkBufferSize(1); + workBuffer = memalign(0x40, workBufferSize); + if (!workBuffer) { + DEBUG_FUNCTION_LINE_WARN("Failed to alloc workBuffer"); + goto end; + } + if (AOC_ListTitle(&outCount, &title, 1, workBuffer, workBufferSize) < 0) { + DEBUG_FUNCTION_LINE_WARN("AOC_ListTitle failed"); + goto end; + } + if (AOC_OpenTitle(aocPath, &title, workBuffer, workBufferSize) < 0) { + DEBUG_FUNCTION_LINE_WARN("AOC_OpenTitle failed"); + goto end; + } + + result = true; + outStr = aocPath; + AOC_CloseTitle(&title); +end: + free(workBuffer); + AOC_Finalize(); + OSDynLoad_Release(aoc_handle); + return result; +} + ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *layerName, const char *replacementDir, FSLayerType layerType) { if (!handle || layerName == nullptr || replacementDir == nullptr) { DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_INVALID_ARG"); @@ -15,10 +95,25 @@ ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *l } std::unique_ptr ptr; if (layerType == FS_LAYER_TYPE_CONTENT_REPLACE) { + DEBUG_FUNCTION_LINE_INFO("Redirecting \"/vol/content\" to \"%s\", mode: \"replace\"", replacementDir); ptr = make_unique_nothrow(layerName, "/vol/content", replacementDir, false, false); } else if (layerType == FS_LAYER_TYPE_CONTENT_MERGE) { + DEBUG_FUNCTION_LINE_INFO("Redirecting \"/vol/content\" to \"%s\", mode: \"merge\"", replacementDir); ptr = make_unique_nothrow(layerName, "/vol/content", replacementDir, true); + } else if (layerType == FS_LAYER_TYPE_AOC_MERGE || layerType == FS_LAYER_TYPE_AOC_REPLACE) { + std::string targetPath; + if (!getAOCPath(targetPath)) { + DEBUG_FUNCTION_LINE_ERR("(%s) Failed to get the AOC path. Not redirecting /vol/aoc", layerName); + return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG; + } + DEBUG_FUNCTION_LINE_INFO("Redirecting \"%s\" to \"%s\", mode: \"%s\"", targetPath.c_str(), replacementDir, layerType == FS_LAYER_TYPE_AOC_MERGE ? "merge" : "replace"); + if (layerType == FS_LAYER_TYPE_AOC_MERGE) { + ptr = make_unique_nothrow(layerName, targetPath.c_str(), replacementDir, true); + } else { + ptr = make_unique_nothrow(layerName, targetPath.c_str(), replacementDir, false, false); + } } else if (layerType == FS_LAYER_TYPE_SAVE_REPLACE) { + DEBUG_FUNCTION_LINE_INFO("Redirecting \"/vol/save\" to \"%s\", mode: \"replace\"", replacementDir); ptr = make_unique_nothrow(layerName, "/vol/save", replacementDir, false, true); } else { DEBUG_FUNCTION_LINE_ERR("CONTENT_REDIRECTION_API_ERROR_UNKNOWN_LAYER_DIR_TYPE: %s %s %d", layerName, replacementDir, layerType);