mirror of
https://github.com/wiiu-env/ContentRedirectionModule.git
synced 2025-05-17 09:47:00 +02:00
Rewrite of almost everything to fix crashes and lags
This commit is contained in:
parent
3be38d6ea9
commit
857461b735
@ -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
|
||||
|
2
Makefile
2
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
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
|
@ -1,9 +1,9 @@
|
||||
#pragma once
|
||||
#include "DirInfo.h"
|
||||
#include <coreinit/filesystem.h>
|
||||
#include <coreinit/filesystem_fsa.h>
|
||||
|
||||
typedef struct FSDirectoryEntryEx {
|
||||
FSDirectoryEntry realEntry{};
|
||||
FSADirectoryEntry realEntry{};
|
||||
bool isMarkedAsDeleted = false;
|
||||
} FSDirectoryEntryEx;
|
||||
|
||||
|
@ -1,82 +0,0 @@
|
||||
#include "FSDirReplacements.h"
|
||||
#include "FileUtils.h"
|
||||
#include "IFSWrapper.h"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/filesystem.h>
|
||||
|
||||
DECL_FUNCTION(FSError, FSAOpenDir, FSAClientHandle client, const char *path, FSADirectoryHandle *dirHandle) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
return doForLayerFSA(
|
||||
[c = client, p = path, h = dirHandle]() -> FSError {
|
||||
return real_FSAOpenDir(c, p, h);
|
||||
},
|
||||
[p = path, h = dirHandle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSOpenDirWrapper(p, h);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAReadDir, FSAClientHandle client, FSADirectoryHandle dirHandle, FSADirectoryEntry *directoryEntry) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%08X", dirHandle);
|
||||
return doForLayerFSA(
|
||||
[c = client, h = dirHandle, de = directoryEntry]() -> FSError {
|
||||
return real_FSAReadDir(c, h, de);
|
||||
},
|
||||
[h = dirHandle, de = directoryEntry](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSReadDirWrapper(h, de);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSARewindDir, FSAClientHandle client, FSADirectoryHandle dirHandle) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%08X", dirHandle);
|
||||
return doForLayerFSA(
|
||||
[c = client, h = dirHandle]() -> FSError {
|
||||
return real_FSARewindDir(c, h);
|
||||
},
|
||||
[h = dirHandle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSRewindDirWrapper(h);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSACloseDir, FSAClientHandle client, FSADirectoryHandle dirHandle) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%08X", dirHandle);
|
||||
return doForLayerFSA(
|
||||
[c = client, h = dirHandle]() -> FSError {
|
||||
return real_FSACloseDir(c, h);
|
||||
},
|
||||
[h = dirHandle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSCloseDirWrapper(h);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAMakeDir, FSAClientHandle client, const char *path, FSMode mode) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
return doForLayerFSA(
|
||||
[c = client, p = path, m = mode]() -> FSError {
|
||||
return real_FSAMakeDir(c, p, m);
|
||||
},
|
||||
[p = path, m = mode](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSMakeDirWrapper(p);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAChangeDir, FSAClientHandle client, const char *path) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
setWorkingDirForFSAClient(client, path);
|
||||
return real_FSAChangeDir(client, path);
|
||||
}
|
||||
|
||||
function_replacement_data_t fsa_dir_function_replacements[] = {
|
||||
REPLACE_FUNCTION(FSAOpenDir, LIBRARY_COREINIT, FSAOpenDir),
|
||||
REPLACE_FUNCTION(FSAReadDir, LIBRARY_COREINIT, FSAReadDir),
|
||||
REPLACE_FUNCTION(FSARewindDir, LIBRARY_COREINIT, FSARewindDir),
|
||||
REPLACE_FUNCTION(FSACloseDir, LIBRARY_COREINIT, FSACloseDir),
|
||||
REPLACE_FUNCTION(FSAMakeDir, LIBRARY_COREINIT, FSAMakeDir),
|
||||
REPLACE_FUNCTION(FSAChangeDir, LIBRARY_COREINIT, FSAChangeDir),
|
||||
};
|
||||
uint32_t fsa_dir_function_replacements_size = sizeof(fsa_dir_function_replacements) / sizeof(function_replacement_data_t);
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "IFSWrapper.h"
|
||||
#include <coreinit/filesystem.h>
|
||||
#include <function_patcher/function_patching.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
extern function_replacement_data_t fsa_dir_function_replacements[];
|
||||
extern uint32_t fsa_dir_function_replacements_size;
|
@ -1,238 +0,0 @@
|
||||
#include "FSFileReplacements.h"
|
||||
#include "FileUtils.h"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/filesystem_fsa.h>
|
||||
|
||||
DECL_FUNCTION(FSError, FSAOpenFileEx, FSAClientHandle client, const char *path, const char *mode, FSMode createMode, FSOpenFileFlags openFlag, uint32_t preallocSize, FSAFileHandle *handle) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("path: %s mode: %d", path, mode);
|
||||
|
||||
return doForLayerFSA(
|
||||
[c = client, p = path, m = mode, cm = createMode, of = openFlag, pa = preallocSize, h = handle]() -> FSError {
|
||||
return real_FSAOpenFileEx(c, p, m, cm, of, pa, h);
|
||||
},
|
||||
[f = getFullPathForFSAClient(client, path), m = mode, h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
// FSAFileHandle is just an alias for FSFileHandle
|
||||
return layer->FSOpenFileWrapper(f.c_str(), m, h);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSACloseFile, FSAClientHandle client, FSAFileHandle fileHandle) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", fileHandle);
|
||||
|
||||
return doForLayerFSA(
|
||||
[c = client, h = fileHandle]() -> FSError {
|
||||
return real_FSACloseFile(c, h);
|
||||
},
|
||||
[h = fileHandle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
// FSAFileHandle is just an alias for FSFileHandle
|
||||
return layer->FSCloseFileWrapper(h);
|
||||
},
|
||||
[h = fileHandle, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr<IFSWrapper> &layer, FSError res) -> FSError {
|
||||
if (layer->isValidFileHandle(h)) {
|
||||
layer->deleteFileHandle(h);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR_LAMBDA(filename, func, line, "Expected to delete fileHandle by handle %08X but it was not found", h);
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Sync result %d", res);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAFlushFile, FSAClientHandle client, FSAFileHandle fileHandle) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", fileHandle);
|
||||
return doForLayerFSA(
|
||||
[c = client, h = fileHandle]() -> FSError {
|
||||
return real_FSAFlushFile(c, h);
|
||||
},
|
||||
[h = fileHandle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
// FSAFileHandle is just an alias for FSFileHandle
|
||||
return layer->FSFlushFileWrapper(h);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAGetStat, FSAClientHandle client, const char *path, FSAStat *stat) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
return doForLayerFSA(
|
||||
|
||||
[c = client, p = path, s = stat]() -> FSError {
|
||||
return real_FSAGetStat(c, p, s);
|
||||
},
|
||||
[f = getFullPathForFSAClient(client, path), s = stat](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
// FSAStat is just an alias for FSStat
|
||||
return layer->FSGetStatWrapper(f.c_str(), s);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAGetStatFile, FSAClientHandle client, FSAFileHandle fileHandle, FSAStat *stat) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", fileHandle);
|
||||
return doForLayerFSA(
|
||||
[c = client, h = fileHandle, s = stat]() -> FSError {
|
||||
return real_FSAGetStatFile(c, h, s);
|
||||
},
|
||||
[h = fileHandle, s = stat](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
// FSAFileHandle is just an alias for FSFileHandle
|
||||
// FSAStat is just an alias for FSStat
|
||||
return layer->FSGetStatFileWrapper(h, s);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSARemove, FSAClientHandle client, const char *path) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
return doForLayerFSA(
|
||||
[c = client, p = path]() -> FSError {
|
||||
return real_FSARemove(c, p);
|
||||
},
|
||||
[f = getFullPathForFSAClient(client, path)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSRemoveWrapper(f.c_str());
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSARename, FSAClientHandle client, const char *oldPath, const char *newPath) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s %s", oldPath, newPath);
|
||||
return doForLayerFSA(
|
||||
[c = client, op = oldPath, np = newPath]() -> FSError {
|
||||
return real_FSARename(c, op, np);
|
||||
},
|
||||
[op = getFullPathForFSAClient(client, oldPath), np = getFullPathForFSAClient(client, newPath)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSRenameWrapper(op.c_str(), np.c_str());
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSASetPosFile, FSAClientHandle client, FSAFileHandle fileHandle, uint32_t pos) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X pos: %08X", fileHandle, pos);
|
||||
return doForLayerFSA(
|
||||
[c = client, h = fileHandle, p = pos]() -> FSError {
|
||||
return real_FSASetPosFile(c, h, p);
|
||||
},
|
||||
[h = fileHandle, p = pos](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSSetPosFileWrapper(h, p);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSATruncateFile, FSAClientHandle client, FSAFileHandle fileHandle) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%08X", fileHandle);
|
||||
return doForLayerFSA(
|
||||
[c = client, h = fileHandle]() -> FSError {
|
||||
return real_FSATruncateFile(c, h);
|
||||
},
|
||||
[h = fileHandle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSTruncateFileWrapper(h);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAReadFile, FSAClientHandle client, void *buffer, uint32_t size, uint32_t count, FSAFileHandle handle, uint32_t flags) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X", handle, buffer, size * count);
|
||||
return doForLayerFSA(
|
||||
[c = client, b = buffer, s = size, co = count, h = handle, f = flags]() -> FSError {
|
||||
return real_FSAReadFile(c, b, s, co, h, f);
|
||||
},
|
||||
[b = buffer, s = size, co = count, h = handle, f = flags](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSReadFileWrapper(b, s, co, h, f);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAWriteFile, FSAClientHandle client, void *buffer, uint32_t size, uint32_t count, FSAFileHandle handle, uint32_t flags) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X", handle, buffer, size * count);
|
||||
return doForLayerFSA(
|
||||
[c = client, b = buffer, s = size, co = count, h = handle, f = flags]() -> FSError {
|
||||
return real_FSAWriteFile(c, b, s, co, h, f);
|
||||
},
|
||||
[b = buffer, s = size, co = count, h = handle, f = flags](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSWriteFileWrapper((uint8_t *) b, s, co, h, f);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAGetPosFile, FSAClientHandle client, FSAFileHandle handle, uint32_t *outPos) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", handle);
|
||||
return doForLayerFSA(
|
||||
[c = client, h = handle, o = outPos]() -> FSError {
|
||||
return real_FSAGetPosFile(c, h, o);
|
||||
},
|
||||
[h = handle, o = outPos](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSGetPosFileWrapper(h, o);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAIsEof, FSAClientHandle client, FSAFileHandle handle) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", handle);
|
||||
return doForLayerFSA(
|
||||
[c = client, h = handle]() -> FSError {
|
||||
return real_FSAIsEof(c, h);
|
||||
},
|
||||
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSIsEofWrapper(h);
|
||||
},
|
||||
SYNC_RESULT_HANDLER_FSA);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAFlushMultiQuota, FSAClientHandle client, const char *path) {
|
||||
DEBUG_FUNCTION_LINE("NOT IMPLEMENTED. path %s", path);
|
||||
return real_FSAFlushMultiQuota(client, path);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAFlushQuota, FSAClientHandle client, const char *path) {
|
||||
DEBUG_FUNCTION_LINE("NOT IMPLEMENTED. path %s", path);
|
||||
return real_FSAFlushQuota(client, path);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAChangeMode, FSAClientHandle client, const char *path, FSMode permission) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED path %s permission: %08X", path, permission);
|
||||
return real_FSAChangeMode(client, path, permission);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAOpenFileByStat, FSAClientHandle client, FSAStat *stat, const char *mode, const char *path, FSAFileHandle *outFileHandle) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||
return real_FSAOpenFileByStat(client, stat, mode, path, outFileHandle);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAAppendFile, FSAClientHandle client, FSAFileHandle fileHandle, uint32_t size, uint32_t count) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||
return real_FSAAppendFile(client, fileHandle, size, count);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAAppendFileEx, FSAClientHandle client, FSAFileHandle fileHandle, uint32_t size, uint32_t count, uint32_t flags) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||
return real_FSAAppendFileEx(client, fileHandle, size, count, flags);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSAWriteFileWithPos, FSAClientHandle client, uint8_t *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, uint32_t flags) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED. handle %08X size %08X", handle, size * count);
|
||||
return real_FSAWriteFileWithPos(client, buffer, size, count, pos, handle, flags);
|
||||
}
|
||||
|
||||
function_replacement_data_t fsa_file_function_replacements[] = {
|
||||
REPLACE_FUNCTION(FSAOpenFileEx, LIBRARY_COREINIT, FSAOpenFileEx),
|
||||
REPLACE_FUNCTION(FSACloseFile, LIBRARY_COREINIT, FSACloseFile),
|
||||
REPLACE_FUNCTION(FSAFlushFile, LIBRARY_COREINIT, FSAFlushFile),
|
||||
REPLACE_FUNCTION(FSAGetStat, LIBRARY_COREINIT, FSAGetStat),
|
||||
REPLACE_FUNCTION(FSAGetStatFile, LIBRARY_COREINIT, FSAGetStatFile),
|
||||
REPLACE_FUNCTION(FSARemove, LIBRARY_COREINIT, FSARemove),
|
||||
REPLACE_FUNCTION(FSARename, LIBRARY_COREINIT, FSARename),
|
||||
REPLACE_FUNCTION(FSASetPosFile, LIBRARY_COREINIT, FSASetPosFile),
|
||||
REPLACE_FUNCTION(FSATruncateFile, LIBRARY_COREINIT, FSATruncateFile),
|
||||
REPLACE_FUNCTION(FSAReadFile, LIBRARY_COREINIT, FSAReadFile),
|
||||
REPLACE_FUNCTION(FSAWriteFile, LIBRARY_COREINIT, FSAWriteFile),
|
||||
REPLACE_FUNCTION(FSAGetPosFile, LIBRARY_COREINIT, FSAGetPosFile),
|
||||
REPLACE_FUNCTION(FSAIsEof, LIBRARY_COREINIT, FSAIsEof),
|
||||
|
||||
REPLACE_FUNCTION(FSAFlushMultiQuota, LIBRARY_COREINIT, FSAFlushMultiQuota),
|
||||
REPLACE_FUNCTION(FSAFlushQuota, LIBRARY_COREINIT, FSAFlushQuota),
|
||||
REPLACE_FUNCTION(FSAChangeMode, LIBRARY_COREINIT, FSAChangeMode),
|
||||
REPLACE_FUNCTION(FSAOpenFileByStat, LIBRARY_COREINIT, FSAOpenFileByStat),
|
||||
REPLACE_FUNCTION(FSAAppendFile, LIBRARY_COREINIT, FSAAppendFile),
|
||||
REPLACE_FUNCTION(FSAAppendFileEx, LIBRARY_COREINIT, FSAAppendFileEx),
|
||||
REPLACE_FUNCTION(FSAWriteFileWithPos, LIBRARY_COREINIT, FSAWriteFileWithPos),
|
||||
};
|
||||
|
||||
uint32_t fsa_file_function_replacements_size = sizeof(fsa_file_function_replacements) / sizeof(function_replacement_data_t);
|
731
src/FSAReplacements.cpp
Normal file
731
src/FSAReplacements.cpp
Normal file
@ -0,0 +1,731 @@
|
||||
#include "FSAReplacements.h"
|
||||
#include "FileUtils.h"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/core.h>
|
||||
#include <malloc.h>
|
||||
|
||||
static FSError processFSAShimInThread(FSAShimBuffer *shimBuffer) {
|
||||
FSError res;
|
||||
if (gThreadsRunning) {
|
||||
auto param = (FSShimWrapper *) malloc(sizeof(FSShimWrapper));
|
||||
if (param == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for FSShimWrapper");
|
||||
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapper");
|
||||
}
|
||||
|
||||
param->api = FS_SHIM_API_FSA;
|
||||
param->sync = FS_SHIM_TYPE_SYNC;
|
||||
param->shim = shimBuffer;
|
||||
|
||||
if (OSGetCurrentThread() == gThreadData[OSGetCoreId()].thread) {
|
||||
res = processShimBufferForFSA(param);
|
||||
//No need to clean "param", it has been already free'd in processFSAShimBuffer.
|
||||
} else {
|
||||
auto message = (FSShimWrapperMessage *) malloc(sizeof(FSShimWrapperMessage));
|
||||
if (message == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate memory for FSShimWrapperMessage");
|
||||
OSFatal("ContentRedirectionModule: Failed to allocate memory for FSShimWrapperMessage");
|
||||
}
|
||||
message->param = param;
|
||||
|
||||
constexpr int32_t messageSize = sizeof(message->messages) / sizeof(message->messages[0]);
|
||||
OSInitMessageQueue(&message->messageQueue, message->messages, messageSize);
|
||||
if (!sendMessageToThread(message)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to send message to thread");
|
||||
OSFatal("ContentRedirectionModule: Failed send message to thread");
|
||||
}
|
||||
OSMessage recv;
|
||||
if (!OSReceiveMessage(&message->messageQueue, &recv, OS_MESSAGE_FLAGS_BLOCKING)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to receive message");
|
||||
OSFatal("ContentRedirectionModule: Failed to receive message");
|
||||
}
|
||||
if (recv.args[0] != FS_IO_QUEUE_SYNC_RESULT) {
|
||||
DEBUG_FUNCTION_LINE_ERR("ContentRedirection: Unexpected message in message queue.");
|
||||
OSFatal("ContentRedirection: Unexpected message in message queue.");
|
||||
}
|
||||
res = (FSError) recv.args[1];
|
||||
// We only need to clean up "message". "param" has already been free'd by the other thread.
|
||||
free(message);
|
||||
}
|
||||
} else {
|
||||
res = FS_ERROR_FORCE_REAL_FUNCTION;
|
||||
DEBUG_FUNCTION_LINE_WARN("Threads are not running yet, skip replacement");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAOpenFileEx, FSAClientHandle client, const char *path, const char *mode, FSMode createMode, FSOpenFileFlags openFlag, uint32_t preallocSize, FSAFileHandle *handle) {
|
||||
if (handle == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_WARN("handle is null.");
|
||||
return FS_ERROR_INVALID_BUFFER;
|
||||
}
|
||||
*handle = -1;
|
||||
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestOpenFile(shimBuffer, client, path, mode, createMode, openFlag, preallocSize);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestOpenFile failed");
|
||||
return res;
|
||||
}
|
||||
// Hacky solution to pass the pointer into the other thread.
|
||||
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
|
||||
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
|
||||
hackyBuffer[1] = (uint32_t) handle;
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAOpenFileEx" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAOpenFileEx(client, path, mode, createMode, openFlag, preallocSize, handle);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAOpenFile, FSAClientHandle client, const char *path, const char *mode, FSAFileHandle *handle) {
|
||||
if (handle == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_WARN("handle is null.");
|
||||
return FS_ERROR_INVALID_BUFFER;
|
||||
}
|
||||
*handle = -1;
|
||||
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestOpenFile(shimBuffer, client, path, mode, static_cast<FSMode>(0x660), static_cast<FSOpenFileFlags>(0), 0);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestOpenFile failed");
|
||||
return res;
|
||||
}
|
||||
// Hacky solution to pass the pointer into the other thread.
|
||||
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
|
||||
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
|
||||
hackyBuffer[1] = (uint32_t) handle;
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAOpenFile" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAOpenFile(client, path, mode, handle);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSACloseFile, FSAClientHandle client, FSAFileHandle handle) {
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestCloseFile(shimBuffer, client, handle);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestCloseFile failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSACloseFile" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSACloseFile(client, handle);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAFlushFile, FSAClientHandle client, FSAFileHandle handle) {
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestFlushFile(shimBuffer, client, handle);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestFlushFile failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAFlushFile" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAFlushFile(client, handle);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAGetStat, FSAClientHandle client, const char *path, FSAStat *stat) {
|
||||
if (stat == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_WARN("stat is null.");
|
||||
return FS_ERROR_INVALID_BUFFER;
|
||||
}
|
||||
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestQueryInfo(shimBuffer, client, path, FSA_QUERY_INFO_STAT);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
// Hacky solution to pass the pointer into the other thread.
|
||||
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
|
||||
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
|
||||
hackyBuffer[1] = (uint32_t) stat;
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAGetStat" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAGetStat(client, path, stat);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAGetStatFile, FSAClientHandle client, FSAFileHandle handle, FSAStat *stat) {
|
||||
if (stat == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_WARN("stat is null.");
|
||||
return FS_ERROR_INVALID_BUFFER;
|
||||
}
|
||||
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestStatFile(shimBuffer, client, handle);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
// Hacky solution to pass the pointer into the other thread.
|
||||
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
|
||||
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
|
||||
hackyBuffer[1] = (uint32_t) stat;
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAGetStatFile" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAGetStatFile(client, handle, stat);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSARemove, FSAClientHandle client, const char *path) {
|
||||
if (path == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_WARN("path is null.");
|
||||
return FS_ERROR_INVALID_PARAM;
|
||||
}
|
||||
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestRemove(shimBuffer, client, path);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSARemove" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSARemove(client, path);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSARename, FSAClientHandle client, const char *oldPath, const char *newPath) {
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestRename(shimBuffer, client, oldPath, newPath);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSARename" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSARename(client, oldPath, newPath);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSASetPosFile, FSAClientHandle client, FSAFileHandle handle, FSAFilePosition pos) {
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestSetPos(shimBuffer, client, handle, pos);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSASetPosFile" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSASetPosFile(client, handle, pos);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSATruncateFile, FSAClientHandle client, FSAFileHandle handle) {
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestTruncate(shimBuffer, client, handle);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSATruncateFile" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSATruncateFile(client, handle);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAReadFile, FSAClientHandle client, uint8_t *buffer, uint32_t size, uint32_t count, FSAFileHandle handle, uint32_t flags) {
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestReadFile(shimBuffer, client, buffer, size, count, 0, handle, static_cast<FSAReadFlag>(flags & 0xfffffffe));
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAReadFile" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAReadFile(client, buffer, size, count, handle, flags);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAReadFileWithPos, FSAClientHandle client, uint8_t *buffer, uint32_t size, uint32_t count, FSAFilePosition pos, FSAFileHandle handle, uint32_t flags) {
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestReadFile(shimBuffer, client, buffer, size, count, pos, handle, static_cast<FSAReadFlag>(flags | FSA_READ_FLAG_READ_WITH_POS));
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAReadFileWithPos" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAReadFileWithPos(client, buffer, size, count, pos, handle, flags);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAWriteFile, FSAClientHandle client, const uint8_t *buffer, uint32_t size, uint32_t count, FSAFileHandle handle, uint32_t flags) {
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestWriteFile(shimBuffer, client, buffer, size, count, 0, handle, static_cast<FSAWriteFlag>(flags & 0xfffffffe));
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAWriteFile" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAWriteFile(client, buffer, size, count, handle, flags);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAWriteFileWithPos, FSAClientHandle client, uint8_t *buffer, uint32_t size, uint32_t count, FSAFilePosition pos, FSAFileHandle handle, uint32_t flags) {
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestWriteFile(shimBuffer, client, buffer, size, count, pos, handle, static_cast<FSAWriteFlag>(flags | FSA_WRITE_FLAG_READ_WITH_POS));
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAWriteFileWithPos" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAWriteFileWithPos(client, buffer, size, count, pos, handle, flags);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAGetPosFile, FSAClientHandle client, FSAFileHandle handle, FSAFilePosition *outPos) {
|
||||
if (outPos == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_WARN("outPos is null.");
|
||||
return FS_ERROR_INVALID_BUFFER;
|
||||
}
|
||||
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestGetPos(shimBuffer, client, handle);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
// Hacky solution to pass the pointer into the other thread.
|
||||
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
|
||||
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
|
||||
hackyBuffer[1] = (uint32_t) outPos;
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAGetPosFile" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAGetPosFile(client, handle, outPos);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAIsEof, FSAClientHandle client, FSAFileHandle handle) {
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestIsEof(shimBuffer, client, handle);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAIsEof" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAIsEof(client, handle);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAFlushMultiQuota, FSAClientHandle client, const char *path) {
|
||||
DEBUG_FUNCTION_LINE("NOT IMPLEMENTED. path %s", path);
|
||||
return real_FSAFlushMultiQuota(client, path);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAFlushQuota, FSAClientHandle client, const char *path) {
|
||||
DEBUG_FUNCTION_LINE("NOT IMPLEMENTED. path %s", path);
|
||||
return real_FSAFlushQuota(client, path);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAChangeMode, FSAClientHandle client, const char *path, FSMode permission) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED path %s permission: %08X", path, permission);
|
||||
return real_FSAChangeMode(client, path, permission);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAOpenFileByStat, FSAClientHandle client, FSAStat *stat, const char *mode, const char *path, FSAFileHandle *outFileHandle) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||
return real_FSAOpenFileByStat(client, stat, mode, path, outFileHandle);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAAppendFile, FSAClientHandle client, FSAFileHandle fileHandle, uint32_t size, uint32_t count) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||
return real_FSAAppendFile(client, fileHandle, size, count);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAAppendFileEx, FSAClientHandle client, FSAFileHandle fileHandle, uint32_t size, uint32_t count, uint32_t flags) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED");
|
||||
return real_FSAAppendFileEx(client, fileHandle, size, count, flags);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAOpenDir, FSAClientHandle client, const char *path, FSADirectoryHandle *dirHandle) {
|
||||
if (dirHandle == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_WARN("handle is null.");
|
||||
return FS_ERROR_INVALID_BUFFER;
|
||||
}
|
||||
*dirHandle = -1;
|
||||
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestOpenDir(shimBuffer, client, path);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
// Hacky solution to pass the pointer into the other thread.
|
||||
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
|
||||
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
|
||||
hackyBuffer[1] = (uint32_t) dirHandle;
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAOpenDir" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAOpenDir(client, path, dirHandle);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAReadDir, FSAClientHandle client, FSADirectoryHandle dirHandle, FSADirectoryEntry *directoryEntry) {
|
||||
if (directoryEntry == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_WARN("handle is null.");
|
||||
return FS_ERROR_INVALID_BUFFER;
|
||||
}
|
||||
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestReadDir(shimBuffer, client, dirHandle);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
// Hacky solution to pass the pointer into the other thread.
|
||||
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
|
||||
auto *hackyBuffer = (uint32_t *) &shimBuffer->response;
|
||||
hackyBuffer[1] = (uint32_t) directoryEntry;
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAOpenDir" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAReadDir(client, dirHandle, directoryEntry);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSARewindDir, FSAClientHandle client, FSADirectoryHandle dirHandle) {
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestRewindDir(shimBuffer, client, dirHandle);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAOpenDir" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSARewindDir(client, dirHandle);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSACloseDir, FSAClientHandle client, FSADirectoryHandle dirHandle) {
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestCloseDir(shimBuffer, client, dirHandle);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSACloseDir" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSACloseDir(client, dirHandle);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAMakeDir, FSAClientHandle client, const char *path, FSMode mode) {
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestMakeDir(shimBuffer, client, path, mode);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAMakeDir" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAMakeDir(client, path, mode);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSError, FSAChangeDir, FSAClientHandle client, const char *path) {
|
||||
auto *shimBuffer = (FSAShimBuffer *) memalign(0x20, sizeof(FSAShimBuffer));
|
||||
if (!shimBuffer) {
|
||||
DEBUG_FUNCTION_LINE_WARN("FS_ERROR_OUT_OF_RESOURCES");
|
||||
return FS_ERROR_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
auto res = fsaShimPrepareRequestChangeDir(shimBuffer, client, path);
|
||||
if (res != FS_ERROR_OK) {
|
||||
free(shimBuffer);
|
||||
DEBUG_FUNCTION_LINE_WARN("fsaShimPrepareRequestQueryInfo failed");
|
||||
return res;
|
||||
}
|
||||
res = processFSAShimInThread(shimBuffer);
|
||||
free(shimBuffer);
|
||||
if (res != FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Other plugins/modules may override this function as well, so we need to call "real_FSAChangeDir" instead of using
|
||||
// the existing shimBuffer (which would be more efficient).
|
||||
return real_FSAChangeDir(client, path);
|
||||
}
|
||||
|
||||
function_replacement_data_t fsa_file_function_replacements[] = {
|
||||
REPLACE_FUNCTION(FSAOpenFile, LIBRARY_COREINIT, FSAOpenFile),
|
||||
REPLACE_FUNCTION(FSAOpenFileEx, LIBRARY_COREINIT, FSAOpenFileEx),
|
||||
REPLACE_FUNCTION(FSACloseFile, LIBRARY_COREINIT, FSACloseFile),
|
||||
REPLACE_FUNCTION(FSAFlushFile, LIBRARY_COREINIT, FSAFlushFile),
|
||||
REPLACE_FUNCTION(FSAGetStat, LIBRARY_COREINIT, FSAGetStat),
|
||||
REPLACE_FUNCTION(FSAGetStatFile, LIBRARY_COREINIT, FSAGetStatFile),
|
||||
REPLACE_FUNCTION(FSARemove, LIBRARY_COREINIT, FSARemove),
|
||||
REPLACE_FUNCTION(FSARename, LIBRARY_COREINIT, FSARename),
|
||||
REPLACE_FUNCTION(FSASetPosFile, LIBRARY_COREINIT, FSASetPosFile),
|
||||
REPLACE_FUNCTION(FSATruncateFile, LIBRARY_COREINIT, FSATruncateFile),
|
||||
REPLACE_FUNCTION(FSAReadFile, LIBRARY_COREINIT, FSAReadFile),
|
||||
REPLACE_FUNCTION(FSAReadFileWithPos, LIBRARY_COREINIT, FSAReadFileWithPos),
|
||||
REPLACE_FUNCTION(FSAWriteFile, LIBRARY_COREINIT, FSAWriteFile),
|
||||
REPLACE_FUNCTION(FSAWriteFileWithPos, LIBRARY_COREINIT, FSAWriteFileWithPos),
|
||||
REPLACE_FUNCTION(FSAGetPosFile, LIBRARY_COREINIT, FSAGetPosFile),
|
||||
REPLACE_FUNCTION(FSAIsEof, LIBRARY_COREINIT, FSAIsEof),
|
||||
|
||||
REPLACE_FUNCTION(FSAFlushMultiQuota, LIBRARY_COREINIT, FSAFlushMultiQuota),
|
||||
REPLACE_FUNCTION(FSAFlushQuota, LIBRARY_COREINIT, FSAFlushQuota),
|
||||
REPLACE_FUNCTION(FSAChangeMode, LIBRARY_COREINIT, FSAChangeMode),
|
||||
REPLACE_FUNCTION(FSAOpenFileByStat, LIBRARY_COREINIT, FSAOpenFileByStat),
|
||||
REPLACE_FUNCTION(FSAAppendFile, LIBRARY_COREINIT, FSAAppendFile),
|
||||
REPLACE_FUNCTION(FSAAppendFileEx, LIBRARY_COREINIT, FSAAppendFileEx),
|
||||
|
||||
REPLACE_FUNCTION(FSAOpenDir, LIBRARY_COREINIT, FSAOpenDir),
|
||||
REPLACE_FUNCTION(FSAReadDir, LIBRARY_COREINIT, FSAReadDir),
|
||||
REPLACE_FUNCTION(FSARewindDir, LIBRARY_COREINIT, FSARewindDir),
|
||||
REPLACE_FUNCTION(FSACloseDir, LIBRARY_COREINIT, FSACloseDir),
|
||||
REPLACE_FUNCTION(FSAMakeDir, LIBRARY_COREINIT, FSAMakeDir),
|
||||
REPLACE_FUNCTION(FSAChangeDir, LIBRARY_COREINIT, FSAChangeDir),
|
||||
};
|
||||
|
||||
uint32_t fsa_file_function_replacements_size = sizeof(fsa_file_function_replacements) / sizeof(function_replacement_data_t);
|
||||
|
||||
FSError processShimBufferForFSA(FSShimWrapper *param) {
|
||||
auto res = doForLayer(param);
|
||||
if (res == FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
if (param->sync == FS_SHIM_TYPE_ASYNC) {
|
||||
DEBUG_FUNCTION_LINE_ERR("ASYNC FSA API is not supported");
|
||||
OSFatal("ContentRedirectionModule: ASYNC FSA API is not supported");
|
||||
}
|
||||
}
|
||||
free(param);
|
||||
return res;
|
||||
}
|
@ -1,219 +0,0 @@
|
||||
#include "FSDirReplacements.h"
|
||||
#include "FileUtils.h"
|
||||
#include "IFSWrapper.h"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/filesystem.h>
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSOpenDir, FSClient *client, FSCmdBlock *block, const char *path, FSDirectoryHandle *handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSOpenDir(client, block, path, handle, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, p = path](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSOpenDir(c, b, p, h, realErrorMask);
|
||||
},
|
||||
[f = getFullPathForFSClient(client, path), h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSOpenDirWrapper(f.c_str(), h);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSOpenDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSDirectoryHandle *handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSOpenDirAsync(client, block, path, handle, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, p = path, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSOpenDirAsync(c, b, p, h, realErrorMask, a);
|
||||
},
|
||||
[f = getFullPathForFSClient(client, path), h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSOpenDirWrapper(f.c_str(), h);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSReadDir, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, [[maybe_unused]] FSDirectoryEntry *entry, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("", errorMask);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSReadDir(client, block, handle, entry, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, e = entry](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSReadDir(c, b, h, e, realErrorMask);
|
||||
},
|
||||
[h = handle, e = entry](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSReadDirWrapper(h, e);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSReadDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSDirectoryEntry *entry, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE();
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSReadDirAsync(client, block, handle, entry, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, e = entry, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSReadDirAsync(c, b, h, e, realErrorMask, a);
|
||||
},
|
||||
[h = handle, e = entry](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSReadDirWrapper(h, e);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSCloseDir, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSCloseDir(client, block, handle, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSCloseDir(c, b, h, realErrorMask);
|
||||
},
|
||||
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSCloseDirWrapper(h);
|
||||
},
|
||||
[h = handle, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr<IFSWrapper> &layer, FSStatus res) -> FSStatus {
|
||||
if (layer->isValidDirHandle(h)) {
|
||||
layer->deleteDirHandle(h);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR_LAMBDA(filename, func, line, "Expected to delete dirHandle by %08X but it was not found", h);
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Sync result %d", res);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSCloseDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE();
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSCloseDirAsync(client, block, handle, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSCloseDirAsync(c, b, h, realErrorMask, a);
|
||||
},
|
||||
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSCloseDirWrapper(h);
|
||||
},
|
||||
[c = client, b = block, h = handle, a = asyncData, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr<IFSWrapper> &layer, FSStatus res) -> FSStatus {
|
||||
if (layer->isValidDirHandle(h)) {
|
||||
layer->deleteDirHandle(h);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR_LAMBDA(filename, func, line, "Expected to delete dirHandle by %08X but it was not found", h);
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Async result %d", res);
|
||||
return send_result_async(c, b, a, res);
|
||||
});
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSRewindDir, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("");
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSRewindDir(client, block, handle, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSRewindDir(c, b, h, realErrorMask);
|
||||
},
|
||||
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSRewindDirWrapper(h);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSRewindDirAsync, FSClient *client, FSCmdBlock *block, FSDirectoryHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE();
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSRewindDirAsync(client, block, handle, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSRewindDirAsync(c, b, h, realErrorMask, a);
|
||||
},
|
||||
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSRewindDirWrapper(h);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSMakeDir, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSMakeDir(client, block, path, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, p = path](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSMakeDir(c, b, p, realErrorMask);
|
||||
},
|
||||
[f = getFullPathForFSClient(client, path)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSMakeDirWrapper(f.c_str());
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSMakeDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSMakeDirAsync(client, block, path, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, p = path, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSMakeDirAsync(c, b, p, realErrorMask, a);
|
||||
},
|
||||
[f = getFullPathForFSClient(client, path)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSMakeDirWrapper(f.c_str());
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSChangeDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("FSChangeDirAsync %s", path);
|
||||
setWorkingDirForFSClient(client, path);
|
||||
return real_FSChangeDirAsync(client, block, path, errorMask, asyncData);
|
||||
}
|
||||
|
||||
function_replacement_data_t fs_dir_function_replacements[] = {
|
||||
REPLACE_FUNCTION(FSOpenDir, LIBRARY_COREINIT, FSOpenDir),
|
||||
REPLACE_FUNCTION(FSOpenDirAsync, LIBRARY_COREINIT, FSOpenDirAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSReadDir, LIBRARY_COREINIT, FSReadDir),
|
||||
REPLACE_FUNCTION(FSReadDirAsync, LIBRARY_COREINIT, FSReadDirAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSCloseDir, LIBRARY_COREINIT, FSCloseDir),
|
||||
REPLACE_FUNCTION(FSCloseDirAsync, LIBRARY_COREINIT, FSCloseDirAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSRewindDir, LIBRARY_COREINIT, FSRewindDir),
|
||||
REPLACE_FUNCTION(FSRewindDirAsync, LIBRARY_COREINIT, FSRewindDirAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSMakeDir, LIBRARY_COREINIT, FSMakeDir),
|
||||
REPLACE_FUNCTION(FSMakeDirAsync, LIBRARY_COREINIT, FSMakeDirAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSChangeDirAsync, LIBRARY_COREINIT, FSChangeDirAsync),
|
||||
};
|
||||
uint32_t fs_dir_function_replacements_size = sizeof(fs_dir_function_replacements) / sizeof(function_replacement_data_t);
|
@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "IFSWrapper.h"
|
||||
#include <coreinit/filesystem.h>
|
||||
#include <function_patcher/function_patching.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
extern function_replacement_data_t fs_dir_function_replacements[];
|
||||
extern uint32_t fs_dir_function_replacements_size;
|
@ -1,616 +0,0 @@
|
||||
#include "FSFileReplacements.h"
|
||||
#include "FileUtils.h"
|
||||
#include "utils/logger.h"
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSOpenFileEx, FSClient *client, FSCmdBlock *block, const char *path, const char *mode, FSMode createMode, FSOpenFileFlags openFlag, uint32_t preallocSize, FSFileHandle *handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSOpenFileEx(client, block, path, mode, createMode, openFlag, preallocSize, handle, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, p = path, m = mode, cm = createMode, of = openFlag, pa = preallocSize, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSOpenFileEx(c, b, p, m, cm, of, pa, h, realErrorMask);
|
||||
},
|
||||
[f = getFullPathForFSClient(client, path), m = mode, h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSOpenFileWrapper(f.c_str(), m, h);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSOpenFileExAsync, FSClient *client, FSCmdBlock *block, const char *path, const char *mode, FSMode createMode, FSOpenFileFlags openFlag, uint32_t preallocSize, FSFileHandle *handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSOpenFileExAsync(client, block, path, mode, createMode, openFlag, preallocSize, handle, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, p = path, m = mode, cm = createMode, of = openFlag, pa = preallocSize, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSOpenFileExAsync(c, b, p, m, cm, of, pa, h, realErrorMask, a);
|
||||
},
|
||||
[p = getFullPathForFSClient(client, path), m = mode, h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSOpenFileWrapper(p.c_str(), m, h);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSOpenFile, FSClient *client, FSCmdBlock *block, char *path, const char *mode, FSFileHandle *handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSOpenFile(client, block, path, mode, handle, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, p = path, m = mode, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSOpenFile(c, b, p, m, h, realErrorMask);
|
||||
},
|
||||
[f = getFullPathForFSClient(client, path), m = mode, h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSOpenFileWrapper(f.c_str(), m, h);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSOpenFileAsync, FSClient *client, FSCmdBlock *block, const char *path, const char *mode, FSFileHandle *handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSOpenFileAsync(client, block, path, mode, handle, errorMask, asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, p = path, m = mode, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSOpenFileAsync(c, b, p, m, h, realErrorMask, a);
|
||||
},
|
||||
[p = getFullPathForFSClient(client, path), m = mode, h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSOpenFileWrapper(p.c_str(), m, h);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSCloseFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSCloseFile(client, block, handle, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSCloseFile(c, b, h, realErrorMask);
|
||||
},
|
||||
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSCloseFileWrapper(h);
|
||||
},
|
||||
[h = handle, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr<IFSWrapper> &layer, FSStatus res) -> FSStatus {
|
||||
if (layer->isValidFileHandle(h)) {
|
||||
layer->deleteFileHandle(h);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR_LAMBDA(filename, func, line, "Expected to delete fileHandle by handle %08X but it was not found", h);
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Sync result %d", res);
|
||||
return res;
|
||||
});
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSCloseFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSCloseFileAsync(client, block, handle, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSCloseFileAsync(c, b, h, realErrorMask, a);
|
||||
},
|
||||
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSCloseFileWrapper(h);
|
||||
},
|
||||
[c = client, b = block, h = handle, a = asyncData, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__](std::unique_ptr<IFSWrapper> &layer, FSStatus res) -> FSStatus {
|
||||
if (layer->isValidFileHandle(h)) {
|
||||
layer->deleteFileHandle(h);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR_LAMBDA(filename, func, line, "Expected to delete fileHandle by handle %08X but it was not found", h);
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Async result %d", res);
|
||||
return send_result_async(c, b, a, res);
|
||||
});
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSGetStat, FSClient *client, FSCmdBlock *block, const char *path, FSStat *stats, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSGetStat(client, block, path, stats, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, p = path, s = stats](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSGetStat(c, b, p, s, realErrorMask);
|
||||
},
|
||||
[p = getFullPathForFSClient(client, path), s = stats](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSGetStatWrapper(p.c_str(), s);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSGetStatAsync, FSClient *client, FSCmdBlock *block, const char *path, FSStat *stats, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSGetStatAsync(client, block, path, stats, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, p = path, s = stats, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSGetStatAsync(c, b, p, s, realErrorMask, a);
|
||||
},
|
||||
[p = getFullPathForFSClient(client, path), s = stats](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSGetStatWrapper(p.c_str(), s);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSGetStatFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSStat *stats, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", handle);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSGetStatFile(client, block, handle, stats, getRealErrorFlag(errorMask));
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, s = stats](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSGetStatFile(c, b, h, s, realErrorMask);
|
||||
},
|
||||
[h = handle, s = stats](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSGetStatFileWrapper(h, s);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSGetStatFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSStat *stats, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X", handle);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSGetStatFileAsync(client, block, handle, stats, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, s = stats, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSGetStatFileAsync(c, b, h, s, realErrorMask, a);
|
||||
},
|
||||
[h = handle, s = stats](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSGetStatFileWrapper(h, s);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSReadFile, FSClient *client, FSCmdBlock *block, void *buffer, uint32_t size, uint32_t count, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X", handle, buffer, size * count);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSReadFile(client, block, buffer, size, count, handle, unk1, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, s = size, co = count, bu = buffer, u = unk1](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSReadFile(c, b, bu, s, co, h, u, realErrorMask);
|
||||
},
|
||||
[b = buffer, s = size, c = count, h = handle, u = unk1](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSReadFileWrapper(b, s, c, h, u);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSReadFileAsync, FSClient *client, FSCmdBlock *block, void *buffer, uint32_t size, uint32_t count, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask,
|
||||
FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X", handle, buffer, size * count);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSReadFileAsync(client, block, buffer, size, count, handle, unk1, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, s = size, co = count, bu = buffer, u = unk1, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSReadFileAsync(c, b, bu, s, co, h, u, realErrorMask, a);
|
||||
},
|
||||
[b = buffer, s = size, c = count, h = handle, u = unk1](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSReadFileWrapper(b, s, c, h, u);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSReadFileWithPos, FSClient *client, FSCmdBlock *block, void *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X pos: %08X", handle, buffer, size * count, pos);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSReadFileWithPos(client, block, buffer, size, count, pos, handle, unk1, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, s = size, co = count, p = pos, bu = buffer, u = unk1](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSReadFileWithPos(c, b, bu, s, co, p, h, u, realErrorMask);
|
||||
},
|
||||
[b = buffer, s = size, c = count, p = pos, h = handle, u = unk1](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSReadFileWithPosWrapper(b, s, c, p, h, u);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSReadFileWithPosAsync, FSClient *client, FSCmdBlock *block, void *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, int32_t unk1, FSErrorFlag errorMask,
|
||||
FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X pos: %08X", handle, buffer, size * count, pos);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSReadFileWithPosAsync(client, block, buffer, size, count, pos, handle, unk1, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, s = size, co = count, p = pos, bu = buffer, u = unk1, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSReadFileWithPosAsync(c, b, bu, s, co, p, h, u, realErrorMask, a);
|
||||
},
|
||||
[b = buffer, s = size, c = count, p = pos, h = handle, u = unk1](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSReadFileWithPosWrapper(b, s, c, p, h, u);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSSetPosFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, uint32_t pos, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X pos: %08X", handle, pos);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSSetPosFile(client, block, handle, pos, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, p = pos](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSSetPosFile(c, b, h, p, realErrorMask);
|
||||
},
|
||||
[h = handle, p = pos](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSSetPosFileWrapper(h, p);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSSetPosFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, uint32_t pos, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X pos: %08X", handle, pos);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSSetPosFileAsync(client, block, handle, pos, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, p = pos, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSSetPosFileAsync(c, b, h, p, realErrorMask, a);
|
||||
},
|
||||
[h = handle, p = pos](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSSetPosFileWrapper(h, p);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSGetPosFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, uint32_t *pos, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSGetPosFile(client, block, handle, pos, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, p = pos](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSGetPosFile(c, b, h, p, realErrorMask);
|
||||
},
|
||||
[h = handle, p = pos](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSGetPosFileWrapper(h, p);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSGetPosFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, uint32_t *pos, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSGetPosFileAsync(client, block, handle, pos, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, p = pos, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSGetPosFileAsync(c, b, h, p, realErrorMask, a);
|
||||
},
|
||||
[h = handle, p = pos](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSGetPosFileWrapper(h, p);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSIsEof, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSIsEof(client, block, handle, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSIsEof(c, b, h, realErrorMask);
|
||||
},
|
||||
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSIsEofWrapper(h);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSIsEofAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSIsEofAsync(client, block, handle, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSIsEofAsync(c, b, h, realErrorMask, a);
|
||||
},
|
||||
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSIsEofWrapper(h);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSWriteFile, FSClient *client, FSCmdBlock *block, uint8_t *buffer, uint32_t size, uint32_t count, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X", handle, buffer, size * count);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSWriteFile(client, block, buffer, size, count, handle, unk1, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, bu = buffer, s = size, co = count, h = handle, u = unk1](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSWriteFile(c, b, bu, s, co, h, u, realErrorMask);
|
||||
},
|
||||
[b = buffer, s = size, c = count, h = handle, u = unk1](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSWriteFileWrapper(b, s, c, h, u);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSWriteFileAsync, FSClient *client, FSCmdBlock *block, uint8_t *buffer, uint32_t size, uint32_t count, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask,
|
||||
FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("handle: %08X buffer: %08X size: %08X", handle, buffer, size * count);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSWriteFileAsync(client, block, buffer, size, count, handle, unk1, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, bu = buffer, s = size, co = count, h = handle, u = unk1, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSWriteFileAsync(c, b, bu, s, co, h, u, realErrorMask, a);
|
||||
},
|
||||
[b = buffer, s = size, c = count, h = handle, u = unk1](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSWriteFileWrapper(b, s, c, h, u);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSTruncateFile, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSTruncateFile(client, block, handle, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSTruncateFile(c, b, h, realErrorMask);
|
||||
},
|
||||
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSTruncateFileWrapper(h);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSTruncateFileAsync, FSClient *client, FSCmdBlock *block, FSFileHandle handle, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSTruncateFileAsync(client, block, handle, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSTruncateFileAsync(c, b, h, realErrorMask, a);
|
||||
},
|
||||
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSTruncateFileWrapper(h);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSRemove, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSRemove(client, block, path, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, p = path](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSRemove(c, b, p, realErrorMask);
|
||||
},
|
||||
[p = getFullPathForFSClient(client, path)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSRemoveWrapper(p.c_str());
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSRemoveAsync, FSClient *client, FSCmdBlock *block, const char *path, [[maybe_unused]] FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s", path);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSRemoveAsync(client, block, path, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, p = path, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSRemoveAsync(c, b, p, realErrorMask, a);
|
||||
},
|
||||
[p = getFullPathForFSClient(client, path)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSRemoveWrapper(p.c_str());
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSRename, FSClient *client, FSCmdBlock *block, const char *oldPath, const char *newPath, FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s -> %s", oldPath, newPath);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSRename(client, block, oldPath, newPath, getRealErrorFlag(errorMask));
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, oP = oldPath, nP = newPath](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSRename(c, b, oP, nP, realErrorMask);
|
||||
},
|
||||
[oP = getFullPathForFSClient(client, oldPath), nP = getFullPathForFSClient(client, newPath)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSRenameWrapper(oP.c_str(), nP.c_str());
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSRenameAsync,
|
||||
FSClient *client,
|
||||
FSCmdBlock *block,
|
||||
const char *oldPath,
|
||||
const char *newPath,
|
||||
FSErrorFlag errorMask,
|
||||
FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%s -> %s", oldPath, newPath);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSRenameAsync(client, block, oldPath, newPath, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, oP = oldPath, nP = newPath, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSRenameAsync(c, b, oP, nP, realErrorMask, a);
|
||||
},
|
||||
[oP = getFullPathForFSClient(client, oldPath), nP = getFullPathForFSClient(client, newPath)](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSRenameWrapper(oP.c_str(), nP.c_str());
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSFlushFile, FSClient *client, FSCmdBlock *block, [[maybe_unused]] FSFileHandle handle, [[maybe_unused]] FSErrorFlag errorMask) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSFlushFile(client, block, handle, errorMask);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSFlushFile(c, b, h, realErrorMask);
|
||||
},
|
||||
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSFlushFileWrapper(h);
|
||||
},
|
||||
SYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSFlushFileAsync, FSClient *client, FSCmdBlock *block, [[maybe_unused]] FSFileHandle handle, [[maybe_unused]] FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("%08X", handle);
|
||||
if (isForceRealFunction(errorMask)) {
|
||||
return real_FSFlushFileAsync(client, block, handle, getRealErrorFlag(errorMask), asyncData);
|
||||
}
|
||||
return doForLayer(
|
||||
client,
|
||||
errorMask,
|
||||
[c = client, b = block, h = handle, a = asyncData](FSErrorFlag realErrorMask) -> FSStatus {
|
||||
return real_FSFlushFileAsync(c, b, h, realErrorMask, a);
|
||||
},
|
||||
[h = handle](std::unique_ptr<IFSWrapper> &layer) -> FSError {
|
||||
return layer->FSFlushFileWrapper(h);
|
||||
},
|
||||
ASYNC_RESULT_HANDLER);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSChangeModeAsync,
|
||||
FSClient *client,
|
||||
FSCmdBlock *block,
|
||||
const char *path,
|
||||
[[maybe_unused]] FSMode mode,
|
||||
[[maybe_unused]] FSMode modeMask,
|
||||
[[maybe_unused]] FSErrorFlag errorMask,
|
||||
FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED path %s mode: %08X", path, mode);
|
||||
return real_FSChangeModeAsync(client, block, path, mode, modeMask, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSGetFreeSpaceSizeAsync, FSClient *client, FSCmdBlock *block, const char *path, [[maybe_unused]] uint64_t *outSize, [[maybe_unused]] FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED. Path: %s", path);
|
||||
return real_FSGetFreeSpaceSizeAsync(client, block, path, outSize, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSWriteFileWithPosAsync, FSClient *client, FSCmdBlock *block, uint8_t *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, uint32_t unk1, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
DEBUG_FUNCTION_LINE_ERR("NOT IMPLEMENTED. handle %08X size %08X", handle, size * count);
|
||||
return real_FSWriteFileWithPosAsync(client, block, buffer, size, count, pos, handle, unk1, errorMask, asyncData);
|
||||
}
|
||||
|
||||
function_replacement_data_t fs_file_function_replacements[] = {
|
||||
REPLACE_FUNCTION(FSOpenFileEx, LIBRARY_COREINIT, FSOpenFileEx),
|
||||
REPLACE_FUNCTION(FSOpenFileExAsync, LIBRARY_COREINIT, FSOpenFileExAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSOpenFile, LIBRARY_COREINIT, FSOpenFile),
|
||||
REPLACE_FUNCTION(FSOpenFileAsync, LIBRARY_COREINIT, FSOpenFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSCloseFile, LIBRARY_COREINIT, FSCloseFile),
|
||||
REPLACE_FUNCTION(FSCloseFileAsync, LIBRARY_COREINIT, FSCloseFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSGetStat, LIBRARY_COREINIT, FSGetStat),
|
||||
REPLACE_FUNCTION(FSGetStatAsync, LIBRARY_COREINIT, FSGetStatAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSGetStatFile, LIBRARY_COREINIT, FSGetStatFile),
|
||||
REPLACE_FUNCTION(FSGetStatFileAsync, LIBRARY_COREINIT, FSGetStatFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSReadFile, LIBRARY_COREINIT, FSReadFile),
|
||||
REPLACE_FUNCTION(FSReadFileAsync, LIBRARY_COREINIT, FSReadFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSReadFileWithPos, LIBRARY_COREINIT, FSReadFileWithPos),
|
||||
REPLACE_FUNCTION(FSReadFileWithPosAsync, LIBRARY_COREINIT, FSReadFileWithPosAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSSetPosFile, LIBRARY_COREINIT, FSSetPosFile),
|
||||
REPLACE_FUNCTION(FSSetPosFileAsync, LIBRARY_COREINIT, FSSetPosFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSGetPosFile, LIBRARY_COREINIT, FSGetPosFile),
|
||||
REPLACE_FUNCTION(FSGetPosFileAsync, LIBRARY_COREINIT, FSGetPosFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSIsEof, LIBRARY_COREINIT, FSIsEof),
|
||||
REPLACE_FUNCTION(FSIsEofAsync, LIBRARY_COREINIT, FSIsEofAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSWriteFile, LIBRARY_COREINIT, FSWriteFile),
|
||||
REPLACE_FUNCTION(FSWriteFileAsync, LIBRARY_COREINIT, FSWriteFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSTruncateFile, LIBRARY_COREINIT, FSTruncateFile),
|
||||
REPLACE_FUNCTION(FSTruncateFileAsync, LIBRARY_COREINIT, FSTruncateFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSRemove, LIBRARY_COREINIT, FSRemove),
|
||||
REPLACE_FUNCTION(FSRemoveAsync, LIBRARY_COREINIT, FSRemoveAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSRename, LIBRARY_COREINIT, FSRename),
|
||||
REPLACE_FUNCTION(FSRenameAsync, LIBRARY_COREINIT, FSRenameAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSFlushFile, LIBRARY_COREINIT, FSFlushFile),
|
||||
REPLACE_FUNCTION(FSFlushFileAsync, LIBRARY_COREINIT, FSFlushFileAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSChangeModeAsync, LIBRARY_COREINIT, FSChangeModeAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSWriteFileWithPosAsync, LIBRARY_COREINIT, FSWriteFileWithPosAsync),
|
||||
|
||||
//REPLACE_FUNCTION(FSGetFreeSpaceSizeAsync, LIBRARY_COREINIT, FSGetFreeSpaceSizeAsync),
|
||||
//REPLACE_FUNCTION_VIA_ADDRESS(FSGetFreeSpaceSizeAsync, LIBRARY_COREINIT, 0x0A000000 + 0x0256079c),
|
||||
};
|
||||
|
||||
uint32_t fs_file_function_replacements_size = sizeof(fs_file_function_replacements) / sizeof(function_replacement_data_t);
|
810
src/FSReplacements.cpp
Normal file
810
src/FSReplacements.cpp
Normal file
@ -0,0 +1,810 @@
|
||||
#include "FSReplacements.h"
|
||||
#include "FileUtils.h"
|
||||
#include "utils/StringTools.h"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/core.h>
|
||||
|
||||
FSStatus processFSError(FSError fsError, FSClient *client, FSErrorFlag errorMask) {
|
||||
auto result = fsError >= 0 ? static_cast<FSStatus>(fsError) : fsaDecodeFsaStatusToFsStatus(fsError);
|
||||
|
||||
if (result >= FS_STATUS_OK || result == FS_STATUS_END || result == FS_STATUS_CANCELLED) {
|
||||
return result;
|
||||
}
|
||||
|
||||
FSErrorFlag errorFlags = FS_ERROR_FLAG_NONE;
|
||||
bool forceError = false;
|
||||
|
||||
switch ((int32_t) result) {
|
||||
case FS_STATUS_MAX:
|
||||
errorFlags = FS_ERROR_FLAG_MAX;
|
||||
break;
|
||||
case FS_STATUS_ALREADY_OPEN:
|
||||
errorFlags = FS_ERROR_FLAG_ALREADY_OPEN;
|
||||
break;
|
||||
case FS_STATUS_EXISTS:
|
||||
errorFlags = FS_ERROR_FLAG_EXISTS;
|
||||
break;
|
||||
case FS_STATUS_NOT_FOUND:
|
||||
errorFlags = FS_ERROR_FLAG_NOT_FOUND;
|
||||
break;
|
||||
case FS_STATUS_NOT_FILE:
|
||||
errorFlags = FS_ERROR_FLAG_NOT_FILE;
|
||||
break;
|
||||
case FS_STATUS_NOT_DIR:
|
||||
errorFlags = FS_ERROR_FLAG_NOT_DIR;
|
||||
break;
|
||||
case FS_STATUS_ACCESS_ERROR:
|
||||
errorFlags = FS_ERROR_FLAG_ACCESS_ERROR;
|
||||
break;
|
||||
case FS_STATUS_PERMISSION_ERROR:
|
||||
errorFlags = FS_ERROR_FLAG_PERMISSION_ERROR;
|
||||
break;
|
||||
case FS_STATUS_FILE_TOO_BIG:
|
||||
errorFlags = FS_ERROR_FLAG_FILE_TOO_BIG;
|
||||
break;
|
||||
case FS_STATUS_STORAGE_FULL:
|
||||
errorFlags = FS_ERROR_FLAG_STORAGE_FULL;
|
||||
break;
|
||||
case FS_STATUS_JOURNAL_FULL:
|
||||
errorFlags = FS_ERROR_FLAG_JOURNAL_FULL;
|
||||
break;
|
||||
case FS_STATUS_UNSUPPORTED_CMD:
|
||||
errorFlags = FS_ERROR_FLAG_UNSUPPORTED_CMD;
|
||||
break;
|
||||
case FS_STATUS_MEDIA_NOT_READY:
|
||||
case FS_STATUS_MEDIA_ERROR:
|
||||
case FS_STATUS_CORRUPTED:
|
||||
case FS_STATUS_FATAL_ERROR:
|
||||
forceError = true;
|
||||
break;
|
||||
case FS_STATUS_OK:
|
||||
break;
|
||||
}
|
||||
|
||||
if (forceError || (errorMask != FS_ERROR_FLAG_NONE && (errorFlags & errorMask) == 0)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Transit to Fatal Error. Error %s (%d)", FSAGetStatusStr(fsError), fsError);
|
||||
auto clientBody = fsClientGetBody(client);
|
||||
|
||||
fsClientHandleFatalErrorAndBlock(clientBody, clientBody->lastError);
|
||||
return FS_STATUS_FATAL_ERROR;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void handleAsyncRequestsCallback(IOSError err, void *context) {
|
||||
auto *param = (AsyncParamFS *) context;
|
||||
auto *client = param->client;
|
||||
auto *clientBody = fsClientGetBody(client);
|
||||
auto *block = param->block;
|
||||
auto *asyncData = ¶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<FSMode>(0x660)) == 0) {
|
||||
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
|
||||
|
||||
return FS_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return real_FSMakeDirAsync(client, block, path, errorMask, asyncData);
|
||||
}
|
||||
|
||||
DECL_FUNCTION(FSStatus, FSChangeDirAsync, FSClient *client, FSCmdBlock *block, const char *path, FSErrorFlag errorMask, FSAsyncData *asyncData) {
|
||||
auto *clientBody = fsClientGetBody(client);
|
||||
auto *shimBuffer = (FSAShimBuffer *) fsCmdBlockGetBody(block);
|
||||
|
||||
if (path == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("path is null.");
|
||||
fsClientHandleFatalError(clientBody, FS_ERROR_INVALID_PATH);
|
||||
return FS_STATUS_FATAL_ERROR;
|
||||
}
|
||||
|
||||
if (fsaShimPrepareRequestChangeDir(shimBuffer, clientBody->clientHandle, path) == 0) {
|
||||
if (processFSAShimInThread(shimBuffer, client, block, errorMask, asyncData)) {
|
||||
|
||||
return FS_STATUS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return real_FSChangeDirAsync(client, block, path, errorMask, asyncData);
|
||||
}
|
||||
|
||||
function_replacement_data_t fs_file_function_replacements[] = {
|
||||
REPLACE_FUNCTION(FSOpenFileExAsync, LIBRARY_COREINIT, FSOpenFileExAsync),
|
||||
REPLACE_FUNCTION(FSCloseFileAsync, LIBRARY_COREINIT, FSCloseFileAsync),
|
||||
REPLACE_FUNCTION(FSGetStatAsync, LIBRARY_COREINIT, FSGetStatAsync),
|
||||
REPLACE_FUNCTION(FSGetStatFileAsync, LIBRARY_COREINIT, FSGetStatFileAsync),
|
||||
REPLACE_FUNCTION_VIA_ADDRESS(FSReadFileGeneric, 0x3201C400 + 0x4ecc0, 0x101C400 + 0x4ecc0),
|
||||
REPLACE_FUNCTION(FSSetPosFileAsync, LIBRARY_COREINIT, FSSetPosFileAsync),
|
||||
REPLACE_FUNCTION(FSGetPosFileAsync, LIBRARY_COREINIT, FSGetPosFileAsync),
|
||||
REPLACE_FUNCTION(FSIsEofAsync, LIBRARY_COREINIT, FSIsEofAsync),
|
||||
REPLACE_FUNCTION_VIA_ADDRESS(FSWriteFileGeneric, 0x3201C400 + 0x4eec0, 0x101C400 + 0x4eec0),
|
||||
REPLACE_FUNCTION(FSTruncateFileAsync, LIBRARY_COREINIT, FSTruncateFileAsync),
|
||||
REPLACE_FUNCTION(FSRemoveAsync, LIBRARY_COREINIT, FSRemoveAsync),
|
||||
REPLACE_FUNCTION(FSRenameAsync, LIBRARY_COREINIT, FSRenameAsync),
|
||||
REPLACE_FUNCTION(FSFlushFileAsync, LIBRARY_COREINIT, FSFlushFileAsync),
|
||||
REPLACE_FUNCTION(FSChangeModeAsync, LIBRARY_COREINIT, FSChangeModeAsync),
|
||||
|
||||
REPLACE_FUNCTION(FSOpenDirAsync, LIBRARY_COREINIT, FSOpenDirAsync),
|
||||
REPLACE_FUNCTION(FSReadDirAsync, LIBRARY_COREINIT, FSReadDirAsync),
|
||||
REPLACE_FUNCTION(FSCloseDirAsync, LIBRARY_COREINIT, FSCloseDirAsync),
|
||||
REPLACE_FUNCTION(FSRewindDirAsync, LIBRARY_COREINIT, FSRewindDirAsync),
|
||||
REPLACE_FUNCTION(FSMakeDirAsync, LIBRARY_COREINIT, FSMakeDirAsync),
|
||||
REPLACE_FUNCTION(FSChangeDirAsync, LIBRARY_COREINIT, FSChangeDirAsync),
|
||||
};
|
||||
|
||||
uint32_t fs_file_function_replacements_size = sizeof(fs_file_function_replacements) / sizeof(function_replacement_data_t);
|
||||
|
||||
FSError processShimBufferForFS(FSShimWrapper *param) {
|
||||
FSError result = doForLayer(param);
|
||||
FSStatus fsResult = FS_STATUS_MEDIA_ERROR;
|
||||
if (result == FS_ERROR_FORCE_REAL_FUNCTION) {
|
||||
if (param->sync == FS_SHIM_TYPE_SYNC) {
|
||||
fsResult = FS_STATUS_MEDIA_ERROR;
|
||||
DEBUG_FUNCTION_LINE_ERR("SYNC FS API is not supported");
|
||||
OSFatal("ContentRedirectionModule: SYNC FS API is not supported");
|
||||
} else if (param->sync == FS_SHIM_TYPE_ASYNC) {
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
|
||||
switch ((FSACommandEnum) param->shim->command) {
|
||||
case FSA_COMMAND_READ_FILE: {
|
||||
auto *request = ¶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<FSMode>(request->unk0x290), static_cast<FSOpenFileFlags>(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;
|
||||
}
|
@ -314,14 +314,14 @@ bool FSWrapper::CheckFileShouldBeIgnored(std::string &path) {
|
||||
auto asPath = std::filesystem::path(path);
|
||||
|
||||
if (std::string(asPath.filename().c_str()).starts_with(deletePrefix)) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Ignore %s, filename starts with %s", path.c_str(), deletePrefix.c_str());
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Ignore %s, filename starts with %s", getName().c_str(), path.c_str(), deletePrefix.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
auto newDelPath = asPath.replace_filename(deletePrefix + asPath.filename().c_str());
|
||||
struct stat buf {};
|
||||
if (stat(newDelPath.c_str(), &buf) == 0) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Ignore %s, file %s exists", path.c_str(), newDelPath.c_str());
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Ignore %s, file %s exists", getName().c_str(), path.c_str(), newDelPath.c_str());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -400,7 +400,7 @@ FSError FSWrapper::FSReadFileWrapper(void *buffer, uint32_t size, uint32_t count
|
||||
|
||||
FSError result;
|
||||
if (read < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] read %u bytes of fd %d (FSFileHandle %08X) failed", getName().c_str(), size * count, real_fd, handle);
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Read %u bytes of fd %d (FSFileHandle %08X) failed", getName().c_str(), size * count, real_fd, handle);
|
||||
auto err = errno;
|
||||
if (err == EBADF || err == EROFS) {
|
||||
return FS_ERROR_ACCESS_ERROR;
|
||||
@ -438,10 +438,10 @@ FSError FSWrapper::FSSetPosFileWrapper(FSFileHandle handle, uint32_t pos) {
|
||||
|
||||
int real_fd = fileHandle->fd;
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] lseek fd %d (FSFileHandle %08X) to get current position for truncation", getName().c_str(), real_fd, handle);
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] lseek fd %d (FSFileHandle %08X) SEEK_SET to position %08X", getName().c_str(), real_fd, handle, pos);
|
||||
off_t newPos;
|
||||
if ((newPos = lseek(real_fd, (off_t) pos, SEEK_SET)) != pos) {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] lseek fd %d (FSFileHandle %08X) to position %u failed", getName().c_str(), real_fd, handle);
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] lseek fd %d (FSFileHandle %08X) to position %08X failed", getName().c_str(), real_fd, handle, pos);
|
||||
if (newPos < 0) {
|
||||
// TODO: read errno
|
||||
}
|
||||
@ -538,7 +538,7 @@ FSError FSWrapper::FSTruncateFileWrapper(FSFileHandle handle) {
|
||||
return result;
|
||||
}
|
||||
|
||||
FSError FSWrapper::FSWriteFileWrapper(uint8_t *buffer, uint32_t size, uint32_t count, FSFileHandle handle, [[maybe_unused]] uint32_t unk1) {
|
||||
FSError FSWrapper::FSWriteFileWrapper(const uint8_t *buffer, uint32_t size, uint32_t count, FSFileHandle handle, [[maybe_unused]] uint32_t unk1) {
|
||||
if (!isValidFileHandle(handle)) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
@ -583,7 +583,7 @@ FSError FSWrapper::FSRemoveWrapper(const char *path) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Remove %s (%s)", getName().c_str(), path, newPath.c_str());
|
||||
if (remove(newPath.c_str()) < 0) {
|
||||
auto err = errno;
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] rename failed %s (%s) errno %d", getName().c_str(), path, newPath.c_str(), err);
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Rename failed %s (%s) errno %d", getName().c_str(), path, newPath.c_str(), err);
|
||||
if (err == ENOTDIR) {
|
||||
return FS_ERROR_NOT_DIR;
|
||||
} else if (err == EACCES) {
|
||||
@ -719,7 +719,7 @@ std::shared_ptr<FileInfo> FSWrapper::getFileFromHandle(FSFileHandle handle) {
|
||||
}
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] FileInfo for handle %08X was not found. isValidFileHandle check missing?", getName().c_str(), handle);
|
||||
OSFatal("Failed to find file handle");
|
||||
OSFatal("ContentRedirectionModule: Failed to find file handle");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -731,7 +731,7 @@ std::shared_ptr<DirInfo> FSWrapper::getDirFromHandle(FSDirectoryHandle handle) {
|
||||
}
|
||||
}
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] DirInfo for handle %08X was not found. isValidDirHandle check missing?", getName().c_str(), handle);
|
||||
OSFatal("Failed to find dir handle");
|
||||
OSFatal("ContentRedirectionModule: Failed to find dir handle");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
#include <filesystem>
|
||||
|
||||
FSError FSWrapperMergeDirsWithParent::FSOpenDirWrapper(const char *path,
|
||||
FSDirectoryHandle *handle) {
|
||||
FSADirectoryHandle *handle) {
|
||||
if (handle == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] handle was NULL", getName().c_str());
|
||||
return FS_ERROR_INVALID_PARAM;
|
||||
@ -26,17 +26,17 @@ FSError FSWrapperMergeDirsWithParent::FSOpenDirWrapper(const char *path,
|
||||
dirHandle->readResultNumberOfEntries = 0;
|
||||
dirHandle->realDirHandle = 0;
|
||||
|
||||
if (pFSClient && pCmdBlock) {
|
||||
FSDirectoryHandle realHandle = 0;
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call real_FSOpenDir for %s with error_flag %08X", getName().c_str(), path, this->getHandle());
|
||||
if (clientHandle) {
|
||||
FSADirectoryHandle realHandle = 0;
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Call FSAOpenDir with %s for parent layer", getName().c_str(), path);
|
||||
// Call FSOpen with "this" as errorFlag call FSOpen for "parent" layers only.
|
||||
if (FSOpenDir(pFSClient, pCmdBlock, path, &realHandle, (FSErrorFlag) this->getHandle()) == FS_STATUS_OK) {
|
||||
if (FSAOpenDir(clientHandle, path, &realHandle) == FS_ERROR_OK) {
|
||||
dirHandle->realDirHandle = realHandle;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Failed to open real dir %s", getName().c_str(), path);
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Global FSClient or FSCmdBlock were null", getName().c_str());
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str());
|
||||
}
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
@ -48,7 +48,7 @@ bool FSWrapperMergeDirsWithParent::SkipDeletedFilesInReadDir() {
|
||||
return false;
|
||||
}
|
||||
|
||||
FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSDirectoryHandle handle, FSDirectoryEntry *entry) {
|
||||
FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSADirectoryHandle handle, FSADirectoryEntry *entry) {
|
||||
do {
|
||||
auto res = FSWrapper::FSReadDirWrapper(handle, entry);
|
||||
if (res == FS_ERROR_OK || res == FS_ERROR_END_OF_DIR) {
|
||||
@ -62,7 +62,7 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSDirectoryHandle handle,
|
||||
dirHandle->readResult = (FSDirectoryEntryEx *) malloc(sizeof(FSDirectoryEntryEx));
|
||||
if (dirHandle->readResult == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to alloc memory for %08X (handle %08X)", getName().c_str(), dirHandle.get(), handle);
|
||||
OSFatal("Failed to alloc memory for read result");
|
||||
OSFatal("ContentRedirectionModule: Failed to alloc memory for read result");
|
||||
}
|
||||
dirHandle->readResultCapacity = 1;
|
||||
}
|
||||
@ -73,11 +73,11 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSDirectoryHandle handle,
|
||||
dirHandle->readResultCapacity = newCapacity;
|
||||
if (dirHandle->readResult == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to realloc memory for %08X (handle %08X)", getName().c_str(), dirHandle.get(), handle);
|
||||
OSFatal("Failed to alloc memory for read result");
|
||||
OSFatal("ContentRedirectionModule: Failed to alloc memory for read result");
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(&dirHandle->readResult[dirHandle->readResultNumberOfEntries].realEntry, entry, sizeof(FSDirectoryEntry));
|
||||
memcpy(&dirHandle->readResult[dirHandle->readResultNumberOfEntries].realEntry, entry, sizeof(FSADirectoryEntry));
|
||||
dirHandle->readResultNumberOfEntries++;
|
||||
|
||||
/**
|
||||
@ -95,19 +95,19 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSDirectoryHandle handle,
|
||||
} else if (res == FS_ERROR_END_OF_DIR) {
|
||||
// Read the real directory.
|
||||
if (dirHandle->realDirHandle != 0) {
|
||||
if (pFSClient && pCmdBlock) {
|
||||
FSDirectoryEntry realDirEntry;
|
||||
FSStatus readDirResult;
|
||||
if (clientHandle) {
|
||||
FSADirectoryEntry realDirEntry;
|
||||
FSError readDirResult;
|
||||
while (true) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call real_FSReadDir for %08X with error_flag %08X", getName().c_str(), dirHandle->realDirHandle, (uint32_t) this->getHandle());
|
||||
readDirResult = FSReadDir(pFSClient, pCmdBlock, dirHandle->realDirHandle, &realDirEntry, (FSErrorFlag) (uint32_t) this->getHandle());
|
||||
if (readDirResult == FS_STATUS_OK) {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Call FSReadDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle);
|
||||
readDirResult = FSAReadDir(clientHandle, dirHandle->realDirHandle, &realDirEntry);
|
||||
if (readDirResult == FS_ERROR_OK) {
|
||||
bool found = false;
|
||||
auto nameDeleted = deletePrefix + realDirEntry.name;
|
||||
for (int i = 0; i < dirHandle->readResultNumberOfEntries; i++) {
|
||||
auto curResult = &dirHandle->readResult[i];
|
||||
|
||||
// Don't return file that are "deleted"
|
||||
// Don't return files that are "deleted"
|
||||
if (strcmp(curResult->realEntry.name, nameDeleted.c_str()) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
@ -120,11 +120,11 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSDirectoryHandle handle,
|
||||
}
|
||||
// If it's new we can use it :)
|
||||
if (!found) {
|
||||
memcpy(entry, &realDirEntry, sizeof(FSDirectoryEntry));
|
||||
memcpy(entry, &realDirEntry, sizeof(FSADirectoryEntry));
|
||||
res = FS_ERROR_OK;
|
||||
break;
|
||||
}
|
||||
} else if (readDirResult == FS_STATUS_END) {
|
||||
} else if (readDirResult == FS_ERROR_END_OF_DIR) {
|
||||
res = FS_ERROR_END_OF_DIR;
|
||||
break;
|
||||
} else {
|
||||
@ -134,7 +134,7 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSDirectoryHandle handle,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Global FSClient or FSCmdBlock were null", getName().c_str());
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -145,7 +145,7 @@ FSError FSWrapperMergeDirsWithParent::FSReadDirWrapper(FSDirectoryHandle handle,
|
||||
} while (true);
|
||||
}
|
||||
|
||||
FSError FSWrapperMergeDirsWithParent::FSCloseDirWrapper(FSDirectoryHandle handle) {
|
||||
FSError FSWrapperMergeDirsWithParent::FSCloseDirWrapper(FSADirectoryHandle handle) {
|
||||
auto res = FSWrapper::FSCloseDirWrapper(handle);
|
||||
|
||||
if (res == FS_ERROR_OK) {
|
||||
@ -155,17 +155,17 @@ FSError FSWrapperMergeDirsWithParent::FSCloseDirWrapper(FSDirectoryHandle handle
|
||||
}
|
||||
auto dirHandle = getDirExFromHandle(handle);
|
||||
if (dirHandle->realDirHandle != 0) {
|
||||
if (pFSClient && pCmdBlock) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call FSCloseDir for %08X with error_flag %08X (this)", getName().c_str(), dirHandle->realDirHandle, (uint32_t) this->getHandle());
|
||||
auto realResult = FSCloseDir(pFSClient, pCmdBlock, dirHandle->realDirHandle, (FSErrorFlag) (uint32_t) this->getHandle());
|
||||
if (realResult == FS_STATUS_OK) {
|
||||
if (clientHandle) {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Call FSCloseDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle);
|
||||
auto realResult = FSACloseDir(clientHandle, dirHandle->realDirHandle);
|
||||
if (realResult == FS_ERROR_OK) {
|
||||
dirHandle->realDirHandle = 0;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to close realDirHandle %d: res %d", getName().c_str(), dirHandle->realDirHandle, realResult);
|
||||
return realResult == FS_STATUS_CANCELLED ? FS_ERROR_CANCELLED : FS_ERROR_MEDIA_ERROR;
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to close realDirHandle %d: res %d", getName().c_str(), dirHandle->realDirHandle, -1);
|
||||
return realResult == FS_ERROR_CANCELLED ? FS_ERROR_CANCELLED : FS_ERROR_MEDIA_ERROR;
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Global FSClient or FSCmdBlock were null", getName().c_str());
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ FSError FSWrapperMergeDirsWithParent::FSCloseDirWrapper(FSDirectoryHandle handle
|
||||
return res;
|
||||
}
|
||||
|
||||
FSError FSWrapperMergeDirsWithParent::FSRewindDirWrapper(FSDirectoryHandle handle) {
|
||||
FSError FSWrapperMergeDirsWithParent::FSRewindDirWrapper(FSADirectoryHandle handle) {
|
||||
auto res = FSWrapper::FSRewindDirWrapper(handle);
|
||||
if (res == FS_ERROR_OK) {
|
||||
if (!isValidDirHandle(handle)) {
|
||||
@ -198,15 +198,15 @@ FSError FSWrapperMergeDirsWithParent::FSRewindDirWrapper(FSDirectoryHandle handl
|
||||
}
|
||||
|
||||
if (dirHandle->realDirHandle != 0) {
|
||||
if (pFSClient && pCmdBlock) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call real_FSRewindDir for %08X with error_flag %08X (this->getHandle())", getName().c_str(), dirHandle->realDirHandle, (uint32_t) this->getHandle());
|
||||
if (FSRewindDir(pFSClient, pCmdBlock, dirHandle->realDirHandle, (FSErrorFlag) (uint32_t) this->getHandle()) == FS_STATUS_OK) {
|
||||
if (clientHandle) {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Call FSARewindDir with %08X for parent layer", getName().c_str(), dirHandle->realDirHandle);
|
||||
if (FSARewindDir(clientHandle, dirHandle->realDirHandle) == FS_ERROR_OK) {
|
||||
dirHandle->realDirHandle = 0;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to rewind dir for realDirHandle %08X", getName().c_str(), dirHandle->realDirHandle);
|
||||
}
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Global FSClient or FSCmdBlock were null", getName().c_str());
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] clientHandle was null", getName().c_str());
|
||||
}
|
||||
}
|
||||
OSMemoryBarrier();
|
||||
@ -222,39 +222,29 @@ FSWrapperMergeDirsWithParent::FSWrapperMergeDirsWithParent(const std::string &na
|
||||
replaceWithPath,
|
||||
fallbackOnError,
|
||||
false) {
|
||||
pFSClient = new (std::nothrow) FSClient;
|
||||
pCmdBlock = new (std::nothrow) FSCmdBlock;
|
||||
if (pFSClient == nullptr || pCmdBlock == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to alloc client or cmdBlock", name.c_str());
|
||||
freeFSClient();
|
||||
this->clientHandle = FSAAddClient(nullptr);
|
||||
if (clientHandle < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] FSAClientHandle failed: %s (%d)", name.c_str(), FSAGetStatusStr(static_cast<FSError>(clientHandle)), clientHandle);
|
||||
clientHandle = 0;
|
||||
}
|
||||
if (FSAddClient(pFSClient, FS_ERROR_FLAG_ALL) != FS_STATUS_OK) {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] Failed to addClient");
|
||||
freeFSClient();
|
||||
}
|
||||
FSInitCmdBlock(pCmdBlock);
|
||||
}
|
||||
|
||||
FSWrapperMergeDirsWithParent::~FSWrapperMergeDirsWithParent() {
|
||||
freeFSClient();
|
||||
}
|
||||
|
||||
void FSWrapperMergeDirsWithParent::freeFSClient() {
|
||||
if (pFSClient) {
|
||||
FSDelClient(pFSClient, FS_ERROR_FLAG_ALL);
|
||||
if (clientHandle) {
|
||||
FSError res;
|
||||
if ((res = FSADelClient(clientHandle)) != FS_ERROR_OK) {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] FSADelClient failed: %s (%d)", FSAGetStatusStr(res), res);
|
||||
}
|
||||
clientHandle = 0;
|
||||
}
|
||||
delete pFSClient;
|
||||
delete pCmdBlock;
|
||||
pFSClient = nullptr;
|
||||
pCmdBlock = nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<DirInfoEx> FSWrapperMergeDirsWithParent::getDirExFromHandle(FSDirectoryHandle handle) {
|
||||
std::shared_ptr<DirInfoEx> FSWrapperMergeDirsWithParent::getDirExFromHandle(FSADirectoryHandle handle) {
|
||||
auto dir = std::dynamic_pointer_cast<DirInfoEx>(getDirFromHandle(handle));
|
||||
|
||||
if (!dir) {
|
||||
DEBUG_FUNCTION_LINE_ERR("[%s] dynamic_pointer_cast<DirInfoEx *>(%08X) failed", getName().c_str(), handle);
|
||||
OSFatal("dynamic_pointer_cast<DirInfoEx *> failed");
|
||||
OSFatal("ContentRedirectionModule: dynamic_pointer_cast<DirInfoEx *> failed");
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
|
@ -27,10 +27,12 @@ public:
|
||||
|
||||
bool SkipDeletedFilesInReadDir() override;
|
||||
|
||||
uint32_t getLayerId() override {
|
||||
return (uint32_t) clientHandle;
|
||||
}
|
||||
|
||||
private:
|
||||
void freeFSClient();
|
||||
FSClient *pFSClient;
|
||||
FSCmdBlock *pCmdBlock;
|
||||
FSAClientHandle clientHandle;
|
||||
|
||||
std::shared_ptr<DirInfoEx> getDirExFromHandle(FSDirectoryHandle handle);
|
||||
};
|
||||
|
@ -6,19 +6,17 @@
|
||||
#include "utils/utils.h"
|
||||
#include <coreinit/cache.h>
|
||||
#include <coreinit/filesystem_fsa.h>
|
||||
#include <malloc.h>
|
||||
#include <map>
|
||||
#include <unistd.h>
|
||||
|
||||
std::mutex workingDirMutexFS;
|
||||
std::map<uint32_t, std::string> workingDirsFS;
|
||||
|
||||
std::mutex workingDirMutexFSA;
|
||||
std::map<uint32_t, std::string> workingDirsFSA;
|
||||
std::mutex workingDirMutex;
|
||||
std::map<FSAClientHandle, std::string> workingDirs;
|
||||
|
||||
std::mutex fsLayerMutex;
|
||||
std::vector<std::unique_ptr<IFSWrapper>> fsLayers;
|
||||
|
||||
std::string getFullPathGeneric(uint32_t client, const char *path, std::mutex &mutex, std::map<uint32_t, std::string> &map) {
|
||||
std::string getFullPathGeneric(FSAClientHandle client, const char *path, std::mutex &mutex, std::map<FSAClientHandle, std::string> &map) {
|
||||
std::lock_guard<std::mutex> workingDirLock(mutex);
|
||||
|
||||
std::string res;
|
||||
@ -26,7 +24,7 @@ std::string getFullPathGeneric(uint32_t client, const char *path, std::mutex &mu
|
||||
if (path[0] != '/' && path[0] != '\\') {
|
||||
if (map.count(client) == 0) {
|
||||
DEBUG_FUNCTION_LINE_WARN("No working dir found for client %08X, fallback to \"/\"", client);
|
||||
workingDirsFS[client] = "/";
|
||||
workingDirs[client] = "/";
|
||||
}
|
||||
res = string_format("%s%s", map.at(client).c_str(), path);
|
||||
} else {
|
||||
@ -38,7 +36,7 @@ std::string getFullPathGeneric(uint32_t client, const char *path, std::mutex &mu
|
||||
return res;
|
||||
}
|
||||
|
||||
void setWorkingDirGeneric(uint32_t client, const char *path, std::mutex &mutex, std::map<uint32_t, std::string> &map) {
|
||||
void setWorkingDirGeneric(FSAClientHandle client, const char *path, std::mutex &mutex, std::map<FSAClientHandle, std::string> &map) {
|
||||
if (!path) {
|
||||
DEBUG_FUNCTION_LINE_WARN("Path was NULL");
|
||||
return;
|
||||
@ -55,30 +53,18 @@ void setWorkingDirGeneric(uint32_t client, const char *path, std::mutex &mutex,
|
||||
}
|
||||
|
||||
|
||||
std::string getFullPathForFSClient(FSClient *pClient, const char *path) {
|
||||
return getFullPathGeneric((uint32_t) pClient, path, workingDirMutexFS, workingDirsFS);
|
||||
std::string getFullPath(FSAClientHandle pClient, const char *path) {
|
||||
return getFullPathGeneric(pClient, path, workingDirMutex, workingDirs);
|
||||
}
|
||||
|
||||
void setWorkingDirForFSClient(FSClient *client, const char *path) {
|
||||
setWorkingDirGeneric((uint32_t) client, path, workingDirMutexFS, workingDirsFS);
|
||||
}
|
||||
|
||||
std::string getFullPathForFSAClient(FSAClientHandle client, const char *path) {
|
||||
return getFullPathGeneric((uint32_t) client, path, workingDirMutexFSA, workingDirsFSA);
|
||||
}
|
||||
|
||||
void setWorkingDirForFSAClient(FSAClientHandle client, const char *path) {
|
||||
setWorkingDirGeneric(client, path, workingDirMutexFSA, workingDirsFSA);
|
||||
void setWorkingDir(FSAClientHandle client, const char *path) {
|
||||
setWorkingDirGeneric(client, path, workingDirMutex, workingDirs);
|
||||
}
|
||||
|
||||
void clearFSLayer() {
|
||||
{
|
||||
std::lock_guard<std::mutex> workingDirLock(workingDirMutexFS);
|
||||
workingDirsFS.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> workingDirLock(workingDirMutexFSA);
|
||||
workingDirsFSA.clear();
|
||||
std::lock_guard<std::mutex> workingDirLock(workingDirMutex);
|
||||
workingDirs.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> layerLock(fsLayerMutex);
|
||||
@ -86,62 +72,32 @@ void clearFSLayer() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FSError doForLayerFSA(const std::function<FSError()> &real_function,
|
||||
const std::function<FSError(std::unique_ptr<IFSWrapper> &layer)> &layer_callback,
|
||||
const std::function<FSError(std::unique_ptr<IFSWrapper> &layer, FSError)> &result_handler) {
|
||||
|
||||
|
||||
std::lock_guard<std::mutex> lock(fsLayerMutex);
|
||||
if (!fsLayers.empty()) {
|
||||
uint32_t startIndex = fsLayers.size();
|
||||
|
||||
if (startIndex > 0) {
|
||||
for (uint32_t i = startIndex; i > 0; i--) {
|
||||
auto &layer = fsLayers[i - 1];
|
||||
if (!layer->isActive()) {
|
||||
continue;
|
||||
}
|
||||
FSError layerResult = layer_callback(layer);
|
||||
if (layerResult != FS_ERROR_FORCE_PARENT_LAYER) {
|
||||
auto result = layerResult >= 0 ? layerResult : (FSError) ((layerResult & FS_ERROR_REAL_MASK) | FS_ERROR_EXTRA_MASK);
|
||||
|
||||
if (result < FS_ERROR_OK && result != FS_ERROR_END_OF_DIR && result != FS_ERROR_END_OF_FILE && result != FS_ERROR_CANCELLED) {
|
||||
if (layer->fallbackOnError()) {
|
||||
// Only fallback if FS_ERROR_FORCE_NO_FALLBACK flag is not set.
|
||||
if (static_cast<FSError>(layerResult & FS_ERROR_EXTRA_MASK) != FS_ERROR_FORCE_NO_FALLBACK) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result_handler(layer, result);
|
||||
}
|
||||
}
|
||||
bool sendMessageToThread(FSShimWrapperMessage *param) {
|
||||
auto *curThread = &gThreadData[OSGetCoreId()];
|
||||
if (curThread->setup) {
|
||||
OSMessage send;
|
||||
send.message = param;
|
||||
send.args[0] = FS_IO_QUEUE_COMMAND_PROCESS_FS_COMMAND;
|
||||
auto res = OSSendMessage(&curThread->queue, &send, OS_MESSAGE_FLAGS_NONE);
|
||||
if (!res) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Message Queue for ContentRedirection IO Thread is full");
|
||||
OSFatal("ContentRedirectionModule: Message Queue for ContentRedirection IO Thread is full");
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Thread not setup");
|
||||
OSFatal("ContentRedirectionModule: Thread not setup");
|
||||
}
|
||||
|
||||
return real_function();
|
||||
return false;
|
||||
}
|
||||
|
||||
// FUN_0204cc20
|
||||
#define fsClientHandleFatalErrorAndBlock ((void (*)(FSClientBody *, uint32_t))(0x101C400 + 0x4cc20))
|
||||
#define fsaDecodeFsaStatusToFsStatus ((FSStatus(*)(FSError))(0x101C400 + 0x4b148))
|
||||
|
||||
FSStatus doForLayer(FSClient *client,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSErrorFlag errorMask)> &real_function,
|
||||
const std::function<FSError(std::unique_ptr<IFSWrapper> &layer)> &layer_callback,
|
||||
const std::function<FSStatus(std::unique_ptr<IFSWrapper> &layer, FSStatus)> &result_handler) {
|
||||
FSErrorFlag realErrorMask = errorMask;
|
||||
|
||||
FSError doForLayer(FSShimWrapper *param) {
|
||||
std::lock_guard<std::mutex> lock(fsLayerMutex);
|
||||
if (!fsLayers.empty()) {
|
||||
uint32_t startIndex = fsLayers.size();
|
||||
for (uint32_t i = fsLayers.size(); i > 0; i--) {
|
||||
if ((uint32_t) fsLayers[i - 1]->getHandle() == errorMask) {
|
||||
startIndex = i - 1;
|
||||
realErrorMask = FS_ERROR_FLAG_ALL;
|
||||
if ((uint32_t) fsLayers[i - 1]->getLayerId() == param->shim->clientHandle) {
|
||||
startIndex = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -152,12 +108,217 @@ FSStatus doForLayer(FSClient *client,
|
||||
if (!layer->isActive()) {
|
||||
continue;
|
||||
}
|
||||
FSError layerResult = layer_callback(layer);
|
||||
auto layerResult = FS_ERROR_FORCE_PARENT_LAYER;
|
||||
auto command = (FSACommandEnum) param->shim->command;
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Waddress-of-packed-member"
|
||||
switch (command) {
|
||||
case FSA_COMMAND_OPEN_DIR: {
|
||||
auto *request = ¶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<FSStatus>(layerResult) : fsaDecodeFsaStatusToFsStatus(maskedResult);
|
||||
auto result = layerResult >= 0 ? layerResult : maskedResult;
|
||||
|
||||
if (result < FS_STATUS_OK && result != FS_STATUS_END && result != FS_STATUS_CANCELLED) {
|
||||
if (result < FS_ERROR_OK && result != FS_ERROR_END_OF_FILE && result != FS_ERROR_END_OF_DIR && result != FS_ERROR_CANCELLED) {
|
||||
if (layer->fallbackOnError()) {
|
||||
// Only fallback if FS_ERROR_FORCE_NO_FALLBACK flag is not set.
|
||||
if (static_cast<FSError>(layerResult & FS_ERROR_EXTRA_MASK) != FS_ERROR_FORCE_NO_FALLBACK) {
|
||||
@ -165,78 +326,36 @@ FSStatus doForLayer(FSClient *client,
|
||||
}
|
||||
}
|
||||
}
|
||||
if (param->sync == FS_SHIM_TYPE_SYNC) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Return with result %08X %s", layer->getName().c_str(), result, result <= 0 ? FSAGetStatusStr(result) : "");
|
||||
return result;
|
||||
} else if (param->sync == FS_SHIM_TYPE_ASYNC) {
|
||||
// convert to IOSError
|
||||
auto err = (IOSError) result;
|
||||
if (result == FS_ERROR_INVALID_BUFFER) {
|
||||
err = IOS_ERROR_ACCESS;
|
||||
} else if (result == FS_ERROR_INVALID_CLIENTHANDLE) {
|
||||
err = IOS_ERROR_INVALID;
|
||||
} else if (result == FS_ERROR_BUSY) {
|
||||
err = IOS_ERROR_QFULL;
|
||||
}
|
||||
|
||||
if (result >= FS_STATUS_OK || result == FS_STATUS_END || result == FS_STATUS_CANCELLED) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Returned %08X by %s", result, layer->getName().c_str());
|
||||
return result_handler(layer, result);
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("[%s] Call async callback :) with result %08X %s", layer->getName().c_str(), err, result <= 0 ? FSAGetStatusStr(result) : "");
|
||||
param->asyncFS.callback(err, ¶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<FSErrorFlag>((realErrorMask & FS_ERROR_FLAG_REAL_MASK) | FS_ERROR_FLAG_FORCE_REAL);
|
||||
return real_function(mask);
|
||||
return FS_ERROR_FORCE_REAL_FUNCTION;
|
||||
}
|
||||
|
||||
FSCmdBlockBody *fsCmdBlockGetBody(FSCmdBlock *cmdBlock) {
|
||||
@ -258,16 +377,14 @@ FSClientBody *fsClientGetBody(FSClient *client) {
|
||||
return body;
|
||||
}
|
||||
|
||||
|
||||
FSStatus send_result_async(FSClient *client, FSCmdBlock *block, FSAsyncData *asyncData, FSStatus status) {
|
||||
FSStatus handleAsyncResult(FSClient *client, FSCmdBlock *block, FSAsyncData *asyncData, FSStatus status) {
|
||||
if (asyncData->callback != nullptr) {
|
||||
if (asyncData->ioMsgQueue != nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("callback and ioMsgQueue both set.");
|
||||
return FS_STATUS_FATAL_ERROR;
|
||||
OSFatal("ContentRedirectionModule: callback and ioMsgQueue both set.");
|
||||
}
|
||||
// userCallbacks are called in the DefaultAppIOQueue.
|
||||
asyncData->ioMsgQueue = OSGetDefaultAppIOQueue();
|
||||
//DEBUG_FUNCTION_LINE("Force to OSGetDefaultAppIOQueue (%08X)", asyncData->ioMsgQueue);
|
||||
}
|
||||
|
||||
if (asyncData->ioMsgQueue != nullptr) {
|
||||
@ -284,6 +401,7 @@ FSStatus send_result_async(FSClient *client, FSCmdBlock *block, FSAsyncData *asy
|
||||
result->block = block;
|
||||
result->status = status;
|
||||
|
||||
OSMemoryBarrier();
|
||||
while (!OSSendMessage(asyncData->ioMsgQueue, (OSMessage *) &(result->ioMsg), OS_MESSAGE_FLAGS_NONE)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to send message");
|
||||
}
|
||||
@ -302,6 +420,7 @@ int64_t readIntoBuffer(int32_t handle, void *buffer, size_t size, size_t count)
|
||||
int32_t curResult;
|
||||
int64_t totalSize = 0;
|
||||
while (sizeToRead > 0) {
|
||||
|
||||
curResult = read(handle, newBuffer, sizeToRead);
|
||||
if (curResult < 0) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Reading %08X bytes from handle %08X failed. result %08X errno: %d ", size * count, handle, curResult, errno);
|
||||
@ -317,9 +436,9 @@ int64_t readIntoBuffer(int32_t handle, void *buffer, size_t size, size_t count)
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
int64_t writeFromBuffer(int32_t handle, void *buffer, size_t size, size_t count) {
|
||||
int64_t writeFromBuffer(int32_t handle, const void *buffer, size_t size, size_t count) {
|
||||
auto sizeToWrite = size * count;
|
||||
void *ptr = buffer;
|
||||
auto *ptr = buffer;
|
||||
int32_t curResult;
|
||||
int64_t totalSize = 0;
|
||||
while (sizeToWrite > 0) {
|
||||
@ -337,3 +456,129 @@ int64_t writeFromBuffer(int32_t handle, void *buffer, size_t size, size_t count)
|
||||
}
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
FSIOThreadData gThreadData[3];
|
||||
bool gThreadsRunning = false;
|
||||
|
||||
static int32_t fsIOthreadCallback([[maybe_unused]] int argc, const char **argv) {
|
||||
auto *magic = ((FSIOThreadData *) argv);
|
||||
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Hello from IO Thread for core: %d", OSGetCoreId());
|
||||
constexpr int32_t messageSize = sizeof(magic->messages) / sizeof(magic->messages[0]);
|
||||
OSInitMessageQueue(&magic->queue, magic->messages, messageSize);
|
||||
|
||||
OSMessage recv;
|
||||
while (OSReceiveMessage(&magic->queue, &recv, OS_MESSAGE_FLAGS_BLOCKING)) {
|
||||
if (recv.args[0] == FS_IO_QUEUE_COMMAND_STOP) {
|
||||
DEBUG_FUNCTION_LINE_VERBOSE("Received break command! Stop thread");
|
||||
break;
|
||||
} else if (recv.args[0] == FS_IO_QUEUE_COMMAND_PROCESS_FS_COMMAND) {
|
||||
auto *message = (FSShimWrapperMessage *) recv.message;
|
||||
auto *param = (FSShimWrapper *) message->param;
|
||||
FSError res = FS_ERROR_MEDIA_ERROR;
|
||||
auto syncType = param->sync;
|
||||
|
||||
if (param->api == FS_SHIM_API_FS) {
|
||||
res = processShimBufferForFS(param);
|
||||
} else if (param->api == FS_SHIM_API_FSA) {
|
||||
res = processShimBufferForFSA(param);
|
||||
} else {
|
||||
DEBUG_FUNCTION_LINE_ERR("Incompatible API type %d", param->api);
|
||||
OSFatal("ContentRedirectionModule: Incompatible API type");
|
||||
}
|
||||
// param is free'd at this point!!!
|
||||
if (syncType == FS_SHIM_TYPE_SYNC) {
|
||||
// For sync messages we can't (and don't need to) free "message", because it contains the queue we're about to use.
|
||||
// But this is not a problem because it's sync anyway.
|
||||
OSMessage send;
|
||||
send.args[0] = FS_IO_QUEUE_SYNC_RESULT;
|
||||
send.args[1] = (uint32_t) res;
|
||||
if (!OSSendMessage(&message->messageQueue, &send, OS_MESSAGE_FLAGS_NONE)) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to send message");
|
||||
OSFatal("ContentRedirectionModule: Failed to send message");
|
||||
}
|
||||
|
||||
} else if (syncType == FS_SHIM_TYPE_ASYNC) {
|
||||
// If it's async we need to clean up "message" :)
|
||||
free(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void startFSIOThreads() {
|
||||
int32_t threadAttributes[] = {OS_THREAD_ATTRIB_AFFINITY_CPU0, OS_THREAD_ATTRIB_AFFINITY_CPU1, OS_THREAD_ATTRIB_AFFINITY_CPU2};
|
||||
auto stackSize = 16 * 1024;
|
||||
|
||||
int coreId = 0;
|
||||
for (int core : threadAttributes) {
|
||||
auto *threadData = &gThreadData[coreId];
|
||||
memset(threadData, 0, sizeof(*threadData));
|
||||
threadData->setup = false;
|
||||
threadData->thread = (OSThread *) memalign(8, sizeof(OSThread));
|
||||
if (!threadData->thread) {
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate threadData");
|
||||
OSFatal("ContentRedirectionModule: Failed to allocate IO Thread");
|
||||
continue;
|
||||
}
|
||||
threadData->stack = (uint8_t *) memalign(0x20, stackSize);
|
||||
if (!threadData->thread) {
|
||||
free(threadData->thread);
|
||||
DEBUG_FUNCTION_LINE_ERR("Failed to allocate threadData stack");
|
||||
OSFatal("ContentRedirectionModule: Failed to allocate IO Thread stack");
|
||||
continue;
|
||||
}
|
||||
|
||||
OSMemoryBarrier();
|
||||
|
||||
if (!OSCreateThread(threadData->thread, &fsIOthreadCallback, 1, (char *) threadData, reinterpret_cast<void *>((uint32_t) threadData->stack + stackSize), stackSize, 0, core)) {
|
||||
free(threadData->thread);
|
||||
free(threadData->stack);
|
||||
threadData->setup = false;
|
||||
DEBUG_FUNCTION_LINE_ERR("failed to create threadData");
|
||||
OSFatal("ContentRedirectionModule: Failed to create threadData");
|
||||
}
|
||||
|
||||
strncpy(threadData->threadName, string_format("ContentRedirection IO Thread %d", coreId).c_str(), sizeof(threadData->threadName) - 1);
|
||||
OSSetThreadName(threadData->thread, threadData->threadName);
|
||||
OSResumeThread(threadData->thread);
|
||||
threadData->setup = true;
|
||||
coreId++;
|
||||
}
|
||||
|
||||
gThreadsRunning = true;
|
||||
OSMemoryBarrier();
|
||||
}
|
||||
|
||||
void stopFSIOThreads() {
|
||||
if (!gThreadsRunning) {
|
||||
return;
|
||||
}
|
||||
for (auto &gThread : gThreadData) {
|
||||
auto *thread = &gThread;
|
||||
if (!thread->setup) {
|
||||
continue;
|
||||
}
|
||||
OSMessage message;
|
||||
message.args[0] = FS_IO_QUEUE_COMMAND_STOP;
|
||||
OSSendMessage(&thread->queue, &message, OS_MESSAGE_FLAGS_NONE);
|
||||
|
||||
if (OSIsThreadSuspended(thread->thread)) {
|
||||
OSResumeThread(thread->thread);
|
||||
}
|
||||
|
||||
OSJoinThread(thread->thread, nullptr);
|
||||
if (thread->stack) {
|
||||
free(thread->stack);
|
||||
thread->stack = nullptr;
|
||||
}
|
||||
if (thread->thread) {
|
||||
free(thread->thread);
|
||||
thread->thread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
gThreadsRunning = false;
|
||||
}
|
124
src/FileUtils.h
124
src/FileUtils.h
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "IFSWrapper.h"
|
||||
#include "utils/logger.h"
|
||||
#include <coreinit/core.h>
|
||||
#include <coreinit/filesystem.h>
|
||||
#include <coreinit/filesystem_fsa.h>
|
||||
#include <functional>
|
||||
@ -8,66 +10,102 @@
|
||||
#include <romfs_dev.h>
|
||||
#include <string>
|
||||
|
||||
struct FSIOThreadData {
|
||||
OSThread *thread;
|
||||
void *stack;
|
||||
OSMessageQueue queue;
|
||||
OSMessage messages[0x10];
|
||||
bool setup;
|
||||
char threadName[0x50];
|
||||
};
|
||||
|
||||
struct AsyncParamFS {
|
||||
FSClient *client;
|
||||
FSCmdBlock *block;
|
||||
FSErrorFlag errorMask;
|
||||
FSAsyncData asyncData;
|
||||
IOSAsyncCallbackFn callback;
|
||||
};
|
||||
|
||||
typedef enum FSShimSyncType {
|
||||
FS_SHIM_TYPE_SYNC = 1,
|
||||
FS_SHIM_TYPE_ASYNC = 2
|
||||
} FSShimSyncType;
|
||||
|
||||
typedef enum FSShimApiType {
|
||||
FS_SHIM_API_FS = 1,
|
||||
FS_SHIM_API_FSA = 2
|
||||
} FSShimApiType;
|
||||
|
||||
struct FSShimWrapper {
|
||||
FSAShimBuffer *shim;
|
||||
AsyncParamFS asyncFS;
|
||||
FSShimSyncType sync;
|
||||
FSShimApiType api;
|
||||
};
|
||||
|
||||
struct FSShimWrapperMessage {
|
||||
FSShimWrapper *param;
|
||||
OSMessageQueue messageQueue;
|
||||
OSMessage messages[0x1];
|
||||
};
|
||||
|
||||
#define FS_IO_QUEUE_COMMAND_STOP 0x13371337
|
||||
#define FS_IO_QUEUE_COMMAND_PROCESS_FS_COMMAND 0x42424242
|
||||
#define FS_IO_QUEUE_SYNC_RESULT 0x43434343
|
||||
|
||||
extern bool gThreadsRunning;
|
||||
extern FSIOThreadData gThreadData[3];
|
||||
extern std::mutex fsLayerMutex;
|
||||
extern std::vector<std::unique_ptr<IFSWrapper>> fsLayers;
|
||||
|
||||
#define SYNC_RESULT_HANDLER [filename = __FILENAME__, func = __FUNCTION__, line = __LINE__]([[maybe_unused]] std::unique_ptr<IFSWrapper> &layer, FSStatus res) -> FSStatus { \
|
||||
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Sync result was %d", res); \
|
||||
return res; \
|
||||
}
|
||||
#define fsaShimPrepareRequestReadFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, uint8_t * buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, FSAReadFlag readFlags))(0x101C400 + 0x436cc))
|
||||
#define fsaShimPrepareRequestWriteFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const uint8_t *buffer, uint32_t size, uint32_t count, uint32_t pos, FSFileHandle handle, FSAWriteFlag writeFlags))(0x101C400 + 0x437f4))
|
||||
#define fsaShimPrepareRequestOpenFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *path, const char *mode, FSMode createMode, FSOpenFileFlags openFlag, uint32_t preallocSize))(0x101C400 + 0x43588))
|
||||
#define fsaShimPrepareRequestCloseFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSFileHandle handle))(0x101C400 + 0x43a00))
|
||||
#define fsaShimPrepareRequestStatFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSFileHandle handle))(0x101C400 + 0x43998))
|
||||
#define fsaShimPrepareRequestQueryInfo ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *path, FSAQueryInfoType type))(0x101C400 + 0x44118))
|
||||
#define fsaShimPrepareRequestSetPos ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSFileHandle handle, FSAFilePosition position))(0x101C400 + 0x43930))
|
||||
#define fsaShimPrepareRequestGetPos ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSFileHandle handle))(0x101C400 + 0x438fc))
|
||||
#define fsaShimPrepareRequestIsEof ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSFileHandle handle))(0x101C400 + 0x43964))
|
||||
#define fsaShimPrepareRequestTruncate ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSFileHandle handle))(0x101C400 + 0x43a34))
|
||||
#define fsaShimPrepareRequestRemove ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *))(0x101C400 + 0x43aa8))
|
||||
#define fsaShimPrepareRequestRename ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *, const char *))(0x101C400 + 0x43bc0))
|
||||
#define fsaShimPrepareRequestFlushFile ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSFileHandle handle))(0x101C400 + 0x439cc))
|
||||
#define fsaShimPrepareRequestChangeMode ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *path, FSMode mode, FSMode modeMask))(0x101C400 + 0x43ff4))
|
||||
|
||||
#define ASYNC_RESULT_HANDLER [c = client, b = block, a = asyncData, filename = __FILENAME__, func = __FUNCTION__, line = __LINE__]([[maybe_unused]] std::unique_ptr<IFSWrapper> &layer, FSStatus res) -> FSStatus { \
|
||||
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Async result was %d", res); \
|
||||
return send_result_async(c, b, a, res); \
|
||||
}
|
||||
#define fsaShimPrepareRequestOpenDir ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *path))(0x101C400 + 0x43458))
|
||||
#define fsaShimPrepareRequestReadDir ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSDirectoryHandle handle))(0x101C400 + 0x434ec))
|
||||
#define fsaShimPrepareRequestCloseDir ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSDirectoryHandle handle))(0x101C400 + 0x43554))
|
||||
#define fsaShimPrepareRequestRewindDir ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, FSDirectoryHandle handle))(0x101C400 + 0x43520))
|
||||
#define fsaShimPrepareRequestMakeDir ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *path, FSMode mode))(0x101C400 + 0x43314))
|
||||
#define fsaShimPrepareRequestChangeDir ((FSError(*)(FSAShimBuffer * shim, IOSHandle clientHandle, const char *path))(0x101C400 + 0x43258))
|
||||
|
||||
#define SYNC_RESULT_HANDLER_FSA [filename = __FILENAME__, func = __FUNCTION__, line = __LINE__]([[maybe_unused]] std::unique_ptr<IFSWrapper> &layer, FSError res) -> FSError { \
|
||||
DEBUG_FUNCTION_LINE_VERBOSE_EX(filename, func, line, "Sync result was %d", res); \
|
||||
return res; \
|
||||
}
|
||||
#define fsaDecodeFsaStatusToFsStatus ((FSStatus(*)(FSError))(0x101C400 + 0x4b148))
|
||||
#define fsClientHandleFatalError ((void (*)(FSClientBody *, uint32_t))(0x101C400 + 0x4b34c))
|
||||
#define fsClientHandleFatalErrorAndBlock ((void (*)(FSClientBody *, uint32_t))(0x101C400 + 0x4cc20))
|
||||
|
||||
#define FS_ERROR_FLAG_EXTRA_MASK (FSErrorFlag) 0xFFFF0000
|
||||
#define FS_ERROR_FLAG_REAL_MASK (FSErrorFlag) 0x0000FFFF
|
||||
#define FS_ERROR_FLAG_FORCE_REAL (FSErrorFlag) 0xFEDC0000
|
||||
extern "C" FSError __FSAShimDecodeIosErrorToFsaStatus(IOSHandle handle, IOSError err);
|
||||
|
||||
static inline FSErrorFlag getRealErrorFlag(FSErrorFlag flag) {
|
||||
auto res = flag & FS_ERROR_FLAG_REAL_MASK;
|
||||
if (res == 0x0000FFFF) {
|
||||
return FS_ERROR_FLAG_ALL;
|
||||
}
|
||||
return static_cast<FSErrorFlag>(res);
|
||||
}
|
||||
|
||||
static inline FSErrorFlag isForceRealFunction(FSErrorFlag flag) {
|
||||
return static_cast<FSErrorFlag>((flag & FS_ERROR_FLAG_EXTRA_MASK) == FS_ERROR_FLAG_FORCE_REAL);
|
||||
}
|
||||
bool sendMessageToThread(FSShimWrapperMessage *param);
|
||||
|
||||
void clearFSLayer();
|
||||
|
||||
std::string getFullPathForFSClient(FSClient *pClient, const char *path);
|
||||
FSError doForLayer(FSShimWrapper *param);
|
||||
|
||||
void setWorkingDirForFSClient(FSClient *client, const char *path);
|
||||
FSError processShimBufferForFS(FSShimWrapper *param);
|
||||
|
||||
std::string getFullPathForFSAClient(FSAClientHandle client, const char *path);
|
||||
|
||||
void setWorkingDirForFSAClient(FSAClientHandle client, const char *path);
|
||||
|
||||
FSError doForLayerFSA(const std::function<FSError()> &real_function,
|
||||
const std::function<FSError(std::unique_ptr<IFSWrapper> &layer)> &layer_callback,
|
||||
const std::function<FSError(std::unique_ptr<IFSWrapper> &layer, FSError)> &result_handler);
|
||||
|
||||
FSStatus doForLayer(FSClient *client,
|
||||
FSErrorFlag errorMask,
|
||||
const std::function<FSStatus(FSErrorFlag errorMask)> &real_function,
|
||||
const std::function<FSError(std::unique_ptr<IFSWrapper> &layer)> &layer_callback,
|
||||
const std::function<FSStatus(std::unique_ptr<IFSWrapper> &layer, FSStatus)> &result_handler);
|
||||
FSError processShimBufferForFSA(FSShimWrapper *param);
|
||||
|
||||
FSCmdBlockBody *fsCmdBlockGetBody(FSCmdBlock *cmdBlock);
|
||||
|
||||
FSClientBody *fsClientGetBody(FSClient *client);
|
||||
|
||||
FSStatus send_result_async(FSClient *client, FSCmdBlock *block, FSAsyncData *asyncData, FSStatus result);
|
||||
FSStatus handleAsyncResult(FSClient *client, FSCmdBlock *block, FSAsyncData *asyncData, FSStatus status);
|
||||
|
||||
int64_t readIntoBuffer(int32_t handle, void *buffer, size_t size, size_t count);
|
||||
|
||||
int64_t writeFromBuffer(int32_t handle, void *buffer, size_t size, size_t count);
|
||||
int64_t writeFromBuffer(int32_t handle, const void *buffer, size_t size, size_t count);
|
||||
|
||||
void startFSIOThreads();
|
||||
void stopFSIOThreads();
|
@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
#include <coreinit/filesystem.h>
|
||||
#include <coreinit/filesystem_fsa.h>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#define FS_ERROR_EXTRA_MASK 0xFFF00000
|
||||
#define FS_ERROR_REAL_MASK 0x000FFFFF
|
||||
#define FS_ERROR_FORCE_PARENT_LAYER (FSError) 0xFFE0000
|
||||
#define FS_ERROR_FORCE_NO_FALLBACK (FSError) 0xFFD0000
|
||||
#define FS_ERROR_EXTRA_MASK 0xFFF00000
|
||||
#define FS_ERROR_REAL_MASK 0x000FFFFF
|
||||
#define FS_ERROR_FORCE_PARENT_LAYER (FSError) 0xFFE00000
|
||||
#define FS_ERROR_FORCE_NO_FALLBACK (FSError) 0xFFD00000
|
||||
#define FS_ERROR_FORCE_REAL_FUNCTION (FSError) 0xFFC00000
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-parameter"
|
||||
@ -15,21 +16,21 @@ class IFSWrapper {
|
||||
public:
|
||||
virtual ~IFSWrapper() = default;
|
||||
virtual FSError FSOpenDirWrapper(const char *path,
|
||||
FSDirectoryHandle *handle) {
|
||||
FSADirectoryHandle *handle) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
virtual FSError FSReadDirWrapper(FSDirectoryHandle handle,
|
||||
FSDirectoryEntry *entry) {
|
||||
virtual FSError FSReadDirWrapper(FSADirectoryHandle handle,
|
||||
FSADirectoryEntry *entry) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
virtual FSError FSCloseDirWrapper(FSDirectoryHandle handle) {
|
||||
virtual FSError FSCloseDirWrapper(FSADirectoryHandle handle) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
|
||||
virtual FSError FSRewindDirWrapper(FSDirectoryHandle handle) {
|
||||
virtual FSError FSRewindDirWrapper(FSADirectoryHandle handle) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
@ -39,29 +40,29 @@ public:
|
||||
|
||||
virtual FSError FSOpenFileWrapper(const char *path,
|
||||
const char *mode,
|
||||
FSFileHandle *handle) {
|
||||
FSAFileHandle *handle) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
virtual FSError FSCloseFileWrapper(FSFileHandle handle) {
|
||||
virtual FSError FSCloseFileWrapper(FSAFileHandle handle) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
virtual FSError FSGetStatWrapper(const char *path,
|
||||
FSStat *stats) {
|
||||
FSAStat *stats) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
|
||||
virtual FSError FSGetStatFileWrapper(FSFileHandle handle,
|
||||
FSStat *stats) {
|
||||
virtual FSError FSGetStatFileWrapper(FSAFileHandle handle,
|
||||
FSAStat *stats) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
virtual FSError FSReadFileWrapper(void *buffer,
|
||||
uint32_t size,
|
||||
uint32_t count,
|
||||
FSFileHandle handle,
|
||||
FSAFileHandle handle,
|
||||
uint32_t unk1) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
@ -70,37 +71,46 @@ public:
|
||||
uint32_t size,
|
||||
uint32_t count,
|
||||
uint32_t pos,
|
||||
FSFileHandle handle,
|
||||
FSAFileHandle handle,
|
||||
int32_t unk1) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
virtual FSError FSSetPosFileWrapper(FSFileHandle handle,
|
||||
virtual FSError FSSetPosFileWrapper(FSAFileHandle handle,
|
||||
uint32_t pos) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
virtual FSError FSGetPosFileWrapper(FSFileHandle handle,
|
||||
virtual FSError FSGetPosFileWrapper(FSAFileHandle handle,
|
||||
uint32_t *pos) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
virtual FSError FSIsEofWrapper(FSFileHandle handle) {
|
||||
virtual FSError FSIsEofWrapper(FSAFileHandle handle) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
virtual FSError FSTruncateFileWrapper(FSFileHandle handle) {
|
||||
virtual FSError FSTruncateFileWrapper(FSAFileHandle handle) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
virtual FSError FSWriteFileWrapper(uint8_t *buffer,
|
||||
virtual FSError FSWriteFileWrapper(const uint8_t *buffer,
|
||||
uint32_t size,
|
||||
uint32_t count,
|
||||
FSFileHandle handle,
|
||||
FSAFileHandle handle,
|
||||
uint32_t unk1) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
virtual FSError FSWriteFileWithPosWrapper(const uint8_t *buffer,
|
||||
uint32_t size,
|
||||
uint32_t count,
|
||||
FSAFilePosition pos,
|
||||
FSAFileHandle handle,
|
||||
uint32_t unk1) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
virtual FSError FSRemoveWrapper(const char *path) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
@ -110,7 +120,7 @@ public:
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
virtual FSError FSFlushFileWrapper(FSFileHandle handle) {
|
||||
virtual FSError FSFlushFileWrapper(FSAFileHandle handle) {
|
||||
return FS_ERROR_FORCE_PARENT_LAYER;
|
||||
}
|
||||
|
||||
@ -130,15 +140,17 @@ public:
|
||||
return pName;
|
||||
}
|
||||
|
||||
virtual bool isValidDirHandle(FSDirectoryHandle handle) = 0;
|
||||
virtual bool isValidDirHandle(FSADirectoryHandle handle) = 0;
|
||||
|
||||
virtual bool isValidFileHandle(FSFileHandle handle) = 0;
|
||||
virtual bool isValidFileHandle(FSAFileHandle handle) = 0;
|
||||
|
||||
virtual void deleteDirHandle(FSDirectoryHandle handle) = 0;
|
||||
virtual void deleteDirHandle(FSADirectoryHandle handle) = 0;
|
||||
|
||||
virtual void deleteFileHandle(FSFileHandle handle) = 0;
|
||||
virtual void deleteFileHandle(FSAFileHandle handle) = 0;
|
||||
|
||||
uint32_t getHandle() {
|
||||
virtual uint32_t getLayerId() = 0;
|
||||
|
||||
virtual uint32_t getHandle() {
|
||||
return (uint32_t) this;
|
||||
}
|
||||
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *layerName, const char *replacementDir, FSLayerType layerType) {
|
||||
if (!handle || layerName == nullptr || replacementDir == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("CONTENT_REDIRECTION_API_ERROR_INVALID_ARG");
|
||||
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_INVALID_ARG");
|
||||
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
|
||||
}
|
||||
std::unique_ptr<IFSWrapper> ptr;
|
||||
@ -37,7 +37,7 @@ ContentRedirectionApiErrorType CRAddFSLayer(CRLayerHandle *handle, const char *l
|
||||
|
||||
ContentRedirectionApiErrorType CRRemoveFSLayer(CRLayerHandle handle) {
|
||||
if (remove_locked_first_if(fsLayerMutex, fsLayers, [handle](auto &cur) { return (CRLayerHandle) cur->getHandle() == handle; })) {
|
||||
DEBUG_FUNCTION_LINE_ERR("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle);
|
||||
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle);
|
||||
return CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND;
|
||||
}
|
||||
return CONTENT_REDIRECTION_API_ERROR_NONE;
|
||||
@ -52,13 +52,12 @@ ContentRedirectionApiErrorType CRSetActive(CRLayerHandle handle, bool active) {
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE_ERR("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle);
|
||||
DEBUG_FUNCTION_LINE_WARN("CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND for handle %08X", handle);
|
||||
return CONTENT_REDIRECTION_API_ERROR_LAYER_NOT_FOUND;
|
||||
}
|
||||
|
||||
ContentRedirectionApiErrorType CRGetVersion(ContentRedirectionVersion *outVersion) {
|
||||
if (outVersion == nullptr) {
|
||||
DEBUG_FUNCTION_LINE_ERR("CONTENT_REDIRECTION_API_ERROR_INVALID_ARG");
|
||||
return CONTENT_REDIRECTION_API_ERROR_INVALID_ARG;
|
||||
}
|
||||
*outVersion = 1;
|
||||
|
26
src/main.cpp
26
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 <coreinit/cache.h>
|
||||
#include <coreinit/core.h>
|
||||
#include <malloc.h>
|
||||
#include <wums.h>
|
||||
|
||||
WUMS_MODULE_EXPORT_NAME("homebrew_content_redirection");
|
||||
@ -22,25 +24,21 @@ WUMS_INITIALIZE() {
|
||||
OSFatal("homebrew_content_redirection: Failed to patch function");
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < fs_dir_function_replacements_size; i++) {
|
||||
if (!FunctionPatcherPatchFunction(&fs_dir_function_replacements[i], nullptr)) {
|
||||
OSFatal("homebrew_content_redirection: Failed to patch function");
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < fsa_dir_function_replacements_size; i++) {
|
||||
if (!FunctionPatcherPatchFunction(&fsa_dir_function_replacements[i], nullptr)) {
|
||||
OSFatal("homebrew_content_redirection: Failed to patch function");
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG_FUNCTION_LINE("Patch functions finished");
|
||||
deinitLogging();
|
||||
}
|
||||
|
||||
|
||||
WUMS_APPLICATION_STARTS() {
|
||||
initLogging();
|
||||
startFSIOThreads();
|
||||
}
|
||||
|
||||
WUMS_APPLICATION_ENDS() {
|
||||
clearFSLayer();
|
||||
|
||||
stopFSIOThreads();
|
||||
|
||||
deinitLogging();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user