mirror of
https://github.com/wiiu-env/RPXLoadingModule.git
synced 2024-11-25 11:26:53 +01:00
Fix FSReadDir when redirecting the /vol/content directory to another path
This commit is contained in:
parent
91b7686e2e
commit
112c14498a
@ -12,7 +12,7 @@
|
||||
|
||||
#define ASYNC_RESULT_HANDLER [client, block, asyncData](FSStatus res) -> FSStatus { \
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Result was %d", res); \
|
||||
return send_result_async(client, block, asyncData, res);\
|
||||
return send_result_async(client, block, asyncData, res); \
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSOpenDir, FSClient *client, FSCmdBlock *block, char *path, FSDirectoryHandle *handle, FSErrorFlag errorMask) {
|
||||
@ -33,6 +33,10 @@ DECL_FUNCTION(FSStatus, FSOpenDir, FSClient *client, FSCmdBlock *block, char *pa
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSOpenDirAsync, FSClient *client, FSCmdBlock *block, char *path, FSDirectoryHandle *handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
FSErrorFlag realErrorMask = errorMask;
|
||||
|
||||
// Even real_FSOpenDir is still calling our FSOpenDirAsync hook. To bypass our code we use "FORCE_REAL_FUNC_WITH_FULL_ERRORS" as an errorMask.
|
||||
if ((errorMask & ERROR_FLAG_MASK) != FORCE_REAL_FUNC_MAGIC) {
|
||||
FSStatus result = FSOpenDirWrapper(path, handle, errorMask,
|
||||
[client, block, handle, errorMask, asyncData]
|
||||
(char *_path) -> FSStatus {
|
||||
@ -42,8 +46,11 @@ DECL_FUNCTION(FSStatus, FSOpenDirAsync, FSClient *client, FSCmdBlock *block, cha
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
realErrorMask = FS_ERROR_FLAG_ALL;
|
||||
}
|
||||
|
||||
return real_FSOpenDirAsync(client, block, path, handle, errorMask, asyncData);
|
||||
return real_FSOpenDirAsync(client, block, path, handle, realErrorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSReadDir, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSDirectoryEntry *entry, FSErrorFlag errorMask) {
|
||||
@ -58,12 +65,18 @@ DECL_FUNCTION(FSStatus, FSReadDir, FSClient *client, FSCmdBlock *block, FSDirect
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSReadDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSDirectoryEntry *entry, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE();
|
||||
FSErrorFlag realErrorMask = errorMask;
|
||||
// Even real_FSReadDir is still calling our FSReadDirAsync hook. To bypass our code we use "FORCE_REAL_FUNC_WITH_FULL_ERRORS" as an errorMask.
|
||||
if ((errorMask & ERROR_FLAG_MASK) != FORCE_REAL_FUNC_MAGIC) {
|
||||
FSStatus result = FSReadDirWrapper(handle, entry, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
realErrorMask = FS_ERROR_FLAG_ALL;
|
||||
}
|
||||
|
||||
return real_FSReadDirAsync(client, block, handle, entry, errorMask, asyncData);
|
||||
return real_FSReadDirAsync(client, block, handle, entry, realErrorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSCloseDir, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask) {
|
||||
@ -78,12 +91,18 @@ DECL_FUNCTION(FSStatus, FSCloseDir, FSClient *client, FSCmdBlock *block, FSDirec
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSCloseDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE();
|
||||
FSErrorFlag realErrorMask = errorMask;
|
||||
// Even real_FSCloseDir is still calling our FSCloseDirAsync hook. To bypass our code we use "FORCE_REAL_FUNC_WITH_FULL_ERRORS" as an errorMask.
|
||||
if ((errorMask & ERROR_FLAG_MASK) != FORCE_REAL_FUNC_MAGIC) {
|
||||
FSStatus result = FSCloseDirWrapper(handle, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
realErrorMask = FS_ERROR_FLAG_ALL;
|
||||
}
|
||||
|
||||
return real_FSCloseDirAsync(client, block, handle, errorMask, asyncData);
|
||||
return real_FSCloseDirAsync(client, block, handle, realErrorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSRewindDir, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask) {
|
||||
@ -98,12 +117,18 @@ DECL_FUNCTION(FSStatus, FSRewindDir, FSClient *client, FSCmdBlock *block, FSDire
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSRewindDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE();
|
||||
FSErrorFlag realErrorMask = errorMask;
|
||||
// Even real_FSRewindDir is still calling our FSRewindDirAsync hook. To bypass our code we use "FORCE_REAL_FUNC_WITH_FULL_ERRORS" as an errorMask.
|
||||
if ((errorMask & ERROR_FLAG_MASK) != FORCE_REAL_FUNC_MAGIC) {
|
||||
FSStatus result = FSRewindDirWrapper(handle, errorMask, ASYNC_RESULT_HANDLER);
|
||||
if (result != FS_STATUS_USE_REAL_OS) {
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
realErrorMask = FS_ERROR_FLAG_ALL;
|
||||
}
|
||||
|
||||
return real_FSRewindDirAsync(client, block, handle, errorMask, asyncData);
|
||||
return real_FSRewindDirAsync(client, block, handle, realErrorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSMakeDir, FSClient *client, FSCmdBlock *block, char *path, FSErrorFlag errorMask) {
|
||||
|
@ -134,6 +134,8 @@ void freeDirHandle(uint32_t handle) {
|
||||
dir_handle_mutex.unlock();
|
||||
}
|
||||
|
||||
extern "C" FSStatus (*real_FSOpenDir)(FSClient *, FSCmdBlock *, char *, FSDirectoryHandle *, FSErrorFlag);
|
||||
|
||||
FSStatus FSOpenDirWrapper(char *path,
|
||||
FSDirectoryHandle *handle,
|
||||
FSErrorFlag errorMask,
|
||||
@ -177,10 +179,30 @@ FSStatus FSOpenDirWrapper(char *path,
|
||||
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));
|
||||
if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) {
|
||||
auto dir_info = &dir_handles[handle_index];
|
||||
|
||||
dir_info->readResult = nullptr;
|
||||
dir_info->readResultCapacity = 0;
|
||||
dir_info->readResultNumberOfEntries = 0;
|
||||
|
||||
dir_info->realDirHandle = 0;
|
||||
|
||||
if (gFSClient && gFSCmd) {
|
||||
FSDirectoryHandle realHandle = 0;
|
||||
if (real_FSOpenDir(gFSClient, gFSCmd, path, &realHandle, (FSErrorFlag) FORCE_REAL_FUNC_WITH_FULL_ERRORS) == FS_STATUS_OK) {
|
||||
dir_info->realDirHandle = realHandle;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Failed to open real dir %s", path);
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Global FSClient or FSCmdBlock were null");
|
||||
}
|
||||
DCFlushRange(dir_info, 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;
|
||||
}
|
||||
@ -198,6 +220,8 @@ FSStatus FSOpenDirWrapper(char *path,
|
||||
return FS_STATUS_USE_REAL_OS;
|
||||
}
|
||||
|
||||
extern "C" FSStatus (*real_FSReadDir)(FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSDirectoryEntry *entry, FSErrorFlag errorMask);
|
||||
|
||||
FSStatus FSReadDirWrapper(FSDirectoryHandle handle,
|
||||
FSDirectoryEntry *entry,
|
||||
FSErrorFlag errorMask,
|
||||
@ -218,6 +242,19 @@ FSStatus FSReadDirWrapper(FSDirectoryHandle handle,
|
||||
OSLockMutex(dir_handles[handle_index].mutex);
|
||||
DIR *dir = dir_handles[handle_index].dir;
|
||||
|
||||
if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) {
|
||||
auto dir_info = &dir_handles[handle_index];
|
||||
|
||||
// Init list if needed
|
||||
if (dir_info->readResultCapacity == 0) {
|
||||
dir_info->readResult = (FSDirectoryEntry *) malloc(sizeof(FSDirectoryEntry));
|
||||
if (dir_info->readResult != nullptr) {
|
||||
dir_info->readResultCapacity = 1;
|
||||
}
|
||||
}
|
||||
DCFlushRange(dir_info, sizeof(dirMagic_t));
|
||||
}
|
||||
|
||||
struct dirent *entry_ = readdir(dir);
|
||||
FSStatus result = FS_STATUS_END;
|
||||
if (entry_) {
|
||||
@ -244,13 +281,73 @@ FSStatus FSReadDirWrapper(FSDirectoryHandle handle,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) {
|
||||
auto dir_info = &dir_handles[handle_index];
|
||||
if (dir_info->readResultNumberOfEntries >= dir_info->readResultCapacity) {
|
||||
auto newCapacity = dir_info->readResultCapacity * 2;
|
||||
dir_info->readResult = (FSDirectoryEntry *) realloc(dir_info->readResult, newCapacity * sizeof(FSDirectoryEntry));
|
||||
dir_info->readResultCapacity = newCapacity;
|
||||
if (dir_info->readResult == nullptr) {
|
||||
OSFatal("Failed to alloc memory for dir entry list");
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&dir_info->readResult[dir_info->readResultNumberOfEntries], entry, sizeof(FSDirectoryEntry));
|
||||
dir_info->readResultNumberOfEntries++;
|
||||
|
||||
DCFlushRange(dir_info->readResult, sizeof(FSDirectoryEntry) * dir_info->readResultNumberOfEntries);
|
||||
DCFlushRange(dir_info, sizeof(dirMagic_t));
|
||||
}
|
||||
|
||||
result = FS_STATUS_OK;
|
||||
} else if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) {
|
||||
auto dir_info = &dir_handles[handle_index];
|
||||
// Read the real directory.
|
||||
if (dir_info->realDirHandle != 0) {
|
||||
if (gFSClient && gFSCmd) {
|
||||
FSDirectoryEntry realDirEntry;
|
||||
FSStatus readDirResult = FS_STATUS_OK;
|
||||
result = FS_STATUS_END;
|
||||
while (readDirResult == FS_STATUS_OK) {
|
||||
readDirResult = real_FSReadDir(gFSClient, gFSCmd, dir_info->realDirHandle, &realDirEntry, (FSErrorFlag) FORCE_REAL_FUNC_WITH_FULL_ERRORS);
|
||||
if (readDirResult == FS_STATUS_OK) {
|
||||
bool found = false;
|
||||
for (int i = 0; i < dir_info->readResultNumberOfEntries; i++) {
|
||||
auto curResult = &dir_info->readResult[i];
|
||||
// Check if this is a new result
|
||||
if (strncmp(curResult->name, realDirEntry.name, sizeof(realDirEntry.name) - 1) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// If it's new we can use it :)
|
||||
if (!found) {
|
||||
memcpy(entry, &realDirEntry, sizeof(FSDirectoryEntry));
|
||||
result = FS_STATUS_OK;
|
||||
break;
|
||||
}
|
||||
} else if (readDirResult == FS_STATUS_END) {
|
||||
result = FS_STATUS_END;
|
||||
break;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("real_FSReadDir returned an unexpected error: %08X", readDirResult);
|
||||
result = FS_STATUS_END;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Global FSClient or FSCmdBlock were null");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OSUnlockMutex(dir_handles[handle_index].mutex);
|
||||
return result_handler(result);
|
||||
}
|
||||
|
||||
extern "C" FSStatus (*real_FSCloseDir)(FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask);
|
||||
|
||||
FSStatus FSCloseDirWrapper(FSDirectoryHandle handle,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler) {
|
||||
@ -274,11 +371,38 @@ FSStatus FSCloseDirWrapper(FSDirectoryHandle handle,
|
||||
result = FS_STATUS_MEDIA_ERROR;
|
||||
}
|
||||
|
||||
if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) {
|
||||
auto dir_info = &dir_handles[handle_index];
|
||||
|
||||
if (dir_info->realDirHandle != 0) {
|
||||
if (gFSClient && gFSCmd) {
|
||||
auto realResult = real_FSCloseDir(gFSClient, gFSCmd, dir_info->realDirHandle, (FSErrorFlag) FORCE_REAL_FUNC_WITH_FULL_ERRORS);
|
||||
if (realResult == FS_STATUS_OK) {
|
||||
dir_info->realDirHandle = 0;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Failed to closed dir %d", realResult);
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Global FSClient or FSCmdBlock were null");
|
||||
}
|
||||
}
|
||||
|
||||
if (dir_info->readResult != nullptr) {
|
||||
free(dir_info->readResult);
|
||||
dir_info->readResult = nullptr;
|
||||
dir_info->readResultCapacity = 0;
|
||||
dir_info->readResultNumberOfEntries = 0;
|
||||
}
|
||||
DCFlushRange(dir_info, sizeof(dirMagic_t));
|
||||
}
|
||||
|
||||
OSUnlockMutex(dir_handles[handle_index].mutex);
|
||||
freeDirHandle(handle_index);
|
||||
return result_handler(result);
|
||||
}
|
||||
|
||||
extern "C" FSStatus (*real_FSRewindDir)(FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask);
|
||||
|
||||
FSStatus FSRewindDirWrapper(FSDirectoryHandle handle,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSStatus)> &result_handler) {
|
||||
@ -297,6 +421,29 @@ FSStatus FSRewindDirWrapper(FSDirectoryHandle handle,
|
||||
|
||||
DIR *dir = dir_handles[real_handle].dir;
|
||||
rewinddir(dir);
|
||||
|
||||
if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) {
|
||||
auto dir_info = &dir_handles[handle_index];
|
||||
|
||||
if (dir_info->readResult != nullptr) {
|
||||
dir_info->readResultNumberOfEntries = 0;
|
||||
memset(dir_info->readResult, 0, sizeof(FSDirectoryEntry) * dir_info->readResultCapacity);
|
||||
}
|
||||
|
||||
if (dir_info->realDirHandle != 0) {
|
||||
if (gFSClient && gFSCmd) {
|
||||
if (real_FSRewindDir(gFSClient, gFSCmd, dir_info->realDirHandle, (FSErrorFlag) FORCE_REAL_FUNC_WITH_FULL_ERRORS) == FS_STATUS_OK) {
|
||||
dir_info->realDirHandle = 0;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Failed to rewind dir");
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE("Global FSClient or FSCmdBlock were null");
|
||||
}
|
||||
}
|
||||
DCFlushRange(dir_info, sizeof(dirMagic_t));
|
||||
}
|
||||
|
||||
OSUnlockMutex(dir_handles[handle_index].mutex);
|
||||
return result_handler(FS_STATUS_OK);
|
||||
}
|
||||
|
@ -7,11 +7,18 @@
|
||||
#include <coreinit/mutex.h>
|
||||
|
||||
typedef struct dirMagic {
|
||||
uint32_t handle;
|
||||
DIR *dir;
|
||||
bool in_use;
|
||||
char path[256];
|
||||
OSMutex *mutex;
|
||||
uint32_t handle{};
|
||||
DIR *dir{};
|
||||
bool in_use{};
|
||||
char path[256]{};
|
||||
|
||||
OSMutex *mutex{};
|
||||
|
||||
FSDirectoryEntry * readResult = nullptr;
|
||||
int readResultCapacity = 0;
|
||||
int readResultNumberOfEntries = 0;
|
||||
|
||||
FSDirectoryHandle realDirHandle = 0;
|
||||
} dirMagic_t;
|
||||
|
||||
typedef struct fileMagic {
|
||||
@ -21,6 +28,12 @@ typedef struct fileMagic {
|
||||
OSMutex *mutex;
|
||||
} fileMagic_t;
|
||||
|
||||
|
||||
#define ERROR_FLAG_MASK (0xFFFF0000)
|
||||
#define FORCE_REAL_FUNC_MAGIC (0x42420000)
|
||||
#define FORCE_REAL_FUNC_WITH_FULL_ERRORS (FORCE_REAL_FUNC_MAGIC | 0x0000FFFF)
|
||||
|
||||
#define HANDLE_INDICATOR_MASK 0xFFFFFF00
|
||||
#define HANDLE_INDICATOR_MASK 0xFFFFFF00
|
||||
#define HANDLE_MASK (0x000000FF)
|
||||
#define DIR_HANDLE_MAGIC 0x30000000
|
||||
|
@ -1,3 +1,7 @@
|
||||
#include <coreinit/filesystem.h>
|
||||
#include "globals.h"
|
||||
|
||||
RPXLoader_ReplacementInformation gReplacementInfo __attribute__((section(".data")));
|
||||
|
||||
FSClient * gFSClient __attribute__((section(".data"))) = nullptr;
|
||||
FSCmdBlock * gFSCmd __attribute__((section(".data"))) = nullptr;
|
@ -1,5 +1,6 @@
|
||||
#include <wums.h>
|
||||
#include <coreinit/mutex.h>
|
||||
#include <coreinit/filesystem.h>
|
||||
|
||||
typedef struct MetaInformation_t {
|
||||
char shortname[64];
|
||||
@ -49,3 +50,5 @@ typedef struct RPXLoader_ReplacementInformation_t {
|
||||
|
||||
|
||||
extern RPXLoader_ReplacementInformation gReplacementInfo;
|
||||
extern FSClient * gFSClient;
|
||||
extern FSCmdBlock * gFSCmd;
|
22
src/main.cpp
22
src/main.cpp
@ -46,6 +46,11 @@ WUMS_APPLICATION_ENDS() {
|
||||
}
|
||||
}
|
||||
gReplacementInfo.rpxReplacementInfo.isRPXReplaced = false;
|
||||
if (gFSClient) {
|
||||
FSDelClient(gFSClient, FS_ERROR_FLAG_ALL);
|
||||
free(gFSClient);
|
||||
}
|
||||
free(gFSCmd);
|
||||
}
|
||||
|
||||
WUMS_APPLICATION_STARTS() {
|
||||
@ -59,6 +64,23 @@ WUMS_APPLICATION_STARTS() {
|
||||
}
|
||||
WHBLogUdpInit();
|
||||
if (gReplacementInfo.contentReplacementInfo.mode == CONTENTREDIRECT_FROM_PATH) {
|
||||
auto fsClient = (FSClient *) memalign(0x20, sizeof(FSClient));
|
||||
auto fsCmd = (FSCmdBlock *) memalign(0x20, sizeof(FSCmdBlock));
|
||||
|
||||
if (fsClient == nullptr || fsCmd == nullptr) {
|
||||
DEBUG_FUNCTION_LINE("Failed to alloc memory for fsclient or fsCmd");
|
||||
free(fsClient);
|
||||
free(fsCmd);
|
||||
} else {
|
||||
auto rc = FSAddClient(fsClient, FS_ERROR_FLAG_ALL);
|
||||
if (rc < 0) {
|
||||
DEBUG_FUNCTION_LINE("Failed to add FSClient");
|
||||
} else {
|
||||
FSInitCmdBlock(fsCmd);
|
||||
gFSClient = fsClient;
|
||||
gFSCmd = fsCmd;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user