diff --git a/Dockerfile b/Dockerfile index e9544b1..7f7d391 100644 --- a/Dockerfile +++ b/Dockerfile @@ -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 diff --git a/Makefile b/Makefile index 605106c..ab332ce 100644 --- a/Makefile +++ b/Makefile @@ -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 #------------------------------------------------------------------------------- diff --git a/src/DirInfoEx.h b/src/DirInfoEx.h index cb5d385..b5884cd 100644 --- a/src/DirInfoEx.h +++ b/src/DirInfoEx.h @@ -1,9 +1,9 @@ #pragma once #include "DirInfo.h" -#include +#include typedef struct FSDirectoryEntryEx { - FSDirectoryEntry realEntry{}; + FSADirectoryEntry realEntry{}; bool isMarkedAsDeleted = false; } FSDirectoryEntryEx; diff --git a/src/FSADirReplacements.cpp b/src/FSADirReplacements.cpp deleted file mode 100644 index dea7038..0000000 --- a/src/FSADirReplacements.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "FSDirReplacements.h" -#include "FileUtils.h" -#include "IFSWrapper.h" -#include "utils/logger.h" -#include -#include - -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 &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 &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 &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 &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 &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); diff --git a/src/FSADirReplacements.h b/src/FSADirReplacements.h deleted file mode 100644 index c45b93d..0000000 --- a/src/FSADirReplacements.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "IFSWrapper.h" -#include -#include -#include -#include - -extern function_replacement_data_t fsa_dir_function_replacements[]; -extern uint32_t fsa_dir_function_replacements_size; diff --git a/src/FSAFileReplacements.cpp b/src/FSAFileReplacements.cpp deleted file mode 100644 index 760b70c..0000000 --- a/src/FSAFileReplacements.cpp +++ /dev/null @@ -1,238 +0,0 @@ -#include "FSFileReplacements.h" -#include "FileUtils.h" -#include "utils/logger.h" -#include - -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 &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 &layer) -> FSError { - // FSAFileHandle is just an alias for FSFileHandle - return layer->FSCloseFileWrapper(h); - }, - [h = fileHandle, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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); \ No newline at end of file diff --git a/src/FSAReplacements.cpp b/src/FSAReplacements.cpp new file mode 100644 index 0000000..fd4afc9 --- /dev/null +++ b/src/FSAReplacements.cpp @@ -0,0 +1,731 @@ +#include "FSAReplacements.h" +#include "FileUtils.h" +#include "utils/logger.h" +#include +#include + +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(0x660), static_cast(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(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(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(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(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; +} \ No newline at end of file diff --git a/src/FSAFileReplacements.h b/src/FSAReplacements.h similarity index 100% rename from src/FSAFileReplacements.h rename to src/FSAReplacements.h diff --git a/src/FSDirReplacements.cpp b/src/FSDirReplacements.cpp deleted file mode 100644 index 329a311..0000000 --- a/src/FSDirReplacements.cpp +++ /dev/null @@ -1,219 +0,0 @@ -#include "FSDirReplacements.h" -#include "FileUtils.h" -#include "IFSWrapper.h" -#include "utils/logger.h" -#include -#include - -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 &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 &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 &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 &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 &layer) -> FSError { - return layer->FSCloseDirWrapper(h); - }, - [h = handle, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr &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 &layer) -> FSError { - return layer->FSCloseDirWrapper(h); - }, - [c = client, b = block, h = handle, a = asyncData, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr &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 &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 &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 &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 &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); diff --git a/src/FSDirReplacements.h b/src/FSDirReplacements.h deleted file mode 100644 index 7f7902a..0000000 --- a/src/FSDirReplacements.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "IFSWrapper.h" -#include -#include -#include -#include - -extern function_replacement_data_t fs_dir_function_replacements[]; -extern uint32_t fs_dir_function_replacements_size; diff --git a/src/FSFileReplacements.cpp b/src/FSFileReplacements.cpp deleted file mode 100644 index 28fd607..0000000 --- a/src/FSFileReplacements.cpp +++ /dev/null @@ -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 &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 &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 &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 &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 &layer) -> FSError { - return layer->FSCloseFileWrapper(h); - }, - [h = handle, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr &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 &layer) -> FSError { - return layer->FSCloseFileWrapper(h); - }, - [c = client, b = block, h = handle, a = asyncData, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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 &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); \ No newline at end of file diff --git a/src/FSReplacements.cpp b/src/FSReplacements.cpp new file mode 100644 index 0000000..7bb5f20 --- /dev/null +++ b/src/FSReplacements.cpp @@ -0,0 +1,810 @@ +#include "FSReplacements.h" +#include "FileUtils.h" +#include "utils/StringTools.h" +#include "utils/logger.h" +#include + +FSStatus processFSError(FSError fsError, FSClient *client, FSErrorFlag errorMask) { + auto result = fsError >= 0 ? static_cast(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 = ¶m->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(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 = ¶m->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, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_WRITE_FILE: { + auto *request = ¶m->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, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_OPEN_FILE: { + auto *request = ¶m->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 *) ¶m->shim->response; + auto *handlePtr = (FSFileHandle *) hackyBuffer[1]; + fsResult = real_FSOpenFileExAsync(param->asyncFS.client, param->asyncFS.block, request->path, request->mode, static_cast(request->unk0x290), static_cast(request->unk0x294), request->unk0x298, handlePtr, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_CLOSE_FILE: { + auto *request = ¶m->shim->request.closeFile; + fsResult = real_FSCloseFileAsync(param->asyncFS.client, param->asyncFS.block, request->handle, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_SET_POS_FILE: { + auto *request = ¶m->shim->request.setPosFile; + fsResult = real_FSSetPosFileAsync(param->asyncFS.client, param->asyncFS.block, request->handle, request->pos, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_GET_POS_FILE: { + auto *request = ¶m->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 *) ¶m->shim->response; + auto *posPtr = (FSAFilePosition *) hackyBuffer[1]; + fsResult = real_FSGetPosFileAsync(param->asyncFS.client, param->asyncFS.block, request->handle, posPtr, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_STAT_FILE: { + auto *request = ¶m->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 *) ¶m->shim->response; + auto *statPtr = (FSStat *) hackyBuffer[1]; + fsResult = real_FSGetStatFileAsync(param->asyncFS.client, param->asyncFS.block, request->handle, statPtr, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_GET_INFO_BY_QUERY: { + auto *request = ¶m->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 *) ¶m->shim->response; + auto *statPtr = (FSStat *) hackyBuffer[1]; + fsResult = real_FSGetStatAsync(param->asyncFS.client, param->asyncFS.block, request->path, statPtr, param->asyncFS.errorMask, ¶m->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, ¶m->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 = ¶m->shim->request.isEof; + fsResult = real_FSIsEofAsync(param->asyncFS.client, param->asyncFS.block, request->handle, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_TRUNCATE_FILE: { + auto *request = ¶m->shim->request.truncateFile; + fsResult = real_FSTruncateFileAsync(param->asyncFS.client, param->asyncFS.block, request->handle, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_REMOVE: { + auto *request = ¶m->shim->request.remove; + fsResult = real_FSRemoveAsync(param->asyncFS.client, param->asyncFS.block, request->path, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_RENAME: { + auto *request = ¶m->shim->request.rename; + fsResult = real_FSRenameAsync(param->asyncFS.client, param->asyncFS.block, request->oldPath, request->newPath, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_FLUSH_FILE: { + auto *request = ¶m->shim->request.flushFile; + fsResult = real_FSFlushFileAsync(param->asyncFS.client, param->asyncFS.block, request->handle, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_CHANGE_MODE: { + auto *request = ¶m->shim->request.changeMode; + fsResult = real_FSChangeModeAsync(param->asyncFS.client, param->asyncFS.block, request->path, (FSMode) request->mode1, (FSMode) request->mode2, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_OPEN_DIR: { + auto *request = ¶m->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 *) ¶m->shim->response; + auto *handlePtr = (FSDirectoryHandle *) hackyBuffer[1]; + fsResult = real_FSOpenDirAsync(param->asyncFS.client, param->asyncFS.block, request->path, handlePtr, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_READ_DIR: { + auto *request = ¶m->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 *) ¶m->shim->response; + auto *entryPtr = (FSDirectoryEntry *) hackyBuffer[1]; + fsResult = real_FSReadDirAsync(param->asyncFS.client, param->asyncFS.block, request->handle, entryPtr, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_CLOSE_DIR: { + auto *request = ¶m->shim->request.closeDir; + fsResult = real_FSCloseDirAsync(param->asyncFS.client, param->asyncFS.block, request->handle, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_REWIND_DIR: { + auto *request = ¶m->shim->request.rewindDir; + fsResult = real_FSRewindDirAsync(param->asyncFS.client, param->asyncFS.block, request->handle, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_MAKE_DIR: { + auto *request = ¶m->shim->request.makeDir; + fsResult = real_FSMakeDirAsync(param->asyncFS.client, param->asyncFS.block, request->path, param->asyncFS.errorMask, ¶m->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, ¶m->asyncFS.asyncData, FS_STATUS_MEDIA_ERROR); + } + break; + } + case FSA_COMMAND_CHANGE_DIR: { + auto *request = ¶m->shim->request.changeDir; + fsResult = real_FSChangeDirAsync(param->asyncFS.client, param->asyncFS.block, request->path, param->asyncFS.errorMask, ¶m->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, ¶m->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; +} \ No newline at end of file diff --git a/src/FSFileReplacements.h b/src/FSReplacements.h similarity index 100% rename from src/FSFileReplacements.h rename to src/FSReplacements.h diff --git a/src/FSWrapper.cpp b/src/FSWrapper.cpp index 1b3b02b..43ade4e 100644 --- a/src/FSWrapper.cpp +++ b/src/FSWrapper.cpp @@ -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 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 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; } diff --git a/src/FSWrapper.h b/src/FSWrapper.h index 1e617a4..b9a2eb6 100644 --- a/src/FSWrapper.h +++ b/src/FSWrapper.h @@ -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); diff --git a/src/FSWrapperMergeDirsWithParent.cpp b/src/FSWrapperMergeDirsWithParent.cpp index 628200c..d206b06 100644 --- a/src/FSWrapperMergeDirsWithParent.cpp +++ b/src/FSWrapperMergeDirsWithParent.cpp @@ -7,7 +7,7 @@ #include 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(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 FSWrapperMergeDirsWithParent::getDirExFromHandle(FSDirectoryHandle handle) { +std::shared_ptr FSWrapperMergeDirsWithParent::getDirExFromHandle(FSADirectoryHandle handle) { auto dir = std::dynamic_pointer_cast(getDirFromHandle(handle)); if (!dir) { DEBUG_FUNCTION_LINE_ERR("[%s] dynamic_pointer_cast(%08X) failed", getName().c_str(), handle); - OSFatal("dynamic_pointer_cast failed"); + OSFatal("ContentRedirectionModule: dynamic_pointer_cast failed"); } return dir; } diff --git a/src/FSWrapperMergeDirsWithParent.h b/src/FSWrapperMergeDirsWithParent.h index ff475a2..24a56f1 100644 --- a/src/FSWrapperMergeDirsWithParent.h +++ b/src/FSWrapperMergeDirsWithParent.h @@ -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 getDirExFromHandle(FSDirectoryHandle handle); }; diff --git a/src/FileUtils.cpp b/src/FileUtils.cpp index 79238dd..e39dc18 100644 --- a/src/FileUtils.cpp +++ b/src/FileUtils.cpp @@ -6,19 +6,17 @@ #include "utils/utils.h" #include #include +#include #include #include -std::mutex workingDirMutexFS; -std::map workingDirsFS; - -std::mutex workingDirMutexFSA; -std::map workingDirsFSA; +std::mutex workingDirMutex; +std::map workingDirs; std::mutex fsLayerMutex; std::vector> fsLayers; -std::string getFullPathGeneric(uint32_t client, const char *path, std::mutex &mutex, std::map &map) { +std::string getFullPathGeneric(FSAClientHandle client, const char *path, std::mutex &mutex, std::map &map) { std::lock_guard 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 &map) { +void setWorkingDirGeneric(FSAClientHandle client, const char *path, std::mutex &mutex, std::map &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 workingDirLock(workingDirMutexFS); - workingDirsFS.clear(); - } - { - std::lock_guard workingDirLock(workingDirMutexFSA); - workingDirsFSA.clear(); + std::lock_guard workingDirLock(workingDirMutex); + workingDirs.clear(); } { std::lock_guard layerLock(fsLayerMutex); @@ -86,62 +72,32 @@ void clearFSLayer() { } } - -FSError doForLayerFSA(const std::function &real_function, - const std::function &layer)> &layer_callback, - const std::function &layer, FSError)> &result_handler) { - - - std::lock_guard 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(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 &real_function, - const std::function &layer)> &layer_callback, - const std::function &layer, FSStatus)> &result_handler) { - FSErrorFlag realErrorMask = errorMask; - +FSError doForLayer(FSShimWrapper *param) { std::lock_guard 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 = ¶m->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 *) ¶m->shim->response; + auto *handlePtr = (FSDirectoryHandle *) hackyBuffer[1]; + layerResult = layer->FSOpenDirWrapper(fullPath.c_str(), handlePtr); + break; + } + case FSA_COMMAND_READ_DIR: { + auto *request = ¶m->shim->request.readDir; + DEBUG_FUNCTION_LINE_VERBOSE("[%s] ReadDir: %08X", layer->getName().c_str(), request->handle); + // Hacky solution: + auto *hackyBuffer = (uint32_t *) ¶m->shim->response; + auto *dirEntryPtr = (FSADirectoryEntry *) hackyBuffer[1]; + layerResult = layer->FSReadDirWrapper(request->handle, dirEntryPtr); + break; + } + case FSA_COMMAND_CLOSE_DIR: { + auto *request = ¶m->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 = ¶m->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 = ¶m->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 = ¶m->shim->request.openFile; + auto fullPath = getFullPath((FSAClientHandle) param->shim->clientHandle, request->path); + // Hacky solution: + auto *hackyBuffer = (uint32_t *) ¶m->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 = ¶m->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 = ¶m->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 *) ¶m->shim->response; + auto *statPtr = (FSStat *) hackyBuffer[1]; + layerResult = layer->FSGetStatWrapper(fullPath.c_str(), statPtr); + } + break; + } + case FSA_COMMAND_STAT_FILE: { + auto *request = ¶m->shim->request.statFile; + DEBUG_FUNCTION_LINE_VERBOSE("[%s] GetStatFile: %08X", layer->getName().c_str(), request->handle); + // Hacky solution: + auto *hackyBuffer = (uint32_t *) ¶m->shim->response; + auto *statPtr = (FSStat *) hackyBuffer[1]; + layerResult = layer->FSGetStatFileWrapper(request->handle, statPtr); + break; + } + case FSA_COMMAND_READ_FILE: { + + auto *request = ¶m->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 = ¶m->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 = ¶m->shim->request.getPosFile; + // Hacky solution: + auto *hackyBuffer = (uint32_t *) ¶m->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 = ¶m->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 = ¶m->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 = ¶m->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 = ¶m->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 = ¶m->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 = ¶m->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 = ¶m->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 = ¶m->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(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(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, ¶m->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((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((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; } \ No newline at end of file diff --git a/src/FileUtils.h b/src/FileUtils.h index 51be2fd..dc3ead2 100644 --- a/src/FileUtils.h +++ b/src/FileUtils.h @@ -1,6 +1,8 @@ #pragma once #include "IFSWrapper.h" +#include "utils/logger.h" +#include #include #include #include @@ -8,66 +10,102 @@ #include #include +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> fsLayers; -#define SYNC_RESULT_HANDLER [filename = __FILENAME__, func = __FUNCTION__, line = __LINE__]([[maybe_unused]] std::unique_ptr &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 &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 &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(res); -} - -static inline FSErrorFlag isForceRealFunction(FSErrorFlag flag) { - return static_cast((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 &real_function, - const std::function &layer)> &layer_callback, - const std::function &layer, FSError)> &result_handler); - -FSStatus doForLayer(FSClient *client, - FSErrorFlag errorMask, - const std::function &real_function, - const std::function &layer)> &layer_callback, - const std::function &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); \ No newline at end of file +int64_t writeFromBuffer(int32_t handle, const void *buffer, size_t size, size_t count); + +void startFSIOThreads(); +void stopFSIOThreads(); \ No newline at end of file diff --git a/src/IFSWrapper.h b/src/IFSWrapper.h index b8f071c..528709d 100644 --- a/src/IFSWrapper.h +++ b/src/IFSWrapper.h @@ -1,12 +1,13 @@ #pragma once -#include +#include #include #include -#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; } diff --git a/src/export.cpp b/src/export.cpp index 716a873..2fc72d9 100644 --- a/src/export.cpp +++ b/src/export.cpp @@ -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 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; diff --git a/src/main.cpp b/src/main.cpp index 821fa7f..d804706 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -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 +#include +#include #include 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(); } \ No newline at end of file