diff --git a/Dockerfile b/Dockerfile index a4ee917..4afc8fc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,8 @@ -FROM wiiuenv/devkitppc:20220212 +FROM wiiuenv/devkitppc:20220417 WORKDIR tmp_build COPY . . -RUN make clean && make && mkdir -p /artifacts/wums && cp -r lib /artifacts/wums && cp -r include /artifacts/wums && cp -r share /artifacts/wums +RUN make clean && make && mkdir -p /artifacts/wums && cp -r lib /artifacts/wums && cp -r include /artifacts/wums WORKDIR /artifacts FROM scratch diff --git a/Dockerfile.buildlocal b/Dockerfile.buildlocal index 59464ad..dddcf14 100644 --- a/Dockerfile.buildlocal +++ b/Dockerfile.buildlocal @@ -1,3 +1,3 @@ -FROM wiiuenv/devkitppc:20220212 +FROM wiiuenv/devkitppc:20220417 WORKDIR project \ No newline at end of file diff --git a/Makefile b/Makefile index eb9fcc1..ddd9b5a 100644 --- a/Makefile +++ b/Makefile @@ -99,10 +99,10 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ .PHONY: all dist-bin dist-src dist install clean #--------------------------------------------------------------------------------- -all: lib/librpxloader.a share/librpxloader.ld +all: lib/librpxloader.a dist-bin: all - @tar --exclude=*~ -cjf librpxloader-$(VERSION).tar.bz2 include lib share + @tar --exclude=*~ -cjf librpxloader-$(VERSION).tar.bz2 include lib dist-src: @tar --exclude=*~ -cjf librpxloader-src-$(VERSION).tar.bz2 include source Makefile @@ -115,15 +115,9 @@ install: dist-bin lib: @[ -d $@ ] || mkdir -p $@ - -share: - @[ -d $@ ] || mkdir -p $@ release: @[ -d $@ ] || mkdir -p $@ - -share/librpxloader.ld :$(SOURCES) $(INCLUDES) | share release - mv $(CURDIR)/release/*.ld $(CURDIR)/$@ lib/librpxloader.a :$(SOURCES) $(INCLUDES) | lib release @$(MAKE) BUILD=release OUTPUT=$(CURDIR)/$@ \ diff --git a/include/rpxloader.h b/include/rpxloader.h deleted file mode 100644 index f1c3357..0000000 --- a/include/rpxloader.h +++ /dev/null @@ -1,124 +0,0 @@ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -typedef enum { - BundleSource_FileDescriptor, - BundleSource_FileDescriptor_CafeOS, -} BundleSource; - -/** - * Setups the given .rpx or .wuhb to be loaded on the next application restart. - * Make sure to (re-)launch the H&S app after calling this function. - * - * Calling this for a .rpx while the .wuhb is running while keep the bundle mounted, - * just the .rpx will be replaced. - * - * @param bundle_path relative path the root of the sd card (e.g. "/apps/test.wuhb") - * @return - */ -bool RL_LoadFromSDOnNextLaunch(const char *bundle_path); - -/** - * Mounts a given bundle to a given mount path. Use RL_UnmountBundle to unmount it - * - * Caution: the mounted path is only available via the - * RL_FileXXX functions - * - * @param name path the bundle should be mounted to (e.g. "rom") - * @param bundle_path path to the bundle file (e.g. "/vol/external01/apps/test.wuhb") - * @param source type of source - * @return 0 on success, < 0 on error - */ -int32_t RL_MountBundle(const char *name, const char *bundle_path, BundleSource source); - -/** - * Unmounts a given mount path. - * - * @param name given mount path that should be unmounted - * @return 0 on success, < 0 on error - */ -int32_t RL_UnmountBundle(const char *name); - -/** - * Opens a file inside a mounted bundle. - * (only read only is supported and is default) - * - * Make sure the bundle is mounted via RL_MountBundle. - * - * If a given files does not exists, it's checks for a compressed version - * (at name + ".gz). If a compressed file was found, all file reads will be - * decompressed on the fly. - * - * @param name - * @param handle handle to be used in other RL_FileXXX functions - * @return - */ -int32_t RL_FileOpen(const char *name, uint32_t *handle); - -/** - * Reads from a given file. - * - * @param handle File to be read from. - * @param buffer buffer where data will be written to. - * Align to 0x40 for best performance - * @param size maximum bytes this function should read into buffer - * @return number of actually read bytes - * <0 on error - */ -int32_t RL_FileRead(uint32_t handle, uint8_t *buffer, uint32_t size); - -/** - * Closes a given file - * - * example: if(RL_FileClose("bundle:/meta/meta.ini") < 0) { //error while closing the file } - * - * @param handle File to be closed - * @return 0 on success, <0 on error - */ -int32_t RL_FileClose(uint32_t handle); - -/** - * Checks if a given file exists - * - * example: RL_FileExists("bundle:/meta/meta.ini"); - * - * @param name Paths to be checked - * @return true if the files exists, false if the files does not exists - */ -bool RL_FileExists(const char *name); - -/** - * Redirects /vol/content to a given path. - * If the application requests a file that is not present in the new path, - * it'll fallback to the original /vol/content. - * - * example: RL_RedirectContentWithFallback("fs:/vol/external01/sdcafiine/0005000010145000/content"); - * - * @param pathToContent The path /vol/content should be redirected to. - * @return true if the given path is valid and can be used, false on error. - */ -bool RL_RedirectContentWithFallback(const char *pathToContent); - -/** - * Disables the /vol/content redirection - * - * @return true if /vol/content was previously redirected - */ -bool RL_DisableContentRedirection(); - -/** - * Unmounts the currently running bundle. This also disables the /vol/content redirection - * - * @return true if a .wuhb is running and the /vol/content was previously redirected - * false if no .wuhb is running or no /vol/content redirection is active. - */ -bool RL_UnmountCurrentRunningBundle(); - -#ifdef __cplusplus -} // extern "C" -#endif \ No newline at end of file diff --git a/include/rpxloader/rpxloader.h b/include/rpxloader/rpxloader.h new file mode 100644 index 0000000..7594e59 --- /dev/null +++ b/include/rpxloader/rpxloader.h @@ -0,0 +1,82 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +enum RPXLoaderStatus { + RPX_LOADER_RESULT_SUCCESS = 0, + RPX_LOADER_RESULT_MODULE_NOT_FOUND = -1, + RPX_LOADER_RESULT_MODULE_MISSING_EXPORT = -2, + RPX_LOADER_RESULT_UNSUPPORTED_VERSION = -3, + RPX_LOADER_RESULT_INVALID_ARG = -10, + RPX_LOADER_RESULT_LIB_UNINITIALIZED = -20, + RPX_LOADER_RESULT_UNKNOWN_ERROR = -1000, +}; + +typedef uint32_t RPXLoaderVersion; +#define RPX_LOADER_MODULE_VERSION 0x00000001 + +/** + * This function has to be called before any other function of this lib (except RPXLoader_GetVersion) can be used. + * + * @return RPX_LOADER_RESULT_SUCCESS: The library has been initialized successfully. Other functions can now be used. + * RPX_LOADER_RESULT_MODULE_NOT_FOUND: The module could not be found. Make sure the module is loaded. + * RPX_LOADER_RESULT_MODULE_MISSING_EXPORT: The module is missing an expected export. + * RPX_LOADER_RESULT_UNSUPPORTED_VERSION: The version of the loaded module is not compatible with this version of the lib. +*/ +RPXLoaderStatus RPXLoader_Init(); + +/** + * Returns the API Version of the RPXLoader Module. + * @return The RPXLoaderVersion of the Module. + */ +RPXLoaderVersion RPXLoader_GetVersion(); + +/** + * Setups the given .rpx or .wuhb to be loaded on the next application restart. + * Make sure to (re-)launch the H&S app after calling this function. + * + * Calling this for a .rpx while the .wuhb is running while keep the bundle mounted, + * just the .rpx will be replaced. + * + * @param bundle_path relative path the root of the sd card (e.g. "/apps/test.wuhb") + * @return RPX_LOADER_RESULT_SUCCESS: The given homebrew will be executed on the next Launch of Health and Safety + * RPX_LOADER_RESULT_LIB_UNINITIALIZED: "RPXLoader_Init()" was not called. + * RPX_LOADER_RESULT_INVALID_ARG: "bundle_path" was NULL + * RPX_LOADER_RESULT_UNKNOWN_ERROR: Error. No effect. +*/ +RPXLoaderStatus RPXLoader_LoadFromSDOnNextLaunch(const char *bundle_path); + +/** + * Enables the /vol/content redirection (is enabled by default if a .wuhb is running) + * +* @return RPX_LOADER_RESULT_SUCCESS: /vol/content has been enabled or was already enabled. +* RPX_LOADER_RESULT_LIB_UNINITIALIZED: "RPXLoader_Init()" was not called. +* RPX_LOADER_RESULT_UNKNOWN_ERROR: Error + */ +RPXLoaderStatus RPXLoader_EnableContentRedirection(); + +/** + * Disables the /vol/content redirection + * + * @return RPX_LOADER_RESULT_SUCCESS: /vol/content has been disabled or was already disabled. + * RPX_LOADER_RESULT_LIB_UNINITIALIZED: "RPXLoader_Init()" was not called. + * RPX_LOADER_RESULT_UNKNOWN_ERROR: Error +*/ +RPXLoaderStatus RPXLoader_DisableContentRedirection(); + +/** + * Unmounts the currently running bundle. This also disables the /vol/content redirection + * + * @return RPX_LOADER_RESULT_SUCCESS: /vol/content has been unmounted or was not previously mounted. + * RPX_LOADER_RESULT_LIB_UNINITIALIZED: "RPXLoader_Init()" was not called. + * RPX_LOADER_RESULT_UNKNOWN_ERROR: Unable to unmount the currently running bundle. +*/ +RPXLoaderStatus RPXLoader_UnmountCurrentRunningBundle(); + +#ifdef __cplusplus +} // extern "C" +#endif \ No newline at end of file diff --git a/source/rpx_loader.def b/source/rpx_loader.def deleted file mode 100644 index c01e05a..0000000 --- a/source/rpx_loader.def +++ /dev/null @@ -1,13 +0,0 @@ -:NAME homebrew_rpx_loader - -:TEXT -RL_LoadFromSDOnNextLaunch -RL_MountBundle -RL_UnmountBundle -RL_FileOpen -RL_FileRead -RL_FileClose -RL_FileExists -RL_RedirectContentWithFallback -RL_DisableContentRedirection -RL_UnmountCurrentRunningBundle \ No newline at end of file diff --git a/source/rpxloader.cpp b/source/rpxloader.cpp new file mode 100644 index 0000000..5c53c2a --- /dev/null +++ b/source/rpxloader.cpp @@ -0,0 +1,104 @@ +#include +#include +#include + +static OSDynLoad_Module sModuleHandle = nullptr; + +static RPXLoaderVersion (*sRLGetVersion)() = nullptr; +static bool (*sRLLoadFromSDOnNextLaunch)() = nullptr; +static bool (*sRLDisableContentRedirection)() = nullptr; +static bool (*sRLEnableContentRedirection)() = nullptr; +static bool (*sRLUnmountCurrentRunningBundle)() = nullptr; + +RPXLoaderStatus RPXLoader_Init() { + if (OSDynLoad_Acquire("homebrew_rpx_loader", &sModuleHandle) != OS_DYNLOAD_OK) { + OSReport("RPXLoader_Init: OSDynLoad_Acquire failed.\n"); + return RPX_LOADER_RESULT_MODULE_NOT_FOUND; + } + + if (OSDynLoad_FindExport(sModuleHandle, FALSE, "RL_GetVersion", (void **) &sRLGetVersion) != OS_DYNLOAD_OK) { + OSReport("RPXLoader_Init: RL_GetVersion failed.\n"); + return RPX_LOADER_RESULT_MODULE_MISSING_EXPORT; + } + auto res = RPXLoader_GetVersion(); + if (res != RPX_LOADER_MODULE_VERSION) { + return RPX_LOADER_RESULT_UNSUPPORTED_VERSION; + } + + if (OSDynLoad_FindExport(sModuleHandle, FALSE, "RL_LoadFromSDOnNextLaunch", (void **) &sRLLoadFromSDOnNextLaunch) != OS_DYNLOAD_OK) { + OSReport("RPXLoader_Init: RL_LoadFromSDOnNextLaunch failed.\n"); + return RPX_LOADER_RESULT_MODULE_MISSING_EXPORT; + } + + if (OSDynLoad_FindExport(sModuleHandle, FALSE, "RL_DisableContentRedirection", (void **) &sRLDisableContentRedirection) != OS_DYNLOAD_OK) { + OSReport("RPXLoader_Init: RL_DisableContentRedirection failed.\n"); + return RPX_LOADER_RESULT_MODULE_MISSING_EXPORT; + } + + if (OSDynLoad_FindExport(sModuleHandle, FALSE, "RL_EnableContentRedirection", (void **) &sRLEnableContentRedirection) != OS_DYNLOAD_OK) { + OSReport("RPXLoader_Init: RL_EnableContentRedirection failed.\n"); + return RPX_LOADER_RESULT_MODULE_MISSING_EXPORT; + } + + if (OSDynLoad_FindExport(sModuleHandle, FALSE, "RL_UnmountCurrentRunningBundle", (void **) &sRLUnmountCurrentRunningBundle) != OS_DYNLOAD_OK) { + OSReport("RPXLoader_Init: RL_UnmountCurrentRunningBundle failed.\n"); + return RPX_LOADER_RESULT_MODULE_MISSING_EXPORT; + } + + return RPX_LOADER_RESULT_SUCCESS; +} + + +RPXLoaderVersion GetVersion(); +RPXLoaderVersion RPXLoader_GetVersion() { + if (sRLGetVersion == nullptr) { + return RPX_LOADER_RESULT_LIB_UNINITIALIZED; + } + + return reinterpret_cast(sRLGetVersion)(); +} + +bool LoadFromSDOnNextLaunch(const char *); +RPXLoaderStatus RPXLoader_LoadFromSDOnNextLaunch(const char *path) { + if (sRLLoadFromSDOnNextLaunch == nullptr) { + return RPX_LOADER_RESULT_LIB_UNINITIALIZED; + } + if (path == nullptr) { + return RPX_LOADER_RESULT_INVALID_ARG; + } + auto res = reinterpret_cast(sRLLoadFromSDOnNextLaunch)(path); + + return res ? RPX_LOADER_RESULT_SUCCESS : RPX_LOADER_RESULT_UNKNOWN_ERROR; +} + +bool DisableContentRedirection(); +RPXLoaderStatus RPXLoader_DisableContentRedirection() { + if (sRLDisableContentRedirection == nullptr) { + return RPX_LOADER_RESULT_LIB_UNINITIALIZED; + } + auto res = reinterpret_cast(sRLDisableContentRedirection)(); + + return res ? RPX_LOADER_RESULT_SUCCESS : RPX_LOADER_RESULT_UNKNOWN_ERROR; +} + +bool EnableContentRedirection(); +RPXLoaderStatus RPXLoader_EnableContentRedirection() { + if (sRLEnableContentRedirection == nullptr) { + return RPX_LOADER_RESULT_LIB_UNINITIALIZED; + } + + auto res = reinterpret_cast(sRLEnableContentRedirection)(); + + return res ? RPX_LOADER_RESULT_SUCCESS : RPX_LOADER_RESULT_UNKNOWN_ERROR; +} + +bool UnmountCurrentRunningBundle(); +RPXLoaderStatus RPXLoader_UnmountCurrentRunningBundle() { + if (sRLUnmountCurrentRunningBundle == nullptr) { + return RPX_LOADER_RESULT_LIB_UNINITIALIZED; + } + + auto res = reinterpret_cast(sRLUnmountCurrentRunningBundle)(); + + return res ? RPX_LOADER_RESULT_SUCCESS : RPX_LOADER_RESULT_UNKNOWN_ERROR; +} \ No newline at end of file