diff --git a/Makefile b/Makefile
index 06c969f..76de26f 100644
--- a/Makefile
+++ b/Makefile
@@ -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)
diff --git a/include/content_redirection/redirection.h b/include/content_redirection/redirection.h
index 992ece8..828cabf 100644
--- a/include/content_redirection/redirection.h
+++ b/include/content_redirection/redirection.h
@@ -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,
@@ -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.
+ * Adds a FSLayers that redirects the /vol/content or /vol/save fs calls for the Game/Wii U Menu process.
* Make sure to remove all added the layers before the application ends.
- * The replacement dir has be to valid in the ContentRedirection Module, use "ContentRedirection_AddDevice" to add a Device for the ContentRedirection Module.
+ * The replacement dir has to be valid in the ContentRedirection Module, use "ContentRedirection_AddDevice" to add a Device for the ContentRedirection Module.
* Multiple layers can be added. Each layer is valid system wide for the Game/Wii U Menu process.
* 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.
* An added layer is active by default.
@@ -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.
- * 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.
+ * The layer has to be removed before the currently running application ends.
+* CONTENT_REDIRECTION_RESULT_LIB_UNINITIALIZED: "ContentRedirection_InitLibrary()" was not called.
+* CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT: "handlePtr", "layerName" or "replacementDir" is NULL
+* CONTENT_REDIRECTION_API_ERROR_NO_MEMORY: Not enough memory to create this layer.
+* CONTENT_REDIRECTION_API_ERROR_UNKNOWN_LAYER_TYPE: Unknown/invalid LayerType. See FSLayerType for all supported layers.
+* 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.
+ * Make sure to remove all added the layers before the application ends.
+ * The replacement dir has to be valid in the ContentRedirection Module, use "ContentRedirection_AddDevice" to add a Device for the ContentRedirection Module.
+ * Multiple layers can be added. Each layer is valid system mwide for the Game/Wii U Menu process.
+ * 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.
+ * 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.
+ * 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.
* The layer has to be removed before the currently running application ends.
+* CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND: This function requires API version 2
* CONTENT_REDIRECTION_RESULT_LIB_UNINITIALIZED: "ContentRedirection_InitLibrary()" was not called.
* CONTENT_REDIRECTION_RESULT_INVALID_ARGUMENT: "handlePtr", "layerName" or "replacementDir" is NULL
* CONTENT_REDIRECTION_API_ERROR_NO_MEMORY: Not enough memory to create this layer.
* CONTENT_REDIRECTION_API_ERROR_UNKNOWN_LAYER_TYPE: Unknown/invalid LayerType. See FSLayerType for all supported layers.
* 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.
diff --git a/source/utils.cpp b/source/utils.cpp
index 74643b2..50651f2 100644
--- a/source/utils.cpp
+++ b/source/utils.cpp
@@ -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;
@@ -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.");
@@ -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.");
@@ -104,7 +108,7 @@ ContentRedirectionStatus ContentRedirection_GetVersion(ContentRedirectionVersion
}
}
- auto res = reinterpret_cast(sCRGetVersion)(outVariable);
+ const auto res = sCRGetVersion(outVersion);
if (res == CONTENT_REDIRECTION_API_ERROR_NONE) {
return CONTENT_REDIRECTION_RESULT_SUCCESS;
}
@@ -112,15 +116,37 @@ ContentRedirectionStatus ContentRedirection_GetVersion(ContentRedirectionVersion
}
-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(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;
}
@@ -136,7 +162,6 @@ 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;
@@ -144,7 +169,7 @@ ContentRedirectionStatus ContentRedirection_RemoveFSLayer(CRLayerHandle handlePt
if (sCRRemoveFSLayer == nullptr || sContentRedirectionVersion < 1) {
return CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND;
}
- auto res = reinterpret_cast(sCRRemoveFSLayer)(handlePtr);
+ const auto res = sCRRemoveFSLayer(handlePtr);
if (res == CONTENT_REDIRECTION_API_ERROR_NONE) {
return CONTENT_REDIRECTION_RESULT_SUCCESS;
}
@@ -156,7 +181,6 @@ 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;
@@ -164,7 +188,7 @@ ContentRedirectionStatus ContentRedirection_SetActive(CRLayerHandle handle, bool
if (sCRSetActive == nullptr || sContentRedirectionVersion < 1) {
return CONTENT_REDIRECTION_RESULT_UNSUPPORTED_COMMAND;
}
- auto res = reinterpret_cast(sCRSetActive)(handle, active);
+ const auto res = sCRSetActive(handle, active);
if (res == CONTENT_REDIRECTION_API_ERROR_NONE) {
return CONTENT_REDIRECTION_RESULT_SUCCESS;
}