Reimplement RPX/Bundle loading logic.

This commit is contained in:
Maschell 2021-02-19 20:32:44 +01:00
parent 158db91f7a
commit 06e92de8e5
6 changed files with 138 additions and 112 deletions

View File

@ -346,13 +346,13 @@ DECL_FUNCTION(FSStatus, FSGetFreeSpaceSizeAsync, FSClient *client, FSCmdBlock *b
DECL_FUNCTION(FSStatus, FSChangeDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE("FSChangeDirAsync %s", path);
strncpy(gWorkingDir, path, sizeof(gWorkingDir));
int len = strlen(gWorkingDir);
if(len > 0 && gWorkingDir[len-1] != '/'){
gWorkingDir[len-1] = '/';
gWorkingDir[len] = 0;
strncpy(gReplacementInfo.bundleMountInformation.workingDir, path, sizeof(gReplacementInfo.bundleMountInformation.workingDir));
int len = strlen(gReplacementInfo.bundleMountInformation.workingDir);
if(len > 0 && gReplacementInfo.bundleMountInformation.workingDir[len-1] != '/'){
gReplacementInfo.bundleMountInformation.workingDir[len-1] = '/';
gReplacementInfo.bundleMountInformation.workingDir[len] = 0;
}
DCFlushRange(gWorkingDir, sizeof(gWorkingDir));
DCFlushRange(gReplacementInfo.bundleMountInformation.workingDir, sizeof(gReplacementInfo.bundleMountInformation.workingDir));
return real_FSChangeDirAsync(client, block, path, errorMask, asyncData);
}

View File

@ -19,7 +19,7 @@ std::mutex file_handle_mutex;
inline void getFullPath(char *pathForCheck, int pathSize, char *path) {
if (path[0] != '/' && path[0] != '\\') {
snprintf(pathForCheck, pathSize, "%s%s", gWorkingDir, path);
snprintf(pathForCheck, pathSize, "%s%s", gReplacementInfo.bundleMountInformation.workingDir, path);
DEBUG_FUNCTION_LINE_VERBOSE("Real path is %s", path);
} else {
strncpy(pathForCheck, path, pathSize - 1);
@ -33,7 +33,7 @@ inline bool checkForSave(char *pathForCheck, int pathSize, char *path) {
memcpy(copy, path, copyLen);
copy[copyLen] = 0;
memset(pathForCheck,0, pathSize);
snprintf(pathForCheck, pathSize, "%s%s", gSavePath, &copy[9]);
snprintf(pathForCheck, pathSize, "%s%s", gReplacementInfo.savePath, &copy[9]);
return true;
}
return false;
@ -127,7 +127,7 @@ FSStatus FSOpenDirWrapper(char *path,
FSErrorFlag errorMask,
std::function<FSStatus(char *_path)> fallback_function,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted) {
if (!gReplacementInfo.bundleMountInformation.isMounted) {
return FS_STATUS_USE_REAL_OS;
}
@ -183,7 +183,7 @@ FSStatus FSReadDirWrapper(FSDirectoryHandle handle,
FSDirectoryEntry *entry,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted || !isValidDirHandle(handle)) {
if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidDirHandle(handle)) {
return FS_STATUS_USE_REAL_OS;
}
@ -231,7 +231,7 @@ FSStatus FSReadDirWrapper(FSDirectoryHandle handle,
FSStatus FSCloseDirWrapper(FSDirectoryHandle handle,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted || !isValidDirHandle(handle)) {
if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidDirHandle(handle)) {
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
@ -257,7 +257,7 @@ FSStatus FSCloseDirWrapper(FSDirectoryHandle handle,
FSStatus FSRewindDirWrapper(FSDirectoryHandle handle,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted || !isValidDirHandle(handle)) {
if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidDirHandle(handle)) {
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
@ -278,7 +278,7 @@ FSStatus FSMakeDirWrapper(char *path,
FSErrorFlag errorMask,
std::function<FSStatus(char *_path)> fallback_function,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted) {
if (!gReplacementInfo.bundleMountInformation.isMounted) {
return FS_STATUS_USE_REAL_OS;
}
@ -307,7 +307,7 @@ FSStatus FSOpenFileWrapper(char *path,
FSErrorFlag errorMask,
std::function<FSStatus(char *_path)> fallback_function,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted) {
if (!gReplacementInfo.bundleMountInformation.isMounted) {
return FS_STATUS_USE_REAL_OS;
}
if (path == nullptr) {
@ -386,7 +386,7 @@ FSStatus FSOpenFileWrapper(char *path,
FSStatus FSCloseFileWrapper(FSFileHandle handle,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted || !isValidFileHandle(handle)) {
if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) {
return FS_STATUS_USE_REAL_OS;
}
@ -417,7 +417,7 @@ FSStatus FSCloseFileWrapper(FSFileHandle handle,
FSStatus FSGetStatWrapper(char *path, FSStat *stats, FSErrorFlag errorMask,
std::function<FSStatus(char *_path)> fallback_function,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted) {
if (!gReplacementInfo.bundleMountInformation.isMounted) {
return FS_STATUS_USE_REAL_OS;
}
if (path == nullptr) {
@ -470,7 +470,7 @@ FSStatus FSGetStatFileWrapper(FSFileHandle handle,
FSStat *stats,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted || !isValidFileHandle(handle)) {
if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) {
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
@ -511,7 +511,7 @@ FSStatus FSReadFileWrapper(void *buffer,
uint32_t unk1,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted || !isValidFileHandle(handle)) {
if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) {
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
@ -556,7 +556,7 @@ FSStatus FSReadFileWithPosWrapper(void *buffer,
int32_t unk1,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted || !isValidFileHandle(handle)) {
if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) {
return FS_STATUS_USE_REAL_OS;
}
FSStatus result;
@ -579,7 +579,7 @@ FSStatus FSSetPosFileWrapper(FSFileHandle handle,
uint32_t pos,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted || !isValidFileHandle(handle)) {
if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) {
return FS_STATUS_USE_REAL_OS;
}
@ -609,7 +609,7 @@ FSStatus FSGetPosFileWrapper(FSFileHandle handle,
uint32_t *pos,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted || !isValidFileHandle(handle)) {
if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) {
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
@ -640,7 +640,7 @@ FSStatus FSGetPosFileWrapper(FSFileHandle handle,
FSStatus FSIsEofWrapper(FSFileHandle handle,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted || !isValidFileHandle(handle)) {
if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) {
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
@ -674,7 +674,7 @@ FSStatus FSIsEofWrapper(FSFileHandle handle,
FSStatus FSTruncateFileWrapper(FSFileHandle handle,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted || !isValidFileHandle(handle)) {
if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) {
return FS_STATUS_USE_REAL_OS;
}
uint32_t handle_index = handle & HANDLE_MASK;
@ -697,7 +697,7 @@ FSStatus FSWriteFileWrapper(uint8_t *buffer,
uint32_t unk1,
FSErrorFlag errorMask,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted || !isValidFileHandle(handle)) {
if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) {
return FS_STATUS_USE_REAL_OS;
}
FSStatus result = FS_STATUS_OK;
@ -711,7 +711,7 @@ FSStatus FSRemoveWrapper(char *path,
FSErrorFlag errorMask,
std::function<FSStatus(char *_path)> fallback_function,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted) {
if (!gReplacementInfo.bundleMountInformation.isMounted) {
return FS_STATUS_USE_REAL_OS;
}
@ -740,7 +740,7 @@ FSStatus FSRenameWrapper(char *oldPath,
FSErrorFlag errorMask,
std::function<FSStatus(char *_oldPath, char *_newPath)> fallback_function,
std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted) {
if (!gReplacementInfo.bundleMountInformation.isMounted) {
return FS_STATUS_USE_REAL_OS;
}
@ -767,7 +767,7 @@ FSStatus FSRenameWrapper(char *oldPath,
}
FSStatus FSFlushFileWrapper(FSFileHandle handle, FSErrorFlag errorMask, std::function<FSStatus(FSStatus)> result_handler) {
if (!gIsMounted || !isValidFileHandle(handle)) {
if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) {
return FS_STATUS_USE_REAL_OS;
}
FSStatus result = FS_STATUS_OK;

View File

@ -16,17 +16,16 @@
#include <cstring>
#include <rpxloader.h>
char gIconCache[65580] __attribute__((section(".data")));
/*
* Patch the meta xml for the home menu
*/
DECL_FUNCTION(int32_t, HBM_NN_ACP_ACPGetTitleMetaXmlByDevice, uint32_t titleid_upper, uint32_t titleid_lower, ACPMetaXml *metaxml, uint32_t device) {
if (gReplacedRPX) {
if (gReplacementInfo.isRPXReplaced) {
memset(&metaxml->longname_ja, 0, 0x338C - 0x38C); // clear all names
strncpy(metaxml->longname_en, gBundleInfo.longname, sizeof(gBundleInfo.longname));
strncpy(metaxml->shortname_en, gBundleInfo.shortname, sizeof(gBundleInfo.longname));
strncpy(metaxml->publisher_en, gBundleInfo.author, sizeof(gBundleInfo.longname));
strncpy(metaxml->longname_en, gReplacementInfo.metaInformation.longname, sizeof(gReplacementInfo.metaInformation.longname));
strncpy(metaxml->shortname_en, gReplacementInfo.metaInformation.shortname, sizeof(gReplacementInfo.metaInformation.shortname));
strncpy(metaxml->publisher_en, gReplacementInfo.metaInformation.author, sizeof(gReplacementInfo.metaInformation.author));
// Disbale the emanual
metaxml->e_manual = 0;
@ -40,9 +39,9 @@ DECL_FUNCTION(int32_t, HBM_NN_ACP_ACPGetTitleMetaXmlByDevice, uint32_t titleid_u
DECL_FUNCTION(int, RPX_FSOpenFile, FSClient *client, FSCmdBlock *block, char *path, const char *mode, int *handle, int error) {
const char *iconTex = "iconTex.tga";
if (StringTools::EndsWith(path, iconTex)) {
if (gReplacedRPX) {
if (gReplacementInfo.isRPXReplaced) {
if (StringTools::EndsWith(path, iconTex)) {
auto *reader = new FileReader(reinterpret_cast<uint8_t *>(gIconCache), sizeof(gIconCache));
auto *reader = new FileReader(reinterpret_cast<uint8_t *>(gReplacementInfo.iconCache), sizeof(gReplacementInfo.iconCache));
*handle = (uint32_t) reader;
return FS_STATUS_OK;
}
@ -85,7 +84,7 @@ uint32_t rpx_utils_function_replacements_size = sizeof(rpx_utils_function_replac
static int parseINIhandler(void *user, const char *section, const char *name,
const char *value) {
auto *fInfo = (BundleInformation *) user;
auto *fInfo = (MetaInformation *) user;
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
if (MATCH("menu", "longname")) {
strncpy(fInfo->longname, value, 64 - 1);
@ -113,16 +112,19 @@ bool RL_LoadFromSDOnNextLaunch(const char *bundle_path) {
bool metaLoaded = false;
gReplacementInfo.replacementType = RPXLoader_RPX;
std::string completePath = std::string("/vol/external01/") + bundle_path;
int res = getRPXInfoForPath(completePath, &info);
bool isBundle = false;
if (res >= 0) {
gReplacementInfo.replacementType = RPXLoader_BUNDLE;
isBundle = true;
request.filesize = ((uint32_t *) &info.length)[1];
request.fileoffset = ((uint32_t *) &info.offset)[1];
if (romfsMount("rcc", completePath.c_str(), RomfsSource_FileDescriptor_CafeOS) == 0) {
if (ini_parse("rcc:/meta/meta.ini", parseINIhandler, &gBundleInfo) < 0) {
if (ini_parse("rcc:/meta/meta.ini", parseINIhandler, &gReplacementInfo.metaInformation) < 0) {
DEBUG_FUNCTION_LINE("Failed to load and parse meta.ini");
} else {
metaLoaded = true;
@ -138,60 +140,74 @@ bool RL_LoadFromSDOnNextLaunch(const char *bundle_path) {
}
if (reader) {
uint32_t alreadyRead = 0;
uint32_t toRead = sizeof(gIconCache);
uint32_t toRead = sizeof(gReplacementInfo.iconCache);
do {
int read = reader->read(reinterpret_cast<uint8_t *>(&gIconCache[alreadyRead]), toRead);
int read = reader->read(reinterpret_cast<uint8_t *>(&gReplacementInfo.iconCache[alreadyRead]), toRead);
if (read <= 0) {
break;
}
alreadyRead += read;
toRead -= read;
} while (alreadyRead < sizeof(gIconCache));
} while (alreadyRead < sizeof(gReplacementInfo.iconCache));
delete reader;
} else {
memset(gIconCache, 0, sizeof(gIconCache));
memset(gReplacementInfo.iconCache, 0, sizeof(gReplacementInfo.iconCache));
}
romfsUnmount("rcc");
}
}
if (!metaLoaded) {
strncpy(gBundleInfo.author, bundle_path, 64 - 1);
strncpy(gBundleInfo.shortname, bundle_path, 64 - 1);
strncpy(gBundleInfo.longname, bundle_path, 64 - 1);
strncpy(gReplacementInfo.metaInformation.author, bundle_path, sizeof(gReplacementInfo.metaInformation.author));
strncpy(gReplacementInfo.metaInformation.shortname, bundle_path, sizeof(gReplacementInfo.metaInformation.shortname));
strncpy(gReplacementInfo.metaInformation.longname, bundle_path, sizeof(gReplacementInfo.metaInformation.longname));
}
strncpy(request.path, bundle_path, 255);
DEBUG_FUNCTION_LINE("Launch %s on next restart [size: %08X offset: %08X]", request.path, request.filesize, request.fileoffset);
DCFlushRange(gIconCache, sizeof(gIconCache));
DCFlushRange(&request, sizeof(LOAD_REQUEST));
DCFlushRange(&gBundleInfo, sizeof(gBundleInfo));
int success = false;
int mcpFd = IOS_Open("/dev/mcp", (IOSOpenMode) 0);
if (mcpFd >= 0) {
int out = 0;
IOS_Ioctl(mcpFd, 100, &request, sizeof(request), &out, sizeof(out));
if (out > 0) {
success = true;
}
IOS_Close(mcpFd);
}
DCFlushRange(&gReplacementInfo, sizeof(gReplacementInfo));
if (!success) {
gReplacementInfo.replacementType = RPXLoader_NONE;
DEBUG_FUNCTION_LINE("Failed to load %s on next restart", request.path);
return false;
}
DEBUG_FUNCTION_LINE("Launch %s on next restart [size: %08X offset: %08X]", request.path, request.filesize, request.fileoffset);
if (isBundle) {
DEBUG_FUNCTION_LINE("Loaded file is a .wuhb bundle");
gTryToReplaceOnNextLaunch = true;
memset(gLoadedBundlePath, 0, sizeof(gLoadedBundlePath));
strncpy(gLoadedBundlePath, completePath.c_str(), completePath.length());
memset(gReplacementInfo.bundleMountInformation.path, 0, sizeof(gReplacementInfo.bundleMountInformation.path));
strncpy(gReplacementInfo.bundleMountInformation.path, completePath.c_str(), completePath.length());
gReplacementInfo.replacementType = RPXLoader_BUNDLE;
gReplacementInfo.bundleMountInformation.redirectionRequested = true;
} else {
DEBUG_FUNCTION_LINE("Loaded file is no bundle");
if (!gIsMounted) {
gTryToReplaceOnNextLaunch = false;
memset(gLoadedBundlePath, 0, sizeof(gLoadedBundlePath));
if (!gReplacementInfo.bundleMountInformation.isMounted) {
memset(gReplacementInfo.bundleMountInformation.path, 0, sizeof(gReplacementInfo.bundleMountInformation.path));
} else {
gReplacementInfo.replacementType = RPXLoader_BUNDLE_OTHER_RPX;
gReplacementInfo.bundleMountInformation.redirectionRequested = true;
// keep the old /vol/content mounted, this way you can reload just the rpx via wiiload
gTryToReplaceOnNextLaunch = true;
}
}
DCFlushRange(&gReplacementInfo, sizeof(gReplacementInfo));
return true;
}

View File

@ -1,11 +1,3 @@
#include "globals.h"
bool gIsMounted __attribute__((section(".data"))) = false;
uint32_t gCurrentHash __attribute__((section(".data"))) = 0;
bool gTryToReplaceOnNextLaunch __attribute__((section(".data"))) = false;
char gLoadedBundlePath[256] __attribute__((section(".data")));
char gSavePath[256] __attribute__((section(".data")));
char gWorkingDir[256] __attribute__((section(".data")));
bool gReplacedRPX __attribute__((section(".data"))) = false;
BundleInformation gBundleInfo __attribute__((section(".data")));
RPXLoader_ReplacementInformation gReplacementInfo __attribute__((section(".data")));

View File

@ -1,18 +1,34 @@
#include <wums.h>
#include <coreinit/mutex.h>
typedef struct BundleInformation_t {
typedef struct MetaInformation_t {
char shortname[64];
char longname[64];
char author[64];
} BundleInformation;
} MetaInformation;
typedef struct BundleMountInformation_t {
bool redirectionRequested;
bool isMounted;
char path[255];
char workingDir[255];
} BundleMountInformation;
extern bool gIsMounted;
extern bool gTryToReplaceOnNextLaunch;
extern char gLoadedBundlePath[256];
extern char gSavePath[256];
extern char gWorkingDir[256];
extern uint32_t gCurrentHash;
extern bool gReplacedRPX;
extern BundleInformation gBundleInfo;
typedef enum RPXLoader_Type {
RPXLoader_NONE,
RPXLoader_RPX,
RPXLoader_BUNDLE,
RPXLoader_BUNDLE_OTHER_RPX,
} RPXLoader_Type;
typedef struct RPXLoader_ReplacementInformation_t {
bool isRPXReplaced;
MetaInformation metaInformation;
RPXLoader_Type replacementType;
BundleMountInformation bundleMountInformation;
char iconCache[65580];
uint32_t currentHash;
char savePath[255];
} RPXLoader_ReplacementInformation;
extern RPXLoader_ReplacementInformation gReplacementInfo;

View File

@ -27,16 +27,16 @@ WUMS_INITIALIZE() {
FunctionPatcherPatchFunction(fs_dir_function_replacements, fs_dir_function_replacements_size);
FunctionPatcherPatchFunction(rpx_utils_function_replacements, rpx_utils_function_replacements_size);
DEBUG_FUNCTION_LINE("Patch functions finished");
gIsMounted = false;
gReplacementInfo = {};
}
WUMS_APPLICATION_ENDS() {
if (gIsMounted) {
if (gReplacementInfo.bundleMountInformation.isMounted) {
DEBUG_FUNCTION_LINE("Unmount /vol/content");
romfsUnmount("rom");
gIsMounted = false;
DCFlushRange(&gIsMounted, sizeof(gIsMounted));
gReplacementInfo.bundleMountInformation.isMounted = false;
DCFlushRange(&gReplacementInfo, sizeof(gReplacementInfo));
}
}
@ -48,43 +48,45 @@ WUMS_APPLICATION_STARTS() {
WHBLogUdpInit();
if (_SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_HEALTH_AND_SAFETY) != OSGetTitleID()) {
DEBUG_FUNCTION_LINE("Set gTryToReplaceOnNextLaunch, gReplacedRPX and gIsMounted to FALSE");
gReplacedRPX = false;
gTryToReplaceOnNextLaunch = false;
gIsMounted = false;
DCFlushRange(&gReplacedRPX, sizeof(gReplacedRPX));
DCFlushRange(&gTryToReplaceOnNextLaunch, sizeof(gTryToReplaceOnNextLaunch));
DCFlushRange(&gIsMounted, sizeof(gIsMounted));
gReplacementInfo.replacementType = RPXLoader_NONE;
gReplacementInfo.isRPXReplaced = false;
gReplacementInfo.bundleMountInformation.isMounted = false;
gReplacementInfo.bundleMountInformation.redirectionRequested = false;
DCFlushRange(&gReplacementInfo, sizeof(gReplacementInfo));
} else {
if (gTryToReplaceOnNextLaunch) {
gCurrentHash = StringTools::hash(gLoadedBundlePath);
if (gReplacementInfo.replacementType != RPXLoader_NONE) {
gReplacementInfo.isRPXReplaced = true;
}
if (gReplacementInfo.bundleMountInformation.redirectionRequested) {
if (gReplacementInfo.replacementType == RPXLoader_BUNDLE || gReplacementInfo.replacementType == RPXLoader_BUNDLE_OTHER_RPX) {
gReplacementInfo.currentHash = StringTools::hash(gReplacementInfo.bundleMountInformation.path);
nn::act::Initialize();
nn::act::SlotNo slot = nn::act::GetSlotNo();
nn::act::Finalize();
std::string basePath = StringTools::strfmt("/vol/external01/wiiu/apps/save/%08X", gCurrentHash);
std::string common = StringTools::strfmt("fs:/vol/external01/wiiu/apps/save/%08X/common", gCurrentHash);
std::string user = StringTools::strfmt("fs:/vol/external01/wiiu/apps/save/%08X/%08X", gCurrentHash, 0x80000000 | slot);
std::string basePath = StringTools::strfmt("/vol/external01/wiiu/apps/save/%08X", gReplacementInfo.currentHash);
std::string common = StringTools::strfmt("fs:/vol/external01/wiiu/apps/save/%08X/common", gReplacementInfo.currentHash);
std::string user = StringTools::strfmt("fs:/vol/external01/wiiu/apps/save/%08X/%08X", gReplacementInfo.currentHash, 0x80000000 | slot);
strncpy(gSavePath,basePath.c_str(), 255);
memset(gWorkingDir, 0, sizeof(gWorkingDir));
DCFlushRange(gWorkingDir, sizeof(gWorkingDir));
strncpy(gReplacementInfo.savePath, basePath.c_str(), sizeof(gReplacementInfo.savePath));
memset(gReplacementInfo.bundleMountInformation.workingDir, 0, sizeof(gReplacementInfo.bundleMountInformation.workingDir));
CreateSubfolder(common.c_str());
CreateSubfolder(user.c_str());
DEBUG_FUNCTION_LINE("Created %s and %s", common.c_str(), user.c_str());
if (romfsMount("rom", gLoadedBundlePath, RomfsSource_FileDescriptor_CafeOS) == 0) {
DEBUG_FUNCTION_LINE("Mounted %s to /vol/content", gLoadedBundlePath);
gIsMounted = true;
if (romfsMount("rom", gReplacementInfo.bundleMountInformation.path, RomfsSource_FileDescriptor_CafeOS) == 0) {
DEBUG_FUNCTION_LINE("Mounted %s to /vol/content", gReplacementInfo.bundleMountInformation.path);
gReplacementInfo.bundleMountInformation.isMounted = true;
} else {
DEBUG_FUNCTION_LINE("Failed to mount %s", gLoadedBundlePath);
gIsMounted = false;
DEBUG_FUNCTION_LINE("Failed to mount %s", gReplacementInfo.bundleMountInformation.path);
gReplacementInfo.bundleMountInformation.isMounted = false;
}
gReplacedRPX = true;
DCFlushRange(&gReplacedRPX, sizeof(gReplacedRPX));
DCFlushRange(&gIsMounted, sizeof(gIsMounted));
DCFlushRange(&gTryToReplaceOnNextLaunch, sizeof(gTryToReplaceOnNextLaunch));
} else if (gReplacementInfo.replacementType == RPXLoader_RPX) {
//
}
}
DCFlushRange(&gReplacementInfo, sizeof(gReplacementInfo));
}
}