Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ TOPDIR ?= $(CURDIR)
include $(DEVKITPRO)/wut/share/wut_rules

export VER_MAJOR := 1
export VER_MINOR := 1
export VER_MINOR := 2
export VER_PATCH := 0

VERSION := $(VER_MAJOR).$(VER_MINOR).$(VER_PATCH)
Expand Down
41 changes: 37 additions & 4 deletions include/content_redirection/redirection.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ typedef enum FSLayerType {
FS_LAYER_TYPE_SAVE_REPLACE_FOR_CURRENT_USER,
} FSLayerType;

typedef enum FSLayerTypeEx {
FS_LAYER_TYPE_EX_REPLACE_DIRECTORY,
FS_LAYER_TYPE_EX_MERGE_DIRECTORY,
FS_LAYER_TYPE_EX_REPLACE_FILE,
} FSLayerTypeEx;

typedef enum ContentRedirectionStatus {
CONTENT_REDIRECTION_RESULT_SUCCESS = 0,
CONTENT_REDIRECTION_RESULT_MODULE_NOT_FOUND = -0x1,
Expand Down Expand Up @@ -104,9 +110,9 @@ ContentRedirectionStatus ContentRedirection_DeInitLibrary();
ContentRedirectionStatus ContentRedirection_GetVersion(ContentRedirectionVersion *outVersion);

/**
* Adds a a FSLayers that redirects the /vol/content or /vol/save fs calles for the Game/Wii U Menu process. <br>
* Adds a FSLayers that redirects the /vol/content or /vol/save fs calls for the Game/Wii U Menu process. <br>
* Make sure to remove all added the layers before the application ends. <br>
* The replacement dir has be to valid in the ContentRedirection Module, use "ContentRedirection_AddDevice" to add a Device for the ContentRedirection Module. <br>
* The replacement dir has to be valid in the ContentRedirection Module, use "ContentRedirection_AddDevice" to add a Device for the ContentRedirection Module. <br>
* Multiple layers can be added. Each layer is valid system wide for the Game/Wii U Menu process. <br>
* The layers will be processed in reverse adding order. e.g. when you add Layer1, Layer2 and then Layer3; Layer3, Layer2 and finally Layer1 will be processed. <br>
* An added layer is active by default.
Expand All @@ -115,16 +121,43 @@ ContentRedirectionStatus ContentRedirection_GetVersion(ContentRedirectionVersion
* @param layerName Name of the layer, used for debugging.
* @param replacementDir Path to the directory that will replace / merge into the original one.
* @param layerType Type of the layer, see FSLayerType for more information. <br>
* If set to to false, errors of this layer will be returned to the OS.
* If set to false, errors of this layer will be returned to the OS.
* @return CONTENT_REDIRECTION_RESULT_SUCCESS: The layer had been added successfully. <br>
* The layer has to be removed before the currently running application ends. <br>
* CONTENT_REDIRECTION_RESULT_LIB_UNINITIALIZED: "ContentRedirection_InitLibrary()" was not called. <br>
* CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT: "handlePtr", "layerName" or "replacementDir" is NULL <br>
* CONTENT_REDIRECTION_API_ERROR_NO_MEMORY: Not enough memory to create this layer. <br>
* CONTENT_REDIRECTION_API_ERROR_UNKNOWN_LAYER_TYPE: Unknown/invalid LayerType. See FSLayerType for all supported layers. <br>
* CONTENT_REDIRECTION_RESULT_UNKNOWN_ERROR: Unknown error.
*/
ContentRedirectionStatus ContentRedirection_AddFSLayer(CRLayerHandle *handlePtr, const char *layerName, const char *replacementDir, FSLayerTypeEx layerType);

/**
* Adds a FSLayer that redirects a files or directories fs calls for the Game/Wii U Menu process. <br>
* Make sure to remove all added the layers before the application ends. <br>
* The replacement dir has to be valid in the ContentRedirection Module, use "ContentRedirection_AddDevice" to add a Device for the ContentRedirection Module. <br>
* Multiple layers can be added. Each layer is valid system mwide for the Game/Wii U Menu process. <br>
* The layers will be processed in reverse adding order. e.g. when you add Layer1, Layer2 and then Layer3; Layer3, Layer2 and finally Layer1 will be processed. <br>
* An added layer is active by default.
*
* **Requires API version 2 or higher**
*
* @param handlePtr The handle of the layer is written to this pointer.
* @param layerName Name of the layer, used for debugging.
* @param targetPath Path to the directory/file that should be replaced or merged.
* @param replacementPath Path to the directory/file that will replace / merge into the original one.
* @param layerType Type of the layer, see FSLayerType for more information. <br>
* If set to false, errors of this layer will be returned to the OS.
* @return CONTENT_REDIRECTION_RESULT_SUCCESS: The layer had been added successfully. <br>
* The layer has to be removed before the currently running application ends. <br>
* CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND: This function requires API version 2 <br>
* CONTENT_REDIRECTION_RESULT_LIB_UNINITIALIZED: "ContentRedirection_InitLibrary()" was not called. <br>
* CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT: "handlePtr", "layerName" or "replacementDir" is NULL <br>
* CONTENT_REDIRECTION_API_ERROR_NO_MEMORY: Not enough memory to create this layer. <br>
* CONTENT_REDIRECTION_API_ERROR_UNKNOWN_LAYER_TYPE: Unknown/invalid LayerType. See FSLayerType for all supported layers. <br>
* CONTENT_REDIRECTION_RESULT_UNKNOWN_ERROR: Unknown error.
*/
ContentRedirectionStatus ContentRedirection_AddFSLayer(CRLayerHandle *handlePtr, const char *layerName, const char *replacementDir, FSLayerType layerType);
ContentRedirectionStatus ContentRedirection_AddFSLayerEx(CRLayerHandle *handlePtr, const char *layerName, const char *targetPath, const char *replacementPath, FSLayerTypeEx layerType);

/**
* Removes a previously added FS Layer.
Expand Down
56 changes: 40 additions & 16 deletions source/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@

static OSDynLoad_Module sModuleHandle = nullptr;

static ContentRedirectionApiErrorType (*sCRAddFSLayer)(CRLayerHandle *, const char *, const char *, FSLayerType) = nullptr;
static ContentRedirectionApiErrorType (*sCRRemoveFSLayer)(CRLayerHandle) = nullptr;
static ContentRedirectionApiErrorType (*sCRSetActive)(CRLayerHandle) = nullptr;
static ContentRedirectionApiErrorType (*sCRGetVersion)(ContentRedirectionVersion *) = nullptr;
static int (*sCRAddDevice)(const devoptab_t *, int *) = nullptr;
static int (*sCRRemoveDevice)(const char *) = nullptr;
static ContentRedirectionApiErrorType (*sCRAddFSLayerEx)(CRLayerHandle *, const char *, const char *, const char *, FSLayerTypeEx) = nullptr;
static ContentRedirectionApiErrorType (*sCRAddFSLayer)(CRLayerHandle *, const char *, const char *, FSLayerType) = nullptr;
static ContentRedirectionApiErrorType (*sCRRemoveFSLayer)(CRLayerHandle) = nullptr;
static ContentRedirectionApiErrorType (*sCRSetActive)(CRLayerHandle, bool) = nullptr;
static ContentRedirectionApiErrorType (*sCRGetVersion)(ContentRedirectionVersion *) = nullptr;
static int (*sCRAddDevice)(const devoptab_t *, int *) = nullptr;
static int (*sCRRemoveDevice)(const char *) = nullptr;

static ContentRedirectionVersion sContentRedirectionVersion = CONTENT_REDIRECTION_MODULE_VERSION_ERROR;

Expand Down Expand Up @@ -62,6 +63,10 @@ ContentRedirectionStatus ContentRedirection_InitLibrary() {
DEBUG_FUNCTION_LINE_ERR("FindExport CRAddFSLayer failed.");
sCRAddFSLayer = nullptr;
}
if (OSDynLoad_FindExport(sModuleHandle, OS_DYNLOAD_EXPORT_FUNC, "CRAddFSLayerEx", (void **) &sCRAddFSLayerEx) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_ERR("FindExport CRAddFSLayerEx failed.");
sCRAddFSLayerEx = nullptr;
}

if (OSDynLoad_FindExport(sModuleHandle, OS_DYNLOAD_EXPORT_FUNC, "CRRemoveFSLayer", (void **) &sCRRemoveFSLayer) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_ERR("FindExport CRRemoveFSLayer failed.");
Expand Down Expand Up @@ -90,8 +95,7 @@ ContentRedirectionStatus ContentRedirection_DeInitLibrary() {
return CONTENT_REDIRECTION_RESULT_SUCCESS;
}

ContentRedirectionApiErrorType GetVersion(ContentRedirectionVersion *);
ContentRedirectionStatus ContentRedirection_GetVersion(ContentRedirectionVersion *outVariable) {
ContentRedirectionStatus ContentRedirection_GetVersion(ContentRedirectionVersion *outVersion) {
if (sCRGetVersion == nullptr) {
if (OSDynLoad_Acquire("homebrew_content_redirection", &sModuleHandle) != OS_DYNLOAD_OK) {
DEBUG_FUNCTION_LINE_WARN("OSDynLoad_Acquire failed.");
Expand All @@ -104,23 +108,45 @@ ContentRedirectionStatus ContentRedirection_GetVersion(ContentRedirectionVersion
}
}

auto res = reinterpret_cast<decltype(&GetVersion)>(sCRGetVersion)(outVariable);
const auto res = sCRGetVersion(outVersion);
if (res == CONTENT_REDIRECTION_API_ERROR_NONE) {
return CONTENT_REDIRECTION_RESULT_SUCCESS;
}
return res == CONTENT_REDIRECTION_API_ERROR_INVALID_ARG ? CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT : CONTENT_REDIRECTION_RESULT_UNKNOWN_ERROR;
}


ContentRedirectionApiErrorType AddFSLayer(CRLayerHandle *, const char *, const char *, FSLayerType);
ContentRedirectionStatus ContentRedirection_AddFSLayer(CRLayerHandle *handlePtr, const char *layerName, const char *replacementDir, FSLayerType layerType) {
ContentRedirectionStatus ContentRedirection_AddFSLayer(CRLayerHandle *handlePtr, const char *layerName, const char *replacementDir, const FSLayerType layerType) {
if (sContentRedirectionVersion == CONTENT_REDIRECTION_MODULE_VERSION_ERROR) {
return CONTENT_REDIRECTION_RESULT_LIB_UNINITIALIZED;
}
if (sCRAddFSLayer == nullptr || sContentRedirectionVersion < 1) {
return CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND;
}
auto res = reinterpret_cast<decltype(&AddFSLayer)>(sCRAddFSLayer)(handlePtr, layerName, replacementDir, layerType);
auto res = sCRAddFSLayer(handlePtr, layerName, replacementDir, layerType);
if (res == CONTENT_REDIRECTION_API_ERROR_NONE) {
return CONTENT_REDIRECTION_RESULT_SUCCESS;
}
switch (res) {
case CONTENT_REDIRECTION_API_ERROR_INVALID_ARG:
return CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT;
case CONTENT_REDIRECTION_API_ERROR_NO_MEMORY:
return CONTENT_REDIRECTION_RESULT_NO_MEMORY;
case CONTENT_REDIRECTION_API_ERROR_UNKNOWN_FS_LAYER_TYPE:
return CONTENT_REDIRECTION_RESULT_UNKNOWN_FS_LAYER_TYPE;
default:
return CONTENT_REDIRECTION_RESULT_UNKNOWN_ERROR;
}
}

ContentRedirectionStatus ContentRedirection_AddFSLayerEx(CRLayerHandle *handlePtr, const char *layerName, const char *targetPath, const char *replacementDir, const FSLayerTypeEx layerType) {
if (sContentRedirectionVersion == CONTENT_REDIRECTION_MODULE_VERSION_ERROR) {
return CONTENT_REDIRECTION_RESULT_LIB_UNINITIALIZED;
}
if (sCRAddFSLayerEx == nullptr || sContentRedirectionVersion < 2) {
return CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND;
}
const auto res = sCRAddFSLayerEx(handlePtr, layerName, targetPath, replacementDir, layerType);
if (res == CONTENT_REDIRECTION_API_ERROR_NONE) {
return CONTENT_REDIRECTION_RESULT_SUCCESS;
}
Expand All @@ -136,15 +162,14 @@ ContentRedirectionStatus ContentRedirection_AddFSLayer(CRLayerHandle *handlePtr,
}
}

ContentRedirectionApiErrorType RemoveFSLayer(CRLayerHandle);
ContentRedirectionStatus ContentRedirection_RemoveFSLayer(CRLayerHandle handlePtr) {
if (sContentRedirectionVersion == CONTENT_REDIRECTION_MODULE_VERSION_ERROR) {
return CONTENT_REDIRECTION_RESULT_LIB_UNINITIALIZED;
}
if (sCRRemoveFSLayer == nullptr || sContentRedirectionVersion < 1) {
return CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND;
}
auto res = reinterpret_cast<decltype(&RemoveFSLayer)>(sCRRemoveFSLayer)(handlePtr);
const auto res = sCRRemoveFSLayer(handlePtr);
if (res == CONTENT_REDIRECTION_API_ERROR_NONE) {
return CONTENT_REDIRECTION_RESULT_SUCCESS;
}
Expand All @@ -156,15 +181,14 @@ ContentRedirectionStatus ContentRedirection_RemoveFSLayer(CRLayerHandle handlePt
return CONTENT_REDIRECTION_RESULT_UNKNOWN_ERROR;
}

ContentRedirectionApiErrorType SetActive(CRLayerHandle, bool);
ContentRedirectionStatus ContentRedirection_SetActive(CRLayerHandle handle, bool active) {
if (sContentRedirectionVersion == CONTENT_REDIRECTION_MODULE_VERSION_ERROR) {
return CONTENT_REDIRECTION_RESULT_LIB_UNINITIALIZED;
}
if (sCRSetActive == nullptr || sContentRedirectionVersion < 1) {
return CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND;
}
auto res = reinterpret_cast<decltype(&SetActive)>(sCRSetActive)(handle, active);
const auto res = sCRSetActive(handle, active);
if (res == CONTENT_REDIRECTION_API_ERROR_NONE) {
return CONTENT_REDIRECTION_RESULT_SUCCESS;
}
Expand Down