WIP, untested
This commit is contained in:
parent
98a137c91f
commit
0fbfd24198
2
Makefile
2
Makefile
|
@ -49,7 +49,7 @@ CXXFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||||
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
CFLAGS += -DDEBUG -DVERBOSE_DEBUG -g
|
||||||
endif
|
endif
|
||||||
|
|
||||||
LIBS := -lwums -lwut -lfunctionpatcher
|
LIBS := -lwums -lwut -lfunctionpatcher -lmocha
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
# list of directories containing libraries, this must be the top level
|
# list of directories containing libraries, this must be the top level
|
||||||
|
|
|
@ -7,20 +7,29 @@
|
||||||
|
|
||||||
static FSError processFSAShimInThread(FSAShimBuffer *shimBuffer) {
|
static FSError processFSAShimInThread(FSAShimBuffer *shimBuffer) {
|
||||||
FSError res;
|
FSError res;
|
||||||
if (gThreadsRunning) {
|
|
||||||
|
auto upid = OSGetUPID();
|
||||||
|
if (!sLayerInfoForUPID.contains(upid)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("invalid UPID %d", upid);
|
||||||
|
OSFatal("Tried to start threads for invalid UPID.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto & layerInfo = sLayerInfoForUPID[upid];
|
||||||
|
if (layerInfo->threadsRunning) {
|
||||||
auto param = (FSShimWrapper *) malloc(sizeof(FSShimWrapper));
|
auto param = (FSShimWrapper *) malloc(sizeof(FSShimWrapper));
|
||||||
if (param == nullptr) {
|
if (param == nullptr) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for FSShimWrapper");
|
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for FSShimWrapper");
|
||||||
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapper");
|
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapper");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
param->upid = OSGetUPID();
|
||||||
param->api = FS_SHIM_API_FSA;
|
param->api = FS_SHIM_API_FSA;
|
||||||
param->sync = FS_SHIM_TYPE_SYNC;
|
param->sync = FS_SHIM_TYPE_SYNC;
|
||||||
param->shim = shimBuffer;
|
param->shim = shimBuffer;
|
||||||
|
|
||||||
if (OSGetCurrentThread() == gThreadData[OSGetCoreId()].thread) {
|
if (OSGetCurrentThread() == layerInfo->threadData[OSGetCoreId()].thread) {
|
||||||
res = processShimBufferForFSA(param);
|
res = processShimBufferForFSA(param);
|
||||||
//No need to clean "param", it has been already free'd in processFSAShimBuffer.
|
// No need to clean "param", it has been already free'd in processFSAShimBuffer.
|
||||||
} else {
|
} else {
|
||||||
auto message = (FSShimWrapperMessage *) malloc(sizeof(FSShimWrapperMessage));
|
auto message = (FSShimWrapperMessage *) malloc(sizeof(FSShimWrapperMessage));
|
||||||
if (message == nullptr) {
|
if (message == nullptr) {
|
||||||
|
@ -31,7 +40,7 @@ static FSError processFSAShimInThread(FSAShimBuffer *shimBuffer) {
|
||||||
|
|
||||||
constexpr int32_t messageSize = sizeof(message->messages) / sizeof(message->messages[0]);
|
constexpr int32_t messageSize = sizeof(message->messages) / sizeof(message->messages[0]);
|
||||||
OSInitMessageQueue(&message->messageQueue, message->messages, messageSize);
|
OSInitMessageQueue(&message->messageQueue, message->messages, messageSize);
|
||||||
if (!sendMessageToThread(message)) {
|
if (!sendMessageToThread(layerInfo, message)) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to send message to thread");
|
DEBUG_FUNCTION_LINE_ERR("Failed to send message to thread");
|
||||||
OSFatal("ContentRedirectionModule: Failed send message to thread");
|
OSFatal("ContentRedirectionModule: Failed send message to thread");
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,8 +2,10 @@
|
||||||
#include "FileUtils.h"
|
#include "FileUtils.h"
|
||||||
#include "utils/StringTools.h"
|
#include "utils/StringTools.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
|
#include <content_redirection/redirection.h>
|
||||||
#include <coreinit/core.h>
|
#include <coreinit/core.h>
|
||||||
#include <coreinit/thread.h>
|
#include <coreinit/thread.h>
|
||||||
|
#include <mocha/mocha.h>
|
||||||
|
|
||||||
FSStatus processFSError(FSError fsError, FSClient *client, FSErrorFlag errorMask) {
|
FSStatus processFSError(FSError fsError, FSClient *client, FSErrorFlag errorMask) {
|
||||||
auto result = fsError >= 0 ? static_cast<FSStatus>(fsError) : fsaDecodeFsaStatusToFsStatus(fsError);
|
auto result = fsError >= 0 ? static_cast<FSStatus>(fsError) : fsaDecodeFsaStatusToFsStatus(fsError);
|
||||||
|
@ -89,7 +91,15 @@ void handleAsyncRequestsCallback(IOSError err, void *context) {
|
||||||
|
|
||||||
bool processFSAShimInThread(FSAShimBuffer *shimBuffer, FSClient *client, FSCmdBlock *block, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
bool processFSAShimInThread(FSAShimBuffer *shimBuffer, FSClient *client, FSCmdBlock *block, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||||
bool res = false;
|
bool res = false;
|
||||||
if (gThreadsRunning) {
|
|
||||||
|
auto upid = OSGetUPID();
|
||||||
|
if (!sLayerInfoForUPID.contains(upid)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("invalid UPID %d", upid);
|
||||||
|
OSFatal("Tried to start threads for invalid UPID.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto & layerInfo = sLayerInfoForUPID[upid];
|
||||||
|
if (layerInfo->threadsRunning) {
|
||||||
// we **don't** need to free this in this function.
|
// we **don't** need to free this in this function.
|
||||||
auto param = (FSShimWrapper *) malloc(sizeof(FSShimWrapper));
|
auto param = (FSShimWrapper *) malloc(sizeof(FSShimWrapper));
|
||||||
if (param == nullptr) {
|
if (param == nullptr) {
|
||||||
|
@ -97,6 +107,7 @@ bool processFSAShimInThread(FSAShimBuffer *shimBuffer, FSClient *client, FSCmdBl
|
||||||
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapper");
|
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapper");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
param->upid = OSGetUPID();
|
||||||
param->api = FS_SHIM_API_FS;
|
param->api = FS_SHIM_API_FS;
|
||||||
param->sync = FS_SHIM_TYPE_ASYNC;
|
param->sync = FS_SHIM_TYPE_ASYNC;
|
||||||
param->shim = shimBuffer;
|
param->shim = shimBuffer;
|
||||||
|
@ -111,7 +122,7 @@ bool processFSAShimInThread(FSAShimBuffer *shimBuffer, FSClient *client, FSCmdBl
|
||||||
// Copy by value
|
// Copy by value
|
||||||
param->asyncFS.errorMask = errorMask;
|
param->asyncFS.errorMask = errorMask;
|
||||||
|
|
||||||
if (OSGetCurrentThread() == gThreadData[OSGetCoreId()].thread) {
|
if (OSGetCurrentThread() == layerInfo->threadData[OSGetCoreId()].thread) {
|
||||||
processShimBufferForFS(param);
|
processShimBufferForFS(param);
|
||||||
// because we're doing this in sync, free(param) has already been called at this point.
|
// because we're doing this in sync, free(param) has already been called at this point.
|
||||||
res = true;
|
res = true;
|
||||||
|
@ -122,7 +133,7 @@ bool processFSAShimInThread(FSAShimBuffer *shimBuffer, FSClient *client, FSCmdBl
|
||||||
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapperMessage");
|
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapperMessage");
|
||||||
}
|
}
|
||||||
message->param = param;
|
message->param = param;
|
||||||
res = sendMessageToThread(message);
|
res = sendMessageToThread(layerInfo, message);
|
||||||
// the other thread is call free for us, so we can return early!
|
// the other thread is call free for us, so we can return early!
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -217,7 +228,6 @@ DECL_FUNCTION(FSStatus, FSOpenFileExAsync, FSClient *client, FSCmdBlock *block,
|
||||||
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
|
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
|
||||||
hackyBuffer[1] = (uint32_t) handle;
|
hackyBuffer[1] = (uint32_t) handle;
|
||||||
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
|
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
|
||||||
|
|
||||||
return FS_STATUS_OK;
|
return FS_STATUS_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -555,28 +565,74 @@ DECL_FUNCTION(FSStatus, FSChangeDirAsync, FSClient *client, FSCmdBlock *block, c
|
||||||
return real_FSChangeDirAsync(client, block, path, errorMask, asyncData);
|
return real_FSChangeDirAsync(client, block, path, errorMask, asyncData);
|
||||||
}
|
}
|
||||||
|
|
||||||
function_replacement_data_t fs_file_function_replacements[] = {
|
DECL_FUNCTION(void, __PPCExit, uint32_t u1) {
|
||||||
REPLACE_FUNCTION(FSOpenFileExAsync, LIBRARY_COREINIT, FSOpenFileExAsync),
|
auto UPID = OSGetUPID();
|
||||||
REPLACE_FUNCTION(FSCloseFileAsync, LIBRARY_COREINIT, FSCloseFileAsync),
|
if (UPID != 2 && UPID != 15 && sLayerInfoForUPID.contains(UPID)) {
|
||||||
REPLACE_FUNCTION(FSGetStatAsync, LIBRARY_COREINIT, FSGetStatAsync),
|
DEBUG_FUNCTION_LINE_ERR("Clear layer for UPID %d", UPID);
|
||||||
REPLACE_FUNCTION(FSGetStatFileAsync, LIBRARY_COREINIT, FSGetStatFileAsync),
|
clearFSLayer(sLayerInfoForUPID[UPID]);
|
||||||
REPLACE_FUNCTION_VIA_ADDRESS(FSReadFileGeneric, 0x3201C400 + 0x4ecc0, 0x101C400 + 0x4ecc0),
|
stopFSIOThreads();
|
||||||
REPLACE_FUNCTION(FSSetPosFileAsync, LIBRARY_COREINIT, FSSetPosFileAsync),
|
}
|
||||||
REPLACE_FUNCTION(FSGetPosFileAsync, LIBRARY_COREINIT, FSGetPosFileAsync),
|
real___PPCExit(u1);
|
||||||
REPLACE_FUNCTION(FSIsEofAsync, LIBRARY_COREINIT, FSIsEofAsync),
|
}
|
||||||
REPLACE_FUNCTION_VIA_ADDRESS(FSWriteFileGeneric, 0x3201C400 + 0x4eec0, 0x101C400 + 0x4eec0),
|
|
||||||
REPLACE_FUNCTION(FSTruncateFileAsync, LIBRARY_COREINIT, FSTruncateFileAsync),
|
|
||||||
REPLACE_FUNCTION(FSRemoveAsync, LIBRARY_COREINIT, FSRemoveAsync),
|
|
||||||
REPLACE_FUNCTION(FSRenameAsync, LIBRARY_COREINIT, FSRenameAsync),
|
|
||||||
REPLACE_FUNCTION(FSFlushFileAsync, LIBRARY_COREINIT, FSFlushFileAsync),
|
|
||||||
REPLACE_FUNCTION(FSChangeModeAsync, LIBRARY_COREINIT, FSChangeModeAsync),
|
|
||||||
|
|
||||||
REPLACE_FUNCTION(FSOpenDirAsync, LIBRARY_COREINIT, FSOpenDirAsync),
|
MochaUtilsStatus MountWrapper(const char *mount, const char *dev, const char *mountTo) {
|
||||||
REPLACE_FUNCTION(FSReadDirAsync, LIBRARY_COREINIT, FSReadDirAsync),
|
auto res = Mocha_MountFS(mount, dev, mountTo);
|
||||||
REPLACE_FUNCTION(FSCloseDirAsync, LIBRARY_COREINIT, FSCloseDirAsync),
|
if (res == MOCHA_RESULT_ALREADY_EXISTS) {
|
||||||
REPLACE_FUNCTION(FSRewindDirAsync, LIBRARY_COREINIT, FSRewindDirAsync),
|
res = Mocha_MountFS(mount, nullptr, mountTo);
|
||||||
REPLACE_FUNCTION(FSMakeDirAsync, LIBRARY_COREINIT, FSMakeDirAsync),
|
}
|
||||||
REPLACE_FUNCTION(FSChangeDirAsync, LIBRARY_COREINIT, FSChangeDirAsync),
|
|
||||||
|
if (res == MOCHA_RESULT_SUCCESS) {
|
||||||
|
std::string mountPath = std::string(mount) + ":/";
|
||||||
|
DEBUG_FUNCTION_LINE_VERBOSE("Mounted %s", mountPath.c_str());
|
||||||
|
} else {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Failed to mount %s: %s [%d]", mount, Mocha_GetStatusStr(res), res);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern ContentRedirectionApiErrorType CRAddFSLayerEx(CRLayerHandle *handle, const char *layerName, const char *replacementDir, FSLayerType layerType, uint32_t upid);
|
||||||
|
DECL_FUNCTION(void, START_HOOK) {
|
||||||
|
real_START_HOOK();
|
||||||
|
auto UPID = OSGetUPID();
|
||||||
|
if (UPID != 2 && UPID != 15 && sLayerInfoForUPID.contains(UPID)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Clear layer for UPID %d", UPID);
|
||||||
|
clearFSLayer(sLayerInfoForUPID[UPID]);
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Start threads");
|
||||||
|
startFSIOThreads();
|
||||||
|
}
|
||||||
|
if (UPID == 8) {
|
||||||
|
CRLayerHandle handle;
|
||||||
|
int test = (int) 2;
|
||||||
|
|
||||||
|
Mocha_MountFS("storage_mlc", nullptr, "/vol/storage_mlc01");
|
||||||
|
CRAddFSLayerEx(&handle, "browser_test", "storage_mlc:/usr/tmp", FS_LAYER_TYPE_CONTENT_MERGE, UPID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function_replacement_data_t fs_file_function_replacements[] = {
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(__PPCExit, LIBRARY_COREINIT, __PPCExit, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSOpenFileExAsync, LIBRARY_COREINIT, FSOpenFileExAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSCloseFileAsync, LIBRARY_COREINIT, FSCloseFileAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSGetStatAsync, LIBRARY_COREINIT, FSGetStatAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSGetStatFileAsync, LIBRARY_COREINIT, FSGetStatFileAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_VIA_ADDRESS_FOR_PROCESS(FSReadFileGeneric, 0x3201C400 + 0x4ecc0, 0x101C400 + 0x4ecc0, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSSetPosFileAsync, LIBRARY_COREINIT, FSSetPosFileAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSGetPosFileAsync, LIBRARY_COREINIT, FSGetPosFileAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSIsEofAsync, LIBRARY_COREINIT, FSIsEofAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_VIA_ADDRESS_FOR_PROCESS(FSWriteFileGeneric, 0x3201C400 + 0x4eec0, 0x101C400 + 0x4eec0, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_VIA_ADDRESS_FOR_PROCESS(START_HOOK, 0x3201C400 + 0x3edc0, 0x101C400 + 0x3edc0, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSTruncateFileAsync, LIBRARY_COREINIT, FSTruncateFileAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSRemoveAsync, LIBRARY_COREINIT, FSRemoveAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSRenameAsync, LIBRARY_COREINIT, FSRenameAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSFlushFileAsync, LIBRARY_COREINIT, FSFlushFileAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSChangeModeAsync, LIBRARY_COREINIT, FSChangeModeAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSOpenDirAsync, LIBRARY_COREINIT, FSOpenDirAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSReadDirAsync, LIBRARY_COREINIT, FSReadDirAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSCloseDirAsync, LIBRARY_COREINIT, FSCloseDirAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSRewindDirAsync, LIBRARY_COREINIT, FSRewindDirAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSMakeDirAsync, LIBRARY_COREINIT, FSMakeDirAsync, FP_TARGET_PROCESS_ALL),
|
||||||
|
REPLACE_FUNCTION_FOR_PROCESS(FSChangeDirAsync, LIBRARY_COREINIT, FSChangeDirAsync, FP_TARGET_PROCESS_ALL),
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t fs_file_function_replacements_size = sizeof(fs_file_function_replacements) / sizeof(function_replacement_data_t);
|
uint32_t fs_file_function_replacements_size = sizeof(fs_file_function_replacements) / sizeof(function_replacement_data_t);
|
||||||
|
|
|
@ -239,7 +239,7 @@ FSWrapperMergeDirsWithParent::~FSWrapperMergeDirsWithParent() {
|
||||||
if (clientHandle) {
|
if (clientHandle) {
|
||||||
FSError res;
|
FSError res;
|
||||||
if ((res = FSADelClient(clientHandle)) != FS_ERROR_OK) {
|
if ((res = FSADelClient(clientHandle)) != FS_ERROR_OK) {
|
||||||
DEBUG_FUNCTION_LINE_ERR("[%s] FSADelClient failed: %s (%d)", FSAGetStatusStr(res), res);
|
DEBUG_FUNCTION_LINE_ERR("FSADelClient failed: %s (%d)", FSAGetStatusStr(res), res);
|
||||||
}
|
}
|
||||||
clientHandle = 0;
|
clientHandle = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,23 +11,17 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
std::mutex workingDirMutex;
|
std::string getFullPathGeneric(std::shared_ptr<LayerInfo> &layerInfo, FSAClientHandle client, const char *path) {
|
||||||
std::map<FSAClientHandle, std::string> workingDirs;
|
std::lock_guard<std::mutex> workingDirLock(layerInfo->mutex);
|
||||||
|
|
||||||
std::mutex fsLayerMutex;
|
|
||||||
std::vector<std::unique_ptr<IFSWrapper>> fsLayers;
|
|
||||||
|
|
||||||
std::string getFullPathGeneric(FSAClientHandle client, const char *path, std::mutex &mutex, std::map<FSAClientHandle, std::string> &map) {
|
|
||||||
std::lock_guard<std::mutex> workingDirLock(mutex);
|
|
||||||
|
|
||||||
std::string res;
|
std::string res;
|
||||||
|
|
||||||
if (path[0] != '/' && path[0] != '\\') {
|
if (path[0] != '/' && path[0] != '\\') {
|
||||||
if (map.count(client) == 0) {
|
if (layerInfo->workingDirs.count(client) == 0) {
|
||||||
DEBUG_FUNCTION_LINE_WARN("No working dir found for client %08X, fallback to \"/\"", client);
|
DEBUG_FUNCTION_LINE_WARN("No working dir found for client %08X, fallback to \"/\"", client);
|
||||||
workingDirs[client] = "/";
|
layerInfo->workingDirs[client] = "/";
|
||||||
}
|
}
|
||||||
res = string_format("%s%s", map.at(client).c_str(), path);
|
res = string_format("%s%s", layerInfo->workingDirs.at(client).c_str(), path);
|
||||||
} else {
|
} else {
|
||||||
res = path;
|
res = path;
|
||||||
}
|
}
|
||||||
|
@ -54,27 +48,33 @@ void setWorkingDirGeneric(FSAClientHandle client, const char *path, std::mutex &
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::string getFullPath(FSAClientHandle pClient, const char *path) {
|
std::string getFullPath(std::shared_ptr<LayerInfo> &layerInfo, FSAClientHandle pClient, const char *path) {
|
||||||
return getFullPathGeneric(pClient, path, workingDirMutex, workingDirs);
|
return getFullPathGeneric(layerInfo, pClient, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setWorkingDir(FSAClientHandle client, const char *path) {
|
void setWorkingDir(std::shared_ptr<LayerInfo> &layerInfo, FSAClientHandle client, const char *path) {
|
||||||
setWorkingDirGeneric(client, path, workingDirMutex, workingDirs);
|
setWorkingDirGeneric(client, path, layerInfo->workingDirMutex, layerInfo->workingDirs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearFSLayer() {
|
void clearFSLayer(std::shared_ptr<LayerInfo> &layerInfo) {
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> workingDirLock(workingDirMutex);
|
std::lock_guard<std::mutex> workingDirLock(layerInfo->workingDirMutex);
|
||||||
workingDirs.clear();
|
layerInfo->workingDirs.clear();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> layerLock(fsLayerMutex);
|
std::lock_guard<std::mutex> layerLock(layerInfo->mutex);
|
||||||
fsLayers.clear();
|
layerInfo->layers.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sendMessageToThread(FSShimWrapperMessage *param) {
|
void clearFSLayers() {
|
||||||
auto *curThread = &gThreadData[OSGetCoreId()];
|
for (auto &[upid, layerInfo] : sLayerInfoForUPID) {
|
||||||
|
clearFSLayer(layerInfo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sendMessageToThread(std::shared_ptr<LayerInfo> &layerInfo, FSShimWrapperMessage *param) {
|
||||||
|
auto *curThread = &layerInfo->threadData[OSGetCoreId()];
|
||||||
if (curThread->setup) {
|
if (curThread->setup) {
|
||||||
OSMessage send;
|
OSMessage send;
|
||||||
send.message = param;
|
send.message = param;
|
||||||
|
@ -92,12 +92,20 @@ bool sendMessageToThread(FSShimWrapperMessage *param) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<uint32_t, std::shared_ptr<LayerInfo>> sLayerInfoForUPID;
|
||||||
|
|
||||||
FSError doForLayer(FSShimWrapper *param) {
|
FSError doForLayer(FSShimWrapper *param) {
|
||||||
std::lock_guard<std::mutex> lock(fsLayerMutex);
|
if (!sLayerInfoForUPID.contains(param->upid)) {
|
||||||
if (!fsLayers.empty()) {
|
DEBUG_FUNCTION_LINE_ERR("INVALID UPID IN SHIMWRAPPER: %d", param->upid);
|
||||||
uint32_t startIndex = fsLayers.size();
|
OSFatal("Invalid UPID");
|
||||||
for (uint32_t i = fsLayers.size(); i > 0; i--) {
|
}
|
||||||
if ((uint32_t) fsLayers[i - 1]->getLayerId() == param->shim->clientHandle) {
|
auto &layerInfo = sLayerInfoForUPID[param->upid];
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> lock(layerInfo->mutex);
|
||||||
|
if (!layerInfo->layers.empty()) {
|
||||||
|
uint32_t startIndex = layerInfo->layers.size();
|
||||||
|
for (uint32_t i = layerInfo->layers.size(); i > 0; i--) {
|
||||||
|
if ((uint32_t) layerInfo->layers[i - 1]->getLayerId() == param->shim->clientHandle) {
|
||||||
startIndex = i - 1;
|
startIndex = i - 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -105,7 +113,7 @@ FSError doForLayer(FSShimWrapper *param) {
|
||||||
|
|
||||||
if (startIndex > 0) {
|
if (startIndex > 0) {
|
||||||
for (uint32_t i = startIndex; i > 0; i--) {
|
for (uint32_t i = startIndex; i > 0; i--) {
|
||||||
auto &layer = fsLayers[i - 1];
|
auto &layer = layerInfo->layers[i - 1];
|
||||||
if (!layer->isActive()) {
|
if (!layer->isActive()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -116,7 +124,7 @@ FSError doForLayer(FSShimWrapper *param) {
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case FSA_COMMAND_OPEN_DIR: {
|
case FSA_COMMAND_OPEN_DIR: {
|
||||||
auto *request = ¶m->shim->request.openDir;
|
auto *request = ¶m->shim->request.openDir;
|
||||||
auto fullPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->path);
|
auto fullPath = getFullPath(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->path);
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] OpenDir: %s (full path: %s)", layer->getName().c_str(), request->path, fullPath.c_str());
|
DEBUG_FUNCTION_LINE_VERBOSE("[%s] OpenDir: %s (full path: %s)", layer->getName().c_str(), request->path, fullPath.c_str());
|
||||||
// Hacky solution:
|
// Hacky solution:
|
||||||
auto *hackyBuffer = (uint32_t *) ¶m->shim->response;
|
auto *hackyBuffer = (uint32_t *) ¶m->shim->response;
|
||||||
|
@ -154,14 +162,14 @@ FSError doForLayer(FSShimWrapper *param) {
|
||||||
}
|
}
|
||||||
case FSA_COMMAND_MAKE_DIR: {
|
case FSA_COMMAND_MAKE_DIR: {
|
||||||
auto *request = ¶m->shim->request.makeDir;
|
auto *request = ¶m->shim->request.makeDir;
|
||||||
auto fullPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->path);
|
auto fullPath = getFullPath(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->path);
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] MakeDir: %s (full path: %s)", layer->getName().c_str(), request->path, fullPath.c_str());
|
DEBUG_FUNCTION_LINE_VERBOSE("[%s] MakeDir: %s (full path: %s)", layer->getName().c_str(), request->path, fullPath.c_str());
|
||||||
layerResult = layer->FSMakeDirWrapper(fullPath.c_str());
|
layerResult = layer->FSMakeDirWrapper(fullPath.c_str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FSA_COMMAND_OPEN_FILE: {
|
case FSA_COMMAND_OPEN_FILE: {
|
||||||
auto *request = ¶m->shim->request.openFile;
|
auto *request = ¶m->shim->request.openFile;
|
||||||
auto fullPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->path);
|
auto fullPath = getFullPath(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->path);
|
||||||
// Hacky solution:
|
// Hacky solution:
|
||||||
auto *hackyBuffer = (uint32_t *) ¶m->shim->response;
|
auto *hackyBuffer = (uint32_t *) ¶m->shim->response;
|
||||||
auto *handlePtr = (FSFileHandle *) hackyBuffer[1];
|
auto *handlePtr = (FSFileHandle *) hackyBuffer[1];
|
||||||
|
@ -185,7 +193,7 @@ FSError doForLayer(FSShimWrapper *param) {
|
||||||
case FSA_COMMAND_GET_INFO_BY_QUERY: {
|
case FSA_COMMAND_GET_INFO_BY_QUERY: {
|
||||||
auto *request = ¶m->shim->request.getInfoByQuery;
|
auto *request = ¶m->shim->request.getInfoByQuery;
|
||||||
if (request->type == FSA_QUERY_INFO_STAT) {
|
if (request->type == FSA_QUERY_INFO_STAT) {
|
||||||
auto fullPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->path);
|
auto fullPath = getFullPath(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->path);
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] GetStat: %s (full path: %s)", layer->getName().c_str(), request->path, fullPath.c_str());
|
DEBUG_FUNCTION_LINE_VERBOSE("[%s] GetStat: %s (full path: %s)", layer->getName().c_str(), request->path, fullPath.c_str());
|
||||||
// Hacky solution:
|
// Hacky solution:
|
||||||
auto *hackyBuffer = (uint32_t *) ¶m->shim->response;
|
auto *hackyBuffer = (uint32_t *) ¶m->shim->response;
|
||||||
|
@ -258,15 +266,15 @@ FSError doForLayer(FSShimWrapper *param) {
|
||||||
}
|
}
|
||||||
case FSA_COMMAND_REMOVE: {
|
case FSA_COMMAND_REMOVE: {
|
||||||
auto *request = ¶m->shim->request.remove;
|
auto *request = ¶m->shim->request.remove;
|
||||||
auto fullPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->path);
|
auto fullPath = getFullPath(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->path);
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Remove: %s (full path: %s)", layer->getName().c_str(), request->path, fullPath.c_str());
|
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Remove: %s (full path: %s)", layer->getName().c_str(), request->path, fullPath.c_str());
|
||||||
layerResult = layer->FSRemoveWrapper(fullPath.c_str());
|
layerResult = layer->FSRemoveWrapper(fullPath.c_str());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FSA_COMMAND_RENAME: {
|
case FSA_COMMAND_RENAME: {
|
||||||
auto *request = ¶m->shim->request.rename;
|
auto *request = ¶m->shim->request.rename;
|
||||||
auto fullOldPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->oldPath);
|
auto fullOldPath = getFullPath(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->oldPath);
|
||||||
auto fullNewPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->newPath);
|
auto fullNewPath = getFullPath(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->newPath);
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Rename: %s -> %s (full path: %s -> %s)", layer->getName().c_str(), request->oldPath, request->newPath, fullOldPath.c_str(), fullNewPath.c_str());
|
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Rename: %s -> %s (full path: %s -> %s)", layer->getName().c_str(), request->oldPath, request->newPath, fullOldPath.c_str(), fullNewPath.c_str());
|
||||||
layerResult = layer->FSRenameWrapper(fullOldPath.c_str(), fullNewPath.c_str());
|
layerResult = layer->FSRenameWrapper(fullOldPath.c_str(), fullNewPath.c_str());
|
||||||
break;
|
break;
|
||||||
|
@ -280,7 +288,7 @@ FSError doForLayer(FSShimWrapper *param) {
|
||||||
case FSA_COMMAND_CHANGE_DIR: {
|
case FSA_COMMAND_CHANGE_DIR: {
|
||||||
auto *request = ¶m->shim->request.changeDir;
|
auto *request = ¶m->shim->request.changeDir;
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] ChangeDir: %s", layer->getName().c_str(), request->path);
|
DEBUG_FUNCTION_LINE_VERBOSE("[%s] ChangeDir: %s", layer->getName().c_str(), request->path);
|
||||||
setWorkingDir((FSAClientHandle) param->shim->clientHandle, request->path);
|
setWorkingDir(layerInfo, (FSAClientHandle) param->shim->clientHandle, request->path);
|
||||||
// We still want to call the original function.
|
// We still want to call the original function.
|
||||||
layerResult = FS_ERROR_FORCE_PARENT_LAYER;
|
layerResult = FS_ERROR_FORCE_PARENT_LAYER;
|
||||||
break;
|
break;
|
||||||
|
@ -458,9 +466,6 @@ int64_t writeFromBuffer(int32_t handle, const void *buffer, size_t size, size_t
|
||||||
return totalSize;
|
return totalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
FSIOThreadData gThreadData[3];
|
|
||||||
bool gThreadsRunning = false;
|
|
||||||
|
|
||||||
static int32_t fsIOthreadCallback([[maybe_unused]] int argc, const char **argv) {
|
static int32_t fsIOthreadCallback([[maybe_unused]] int argc, const char **argv) {
|
||||||
auto *magic = ((FSIOThreadData *) argv);
|
auto *magic = ((FSIOThreadData *) argv);
|
||||||
|
|
||||||
|
@ -512,10 +517,24 @@ static int32_t fsIOthreadCallback([[maybe_unused]] int argc, const char **argv)
|
||||||
void startFSIOThreads() {
|
void startFSIOThreads() {
|
||||||
int32_t threadAttributes[] = {OS_THREAD_ATTRIB_AFFINITY_CPU0, OS_THREAD_ATTRIB_AFFINITY_CPU1, OS_THREAD_ATTRIB_AFFINITY_CPU2};
|
int32_t threadAttributes[] = {OS_THREAD_ATTRIB_AFFINITY_CPU0, OS_THREAD_ATTRIB_AFFINITY_CPU1, OS_THREAD_ATTRIB_AFFINITY_CPU2};
|
||||||
auto stackSize = 16 * 1024;
|
auto stackSize = 16 * 1024;
|
||||||
|
auto upid = OSGetUPID();
|
||||||
|
if (!sLayerInfoForUPID.contains(upid)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Tried to start threads for invalid UPID %d", upid);
|
||||||
|
OSFatal("Tried to start threads for invalid UPID.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &layerInfo = sLayerInfoForUPID[upid];
|
||||||
|
if (layerInfo->threadsRunning) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
int coreId = 0;
|
int coreId = 0;
|
||||||
for (int core : threadAttributes) {
|
for (int core : threadAttributes) {
|
||||||
auto *threadData = &gThreadData[coreId];
|
if (upid != 2 && upid != 15 && core == OS_THREAD_ATTRIB_AFFINITY_CPU2) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Skip core 2 for non-game UPID %d", upid);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto *threadData = &layerInfo->threadData[coreId];
|
||||||
memset(threadData, 0, sizeof(*threadData));
|
memset(threadData, 0, sizeof(*threadData));
|
||||||
threadData->setup = false;
|
threadData->setup = false;
|
||||||
threadData->thread = (OSThread *) memalign(8, sizeof(OSThread));
|
threadData->thread = (OSThread *) memalign(8, sizeof(OSThread));
|
||||||
|
@ -549,16 +568,24 @@ void startFSIOThreads() {
|
||||||
coreId++;
|
coreId++;
|
||||||
}
|
}
|
||||||
|
|
||||||
gThreadsRunning = true;
|
layerInfo->threadsRunning = true;
|
||||||
OSMemoryBarrier();
|
OSMemoryBarrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopFSIOThreads() {
|
void stopFSIOThreads() {
|
||||||
if (!gThreadsRunning) {
|
auto upid = OSGetUPID();
|
||||||
|
if (!sLayerInfoForUPID.contains(upid)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Tried to start threads for invalid UPID %d", upid);
|
||||||
|
OSFatal("Tried to start threads for invalid UPID.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &layerInfo = sLayerInfoForUPID[upid];
|
||||||
|
if (!layerInfo->threadsRunning) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (auto &gThread : gThreadData) {
|
|
||||||
auto *thread = &gThread;
|
for (auto &curThread : layerInfo->threadData) {
|
||||||
|
auto *thread = &curThread;
|
||||||
if (!thread->setup) {
|
if (!thread->setup) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -581,5 +608,5 @@ void stopFSIOThreads() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
gThreadsRunning = false;
|
layerInfo->threadsRunning = false;
|
||||||
}
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
#include <coreinit/filesystem.h>
|
#include <coreinit/filesystem.h>
|
||||||
#include <coreinit/filesystem_fsa.h>
|
#include <coreinit/filesystem_fsa.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <map>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <romfs_dev.h>
|
#include <romfs_dev.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -42,6 +43,7 @@ struct FSShimWrapper {
|
||||||
AsyncParamFS asyncFS;
|
AsyncParamFS asyncFS;
|
||||||
FSShimSyncType sync;
|
FSShimSyncType sync;
|
||||||
FSShimApiType api;
|
FSShimApiType api;
|
||||||
|
uint32_t upid;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FSShimWrapperMessage {
|
struct FSShimWrapperMessage {
|
||||||
|
@ -54,10 +56,16 @@ struct FSShimWrapperMessage {
|
||||||
#define FS_IO_QUEUE_COMMAND_PROCESS_FS_COMMAND 0x42424242
|
#define FS_IO_QUEUE_COMMAND_PROCESS_FS_COMMAND 0x42424242
|
||||||
#define FS_IO_QUEUE_SYNC_RESULT 0x43434343
|
#define FS_IO_QUEUE_SYNC_RESULT 0x43434343
|
||||||
|
|
||||||
extern bool gThreadsRunning;
|
struct LayerInfo {
|
||||||
extern FSIOThreadData gThreadData[3];
|
std::mutex mutex{};
|
||||||
extern std::mutex fsLayerMutex;
|
std::vector<std::unique_ptr<IFSWrapper>> layers{};
|
||||||
extern std::vector<std::unique_ptr<IFSWrapper>> fsLayers;
|
std::mutex workingDirMutex{};
|
||||||
|
std::map<FSAClientHandle, std::string> workingDirs{};
|
||||||
|
FSIOThreadData threadData[3]{};
|
||||||
|
bool threadsRunning{};
|
||||||
|
};
|
||||||
|
|
||||||
|
extern std::map<uint32_t, std::shared_ptr<LayerInfo>> sLayerInfoForUPID;
|
||||||
|
|
||||||
#define fsaShimPrepareRequestReadFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, uint8_t * buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, FSAReadFlag readFlags))(0x101C400 + 0x436cc))
|
#define fsaShimPrepareRequestReadFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, uint8_t * buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, FSAReadFlag readFlags))(0x101C400 + 0x436cc))
|
||||||
#define fsaShimPrepareRequestWriteFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, FSAWriteFlag writeFlags))(0x101C400 + 0x437f4))
|
#define fsaShimPrepareRequestWriteFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, FSAWriteFlag writeFlags))(0x101C400 + 0x437f4))
|
||||||
|
@ -87,9 +95,11 @@ extern std::vector<std::unique_ptr<IFSWrapper>> fsLayers;
|
||||||
|
|
||||||
extern "C" FSError __FSAShimDecodeIosErrorToFsaStatus(IOSHandle handle, IOSError err);
|
extern "C" FSError __FSAShimDecodeIosErrorToFsaStatus(IOSHandle handle, IOSError err);
|
||||||
|
|
||||||
bool sendMessageToThread(FSShimWrapperMessage *param);
|
bool sendMessageToThread(std::shared_ptr<LayerInfo> &layerInfo, FSShimWrapperMessage *param);
|
||||||
|
|
||||||
void clearFSLayer();
|
void clearFSLayer(std::shared_ptr<LayerInfo> &layerInfo);
|
||||||
|
|
||||||
|
void clearFSLayers();
|
||||||
|
|
||||||
FSError doForLayer(FSShimWrapper *param);
|
FSError doForLayer(FSShimWrapper *param);
|
||||||
|
|
||||||
|
|
|
@ -16,12 +16,12 @@ struct AOCTitle {
|
||||||
WUT_CHECK_SIZE(AOCTitle, 0x68);
|
WUT_CHECK_SIZE(AOCTitle, 0x68);
|
||||||
|
|
||||||
bool getAOCPath(std::string &outStr) {
|
bool getAOCPath(std::string &outStr) {
|
||||||
int32_t (*AOC_Initialize)() = nullptr;
|
int32_t (*AOC_Initialize)() = nullptr;
|
||||||
int32_t (*AOC_Finalize)() = nullptr;
|
int32_t (*AOC_Finalize)() = nullptr;
|
||||||
int32_t (*AOC_ListTitle)(uint32_t * titleCountOut, AOCTitle * titleList, uint32_t maxCount, void *workBuffer, uint32_t workBufferSize) = nullptr;
|
int32_t (*AOC_ListTitle)(uint32_t *titleCountOut, AOCTitle *titleList, uint32_t maxCount, void *workBuffer, uint32_t workBufferSize) = nullptr;
|
||||||
int32_t (*AOC_OpenTitle)(char *pathOut, AOCTitle *aocTitleInfo, void *workBuffer, uint32_t workBufferSize) = nullptr;
|
int32_t (*AOC_OpenTitle)(char *pathOut, AOCTitle *aocTitleInfo, void *workBuffer, uint32_t workBufferSize) = nullptr;
|
||||||
int32_t (*AOC_CalculateWorkBufferSize)(uint32_t count) = nullptr;
|
int32_t (*AOC_CalculateWorkBufferSize)(uint32_t count) = nullptr;
|
||||||
int32_t (*AOC_CloseTitle)(AOCTitle * aocTitleInfo) = nullptr;
|
int32_t (*AOC_CloseTitle)(AOCTitle *aocTitleInfo) = nullptr;
|
||||||
|
|
||||||
AOCTitle title{};
|
AOCTitle title{};
|
||||||
char aocPath[256];
|
char aocPath[256];
|
||||||
|
@ -88,7 +88,7 @@ end:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *layerName, const char *replacementDir, FSLayerType layerType) {
|
ContentRedirectionApiErrorType CRAddFSLayerEx(CRLayerHandle *handle, const char *layerName, const char *replacementDir, FSLayerType layerType, uint32_t upid) {
|
||||||
if (!handle || layerName == nullptr || replacementDir == nullptr) {
|
if (!handle || layerName == nullptr || replacementDir == nullptr) {
|
||||||
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_INVALID_ARG");
|
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_INVALID_ARG");
|
||||||
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
|
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
|
||||||
|
@ -121,28 +121,23 @@ ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *l
|
||||||
}
|
}
|
||||||
if (ptr) {
|
if (ptr) {
|
||||||
DEBUG_FUNCTION_LINE_VERBOSE("Added new layer (%s). Replacement dir: %s Type:%d", layerName, replacementDir, layerType);
|
DEBUG_FUNCTION_LINE_VERBOSE("Added new layer (%s). Replacement dir: %s Type:%d", layerName, replacementDir, layerType);
|
||||||
std::lock_guard<std::mutex> lock(fsLayerMutex);
|
auto &layerInfo = sLayerInfoForUPID[upid];
|
||||||
|
std::lock_guard<std::mutex> lock(layerInfo->mutex);
|
||||||
*handle = (CRLayerHandle) ptr->getHandle();
|
*handle = (CRLayerHandle) ptr->getHandle();
|
||||||
fsLayers.push_back(std::move(ptr));
|
layerInfo->layers.push_back(std::move(ptr));
|
||||||
return CONTENT_REDIRECTION_API_ERROR_NONE;
|
return CONTENT_REDIRECTION_API_ERROR_NONE;
|
||||||
}
|
}
|
||||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory");
|
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory");
|
||||||
return CONTENT_REDIRECTION_API_ERROR_NO_MEMORY;
|
return CONTENT_REDIRECTION_API_ERROR_NO_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentRedirectionApiErrorType CRRemoveFSLayer(CRLayerHandle handle) {
|
ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *layerName, const char *replacementDir, FSLayerType layerType) {
|
||||||
if (!remove_locked_first_if(fsLayerMutex, fsLayers, [handle](auto &cur) { return (CRLayerHandle) cur->getHandle() == handle; })) {
|
return CRAddFSLayerEx(handle, layerName, replacementDir, layerType, 2);
|
||||||
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle);
|
|
||||||
return CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND;
|
|
||||||
}
|
|
||||||
return CONTENT_REDIRECTION_API_ERROR_NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentRedirectionApiErrorType CRSetActive(CRLayerHandle handle, bool active) {
|
ContentRedirectionApiErrorType CRRemoveFSLayer(CRLayerHandle handle) {
|
||||||
std::lock_guard<std::mutex> lock(fsLayerMutex);
|
for (auto &[key, layerInfo] : sLayerInfoForUPID) {
|
||||||
for (auto &cur : fsLayers) {
|
if (remove_locked_first_if(layerInfo->mutex, layerInfo->layers, [handle](auto &cur) { return (CRLayerHandle) cur->getHandle() == handle; })) {
|
||||||
if ((CRLayerHandle) cur->getHandle() == handle) {
|
|
||||||
cur->setActive(active);
|
|
||||||
return CONTENT_REDIRECTION_API_ERROR_NONE;
|
return CONTENT_REDIRECTION_API_ERROR_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,11 +146,27 @@ ContentRedirectionApiErrorType CRSetActive(CRLayerHandle handle, bool active) {
|
||||||
return CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND;
|
return CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ContentRedirectionApiErrorType CRSetActive(CRLayerHandle handle, bool active) {
|
||||||
|
for (auto &[key, layerInfo] : sLayerInfoForUPID) {
|
||||||
|
std::lock_guard<std::mutex> lock(layerInfo->mutex);
|
||||||
|
for (auto &cur : layerInfo->layers) {
|
||||||
|
if ((CRLayerHandle) cur->getHandle() == handle) {
|
||||||
|
cur->setActive(active);
|
||||||
|
return CONTENT_REDIRECTION_API_ERROR_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle);
|
||||||
|
return CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
ContentRedirectionApiErrorType CRGetVersion(ContentRedirectionVersion *outVersion) {
|
ContentRedirectionApiErrorType CRGetVersion(ContentRedirectionVersion *outVersion) {
|
||||||
if (outVersion == nullptr) {
|
if (outVersion == nullptr) {
|
||||||
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
|
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
|
||||||
}
|
}
|
||||||
*outVersion = 1;
|
*outVersion = 2;
|
||||||
return CONTENT_REDIRECTION_API_ERROR_NONE;
|
return CONTENT_REDIRECTION_API_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,6 +180,7 @@ int CRRemoveDevice(const char *name) {
|
||||||
|
|
||||||
WUMS_EXPORT_FUNCTION(CRGetVersion);
|
WUMS_EXPORT_FUNCTION(CRGetVersion);
|
||||||
WUMS_EXPORT_FUNCTION(CRAddFSLayer);
|
WUMS_EXPORT_FUNCTION(CRAddFSLayer);
|
||||||
|
WUMS_EXPORT_FUNCTION(CRAddFSLayerEx);
|
||||||
WUMS_EXPORT_FUNCTION(CRRemoveFSLayer);
|
WUMS_EXPORT_FUNCTION(CRRemoveFSLayer);
|
||||||
WUMS_EXPORT_FUNCTION(CRSetActive);
|
WUMS_EXPORT_FUNCTION(CRSetActive);
|
||||||
WUMS_EXPORT_FUNCTION(CRAddDevice);
|
WUMS_EXPORT_FUNCTION(CRAddDevice);
|
||||||
|
|
34
src/main.cpp
34
src/main.cpp
|
@ -3,7 +3,9 @@
|
||||||
#include "FileUtils.h"
|
#include "FileUtils.h"
|
||||||
#include "utils/StringTools.h"
|
#include "utils/StringTools.h"
|
||||||
#include "utils/logger.h"
|
#include "utils/logger.h"
|
||||||
|
#include "utils/utils.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
#include <mocha/mocha.h>
|
||||||
#include <wums.h>
|
#include <wums.h>
|
||||||
|
|
||||||
WUMS_MODULE_EXPORT_NAME("homebrew_content_redirection");
|
WUMS_MODULE_EXPORT_NAME("homebrew_content_redirection");
|
||||||
|
@ -13,7 +15,14 @@ WUMS_DEPENDS_ON(homebrew_functionpatcher);
|
||||||
#define VERSION "v0.2.5"
|
#define VERSION "v0.2.5"
|
||||||
|
|
||||||
DECL_FUNCTION(void, OSCancelThread, OSThread *thread) {
|
DECL_FUNCTION(void, OSCancelThread, OSThread *thread) {
|
||||||
if (thread == gThreadData[0].thread || thread == gThreadData[1].thread || thread == gThreadData[2].thread) {
|
auto upid = OSGetUPID();
|
||||||
|
if (!sLayerInfoForUPID.contains(upid)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("invalid UPID %d", upid);
|
||||||
|
OSFatal("Invalid UPID.");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &layerInfo = sLayerInfoForUPID[upid];
|
||||||
|
if (thread == layerInfo->threadData[0].thread || thread == layerInfo->threadData[1].thread || thread == layerInfo->threadData[2].thread) {
|
||||||
DEBUG_FUNCTION_LINE_INFO("Prevent calling OSCancelThread for ContentRedirection IO Threads");
|
DEBUG_FUNCTION_LINE_INFO("Prevent calling OSCancelThread for ContentRedirection IO Threads");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -29,6 +38,11 @@ WUMS_INITIALIZE() {
|
||||||
OSFatal("homebrew_content_redirection: FunctionPatcher_InitLibrary failed");
|
OSFatal("homebrew_content_redirection: FunctionPatcher_InitLibrary failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int mochaInitResult;
|
||||||
|
if ((mochaInitResult = Mocha_InitLibrary()) != MOCHA_RESULT_SUCCESS) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Mocha_InitLibrary() failed %d", mochaInitResult);
|
||||||
|
}
|
||||||
|
|
||||||
bool wasPatched;
|
bool wasPatched;
|
||||||
for (uint32_t i = 0; i < fs_file_function_replacements_size; i++) {
|
for (uint32_t i = 0; i < fs_file_function_replacements_size; i++) {
|
||||||
wasPatched = false;
|
wasPatched = false;
|
||||||
|
@ -46,6 +60,19 @@ WUMS_INITIALIZE() {
|
||||||
if (FunctionPatcher_AddFunctionPatch(&OSCancelThreadReplacement, nullptr, &wasPatched) != FUNCTION_PATCHER_RESULT_SUCCESS || !wasPatched) {
|
if (FunctionPatcher_AddFunctionPatch(&OSCancelThreadReplacement, nullptr, &wasPatched) != FUNCTION_PATCHER_RESULT_SUCCESS || !wasPatched) {
|
||||||
OSFatal("homebrew_content_redirection: Failed to patch OSCancelThreadReplacement");
|
OSFatal("homebrew_content_redirection: Failed to patch OSCancelThreadReplacement");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Give UPID 2 (Wii U Menu) and UPID 15 the same layer
|
||||||
|
auto layerInfoGameMenu = make_shared_nothrow<LayerInfo>();
|
||||||
|
sLayerInfoForUPID[2] = layerInfoGameMenu;
|
||||||
|
sLayerInfoForUPID[15] = layerInfoGameMenu;
|
||||||
|
|
||||||
|
// Fill in for all other UPIDs
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
if (i == 2 || i == 15) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sLayerInfoForUPID[i] = make_shared_nothrow<LayerInfo>();
|
||||||
|
}
|
||||||
DEBUG_FUNCTION_LINE("Patch functions finished");
|
DEBUG_FUNCTION_LINE("Patch functions finished");
|
||||||
deinitLogging();
|
deinitLogging();
|
||||||
}
|
}
|
||||||
|
@ -57,7 +84,10 @@ WUMS_APPLICATION_STARTS() {
|
||||||
}
|
}
|
||||||
|
|
||||||
WUMS_APPLICATION_ENDS() {
|
WUMS_APPLICATION_ENDS() {
|
||||||
clearFSLayer();
|
if (sLayerInfoForUPID.contains(2)) {
|
||||||
|
DEBUG_FUNCTION_LINE_ERR("Clear layer for UPID %d", 2);
|
||||||
|
clearFSLayer(sLayerInfoForUPID[2]);
|
||||||
|
}
|
||||||
|
|
||||||
stopFSIOThreads();
|
stopFSIOThreads();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue