Rewrite of almost everything to fix crashes and lags

This commit is contained in:
Maschell 2022-09-10 21:24:58 +02:00
parent 3be38d6ea9
commit 857461b735
22 changed files with 2141 additions and 1487 deletions

View File

@ -1,8 +1,8 @@
FROM wiiuenv/devkitppc:20220806
FROM wiiuenv/devkitppc:20220917
COPY --from=wiiuenv/libfunctionpatcher:20220904 /artifacts $DEVKITPRO
COPY --from=wiiuenv/wiiumodulesystem:20220904 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libromfs_wiiu:20220904 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libcontentredirection:20220903 /artifacts $DEVKITPRO
COPY --from=wiiuenv/libcontentredirection:20220916 /artifacts $DEVKITPRO
WORKDIR project

View File

@ -108,7 +108,7 @@ export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD))
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#-------------------------------------------------------------------------------

View File

@ -1,9 +1,9 @@
#pragma once
#include "DirInfo.h"
#include <coreinit/filesystem.h>
#include <coreinit/filesystem_fsa.h>
typedef struct FSDirectoryEntryEx {
FSDirectoryEntry realEntry{};
FSADirectoryEntry realEntry{};
bool isMarkedAsDeleted = false;
} FSDirectoryEntryEx;

View File

@ -1,82 +0,0 @@
#include "FSDirReplacements.h"
#include "FileUtils.h"
#include "IFSWrapper.h"
#include "utils/logger.h"
#include <coreinit/cache.h>
#include <coreinit/filesystem.h>
DECL_FUNCTION(FSError, FSAOpenDir, FSAClientHandle client, const char *path, FSADirectoryHandle *dirHandle) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
return doForLayerFSA(
[c = client, p = path, h = dirHandle]() -> FSError {
return real_FSAOpenDir(c, p, h);
},
[p = path, h = dirHandle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSOpenDirWrapper(p, h);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSAReadDir, FSAClientHandle client, FSADirectoryHandle dirHandle, FSADirectoryEntry *directoryEntry) {
DEBUG_FUNCTION_LINE_VERBOSE("%08X", dirHandle);
return doForLayerFSA(
[c = client, h = dirHandle, de = directoryEntry]() -> FSError {
return real_FSAReadDir(c, h, de);
},
[h = dirHandle, de = directoryEntry](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSReadDirWrapper(h, de);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSARewindDir, FSAClientHandle client, FSADirectoryHandle dirHandle) {
DEBUG_FUNCTION_LINE_VERBOSE("%08X", dirHandle);
return doForLayerFSA(
[c = client, h = dirHandle]() -> FSError {
return real_FSARewindDir(c, h);
},
[h = dirHandle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSRewindDirWrapper(h);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSACloseDir, FSAClientHandle client, FSADirectoryHandle dirHandle) {
DEBUG_FUNCTION_LINE_VERBOSE("%08X", dirHandle);
return doForLayerFSA(
[c = client, h = dirHandle]() -> FSError {
return real_FSACloseDir(c, h);
},
[h = dirHandle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSCloseDirWrapper(h);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSAMakeDir, FSAClientHandle client, const char *path, FSMode mode) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
return doForLayerFSA(
[c = client, p = path, m = mode]() -> FSError {
return real_FSAMakeDir(c, p, m);
},
[p = path, m = mode](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSMakeDirWrapper(p);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSAChangeDir, FSAClientHandle client, const char *path) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
setWorkingDirForFSAClient(client, path);
return real_FSAChangeDir(client, path);
}
function_replacement_data_t fsa_dir_function_replacements[] = {
REPLACE_FUNCTION(FSAOpenDir, LIBRARY_COREINIT, FSAOpenDir),
REPLACE_FUNCTION(FSAReadDir, LIBRARY_COREINIT, FSAReadDir),
REPLACE_FUNCTION(FSARewindDir, LIBRARY_COREINIT, FSARewindDir),
REPLACE_FUNCTION(FSACloseDir, LIBRARY_COREINIT, FSACloseDir),
REPLACE_FUNCTION(FSAMakeDir, LIBRARY_COREINIT, FSAMakeDir),
REPLACE_FUNCTION(FSAChangeDir, LIBRARY_COREINIT, FSAChangeDir),
};
uint32_t fsa_dir_function_replacements_size = sizeof(fsa_dir_function_replacements) / sizeof(function_replacement_data_t);

View File

@ -1,10 +0,0 @@
#pragma once
#include "IFSWrapper.h"
#include <coreinit/filesystem.h>
#include <function_patcher/function_patching.h>
#include <functional>
#include <string>
extern function_replacement_data_t fsa_dir_function_replacements[];
extern uint32_t fsa_dir_function_replacements_size;

View File

@ -1,238 +0,0 @@
#include "FSFileReplacements.h"
#include "FileUtils.h"
#include "utils/logger.h"
#include <coreinit/filesystem_fsa.h>
DECL_FUNCTION(FSError, FSAOpenFileEx, FSAClientHandle client, const char *path, const char *mode, FSMode createMode, FSOpenFileFlags openFlag, uint32_t preallocSize, FSAFileHandle *handle) {
DEBUG_FUNCTION_LINE_VERBOSE("path: %s mode: %d", path, mode);
return doForLayerFSA(
[c = client, p = path, m = mode, cm = createMode, of = openFlag, pa = preallocSize, h = handle]() -> FSError {
return real_FSAOpenFileEx(c, p, m, cm, of, pa, h);
},
[f = getFullPathForFSAClient(client, path), m = mode, h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
// FSAFileHandle is just an alias for FSFileHandle
return layer->FSOpenFileWrapper(f.c_str(), m, h);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSACloseFile, FSAClientHandle client, FSAFileHandle fileHandle) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", fileHandle);
return doForLayerFSA(
[c = client, h = fileHandle]() -> FSError {
return real_FSACloseFile(c, h);
},
[h = fileHandle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
// FSAFileHandle is just an alias for FSFileHandle
return layer->FSCloseFileWrapper(h);
},
[h = fileHandle, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr<IFSWrapper> &layer, FSError res) -> FSError {
if (layer->isValidFileHandle(h)) {
layer->deleteFileHandle(h);
} else {
DEBUG_FUNCTION_LINE_ERR_LAMBDA(filename, func, line, "Expected to delete fileHandle by handle %08X but it was not found", h);
}
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Sync result %d", res);
return res;
});
}
DECL_FUNCTION(FSError, FSAFlushFile, FSAClientHandle client, FSAFileHandle fileHandle) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", fileHandle);
return doForLayerFSA(
[c = client, h = fileHandle]() -> FSError {
return real_FSAFlushFile(c, h);
},
[h = fileHandle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
// FSAFileHandle is just an alias for FSFileHandle
return layer->FSFlushFileWrapper(h);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSAGetStat, FSAClientHandle client, const char *path, FSAStat *stat) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
return doForLayerFSA(
[c = client, p = path, s = stat]() -> FSError {
return real_FSAGetStat(c, p, s);
},
[f = getFullPathForFSAClient(client, path), s = stat](std::unique_ptr<IFSWrapper> &layer) -> FSError {
// FSAStat is just an alias for FSStat
return layer->FSGetStatWrapper(f.c_str(), s);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSAGetStatFile, FSAClientHandle client, FSAFileHandle fileHandle, FSAStat *stat) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", fileHandle);
return doForLayerFSA(
[c = client, h = fileHandle, s = stat]() -> FSError {
return real_FSAGetStatFile(c, h, s);
},
[h = fileHandle, s = stat](std::unique_ptr<IFSWrapper> &layer) -> FSError {
// FSAFileHandle is just an alias for FSFileHandle
// FSAStat is just an alias for FSStat
return layer->FSGetStatFileWrapper(h, s);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSARemove, FSAClientHandle client, const char *path) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
return doForLayerFSA(
[c = client, p = path]() -> FSError {
return real_FSARemove(c, p);
},
[f = getFullPathForFSAClient(client, path)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSRemoveWrapper(f.c_str());
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSARename, FSAClientHandle client, const char *oldPath, const char *newPath) {
DEBUG_FUNCTION_LINE_VERBOSE("%s %s", oldPath, newPath);
return doForLayerFSA(
[c = client, op = oldPath, np = newPath]() -> FSError {
return real_FSARename(c, op, np);
},
[op = getFullPathForFSAClient(client, oldPath), np = getFullPathForFSAClient(client, newPath)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSRenameWrapper(op.c_str(), np.c_str());
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSASetPosFile, FSAClientHandle client, FSAFileHandle fileHandle, uint32_t pos) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X pos: %08X", fileHandle, pos);
return doForLayerFSA(
[c = client, h = fileHandle, p = pos]() -> FSError {
return real_FSASetPosFile(c, h, p);
},
[h = fileHandle, p = pos](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSSetPosFileWrapper(h, p);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSATruncateFile, FSAClientHandle client, FSAFileHandle fileHandle) {
DEBUG_FUNCTION_LINE_VERBOSE("%08X", fileHandle);
return doForLayerFSA(
[c = client, h = fileHandle]() -> FSError {
return real_FSATruncateFile(c, h);
},
[h = fileHandle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSTruncateFileWrapper(h);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSAReadFile, FSAClientHandle client, void *buffer, uint32_t size, uint32_t count, FSAFileHandle handle, uint32_t flags) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X", handle, buffer, size * count);
return doForLayerFSA(
[c = client, b = buffer, s = size, co = count, h = handle, f = flags]() -> FSError {
return real_FSAReadFile(c, b, s, co, h, f);
},
[b = buffer, s = size, co = count, h = handle, f = flags](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSReadFileWrapper(b, s, co, h, f);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSAWriteFile, FSAClientHandle client, void *buffer, uint32_t size, uint32_t count, FSAFileHandle handle, uint32_t flags) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X", handle, buffer, size * count);
return doForLayerFSA(
[c = client, b = buffer, s = size, co = count, h = handle, f = flags]() -> FSError {
return real_FSAWriteFile(c, b, s, co, h, f);
},
[b = buffer, s = size, co = count, h = handle, f = flags](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSWriteFileWrapper((uint8_t *) b, s, co, h, f);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSAGetPosFile, FSAClientHandle client, FSAFileHandle handle, uint32_t *outPos) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", handle);
return doForLayerFSA(
[c = client, h = handle, o = outPos]() -> FSError {
return real_FSAGetPosFile(c, h, o);
},
[h = handle, o = outPos](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSGetPosFileWrapper(h, o);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSAIsEof, FSAClientHandle client, FSAFileHandle handle) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", handle);
return doForLayerFSA(
[c = client, h = handle]() -> FSError {
return real_FSAIsEof(c, h);
},
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSIsEofWrapper(h);
},
SYNC_RESULT_HANDLER_FSA);
}
DECL_FUNCTION(FSError, FSAFlushMultiQuota, FSAClientHandle client, const char *path) {
DEBUG_FUNCTION_LINE("NOT IMPLEMENTED. path %s", path);
return real_FSAFlushMultiQuota(client, path);
}
DECL_FUNCTION(FSError, FSAFlushQuota, FSAClientHandle client, const char *path) {
DEBUG_FUNCTION_LINE("NOT IMPLEMENTED. path %s", path);
return real_FSAFlushQuota(client, path);
}
DECL_FUNCTION(FSError, FSAChangeMode, FSAClientHandle client, const char *path, FSMode permission) {
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED path %s permission: %08X", path, permission);
return real_FSAChangeMode(client, path, permission);
}
DECL_FUNCTION(FSError, FSAOpenFileByStat, FSAClientHandle client, FSAStat *stat, const char *mode, const char *path, FSAFileHandle *outFileHandle) {
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
return real_FSAOpenFileByStat(client, stat, mode, path, outFileHandle);
}
DECL_FUNCTION(FSError, FSAAppendFile, FSAClientHandle client, FSAFileHandle fileHandle, uint32_t size, uint32_t count) {
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
return real_FSAAppendFile(client, fileHandle, size, count);
}
DECL_FUNCTION(FSError, FSAAppendFileEx, FSAClientHandle client, FSAFileHandle fileHandle, uint32_t size, uint32_t count, uint32_t flags) {
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
return real_FSAAppendFileEx(client, fileHandle, size, count, flags);
}
DECL_FUNCTION(FSStatus, FSAWriteFileWithPos, FSAClientHandle client, uint8_t *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, uint32_t flags) {
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED. handle %08X size %08X", handle, size * count);
return real_FSAWriteFileWithPos(client, buffer, size, count, pos, handle, flags);
}
function_replacement_data_t fsa_file_function_replacements[] = {
REPLACE_FUNCTION(FSAOpenFileEx, LIBRARY_COREINIT, FSAOpenFileEx),
REPLACE_FUNCTION(FSACloseFile, LIBRARY_COREINIT, FSACloseFile),
REPLACE_FUNCTION(FSAFlushFile, LIBRARY_COREINIT, FSAFlushFile),
REPLACE_FUNCTION(FSAGetStat, LIBRARY_COREINIT, FSAGetStat),
REPLACE_FUNCTION(FSAGetStatFile, LIBRARY_COREINIT, FSAGetStatFile),
REPLACE_FUNCTION(FSARemove, LIBRARY_COREINIT, FSARemove),
REPLACE_FUNCTION(FSARename, LIBRARY_COREINIT, FSARename),
REPLACE_FUNCTION(FSASetPosFile, LIBRARY_COREINIT, FSASetPosFile),
REPLACE_FUNCTION(FSATruncateFile, LIBRARY_COREINIT, FSATruncateFile),
REPLACE_FUNCTION(FSAReadFile, LIBRARY_COREINIT, FSAReadFile),
REPLACE_FUNCTION(FSAWriteFile, LIBRARY_COREINIT, FSAWriteFile),
REPLACE_FUNCTION(FSAGetPosFile, LIBRARY_COREINIT, FSAGetPosFile),
REPLACE_FUNCTION(FSAIsEof, LIBRARY_COREINIT, FSAIsEof),
REPLACE_FUNCTION(FSAFlushMultiQuota, LIBRARY_COREINIT, FSAFlushMultiQuota),
REPLACE_FUNCTION(FSAFlushQuota, LIBRARY_COREINIT, FSAFlushQuota),
REPLACE_FUNCTION(FSAChangeMode, LIBRARY_COREINIT, FSAChangeMode),
REPLACE_FUNCTION(FSAOpenFileByStat, LIBRARY_COREINIT, FSAOpenFileByStat),
REPLACE_FUNCTION(FSAAppendFile, LIBRARY_COREINIT, FSAAppendFile),
REPLACE_FUNCTION(FSAAppendFileEx, LIBRARY_COREINIT, FSAAppendFileEx),
REPLACE_FUNCTION(FSAWriteFileWithPos, LIBRARY_COREINIT, FSAWriteFileWithPos),
};
uint32_t fsa_file_function_replacements_size = sizeof(fsa_file_function_replacements) / sizeof(function_replacement_data_t);

731
src/FSAReplacements.cpp Normal file
View File

@ -0,0 +1,731 @@
#include "FSAReplacements.h"
#include "FileUtils.h"
#include "utils/logger.h"
#include <coreinit/core.h>
#include <malloc.h>
static FSError processFSAShimInThread(FSAShimBuffer *shimBuffer) {
FSError res;
if (gThreadsRunning) {
auto param = (FSShimWrapper *) malloc(sizeof(FSShimWrapper));
if (param == nullptr) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for FSShimWrapper");
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapper");
}
param->api = FS_SHIM_API_FSA;
param->sync = FS_SHIM_TYPE_SYNC;
param->shim = shimBuffer;
if (OSGetCurrentThread() == gThreadData[OSGetCoreId()].thread) {
res = processShimBufferForFSA(param);
//No need to clean "param", it has been already free'd in processFSAShimBuffer.
} else {
auto message = (FSShimWrapperMessage *) malloc(sizeof(FSShimWrapperMessage));
if (message == nullptr) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for FSShimWrapperMessage");
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapperMessage");
}
message->param = param;
constexpr int32_t messageSize = sizeof(message->messages) / sizeof(message->messages[0]);
OSInitMessageQueue(&message->messageQueue, message->messages, messageSize);
if (!sendMessageToThread(message)) {
DEBUG_FUNCTION_LINE_ERR("Failed to send message to thread");
OSFatal("ContentRedirectionModule: Failed send message to thread");
}
OSMessage recv;
if (!OSReceiveMessage(&message->messageQueue, &recv, OS_MESSAGE_FLAGS_BLOCKING)) {
DEBUG_FUNCTION_LINE_ERR("Failed to receive message");
OSFatal("ContentRedirectionModule: Failed to receive message");
}
if (recv.args[0] != FS_IO_QUEUE_SYNC_RESULT) {
DEBUG_FUNCTION_LINE_ERR("ContentRedirection: Unexpected message in message queue.");
OSFatal("ContentRedirection: Unexpected message in message queue.");
}
res = (FSError) recv.args[1];
// We only need to clean up "message". "param" has already been free'd by the other thread.
free(message);
}
} else {
res = FS_ERROR_FORCE_REAL_FUNCTION;
DEBUG_FUNCTION_LINE_WARN("Threads are not running yet, skip replacement");
}
return res;
}
DECL_FUNCTION(FSError, FSAOpenFileEx, FSAClientHandle client, const char *path, const char *mode, FSMode createMode, FSOpenFileFlags openFlag, uint32_t preallocSize, FSAFileHandle *handle) {
if (handle == nullptr) {
DEBUG_FUNCTION_LINE_WARN("handle is null.");
return FS_ERROR_INVALID_BUFFER;
}
*handle = -1;
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestOpenFile(shimBuffer, client, path, mode, createMode, openFlag, preallocSize);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestOpenFile failed");
return res;
}
// Hacky solution to pass the pointer into the other thread.
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
hackyBuffer[1] = (uint32_t) handle;
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAOpenFileEx" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAOpenFileEx(client, path, mode, createMode, openFlag, preallocSize, handle);
}
DECL_FUNCTION(FSError, FSAOpenFile, FSAClientHandle client, const char *path, const char *mode, FSAFileHandle *handle) {
if (handle == nullptr) {
DEBUG_FUNCTION_LINE_WARN("handle is null.");
return FS_ERROR_INVALID_BUFFER;
}
*handle = -1;
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestOpenFile(shimBuffer, client, path, mode, static_cast<FSMode>(0x660), static_cast<FSOpenFileFlags>(0), 0);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestOpenFile failed");
return res;
}
// Hacky solution to pass the pointer into the other thread.
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
hackyBuffer[1] = (uint32_t) handle;
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAOpenFile" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAOpenFile(client, path, mode, handle);
}
DECL_FUNCTION(FSError, FSACloseFile, FSAClientHandle client, FSAFileHandle handle) {
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestCloseFile(shimBuffer, client, handle);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestCloseFile failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSACloseFile" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSACloseFile(client, handle);
}
DECL_FUNCTION(FSError, FSAFlushFile, FSAClientHandle client, FSAFileHandle handle) {
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestFlushFile(shimBuffer, client, handle);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestFlushFile failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAFlushFile" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAFlushFile(client, handle);
}
DECL_FUNCTION(FSError, FSAGetStat, FSAClientHandle client, const char *path, FSAStat *stat) {
if (stat == nullptr) {
DEBUG_FUNCTION_LINE_WARN("stat is null.");
return FS_ERROR_INVALID_BUFFER;
}
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestQueryInfo(shimBuffer, client, path, FSA_QUERY_INFO_STAT);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
// Hacky solution to pass the pointer into the other thread.
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
hackyBuffer[1] = (uint32_t) stat;
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAGetStat" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAGetStat(client, path, stat);
}
DECL_FUNCTION(FSError, FSAGetStatFile, FSAClientHandle client, FSAFileHandle handle, FSAStat *stat) {
if (stat == nullptr) {
DEBUG_FUNCTION_LINE_WARN("stat is null.");
return FS_ERROR_INVALID_BUFFER;
}
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestStatFile(shimBuffer, client, handle);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
// Hacky solution to pass the pointer into the other thread.
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
hackyBuffer[1] = (uint32_t) stat;
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAGetStatFile" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAGetStatFile(client, handle, stat);
}
DECL_FUNCTION(FSError, FSARemove, FSAClientHandle client, const char *path) {
if (path == nullptr) {
DEBUG_FUNCTION_LINE_WARN("path is null.");
return FS_ERROR_INVALID_PARAM;
}
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestRemove(shimBuffer, client, path);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSARemove" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSARemove(client, path);
}
DECL_FUNCTION(FSError, FSARename, FSAClientHandle client, const char *oldPath, const char *newPath) {
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestRename(shimBuffer, client, oldPath, newPath);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSARename" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSARename(client, oldPath, newPath);
}
DECL_FUNCTION(FSError, FSASetPosFile, FSAClientHandle client, FSAFileHandle handle, FSAFilePosition pos) {
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestSetPos(shimBuffer, client, handle, pos);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSASetPosFile" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSASetPosFile(client, handle, pos);
}
DECL_FUNCTION(FSError, FSATruncateFile, FSAClientHandle client, FSAFileHandle handle) {
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestTruncate(shimBuffer, client, handle);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSATruncateFile" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSATruncateFile(client, handle);
}
DECL_FUNCTION(FSError, FSAReadFile, FSAClientHandle client, uint8_t *buffer, uint32_t size, uint32_t count, FSAFileHandle handle, uint32_t flags) {
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestReadFile(shimBuffer, client, buffer, size, count, 0, handle, static_cast<FSAReadFlag>(flags & 0xfffffffe));
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAReadFile" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAReadFile(client, buffer, size, count, handle, flags);
}
DECL_FUNCTION(FSError, FSAReadFileWithPos, FSAClientHandle client, uint8_t *buffer, uint32_t size, uint32_t count, FSAFilePosition pos, FSAFileHandle handle, uint32_t flags) {
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestReadFile(shimBuffer, client, buffer, size, count, pos, handle, static_cast<FSAReadFlag>(flags | FSA_READ_FLAG_READ_WITH_POS));
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAReadFileWithPos" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAReadFileWithPos(client, buffer, size, count, pos, handle, flags);
}
DECL_FUNCTION(FSError, FSAWriteFile, FSAClientHandle client, const uint8_t *buffer, uint32_t size, uint32_t count, FSAFileHandle handle, uint32_t flags) {
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestWriteFile(shimBuffer, client, buffer, size, count, 0, handle, static_cast<FSAWriteFlag>(flags & 0xfffffffe));
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAWriteFile" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAWriteFile(client, buffer, size, count, handle, flags);
}
DECL_FUNCTION(FSError, FSAWriteFileWithPos, FSAClientHandle client, uint8_t *buffer, uint32_t size, uint32_t count, FSAFilePosition pos, FSAFileHandle handle, uint32_t flags) {
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestWriteFile(shimBuffer, client, buffer, size, count, pos, handle, static_cast<FSAWriteFlag>(flags | FSA_WRITE_FLAG_READ_WITH_POS));
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAWriteFileWithPos" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAWriteFileWithPos(client, buffer, size, count, pos, handle, flags);
}
DECL_FUNCTION(FSError, FSAGetPosFile, FSAClientHandle client, FSAFileHandle handle, FSAFilePosition *outPos) {
if (outPos == nullptr) {
DEBUG_FUNCTION_LINE_WARN("outPos is null.");
return FS_ERROR_INVALID_BUFFER;
}
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestGetPos(shimBuffer, client, handle);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
// Hacky solution to pass the pointer into the other thread.
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
hackyBuffer[1] = (uint32_t) outPos;
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAGetPosFile" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAGetPosFile(client, handle, outPos);
}
DECL_FUNCTION(FSError, FSAIsEof, FSAClientHandle client, FSAFileHandle handle) {
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestIsEof(shimBuffer, client, handle);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAIsEof" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAIsEof(client, handle);
}
DECL_FUNCTION(FSError, FSAFlushMultiQuota, FSAClientHandle client, const char *path) {
DEBUG_FUNCTION_LINE("NOT IMPLEMENTED. path %s", path);
return real_FSAFlushMultiQuota(client, path);
}
DECL_FUNCTION(FSError, FSAFlushQuota, FSAClientHandle client, const char *path) {
DEBUG_FUNCTION_LINE("NOT IMPLEMENTED. path %s", path);
return real_FSAFlushQuota(client, path);
}
DECL_FUNCTION(FSError, FSAChangeMode, FSAClientHandle client, const char *path, FSMode permission) {
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED path %s permission: %08X", path, permission);
return real_FSAChangeMode(client, path, permission);
}
DECL_FUNCTION(FSError, FSAOpenFileByStat, FSAClientHandle client, FSAStat *stat, const char *mode, const char *path, FSAFileHandle *outFileHandle) {
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
return real_FSAOpenFileByStat(client, stat, mode, path, outFileHandle);
}
DECL_FUNCTION(FSError, FSAAppendFile, FSAClientHandle client, FSAFileHandle fileHandle, uint32_t size, uint32_t count) {
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
return real_FSAAppendFile(client, fileHandle, size, count);
}
DECL_FUNCTION(FSError, FSAAppendFileEx, FSAClientHandle client, FSAFileHandle fileHandle, uint32_t size, uint32_t count, uint32_t flags) {
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
return real_FSAAppendFileEx(client, fileHandle, size, count, flags);
}
DECL_FUNCTION(FSError, FSAOpenDir, FSAClientHandle client, const char *path, FSADirectoryHandle *dirHandle) {
if (dirHandle == nullptr) {
DEBUG_FUNCTION_LINE_WARN("handle is null.");
return FS_ERROR_INVALID_BUFFER;
}
*dirHandle = -1;
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestOpenDir(shimBuffer, client, path);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
// Hacky solution to pass the pointer into the other thread.
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
hackyBuffer[1] = (uint32_t) dirHandle;
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAOpenDir" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAOpenDir(client, path, dirHandle);
}
DECL_FUNCTION(FSError, FSAReadDir, FSAClientHandle client, FSADirectoryHandle dirHandle, FSADirectoryEntry *directoryEntry) {
if (directoryEntry == nullptr) {
DEBUG_FUNCTION_LINE_WARN("handle is null.");
return FS_ERROR_INVALID_BUFFER;
}
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestReadDir(shimBuffer, client, dirHandle);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
// Hacky solution to pass the pointer into the other thread.
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
hackyBuffer[1] = (uint32_t) directoryEntry;
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAOpenDir" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAReadDir(client, dirHandle, directoryEntry);
}
DECL_FUNCTION(FSError, FSARewindDir, FSAClientHandle client, FSADirectoryHandle dirHandle) {
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestRewindDir(shimBuffer, client, dirHandle);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAOpenDir" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSARewindDir(client, dirHandle);
}
DECL_FUNCTION(FSError, FSACloseDir, FSAClientHandle client, FSADirectoryHandle dirHandle) {
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestCloseDir(shimBuffer, client, dirHandle);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSACloseDir" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSACloseDir(client, dirHandle);
}
DECL_FUNCTION(FSError, FSAMakeDir, FSAClientHandle client, const char *path, FSMode mode) {
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestMakeDir(shimBuffer, client, path, mode);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAMakeDir" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAMakeDir(client, path, mode);
}
DECL_FUNCTION(FSError, FSAChangeDir, FSAClientHandle client, const char *path) {
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
if (!shimBuffer) {
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
return FS_ERROR_OUT_OF_RESOURCES;
}
auto res = fsaShimPrepareRequestChangeDir(shimBuffer, client, path);
if (res != FS_ERROR_OK) {
free(shimBuffer);
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
return res;
}
res = processFSAShimInThread(shimBuffer);
free(shimBuffer);
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
return res;
}
// Other plugins/modules may override this function as well, so we need to call "real_FSAChangeDir" instead of using
// the existing shimBuffer (which would be more efficient).
return real_FSAChangeDir(client, path);
}
function_replacement_data_t fsa_file_function_replacements[] = {
REPLACE_FUNCTION(FSAOpenFile, LIBRARY_COREINIT, FSAOpenFile),
REPLACE_FUNCTION(FSAOpenFileEx, LIBRARY_COREINIT, FSAOpenFileEx),
REPLACE_FUNCTION(FSACloseFile, LIBRARY_COREINIT, FSACloseFile),
REPLACE_FUNCTION(FSAFlushFile, LIBRARY_COREINIT, FSAFlushFile),
REPLACE_FUNCTION(FSAGetStat, LIBRARY_COREINIT, FSAGetStat),
REPLACE_FUNCTION(FSAGetStatFile, LIBRARY_COREINIT, FSAGetStatFile),
REPLACE_FUNCTION(FSARemove, LIBRARY_COREINIT, FSARemove),
REPLACE_FUNCTION(FSARename, LIBRARY_COREINIT, FSARename),
REPLACE_FUNCTION(FSASetPosFile, LIBRARY_COREINIT, FSASetPosFile),
REPLACE_FUNCTION(FSATruncateFile, LIBRARY_COREINIT, FSATruncateFile),
REPLACE_FUNCTION(FSAReadFile, LIBRARY_COREINIT, FSAReadFile),
REPLACE_FUNCTION(FSAReadFileWithPos, LIBRARY_COREINIT, FSAReadFileWithPos),
REPLACE_FUNCTION(FSAWriteFile, LIBRARY_COREINIT, FSAWriteFile),
REPLACE_FUNCTION(FSAWriteFileWithPos, LIBRARY_COREINIT, FSAWriteFileWithPos),
REPLACE_FUNCTION(FSAGetPosFile, LIBRARY_COREINIT, FSAGetPosFile),
REPLACE_FUNCTION(FSAIsEof, LIBRARY_COREINIT, FSAIsEof),
REPLACE_FUNCTION(FSAFlushMultiQuota, LIBRARY_COREINIT, FSAFlushMultiQuota),
REPLACE_FUNCTION(FSAFlushQuota, LIBRARY_COREINIT, FSAFlushQuota),
REPLACE_FUNCTION(FSAChangeMode, LIBRARY_COREINIT, FSAChangeMode),
REPLACE_FUNCTION(FSAOpenFileByStat, LIBRARY_COREINIT, FSAOpenFileByStat),
REPLACE_FUNCTION(FSAAppendFile, LIBRARY_COREINIT, FSAAppendFile),
REPLACE_FUNCTION(FSAAppendFileEx, LIBRARY_COREINIT, FSAAppendFileEx),
REPLACE_FUNCTION(FSAOpenDir, LIBRARY_COREINIT, FSAOpenDir),
REPLACE_FUNCTION(FSAReadDir, LIBRARY_COREINIT, FSAReadDir),
REPLACE_FUNCTION(FSARewindDir, LIBRARY_COREINIT, FSARewindDir),
REPLACE_FUNCTION(FSACloseDir, LIBRARY_COREINIT, FSACloseDir),
REPLACE_FUNCTION(FSAMakeDir, LIBRARY_COREINIT, FSAMakeDir),
REPLACE_FUNCTION(FSAChangeDir, LIBRARY_COREINIT, FSAChangeDir),
};
uint32_t fsa_file_function_replacements_size = sizeof(fsa_file_function_replacements) / sizeof(function_replacement_data_t);
FSError processShimBufferForFSA(FSShimWrapper *param) {
auto res = doForLayer(param);
if (res == FS_ERROR_FORCE_REAL_FUNCTION) {
if (param->sync == FS_SHIM_TYPE_ASYNC) {
DEBUG_FUNCTION_LINE_ERR("ASYNC FSA API is not supported");
OSFatal("ContentRedirectionModule: ASYNC FSA API is not supported");
}
}
free(param);
return res;
}

View File

@ -1,219 +0,0 @@
#include "FSDirReplacements.h"
#include "FileUtils.h"
#include "IFSWrapper.h"
#include "utils/logger.h"
#include <coreinit/cache.h>
#include <coreinit/filesystem.h>
DECL_FUNCTION(FSStatus, FSOpenDir, FSClient *client, FSCmdBlock *block, const char *path, FSDirectoryHandle *handle, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
if (isForceRealFunction(errorMask)) {
return real_FSOpenDir(client, block, path, handle, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, p = path](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSOpenDir(c, b, p, h, realErrorMask);
},
[f = getFullPathForFSClient(client, path), h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSOpenDirWrapper(f.c_str(), h);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSOpenDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSDirectoryHandle *handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
if (isForceRealFunction(errorMask)) {
return real_FSOpenDirAsync(client, block, path, handle, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, p = path, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSOpenDirAsync(c, b, p, h, realErrorMask, a);
},
[f = getFullPathForFSClient(client, path), h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSOpenDirWrapper(f.c_str(), h);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSReadDir, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, [[maybe_unused]] FSDirectoryEntry *entry, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("", errorMask);
if (isForceRealFunction(errorMask)) {
return real_FSReadDir(client, block, handle, entry, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, e = entry](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSReadDir(c, b, h, e, realErrorMask);
},
[h = handle, e = entry](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSReadDirWrapper(h, e);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSReadDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSDirectoryEntry *entry, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE();
if (isForceRealFunction(errorMask)) {
return real_FSReadDirAsync(client, block, handle, entry, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, e = entry, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSReadDirAsync(c, b, h, e, realErrorMask, a);
},
[h = handle, e = entry](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSReadDirWrapper(h, e);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSCloseDir, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("");
if (isForceRealFunction(errorMask)) {
return real_FSCloseDir(client, block, handle, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSCloseDir(c, b, h, realErrorMask);
},
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSCloseDirWrapper(h);
},
[h = handle, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr<IFSWrapper> &layer, FSStatus res) -> FSStatus {
if (layer->isValidDirHandle(h)) {
layer->deleteDirHandle(h);
} else {
DEBUG_FUNCTION_LINE_ERR_LAMBDA(filename, func, line, "Expected to delete dirHandle by %08X but it was not found", h);
}
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Sync result %d", res);
return res;
});
}
DECL_FUNCTION(FSStatus, FSCloseDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE();
if (isForceRealFunction(errorMask)) {
return real_FSCloseDirAsync(client, block, handle, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSCloseDirAsync(c, b, h, realErrorMask, a);
},
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSCloseDirWrapper(h);
},
[c = client, b = block, h = handle, a = asyncData, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr<IFSWrapper> &layer, FSStatus res) -> FSStatus {
if (layer->isValidDirHandle(h)) {
layer->deleteDirHandle(h);
} else {
DEBUG_FUNCTION_LINE_ERR_LAMBDA(filename, func, line, "Expected to delete dirHandle by %08X but it was not found", h);
}
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Async result %d", res);
return send_result_async(c, b, a, res);
});
}
DECL_FUNCTION(FSStatus, FSRewindDir, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("");
if (isForceRealFunction(errorMask)) {
return real_FSRewindDir(client, block, handle, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSRewindDir(c, b, h, realErrorMask);
},
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSRewindDirWrapper(h);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSRewindDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE();
if (isForceRealFunction(errorMask)) {
return real_FSRewindDirAsync(client, block, handle, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSRewindDirAsync(c, b, h, realErrorMask, a);
},
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSRewindDirWrapper(h);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSMakeDir, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
if (isForceRealFunction(errorMask)) {
return real_FSMakeDir(client, block, path, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, p = path](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSMakeDir(c, b, p, realErrorMask);
},
[f = getFullPathForFSClient(client, path)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSMakeDirWrapper(f.c_str());
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSMakeDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
if (isForceRealFunction(errorMask)) {
return real_FSMakeDirAsync(client, block, path, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, p = path, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSMakeDirAsync(c, b, p, realErrorMask, a);
},
[f = getFullPathForFSClient(client, path)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSMakeDirWrapper(f.c_str());
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSChangeDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("FSChangeDirAsync %s", path);
setWorkingDirForFSClient(client, path);
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),
REPLACE_FUNCTION(FSReadDir, LIBRARY_COREINIT, FSReadDir),
REPLACE_FUNCTION(FSReadDirAsync, LIBRARY_COREINIT, FSReadDirAsync),
REPLACE_FUNCTION(FSCloseDir, LIBRARY_COREINIT, FSCloseDir),
REPLACE_FUNCTION(FSCloseDirAsync, LIBRARY_COREINIT, FSCloseDirAsync),
REPLACE_FUNCTION(FSRewindDir, LIBRARY_COREINIT, FSRewindDir),
REPLACE_FUNCTION(FSRewindDirAsync, LIBRARY_COREINIT, FSRewindDirAsync),
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);

View File

@ -1,10 +0,0 @@
#pragma once
#include "IFSWrapper.h"
#include <coreinit/filesystem.h>
#include <function_patcher/function_patching.h>
#include <functional>
#include <string>
extern function_replacement_data_t fs_dir_function_replacements[];
extern uint32_t fs_dir_function_replacements_size;

View File

@ -1,616 +0,0 @@
#include "FSFileReplacements.h"
#include "FileUtils.h"
#include "utils/logger.h"
DECL_FUNCTION(FSStatus, FSOpenFileEx, FSClient *client, FSCmdBlock *block, const char *path, const char *mode, FSMode createMode, FSOpenFileFlags openFlag, uint32_t preallocSize, FSFileHandle *handle, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
if (isForceRealFunction(errorMask)) {
return real_FSOpenFileEx(client, block, path, mode, createMode, openFlag, preallocSize, handle, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, p = path, m = mode, cm = createMode, of = openFlag, pa = preallocSize, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSOpenFileEx(c, b, p, m, cm, of, pa, h, realErrorMask);
},
[f = getFullPathForFSClient(client, path), m = mode, h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSOpenFileWrapper(f.c_str(), m, h);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSOpenFileExAsync, FSClient *client, FSCmdBlock *block, const char *path, const char *mode, FSMode createMode, FSOpenFileFlags openFlag, uint32_t preallocSize, FSFileHandle *handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
if (isForceRealFunction(errorMask)) {
return real_FSOpenFileExAsync(client, block, path, mode, createMode, openFlag, preallocSize, handle, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, p = path, m = mode, cm = createMode, of = openFlag, pa = preallocSize, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSOpenFileExAsync(c, b, p, m, cm, of, pa, h, realErrorMask, a);
},
[p = getFullPathForFSClient(client, path), m = mode, h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSOpenFileWrapper(p.c_str(), m, h);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSOpenFile, FSClient *client, FSCmdBlock *block, char *path, const char *mode, FSFileHandle *handle, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
if (isForceRealFunction(errorMask)) {
return real_FSOpenFile(client, block, path, mode, handle, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, p = path, m = mode, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSOpenFile(c, b, p, m, h, realErrorMask);
},
[f = getFullPathForFSClient(client, path), m = mode, h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSOpenFileWrapper(f.c_str(), m, h);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSOpenFileAsync, FSClient *client, FSCmdBlock *block, const char *path, const char *mode, FSFileHandle *handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
if (isForceRealFunction(errorMask)) {
return real_FSOpenFileAsync(client, block, path, mode, handle, errorMask, asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, p = path, m = mode, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSOpenFileAsync(c, b, p, m, h, realErrorMask, a);
},
[p = getFullPathForFSClient(client, path), m = mode, h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSOpenFileWrapper(p.c_str(), m, h);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSCloseFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
if (isForceRealFunction(errorMask)) {
return real_FSCloseFile(client, block, handle, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSCloseFile(c, b, h, realErrorMask);
},
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSCloseFileWrapper(h);
},
[h = handle, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr<IFSWrapper> &layer, FSStatus res) -> FSStatus {
if (layer->isValidFileHandle(h)) {
layer->deleteFileHandle(h);
} else {
DEBUG_FUNCTION_LINE_ERR_LAMBDA(filename, func, line, "Expected to delete fileHandle by handle %08X but it was not found", h);
}
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Sync result %d", res);
return res;
});
}
DECL_FUNCTION(FSStatus, FSCloseFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
if (isForceRealFunction(errorMask)) {
return real_FSCloseFileAsync(client, block, handle, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSCloseFileAsync(c, b, h, realErrorMask, a);
},
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSCloseFileWrapper(h);
},
[c = client, b = block, h = handle, a = asyncData, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr<IFSWrapper> &layer, FSStatus res) -> FSStatus {
if (layer->isValidFileHandle(h)) {
layer->deleteFileHandle(h);
} else {
DEBUG_FUNCTION_LINE_ERR_LAMBDA(filename, func, line, "Expected to delete fileHandle by handle %08X but it was not found", h);
}
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Async result %d", res);
return send_result_async(c, b, a, res);
});
}
DECL_FUNCTION(FSStatus, FSGetStat, FSClient *client, FSCmdBlock *block, const char *path, FSStat *stats, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
if (isForceRealFunction(errorMask)) {
return real_FSGetStat(client, block, path, stats, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, p = path, s = stats](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSGetStat(c, b, p, s, realErrorMask);
},
[p = getFullPathForFSClient(client, path), s = stats](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSGetStatWrapper(p.c_str(), s);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSGetStatAsync, FSClient *client, FSCmdBlock *block, const char *path, FSStat *stats, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
if (isForceRealFunction(errorMask)) {
return real_FSGetStatAsync(client, block, path, stats, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, p = path, s = stats, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSGetStatAsync(c, b, p, s, realErrorMask, a);
},
[p = getFullPathForFSClient(client, path), s = stats](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSGetStatWrapper(p.c_str(), s);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSGetStatFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSStat *stats, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", handle);
if (isForceRealFunction(errorMask)) {
return real_FSGetStatFile(client, block, handle, stats, getRealErrorFlag(errorMask));
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, s = stats](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSGetStatFile(c, b, h, s, realErrorMask);
},
[h = handle, s = stats](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSGetStatFileWrapper(h, s);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSGetStatFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSStat *stats, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", handle);
if (isForceRealFunction(errorMask)) {
return real_FSGetStatFileAsync(client, block, handle, stats, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, s = stats, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSGetStatFileAsync(c, b, h, s, realErrorMask, a);
},
[h = handle, s = stats](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSGetStatFileWrapper(h, s);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSReadFile, FSClient *client, FSCmdBlock *block, void *buffer, uint32_t size, uint32_t count, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X", handle, buffer, size * count);
if (isForceRealFunction(errorMask)) {
return real_FSReadFile(client, block, buffer, size, count, handle, unk1, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, s = size, co = count, bu = buffer, u = unk1](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSReadFile(c, b, bu, s, co, h, u, realErrorMask);
},
[b = buffer, s = size, c = count, h = handle, u = unk1](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSReadFileWrapper(b, s, c, h, u);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSReadFileAsync, FSClient *client, FSCmdBlock *block, void *buffer, uint32_t size, uint32_t count, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask,
FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X", handle, buffer, size * count);
if (isForceRealFunction(errorMask)) {
return real_FSReadFileAsync(client, block, buffer, size, count, handle, unk1, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, s = size, co = count, bu = buffer, u = unk1, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSReadFileAsync(c, b, bu, s, co, h, u, realErrorMask, a);
},
[b = buffer, s = size, c = count, h = handle, u = unk1](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSReadFileWrapper(b, s, c, h, u);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSReadFileWithPos, FSClient *client, FSCmdBlock *block, void *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X pos: %08X", handle, buffer, size * count, pos);
if (isForceRealFunction(errorMask)) {
return real_FSReadFileWithPos(client, block, buffer, size, count, pos, handle, unk1, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, s = size, co = count, p = pos, bu = buffer, u = unk1](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSReadFileWithPos(c, b, bu, s, co, p, h, u, realErrorMask);
},
[b = buffer, s = size, c = count, p = pos, h = handle, u = unk1](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSReadFileWithPosWrapper(b, s, c, p, h, u);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSReadFileWithPosAsync, FSClient *client, FSCmdBlock *block, void *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, int32_t unk1, FSErrorFlag errorMask,
FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X pos: %08X", handle, buffer, size * count, pos);
if (isForceRealFunction(errorMask)) {
return real_FSReadFileWithPosAsync(client, block, buffer, size, count, pos, handle, unk1, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, s = size, co = count, p = pos, bu = buffer, u = unk1, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSReadFileWithPosAsync(c, b, bu, s, co, p, h, u, realErrorMask, a);
},
[b = buffer, s = size, c = count, p = pos, h = handle, u = unk1](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSReadFileWithPosWrapper(b, s, c, p, h, u);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSSetPosFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, uint32_t pos, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X pos: %08X", handle, pos);
if (isForceRealFunction(errorMask)) {
return real_FSSetPosFile(client, block, handle, pos, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, p = pos](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSSetPosFile(c, b, h, p, realErrorMask);
},
[h = handle, p = pos](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSSetPosFileWrapper(h, p);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSSetPosFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, uint32_t pos, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X pos: %08X", handle, pos);
if (isForceRealFunction(errorMask)) {
return real_FSSetPosFileAsync(client, block, handle, pos, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, p = pos, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSSetPosFileAsync(c, b, h, p, realErrorMask, a);
},
[h = handle, p = pos](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSSetPosFileWrapper(h, p);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSGetPosFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, uint32_t *pos, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
if (isForceRealFunction(errorMask)) {
return real_FSGetPosFile(client, block, handle, pos, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, p = pos](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSGetPosFile(c, b, h, p, realErrorMask);
},
[h = handle, p = pos](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSGetPosFileWrapper(h, p);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSGetPosFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, uint32_t *pos, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
if (isForceRealFunction(errorMask)) {
return real_FSGetPosFileAsync(client, block, handle, pos, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, p = pos, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSGetPosFileAsync(c, b, h, p, realErrorMask, a);
},
[h = handle, p = pos](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSGetPosFileWrapper(h, p);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSIsEof, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
if (isForceRealFunction(errorMask)) {
return real_FSIsEof(client, block, handle, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSIsEof(c, b, h, realErrorMask);
},
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSIsEofWrapper(h);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSIsEofAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
if (isForceRealFunction(errorMask)) {
return real_FSIsEofAsync(client, block, handle, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSIsEofAsync(c, b, h, realErrorMask, a);
},
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSIsEofWrapper(h);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSWriteFile, FSClient *client, FSCmdBlock *block, uint8_t *buffer, uint32_t size, uint32_t count, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X", handle, buffer, size * count);
if (isForceRealFunction(errorMask)) {
return real_FSWriteFile(client, block, buffer, size, count, handle, unk1, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, bu = buffer, s = size, co = count, h = handle, u = unk1](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSWriteFile(c, b, bu, s, co, h, u, realErrorMask);
},
[b = buffer, s = size, c = count, h = handle, u = unk1](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSWriteFileWrapper(b, s, c, h, u);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSWriteFileAsync, FSClient *client, FSCmdBlock *block, uint8_t *buffer, uint32_t size, uint32_t count, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask,
FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X", handle, buffer, size * count);
if (isForceRealFunction(errorMask)) {
return real_FSWriteFileAsync(client, block, buffer, size, count, handle, unk1, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, bu = buffer, s = size, co = count, h = handle, u = unk1, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSWriteFileAsync(c, b, bu, s, co, h, u, realErrorMask, a);
},
[b = buffer, s = size, c = count, h = handle, u = unk1](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSWriteFileWrapper(b, s, c, h, u);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSTruncateFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
if (isForceRealFunction(errorMask)) {
return real_FSTruncateFile(client, block, handle, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSTruncateFile(c, b, h, realErrorMask);
},
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSTruncateFileWrapper(h);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSTruncateFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
if (isForceRealFunction(errorMask)) {
return real_FSTruncateFileAsync(client, block, handle, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSTruncateFileAsync(c, b, h, realErrorMask, a);
},
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSTruncateFileWrapper(h);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSRemove, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
if (isForceRealFunction(errorMask)) {
return real_FSRemove(client, block, path, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, p = path](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSRemove(c, b, p, realErrorMask);
},
[p = getFullPathForFSClient(client, path)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSRemoveWrapper(p.c_str());
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSRemoveAsync, FSClient *client, FSCmdBlock *block, const char *path, [[maybe_unused]] FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
if (isForceRealFunction(errorMask)) {
return real_FSRemoveAsync(client, block, path, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, p = path, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSRemoveAsync(c, b, p, realErrorMask, a);
},
[p = getFullPathForFSClient(client, path)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSRemoveWrapper(p.c_str());
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSRename, FSClient *client, FSCmdBlock *block, const char *oldPath, const char *newPath, FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("%s -> %s", oldPath, newPath);
if (isForceRealFunction(errorMask)) {
return real_FSRename(client, block, oldPath, newPath, getRealErrorFlag(errorMask));
}
return doForLayer(
client,
errorMask,
[c = client, b = block, oP = oldPath, nP = newPath](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSRename(c, b, oP, nP, realErrorMask);
},
[oP = getFullPathForFSClient(client, oldPath), nP = getFullPathForFSClient(client, newPath)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSRenameWrapper(oP.c_str(), nP.c_str());
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSRenameAsync,
FSClient *client,
FSCmdBlock *block,
const char *oldPath,
const char *newPath,
FSErrorFlag errorMask,
FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("%s -> %s", oldPath, newPath);
if (isForceRealFunction(errorMask)) {
return real_FSRenameAsync(client, block, oldPath, newPath, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, oP = oldPath, nP = newPath, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSRenameAsync(c, b, oP, nP, realErrorMask, a);
},
[oP = getFullPathForFSClient(client, oldPath), nP = getFullPathForFSClient(client, newPath)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSRenameWrapper(oP.c_str(), nP.c_str());
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSFlushFile, FSClient *client, FSCmdBlock *block, [[maybe_unused]] FSFileHandle handle, [[maybe_unused]] FSErrorFlag errorMask) {
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
if (isForceRealFunction(errorMask)) {
return real_FSFlushFile(client, block, handle, errorMask);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSFlushFile(c, b, h, realErrorMask);
},
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSFlushFileWrapper(h);
},
SYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSFlushFileAsync, FSClient *client, FSCmdBlock *block, [[maybe_unused]] FSFileHandle handle, [[maybe_unused]] FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
if (isForceRealFunction(errorMask)) {
return real_FSFlushFileAsync(client, block, handle, getRealErrorFlag(errorMask), asyncData);
}
return doForLayer(
client,
errorMask,
[c = client, b = block, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
return real_FSFlushFileAsync(c, b, h, realErrorMask, a);
},
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
return layer->FSFlushFileWrapper(h);
},
ASYNC_RESULT_HANDLER);
}
DECL_FUNCTION(FSStatus, FSChangeModeAsync,
FSClient *client,
FSCmdBlock *block,
const char *path,
[[maybe_unused]] FSMode mode,
[[maybe_unused]] FSMode modeMask,
[[maybe_unused]] FSErrorFlag errorMask,
FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED path %s mode: %08X", path, mode);
return real_FSChangeModeAsync(client, block, path, mode, modeMask, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSGetFreeSpaceSizeAsync, FSClient *client, FSCmdBlock *block, const char *path, [[maybe_unused]] uint64_t *outSize, [[maybe_unused]] FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED. Path: %s", path);
return real_FSGetFreeSpaceSizeAsync(client, block, path, outSize, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSWriteFileWithPosAsync, FSClient *client, FSCmdBlock *block, uint8_t *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask, FSAsyncData *asyncData) {
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED. handle %08X size %08X", handle, size * count);
return real_FSWriteFileWithPosAsync(client, block, buffer, size, count, pos, handle, unk1, errorMask, asyncData);
}
function_replacement_data_t fs_file_function_replacements[] = {
REPLACE_FUNCTION(FSOpenFileEx, LIBRARY_COREINIT, FSOpenFileEx),
REPLACE_FUNCTION(FSOpenFileExAsync, LIBRARY_COREINIT, FSOpenFileExAsync),
REPLACE_FUNCTION(FSOpenFile, LIBRARY_COREINIT, FSOpenFile),
REPLACE_FUNCTION(FSOpenFileAsync, LIBRARY_COREINIT, FSOpenFileAsync),
REPLACE_FUNCTION(FSCloseFile, LIBRARY_COREINIT, FSCloseFile),
REPLACE_FUNCTION(FSCloseFileAsync, LIBRARY_COREINIT, FSCloseFileAsync),
REPLACE_FUNCTION(FSGetStat, LIBRARY_COREINIT, FSGetStat),
REPLACE_FUNCTION(FSGetStatAsync, LIBRARY_COREINIT, FSGetStatAsync),
REPLACE_FUNCTION(FSGetStatFile, LIBRARY_COREINIT, FSGetStatFile),
REPLACE_FUNCTION(FSGetStatFileAsync, LIBRARY_COREINIT, FSGetStatFileAsync),
REPLACE_FUNCTION(FSReadFile, LIBRARY_COREINIT, FSReadFile),
REPLACE_FUNCTION(FSReadFileAsync, LIBRARY_COREINIT, FSReadFileAsync),
REPLACE_FUNCTION(FSReadFileWithPos, LIBRARY_COREINIT, FSReadFileWithPos),
REPLACE_FUNCTION(FSReadFileWithPosAsync, LIBRARY_COREINIT, FSReadFileWithPosAsync),
REPLACE_FUNCTION(FSSetPosFile, LIBRARY_COREINIT, FSSetPosFile),
REPLACE_FUNCTION(FSSetPosFileAsync, LIBRARY_COREINIT, FSSetPosFileAsync),
REPLACE_FUNCTION(FSGetPosFile, LIBRARY_COREINIT, FSGetPosFile),
REPLACE_FUNCTION(FSGetPosFileAsync, LIBRARY_COREINIT, FSGetPosFileAsync),
REPLACE_FUNCTION(FSIsEof, LIBRARY_COREINIT, FSIsEof),
REPLACE_FUNCTION(FSIsEofAsync, LIBRARY_COREINIT, FSIsEofAsync),
REPLACE_FUNCTION(FSWriteFile, LIBRARY_COREINIT, FSWriteFile),
REPLACE_FUNCTION(FSWriteFileAsync, LIBRARY_COREINIT, FSWriteFileAsync),
REPLACE_FUNCTION(FSTruncateFile, LIBRARY_COREINIT, FSTruncateFile),
REPLACE_FUNCTION(FSTruncateFileAsync, LIBRARY_COREINIT, FSTruncateFileAsync),
REPLACE_FUNCTION(FSRemove, LIBRARY_COREINIT, FSRemove),
REPLACE_FUNCTION(FSRemoveAsync, LIBRARY_COREINIT, FSRemoveAsync),
REPLACE_FUNCTION(FSRename, LIBRARY_COREINIT, FSRename),
REPLACE_FUNCTION(FSRenameAsync, LIBRARY_COREINIT, FSRenameAsync),
REPLACE_FUNCTION(FSFlushFile, LIBRARY_COREINIT, FSFlushFile),
REPLACE_FUNCTION(FSFlushFileAsync, LIBRARY_COREINIT, FSFlushFileAsync),
REPLACE_FUNCTION(FSChangeModeAsync, LIBRARY_COREINIT, FSChangeModeAsync),
REPLACE_FUNCTION(FSWriteFileWithPosAsync, LIBRARY_COREINIT, FSWriteFileWithPosAsync),
//REPLACE_FUNCTION(FSGetFreeSpaceSizeAsync, LIBRARY_COREINIT, FSGetFreeSpaceSizeAsync),
//REPLACE_FUNCTION_VIA_ADDRESS(FSGetFreeSpaceSizeAsync, LIBRARY_COREINIT, 0x0A000000 + 0x0256079c),
};
uint32_t fs_file_function_replacements_size = sizeof(fs_file_function_replacements) / sizeof(function_replacement_data_t);

810
src/FSReplacements.cpp Normal file
View File

@ -0,0 +1,810 @@
#include "FSReplacements.h"
#include "FileUtils.h"
#include "utils/StringTools.h"
#include "utils/logger.h"
#include <coreinit/core.h>
FSStatus processFSError(FSError fsError, FSClient *client, FSErrorFlag errorMask) {
auto result = fsError >= 0 ? static_cast<FSStatus>(fsError) : fsaDecodeFsaStatusToFsStatus(fsError);
if (result >= FS_STATUS_OK || result == FS_STATUS_END || result == FS_STATUS_CANCELLED) {
return result;
}
FSErrorFlag errorFlags = FS_ERROR_FLAG_NONE;
bool forceError = false;
switch ((int32_t) result) {
case FS_STATUS_MAX:
errorFlags = FS_ERROR_FLAG_MAX;
break;
case FS_STATUS_ALREADY_OPEN:
errorFlags = FS_ERROR_FLAG_ALREADY_OPEN;
break;
case FS_STATUS_EXISTS:
errorFlags = FS_ERROR_FLAG_EXISTS;
break;
case FS_STATUS_NOT_FOUND:
errorFlags = FS_ERROR_FLAG_NOT_FOUND;
break;
case FS_STATUS_NOT_FILE:
errorFlags = FS_ERROR_FLAG_NOT_FILE;
break;
case FS_STATUS_NOT_DIR:
errorFlags = FS_ERROR_FLAG_NOT_DIR;
break;
case FS_STATUS_ACCESS_ERROR:
errorFlags = FS_ERROR_FLAG_ACCESS_ERROR;
break;
case FS_STATUS_PERMISSION_ERROR:
errorFlags = FS_ERROR_FLAG_PERMISSION_ERROR;
break;
case FS_STATUS_FILE_TOO_BIG:
errorFlags = FS_ERROR_FLAG_FILE_TOO_BIG;
break;
case FS_STATUS_STORAGE_FULL:
errorFlags = FS_ERROR_FLAG_STORAGE_FULL;
break;
case FS_STATUS_JOURNAL_FULL:
errorFlags = FS_ERROR_FLAG_JOURNAL_FULL;
break;
case FS_STATUS_UNSUPPORTED_CMD:
errorFlags = FS_ERROR_FLAG_UNSUPPORTED_CMD;
break;
case FS_STATUS_MEDIA_NOT_READY:
case FS_STATUS_MEDIA_ERROR:
case FS_STATUS_CORRUPTED:
case FS_STATUS_FATAL_ERROR:
forceError = true;
break;
case FS_STATUS_OK:
break;
}
if (forceError || (errorMask != FS_ERROR_FLAG_NONE && (errorFlags & errorMask) == 0)) {
DEBUG_FUNCTION_LINE_ERR("Transit to Fatal Error. Error %s (%d)", FSAGetStatusStr(fsError), fsError);
auto clientBody = fsClientGetBody(client);
fsClientHandleFatalErrorAndBlock(clientBody, clientBody->lastError);
return FS_STATUS_FATAL_ERROR;
}
return result;
}
void handleAsyncRequestsCallback(IOSError err, void *context) {
auto *param = (AsyncParamFS *) context;
auto *client = param->client;
auto *clientBody = fsClientGetBody(client);
auto *block = param->block;
auto *asyncData = &param->asyncData;
auto errorMask = param->errorMask;
auto fsError = __FSAShimDecodeIosErrorToFsaStatus(clientBody->clientHandle, err);
auto fsStatus = processFSError(fsError, client, errorMask);
handleAsyncResult(client, block, asyncData, fsStatus);
}
bool processFSAShimInThread(FSAShimBuffer *shimBuffer, FSClient *client, FSCmdBlock *block, FSErrorFlag errorMask, FSAsyncData *asyncData) {
bool res = false;
if (gThreadsRunning) {
// we **don't** need to free this in this function.
auto param = (FSShimWrapper *) malloc(sizeof(FSShimWrapper));
if (param == nullptr) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for FSShimWrapper");
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapper");
}
param->api = FS_SHIM_API_FS;
param->sync = FS_SHIM_TYPE_ASYNC;
param->shim = shimBuffer;
param->asyncFS.callback = handleAsyncRequestsCallback;
// The client and block have to valid during the whole fs operation
param->asyncFS.client = client;
param->asyncFS.block = block;
// But we need to copy the asyncData as it might be on the stack.
param->asyncFS.asyncData.param = asyncData->param;
param->asyncFS.asyncData.callback = asyncData->callback;
param->asyncFS.asyncData.ioMsgQueue = asyncData->ioMsgQueue;
// Copy by value
param->asyncFS.errorMask = errorMask;
if (OSGetCurrentThread() == gThreadData[OSGetCoreId()].thread) {
processShimBufferForFS(param);
// because we're doing this in sync, free(param) has already been called at this point.
res = true;
} else {
auto message = (FSShimWrapperMessage *) malloc(sizeof(FSShimWrapperMessage));
if (message == nullptr) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for FSShimWrapperMessage");
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapperMessage");
}
message->param = param;
res = sendMessageToThread(message);
// the other thread is call free for us, so we can return early!
}
} else {
DEBUG_FUNCTION_LINE_WARN("Threads are not running yet, skip replacement");
}
return res;
}
DECL_FUNCTION(FSStatus, FSReadFileGeneric, FSClient *client, FSCmdBlock *block, uint8_t *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, FSAReadFlag readFlag, FSErrorFlag errorMask,
FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
// Ensure size * count is not > 32 bit.
auto bytes = uint64_t{size} * uint64_t{count};
if (bytes > 0xFFFFFFFFull) {
DEBUG_FUNCTION_LINE_ERR("FS doesn't support transaction size >= 4GB.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_PARAM);
return FS_STATUS_FATAL_ERROR;
}
if (((uint32_t) buffer & 0x3f) != 0) {
DEBUG_FUNCTION_LINE_ERR("buffer must be aligned by FS_IO_BUFFER_ALIGN");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_ALIGNMENT);
return FS_STATUS_FATAL_ERROR;
}
if (fsaShimPrepareRequestReadFile(shimBuffer, clientBody->clientHandle, buffer, size, count, pos, handle, readFlag) == 0) {
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSReadFileGeneric(client, block, buffer, size, count, pos, handle, readFlag, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSWriteFileGeneric, FSClient *client, FSCmdBlock *block, const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, FSAWriteFlag writeFlag, FSErrorFlag errorMask,
FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
// Ensure size * count is not > 32 bit.
auto bytes = uint64_t{size} * uint64_t{count};
if (bytes > 0xFFFFFFFFull) {
DEBUG_FUNCTION_LINE_ERR("FS doesn't support transaction size >= 4GB.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_PARAM);
return FS_STATUS_FATAL_ERROR;
}
if (((uint32_t) buffer & 0x3f) != 0) {
DEBUG_FUNCTION_LINE_ERR("buffer must be aligned by FS_IO_BUFFER_ALIGN");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_ALIGNMENT);
return FS_STATUS_FATAL_ERROR;
}
if (fsaShimPrepareRequestWriteFile(shimBuffer, clientBody->clientHandle, buffer, size, count, pos, handle, writeFlag) == 0) {
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSWriteFileGeneric(client, block, buffer, size, count, pos, handle, writeFlag, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSOpenFileExAsync, FSClient *client, FSCmdBlock *block, const char *path, const char *mode, FSMode createMode, FSOpenFileFlags openFlag, uint32_t preallocSize, FSFileHandle *handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (handle == nullptr) {
DEBUG_FUNCTION_LINE_ERR("handle is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_BUFFER);
return FS_STATUS_FATAL_ERROR;
}
if (path == nullptr) {
DEBUG_FUNCTION_LINE_ERR("path is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_PATH);
return FS_STATUS_FATAL_ERROR;
}
if (mode == nullptr) {
DEBUG_FUNCTION_LINE_ERR("mode is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_PATH);
return FS_STATUS_FATAL_ERROR;
}
if (fsaShimPrepareRequestOpenFile(shimBuffer, clientBody->clientHandle, path, mode, createMode, openFlag, preallocSize) == 0) {
// Hacky solution to pass the pointer into the other thread.
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
hackyBuffer[1] = (uint32_t) handle;
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSOpenFileExAsync(client, block, path, mode, createMode, openFlag, preallocSize, handle, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSCloseFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (fsaShimPrepareRequestCloseFile(shimBuffer, clientBody->clientHandle, handle) == 0) {
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSCloseFileAsync(client, block, handle, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSGetStatAsync, FSClient *client, FSCmdBlock *block, const char *path, FSStat *stat, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (path == nullptr) {
DEBUG_FUNCTION_LINE_ERR("path is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_PATH);
return FS_STATUS_FATAL_ERROR;
}
if (stat == nullptr) {
DEBUG_FUNCTION_LINE_ERR("stat is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_BUFFER);
return FS_STATUS_FATAL_ERROR;
}
if (fsaShimPrepareRequestQueryInfo(shimBuffer, clientBody->clientHandle, path, FSA_QUERY_INFO_STAT) == 0) {
// Hacky solution to pass the pointer into the other thread.
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
hackyBuffer[1] = (uint32_t) stat;
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSGetStatAsync(client, block, path, stat, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSGetStatFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSStat *stat, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (stat == nullptr) {
DEBUG_FUNCTION_LINE_ERR("stat is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_BUFFER);
return FS_STATUS_FATAL_ERROR;
}
if (fsaShimPrepareRequestStatFile(shimBuffer, clientBody->clientHandle, handle) == 0) {
// Hacky solution to pass the pointer into the other thread.
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
hackyBuffer[1] = (uint32_t) stat;
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSGetStatFileAsync(client, block, handle, stat, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSSetPosFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSAFilePosition pos, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (fsaShimPrepareRequestSetPos(shimBuffer, clientBody->clientHandle, handle, pos) == 0) {
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSSetPosFileAsync(client, block, handle, pos, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSGetPosFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, const FSAFilePosition *pos, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (pos == nullptr) {
DEBUG_FUNCTION_LINE_ERR("pos is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_BUFFER);
return FS_STATUS_FATAL_ERROR;
}
if (fsaShimPrepareRequestGetPos(shimBuffer, clientBody->clientHandle, handle) == 0) {
// Hacky solution to pass the pointer into the other thread.
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
hackyBuffer[1] = (uint32_t) pos;
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSGetPosFileAsync(client, block, handle, pos, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSIsEofAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (fsaShimPrepareRequestIsEof(shimBuffer, clientBody->clientHandle, handle) == 0) {
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSIsEofAsync(client, block, handle, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSTruncateFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (fsaShimPrepareRequestTruncate(shimBuffer, clientBody->clientHandle, handle) == 0) {
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSTruncateFileAsync(client, block, handle, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSRemoveAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (path == nullptr) {
DEBUG_FUNCTION_LINE_ERR("path is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_PATH);
return FS_STATUS_FATAL_ERROR;
}
if (fsaShimPrepareRequestRemove(shimBuffer, clientBody->clientHandle, path) == 0) {
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSRemoveAsync(client, block, path, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSRenameAsync, FSClient *client, FSCmdBlock *block, const char *oldPath, const char *newPath, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (oldPath == nullptr || newPath == nullptr) {
DEBUG_FUNCTION_LINE_ERR("oldPath or newPath is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_PATH);
return FS_STATUS_FATAL_ERROR;
}
if (fsaShimPrepareRequestRename(shimBuffer, clientBody->clientHandle, oldPath, newPath) == 0) {
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSRenameAsync(client, block, oldPath, newPath, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSFlushFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (fsaShimPrepareRequestFlushFile(shimBuffer, clientBody->clientHandle, handle) == 0) {
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSFlushFileAsync(client, block, handle, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSChangeModeAsync, FSClient *client, FSCmdBlock *block, const char *path, FSMode mode, FSMode modeMask, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (path == nullptr) {
DEBUG_FUNCTION_LINE_ERR("path is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_PATH);
return FS_STATUS_FATAL_ERROR;
}
if (fsaShimPrepareRequestChangeMode(shimBuffer, clientBody->clientHandle, path, mode, modeMask) == 0) {
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSChangeModeAsync(client, block, path, mode, modeMask, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSOpenDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSDirectoryHandle *handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (path == nullptr) {
DEBUG_FUNCTION_LINE_ERR("path is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_PATH);
return FS_STATUS_FATAL_ERROR;
}
if (handle == nullptr) {
DEBUG_FUNCTION_LINE_ERR("handle is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_BUFFER);
return FS_STATUS_FATAL_ERROR;
}
if (fsaShimPrepareRequestOpenDir(shimBuffer, clientBody->clientHandle, path) == 0) {
// Hacky solution to pass the pointer into the other thread.
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
hackyBuffer[1] = (uint32_t) handle;
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSOpenDirAsync(client, block, path, handle, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSReadDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSDirectoryEntry *entry, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (entry == nullptr) {
DEBUG_FUNCTION_LINE_ERR("entry is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_BUFFER);
return FS_STATUS_FATAL_ERROR;
}
if (fsaShimPrepareRequestReadDir(shimBuffer, clientBody->clientHandle, handle) == 0) {
// Hacky solution to pass the pointer into the other thread.
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
hackyBuffer[1] = (uint32_t) entry;
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSReadDirAsync(client, block, handle, entry, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSCloseDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (fsaShimPrepareRequestCloseDir(shimBuffer, clientBody->clientHandle, handle) == 0) {
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSCloseDirAsync(client, block, handle, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSRewindDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (fsaShimPrepareRequestRewindDir(shimBuffer, clientBody->clientHandle, handle) == 0) {
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSRewindDirAsync(client, block, handle, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSMakeDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (path == nullptr) {
DEBUG_FUNCTION_LINE_ERR("path is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_PATH);
return FS_STATUS_FATAL_ERROR;
}
if (fsaShimPrepareRequestMakeDir(shimBuffer, clientBody->clientHandle, path, static_cast<FSMode>(0x660)) == 0) {
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSMakeDirAsync(client, block, path, errorMask, asyncData);
}
DECL_FUNCTION(FSStatus, FSChangeDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
auto *clientBody = fsClientGetBody(client);
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
if (path == nullptr) {
DEBUG_FUNCTION_LINE_ERR("path is null.");
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_PATH);
return FS_STATUS_FATAL_ERROR;
}
if (fsaShimPrepareRequestChangeDir(shimBuffer, clientBody->clientHandle, path) == 0) {
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
return FS_STATUS_OK;
}
}
return real_FSChangeDirAsync(client, block, path, errorMask, asyncData);
}
function_replacement_data_t fs_file_function_replacements[] = {
REPLACE_FUNCTION(FSOpenFileExAsync, LIBRARY_COREINIT, FSOpenFileExAsync),
REPLACE_FUNCTION(FSCloseFileAsync, LIBRARY_COREINIT, FSCloseFileAsync),
REPLACE_FUNCTION(FSGetStatAsync, LIBRARY_COREINIT, FSGetStatAsync),
REPLACE_FUNCTION(FSGetStatFileAsync, LIBRARY_COREINIT, FSGetStatFileAsync),
REPLACE_FUNCTION_VIA_ADDRESS(FSReadFileGeneric, 0x3201C400 + 0x4ecc0, 0x101C400 + 0x4ecc0),
REPLACE_FUNCTION(FSSetPosFileAsync, LIBRARY_COREINIT, FSSetPosFileAsync),
REPLACE_FUNCTION(FSGetPosFileAsync, LIBRARY_COREINIT, FSGetPosFileAsync),
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),
REPLACE_FUNCTION(FSReadDirAsync, LIBRARY_COREINIT, FSReadDirAsync),
REPLACE_FUNCTION(FSCloseDirAsync, LIBRARY_COREINIT, FSCloseDirAsync),
REPLACE_FUNCTION(FSRewindDirAsync, LIBRARY_COREINIT, FSRewindDirAsync),
REPLACE_FUNCTION(FSMakeDirAsync, LIBRARY_COREINIT, FSMakeDirAsync),
REPLACE_FUNCTION(FSChangeDirAsync, LIBRARY_COREINIT, FSChangeDirAsync),
};
uint32_t fs_file_function_replacements_size = sizeof(fs_file_function_replacements) / sizeof(function_replacement_data_t);
FSError processShimBufferForFS(FSShimWrapper *param) {
FSError result = doForLayer(param);
FSStatus fsResult = FS_STATUS_MEDIA_ERROR;
if (result == FS_ERROR_FORCE_REAL_FUNCTION) {
if (param->sync == FS_SHIM_TYPE_SYNC) {
fsResult = FS_STATUS_MEDIA_ERROR;
DEBUG_FUNCTION_LINE_ERR("SYNC FS API is not supported");
OSFatal("ContentRedirectionModule: SYNC FS API is not supported");
} else if (param->sync == FS_SHIM_TYPE_ASYNC) {
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
switch ((FSACommandEnum) param->shim->command) {
case FSA_COMMAND_READ_FILE: {
auto *request = &param->shim->request.readFile;
fsResult = real_FSReadFileGeneric(param->asyncFS.client, param->asyncFS.block, request->buffer, request->size, request->count, request->pos, request->handle, request->readFlags, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSReadFileGeneric. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_WRITE_FILE: {
auto *request = &param->shim->request.writeFile;
fsResult = real_FSWriteFileGeneric(param->asyncFS.client, param->asyncFS.block, request->buffer, request->size, request->count, request->pos, request->handle, request->writeFlags, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSWriteFileGeneric. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_OPEN_FILE: {
auto *request = &param->shim->request.openFile;
// Hacky solution. We stored the pointer from the user in the response to use it at this point.
auto *hackyBuffer = (uint32_t *) &param->shim->response;
auto *handlePtr = (FSFileHandle *) hackyBuffer[1];
fsResult = real_FSOpenFileExAsync(param->asyncFS.client, param->asyncFS.block, request->path, request->mode, static_cast<FSMode>(request->unk0x290), static_cast<FSOpenFileFlags>(request->unk0x294), request->unk0x298, handlePtr, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSOpenFileExAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_CLOSE_FILE: {
auto *request = &param->shim->request.closeFile;
fsResult = real_FSCloseFileAsync(param->asyncFS.client, param->asyncFS.block, request->handle, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSCloseFileAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_SET_POS_FILE: {
auto *request = &param->shim->request.setPosFile;
fsResult = real_FSSetPosFileAsync(param->asyncFS.client, param->asyncFS.block, request->handle, request->pos, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSSetPosFileAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_GET_POS_FILE: {
auto *request = &param->shim->request.getPosFile;
// Hacky solution. We stored the pointer from the user in the response to use it at this point.
auto *hackyBuffer = (uint32_t *) &param->shim->response;
auto *posPtr = (FSAFilePosition *) hackyBuffer[1];
fsResult = real_FSGetPosFileAsync(param->asyncFS.client, param->asyncFS.block, request->handle, posPtr, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSGetPosFileAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_STAT_FILE: {
auto *request = &param->shim->request.statFile;
// Hacky solution. We stored the pointer from the user in the response to use it at this point.
auto *hackyBuffer = (uint32_t *) &param->shim->response;
auto *statPtr = (FSStat *) hackyBuffer[1];
fsResult = real_FSGetStatFileAsync(param->asyncFS.client, param->asyncFS.block, request->handle, statPtr, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSGetStatFileAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_GET_INFO_BY_QUERY: {
auto *request = &param->shim->request.getInfoByQuery;
if (request->type == FSA_QUERY_INFO_STAT) {
// Hacky solution. We stored the pointer from the user in the response to use it at this point.
auto *hackyBuffer = (uint32_t *) &param->shim->response;
auto *statPtr = (FSStat *) hackyBuffer[1];
fsResult = real_FSGetStatAsync(param->asyncFS.client, param->asyncFS.block, request->path, statPtr, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSGetStatAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
} else {
DEBUG_FUNCTION_LINE_ERR("Missing real implementation for FSA_COMMAND_GET_INFO_BY_QUERY type %08X", request->type);
}
break;
}
case FSA_COMMAND_IS_EOF: {
auto *request = &param->shim->request.isEof;
fsResult = real_FSIsEofAsync(param->asyncFS.client, param->asyncFS.block, request->handle, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSIsEofAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_TRUNCATE_FILE: {
auto *request = &param->shim->request.truncateFile;
fsResult = real_FSTruncateFileAsync(param->asyncFS.client, param->asyncFS.block, request->handle, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSTruncateFileAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_REMOVE: {
auto *request = &param->shim->request.remove;
fsResult = real_FSRemoveAsync(param->asyncFS.client, param->asyncFS.block, request->path, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSRemoveAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_RENAME: {
auto *request = &param->shim->request.rename;
fsResult = real_FSRenameAsync(param->asyncFS.client, param->asyncFS.block, request->oldPath, request->newPath, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSRenameAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_FLUSH_FILE: {
auto *request = &param->shim->request.flushFile;
fsResult = real_FSFlushFileAsync(param->asyncFS.client, param->asyncFS.block, request->handle, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSFlushFileAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_CHANGE_MODE: {
auto *request = &param->shim->request.changeMode;
fsResult = real_FSChangeModeAsync(param->asyncFS.client, param->asyncFS.block, request->path, (FSMode) request->mode1, (FSMode) request->mode2, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSChangeModeAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_OPEN_DIR: {
auto *request = &param->shim->request.openDir;
// Hacky solution. We stored the pointer from the user in the response to use it at this point.
auto *hackyBuffer = (uint32_t *) &param->shim->response;
auto *handlePtr = (FSDirectoryHandle *) hackyBuffer[1];
fsResult = real_FSOpenDirAsync(param->asyncFS.client, param->asyncFS.block, request->path, handlePtr, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSOpenDirAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_READ_DIR: {
auto *request = &param->shim->request.readDir;
// Hacky solution. We stored the pointer from the user in the response to use it at this point.
auto *hackyBuffer = (uint32_t *) &param->shim->response;
auto *entryPtr = (FSDirectoryEntry *) hackyBuffer[1];
fsResult = real_FSReadDirAsync(param->asyncFS.client, param->asyncFS.block, request->handle, entryPtr, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSReadDirAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_CLOSE_DIR: {
auto *request = &param->shim->request.closeDir;
fsResult = real_FSCloseDirAsync(param->asyncFS.client, param->asyncFS.block, request->handle, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSCloseDirAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_REWIND_DIR: {
auto *request = &param->shim->request.rewindDir;
fsResult = real_FSRewindDirAsync(param->asyncFS.client, param->asyncFS.block, request->handle, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSRewindDirAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_MAKE_DIR: {
auto *request = &param->shim->request.makeDir;
fsResult = real_FSMakeDirAsync(param->asyncFS.client, param->asyncFS.block, request->path, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSMakeDirAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
case FSA_COMMAND_CHANGE_DIR: {
auto *request = &param->shim->request.changeDir;
fsResult = real_FSChangeDirAsync(param->asyncFS.client, param->asyncFS.block, request->path, param->asyncFS.errorMask, &param->asyncFS.asyncData);
if (fsResult != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("Failed to submit real_FSChangeDirAsync. Return was %d. Fake actual async result to FS_STATUS_MEDIA_ERROR instead", fsResult);
handleAsyncResult(param->asyncFS.client, param->asyncFS.block, &param->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR);
}
break;
}
default: {
DEBUG_FUNCTION_LINE_ERR("Missing real implementation for command %08X", param->shim->command);
fsResult = FS_STATUS_FATAL_ERROR;
}
}
#pragma GCC diagnostic pop
}
}
free(param);
if (fsResult != FS_STATUS_OK) {
result = FS_ERROR_MEDIA_ERROR;
}
return result;
}

View File

@ -314,14 +314,14 @@ bool FSWrapper::CheckFileShouldBeIgnored(std::string &path) {
auto asPath = std::filesystem::path(path);
if (std::string(asPath.filename().c_str()).starts_with(deletePrefix)) {
DEBUG_FUNCTION_LINE_VERBOSE("Ignore %s, filename starts with %s", path.c_str(), deletePrefix.c_str());
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Ignore %s, filename starts with %s", getName().c_str(), path.c_str(), deletePrefix.c_str());
return true;
}
auto newDelPath = asPath.replace_filename(deletePrefix + asPath.filename().c_str());
struct stat buf {};
if (stat(newDelPath.c_str(), &buf) == 0) {
DEBUG_FUNCTION_LINE_VERBOSE("Ignore %s, file %s exists", path.c_str(), newDelPath.c_str());
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Ignore %s, file %s exists", getName().c_str(), path.c_str(), newDelPath.c_str());
return true;
}
return false;
@ -400,7 +400,7 @@ FSError FSWrapper::FSReadFileWrapper(void *buffer, uint32_t size, uint32_t count
FSError result;
if (read < 0) {
DEBUG_FUNCTION_LINE_ERR("[%s] read %u bytes of fd %d (FSFileHandle %08X) failed", getName().c_str(), size * count, real_fd, handle);
DEBUG_FUNCTION_LINE_ERR("[%s] Read %u bytes of fd %d (FSFileHandle %08X) failed", getName().c_str(), size * count, real_fd, handle);
auto err = errno;
if (err == EBADF || err == EROFS) {
return FS_ERROR_ACCESS_ERROR;
@ -438,10 +438,10 @@ FSError FSWrapper::FSSetPosFileWrapper(FSFileHandle handle, uint32_t pos) {
int real_fd = fileHandle->fd;
DEBUG_FUNCTION_LINE_VERBOSE("[%s] lseek fd %d (FSFileHandle %08X) to get current position for truncation", getName().c_str(), real_fd, handle);
DEBUG_FUNCTION_LINE_VERBOSE("[%s] lseek fd %d (FSFileHandle %08X) SEEK_SET to position %08X", getName().c_str(), real_fd, handle, pos);
off_t newPos;
if ((newPos = lseek(real_fd, (off_t) pos, SEEK_SET)) != pos) {
DEBUG_FUNCTION_LINE_ERR("[%s] lseek fd %d (FSFileHandle %08X) to position %u failed", getName().c_str(), real_fd, handle);
DEBUG_FUNCTION_LINE_ERR("[%s] lseek fd %d (FSFileHandle %08X) to position %08X failed", getName().c_str(), real_fd, handle, pos);
if (newPos < 0) {
// TODO: read errno
}
@ -538,7 +538,7 @@ FSError FSWrapper::FSTruncateFileWrapper(FSFileHandle handle) {
return result;
}
FSError FSWrapper::FSWriteFileWrapper(uint8_t *buffer, uint32_t size, uint32_t count, FSFileHandle handle, [[maybe_unused]] uint32_t unk1) {
FSError FSWrapper::FSWriteFileWrapper(const uint8_t *buffer, uint32_t size, uint32_t count, FSFileHandle handle, [[maybe_unused]] uint32_t unk1) {
if (!isValidFileHandle(handle)) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
@ -583,7 +583,7 @@ FSError FSWrapper::FSRemoveWrapper(const char *path) {
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Remove %s (%s)", getName().c_str(), path, newPath.c_str());
if (remove(newPath.c_str()) < 0) {
auto err = errno;
DEBUG_FUNCTION_LINE_ERR("[%s] rename failed %s (%s) errno %d", getName().c_str(), path, newPath.c_str(), err);
DEBUG_FUNCTION_LINE_ERR("[%s] Rename failed %s (%s) errno %d", getName().c_str(), path, newPath.c_str(), err);
if (err == ENOTDIR) {
return FS_ERROR_NOT_DIR;
} else if (err == EACCES) {
@ -719,7 +719,7 @@ std::shared_ptr<FileInfo> FSWrapper::getFileFromHandle(FSFileHandle handle) {
}
}
DEBUG_FUNCTION_LINE_ERR("[%s] FileInfo for handle %08X was not found. isValidFileHandle check missing?", getName().c_str(), handle);
OSFatal("Failed to find file handle");
OSFatal("ContentRedirectionModule: Failed to find file handle");
return nullptr;
}
@ -731,7 +731,7 @@ std::shared_ptr<DirInfo> FSWrapper::getDirFromHandle(FSDirectoryHandle handle) {
}
}
DEBUG_FUNCTION_LINE_ERR("[%s] DirInfo for handle %08X was not found. isValidDirHandle check missing?", getName().c_str(), handle);
OSFatal("Failed to find dir handle");
OSFatal("ContentRedirectionModule: Failed to find dir handle");
return nullptr;
}

View File

@ -82,7 +82,7 @@ public:
FSError FSTruncateFileWrapper(FSFileHandle handle) override;
FSError FSWriteFileWrapper(uint8_t *buffer,
FSError FSWriteFileWrapper(const uint8_t *buffer,
uint32_t size,
uint32_t count,
FSFileHandle handle,
@ -95,6 +95,10 @@ public:
FSError FSFlushFileWrapper(FSFileHandle handle) override;
uint32_t getLayerId() override {
return (uint32_t) this;
}
protected:
virtual bool IsFileModeAllowed(const char *mode);

View File

@ -7,7 +7,7 @@
#include <filesystem>
FSError FSWrapperMergeDirsWithParent::FSOpenDirWrapper(const char *path,
FSDirectoryHandle *handle) {
FSADirectoryHandle *handle) {
if (handle == nullptr) {
DEBUG_FUNCTION_LINE_ERR("[%s] handle was NULL", getName().c_str());
return FS_ERROR_INVALID_PARAM;
@ -26,17 +26,17 @@ FSError FSWrapperMergeDirsWithParent::FSOpenDirWrapper(const char *path,
dirHandle->readResultNumberOfEntries = 0;
dirHandle->realDirHandle = 0;
if (pFSClient && pCmdBlock) {
FSDirectoryHandle realHandle = 0;
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call real_FSOpenDir for %s with error_flag %08X", getName().c_str(), path, this->getHandle());
if (clientHandle) {
FSADirectoryHandle realHandle = 0;
DEBUG_FUNCTION_LINE_ERR("[%s] Call FSAOpenDir with %s for parent layer", getName().c_str(), path);
// Call FSOpen with "this" as errorFlag call FSOpen for "parent" layers only.
if (FSOpenDir(pFSClient, pCmdBlock, path, &realHandle, (FSErrorFlag) this->getHandle()) == FS_STATUS_OK) {
if (FSAOpenDir(clientHandle, path, &realHandle) == FS_ERROR_OK) {
dirHandle->realDirHandle = realHandle;
} else {
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Failed to open real dir %s", getName().c_str(), path);
}
} else {
DEBUG_FUNCTION_LINE_ERR("[%s] Global FSClient or FSCmdBlock were null", getName().c_str());
DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str());
}
OSMemoryBarrier();
}
@ -48,7 +48,7 @@ bool FSWrapperMergeDirsWithParent::SkipDeletedFilesInReadDir() {
return false;
}
FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSDirectoryHandle handle, FSDirectoryEntry *entry) {
FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSADirectoryHandle handle, FSADirectoryEntry *entry) {
do {
auto res = FSWrapper::FSReadDirWrapper(handle, entry);
if (res == FS_ERROR_OK || res == FS_ERROR_END_OF_DIR) {
@ -62,7 +62,7 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSDirectoryHandle handle,
dirHandle->readResult = (FSDirectoryEntryEx *) malloc(sizeof(FSDirectoryEntryEx));
if (dirHandle->readResult == nullptr) {
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to alloc memory for %08X (handle %08X)", getName().c_str(), dirHandle.get(), handle);
OSFatal("Failed to alloc memory for read result");
OSFatal("ContentRedirectionModule: Failed to alloc memory for read result");
}
dirHandle->readResultCapacity = 1;
}
@ -73,11 +73,11 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSDirectoryHandle handle,
dirHandle->readResultCapacity = newCapacity;
if (dirHandle->readResult == nullptr) {
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to realloc memory for %08X (handle %08X)", getName().c_str(), dirHandle.get(), handle);
OSFatal("Failed to alloc memory for read result");
OSFatal("ContentRedirectionModule: Failed to alloc memory for read result");
}
}
memcpy(&dirHandle->readResult[dirHandle->readResultNumberOfEntries].realEntry, entry, sizeof(FSDirectoryEntry));
memcpy(&dirHandle->readResult[dirHandle->readResultNumberOfEntries].realEntry, entry, sizeof(FSADirectoryEntry));
dirHandle->readResultNumberOfEntries++;
/**
@ -95,19 +95,19 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSDirectoryHandle handle,
} else if (res == FS_ERROR_END_OF_DIR) {
// Read the real directory.
if (dirHandle->realDirHandle != 0) {
if (pFSClient && pCmdBlock) {
FSDirectoryEntry realDirEntry;
FSStatus readDirResult;
if (clientHandle) {
FSADirectoryEntry realDirEntry;
FSError readDirResult;
while (true) {
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call real_FSReadDir for %08X with error_flag %08X", getName().c_str(), dirHandle->realDirHandle, (uint32_t) this->getHandle());
readDirResult = FSReadDir(pFSClient, pCmdBlock, dirHandle->realDirHandle, &realDirEntry, (FSErrorFlag) (uint32_t) this->getHandle());
if (readDirResult == FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("[%s] Call FSReadDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle);
readDirResult = FSAReadDir(clientHandle, dirHandle->realDirHandle, &realDirEntry);
if (readDirResult == FS_ERROR_OK) {
bool found = false;
auto nameDeleted = deletePrefix + realDirEntry.name;
for (int i = 0; i < dirHandle->readResultNumberOfEntries; i++) {
auto curResult = &dirHandle->readResult[i];
// Don't return file that are "deleted"
// Don't return files that are "deleted"
if (strcmp(curResult->realEntry.name, nameDeleted.c_str()) == 0) {
found = true;
break;
@ -120,11 +120,11 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSDirectoryHandle handle,
}
// If it's new we can use it :)
if (!found) {
memcpy(entry, &realDirEntry, sizeof(FSDirectoryEntry));
memcpy(entry, &realDirEntry, sizeof(FSADirectoryEntry));
res = FS_ERROR_OK;
break;
}
} else if (readDirResult == FS_STATUS_END) {
} else if (readDirResult == FS_ERROR_END_OF_DIR) {
res = FS_ERROR_END_OF_DIR;
break;
} else {
@ -134,7 +134,7 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSDirectoryHandle handle,
}
}
} else {
DEBUG_FUNCTION_LINE_ERR("[%s] Global FSClient or FSCmdBlock were null", getName().c_str());
DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str());
}
}
} else {
@ -145,7 +145,7 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSDirectoryHandle handle,
} while (true);
}
FSError FSWrapperMergeDirsWithParent::FSCloseDirWrapper(FSDirectoryHandle handle) {
FSError FSWrapperMergeDirsWithParent::FSCloseDirWrapper(FSADirectoryHandle handle) {
auto res = FSWrapper::FSCloseDirWrapper(handle);
if (res == FS_ERROR_OK) {
@ -155,17 +155,17 @@ FSError FSWrapperMergeDirsWithParent::FSCloseDirWrapper(FSDirectoryHandle handle
}
auto dirHandle = getDirExFromHandle(handle);
if (dirHandle->realDirHandle != 0) {
if (pFSClient && pCmdBlock) {
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSCloseDir for %08X with error_flag %08X (this)", getName().c_str(), dirHandle->realDirHandle, (uint32_t) this->getHandle());
auto realResult = FSCloseDir(pFSClient, pCmdBlock, dirHandle->realDirHandle, (FSErrorFlag) (uint32_t) this->getHandle());
if (realResult == FS_STATUS_OK) {
if (clientHandle) {
DEBUG_FUNCTION_LINE_ERR("[%s] Call FSCloseDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle);
auto realResult = FSACloseDir(clientHandle, dirHandle->realDirHandle);
if (realResult == FS_ERROR_OK) {
dirHandle->realDirHandle = 0;
} else {
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to close realDirHandle %d: res %d", getName().c_str(), dirHandle->realDirHandle, realResult);
return realResult == FS_STATUS_CANCELLED ? FS_ERROR_CANCELLED : FS_ERROR_MEDIA_ERROR;
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to close realDirHandle %d: res %d", getName().c_str(), dirHandle->realDirHandle, -1);
return realResult == FS_ERROR_CANCELLED ? FS_ERROR_CANCELLED : FS_ERROR_MEDIA_ERROR;
}
} else {
DEBUG_FUNCTION_LINE_ERR("[%s] Global FSClient or FSCmdBlock were null", getName().c_str());
DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str());
}
}
@ -181,7 +181,7 @@ FSError FSWrapperMergeDirsWithParent::FSCloseDirWrapper(FSDirectoryHandle handle
return res;
}
FSError FSWrapperMergeDirsWithParent::FSRewindDirWrapper(FSDirectoryHandle handle) {
FSError FSWrapperMergeDirsWithParent::FSRewindDirWrapper(FSADirectoryHandle handle) {
auto res = FSWrapper::FSRewindDirWrapper(handle);
if (res == FS_ERROR_OK) {
if (!isValidDirHandle(handle)) {
@ -198,15 +198,15 @@ FSError FSWrapperMergeDirsWithParent::FSRewindDirWrapper(FSDirectoryHandle handl
}
if (dirHandle->realDirHandle != 0) {
if (pFSClient && pCmdBlock) {
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call real_FSRewindDir for %08X with error_flag %08X (this->getHandle())", getName().c_str(), dirHandle->realDirHandle, (uint32_t) this->getHandle());
if (FSRewindDir(pFSClient, pCmdBlock, dirHandle->realDirHandle, (FSErrorFlag) (uint32_t) this->getHandle()) == FS_STATUS_OK) {
if (clientHandle) {
DEBUG_FUNCTION_LINE_ERR("[%s] Call FSARewindDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle);
if (FSARewindDir(clientHandle, dirHandle->realDirHandle) == FS_ERROR_OK) {
dirHandle->realDirHandle = 0;
} else {
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to rewind dir for realDirHandle %08X", getName().c_str(), dirHandle->realDirHandle);
}
} else {
DEBUG_FUNCTION_LINE_ERR("[%s] Global FSClient or FSCmdBlock were null", getName().c_str());
DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str());
}
}
OSMemoryBarrier();
@ -222,39 +222,29 @@ FSWrapperMergeDirsWithParent::FSWrapperMergeDirsWithParent(const std::string &na
replaceWithPath,
fallbackOnError,
false) {
pFSClient = new (std::nothrow) FSClient;
pCmdBlock = new (std::nothrow) FSCmdBlock;
if (pFSClient == nullptr || pCmdBlock == nullptr) {
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to alloc client or cmdBlock", name.c_str());
freeFSClient();
this->clientHandle = FSAAddClient(nullptr);
if (clientHandle < 0) {
DEBUG_FUNCTION_LINE_ERR("[%s] FSAClientHandle failed: %s (%d)", name.c_str(), FSAGetStatusStr(static_cast<FSError>(clientHandle)), clientHandle);
clientHandle = 0;
}
if (FSAddClient(pFSClient, FS_ERROR_FLAG_ALL) != FS_STATUS_OK) {
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to addClient");
freeFSClient();
}
FSInitCmdBlock(pCmdBlock);
}
FSWrapperMergeDirsWithParent::~FSWrapperMergeDirsWithParent() {
freeFSClient();
}
void FSWrapperMergeDirsWithParent::freeFSClient() {
if (pFSClient) {
FSDelClient(pFSClient, FS_ERROR_FLAG_ALL);
if (clientHandle) {
FSError res;
if ((res = FSADelClient(clientHandle)) != FS_ERROR_OK) {
DEBUG_FUNCTION_LINE_ERR("[%s] FSADelClient failed: %s (%d)", FSAGetStatusStr(res), res);
}
clientHandle = 0;
}
delete pFSClient;
delete pCmdBlock;
pFSClient = nullptr;
pCmdBlock = nullptr;
}
std::shared_ptr<DirInfoEx> FSWrapperMergeDirsWithParent::getDirExFromHandle(FSDirectoryHandle handle) {
std::shared_ptr<DirInfoEx> FSWrapperMergeDirsWithParent::getDirExFromHandle(FSADirectoryHandle handle) {
auto dir = std::dynamic_pointer_cast<DirInfoEx>(getDirFromHandle(handle));
if (!dir) {
DEBUG_FUNCTION_LINE_ERR("[%s] dynamic_pointer_cast<DirInfoEx *>(%08X) failed", getName().c_str(), handle);
OSFatal("dynamic_pointer_cast<DirInfoEx *> failed");
OSFatal("ContentRedirectionModule: dynamic_pointer_cast<DirInfoEx *> failed");
}
return dir;
}

View File

@ -27,10 +27,12 @@ public:
bool SkipDeletedFilesInReadDir() override;
uint32_t getLayerId() override {
return (uint32_t) clientHandle;
}
private:
void freeFSClient();
FSClient *pFSClient;
FSCmdBlock *pCmdBlock;
FSAClientHandle clientHandle;
std::shared_ptr<DirInfoEx> getDirExFromHandle(FSDirectoryHandle handle);
};

View File

@ -6,19 +6,17 @@
#include "utils/utils.h"
#include <coreinit/cache.h>
#include <coreinit/filesystem_fsa.h>
#include <malloc.h>
#include <map>
#include <unistd.h>
std::mutex workingDirMutexFS;
std::map<uint32_t, std::string> workingDirsFS;
std::mutex workingDirMutexFSA;
std::map<uint32_t, std::string> workingDirsFSA;
std::mutex workingDirMutex;
std::map<FSAClientHandle, std::string> workingDirs;
std::mutex fsLayerMutex;
std::vector<std::unique_ptr<IFSWrapper>> fsLayers;
std::string getFullPathGeneric(uint32_t client, const char *path, std::mutex &mutex, std::map<uint32_t, std::string> &map) {
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;
@ -26,7 +24,7 @@ std::string getFullPathGeneric(uint32_t client, const char *path, std::mutex &mu
if (path[0] != '/' && path[0] != '\\') {
if (map.count(client) == 0) {
DEBUG_FUNCTION_LINE_WARN("No working dir found for client %08X, fallback to \"/\"", client);
workingDirsFS[client] = "/";
workingDirs[client] = "/";
}
res = string_format("%s%s", map.at(client).c_str(), path);
} else {
@ -38,7 +36,7 @@ std::string getFullPathGeneric(uint32_t client, const char *path, std::mutex &mu
return res;
}
void setWorkingDirGeneric(uint32_t client, const char *path, std::mutex &mutex, std::map<uint32_t, std::string> &map) {
void setWorkingDirGeneric(FSAClientHandle client, const char *path, std::mutex &mutex, std::map<FSAClientHandle, std::string> &map) {
if (!path) {
DEBUG_FUNCTION_LINE_WARN("Path was NULL");
return;
@ -55,30 +53,18 @@ void setWorkingDirGeneric(uint32_t client, const char *path, std::mutex &mutex,
}
std::string getFullPathForFSClient(FSClient *pClient, const char *path) {
return getFullPathGeneric((uint32_t) pClient, path, workingDirMutexFS, workingDirsFS);
std::string getFullPath(FSAClientHandle pClient, const char *path) {
return getFullPathGeneric(pClient, path, workingDirMutex, workingDirs);
}
void setWorkingDirForFSClient(FSClient *client, const char *path) {
setWorkingDirGeneric((uint32_t) client, path, workingDirMutexFS, workingDirsFS);
}
std::string getFullPathForFSAClient(FSAClientHandle client, const char *path) {
return getFullPathGeneric((uint32_t) client, path, workingDirMutexFSA, workingDirsFSA);
}
void setWorkingDirForFSAClient(FSAClientHandle client, const char *path) {
setWorkingDirGeneric(client, path, workingDirMutexFSA, workingDirsFSA);
void setWorkingDir(FSAClientHandle client, const char *path) {
setWorkingDirGeneric(client, path, workingDirMutex, workingDirs);
}
void clearFSLayer() {
{
std::lock_guard<std::mutex> workingDirLock(workingDirMutexFS);
workingDirsFS.clear();
}
{
std::lock_guard<std::mutex> workingDirLock(workingDirMutexFSA);
workingDirsFSA.clear();
std::lock_guard<std::mutex> workingDirLock(workingDirMutex);
workingDirs.clear();
}
{
std::lock_guard<std::mutex> layerLock(fsLayerMutex);
@ -86,62 +72,32 @@ void clearFSLayer() {
}
}
FSError doForLayerFSA(const std::function<FSError()> &real_function,
const std::function<FSError(std::unique_ptr<IFSWrapper> &layer)> &layer_callback,
const std::function<FSError(std::unique_ptr<IFSWrapper> &layer, FSError)> &result_handler) {
std::lock_guard<std::mutex> lock(fsLayerMutex);
if (!fsLayers.empty()) {
uint32_t startIndex = fsLayers.size();
if (startIndex > 0) {
for (uint32_t i = startIndex; i > 0; i--) {
auto &layer = fsLayers[i - 1];
if (!layer->isActive()) {
continue;
}
FSError layerResult = layer_callback(layer);
if (layerResult != FS_ERROR_FORCE_PARENT_LAYER) {
auto result = layerResult >= 0 ? layerResult : (FSError) ((layerResult & FS_ERROR_REAL_MASK) | FS_ERROR_EXTRA_MASK);
if (result < FS_ERROR_OK && result != FS_ERROR_END_OF_DIR && result != FS_ERROR_END_OF_FILE && result != FS_ERROR_CANCELLED) {
if (layer->fallbackOnError()) {
// Only fallback if FS_ERROR_FORCE_NO_FALLBACK flag is not set.
if (static_cast<FSError>(layerResult & FS_ERROR_EXTRA_MASK) != FS_ERROR_FORCE_NO_FALLBACK) {
continue;
}
}
}
return result_handler(layer, result);
}
}
bool sendMessageToThread(FSShimWrapperMessage *param) {
auto *curThread = &gThreadData[OSGetCoreId()];
if (curThread->setup) {
OSMessage send;
send.message = param;
send.args[0] = FS_IO_QUEUE_COMMAND_PROCESS_FS_COMMAND;
auto res = OSSendMessage(&curThread->queue, &send, OS_MESSAGE_FLAGS_NONE);
if (!res) {
DEBUG_FUNCTION_LINE_ERR("Message Queue for ContentRedirection IO Thread is full");
OSFatal("ContentRedirectionModule: Message Queue for ContentRedirection IO Thread is full");
}
return res;
} else {
DEBUG_FUNCTION_LINE_ERR("Thread not setup");
OSFatal("ContentRedirectionModule: Thread not setup");
}
return real_function();
return false;
}
// FUN_0204cc20
#define fsClientHandleFatalErrorAndBlock ((void (*)(FSClientBody *, uint32_t))(0x101C400 + 0x4cc20))
#define fsaDecodeFsaStatusToFsStatus ((FSStatus(*)(FSError))(0x101C400 + 0x4b148))
FSStatus doForLayer(FSClient *client,
FSErrorFlag errorMask,
const std::function<FSStatus(FSErrorFlag errorMask)> &real_function,
const std::function<FSError(std::unique_ptr<IFSWrapper> &layer)> &layer_callback,
const std::function<FSStatus(std::unique_ptr<IFSWrapper> &layer, FSStatus)> &result_handler) {
FSErrorFlag realErrorMask = errorMask;
FSError doForLayer(FSShimWrapper *param) {
std::lock_guard<std::mutex> lock(fsLayerMutex);
if (!fsLayers.empty()) {
uint32_t startIndex = fsLayers.size();
for (uint32_t i = fsLayers.size(); i > 0; i--) {
if ((uint32_t) fsLayers[i - 1]->getHandle() == errorMask) {
startIndex = i - 1;
realErrorMask = FS_ERROR_FLAG_ALL;
if ((uint32_t) fsLayers[i - 1]->getLayerId() == param->shim->clientHandle) {
startIndex = i - 1;
break;
}
}
@ -152,12 +108,217 @@ FSStatus doForLayer(FSClient *client,
if (!layer->isActive()) {
continue;
}
FSError layerResult = layer_callback(layer);
auto layerResult = FS_ERROR_FORCE_PARENT_LAYER;
auto command = (FSACommandEnum) param->shim->command;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
switch (command) {
case FSA_COMMAND_OPEN_DIR: {
auto *request = &param->shim->request.openDir;
auto fullPath = getFullPath((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());
// Hacky solution:
auto *hackyBuffer = (uint32_t *) &param->shim->response;
auto *handlePtr = (FSDirectoryHandle *) hackyBuffer[1];
layerResult = layer->FSOpenDirWrapper(fullPath.c_str(), handlePtr);
break;
}
case FSA_COMMAND_READ_DIR: {
auto *request = &param->shim->request.readDir;
DEBUG_FUNCTION_LINE_VERBOSE("[%s] ReadDir: %08X", layer->getName().c_str(), request->handle);
// Hacky solution:
auto *hackyBuffer = (uint32_t *) &param->shim->response;
auto *dirEntryPtr = (FSADirectoryEntry *) hackyBuffer[1];
layerResult = layer->FSReadDirWrapper(request->handle, dirEntryPtr);
break;
}
case FSA_COMMAND_CLOSE_DIR: {
auto *request = &param->shim->request.closeDir;
DEBUG_FUNCTION_LINE_VERBOSE("[%s] CloseDir: %08X", layer->getName().c_str(), request->handle);
layerResult = layer->FSCloseDirWrapper(request->handle);
if (layerResult != FS_ERROR_FORCE_REAL_FUNCTION && layerResult != FS_ERROR_FORCE_PARENT_LAYER) {
if (layer->isValidDirHandle(request->handle)) {
layer->deleteDirHandle(request->handle);
} else {
DEBUG_FUNCTION_LINE_ERR("[%s] Expected to delete dirHandle by %08X but it was not found", layer->getName().c_str(), request->handle);
}
}
break;
}
case FSA_COMMAND_REWIND_DIR: {
auto *request = &param->shim->request.rewindDir;
DEBUG_FUNCTION_LINE_VERBOSE("[%s] RewindDir: %08X", layer->getName().c_str(), request->handle);
layerResult = layer->FSRewindDirWrapper(request->handle);
break;
}
case FSA_COMMAND_MAKE_DIR: {
auto *request = &param->shim->request.makeDir;
auto fullPath = getFullPath((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());
layerResult = layer->FSMakeDirWrapper(fullPath.c_str());
break;
}
case FSA_COMMAND_OPEN_FILE: {
auto *request = &param->shim->request.openFile;
auto fullPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->path);
// Hacky solution:
auto *hackyBuffer = (uint32_t *) &param->shim->response;
auto *handlePtr = (FSFileHandle *) hackyBuffer[1];
DEBUG_FUNCTION_LINE_VERBOSE("[%s] OpenFile: path %s (full path: %s) mode %s", layer->getName().c_str(), request->path, fullPath.c_str(), request->mode);
layerResult = layer->FSOpenFileWrapper(fullPath.c_str(), request->mode, handlePtr);
break;
}
case FSA_COMMAND_CLOSE_FILE: {
auto *request = &param->shim->request.closeFile;
DEBUG_FUNCTION_LINE_VERBOSE("[%s] CloseFile: %08X", layer->getName().c_str(), request->handle);
layerResult = layer->FSCloseFileWrapper(request->handle);
if (layerResult != FS_ERROR_FORCE_REAL_FUNCTION && layerResult != FS_ERROR_FORCE_PARENT_LAYER) {
if (layer->isValidFileHandle(request->handle)) {
layer->deleteFileHandle(request->handle);
} else {
DEBUG_FUNCTION_LINE_ERR("[%s] Expected to delete fileHandle by handle %08X but it was not found", layer->getName().c_str(), request->handle);
}
}
break;
}
case FSA_COMMAND_GET_INFO_BY_QUERY: {
auto *request = &param->shim->request.getInfoByQuery;
if (request->type == FSA_QUERY_INFO_STAT) {
auto fullPath = getFullPath((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());
// Hacky solution:
auto *hackyBuffer = (uint32_t *) &param->shim->response;
auto *statPtr = (FSStat *) hackyBuffer[1];
layerResult = layer->FSGetStatWrapper(fullPath.c_str(), statPtr);
}
break;
}
case FSA_COMMAND_STAT_FILE: {
auto *request = &param->shim->request.statFile;
DEBUG_FUNCTION_LINE_VERBOSE("[%s] GetStatFile: %08X", layer->getName().c_str(), request->handle);
// Hacky solution:
auto *hackyBuffer = (uint32_t *) &param->shim->response;
auto *statPtr = (FSStat *) hackyBuffer[1];
layerResult = layer->FSGetStatFileWrapper(request->handle, statPtr);
break;
}
case FSA_COMMAND_READ_FILE: {
auto *request = &param->shim->request.readFile;
if (request->readFlags == FSA_READ_FLAG_NONE) {
DEBUG_FUNCTION_LINE_VERBOSE("[%s] ReadFile: buffer %08X size %08X count %08X handle %08X", layer->getName().c_str(), request->buffer, request->size, request->count, request->handle);
layerResult = layer->FSReadFileWrapper(request->buffer, request->size, request->count, request->handle, 0);
} else if (request->readFlags == FSA_READ_FLAG_READ_WITH_POS) {
DEBUG_FUNCTION_LINE_VERBOSE("[%s] ReadFileWithPos: buffer %08X size %08X count %08X pos %08X handle %08X", layer->getName().c_str(), request->buffer, request->size, request->count, request->pos, request->handle);
layerResult = layer->FSReadFileWithPosWrapper(request->buffer, request->size, request->count, request->pos, request->handle, 0);
}
break;
}
case FSA_COMMAND_SET_POS_FILE: {
auto *request = &param->shim->request.setPosFile;
DEBUG_FUNCTION_LINE_VERBOSE("[%s] SetPosFile: %08X %08X", layer->getName().c_str(), request->handle, request->pos);
layerResult = layer->FSSetPosFileWrapper(request->handle, request->pos);
break;
}
case FSA_COMMAND_GET_POS_FILE: {
auto *request = &param->shim->request.getPosFile;
// Hacky solution:
auto *hackyBuffer = (uint32_t *) &param->shim->response;
auto *posPtr = (FSAFilePosition *) hackyBuffer[1];
DEBUG_FUNCTION_LINE_VERBOSE("[%s] GetPosFile: %08X", layer->getName().c_str(), request->handle);
layerResult = layer->FSGetPosFileWrapper(request->handle, posPtr);
break;
}
case FSA_COMMAND_IS_EOF: {
auto *request = &param->shim->request.isEof;
DEBUG_FUNCTION_LINE_VERBOSE("[%s] IsEof: %08X", layer->getName().c_str(), request->handle);
layerResult = layer->FSIsEofWrapper(request->handle);
break;
}
case FSA_COMMAND_TRUNCATE_FILE: {
auto *request = &param->shim->request.truncateFile;
DEBUG_FUNCTION_LINE_VERBOSE("[%s] TruncateFile: %08X", layer->getName().c_str(), request->handle);
layerResult = layer->FSTruncateFileWrapper(request->handle);
break;
}
case FSA_COMMAND_WRITE_FILE: {
auto *request = &param->shim->request.writeFile;
if (request->writeFlags == FSA_WRITE_FLAG_NONE) {
DEBUG_FUNCTION_LINE_VERBOSE("[%s] WriteFile: buffer %08X size %08X count %08X handle %08X", layer->getName().c_str(), request->buffer, request->size, request->count, request->handle);
layerResult = layer->FSWriteFileWrapper(request->buffer, request->size, request->count, request->handle, 0);
} else if (request->writeFlags == FSA_WRITE_FLAG_READ_WITH_POS) {
DEBUG_FUNCTION_LINE_VERBOSE("[%s] WriteFileWithPos: buffer %08X size %08X count %08X pos %08X handle %08X", layer->getName().c_str(), request->buffer, request->size, request->count, request->pos, request->handle);
layerResult = layer->FSWriteFileWithPosWrapper(request->buffer, request->size, request->count, request->pos, request->handle, 0);
}
break;
}
case FSA_COMMAND_REMOVE: {
auto *request = &param->shim->request.remove;
auto fullPath = getFullPath((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());
layerResult = layer->FSRemoveWrapper(fullPath.c_str());
break;
}
case FSA_COMMAND_RENAME: {
auto *request = &param->shim->request.rename;
auto fullOldPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->oldPath);
auto fullNewPath = getFullPath((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());
layerResult = layer->FSRenameWrapper(fullOldPath.c_str(), fullNewPath.c_str());
break;
}
case FSA_COMMAND_FLUSH_FILE: {
auto *request = &param->shim->request.flushFile;
DEBUG_FUNCTION_LINE_VERBOSE("[%s] FlushFile: %08X", layer->getName().c_str(), request->handle);
layerResult = layer->FSFlushFileWrapper(request->handle);
break;
}
case FSA_COMMAND_CHANGE_DIR: {
auto *request = &param->shim->request.changeDir;
DEBUG_FUNCTION_LINE_VERBOSE("[%s] ChangeDir: %s", layer->getName().c_str(), request->path);
setWorkingDir((FSAClientHandle) param->shim->clientHandle, request->path);
// We still want to call the original function.
layerResult = FS_ERROR_FORCE_PARENT_LAYER;
break;
}
case FSA_COMMAND_GET_CWD: {
DEBUG_FUNCTION_LINE_WARN("FSA_COMMAND_GET_CWD hook not implemented");
break;
}
case FSA_COMMAND_APPEND_FILE: {
auto *request = &param->shim->request.appendFile;
DEBUG_FUNCTION_LINE_WARN("FSA_COMMAND_APPEND_FILE hook not implemented for handle %08X", request->handle);
break;
}
case FSA_COMMAND_FLUSH_MULTI_QUOTA: {
DEBUG_FUNCTION_LINE_WARN("FSA_COMMAND_FLUSH_MULTI_QUOTA hook not implemented");
break;
}
case FSA_COMMAND_OPEN_FILE_BY_STAT: {
DEBUG_FUNCTION_LINE_WARN("FSA_COMMAND_OPEN_FILE_BY_STAT hook not implemented");
break;
}
case FSA_COMMAND_CHANGE_OWNER: {
DEBUG_FUNCTION_LINE_WARN("FSA_COMMAND_CHANGE_OWNER hook not implemented");
break;
}
case FSA_COMMAND_CHANGE_MODE: {
DEBUG_FUNCTION_LINE_WARN("FSA_COMMAND_CHANGE_OWNER hook not implemented");
break;
}
default: {
break;
}
}
#pragma GCC diagnostic pop
if (layerResult != FS_ERROR_FORCE_PARENT_LAYER) {
auto maskedResult = (FSError) ((layerResult & FS_ERROR_REAL_MASK) | FS_ERROR_EXTRA_MASK);
auto result = layerResult >= 0 ? static_cast<FSStatus>(layerResult) : fsaDecodeFsaStatusToFsStatus(maskedResult);
auto result = layerResult >= 0 ? layerResult : maskedResult;
if (result < FS_STATUS_OK && result != FS_STATUS_END && result != FS_STATUS_CANCELLED) {
if (result < FS_ERROR_OK && result != FS_ERROR_END_OF_FILE && result != FS_ERROR_END_OF_DIR && result != FS_ERROR_CANCELLED) {
if (layer->fallbackOnError()) {
// Only fallback if FS_ERROR_FORCE_NO_FALLBACK flag is not set.
if (static_cast<FSError>(layerResult & FS_ERROR_EXTRA_MASK) != FS_ERROR_FORCE_NO_FALLBACK) {
@ -165,78 +326,36 @@ FSStatus doForLayer(FSClient *client,
}
}
}
if (param->sync == FS_SHIM_TYPE_SYNC) {
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Return with result %08X %s", layer->getName().c_str(), result, result <= 0 ? FSAGetStatusStr(result) : "");
return result;
} else if (param->sync == FS_SHIM_TYPE_ASYNC) {
// convert to IOSError
auto err = (IOSError) result;
if (result == FS_ERROR_INVALID_BUFFER) {
err = IOS_ERROR_ACCESS;
} else if (result == FS_ERROR_INVALID_CLIENTHANDLE) {
err = IOS_ERROR_INVALID;
} else if (result == FS_ERROR_BUSY) {
err = IOS_ERROR_QFULL;
}
if (result >= FS_STATUS_OK || result == FS_STATUS_END || result == FS_STATUS_CANCELLED) {
DEBUG_FUNCTION_LINE_VERBOSE("Returned %08X by %s", result, layer->getName().c_str());
return result_handler(layer, result);
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call async callback :) with result %08X %s", layer->getName().c_str(), err, result <= 0 ? FSAGetStatusStr(result) : "");
param->asyncFS.callback(err, &param->asyncFS);
return FS_ERROR_OK;
} else {
// This should never happen.
DEBUG_FUNCTION_LINE_ERR("Unknown sync type.");
OSFatal("ContentRedirectionModule: Unknown sync type.");
}
FSErrorFlag errorFlags = FS_ERROR_FLAG_NONE;
bool forceError = false;
switch ((int32_t) result) {
case FS_STATUS_MAX:
errorFlags = FS_ERROR_FLAG_MAX;
break;
case FS_STATUS_ALREADY_OPEN:
errorFlags = FS_ERROR_FLAG_ALREADY_OPEN;
break;
case FS_STATUS_EXISTS:
errorFlags = FS_ERROR_FLAG_EXISTS;
break;
case FS_STATUS_NOT_FOUND:
errorFlags = FS_ERROR_FLAG_NOT_FOUND;
break;
case FS_STATUS_NOT_FILE:
errorFlags = FS_ERROR_FLAG_NOT_FILE;
break;
case FS_STATUS_NOT_DIR:
errorFlags = FS_ERROR_FLAG_NOT_DIR;
break;
case FS_STATUS_ACCESS_ERROR:
errorFlags = FS_ERROR_FLAG_ACCESS_ERROR;
break;
case FS_STATUS_PERMISSION_ERROR:
errorFlags = FS_ERROR_FLAG_PERMISSION_ERROR;
break;
case FS_STATUS_FILE_TOO_BIG:
errorFlags = FS_ERROR_FLAG_FILE_TOO_BIG;
break;
case FS_STATUS_STORAGE_FULL:
errorFlags = FS_ERROR_FLAG_STORAGE_FULL;
break;
case FS_STATUS_JOURNAL_FULL:
errorFlags = FS_ERROR_FLAG_JOURNAL_FULL;
break;
case FS_STATUS_UNSUPPORTED_CMD:
errorFlags = FS_ERROR_FLAG_UNSUPPORTED_CMD;
break;
case FS_STATUS_MEDIA_NOT_READY:
case FS_STATUS_MEDIA_ERROR:
case FS_STATUS_CORRUPTED:
case FS_STATUS_FATAL_ERROR:
forceError = true;
break;
case FS_STATUS_OK:
break;
}
if (forceError || (realErrorMask != FS_ERROR_FLAG_NONE && (errorFlags & realErrorMask) == 0)) {
DEBUG_FUNCTION_LINE_ERR("Transit to Fatal Error");
auto clientBody = fsClientGetBody(client);
fsClientHandleFatalErrorAndBlock(clientBody, clientBody->lastError);
return FS_STATUS_FATAL_ERROR;
}
DEBUG_FUNCTION_LINE_VERBOSE("%08X Returned %08X by %s ", errorMask, result, layer->getName().c_str());
return result_handler(layer, result);
} else {
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call parent layer / real function", layer->getName().c_str());
}
}
}
}
auto mask = static_cast<FSErrorFlag>((realErrorMask & FS_ERROR_FLAG_REAL_MASK) | FS_ERROR_FLAG_FORCE_REAL);
return real_function(mask);
return FS_ERROR_FORCE_REAL_FUNCTION;
}
FSCmdBlockBody *fsCmdBlockGetBody(FSCmdBlock *cmdBlock) {
@ -258,16 +377,14 @@ FSClientBody *fsClientGetBody(FSClient *client) {
return body;
}
FSStatus send_result_async(FSClient *client, FSCmdBlock *block, FSAsyncData *asyncData, FSStatus status) {
FSStatus handleAsyncResult(FSClient *client, FSCmdBlock *block, FSAsyncData *asyncData, FSStatus status) {
if (asyncData->callback != nullptr) {
if (asyncData->ioMsgQueue != nullptr) {
DEBUG_FUNCTION_LINE_ERR("callback and ioMsgQueue both set.");
return FS_STATUS_FATAL_ERROR;
OSFatal("ContentRedirectionModule: callback and ioMsgQueue both set.");
}
// userCallbacks are called in the DefaultAppIOQueue.
asyncData->ioMsgQueue = OSGetDefaultAppIOQueue();
//DEBUG_FUNCTION_LINE("Force to OSGetDefaultAppIOQueue (%08X)", asyncData->ioMsgQueue);
}
if (asyncData->ioMsgQueue != nullptr) {
@ -284,6 +401,7 @@ FSStatus send_result_async(FSClient *client, FSCmdBlock *block, FSAsyncData *asy
result->block = block;
result->status = status;
OSMemoryBarrier();
while (!OSSendMessage(asyncData->ioMsgQueue, (OSMessage *) &(result->ioMsg), OS_MESSAGE_FLAGS_NONE)) {
DEBUG_FUNCTION_LINE_ERR("Failed to send message");
}
@ -302,6 +420,7 @@ int64_t readIntoBuffer(int32_t handle, void *buffer, size_t size, size_t count)
int32_t curResult;
int64_t totalSize = 0;
while (sizeToRead > 0) {
curResult = read(handle, newBuffer, sizeToRead);
if (curResult < 0) {
DEBUG_FUNCTION_LINE_ERR("Reading %08X bytes from handle %08X failed. result %08X errno: %d ", size * count, handle, curResult, errno);
@ -317,9 +436,9 @@ int64_t readIntoBuffer(int32_t handle, void *buffer, size_t size, size_t count)
return totalSize;
}
int64_t writeFromBuffer(int32_t handle, void *buffer, size_t size, size_t count) {
int64_t writeFromBuffer(int32_t handle, const void *buffer, size_t size, size_t count) {
auto sizeToWrite = size * count;
void *ptr = buffer;
auto *ptr = buffer;
int32_t curResult;
int64_t totalSize = 0;
while (sizeToWrite > 0) {
@ -336,4 +455,130 @@ int64_t writeFromBuffer(int32_t handle, void *buffer, size_t size, size_t count)
sizeToWrite -= curResult;
}
return totalSize;
}
FSIOThreadData gThreadData[3];
bool gThreadsRunning = false;
static int32_t fsIOthreadCallback([[maybe_unused]] int argc, const char **argv) {
auto *magic = ((FSIOThreadData *) argv);
DEBUG_FUNCTION_LINE_VERBOSE("Hello from IO Thread for core: %d", OSGetCoreId());
constexpr int32_t messageSize = sizeof(magic->messages) / sizeof(magic->messages[0]);
OSInitMessageQueue(&magic->queue, magic->messages, messageSize);
OSMessage recv;
while (OSReceiveMessage(&magic->queue, &recv, OS_MESSAGE_FLAGS_BLOCKING)) {
if (recv.args[0] == FS_IO_QUEUE_COMMAND_STOP) {
DEBUG_FUNCTION_LINE_VERBOSE("Received break command! Stop thread");
break;
} else if (recv.args[0] == FS_IO_QUEUE_COMMAND_PROCESS_FS_COMMAND) {
auto *message = (FSShimWrapperMessage *) recv.message;
auto *param = (FSShimWrapper *) message->param;
FSError res = FS_ERROR_MEDIA_ERROR;
auto syncType = param->sync;
if (param->api == FS_SHIM_API_FS) {
res = processShimBufferForFS(param);
} else if (param->api == FS_SHIM_API_FSA) {
res = processShimBufferForFSA(param);
} else {
DEBUG_FUNCTION_LINE_ERR("Incompatible API type %d", param->api);
OSFatal("ContentRedirectionModule: Incompatible API type");
}
// param is free'd at this point!!!
if (syncType == FS_SHIM_TYPE_SYNC) {
// For sync messages we can't (and don't need to) free "message", because it contains the queue we're about to use.
// But this is not a problem because it's sync anyway.
OSMessage send;
send.args[0] = FS_IO_QUEUE_SYNC_RESULT;
send.args[1] = (uint32_t) res;
if (!OSSendMessage(&message->messageQueue, &send, OS_MESSAGE_FLAGS_NONE)) {
DEBUG_FUNCTION_LINE_ERR("Failed to send message");
OSFatal("ContentRedirectionModule: Failed to send message");
}
} else if (syncType == FS_SHIM_TYPE_ASYNC) {
// If it's async we need to clean up "message" :)
free(message);
}
}
}
return 0;
}
void startFSIOThreads() {
int32_t threadAttributes[] = {OS_THREAD_ATTRIB_AFFINITY_CPU0, OS_THREAD_ATTRIB_AFFINITY_CPU1, OS_THREAD_ATTRIB_AFFINITY_CPU2};
auto stackSize = 16 * 1024;
int coreId = 0;
for (int core : threadAttributes) {
auto *threadData = &gThreadData[coreId];
memset(threadData, 0, sizeof(*threadData));
threadData->setup = false;
threadData->thread = (OSThread *) memalign(8, sizeof(OSThread));
if (!threadData->thread) {
DEBUG_FUNCTION_LINE_ERR("Failed to allocate threadData");
OSFatal("ContentRedirectionModule: Failed to allocate IO Thread");
continue;
}
threadData->stack = (uint8_t *) memalign(0x20, stackSize);
if (!threadData->thread) {
free(threadData->thread);
DEBUG_FUNCTION_LINE_ERR("Failed to allocate threadData stack");
OSFatal("ContentRedirectionModule: Failed to allocate IO Thread stack");
continue;
}
OSMemoryBarrier();
if (!OSCreateThread(threadData->thread, &fsIOthreadCallback, 1, (char *) threadData, reinterpret_cast<void *>((uint32_t) threadData->stack + stackSize), stackSize, 0, core)) {
free(threadData->thread);
free(threadData->stack);
threadData->setup = false;
DEBUG_FUNCTION_LINE_ERR("failed to create threadData");
OSFatal("ContentRedirectionModule: Failed to create threadData");
}
strncpy(threadData->threadName, string_format("ContentRedirection IO Thread %d", coreId).c_str(), sizeof(threadData->threadName) - 1);
OSSetThreadName(threadData->thread, threadData->threadName);
OSResumeThread(threadData->thread);
threadData->setup = true;
coreId++;
}
gThreadsRunning = true;
OSMemoryBarrier();
}
void stopFSIOThreads() {
if (!gThreadsRunning) {
return;
}
for (auto &gThread : gThreadData) {
auto *thread = &gThread;
if (!thread->setup) {
continue;
}
OSMessage message;
message.args[0] = FS_IO_QUEUE_COMMAND_STOP;
OSSendMessage(&thread->queue, &message, OS_MESSAGE_FLAGS_NONE);
if (OSIsThreadSuspended(thread->thread)) {
OSResumeThread(thread->thread);
}
OSJoinThread(thread->thread, nullptr);
if (thread->stack) {
free(thread->stack);
thread->stack = nullptr;
}
if (thread->thread) {
free(thread->thread);
thread->thread = nullptr;
}
}
gThreadsRunning = false;
}

View File

@ -1,6 +1,8 @@
#pragma once
#include "IFSWrapper.h"
#include "utils/logger.h"
#include <coreinit/core.h>
#include <coreinit/filesystem.h>
#include <coreinit/filesystem_fsa.h>
#include <functional>
@ -8,66 +10,102 @@
#include <romfs_dev.h>
#include <string>
struct FSIOThreadData {
OSThread *thread;
void *stack;
OSMessageQueue queue;
OSMessage messages[0x10];
bool setup;
char threadName[0x50];
};
struct AsyncParamFS {
FSClient *client;
FSCmdBlock *block;
FSErrorFlag errorMask;
FSAsyncData asyncData;
IOSAsyncCallbackFn callback;
};
typedef enum FSShimSyncType {
FS_SHIM_TYPE_SYNC = 1,
FS_SHIM_TYPE_ASYNC = 2
} FSShimSyncType;
typedef enum FSShimApiType {
FS_SHIM_API_FS = 1,
FS_SHIM_API_FSA = 2
} FSShimApiType;
struct FSShimWrapper {
FSAShimBuffer *shim;
AsyncParamFS asyncFS;
FSShimSyncType sync;
FSShimApiType api;
};
struct FSShimWrapperMessage {
FSShimWrapper *param;
OSMessageQueue messageQueue;
OSMessage messages[0x1];
};
#define FS_IO_QUEUE_COMMAND_STOP 0x13371337
#define FS_IO_QUEUE_COMMAND_PROCESS_FS_COMMAND 0x42424242
#define FS_IO_QUEUE_SYNC_RESULT 0x43434343
extern bool gThreadsRunning;
extern FSIOThreadData gThreadData[3];
extern std::mutex fsLayerMutex;
extern std::vector<std::unique_ptr<IFSWrapper>> fsLayers;
#define SYNC_RESULT_HANDLER [filename = __FILENAME__, func = __FUNCTION__, line = __LINE__]([[maybe_unused]] std::unique_ptr<IFSWrapper> &layer, FSStatus res) -> FSStatus { \
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Sync result was %d", res); \
return res; \
}
#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 fsaShimPrepareRequestOpenFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *path, const char *mode, FSMode createMode, FSOpenFileFlags openFlag, uint32_t preallocSize))(0x101C400 + 0x43588))
#define fsaShimPrepareRequestCloseFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSFileHandle handle))(0x101C400 + 0x43a00))
#define fsaShimPrepareRequestStatFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSFileHandle handle))(0x101C400 + 0x43998))
#define fsaShimPrepareRequestQueryInfo ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *path, FSAQueryInfoType type))(0x101C400 + 0x44118))
#define fsaShimPrepareRequestSetPos ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSFileHandle handle, FSAFilePosition position))(0x101C400 + 0x43930))
#define fsaShimPrepareRequestGetPos ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSFileHandle handle))(0x101C400 + 0x438fc))
#define fsaShimPrepareRequestIsEof ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSFileHandle handle))(0x101C400 + 0x43964))
#define fsaShimPrepareRequestTruncate ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSFileHandle handle))(0x101C400 + 0x43a34))
#define fsaShimPrepareRequestRemove ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *))(0x101C400 + 0x43aa8))
#define fsaShimPrepareRequestRename ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *, const char *))(0x101C400 + 0x43bc0))
#define fsaShimPrepareRequestFlushFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSFileHandle handle))(0x101C400 + 0x439cc))
#define fsaShimPrepareRequestChangeMode ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *path, FSMode mode, FSMode modeMask))(0x101C400 + 0x43ff4))
#define ASYNC_RESULT_HANDLER [c = client, b = block, a = asyncData, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__]([[maybe_unused]] std::unique_ptr<IFSWrapper> &layer, FSStatus res) -> FSStatus { \
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Async result was %d", res); \
return send_result_async(c, b, a, res); \
}
#define fsaShimPrepareRequestOpenDir ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *path))(0x101C400 + 0x43458))
#define fsaShimPrepareRequestReadDir ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSDirectoryHandle handle))(0x101C400 + 0x434ec))
#define fsaShimPrepareRequestCloseDir ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSDirectoryHandle handle))(0x101C400 + 0x43554))
#define fsaShimPrepareRequestRewindDir ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSDirectoryHandle handle))(0x101C400 + 0x43520))
#define fsaShimPrepareRequestMakeDir ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *path, FSMode mode))(0x101C400 + 0x43314))
#define fsaShimPrepareRequestChangeDir ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *path))(0x101C400 + 0x43258))
#define SYNC_RESULT_HANDLER_FSA [filename = __FILENAME__, func = __FUNCTION__, line = __LINE__]([[maybe_unused]] std::unique_ptr<IFSWrapper> &layer, FSError res) -> FSError { \
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Sync result was %d", res); \
return res; \
}
#define fsaDecodeFsaStatusToFsStatus ((FSStatus(*)(FSError))(0x101C400 + 0x4b148))
#define fsClientHandleFatalError ((void (*)(FSClientBody *, uint32_t))(0x101C400 + 0x4b34c))
#define fsClientHandleFatalErrorAndBlock ((void (*)(FSClientBody *, uint32_t))(0x101C400 + 0x4cc20))
#define FS_ERROR_FLAG_EXTRA_MASK (FSErrorFlag) 0xFFFF0000
#define FS_ERROR_FLAG_REAL_MASK (FSErrorFlag) 0x0000FFFF
#define FS_ERROR_FLAG_FORCE_REAL (FSErrorFlag) 0xFEDC0000
extern "C" FSError __FSAShimDecodeIosErrorToFsaStatus(IOSHandle handle, IOSError err);
static inline FSErrorFlag getRealErrorFlag(FSErrorFlag flag) {
auto res = flag & FS_ERROR_FLAG_REAL_MASK;
if (res == 0x0000FFFF) {
return FS_ERROR_FLAG_ALL;
}
return static_cast<FSErrorFlag>(res);
}
static inline FSErrorFlag isForceRealFunction(FSErrorFlag flag) {
return static_cast<FSErrorFlag>((flag & FS_ERROR_FLAG_EXTRA_MASK) == FS_ERROR_FLAG_FORCE_REAL);
}
bool sendMessageToThread(FSShimWrapperMessage *param);
void clearFSLayer();
std::string getFullPathForFSClient(FSClient *pClient, const char *path);
FSError doForLayer(FSShimWrapper *param);
void setWorkingDirForFSClient(FSClient *client, const char *path);
FSError processShimBufferForFS(FSShimWrapper *param);
std::string getFullPathForFSAClient(FSAClientHandle client, const char *path);
void setWorkingDirForFSAClient(FSAClientHandle client, const char *path);
FSError doForLayerFSA(const std::function<FSError()> &real_function,
const std::function<FSError(std::unique_ptr<IFSWrapper> &layer)> &layer_callback,
const std::function<FSError(std::unique_ptr<IFSWrapper> &layer, FSError)> &result_handler);
FSStatus doForLayer(FSClient *client,
FSErrorFlag errorMask,
const std::function<FSStatus(FSErrorFlag errorMask)> &real_function,
const std::function<FSError(std::unique_ptr<IFSWrapper> &layer)> &layer_callback,
const std::function<FSStatus(std::unique_ptr<IFSWrapper> &layer, FSStatus)> &result_handler);
FSError processShimBufferForFSA(FSShimWrapper *param);
FSCmdBlockBody *fsCmdBlockGetBody(FSCmdBlock *cmdBlock);
FSClientBody *fsClientGetBody(FSClient *client);
FSStatus send_result_async(FSClient *client, FSCmdBlock *block, FSAsyncData *asyncData, FSStatus result);
FSStatus handleAsyncResult(FSClient *client, FSCmdBlock *block, FSAsyncData *asyncData, FSStatus status);
int64_t readIntoBuffer(int32_t handle, void *buffer, size_t size, size_t count);
int64_t writeFromBuffer(int32_t handle, void *buffer, size_t size, size_t count);
int64_t writeFromBuffer(int32_t handle, const void *buffer, size_t size, size_t count);
void startFSIOThreads();
void stopFSIOThreads();

View File

@ -1,12 +1,13 @@
#pragma once
#include <coreinit/filesystem.h>
#include <coreinit/filesystem_fsa.h>
#include <functional>
#include <string>
#define FS_ERROR_EXTRA_MASK 0xFFF00000
#define FS_ERROR_REAL_MASK 0x000FFFFF
#define FS_ERROR_FORCE_PARENT_LAYER (FSError) 0xFFE0000
#define FS_ERROR_FORCE_NO_FALLBACK (FSError) 0xFFD0000
#define FS_ERROR_EXTRA_MASK 0xFFF00000
#define FS_ERROR_REAL_MASK 0x000FFFFF
#define FS_ERROR_FORCE_PARENT_LAYER (FSError) 0xFFE00000
#define FS_ERROR_FORCE_NO_FALLBACK (FSError) 0xFFD00000
#define FS_ERROR_FORCE_REAL_FUNCTION (FSError) 0xFFC00000
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
@ -15,21 +16,21 @@ class IFSWrapper {
public:
virtual ~IFSWrapper() = default;
virtual FSError FSOpenDirWrapper(const char *path,
FSDirectoryHandle *handle) {
FSADirectoryHandle *handle) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSReadDirWrapper(FSDirectoryHandle handle,
FSDirectoryEntry *entry) {
virtual FSError FSReadDirWrapper(FSADirectoryHandle handle,
FSADirectoryEntry *entry) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSCloseDirWrapper(FSDirectoryHandle handle) {
virtual FSError FSCloseDirWrapper(FSADirectoryHandle handle) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSRewindDirWrapper(FSDirectoryHandle handle) {
virtual FSError FSRewindDirWrapper(FSADirectoryHandle handle) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
@ -39,29 +40,29 @@ public:
virtual FSError FSOpenFileWrapper(const char *path,
const char *mode,
FSFileHandle *handle) {
FSAFileHandle *handle) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSCloseFileWrapper(FSFileHandle handle) {
virtual FSError FSCloseFileWrapper(FSAFileHandle handle) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSGetStatWrapper(const char *path,
FSStat *stats) {
FSAStat *stats) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSGetStatFileWrapper(FSFileHandle handle,
FSStat *stats) {
virtual FSError FSGetStatFileWrapper(FSAFileHandle handle,
FSAStat *stats) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSReadFileWrapper(void *buffer,
uint32_t size,
uint32_t count,
FSFileHandle handle,
FSAFileHandle handle,
uint32_t unk1) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
@ -70,37 +71,46 @@ public:
uint32_t size,
uint32_t count,
uint32_t pos,
FSFileHandle handle,
FSAFileHandle handle,
int32_t unk1) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSSetPosFileWrapper(FSFileHandle handle,
virtual FSError FSSetPosFileWrapper(FSAFileHandle handle,
uint32_t pos) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSGetPosFileWrapper(FSFileHandle handle,
virtual FSError FSGetPosFileWrapper(FSAFileHandle handle,
uint32_t *pos) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSIsEofWrapper(FSFileHandle handle) {
virtual FSError FSIsEofWrapper(FSAFileHandle handle) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSTruncateFileWrapper(FSFileHandle handle) {
virtual FSError FSTruncateFileWrapper(FSAFileHandle handle) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSWriteFileWrapper(uint8_t *buffer,
virtual FSError FSWriteFileWrapper(const uint8_t *buffer,
uint32_t size,
uint32_t count,
FSFileHandle handle,
FSAFileHandle handle,
uint32_t unk1) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSWriteFileWithPosWrapper(const uint8_t *buffer,
uint32_t size,
uint32_t count,
FSAFilePosition pos,
FSAFileHandle handle,
uint32_t unk1) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSRemoveWrapper(const char *path) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
@ -110,7 +120,7 @@ public:
return FS_ERROR_FORCE_PARENT_LAYER;
}
virtual FSError FSFlushFileWrapper(FSFileHandle handle) {
virtual FSError FSFlushFileWrapper(FSAFileHandle handle) {
return FS_ERROR_FORCE_PARENT_LAYER;
}
@ -130,15 +140,17 @@ public:
return pName;
}
virtual bool isValidDirHandle(FSDirectoryHandle handle) = 0;
virtual bool isValidDirHandle(FSADirectoryHandle handle) = 0;
virtual bool isValidFileHandle(FSFileHandle handle) = 0;
virtual bool isValidFileHandle(FSAFileHandle handle) = 0;
virtual void deleteDirHandle(FSDirectoryHandle handle) = 0;
virtual void deleteDirHandle(FSADirectoryHandle handle) = 0;
virtual void deleteFileHandle(FSFileHandle handle) = 0;
virtual void deleteFileHandle(FSAFileHandle handle) = 0;
uint32_t getHandle() {
virtual uint32_t getLayerId() = 0;
virtual uint32_t getHandle() {
return (uint32_t) this;
}

View File

@ -10,7 +10,7 @@
ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *layerName, const char *replacementDir, FSLayerType layerType) {
if (!handle || layerName == nullptr || replacementDir == nullptr) {
DEBUG_FUNCTION_LINE_ERR("CONTENT_REDIRECTION_API_ERROR_INVALID_ARG");
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_INVALID_ARG");
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
}
std::unique_ptr<IFSWrapper> ptr;
@ -37,7 +37,7 @@ ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *l
ContentRedirectionApiErrorType CRRemoveFSLayer(CRLayerHandle handle) {
if (remove_locked_first_if(fsLayerMutex, fsLayers, [handle](auto &cur) { return (CRLayerHandle) cur->getHandle() == handle; })) {
DEBUG_FUNCTION_LINE_ERR("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle);
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;
@ -52,13 +52,12 @@ ContentRedirectionApiErrorType CRSetActive(CRLayerHandle handle, bool active) {
}
}
DEBUG_FUNCTION_LINE_ERR("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle);
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) {
if (outVersion == nullptr) {
DEBUG_FUNCTION_LINE_ERR("CONTENT_REDIRECTION_API_ERROR_INVALID_ARG");
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
}
*outVersion = 1;

View File

@ -1,9 +1,11 @@
#include "FSADirReplacements.h"
#include "FSAFileReplacements.h"
#include "FSDirReplacements.h"
#include "FSFileReplacements.h"
#include "FSAReplacements.h"
#include "FSReplacements.h"
#include "FileUtils.h"
#include "utils/StringTools.h"
#include "utils/logger.h"
#include <coreinit/cache.h>
#include <coreinit/core.h>
#include <malloc.h>
#include <wums.h>
WUMS_MODULE_EXPORT_NAME("homebrew_content_redirection");
@ -22,25 +24,21 @@ WUMS_INITIALIZE() {
OSFatal("homebrew_content_redirection: Failed to patch function");
}
}
for (uint32_t i = 0; i < fs_dir_function_replacements_size; i++) {
if (!FunctionPatcherPatchFunction(&fs_dir_function_replacements[i], nullptr)) {
OSFatal("homebrew_content_redirection: Failed to patch function");
}
}
for (uint32_t i = 0; i < fsa_dir_function_replacements_size; i++) {
if (!FunctionPatcherPatchFunction(&fsa_dir_function_replacements[i], nullptr)) {
OSFatal("homebrew_content_redirection: Failed to patch function");
}
}
DEBUG_FUNCTION_LINE("Patch functions finished");
deinitLogging();
}
WUMS_APPLICATION_STARTS() {
initLogging();
startFSIOThreads();
}
WUMS_APPLICATION_ENDS() {
clearFSLayer();
stopFSIOThreads();
deinitLogging();
}