diff --git a/src/FSDirReplacements.cpp b/src/FSDirReplacements.cpp index f8a61bf..6e2ab74 100644 --- a/src/FSDirReplacements.cpp +++ b/src/FSDirReplacements.cpp @@ -1,5 +1,6 @@ #include "FSDirReplacements.h" #include +#include #include "utils/logger.h" #include "globals.h" #include "FSWrapper.h" @@ -134,6 +135,18 @@ DECL_FUNCTION(FSStatus, FSMakeDirAsync, FSClient *client, FSCmdBlock *block, cha return real_FSMakeDirAsync(client, block, path, errorMask, asyncData); } +DECL_FUNCTION(FSStatus, FSChangeDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) { + DEBUG_FUNCTION_LINE_VERBOSE("FSChangeDirAsync %s", path); + snprintf(gReplacementInfo.contentReplacementInfo.workingDir, sizeof(gReplacementInfo.contentReplacementInfo.workingDir), "%s", path); + int len = strlen(gReplacementInfo.contentReplacementInfo.workingDir); + if (len > 0 && gReplacementInfo.contentReplacementInfo.workingDir[len - 1] != '/') { + gReplacementInfo.contentReplacementInfo.workingDir[len - 1] = '/'; + gReplacementInfo.contentReplacementInfo.workingDir[len] = 0; + } + DCFlushRange(gReplacementInfo.contentReplacementInfo.workingDir, sizeof(gReplacementInfo.contentReplacementInfo.workingDir)); + return real_FSChangeDirAsync(client, block, path, errorMask, asyncData); +} + function_replacement_data_t fs_dir_function_replacements[] = { REPLACE_FUNCTION(FSOpenDir, LIBRARY_COREINIT, FSOpenDir), REPLACE_FUNCTION(FSOpenDirAsync, LIBRARY_COREINIT, FSOpenDirAsync), @@ -149,6 +162,8 @@ function_replacement_data_t fs_dir_function_replacements[] = { REPLACE_FUNCTION(FSMakeDir, LIBRARY_COREINIT, FSMakeDir), REPLACE_FUNCTION(FSMakeDirAsync, LIBRARY_COREINIT, FSMakeDirAsync), + + REPLACE_FUNCTION(FSChangeDirAsync, LIBRARY_COREINIT, FSChangeDirAsync), }; uint32_t fs_dir_function_replacements_size = sizeof(fs_dir_function_replacements) / sizeof(function_replacement_data_t); \ No newline at end of file diff --git a/src/FSFileReplacements.cpp b/src/FSFileReplacements.cpp index 451e3ba..8f11173 100644 --- a/src/FSFileReplacements.cpp +++ b/src/FSFileReplacements.cpp @@ -344,17 +344,6 @@ DECL_FUNCTION(FSStatus, FSGetFreeSpaceSizeAsync, FSClient *client, FSCmdBlock *b return real_FSGetFreeSpaceSizeAsync(client, block, path, outSize, errorMask, asyncData); } -DECL_FUNCTION(FSStatus, FSChangeDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) { - DEBUG_FUNCTION_LINE("FSChangeDirAsync %s", path); - 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(gReplacementInfo.bundleMountInformation.workingDir, sizeof(gReplacementInfo.bundleMountInformation.workingDir)); - return real_FSChangeDirAsync(client, block, path, errorMask, asyncData); -} function_replacement_data_t fs_file_function_replacements[] = { REPLACE_FUNCTION(FSOpenFile, LIBRARY_COREINIT, FSOpenFile), @@ -399,8 +388,6 @@ function_replacement_data_t fs_file_function_replacements[] = { REPLACE_FUNCTION(FSFlushFile, LIBRARY_COREINIT, FSFlushFile), REPLACE_FUNCTION(FSFlushFileAsync, LIBRARY_COREINIT, FSFlushFileAsync), - REPLACE_FUNCTION(FSChangeDirAsync, LIBRARY_COREINIT, FSChangeDirAsync), - //REPLACE_FUNCTION(FSChangeModeAsync, LIBRARY_COREINIT, FSChangeModeAsync), //REPLACE_FUNCTION(FSGetFreeSpaceSizeAsync, LIBRARY_COREINIT, FSGetFreeSpaceSizeAsync), diff --git a/src/FSWrapper.cpp b/src/FSWrapper.cpp index 66dede9..40a9f6d 100644 --- a/src/FSWrapper.cpp +++ b/src/FSWrapper.cpp @@ -17,23 +17,32 @@ fileMagic_t file_handles[FILE_HANDLES_LENGTH]; std::mutex dir_handle_mutex; std::mutex file_handle_mutex; +static inline void replaceContentPath(char *pathForCheck, int pathForCheckSize, int replaceLen, char *replaceWith); + inline void getFullPath(char *pathForCheck, int pathSize, char *path) { if (path[0] != '/' && path[0] != '\\') { - snprintf(pathForCheck, pathSize, "%s%s", gReplacementInfo.bundleMountInformation.workingDir, path); + snprintf(pathForCheck, pathSize, "%s%s", gReplacementInfo.contentReplacementInfo.workingDir, path); DEBUG_FUNCTION_LINE_VERBOSE("Real path is %s", path); } else { - strncpy(pathForCheck, path, pathSize - 1); + pathForCheck[0] = '\0'; + strncat(pathForCheck, path, pathSize - 1); + } + + for(int i = 0; i < strlen(pathForCheck);i++){ + if(pathForCheck[i] == '\\'){ + pathForCheck[i] = '/'; + } } } inline bool checkForSave(char *pathForCheck, int pathSize, char *path) { if (strncmp(path, "/vol/save", 9) == 0) { int copyLen = strlen(path); - char copy[copyLen+1]; + char copy[copyLen + 1]; memcpy(copy, path, copyLen); copy[copyLen] = 0; - memset(pathForCheck,0, pathSize); - snprintf(pathForCheck, pathSize, "%s%s", gReplacementInfo.savePath, ©[9]); + memset(pathForCheck, 0, pathSize); + snprintf(pathForCheck, pathSize, "%s%s", gReplacementInfo.contentReplacementInfo.savePath, ©[9]); return true; } return false; @@ -127,7 +136,8 @@ FSStatus FSOpenDirWrapper(char *path, FSErrorFlag errorMask, std::function fallback_function, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { return FS_STATUS_USE_REAL_OS; } @@ -145,9 +155,9 @@ FSStatus FSOpenDirWrapper(char *path, } if (strncmp(pathForCheck, "/vol/content", 12) == 0) { - memcpy(pathForCheck, "rom:", 4); + replaceContentPath(pathForCheck, sizeof(pathForCheck), 12, gReplacementInfo.contentReplacementInfo.replacementPath); - DEBUG_FUNCTION_LINE_VERBOSE("%s", path); + DEBUG_FUNCTION_LINE_VERBOSE("%s -> %s", path, pathForCheck); FSStatus result = FS_STATUS_OK; int handle_index = getNewDirHandleIndex(); @@ -160,11 +170,17 @@ FSStatus FSOpenDirWrapper(char *path, *handle = dir_handles[handle_index].handle; dir_handles[handle_index].dir = dir; dir_handles[handle_index].in_use = true; - strncpy(dir_handles[handle_index].path, pathForCheck, 255); + + dir_handles[handle_index].path[0] = '\0'; + strncat(dir_handles[handle_index].path, pathForCheck, sizeof(dir_handles[handle_index].path) - 1); + DCFlushRange(&dir_handles[handle_index], sizeof(dirMagic_t)); OSUnlockMutex(dir_handles[handle_index].mutex); } else { DEBUG_FUNCTION_LINE("Dir not found %s", pathForCheck); + if (gReplacementInfo.contentReplacementInfo.fallbackOnError) { + return FS_STATUS_USE_REAL_OS; + } if (errorMask & FS_ERROR_FLAG_NOT_FOUND) { result = FS_STATUS_NOT_FOUND; } @@ -183,7 +199,10 @@ FSStatus FSReadDirWrapper(FSDirectoryHandle handle, FSDirectoryEntry *entry, FSErrorFlag errorMask, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidDirHandle(handle)) { + + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || + !isValidDirHandle(handle)) { return FS_STATUS_USE_REAL_OS; } @@ -199,7 +218,8 @@ FSStatus FSReadDirWrapper(FSDirectoryHandle handle, struct dirent *entry_ = readdir(dir); FSStatus result = FS_STATUS_END; if (entry_) { - strncpy(entry->name, entry_->d_name, 254); + entry->name[0] = '\0'; + strncat(entry->name, entry_->d_name, sizeof(entry->name)-1); entry->info.mode = (FSMode) FS_MODE_READ_OWNER; if (entry_->d_type == DT_DIR) { entry->info.flags = (FSStatFlags) ((uint32_t) FS_STAT_DIRECTORY); @@ -231,7 +251,9 @@ FSStatus FSReadDirWrapper(FSDirectoryHandle handle, FSStatus FSCloseDirWrapper(FSDirectoryHandle handle, FSErrorFlag errorMask, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidDirHandle(handle)) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || + !isValidDirHandle(handle)) { return FS_STATUS_USE_REAL_OS; } uint32_t handle_index = handle & HANDLE_MASK; @@ -257,7 +279,9 @@ FSStatus FSCloseDirWrapper(FSDirectoryHandle handle, FSStatus FSRewindDirWrapper(FSDirectoryHandle handle, FSErrorFlag errorMask, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidDirHandle(handle)) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || + !isValidDirHandle(handle)) { return FS_STATUS_USE_REAL_OS; } uint32_t handle_index = handle & HANDLE_MASK; @@ -278,7 +302,9 @@ FSStatus FSMakeDirWrapper(char *path, FSErrorFlag errorMask, std::function fallback_function, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { return FS_STATUS_USE_REAL_OS; } @@ -307,7 +333,8 @@ FSStatus FSOpenFileWrapper(char *path, FSErrorFlag errorMask, std::function fallback_function, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { return FS_STATUS_USE_REAL_OS; } if (path == nullptr) { @@ -318,6 +345,7 @@ FSStatus FSOpenFileWrapper(char *path, char pathForCheck[256]; getFullPath(pathForCheck, sizeof(pathForCheck), path); + DEBUG_FUNCTION_LINE_VERBOSE("%s -> %s", path, pathForCheck); if (checkForSave(pathForCheck, sizeof(pathForCheck), pathForCheck)) { DEBUG_FUNCTION_LINE("Redirect save to %s", pathForCheck); @@ -329,8 +357,9 @@ FSStatus FSOpenFileWrapper(char *path, } if (strncmp(pathForCheck, "/vol/content", 12) == 0) { - memcpy(pathForCheck, "rom:", 4); - DEBUG_FUNCTION_LINE_VERBOSE("Trying to open %s", pathForCheck); + replaceContentPath(pathForCheck, sizeof(pathForCheck), 12, gReplacementInfo.contentReplacementInfo.replacementPath); + + DEBUG_FUNCTION_LINE_VERBOSE("%s -> %s", path, pathForCheck); int handle_index = getNewFileHandleIndex(); FSStatus result = FS_STATUS_OK; if (handle_index >= 0) { @@ -368,17 +397,24 @@ FSStatus FSOpenFileWrapper(char *path, DCFlushRange(&file_handles[handle_index], sizeof(fileMagic_t)); } else { DEBUG_FUNCTION_LINE("File not found %s", pathForCheck); - if (errorMask & FS_ERROR_FLAG_NOT_FOUND) { + if (gReplacementInfo.contentReplacementInfo.fallbackOnError) { + result = FS_STATUS_USE_REAL_OS; + } else if (errorMask & FS_ERROR_FLAG_NOT_FOUND) { result = FS_STATUS_NOT_FOUND; } } OSUnlockMutex(file_handles[handle_index].mutex); } else { - if (errorMask & FS_ERROR_FLAG_MAX) { + if (gReplacementInfo.contentReplacementInfo.fallbackOnError) { + result = FS_STATUS_USE_REAL_OS; + } else if (errorMask & FS_ERROR_FLAG_MAX) { result = FS_STATUS_MAX; } } - return result_handler(result); + if (result != FS_STATUS_USE_REAL_OS) { + DEBUG_FUNCTION_LINE_VERBOSE("return error %d", result); + return result_handler(result); + } } return FS_STATUS_USE_REAL_OS; } @@ -386,7 +422,9 @@ FSStatus FSOpenFileWrapper(char *path, FSStatus FSCloseFileWrapper(FSFileHandle handle, FSErrorFlag errorMask, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || + !isValidFileHandle(handle)) { return FS_STATUS_USE_REAL_OS; } @@ -417,7 +455,8 @@ FSStatus FSCloseFileWrapper(FSFileHandle handle, FSStatus FSGetStatWrapper(char *path, FSStat *stats, FSErrorFlag errorMask, std::function fallback_function, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { return FS_STATUS_USE_REAL_OS; } if (path == nullptr) { @@ -429,22 +468,30 @@ FSStatus FSGetStatWrapper(char *path, FSStat *stats, FSErrorFlag errorMask, getFullPath(pathForCheck, sizeof(pathForCheck), path); - if (checkForSave(pathForCheck, sizeof(pathForCheck), pathForCheck)) { + if (gReplacementInfo.contentReplacementInfo.replaceSave && + checkForSave(pathForCheck, sizeof(pathForCheck), pathForCheck)) { DEBUG_FUNCTION_LINE("Redirect save to %s", pathForCheck); return fallback_function(pathForCheck); } if (strncmp(pathForCheck, "/vol/content", 12) == 0) { - memcpy(pathForCheck, "rom:", 4); + replaceContentPath(pathForCheck, sizeof(pathForCheck), 12, gReplacementInfo.contentReplacementInfo.replacementPath); + DEBUG_FUNCTION_LINE("%s -> %s", path, pathForCheck); + FSStatus result = FS_STATUS_OK; if (stats == nullptr) { + if (gReplacementInfo.contentReplacementInfo.fallbackOnError) { + return FS_STATUS_USE_REAL_OS; + } DEBUG_FUNCTION_LINE("Invalid args"); return FS_STATUS_FATAL_ERROR; } else { struct stat path_stat{}; memset(&path_stat, 0, sizeof(path_stat)); if (stat(pathForCheck, &path_stat) < 0) { - DEBUG_FUNCTION_LINE("Path not found %s", pathForCheck); - if (errorMask & FS_ERROR_FLAG_NOT_FOUND) { + if (gReplacementInfo.contentReplacementInfo.fallbackOnError) { + return FS_STATUS_USE_REAL_OS; + } else if (errorMask & FS_ERROR_FLAG_NOT_FOUND) { + DEBUG_FUNCTION_LINE("Path not found %s", pathForCheck); result = FS_STATUS_NOT_FOUND; } } else { @@ -466,11 +513,26 @@ FSStatus FSGetStatWrapper(char *path, FSStat *stats, FSErrorFlag errorMask, return FS_STATUS_USE_REAL_OS; } +static inline void replaceContentPath(char *pathForCheck, int pathForCheckSize, int skipLen, char *replaceWith) { + int subStrLen = strlen(pathForCheck) - skipLen; + if (subStrLen <= 0) { + pathForCheck[0] = '\0'; + strncat(pathForCheck, replaceWith, sizeof(pathForCheck) - 1); + } else { + char pathCopy[subStrLen+1]; + pathCopy[0] = '\0'; + strncat(pathCopy, &pathForCheck[skipLen], sizeof(pathCopy) - 1); + snprintf(pathForCheck, pathForCheckSize, "%s%s", replaceWith, pathCopy); + } +} + FSStatus FSGetStatFileWrapper(FSFileHandle handle, FSStat *stats, FSErrorFlag errorMask, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || + !isValidFileHandle(handle)) { return FS_STATUS_USE_REAL_OS; } uint32_t handle_index = handle & HANDLE_MASK; @@ -511,7 +573,9 @@ FSStatus FSReadFileWrapper(void *buffer, uint32_t unk1, FSErrorFlag errorMask, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || + !isValidFileHandle(handle)) { return FS_STATUS_USE_REAL_OS; } uint32_t handle_index = handle & HANDLE_MASK; @@ -556,7 +620,9 @@ FSStatus FSReadFileWithPosWrapper(void *buffer, int32_t unk1, FSErrorFlag errorMask, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || + !isValidFileHandle(handle)) { return FS_STATUS_USE_REAL_OS; } FSStatus result; @@ -579,7 +645,9 @@ FSStatus FSSetPosFileWrapper(FSFileHandle handle, uint32_t pos, FSErrorFlag errorMask, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || + !isValidFileHandle(handle)) { return FS_STATUS_USE_REAL_OS; } @@ -609,7 +677,9 @@ FSStatus FSGetPosFileWrapper(FSFileHandle handle, uint32_t *pos, FSErrorFlag errorMask, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || + !isValidFileHandle(handle)) { return FS_STATUS_USE_REAL_OS; } uint32_t handle_index = handle & HANDLE_MASK; @@ -640,7 +710,9 @@ FSStatus FSGetPosFileWrapper(FSFileHandle handle, FSStatus FSIsEofWrapper(FSFileHandle handle, FSErrorFlag errorMask, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || + !isValidFileHandle(handle)) { return FS_STATUS_USE_REAL_OS; } uint32_t handle_index = handle & HANDLE_MASK; @@ -674,7 +746,10 @@ FSStatus FSIsEofWrapper(FSFileHandle handle, FSStatus FSTruncateFileWrapper(FSFileHandle handle, FSErrorFlag errorMask, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || + !isValidFileHandle(handle)) { return FS_STATUS_USE_REAL_OS; } uint32_t handle_index = handle & HANDLE_MASK; @@ -697,7 +772,10 @@ FSStatus FSWriteFileWrapper(uint8_t *buffer, uint32_t unk1, FSErrorFlag errorMask, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) || + !isValidFileHandle(handle)) { return FS_STATUS_USE_REAL_OS; } FSStatus result = FS_STATUS_OK; @@ -711,7 +789,9 @@ FSStatus FSRemoveWrapper(char *path, FSErrorFlag errorMask, std::function fallback_function, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { return FS_STATUS_USE_REAL_OS; } @@ -740,7 +820,9 @@ FSStatus FSRenameWrapper(char *oldPath, FSErrorFlag errorMask, std::function fallback_function, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { return FS_STATUS_USE_REAL_OS; } @@ -767,10 +849,13 @@ FSStatus FSRenameWrapper(char *oldPath, } FSStatus FSFlushFileWrapper(FSFileHandle handle, FSErrorFlag errorMask, std::function result_handler) { - if (!gReplacementInfo.bundleMountInformation.isMounted || !isValidFileHandle(handle)) { + if ((gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_NONE) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) || + (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && !gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { return FS_STATUS_USE_REAL_OS; } FSStatus result = FS_STATUS_OK; + if (errorMask & FS_ERROR_FLAG_ACCESS_ERROR) { result = FS_STATUS_ACCESS_ERROR; } diff --git a/src/FSWrapper.h b/src/FSWrapper.h index fdc84f0..fe75218 100644 --- a/src/FSWrapper.h +++ b/src/FSWrapper.h @@ -10,7 +10,7 @@ typedef struct dirMagic { uint32_t handle; DIR *dir; bool in_use; - char path[255]; + char path[256]; OSMutex *mutex; } dirMagic_t; diff --git a/src/RPXLoading.cpp b/src/RPXLoading.cpp index 8bc7fff..d9ecacc 100644 --- a/src/RPXLoading.cpp +++ b/src/RPXLoading.cpp @@ -21,11 +21,12 @@ * 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 (gReplacementInfo.isRPXReplaced) { + if (gReplacementInfo.rpxReplacementInfo.isRPXReplaced) { memset(&metaxml->longname_ja, 0, 0x338C - 0x38C); // clear all names - 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)); + + snprintf(metaxml->longname_en, sizeof(metaxml->longname_en), "%s", gReplacementInfo.rpxReplacementInfo.metaInformation.longname); + snprintf(metaxml->shortname_en, sizeof(metaxml->shortname_en), "%s", gReplacementInfo.rpxReplacementInfo.metaInformation.longname); + snprintf(metaxml->publisher_en, sizeof(metaxml->publisher_en), "%s", gReplacementInfo.rpxReplacementInfo.metaInformation.longname); // Disbale the emanual metaxml->e_manual = 0; @@ -39,9 +40,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 (gReplacementInfo.isRPXReplaced) { + if (gReplacementInfo.rpxReplacementInfo.isRPXReplaced) { if (StringTools::EndsWith(path, iconTex)) { - auto *reader = new FileReader(reinterpret_cast(gReplacementInfo.iconCache), sizeof(gReplacementInfo.iconCache)); + auto *reader = new FileReader(reinterpret_cast(gReplacementInfo.rpxReplacementInfo.iconCache), sizeof(gReplacementInfo.rpxReplacementInfo.iconCache)); *handle = (uint32_t) reader; return FS_STATUS_OK; } @@ -92,11 +93,14 @@ static int parseINIhandler(void *user, const char *section, const char *name, 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); + fInfo->longname[0] = '\0'; + strncat(fInfo->longname, value, sizeof(fInfo->longname) - 1); } else if (MATCH("menu", "shortname")) { - strncpy(fInfo->shortname, value, 64 - 1); + fInfo->shortname[0] = '\0'; + strncat(fInfo->shortname, value, sizeof(fInfo->shortname) - 1); } else if (MATCH("menu", "author")) { - strncpy(fInfo->author, value, 64 - 1); + fInfo->author[0] = '\0'; + strncat(fInfo->author, value, sizeof(fInfo->author) - 1); } else { return 0; /* unknown section/name, error */ } @@ -110,26 +114,23 @@ bool RL_LoadFromSDOnNextLaunch(const char *bundle_path) { request.command = 0xFC; // IPC_CUSTOM_LOAD_CUSTOM_RPX; request.target = 0; // LOAD_FILE_TARGET_SD_CARD - request.filesize = 0; // unknown + request.filesize = 0; // unknown filesize request.fileoffset = 0; // romfs_fileInfo info; 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, &gReplacementInfo.metaInformation) < 0) { + if (ini_parse("rcc:/meta/meta.ini", parseINIhandler, &gReplacementInfo.rpxReplacementInfo.metaInformation) < 0) { DEBUG_FUNCTION_LINE("Failed to load and parse meta.ini"); } else { metaLoaded = true; @@ -145,30 +146,40 @@ bool RL_LoadFromSDOnNextLaunch(const char *bundle_path) { } if (reader) { uint32_t alreadyRead = 0; - uint32_t toRead = sizeof(gReplacementInfo.iconCache); + uint32_t toRead = sizeof(gReplacementInfo.rpxReplacementInfo.iconCache); do { - int read = reader->read(reinterpret_cast(&gReplacementInfo.iconCache[alreadyRead]), toRead); + int read = reader->read(reinterpret_cast(&gReplacementInfo.rpxReplacementInfo.iconCache[alreadyRead]), toRead); if (read <= 0) { break; } alreadyRead += read; toRead -= read; - } while (alreadyRead < sizeof(gReplacementInfo.iconCache)); + } while (alreadyRead < sizeof(gReplacementInfo.rpxReplacementInfo.iconCache)); delete reader; } else { - memset(gReplacementInfo.iconCache, 0, sizeof(gReplacementInfo.iconCache)); + memset(gReplacementInfo.rpxReplacementInfo.iconCache, 0, sizeof(gReplacementInfo.rpxReplacementInfo.iconCache)); } romfsUnmount("rcc"); } + } else { + if (!(gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && + gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted)) { + memset(gReplacementInfo.rpxReplacementInfo.iconCache, 0, sizeof(gReplacementInfo.rpxReplacementInfo.iconCache)); + } } if (!metaLoaded) { - 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)); + gReplacementInfo.rpxReplacementInfo.metaInformation.author[0] = '\0'; + gReplacementInfo.rpxReplacementInfo.metaInformation.shortname[0] = '\0'; + gReplacementInfo.rpxReplacementInfo.metaInformation.longname[0] = '\0'; + + strncat(gReplacementInfo.rpxReplacementInfo.metaInformation.author, bundle_path, sizeof(gReplacementInfo.rpxReplacementInfo.metaInformation.author) - 1); + strncat(gReplacementInfo.rpxReplacementInfo.metaInformation.shortname, bundle_path, sizeof(gReplacementInfo.rpxReplacementInfo.metaInformation.shortname) - 1); + strncat(gReplacementInfo.rpxReplacementInfo.metaInformation.longname, bundle_path, sizeof(gReplacementInfo.rpxReplacementInfo.metaInformation.longname) - 1); } - strncpy(request.path, bundle_path, 255); + request.path[0] = '\0'; + strncat(request.path, bundle_path, sizeof(request.path) - 1); DCFlushRange(&request, sizeof(LOAD_REQUEST)); @@ -187,27 +198,33 @@ bool RL_LoadFromSDOnNextLaunch(const char *bundle_path) { DCFlushRange(&gReplacementInfo, sizeof(gReplacementInfo)); if (!success) { - gReplacementInfo.replacementType = RPXLoader_NONE; + gReplacementInfo.rpxReplacementInfo.isRPXReplaced = false; DEBUG_FUNCTION_LINE("Failed to load %s on next restart", request.path); return false; + } else { + gReplacementInfo.rpxReplacementInfo.isRPXReplaced = true; } 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"); - 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; + gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath[0] = '\0'; + strncat(gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath, + completePath.c_str(), + sizeof(gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath) - 1); + gReplacementInfo.contentReplacementInfo.mode = CONTENTREDIRECT_FROM_WUHB_BUNDLE; } else { DEBUG_FUNCTION_LINE("Loaded file is no bundle"); - if (!gReplacementInfo.bundleMountInformation.isMounted) { - memset(gReplacementInfo.bundleMountInformation.path, 0, sizeof(gReplacementInfo.bundleMountInformation.path)); - } else { - gReplacementInfo.replacementType = RPXLoader_BUNDLE_OTHER_RPX; - gReplacementInfo.bundleMountInformation.redirectionRequested = true; + gReplacementInfo.rpxReplacementInfo.isRPXReplaced = true; + + if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE && + gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) { // keep the old /vol/content mounted, this way you can reload just the rpx via wiiload + gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath[0] = '\0'; + strncat(gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath, + gReplacementInfo.contentReplacementInfo.bundleMountInformation.mountedPath, + sizeof(gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath) - 1); } } diff --git a/src/globals.h b/src/globals.h index ac78f39..0673922 100644 --- a/src/globals.h +++ b/src/globals.h @@ -8,27 +8,43 @@ typedef struct MetaInformation_t { } MetaInformation; typedef struct BundleMountInformation_t { - bool redirectionRequested; bool isMounted; - char path[255]; - char workingDir[255]; + char toMountPath[255]; + char mountedPath[255]; } BundleMountInformation; -typedef enum RPXLoader_Type { - RPXLoader_NONE, - RPXLoader_RPX, - RPXLoader_BUNDLE, - RPXLoader_BUNDLE_OTHER_RPX, -} RPXLoader_Type; - -typedef struct RPXLoader_ReplacementInformation_t { +typedef struct RPXReplacementInfo_t { bool isRPXReplaced; MetaInformation metaInformation; - RPXLoader_Type replacementType; - BundleMountInformation bundleMountInformation; char iconCache[65580]; - uint32_t currentHash; +} RPXReplacementInfo; + +typedef enum ContentRedirect_Mode { + CONTENTREDIRECT_NONE, + CONTENTREDIRECT_FROM_WUHB_BUNDLE, + CONTENTREDIRECT_FROM_PATH, +} ContentRedirect_Mode; + +typedef struct ContentReplacementInfo_t { + ContentRedirect_Mode mode; + + BundleMountInformation bundleMountInformation; + + char workingDir[255]; + + char replacementPath[255]; + + bool replaceSave; + char savePath[255]; + + bool fallbackOnError; +} ContentReplacementInfo; + +typedef struct RPXLoader_ReplacementInformation_t { + RPXReplacementInfo rpxReplacementInfo; + ContentReplacementInfo contentReplacementInfo; } RPXLoader_ReplacementInformation; + extern RPXLoader_ReplacementInformation gReplacementInfo; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index a88b937..f3c7682 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,11 +32,16 @@ WUMS_INITIALIZE() { WUMS_APPLICATION_ENDS() { - if (gReplacementInfo.bundleMountInformation.isMounted) { - DEBUG_FUNCTION_LINE("Unmount /vol/content"); - romfsUnmount("rom"); - gReplacementInfo.bundleMountInformation.isMounted = false; - DCFlushRange(&gReplacementInfo, sizeof(gReplacementInfo)); + if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) { + gReplacementInfo.contentReplacementInfo.mode = CONTENTREDIRECT_NONE; + } + if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE) { + if (gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted) { + DEBUG_FUNCTION_LINE("Unmount /vol/content"); + romfsUnmount("rom"); + gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted = false; + DCFlushRange(&gReplacementInfo, sizeof(gReplacementInfo)); + } } } @@ -46,46 +51,56 @@ WUMS_APPLICATION_STARTS() { return; } WHBLogUdpInit(); + if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) { + return; + } + if (_SYSGetSystemApplicationTitleId(SYSTEM_APP_ID_HEALTH_AND_SAFETY) != OSGetTitleID()) { DEBUG_FUNCTION_LINE("Set gTryToReplaceOnNextLaunch, gReplacedRPX and gIsMounted to FALSE"); - gReplacementInfo.replacementType = RPXLoader_NONE; - gReplacementInfo.isRPXReplaced = false; - gReplacementInfo.bundleMountInformation.isMounted = false; - gReplacementInfo.bundleMountInformation.redirectionRequested = false; + gReplacementInfo.contentReplacementInfo.mode = CONTENTREDIRECT_NONE; DCFlushRange(&gReplacementInfo, sizeof(gReplacementInfo)); } else { - 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); + if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_WUHB_BUNDLE) { + uint32_t currentHash = StringTools::hash(gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath); - nn::act::Initialize(); - nn::act::SlotNo slot = nn::act::GetSlotNo(); - nn::act::Finalize(); + nn::act::Initialize(); + nn::act::PersistentId slot = nn::act::GetPersistentId(); + nn::act::Finalize(); - 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); + std::string basePath = StringTools::strfmt("/vol/external01/wiiu/apps/save/%08X", currentHash); + std::string common = StringTools::strfmt("fs:/vol/external01/wiiu/apps/save/%08X/common", currentHash); + std::string user = StringTools::strfmt("fs:/vol/external01/wiiu/apps/save/%08X/%08X", currentHash, 0x80000000 | slot); - strncpy(gReplacementInfo.savePath, basePath.c_str(), sizeof(gReplacementInfo.savePath)); - memset(gReplacementInfo.bundleMountInformation.workingDir, 0, sizeof(gReplacementInfo.bundleMountInformation.workingDir)); + gReplacementInfo.contentReplacementInfo.savePath[0] = '\0'; + strncat(gReplacementInfo.contentReplacementInfo.savePath, + basePath.c_str(), + sizeof(gReplacementInfo.contentReplacementInfo.savePath) - 1); - CreateSubfolder(common.c_str()); - CreateSubfolder(user.c_str()); - DEBUG_FUNCTION_LINE("Created %s and %s", common.c_str(), user.c_str()); - 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", gReplacementInfo.bundleMountInformation.path); - gReplacementInfo.bundleMountInformation.isMounted = false; - } - } else if (gReplacementInfo.replacementType == RPXLoader_RPX) { - // + memset(gReplacementInfo.contentReplacementInfo.workingDir, 0, sizeof(gReplacementInfo.contentReplacementInfo.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", gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath, RomfsSource_FileDescriptor_CafeOS) == 0) { + gReplacementInfo.contentReplacementInfo.bundleMountInformation.mountedPath[0] = '\0'; + strncat(gReplacementInfo.contentReplacementInfo.bundleMountInformation.mountedPath, + gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath, + sizeof(gReplacementInfo.contentReplacementInfo.bundleMountInformation.mountedPath) - 1); + + + gReplacementInfo.contentReplacementInfo.replacementPath[0] = '\0'; + strncat(gReplacementInfo.contentReplacementInfo.replacementPath, + "rom:/content", + sizeof(gReplacementInfo.contentReplacementInfo.replacementPath) - 1); + + DEBUG_FUNCTION_LINE("Mounted %s to /vol/content", gReplacementInfo.contentReplacementInfo.bundleMountInformation.mountedPath); + gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted = true; + } else { + DEBUG_FUNCTION_LINE("Failed to mount %s", gReplacementInfo.contentReplacementInfo.bundleMountInformation.toMountPath); + gReplacementInfo.contentReplacementInfo.bundleMountInformation.isMounted = false; } } + DCFlushRange(&gReplacementInfo, sizeof(gReplacementInfo)); } }