From 6073ab3ec65780ac9951fbc92eb980c035aa41bb Mon Sep 17 00:00:00 2001 From: Maschell Date: Sun, 4 Jun 2023 11:13:45 +0200 Subject: [PATCH] coreinit: Refactor FS functions to be more accurate (#842) --- src/Cafe/IOSU/fsa/fsa_types.h | 103 ++- src/Cafe/IOSU/fsa/iosu_fsa.cpp | 555 +++++++------- src/Cafe/IOSU/fsa/iosu_fsa.h | 243 +++--- src/Cafe/OS/libs/coreinit/coreinit_FS.cpp | 895 +++++++++++++++------- src/Cafe/OS/libs/coreinit/coreinit_FS.h | 187 +++-- 5 files changed, 1184 insertions(+), 799 deletions(-) diff --git a/src/Cafe/IOSU/fsa/fsa_types.h b/src/Cafe/IOSU/fsa/fsa_types.h index 2d2daa50..2825e421 100644 --- a/src/Cafe/IOSU/fsa/fsa_types.h +++ b/src/Cafe/IOSU/fsa/fsa_types.h @@ -4,48 +4,83 @@ enum class FS_RESULT : sint32 // aka FSStatus { SUCCESS = 0, END_ITERATION = -2, // used by FSGetMountSource / FSGetMountSourceNext to indicate when last element was reached - FATAL_ERROR = -0x400, - + MAX_HANDLES = -3, ALREADY_EXISTS = -5, NOT_FOUND = -6, NOT_FILE = -7, NOT_DIR = -8, PERMISSION_ERROR = -10, - INVALID_CLIENT_HANDLE = -0x30000 - 37, - + FATAL_ERROR = -0x400, ERR_PLACEHOLDER = -9999, // used when exact error code has yet to be determined }; enum class FSA_RESULT : sint32 // aka FSError/FSAStatus { SUCCESS = 0, - INVALID_CLIENT_HANDLE = -0x30000 - 37, - INVALID_HANDLE_UKN38 = -0x30000 - 38, + END_DIR = -0x30000 - 0x04, + END_FILE = -0x30000 - 0x05, + MAX_FILES = -0x30000 - 0x13, + MAX_DIRS = -0x30000 - 0x14, + ALREADY_EXISTS = -0x30000 - 0x16, + NOT_FOUND = -0x30000 - 0x17, + PERMISSION_ERROR = -0x30000 - 0x1A, + INVALID_PARAM = -0x30000 - 0x21, + INVALID_PATH = -0x30000 - 0x22, + INVALID_BUFFER = -0x30000 - 0x23, + INVALID_ALIGNMENT = -0x30000 - 0x24, + INVALID_CLIENT_HANDLE = -0x30000 - 0x25, + INVALID_FILE_HANDLE = -0x30000 - 0x26, + INVALID_DIR_HANDLE = -0x30000 - 0x27, + NOT_FILE = -0x30000 - 0x28, + NOT_DIR = -0x30000 - 0x29, FATAL_ERROR = -0x30000 - 0x400, }; -// todo - error handling in the IOSU part is pretty hacky right now and we use FS_RESULT in most places which we shouldn't be doing. Rework it + +enum class FSA_CMD_OPERATION_TYPE : uint32 +{ + CHANGEDIR = 0x5, + GETCWD = 0x6, + MAKEDIR = 0x7, + REMOVE = 0x8, + RENAME = 0x9, + OPENDIR = 0xA, + READDIR = 0xB, + CLOSEDIR = 0xD, + OPENFILE = 0xE, + READ = 0xF, + WRITE = 0x10, + GETPOS = 0x11, + SETPOS = 0x12, + ISEOF = 0x13, + GETSTATFILE = 0x14, + CLOSEFILE = 0x15, + QUERYINFO = 0x18, + APPENDFILE = 0x19, + TRUNCATEFILE = 0x1A, + FLUSHQUOTA = 0x1E, +}; using FSResHandle = sint32; using FSFileHandle2 = FSResHandle; using FSDirHandle2 = FSResHandle; -#define FS_INVALID_HANDLE_VALUE -1 +#define FS_INVALID_HANDLE_VALUE -1 -#define FSA_FILENAME_SIZE_MAX 128 -#define FSA_PATH_SIZE_MAX (512 + FSA_FILENAME_SIZE_MAX) -#define FSA_CMD_PATH_MAX_LENGTH FSA_PATH_SIZE_MAX -#define FSA_MAX_CLIENTS 32 +#define FSA_FILENAME_SIZE_MAX 128 +#define FSA_PATH_SIZE_MAX (512 + FSA_FILENAME_SIZE_MAX) +#define FSA_CMD_PATH_MAX_LENGTH FSA_PATH_SIZE_MAX +#define FSA_MAX_CLIENTS 32 -typedef sint32 FSStatus; // DEPR - replaced by FS_RESULT -typedef uint32 FS_ERROR_MASK; // replace with enum bitmask -typedef uint32 FSFileSize; -typedef uint64 FSLargeSize; -typedef uint64 FSTime; +typedef sint32 FSStatus; // DEPR - replaced by FS_RESULT +typedef uint32 FS_ERROR_MASK; // replace with enum bitmask +typedef uint32 FSFileSize; +typedef uint64 FSLargeSize; +typedef uint64 FSTime; enum class FSFlag : uint32 { - NONE = 0, - IS_DIR = 0x80000000, + NONE = 0, + IS_DIR = 0x80000000, }; DEFINE_ENUM_FLAG_OPERATORS(FSFlag); @@ -53,25 +88,25 @@ DEFINE_ENUM_FLAG_OPERATORS(FSFlag); struct FSStat_t { - /* +0x000 */ betype flag; - /* +0x004 */ uint32be permissions; - /* +0x008 */ uint32be ownerId; - /* +0x00C */ uint32be groupId; - /* +0x010 */ betype size; - /* +0x014 */ betype allocatedSize; - /* +0x018 */ betype quotaSize; - /* +0x020 */ uint32be entryId; - /* +0x024 */ betype createdTime; - /* +0x02C */ betype modifiedTime; - /* +0x034 */ uint8 attributes[0x30]; + /* +0x000 */ betype flag; + /* +0x004 */ uint32be permissions; + /* +0x008 */ uint32be ownerId; + /* +0x00C */ uint32be groupId; + /* +0x010 */ betype size; + /* +0x014 */ betype allocatedSize; + /* +0x018 */ betype quotaSize; + /* +0x020 */ uint32be entryId; + /* +0x024 */ betype createdTime; + /* +0x02C */ betype modifiedTime; + /* +0x034 */ uint8 attributes[0x30]; }; static_assert(sizeof(FSStat_t) == 0x64); struct FSDirEntry_t { - /* +0x00 */ FSStat_t stat; - /* +0x64 */ char name[FSA_FILENAME_SIZE_MAX]; + /* +0x00 */ FSStat_t stat; + /* +0x64 */ char name[FSA_FILENAME_SIZE_MAX]; }; static_assert(sizeof(FSDirEntry_t) == 0xE4); @@ -79,5 +114,5 @@ static_assert(sizeof(FSDirEntry_t) == 0xE4); #pragma pack() // query types for QueryInfo -#define FSA_QUERY_TYPE_FREESPACE 0 -#define FSA_QUERY_TYPE_STAT 5 +#define FSA_QUERY_TYPE_FREESPACE 0 +#define FSA_QUERY_TYPE_STAT 5 diff --git a/src/Cafe/IOSU/fsa/iosu_fsa.cpp b/src/Cafe/IOSU/fsa/iosu_fsa.cpp index fd0b490e..17d86266 100644 --- a/src/Cafe/IOSU/fsa/iosu_fsa.cpp +++ b/src/Cafe/IOSU/fsa/iosu_fsa.cpp @@ -4,7 +4,7 @@ #include "Cafe/Filesystem/fsc.h" #include "util/helpers/helpers.h" -#include "Cafe/OS/libs/coreinit/coreinit_FS.h" // get rid of this dependency, requires reworking some of the IPC stuff. See locations where we use coreinit::FSCmdBlockBody_t +#include "Cafe/OS/libs/coreinit/coreinit_FS.h" // get rid of this dependency, requires reworking some of the IPC stuff. See locations where we use coreinit::FSCmdBlockBody_t #include "Cafe/HW/Latte/Core/LatteBufferCache.h" // also remove this dependency #include "Cafe/HW/MMU/MMU.h" @@ -19,10 +19,10 @@ namespace iosu SysAllocator _m_sFSAIoMsgQueueMsgBuffer; std::thread sFSAIoThread; - struct FSAClient // IOSU's counterpart to the coreinit FSClient struct + struct FSAClient // IOSU's counterpart to the coreinit FSClient struct { std::string workingDirectory; - bool isAllocated{ false }; + bool isAllocated{false}; void AllocateAndInitialize() { @@ -42,7 +42,7 @@ namespace iosu { for (size_t i = 0; i < sFSAClientArray.size(); i++) { - if(sFSAClientArray[i].isAllocated) + if (sFSAClientArray[i].isAllocated) continue; sFSAClientArray[i].AllocateAndInitialize(); indexOut = (sint32)i; @@ -51,16 +51,16 @@ namespace iosu return (IOS_ERROR)0xFFFCFFEE; } - sint32 FSA_convertFSCtoFSStatus(sint32 fscError) + FSA_RESULT FSA_convertFSCtoFSAStatus(sint32 fscError) { if (fscError == FSC_STATUS_OK) - return (FSStatus)FS_RESULT::SUCCESS; + return FSA_RESULT::SUCCESS; else if (fscError == FSC_STATUS_FILE_NOT_FOUND) - return (sint32)FS_RESULT::NOT_FOUND; + return FSA_RESULT::NOT_FOUND; else if (fscError == FSC_STATUS_ALREADY_EXISTS) - return (sint32)FS_RESULT::ALREADY_EXISTS; + return FSA_RESULT::ALREADY_EXISTS; cemu_assert_unimplemented(); - return -1; + return FSA_RESULT::FATAL_ERROR; } std::string __FSATranslatePath(FSAClient* fsaClient, std::string_view input, bool endWithSlash = false) @@ -152,21 +152,21 @@ namespace iosu return fsc_open(translatedPath.c_str(), accessFlags, &fscStatus); } - class _FSAHandleTable - { + class _FSAHandleTable { struct _FSAHandleResource { - bool isAllocated{ false }; + bool isAllocated{false}; FSCVirtualFile* fscFile; uint16 handleCheckValue; }; + public: FSA_RESULT AllocateHandle(FSResHandle& handleOut, FSCVirtualFile* fscFile) { for (size_t i = 0; i < m_handleTable.size(); i++) { auto& it = m_handleTable.at(i); - if(it.isAllocated) + if (it.isAllocated) continue; uint16 checkValue = (uint16)m_currentCounter; m_currentCounter++; @@ -186,12 +186,12 @@ namespace iosu uint16 index = (uint16)((uint32)handle >> 16); uint16 checkValue = (uint16)(handle & 0xFFFF); if (index >= m_handleTable.size()) - return FSA_RESULT::INVALID_HANDLE_UKN38; + return FSA_RESULT::INVALID_FILE_HANDLE; auto& it = m_handleTable.at(index); - if(!it.isAllocated) - return FSA_RESULT::INVALID_HANDLE_UKN38; - if(it.handleCheckValue != checkValue) - return FSA_RESULT::INVALID_HANDLE_UKN38; + if (!it.isAllocated) + return FSA_RESULT::INVALID_FILE_HANDLE; + if (it.handleCheckValue != checkValue) + return FSA_RESULT::INVALID_FILE_HANDLE; it.fscFile = nullptr; it.isAllocated = false; return FSA_RESULT::SUCCESS; @@ -210,7 +210,7 @@ namespace iosu return nullptr; return it.fscFile; } - + private: uint32 m_currentCounter = 1; std::array<_FSAHandleResource, 0x3C0> m_handleTable; @@ -219,13 +219,12 @@ namespace iosu _FSAHandleTable sFileHandleTable; _FSAHandleTable sDirHandleTable; - - FSStatus __FSAOpenFile(FSAClient* client, const char* path, const char* accessModifierStr, sint32* fileHandle) + FSA_RESULT __FSAOpenFile(FSAClient* client, const char* path, const char* accessModifierStr, sint32* fileHandle) { *fileHandle = FS_INVALID_HANDLE_VALUE; FSC_ACCESS_FLAG accessModifier = FSC_ACCESS_FLAG::NONE; bool truncateFile = false; // todo: Support for this - bool isAppend = false; // todo: proper support for this (all write operations should move cursor to the end of the file?) + bool isAppend = false; // todo: proper support for this (all write operations should move cursor to the end of the file?) if (strcmp(accessModifierStr, "r") == 0 || strcmp(accessModifierStr, "rb") == 0) accessModifier = FSC_ACCESS_FLAG::READ_PERMISSION; else if (strcmp(accessModifierStr, "r+") == 0) @@ -266,11 +265,11 @@ namespace iosu sint32 fscStatus; FSCVirtualFile* fscFile = __FSAOpenNode(client, path, accessModifier, fscStatus); if (!fscFile) - return (sint32)FS_RESULT::NOT_FOUND; + return FSA_RESULT::NOT_FOUND; if (fscFile->fscGetType() != FSC_TYPE_FILE) { delete fscFile; - return (sint32)FS_RESULT::NOT_FILE; + return FSA_RESULT::NOT_FILE; } if (isAppend) fsc_setFileSeek(fscFile, fsc_getFileSize(fscFile)); @@ -280,75 +279,75 @@ namespace iosu { cemuLog_log(LogType::Force, "Exceeded maximum number of FSA file handles"); delete fscFile; - return -0x400; + return FSA_RESULT::MAX_FILES; } *fileHandle = fsFileHandle; cemuLog_log(LogType::CoreinitFile, "Open file {} (access: {} result: ok handle: 0x{})", path, accessModifierStr, (uint32)*fileHandle); - return (FSStatus)FS_RESULT::SUCCESS; + return FSA_RESULT::SUCCESS; } - FSStatus __FSAOpenDirectory(FSAClient* client, std::string_view path, sint32* dirHandle) + FSA_RESULT __FSAOpenDirectory(FSAClient* client, std::string_view path, sint32* dirHandle) { *dirHandle = FS_INVALID_HANDLE_VALUE; sint32 fscStatus; FSCVirtualFile* fscFile = __FSAOpenNode(client, path, FSC_ACCESS_FLAG::OPEN_DIR | FSC_ACCESS_FLAG::OPEN_FILE, fscStatus); if (!fscFile) - return (FSStatus)FS_RESULT::NOT_FOUND; + return FSA_RESULT::NOT_FOUND; if (fscFile->fscGetType() != FSC_TYPE_DIRECTORY) { delete fscFile; - return (FSStatus)(FS_RESULT::NOT_DIR); + return FSA_RESULT::NOT_DIR; } FSResHandle fsDirHandle; FSA_RESULT r = sDirHandleTable.AllocateHandle(fsDirHandle, fscFile); if (r != FSA_RESULT::SUCCESS) { delete fscFile; - return -0x400; + return FSA_RESULT::MAX_DIRS; } *dirHandle = fsDirHandle; cemuLog_log(LogType::CoreinitFile, "Open directory {} (result: ok handle: 0x{})", path, (uint32)*dirHandle); - return (FSStatus)FS_RESULT::SUCCESS; + return FSA_RESULT::SUCCESS; } - FSStatus __FSACloseFile(uint32 fileHandle) + FSA_RESULT __FSACloseFile(uint32 fileHandle) { uint8 handleType = 0; FSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle); if (!fscFile) { cemuLog_logDebug(LogType::Force, "__FSACloseFile(): Invalid handle (0x{:08x})", fileHandle); - return (FSStatus)FS_RESULT::ERR_PLACEHOLDER; + return FSA_RESULT::INVALID_FILE_HANDLE; } // unregister file sFileHandleTable.ReleaseHandle(fileHandle); // todo - use the error code of this fsc_close(fscFile); - return (FSStatus)FS_RESULT::SUCCESS; + return FSA_RESULT::SUCCESS; } - FSStatus FSAProcessCmd_remove(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_remove(FSAClient* client, FSAShimBuffer* shimBuffer) { - std::string path = __FSATranslatePath(client, (char*)cmd->cmdRemove.path); + std::string path = __FSATranslatePath(client, (char*)shimBuffer->request.cmdRemove.path); sint32 fscStatus = FSC_STATUS_FILE_NOT_FOUND; fsc_remove(path.c_str(), &fscStatus); - return FSA_convertFSCtoFSStatus(fscStatus); + return FSA_convertFSCtoFSAStatus(fscStatus); } - FSStatus FSAProcessCmd_makeDir(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_makeDir(FSAClient* client, FSAShimBuffer* shimBuffer) { - std::string path = __FSATranslatePath(client, (char*)cmd->cmdMakeDir.path); + std::string path = __FSATranslatePath(client, (char*)shimBuffer->request.cmdMakeDir.path); sint32 fscStatus = FSC_STATUS_FILE_NOT_FOUND; fsc_createDir(path.c_str(), &fscStatus); - return FSA_convertFSCtoFSStatus(fscStatus); + return FSA_convertFSCtoFSAStatus(fscStatus); } - FSStatus FSAProcessCmd_rename(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_rename(FSAClient* client, FSAShimBuffer* shimBuffer) { - std::string srcPath = __FSATranslatePath(client, (char*)cmd->cmdRename.srcPath); - std::string dstPath = __FSATranslatePath(client, (char*)cmd->cmdRename.dstPath); + std::string srcPath = __FSATranslatePath(client, (char*)shimBuffer->request.cmdRename.srcPath); + std::string dstPath = __FSATranslatePath(client, (char*)shimBuffer->request.cmdRename.dstPath); sint32 fscStatus = FSC_STATUS_FILE_NOT_FOUND; fsc_rename(srcPath.c_str(), dstPath.c_str(), &fscStatus); - return FSA_convertFSCtoFSStatus(fscStatus); + return FSA_convertFSCtoFSAStatus(fscStatus); } bool __FSA_GetStatFromFSCFile(FSCVirtualFile* fscFile, FSStat_t* fsStatOut) @@ -376,88 +375,68 @@ namespace iosu return true; } - FSStatus __FSA_GetFileStat(FSAClient* client, const char* path, FSStat_t* fsStatOut) + FSA_RESULT __FSA_GetFileStat(FSAClient* client, const char* path, FSStat_t* fsStatOut) { sint32 fscStatus; FSCVirtualFile* fscFile = __FSAOpenNode(client, path, FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::OPEN_DIR, fscStatus); if (!fscFile) - return FSA_convertFSCtoFSStatus(fscStatus); + return FSA_convertFSCtoFSAStatus(fscStatus); __FSA_GetStatFromFSCFile(fscFile, fsStatOut); delete fscFile; - return (FSStatus)FS_RESULT::SUCCESS; + return FSA_RESULT::SUCCESS; } - FSStatus FSAProcessCmd_queryInfo(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_queryInfo(FSAClient* client, FSAShimBuffer* shimBuffer) { - coreinit::FSCmdBlockBody_t* fullCmd = (coreinit::FSCmdBlockBody_t*)cmd; - - char* path = (char*)cmd->cmdQueryInfo.query; - uint32 queryType = _swapEndianU32(cmd->cmdQueryInfo.queryType); - void* queryResult = memory_getPointerFromVirtualOffset(_swapEndianU32(fullCmd->returnValueMPTR)); + char* path = (char*)shimBuffer->request.cmdQueryInfo.query; + uint32 queryType = shimBuffer->request.cmdQueryInfo.queryType; // handle query sint32 fscStatus = FSC_STATUS_OK; if (queryType == FSA_QUERY_TYPE_STAT) { - FSStat_t* fsStat = (FSStat_t*)queryResult; - FSStatus fsStatus = __FSA_GetFileStat(client, path, fsStat); - return fsStatus; + FSStat_t* fsStat = &shimBuffer->response.cmdQueryInfo.queryStat.stat; + FSA_RESULT fsaStatus = __FSA_GetFileStat(client, path, fsStat); + return fsaStatus; } else if (queryType == FSA_QUERY_TYPE_FREESPACE) { sint32 fscStatus; FSCVirtualFile* fscFile = __FSAOpenNode(client, path, FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::OPEN_DIR, fscStatus); if (!fscFile) - return FSA_convertFSCtoFSStatus(fscStatus); - betype* fsStatSize = (betype*)queryResult; + return FSA_convertFSCtoFSAStatus(fscStatus); + betype* fsStatSize = &shimBuffer->response.cmdQueryInfo.queryFreeSpace.freespace; *fsStatSize = 30ull * 1024 * 1024 * 1024; // placeholder value. How is this determined? delete fscFile; - return (FSStatus)FS_RESULT::SUCCESS; + return FSA_RESULT::SUCCESS; } else cemu_assert_unimplemented(); - return FSA_convertFSCtoFSStatus(fscStatus); + return FSA_convertFSCtoFSAStatus(fscStatus); } - FSStatus FSAProcessCmd_getStatFile(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_getStatFile(FSAClient* client, FSAShimBuffer* shimBuffer) { - coreinit::FSCmdBlockBody_t* fullCmd = (coreinit::FSCmdBlockBody_t*)cmd; - - FSFileHandle2 fileHandle = cmd->cmdGetStatFile.fileHandle; - FSStat_t* statOut = (FSStat_t*)memory_getPointerFromVirtualOffset(_swapEndianU32(fullCmd->returnValueMPTR)); + FSFileHandle2 fileHandle = shimBuffer->request.cmdGetStatFile.fileHandle; + FSStat_t* statOut = &shimBuffer->response.cmdStatFile.statOut; FSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle); if (!fscFile) - return (FSStatus)FS_RESULT::NOT_FOUND; + return FSA_RESULT::NOT_FOUND; cemu_assert_debug(fsc_isFile(fscFile)); __FSA_GetStatFromFSCFile(fscFile, statOut); - return (FSStatus)FS_RESULT::SUCCESS; + return FSA_RESULT::SUCCESS; } - FSStatus FSAProcessCmd_read(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_read(FSAClient* client, FSAShimBuffer* shimBuffer, MEMPTR destPtr, uint32be transferSize) { - coreinit::FSCmdBlockBody_t* fullCmd = (coreinit::FSCmdBlockBody_t*)cmd; + uint32 transferElementSize = shimBuffer->request.cmdReadFile.size; + uint32 filePos = shimBuffer->request.cmdReadFile.filePos; + uint32 fileHandle = shimBuffer->request.cmdReadFile.fileHandle; + uint32 flags = shimBuffer->request.cmdReadFile.flag; - uint32 filePos = _swapEndianU32(cmd->cmdDefault.transferFilePos); - uint32 fileHandle = _swapEndianU32(cmd->cmdDefault.fileHandle); - MPTR destOffset = _swapEndianU32(cmd->cmdDefault.destBufferMPTR); - void* destPtr = memory_getPointerFromVirtualOffset(destOffset); - uint32 transferSize = _swapEndianU32(fullCmd->transferSize); - uint32 transferElementSize = _swapEndianU32(fullCmd->transferElemSize); - uint32 flags = _swapEndianU32(cmd->cmdDefault.cmdFlag); - uint32 errHandling = _swapEndianU32(fullCmd->errHandling); FSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle); if (!fscFile) - return (FSStatus)FS_RESULT::ERR_PLACEHOLDER; - uint32 elementSize = transferElementSize; - uint32 elementCount = 0; - if (transferElementSize != 0) - { - elementCount = transferSize / transferElementSize; - cemu_assert_debug((transferSize % transferElementSize) == 0); - } - else - { - cemu_assert_debug(transferSize == 0); - } + return FSA_RESULT::INVALID_FILE_HANDLE; + uint32 bytesToRead = transferSize; // update file position if flag is set if ((flags & FSA_CMD_FLAG_SET_POS) != 0) @@ -465,107 +444,91 @@ namespace iosu // todo: File permissions uint32 bytesSuccessfullyRead = fsc_readFile(fscFile, destPtr, bytesToRead); if (transferElementSize == 0) - return 0; + return FSA_RESULT::SUCCESS; - LatteBufferCache_notifyDCFlush(memory_getVirtualOffsetFromPointer(destPtr), bytesToRead); + LatteBufferCache_notifyDCFlush(destPtr.GetMPTR(), bytesToRead); - return bytesSuccessfullyRead / transferElementSize; // return number of elements read + return (FSA_RESULT)(bytesSuccessfullyRead / transferElementSize); // return number of elements read } - FSStatus FSAProcessCmd_write(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_write(FSAClient* client, FSAShimBuffer* shimBuffer, MEMPTR destPtr, uint32be transferSize) { - coreinit::FSCmdBlockBody_t* fullCmd = (coreinit::FSCmdBlockBody_t*)cmd; + uint32 transferElementSize = shimBuffer->request.cmdWriteFile.size; + uint32 filePos = shimBuffer->request.cmdWriteFile.filePos; + uint32 fileHandle = shimBuffer->request.cmdWriteFile.fileHandle; + uint32 flags = shimBuffer->request.cmdWriteFile.flag; - uint32 filePos = _swapEndianU32(cmd->cmdDefault.transferFilePos); - uint32 fileHandle = _swapEndianU32(cmd->cmdDefault.fileHandle); - MPTR destOffset = _swapEndianU32(cmd->cmdDefault.destBufferMPTR); - void* destPtr = memory_getPointerFromVirtualOffset(destOffset); - uint32 transferSize = _swapEndianU32(fullCmd->transferSize); - uint32 transferElementSize = _swapEndianU32(fullCmd->transferElemSize); - uint32 flags = _swapEndianU32(cmd->cmdDefault.cmdFlag); - uint32 errHandling = _swapEndianU32(fullCmd->errHandling); FSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle); if (!fscFile) - return (FSStatus)FS_RESULT::ERR_PLACEHOLDER; - uint32 elementSize = transferElementSize; - uint32 elementCount = transferSize / transferElementSize; + return FSA_RESULT::INVALID_FILE_HANDLE; cemu_assert_debug((transferSize % transferElementSize) == 0); uint32 bytesToWrite = transferSize; // check for write permission (should this happen before or after setting file position?) if (!fsc_isWritable(fscFile)) { cemu_assert_debug(false); - return (FSStatus)FS_RESULT::PERMISSION_ERROR; + return FSA_RESULT::PERMISSION_ERROR; } // update file position if flag is set if ((flags & FSA_CMD_FLAG_SET_POS) != 0) fsc_setFileSeek(fscFile, filePos); uint32 bytesSuccessfullyWritten = fsc_writeFile(fscFile, destPtr, bytesToWrite); debug_printf("FSAProcessCmd_write(): Writing 0x%08x bytes (bytes actually written: 0x%08x)\n", bytesToWrite, bytesSuccessfullyWritten); - return bytesSuccessfullyWritten / transferElementSize; // return number of elements read + return (FSA_RESULT)(bytesSuccessfullyWritten / transferElementSize); // return number of elements read } - FSStatus FSAProcessCmd_setPos(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_setPos(FSAClient* client, FSAShimBuffer* shimBuffer) { - uint32 fileHandle = _swapEndianU32(cmd->cmdDefault.destBufferMPTR); - uint32 filePos = _swapEndianU32(cmd->cmdDefault.ukn0008); + uint32 fileHandle = shimBuffer->request.cmdSetPosFile.fileHandle; + uint32 filePos = shimBuffer->request.cmdSetPosFile.filePos; FSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle); if (!fscFile) - return (FSStatus)FS_RESULT::ERR_PLACEHOLDER; + return FSA_RESULT::INVALID_FILE_HANDLE; fsc_setFileSeek(fscFile, filePos); - return (FSStatus)FS_RESULT::SUCCESS; + return FSA_RESULT::SUCCESS; } - FSStatus FSAProcessCmd_getPos(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_getPos(FSAClient* client, FSAShimBuffer* shimBuffer) { - coreinit::FSCmdBlockBody_t* fullCmd = (coreinit::FSCmdBlockBody_t*)cmd; - - uint32 fileHandle = _swapEndianU32(cmd->cmdDefault.destBufferMPTR); - MPTR returnedFilePos = _swapEndianU32(fullCmd->returnValueMPTR); + uint32 fileHandle = shimBuffer->request.cmdGetPosFile.fileHandle; FSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle); if (!fscFile) - return (FSStatus)FS_RESULT::ERR_PLACEHOLDER; + return FSA_RESULT::INVALID_FILE_HANDLE; uint32 filePos = fsc_getFileSeek(fscFile); - memory_writeU32(returnedFilePos, filePos); - return (FSStatus)FS_RESULT::SUCCESS; + shimBuffer->response.cmdGetPosFile.filePos = filePos; + return FSA_RESULT::SUCCESS; } - FSStatus FSAProcessCmd_openFile(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_openFile(FSAClient* client, FSAShimBuffer* shimBuffer) { - coreinit::FSCmdBlockBody_t* fullCmd = (coreinit::FSCmdBlockBody_t*)cmd; sint32 fileHandle = 0; - FSStatus fsStatus = __FSAOpenFile(client, (char*)cmd->cmdOpenFile.path, (char*)cmd->cmdOpenFile.mode, &fileHandle); - memory_writeU32(_swapEndianU32(fullCmd->returnValueMPTR), fileHandle); - cmd->cmdOpenFile.fileHandleOutput = fileHandle; - return fsStatus; + FSA_RESULT fsaResult = __FSAOpenFile(client, (char*)shimBuffer->request.cmdOpenFile.path, (char*)shimBuffer->request.cmdOpenFile.mode, &fileHandle); + shimBuffer->response.cmdOpenFile.fileHandleOutput = fileHandle; + return fsaResult; } - FSStatus FSAProcessCmd_closeFile(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_closeFile(FSAClient* client, FSAShimBuffer* shimBuffer) { - return __FSACloseFile(cmd->cmdCloseFile.fileHandle); + return __FSACloseFile(shimBuffer->request.cmdCloseFile.fileHandle); } - FSStatus FSAProcessCmd_openDir(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_openDir(FSAClient* client, FSAShimBuffer* shimBuffer) { - coreinit::FSCmdBlockBody_t* fullCmd = (coreinit::FSCmdBlockBody_t*)cmd; sint32 dirHandle = 0; - FSStatus fsStatus = __FSAOpenDirectory(client, (const char*)cmd->cmdOpenFile.path, &dirHandle); - memory_writeU32(_swapEndianU32(fullCmd->returnValueMPTR), dirHandle); - cmd->cmdOpenDir.dirHandleOutput = dirHandle; - return fsStatus; + FSA_RESULT fsaResult = __FSAOpenDirectory(client, (const char*)shimBuffer->request.cmdOpenFile.path, &dirHandle); + shimBuffer->response.cmdOpenDir.dirHandleOutput = dirHandle; + return fsaResult; } - FSStatus FSAProcessCmd_readDir(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_readDir(FSAClient* client, FSAShimBuffer* shimBuffer) { - coreinit::FSCmdBlockBody_t* fullCmd = (coreinit::FSCmdBlockBody_t*)cmd; - - FSCVirtualFile* fscFile = sDirHandleTable.GetByHandle((sint32)cmd->cmdReadDir.dirHandle); + FSCVirtualFile* fscFile = sDirHandleTable.GetByHandle((sint32)shimBuffer->request.cmdReadDir.dirHandle); if (!fscFile) - return (FSStatus)FS_RESULT::ERR_PLACEHOLDER; - FSDirEntry_t* dirEntryOut = (FSDirEntry_t*)memory_getPointerFromVirtualOffset(_swapEndianU32(fullCmd->returnValueMPTR)); + return FSA_RESULT::INVALID_DIR_HANDLE; + FSDirEntry_t* dirEntryOut = &shimBuffer->response.cmdReadDir.dirEntry; FSCDirEntry fscDirEntry; if (fsc_nextDir(fscFile, &fscDirEntry) == false) - return (FSStatus)FS_RESULT::END_ITERATION; + return FSA_RESULT::END_DIR; strcpy(dirEntryOut->name, fscDirEntry.path); FSFlag statFlag = FSFlag::NONE; dirEntryOut->stat.size = 0; @@ -579,173 +542,241 @@ namespace iosu } dirEntryOut->stat.flag = statFlag; dirEntryOut->stat.permissions = 0x777; - return (FSStatus)FS_RESULT::SUCCESS; + return FSA_RESULT::SUCCESS; } - FSStatus FSAProcessCmd_closeDir(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_closeDir(FSAClient* client, FSAShimBuffer* shimBuffer) { - FSCVirtualFile* fscFile = sDirHandleTable.GetByHandle((sint32)cmd->cmdReadDir.dirHandle); + FSCVirtualFile* fscFile = sDirHandleTable.GetByHandle((sint32)shimBuffer->request.cmdReadDir.dirHandle); if (!fscFile) { - cemuLog_logDebug(LogType::Force, "CloseDir: Invalid handle (0x{:08x})", (sint32)cmd->cmdReadDir.dirHandle); - return (FSStatus)FS_RESULT::ERR_PLACEHOLDER; + cemuLog_logDebug(LogType::Force, "CloseDir: Invalid handle (0x{:08x})", (sint32)shimBuffer->request.cmdReadDir.dirHandle); + return FSA_RESULT::INVALID_DIR_HANDLE; } - sDirHandleTable.ReleaseHandle(cmd->cmdReadDir.dirHandle); + sDirHandleTable.ReleaseHandle(shimBuffer->request.cmdReadDir.dirHandle); fsc_close(fscFile); - return (FSStatus)FS_RESULT::SUCCESS; + return FSA_RESULT::SUCCESS; } - FSStatus FSAProcessCmd_flushQuota(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_flushQuota(FSAClient* client, FSAShimBuffer* shimBuffer) { - return (FSStatus)FS_RESULT::SUCCESS; + return FSA_RESULT::SUCCESS; } - FSStatus FSAProcessCmd_appendFile(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_appendFile(FSAClient* client, FSAShimBuffer* shimBuffer) { - uint32 fileHandle = _swapEndianU32(cmd->cmdDefault.destBufferMPTR); + uint32 fileHandle = shimBuffer->request.cmdAppendFile.fileHandle; FSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle); if (!fscFile) - return (FSStatus)FS_RESULT::ERR_PLACEHOLDER; + return FSA_RESULT::INVALID_FILE_HANDLE; #ifdef CEMU_DEBUG_ASSERT - cemuLog_log(LogType::Force, "FSAProcessCmd_appendFile(): size 0x{:08x} count 0x{:08x} (todo)\n", _swapEndianU32(cmd->cmdAppendFile.size), _swapEndianU32(cmd->cmdAppendFile.count)); + cemuLog_log(LogType::Force, "FSAProcessCmd_appendFile(): size 0x{:08x} count 0x{:08x} (todo)\n", shimBuffer->request.cmdAppendFile.size, shimBuffer->request.cmdAppendFile.count); #endif - return _swapEndianU32(cmd->cmdAppendFile.size) * _swapEndianU32(cmd->cmdAppendFile.count); + return (FSA_RESULT)(shimBuffer->request.cmdAppendFile.size * shimBuffer->request.cmdAppendFile.count); } - FSStatus FSAProcessCmd_truncateFile(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_truncateFile(FSAClient* client, FSAShimBuffer* shimBuffer) { - FSFileHandle2 fileHandle = cmd->cmdTruncateFile.fileHandle; + FSFileHandle2 fileHandle = shimBuffer->request.cmdTruncateFile.fileHandle; FSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle); if (!fscFile) - return (FSStatus)FS_RESULT::ERR_PLACEHOLDER; + return FSA_RESULT::INVALID_FILE_HANDLE; fsc_setFileLength(fscFile, fsc_getFileSeek(fscFile)); - return (FSStatus)FS_RESULT::SUCCESS; + return FSA_RESULT::SUCCESS; } - FSStatus FSAProcessCmd_isEof(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_isEof(FSAClient* client, FSAShimBuffer* shimBuffer) { - uint32 fileHandle = _swapEndianU32(cmd->cmdDefault.destBufferMPTR); + uint32 fileHandle = shimBuffer->request.cmdIsEof.fileHandle; FSCVirtualFile* fscFile = sFileHandleTable.GetByHandle(fileHandle); if (!fscFile) - return (FSStatus)FS_RESULT::ERR_PLACEHOLDER; + return FSA_RESULT::INVALID_FILE_HANDLE; uint32 filePos = fsc_getFileSeek(fscFile); uint32 fileSize = fsc_getFileSize(fscFile); if (filePos >= fileSize) - return (FSStatus)FS_RESULT::END_ITERATION; - return (FSStatus)FS_RESULT::SUCCESS; + return FSA_RESULT::END_FILE; + return FSA_RESULT::SUCCESS; } - FSStatus FSAProcessCmd_getCwd(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_getCwd(FSAClient* client, FSAShimBuffer* shimBuffer) { - coreinit::FSCmdBlockBody_t* fullCmd = (coreinit::FSCmdBlockBody_t*)cmd; - - char* pathOutput = (char*)memory_getPointerFromVirtualOffset(_swapEndianU32(fullCmd->returnValueMPTR)); - sint32 pathOutputMaxLen = _swapEndianU32(fullCmd->transferSize); + char* pathOutput = shimBuffer->response.cmdGetCWD.path; + sint32 pathOutputMaxLen = sizeof(shimBuffer->response.cmdGetCWD.path); cemu_assert(pathOutputMaxLen > 0); sint32 fscStatus = FSC_STATUS_OK; strncpy(pathOutput, client->workingDirectory.data(), std::min(client->workingDirectory.size() + 1, (size_t)pathOutputMaxLen)); pathOutput[pathOutputMaxLen - 1] = '\0'; - return FSA_convertFSCtoFSStatus(fscStatus); + return FSA_convertFSCtoFSAStatus(fscStatus); } - FSStatus FSAProcessCmd_changeDir(FSAClient* client, FSAIpcCommand* cmd) + FSA_RESULT FSAProcessCmd_changeDir(FSAClient* client, FSAShimBuffer* shimBuffer) { - const char* path = (const char*)cmd->cmdChangeDir.path; - cmd->cmdChangeDir.path[sizeof(cmd->cmdChangeDir.path) - 1] = '\0'; + const char* path = (const char*)shimBuffer->request.cmdChangeDir.path; + shimBuffer->request.cmdChangeDir.path[sizeof(shimBuffer->request.cmdChangeDir.path) - 1] = '\0'; sint32 fscStatus = FSC_STATUS_OK; client->workingDirectory.assign(__FSATranslatePath(client, path, true)); - return FSA_convertFSCtoFSStatus(fscStatus); + return FSA_convertFSCtoFSAStatus(fscStatus); } - void FSAHandleCommandIoctl(FSAClient* client, IPCCommandBody* cmd, uint32 operationId, void* ptrIn, void* ptrOut) + void FSAHandleCommandIoctlv(FSAClient* client, IPCCommandBody* cmd, FSA_CMD_OPERATION_TYPE operationId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec) { - FSAIpcCommand* fsaCommand = (FSAIpcCommand*)ptrIn; - FSStatus fsStatus = (FSStatus)(FS_RESULT::FATAL_ERROR); - if (operationId == FSA_CMD_OPERATION_TYPE_REMOVE) + FSA_RESULT fsaResult = FSA_RESULT::FATAL_ERROR; + + switch (operationId) { - fsStatus = FSAProcessCmd_remove(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_MAKEDIR) + case FSA_CMD_OPERATION_TYPE::READ: { - fsStatus = FSAProcessCmd_makeDir(client, fsaCommand); + fsaResult = FSAProcessCmd_read(client, (FSAShimBuffer*)vec[0].basePhys.GetPtr(), vec[1].basePhys, vec[1].size); + break; } - else if (operationId == FSA_CMD_OPERATION_TYPE_RENAME) + case FSA_CMD_OPERATION_TYPE::WRITE: { - fsStatus = FSAProcessCmd_rename(client, fsaCommand); + fsaResult = FSAProcessCmd_write(client, (FSAShimBuffer*)vec[0].basePhys.GetPtr(), vec[1].basePhys, vec[1].size); + break; } - else if (operationId == FSA_CMD_OPERATION_TYPE_READ) + case FSA_CMD_OPERATION_TYPE::CHANGEDIR: + case FSA_CMD_OPERATION_TYPE::GETCWD: + case FSA_CMD_OPERATION_TYPE::MAKEDIR: + case FSA_CMD_OPERATION_TYPE::RENAME: + case FSA_CMD_OPERATION_TYPE::OPENDIR: + case FSA_CMD_OPERATION_TYPE::READDIR: + case FSA_CMD_OPERATION_TYPE::CLOSEDIR: + case FSA_CMD_OPERATION_TYPE::OPENFILE: + case FSA_CMD_OPERATION_TYPE::REMOVE: + case FSA_CMD_OPERATION_TYPE::GETPOS: + case FSA_CMD_OPERATION_TYPE::SETPOS: + case FSA_CMD_OPERATION_TYPE::ISEOF: + case FSA_CMD_OPERATION_TYPE::GETSTATFILE: + case FSA_CMD_OPERATION_TYPE::CLOSEFILE: + case FSA_CMD_OPERATION_TYPE::QUERYINFO: + case FSA_CMD_OPERATION_TYPE::APPENDFILE: + case FSA_CMD_OPERATION_TYPE::TRUNCATEFILE: + case FSA_CMD_OPERATION_TYPE::FLUSHQUOTA: { - fsStatus = FSAProcessCmd_read(client, fsaCommand); + // These are IOCTL and no IOCTLV + cemu_assert_error(); + break; } - else if (operationId == FSA_CMD_OPERATION_TYPE_WRITE) - { - fsStatus = FSAProcessCmd_write(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_SETPOS) - { - fsStatus = FSAProcessCmd_setPos(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_GETPOS) - { - fsStatus = FSAProcessCmd_getPos(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_OPENFILE) - { - fsStatus = FSAProcessCmd_openFile(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_CLOSEFILE) - { - fsStatus = FSAProcessCmd_closeFile(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_APPENDFILE) - { - fsStatus = FSAProcessCmd_appendFile(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_TRUNCATEFILE) - { - fsStatus = FSAProcessCmd_truncateFile(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_ISEOF) - { - fsStatus = FSAProcessCmd_isEof(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_QUERYINFO) - { - fsStatus = FSAProcessCmd_queryInfo(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_GETSTATFILE) - { - fsStatus = FSAProcessCmd_getStatFile(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_GETCWD) - { - fsStatus = FSAProcessCmd_getCwd(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_CHANGEDIR) - { - fsStatus = FSAProcessCmd_changeDir(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_OPENDIR) - { - fsStatus = FSAProcessCmd_openDir(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_READDIR) - { - fsStatus = FSAProcessCmd_readDir(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_CLOSEDIR) - { - fsStatus = FSAProcessCmd_closeDir(client, fsaCommand); - } - else if (operationId == FSA_CMD_OPERATION_TYPE_FLUSHQUOTA) - { - fsStatus = FSAProcessCmd_flushQuota(client, fsaCommand); - } - else + default: { cemu_assert_unimplemented(); + break; } - IOS_ResourceReply(cmd, (IOS_ERROR)fsStatus); + } + + IOS_ResourceReply(cmd, (IOS_ERROR)fsaResult); + } + + void FSAHandleCommandIoctl(FSAClient* client, IPCCommandBody* cmd, FSA_CMD_OPERATION_TYPE operationId, void* ptrIn, void* ptrOut) + { + FSAShimBuffer* shimBuffer = (FSAShimBuffer*)ptrIn; + FSA_RESULT fsaResult = FSA_RESULT::FATAL_ERROR; + + switch (operationId) + { + case FSA_CMD_OPERATION_TYPE::REMOVE: + { + fsaResult = FSAProcessCmd_remove(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::CHANGEDIR: + { + fsaResult = FSAProcessCmd_changeDir(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::GETCWD: + { + fsaResult = FSAProcessCmd_getCwd(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::MAKEDIR: + { + fsaResult = FSAProcessCmd_makeDir(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::RENAME: + { + fsaResult = FSAProcessCmd_rename(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::OPENDIR: + { + fsaResult = FSAProcessCmd_openDir(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::READDIR: + { + fsaResult = FSAProcessCmd_readDir(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::CLOSEDIR: + { + fsaResult = FSAProcessCmd_closeDir(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::OPENFILE: + { + fsaResult = FSAProcessCmd_openFile(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::GETPOS: + { + fsaResult = FSAProcessCmd_getPos(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::SETPOS: + { + fsaResult = FSAProcessCmd_setPos(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::ISEOF: + { + fsaResult = FSAProcessCmd_isEof(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::GETSTATFILE: + { + fsaResult = FSAProcessCmd_getStatFile(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::CLOSEFILE: + { + fsaResult = FSAProcessCmd_closeFile(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::QUERYINFO: + { + fsaResult = FSAProcessCmd_queryInfo(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::APPENDFILE: + { + fsaResult = FSAProcessCmd_appendFile(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::TRUNCATEFILE: + { + fsaResult = FSAProcessCmd_truncateFile(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::FLUSHQUOTA: + { + fsaResult = FSAProcessCmd_flushQuota(client, shimBuffer); + break; + } + case FSA_CMD_OPERATION_TYPE::READ: + case FSA_CMD_OPERATION_TYPE::WRITE: + { + // These commands are IOCTLVs not IOCTL + cemu_assert_error(); + } + default: + { + cemu_assert_unimplemented(); + break; + } + } + IOS_ResourceReply(cmd, (IOS_ERROR)fsaResult); } void FSAIoThread() @@ -783,17 +814,17 @@ namespace iosu { cemu_assert(clientHandle < sFSAClientArray.size()); cemu_assert(sFSAClientArray[clientHandle].isAllocated); - FSAHandleCommandIoctl(sFSAClientArray.data() + clientHandle, cmd, cmd->args[0], MEMPTR(cmd->args[1]), MEMPTR(cmd->args[3])); + FSAHandleCommandIoctl(sFSAClientArray.data() + clientHandle, cmd, (FSA_CMD_OPERATION_TYPE)cmd->args[0].value(), MEMPTR(cmd->args[1]), MEMPTR(cmd->args[3])); } else if (cmd->cmdId == IPCCommandId::IOS_IOCTLV) { - cemu_assert_unimplemented(); - //uint32 requestId = cmd->args[0]; - //uint32 numIn = cmd->args[1]; - //uint32 numOut = cmd->args[2]; - //IPCIoctlVector* vec = MEMPTR{ cmd->args[3] }.GetPtr(); - IOS_ResourceReply(cmd, IOS_ERROR_INVALID); - continue; + cemu_assert(clientHandle < sFSAClientArray.size()); + cemu_assert(sFSAClientArray[clientHandle].isAllocated); + FSA_CMD_OPERATION_TYPE requestId = (FSA_CMD_OPERATION_TYPE)cmd->args[0].value(); + uint32 numIn = cmd->args[1]; + uint32 numOut = cmd->args[2]; + IPCIoctlVector* vec = MEMPTR{cmd->args[3]}.GetPtr(); + FSAHandleCommandIoctlv(sFSAClientArray.data() + clientHandle, cmd, requestId, numIn, numOut, vec); } else { @@ -820,5 +851,5 @@ namespace iosu IOS_SendMessage(sFSAIoMsgQueue, 0, 0); sFSAIoThread.join(); } - } -} + } // namespace fsa +} // namespace iosu diff --git a/src/Cafe/IOSU/fsa/iosu_fsa.h b/src/Cafe/IOSU/fsa/iosu_fsa.h index 35b53d46..8f8d2323 100644 --- a/src/Cafe/IOSU/fsa/iosu_fsa.h +++ b/src/Cafe/IOSU/fsa/iosu_fsa.h @@ -1,162 +1,197 @@ #pragma once +#include #include "fsa_types.h" namespace iosu { namespace fsa { - struct FSAIpcCommand + + struct FSARequest { + uint32be ukn0; union { + uint8 ukn04[0x51C]; struct { - uint32 ukn0000; - uint32 destBufferMPTR; // used as fileHandle for FSSetFilePosAsync - uint32 ukn0008; // used as filePos for FSSetFilePosAsync - uint32 ukn000C; - uint32 transferFilePos; // used as filePos for read/write operation - uint32 fileHandle; - uint32 cmdFlag; - uint32 ukn001C; - uint8 ukn0020[0x10]; - uint8 ukn0030[0x10]; - uint8 ukn0040[0x10]; - uint8 ukn0050[0x10]; - uint8 ukn0060[0x10]; - uint8 ukn0070[0x10]; - uint8 ukn0080[0x10]; - uint8 ukn0090[0x10]; - uint8 ukn00A0[0x10]; - uint8 ukn00B0[0x10]; - uint8 ukn00C0[0x10]; - uint8 ukn00D0[0x10]; - uint8 ukn00E0[0x10]; - uint8 ukn00F0[0x10]; - uint8 ukn0100[0x100]; - uint8 ukn0200[0x100]; - uint8 ukn0300[0x100]; - uint8 ukn0400[0x100]; - uint8 ukn0500[0x100]; - uint8 ukn0600[0x100]; - }cmdDefault; + MEMPTR dest; + uint32be size; + uint32be count; + uint32be filePos; + uint32be fileHandle; + uint32be flag; + } cmdReadFile; + struct + { + MEMPTR dest; + uint32be size; + uint32be count; + uint32be filePos; + uint32be fileHandle; + uint32be flag; + } cmdWriteFile; struct { - uint32 ukn0000; uint8 path[FSA_CMD_PATH_MAX_LENGTH]; - uint8 mode[12]; // +0x284 note: code seems to access this value like it has a size of 0x10 but the actual struct element is only 12 bytes? Maybe a typo (10 instead of 0x10 in the struct def) - uint32 createMode; // +0x290 - uint32 openFlags; // +0x294 - uint32 preallocSize; // +0x298 - uint8 ukn[0x2E8]; // +0x29C - // output - uint32be fileHandleOutput; // +0x584 used to return file handle on success - }cmdOpenFile; + uint8 mode[12]; // +0x284 note: code seems to access this value like it has a size of 0x10 but the actual struct element is only 12 bytes? Maybe a typo (10 instead of 0x10 in the struct def) + uint32be createMode; // +0x290 + uint32be openFlags; // +0x294 + uint32be preallocSize; // +0x298 + } cmdOpenFile; struct { - uint32 ukn0000; // +0x000 - uint32be fileHandle; // +0x004 - }cmdCloseFile; + uint32be fileHandle; + } cmdCloseFile; struct { - uint32 ukn0000; uint8 path[FSA_CMD_PATH_MAX_LENGTH]; - uint32 ukn0284; - uint8 ukn0288[0x80 - 8]; - uint8 ukn0300[0x100]; - uint8 ukn0400[0x100]; - uint32 ukn0500; - }cmdRemove; + } cmdRemove; struct { - uint32 ukn0000; uint8 path[FSA_CMD_PATH_MAX_LENGTH]; uint8 ukn0284[12]; // +0x284 - uint32 ukn0290; // +0x290 - uint32 ukn0294; // +0x294 - uint32 ukn0298; // +0x298 - uint8 ukn[0x2E8]; // +0x29C - // output - uint32be dirHandleOutput; // +0x584 used to return dir handle on success - }cmdOpenDir; + } cmdOpenDir; struct { - uint32 ukn0000; betype dirHandle; - }cmdReadDir; + } cmdReadDir; struct { - uint32 ukn0000; betype dirHandle; - }cmdCloseDir; + } cmdCloseDir; struct { - uint32 ukn0000; uint8 path[FSA_CMD_PATH_MAX_LENGTH]; - uint32 uknParam; - uint8 ukn0288[0x80 - 8]; - uint8 ukn0300[0x100]; - uint8 ukn0400[0x100]; - uint32 ukn0500; - }cmdMakeDir; + uint32be uknParam; + } cmdMakeDir; struct { - uint32 ukn0000; uint8 path[FSA_CMD_PATH_MAX_LENGTH]; - uint8 ukn0284[0x80 - 4]; - uint8 ukn0300[0x100]; - uint8 ukn0400[0x100]; - uint32 ukn0500; - }cmdChangeDir; + } cmdChangeDir; struct { - uint32 ukn0000; uint8 query[FSA_CMD_PATH_MAX_LENGTH]; - uint32 queryType; - uint8 ukn0288[0x80 - 8]; - uint8 ukn0300[0x100]; - uint8 ukn0400[0x100]; - uint32 ukn0500; - }cmdQueryInfo; + uint32be queryType; + } cmdQueryInfo; struct { - uint32 ukn0000; uint8 srcPath[FSA_CMD_PATH_MAX_LENGTH]; uint8 dstPath[FSA_CMD_PATH_MAX_LENGTH]; - }cmdRename; + } cmdRename; struct { - uint32 ukn0000; - uint32 size; - uint32 count; - uint32 fileHandle; - uint32 uknParam; - }cmdAppendFile; + uint32be size; + uint32be count; + uint32be fileHandle; + uint32be uknParam; + } cmdAppendFile; struct { - uint32 ukn0000; - betype fileHandle; - uint32be ukn0008; - }cmdTruncateFile; + uint32be fileHandle; + } cmdTruncateFile; struct { - uint32 ukn0000; - betype fileHandle; - }cmdGetStatFile; + uint32be fileHandle; + } cmdGetStatFile; struct { - uint32 ukn0000; uint8 path[FSA_CMD_PATH_MAX_LENGTH]; - }cmdFlushQuota; + } cmdFlushQuota; + struct + { + uint32be fileHandle; + uint32be filePos; + } cmdSetPosFile; + struct + { + uint32be fileHandle; + } cmdGetPosFile; + struct + { + uint32be fileHandle; + } cmdIsEof; }; - uint8 ukn0700[0x100]; - uint8 ukn0800[0x10]; - uint8 ukn0810[0x10]; }; + static_assert(sizeof(FSARequest) == 0x520); - static_assert(sizeof(FSAIpcCommand) == 0x820); // exact size of this is not known + struct FSAResponse + { + uint32be ukn0; + union + { + uint8 ukn04[0x28F]; + struct + { + uint32be fileHandleOutput; // +0x584 used to return file handle on success + } cmdOpenFile; + struct + { + uint32be dirHandleOutput; // +0x584 used to return dir handle on success + } cmdOpenDir; + struct + { + uint32be filePos; + } cmdGetPosFile; + struct + { + FSStat_t statOut; + } cmdStatFile; + struct + { + FSDirEntry_t dirEntry; + } cmdReadDir; + struct + { + char path[FSA_CMD_PATH_MAX_LENGTH]; + } cmdGetCWD; + struct + { + union + { + uint8 ukn04[0x64]; + struct + { + uint64be freespace; + } queryFreeSpace; + struct + { + FSStat_t stat; + } queryStat; + }; + } cmdQueryInfo; + }; + }; + // static_assert(sizeof(FSAResponse) == 0x293); + + struct FSAShimBuffer + { + FSARequest request; + uint8 ukn0520[0x60]; + FSAResponse response; + uint8 ukn0813[0x6D]; + IPCIoctlVector ioctlvVec[3]; + uint8 ukn08A4[0x5C]; + /* +0x0900 */ uint32be operationType; + betype fsaDevHandle; + /* +0x0908 */ uint16be ipcReqType; // 0 -> IoctlAsync, 1 -> IoctlvAsync + uint8 ioctlvVecIn; + uint8 ioctlvVecOut; + uint32 ukn090C; + uint32 ukn0910; + uint32 ukn0914; + uint32 ukn0918; + uint32 ukn091C; + uint32 ukn0920; + uint32 ukn0924; + uint32 ukn0928; + uint32 ukn092C; + uint32 ukn0930; + uint32 ukn0934; + }; + // static_assert(sizeof(FSAShimBuffer) == 0x938); // exact size of this is not known void Initialize(); void Shutdown(); - } -} + } // namespace fsa +} // namespace iosu diff --git a/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp b/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp index c53d93c7..6a864cf2 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_FS.cpp @@ -1,3 +1,4 @@ +#include #include "config/ActiveSettings.h" #include "Cafe/OS/libs/coreinit/coreinit_SystemInfo.h" #include "Cafe/OS/common/OSCommon.h" @@ -10,11 +11,11 @@ #include "coreinit_IPC.h" #include "Cafe/Filesystem/fsc.h" -#define FS_CB_PLACEHOLDER_FINISHCMD (MPTR)(0xF122330E) +#define FS_CB_PLACEHOLDER_FINISHCMD (MPTR)(0xF122330E) // return false if src+'\0' does not fit into dst template -bool strcpy_whole(char(&dst)[Size], const char* src) +bool strcpy_whole(char (&dst)[Size], const char* src) { size_t inputLength = strlen(src); if ((inputLength + 1) > Size) @@ -64,24 +65,24 @@ namespace coreinit // 1 = usb? }; - struct FS_MOUNT_SOURCE + struct FS_MOUNT_SOURCE { uint32be sourceType; // ukn values - char path[128]; // todo - determine correct length + char path[128]; // todo - determine correct length }; FS_RESULT FSGetMountSourceNext(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, MOUNT_TYPE mountSourceType, FS_MOUNT_SOURCE* mountSourceInfo, FS_ERROR_MASK errMask) { // hacky static FS_MOUNT_SOURCE* s_last_source = nullptr; - if(s_last_source != mountSourceInfo) + if (s_last_source != mountSourceInfo) { s_last_source = mountSourceInfo; fsCmdBlock->data.mount_it = 0; } fsCmdBlock->data.mount_it++; - + // SD if (mountSourceType == MOUNT_TYPE::SD && fsCmdBlock->data.mount_it == 1) { @@ -135,7 +136,8 @@ namespace coreinit FS_RESULT FSBindMount(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* mountPathSrc, char* mountPathOut, FS_ERROR_MASK errMask) { - if (strcmp(mountPathSrc, "/dev/sdcard01") == 0) { + if (strcmp(mountPathSrc, "/dev/sdcard01") == 0) + { if (_sdCard01Mounted) return FS_RESULT::ERR_PLACEHOLDER; @@ -146,7 +148,8 @@ namespace coreinit return FS_RESULT::ERR_PLACEHOLDER; _sdCard01Mounted = true; } - else if (strcmp(mountPathSrc, "/dev/mlc01") == 0) { + else if (strcmp(mountPathSrc, "/dev/mlc01") == 0) + { if (_mlc01Mounted) return FS_RESULT::ERR_PLACEHOLDER; @@ -154,7 +157,8 @@ namespace coreinit return FS_RESULT::ERR_PLACEHOLDER; _mlc01Mounted = true; } - else { + else + { return FS_RESULT::ERR_PLACEHOLDER; } @@ -183,7 +187,6 @@ namespace coreinit return fsCmdBlockBody; } - void __FSErrorAndBlock(std::string_view msg) { cemuLog_log(LogType::Force, "Critical error in FS: {}", msg); @@ -436,16 +439,21 @@ namespace coreinit void __FSAIoctlResponseCallback(PPCInterpreter_t* hCPU); - void __FSAIPCSubmitCommand(FSCmdBlockBody_t* cmd) + void __FSAIPCSubmitCommandAsync(iosu::fsa::FSAShimBuffer* shimBuffer, const MEMPTR& callback, void* context) { - if (cmd->ipcReqType == 0) + if (shimBuffer->ipcReqType == 0) { - IOS_ERROR r = IOS_IoctlAsync(cmd->fsaDevHandle, cmd->operationType, cmd, 0x520, (uint8*)cmd + 0x580, 0x293, MEMPTR(PPCInterpreter_makeCallableExportDepr(__FSAIoctlResponseCallback)), cmd); + IOS_ERROR r = IOS_IoctlAsync(shimBuffer->fsaDevHandle, shimBuffer->operationType, &shimBuffer->request, sizeof(shimBuffer->request), &shimBuffer->response, sizeof(shimBuffer->response), callback, context); + cemu_assert(!IOS_ResultIsError(r)); + } + else if (shimBuffer->ipcReqType == 1) + { + IOS_ERROR r = IOS_IoctlvAsync(shimBuffer->fsaDevHandle, shimBuffer->operationType, shimBuffer->ioctlvVecIn, shimBuffer->ioctlvVecOut, shimBuffer->ioctlvVec, callback, context); cemu_assert(!IOS_ResultIsError(r)); } else { - cemu_assert_unimplemented(); // IOS_IoctlvAsync + cemu_assert_error(); } } @@ -461,15 +469,103 @@ namespace coreinit if (cmdQueue->numCommandsInFlight >= cmdQueue->numMaxCommandsInFlight) cmdQueue->queueFlags = cmdQueue->queueFlags | FSCmdQueue::QUEUE_FLAG::IS_FULL; cemu_assert_debug(cmdQueue->dequeueHandlerFuncMPTR == 0); // not supported. We HLE call the handler here - __FSAIPCSubmitCommand(dequeuedCommand); + __FSAIPCSubmitCommandAsync(&dequeuedCommand->fsaShimBuffer, MEMPTR(PPCInterpreter_makeCallableExportDepr(__FSAIoctlResponseCallback)), &dequeuedCommand->fsaShimBuffer); } } FSUnlockMutex(); } + void __FSQueueDefaultFinishFunc(FSCmdBlockBody_t* fsCmdBlockBody, FS_RESULT result) + { + switch ((FSA_CMD_OPERATION_TYPE)fsCmdBlockBody->fsaShimBuffer.operationType.value()) + { + case FSA_CMD_OPERATION_TYPE::OPENFILE: + { + *fsCmdBlockBody->returnValues.cmdOpenFile.handlePtr = fsCmdBlockBody->fsaShimBuffer.response.cmdOpenFile.fileHandleOutput; + break; + } + + case FSA_CMD_OPERATION_TYPE::GETCWD: + { + auto transferSize = fsCmdBlockBody->returnValues.cmdGetCwd.transferSize; + if (transferSize < 0 && transferSize > sizeof(fsCmdBlockBody->fsaShimBuffer.response.cmdGetCWD.path)) + { + cemu_assert_error(); + } + memcpy(fsCmdBlockBody->returnValues.cmdGetCwd.pathPtr, fsCmdBlockBody->fsaShimBuffer.response.cmdGetCWD.path, transferSize); + break; + } + + case FSA_CMD_OPERATION_TYPE::OPENDIR: + { + *fsCmdBlockBody->returnValues.cmdOpenDir.handlePtr = fsCmdBlockBody->fsaShimBuffer.response.cmdOpenDir.dirHandleOutput; + break; + } + case FSA_CMD_OPERATION_TYPE::READDIR: + { + *fsCmdBlockBody->returnValues.cmdReadDir.dirEntryPtr = fsCmdBlockBody->fsaShimBuffer.response.cmdReadDir.dirEntry; + break; + } + case FSA_CMD_OPERATION_TYPE::GETPOS: + { + *fsCmdBlockBody->returnValues.cmdGetPosFile.filePosPtr = fsCmdBlockBody->fsaShimBuffer.response.cmdGetPosFile.filePos; + break; + } + case FSA_CMD_OPERATION_TYPE::GETSTATFILE: + { + *((FSStat_t*)fsCmdBlockBody->returnValues.cmdStatFile.resultPtr.GetPtr()) = fsCmdBlockBody->fsaShimBuffer.response.cmdStatFile.statOut; + break; + } + case FSA_CMD_OPERATION_TYPE::QUERYINFO: + { + if (fsCmdBlockBody->fsaShimBuffer.request.cmdQueryInfo.queryType == FSA_QUERY_TYPE_FREESPACE) + { + *((uint64be*)fsCmdBlockBody->returnValues.cmdQueryInfo.queryResultPtr.GetPtr()) = fsCmdBlockBody->fsaShimBuffer.response.cmdQueryInfo.queryFreeSpace.freespace; + } + else if (fsCmdBlockBody->fsaShimBuffer.request.cmdQueryInfo.queryType == FSA_QUERY_TYPE_STAT) + { + *((FSStat_t*)fsCmdBlockBody->returnValues.cmdQueryInfo.queryResultPtr.GetPtr()) = fsCmdBlockBody->fsaShimBuffer.response.cmdQueryInfo.queryStat.stat; + } + else + { + cemu_assert_unimplemented(); + } + break; + } + case FSA_CMD_OPERATION_TYPE::CHANGEDIR: + case FSA_CMD_OPERATION_TYPE::MAKEDIR: + case FSA_CMD_OPERATION_TYPE::REMOVE: + case FSA_CMD_OPERATION_TYPE::RENAME: + case FSA_CMD_OPERATION_TYPE::CLOSEDIR: + case FSA_CMD_OPERATION_TYPE::READ: + case FSA_CMD_OPERATION_TYPE::WRITE: + case FSA_CMD_OPERATION_TYPE::SETPOS: + case FSA_CMD_OPERATION_TYPE::ISEOF: + case FSA_CMD_OPERATION_TYPE::CLOSEFILE: + case FSA_CMD_OPERATION_TYPE::APPENDFILE: + case FSA_CMD_OPERATION_TYPE::TRUNCATEFILE: + case FSA_CMD_OPERATION_TYPE::FLUSHQUOTA: + { + break; + } + default: + { + cemu_assert_unimplemented(); + } + } + } + + void export___FSQueueDefaultFinishFunc(PPCInterpreter_t* hCPU) + { + ppcDefineParamPtr(cmd, FSCmdBlockBody_t, 0); + FS_RESULT result = (FS_RESULT)PPCInterpreter_getCallParamU32(hCPU, 1); + __FSQueueDefaultFinishFunc(cmd, static_cast(result)); + osLib_returnFromFunction(hCPU, 0); + } + void __FSQueueCmd(FSCmdQueue* cmdQueue, FSCmdBlockBody_t* fsCmdBlockBody, MPTR finishCmdFunc) { - fsCmdBlockBody->cmdFinishFuncMPTR = _swapEndianU32(finishCmdFunc); + fsCmdBlockBody->cmdFinishFuncMPTR = finishCmdFunc; FSLockMutex(); fsCmdBlockBody->statusCode = _swapEndianU32(FSA_CMD_STATUS_CODE_D900A22); __FSQueueCmdByPriority(cmdQueue, fsCmdBlockBody, true); @@ -484,9 +580,60 @@ namespace coreinit FS_RESULT _FSAStatusToFSStatus(FSA_RESULT err) { - // todo - // currently /dev/fsa uses FS status codes internally. We should refactor everything to use FSA error codes (which are compatible with IOS_ERROR) and then translate them here to FS status - return (FS_RESULT)err; + if ((int)err > 0) + { + return (FS_RESULT)err; + } + switch (err) + { + case FSA_RESULT::SUCCESS: + { + return FS_RESULT::SUCCESS; + } + case FSA_RESULT::END_DIR: + case FSA_RESULT::END_FILE: + { + return FS_RESULT::END_ITERATION; + } + case FSA_RESULT::ALREADY_EXISTS: + { + return FS_RESULT::ALREADY_EXISTS; + } + case FSA_RESULT::NOT_FOUND: + { + return FS_RESULT::NOT_FOUND; + } + case FSA_RESULT::PERMISSION_ERROR: + { + return FS_RESULT::PERMISSION_ERROR; + } + case FSA_RESULT::NOT_FILE: + { + return FS_RESULT::NOT_FILE; + } + case FSA_RESULT::NOT_DIR: + { + return FS_RESULT::NOT_DIR; + } + case FSA_RESULT::MAX_FILES: + case FSA_RESULT::MAX_DIRS: + { + return FS_RESULT::MAX_HANDLES; + } + case FSA_RESULT::INVALID_CLIENT_HANDLE: + case FSA_RESULT::INVALID_FILE_HANDLE: + case FSA_RESULT::INVALID_DIR_HANDLE: + case FSA_RESULT::INVALID_PARAM: + case FSA_RESULT::INVALID_PATH: + case FSA_RESULT::INVALID_BUFFER: + case FSA_RESULT::INVALID_ALIGNMENT: + case FSA_RESULT::FATAL_ERROR: + { + return FS_RESULT::FATAL_ERROR; + } + } + cemu_assert_unimplemented(); + return FS_RESULT::FATAL_ERROR; } void __FSCmdSubmitResult(FSCmdBlockBody_t* fsCmdBlockBody, FS_RESULT result) @@ -494,7 +641,7 @@ namespace coreinit _debugVerifyCommand("FSCmdSubmitResult", fsCmdBlockBody); FSClientBody_t* fsClientBody = fsCmdBlockBody->fsClientBody.GetPtr(); - sFSClientLock.lock(); // OSFastMutex_Lock(&fsClientBody->fsCmdQueue.mutex) + sFSClientLock.lock(); // OSFastMutex_Lock(&fsClientBody->fsCmdQueue.mutex) fsCmdBlockBody->cancelState &= ~(1 << 0); // clear cancel bit if (fsClientBody->currentCmdBlockBody.GetPtr() == fsCmdBlockBody) fsClientBody->currentCmdBlockBody = nullptr; @@ -550,6 +697,13 @@ namespace coreinit cmdQueue.numCommandsInFlight -= 1; cmdQueue.queueFlags = cmdQueue.queueFlags & ~FSCmdQueue::QUEUE_FLAG::IS_FULL; FSUnlockMutex(); + + if (cmd->cmdFinishFuncMPTR) + { + if (cmd->cmdFinishFuncMPTR != FS_CB_PLACEHOLDER_FINISHCMD) + PPCCoreCallback(MEMPTR(cmd->cmdFinishFuncMPTR), cmd, fsStatus); + } + __FSCmdSubmitResult(cmd, fsStatus); __FSUpdateQueue(&cmd->fsClientBody->fsCmdQueue); osLib_returnFromFunction(hCPU, 0); @@ -612,15 +766,17 @@ namespace coreinit fsCmdBlockBody->errHandling = _swapEndianU32(errHandling); fsCmdBlockBody->uknStatusGuessed09E9 = 0; fsCmdBlockBody->cancelState &= ~(1 << 0); // clear cancel bit - fsCmdBlockBody->fsaDevHandle = fsClientBody->iosuFSAHandle; - __FSPrepareCmdAsyncResult(fsClientBody, fsCmdBlockBody , &fsCmdBlockBody->asyncResult, fsAsyncParams); + fsCmdBlockBody->fsaShimBuffer.fsaDevHandle = fsClientBody->iosuFSAHandle; + __FSPrepareCmdAsyncResult(fsClientBody, fsCmdBlockBody, &fsCmdBlockBody->asyncResult, fsAsyncParams); return 0; } -#define _FSCmdIntro() FSClientBody_t* fsClientBody = __FSGetClientBody(fsClient); \ - FSCmdBlockBody_t* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock); \ - sint32 fsError = __FSPrepareCmd(fsClientBody, fsCmdBlockBody, errorMask, fsAsyncParams); \ - if (fsError != 0) return fsError; +#define _FSCmdIntro() \ + FSClientBody_t* fsClientBody = __FSGetClientBody(fsClient); \ + FSCmdBlockBody_t* fsCmdBlockBody = __FSGetCmdBlockBody(fsCmdBlock); \ + sint32 fsError = __FSPrepareCmd(fsClientBody, fsCmdBlockBody, errorMask, fsAsyncParams); \ + if (fsError != 0) \ + return fsError; void _debugVerifyCommand(const char* stage, FSCmdBlockBody_t* fsCmdBlockBody) { @@ -631,11 +787,10 @@ namespace coreinit for (uint32 i = 0; i < (sizeof(FSCmdBlockBody_t) + 31) / 32; i++) { uint8* p = ((uint8*)fsCmdBlockBody) + i * 32; - cemuLog_log(LogType::Force, "{:04x}: {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} | {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x}", - i * 32, - p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15], - p[16], p[17], p[18], p[19], p[20], p[21], p[22], p[23], p[24], p[25], p[26], p[27], p[28], p[29], p[30], p[31]); - + cemuLog_log(LogType::Force, "{:04x}: {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} | {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x} - {:02x} {:02x} {:02x} {:02x}", + i * 32, + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15], + p[16], p[17], p[18], p[19], p[20], p[21], p[22], p[23], p[24], p[25], p[26], p[27], p[28], p[29], p[30], p[31]); } } } @@ -666,18 +821,17 @@ namespace coreinit } } - uint32 __FSPrepareCmd_OpenFile(FSCmdBlockBody_t* fsCmdBlockBody, char* path, char* mode, uint32 createMode, uint32 openFlags, uint32 preallocSize) + FSA_RESULT __FSPrepareCmd_OpenFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, char* path, char* mode, uint32 createMode, uint32 openFlags, uint32 preallocSize) { - fsCmdBlockBody->fsCmdBlockBodyMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBody)); - if (fsCmdBlockBody == NULL) - return 0xFFFCFFDD; + if (fsaShimBuffer == NULL) + return FSA_RESULT::INVALID_BUFFER; if (path == NULL) - return 0xFFFCFFDD + 1; + return FSA_RESULT::INVALID_PATH; if (mode == NULL) - return 0xFFFCFFDD + 2; - fsCmdBlockBody->fsCmdBlockBodyMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBody)); - fsCmdBlockBody->ipcData.cmdOpenFile.fileHandleOutput = _swapEndianU32(0xFFFFFFFF); - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_OPENFILE; + return FSA_RESULT::INVALID_PARAM; + fsaShimBuffer->fsaDevHandle = fsaHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::OPENFILE; // path size_t pathLen = strlen((char*)path); if (pathLen >= FSA_CMD_PATH_MAX_LENGTH) @@ -686,9 +840,9 @@ namespace coreinit pathLen = FSA_CMD_PATH_MAX_LENGTH - 1; } for (sint32 i = 0; i < pathLen; i++) - fsCmdBlockBody->ipcData.cmdOpenFile.path[i] = path[i]; + fsaShimBuffer->request.cmdOpenFile.path[i] = path[i]; for (size_t i = pathLen; i < FSA_CMD_PATH_MAX_LENGTH; i++) - fsCmdBlockBody->ipcData.cmdOpenFile.path[i] = '\0'; + fsaShimBuffer->request.cmdOpenFile.path[i] = '\0'; // mode size_t modeLen = strlen((char*)mode); if (modeLen >= 12) @@ -697,28 +851,31 @@ namespace coreinit modeLen = 12 - 1; } for (sint32 i = 0; i < modeLen; i++) - fsCmdBlockBody->ipcData.cmdOpenFile.mode[i] = mode[i]; + fsaShimBuffer->request.cmdOpenFile.mode[i] = mode[i]; for (size_t i = modeLen; i < 12; i++) - fsCmdBlockBody->ipcData.cmdOpenFile.mode[i] = '\0'; + fsaShimBuffer->request.cmdOpenFile.mode[i] = '\0'; // createMode - fsCmdBlockBody->ipcData.cmdOpenFile.createMode = createMode; + fsaShimBuffer->request.cmdOpenFile.createMode = createMode; // openFlags - fsCmdBlockBody->ipcData.cmdOpenFile.openFlags = openFlags; + fsaShimBuffer->request.cmdOpenFile.openFlags = openFlags; // preallocSize - fsCmdBlockBody->ipcData.cmdOpenFile.preallocSize = preallocSize; - return 0; + fsaShimBuffer->request.cmdOpenFile.preallocSize = preallocSize; + + fsaShimBuffer->response.cmdOpenFile.fileHandleOutput = 0xFFFFFFFF; + + return FSA_RESULT::SUCCESS; } - sint32 FSOpenFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandleDepr_t* fileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) + sint32 FSOpenFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandleDepr_t* outFileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { _FSCmdIntro(); - if (fileHandle == nullptr || path == nullptr || mode == nullptr) + if (outFileHandle == nullptr || path == nullptr || mode == nullptr) return -0x400; - fsCmdBlockBody->returnValueMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fileHandle)); - fsError = __FSPrepareCmd_OpenFile(fsCmdBlockBody, path, mode, 0x660, 0, 0); + fsCmdBlockBody->returnValues.cmdOpenFile.handlePtr = &outFileHandle->fileHandle; + fsError = (FSStatus)__FSPrepareCmd_OpenFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, path, mode, 0x660, 0, 0); if (fsError != (FSStatus)FS_RESULT::SUCCESS) return fsError; - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -730,7 +887,7 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling); } - sint32 FSOpenFileExAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, uint32 createMode, uint32 openFlag, uint32 preallocSize, FSFileHandleDepr_t* fileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) + sint32 FSOpenFileExAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, uint32 createMode, uint32 openFlag, uint32 preallocSize, FSFileHandleDepr_t* outFileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { if (openFlag != 0) { @@ -739,13 +896,15 @@ namespace coreinit } _FSCmdIntro(); - if (fileHandle == nullptr || path == nullptr || mode == nullptr) + if (outFileHandle == nullptr || path == nullptr || mode == nullptr) return -0x400; - fsCmdBlockBody->returnValueMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fileHandle)); - fsError = __FSPrepareCmd_OpenFile(fsCmdBlockBody, path, mode, createMode, openFlag, preallocSize); - if (fsError != (FSStatus)FS_RESULT::SUCCESS) - return fsError; - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + fsCmdBlockBody->returnValues.cmdOpenFile.handlePtr = &outFileHandle->fileHandle; + + FSA_RESULT prepareResult = __FSPrepareCmd_OpenFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, path, mode, createMode, openFlag, preallocSize); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -757,17 +916,28 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling); } - void __FSPrepareCmd_CloseFile(FSCmdBlockBody_t* fsCmdBlockBody, uint32 fileHandle) + FSA_RESULT __FSPrepareCmd_CloseFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, uint32 fileHandle) { - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_CLOSEFILE; - fsCmdBlockBody->ipcData.cmdCloseFile.fileHandle = fileHandle; + if (fsaShimBuffer == nullptr) + { + return FSA_RESULT::INVALID_BUFFER; + } + fsaShimBuffer->fsaDevHandle = fsaHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::CLOSEFILE; + fsaShimBuffer->request.cmdCloseFile.fileHandle = fileHandle; + return FSA_RESULT::SUCCESS; } sint32 FSCloseFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { _FSCmdIntro(); - __FSPrepareCmd_CloseFile(fsCmdBlockBody, fileHandle); - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + + FSA_RESULT prepareResult = __FSPrepareCmd_CloseFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -779,31 +949,38 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errHandling); } - uint32 __FSPrepareCmd_ReadFile(FSCmdBlockBody_t* fsCmdBlockBody, void* dest, uint32 uknR6, uint32 transferSizeUknAligned, uint32 filePos, uint32 fileHandle, uint32 flag) + FSA_RESULT __FSPrepareCmd_ReadFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, void* dest, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag) { - fsCmdBlockBody->fsCmdBlockBodyMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBody)); - if (fsCmdBlockBody == NULL || dest == NULL) - return 0xFFFCFFDD; + if (fsaShimBuffer == NULL || dest == NULL) + return FSA_RESULT::INVALID_BUFFER; MPTR destMPTR = memory_getVirtualOffsetFromPointer(dest); if ((destMPTR & 0x3F) != 0) - return 0xFFFCFFDC; - fsCmdBlockBody->fsCmdBlockBodyMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBody)); - fsCmdBlockBody->ipcData.cmdDefault.fileHandle = _swapEndianU32(fileHandle); - fsCmdBlockBody->ukn0898 = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBody) + 0x580); - fsCmdBlockBody->ipcData.cmdDefault.ukn0008 = _swapEndianU32(uknR6); - fsCmdBlockBody->ipcData.cmdDefault.ukn000C = _swapEndianU32(transferSizeUknAligned); - uint32 fullTransferSize = transferSizeUknAligned * uknR6; - fsCmdBlockBody->ukn090B = 2; // byte - fsCmdBlockBody->ukn089C = _swapEndianU32(0x293); - fsCmdBlockBody->ukn0890 = _swapEndianU32(fullTransferSize); - fsCmdBlockBody->ukn0884 = _swapEndianU32(0x520); - fsCmdBlockBody->destBuffer88CMPTR = _swapEndianU32(destMPTR); - fsCmdBlockBody->ukn090A = 1; - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_READ; - fsCmdBlockBody->ipcData.cmdDefault.destBufferMPTR = _swapEndianU32(destMPTR); - fsCmdBlockBody->ipcData.cmdDefault.transferFilePos = _swapEndianU32(filePos); - fsCmdBlockBody->ipcData.cmdDefault.cmdFlag = _swapEndianU32(flag); - return 0; + return FSA_RESULT::INVALID_ALIGNMENT; + + fsaShimBuffer->fsaDevHandle = fsaHandle; + fsaShimBuffer->ipcReqType = 1; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::READ; + + fsaShimBuffer->ioctlvVecIn = 1; + fsaShimBuffer->ioctlvVecOut = 2; + + fsaShimBuffer->ioctlvVec[0].baseVirt = fsaShimBuffer; + fsaShimBuffer->ioctlvVec[0].size = sizeof(iosu::fsa::FSARequest); + + fsaShimBuffer->ioctlvVec[1].baseVirt = destMPTR; + fsaShimBuffer->ioctlvVec[1].size = size * count; + + fsaShimBuffer->ioctlvVec[2].baseVirt = &fsaShimBuffer->response; + fsaShimBuffer->ioctlvVec[2].size = sizeof(iosu::fsa::FSAResponse); + + fsaShimBuffer->request.cmdReadFile.dest = dest; + fsaShimBuffer->request.cmdReadFile.size = size; + fsaShimBuffer->request.cmdReadFile.count = count; + fsaShimBuffer->request.cmdReadFile.filePos = filePos; + fsaShimBuffer->request.cmdReadFile.fileHandle = fileHandle; + fsaShimBuffer->request.cmdReadFile.flag = flag; + + return FSA_RESULT::SUCCESS; } SysAllocator _tempFSSpace; @@ -820,21 +997,22 @@ namespace coreinit cemu_assert(false); return -0x400; } - uint32 transferSize = (uint32)transferSizeS64; - fsCmdBlockBody->transferSize = _swapEndianU32(transferSize); - fsCmdBlockBody->transferElemSize = _swapEndianU32(size); - fsCmdBlockBody->uknVal094C = _swapEndianU32(0); - if (transferSize < 0x10) - transferSize = 0x10; - fsCmdBlockBody->uknVal0954 = _swapEndianU32(transferSize); - if(usePos) + + // coreinit.rpl splits up each read into smaller chunks (probably to support canceling big writes). This is handled by a specific + // callback for the __FSQueueCmd functions. Whenever a chunk is read, it's getting re-queued until the reading has been completed. + // For this it writes values into the fsCmdBlockBody->returnValues struct. At the moment we go the lazy route of just reading everything + // at once, so we can skip the initialization of these values. + + if (usePos) flag |= FSA_CMD_FLAG_SET_POS; else flag &= ~FSA_CMD_FLAG_SET_POS; - fsError = __FSPrepareCmd_ReadFile(fsCmdBlockBody, dest, 1, transferSize, filePos, fileHandle, flag); - if (fsError != (FSStatus)FS_RESULT::SUCCESS) - return fsError; - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + + FSA_RESULT prepareResult = __FSPrepareCmd_ReadFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, dest, size, count, filePos, fileHandle, flag); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -867,32 +1045,38 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - uint32 __FSPrepareCmd_WriteFile(FSCmdBlockBody_t* fsCmdBlockBody, void* dest, uint32 uknR6, uint32 transferSizeUknAligned, uint32 filePos, uint32 fileHandle, uint32 flag) + FSA_RESULT __FSPrepareCmd_WriteFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, void* dest, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag) { - fsCmdBlockBody->fsCmdBlockBodyMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBody)); - if (fsCmdBlockBody == NULL && dest == NULL) - return 0xFFFCFFDD; + if (fsaShimBuffer == NULL || dest == NULL) + return FSA_RESULT::INVALID_BUFFER; MPTR destMPTR = memory_getVirtualOffsetFromPointer(dest); if ((destMPTR & 0x3F) != 0) - return 0xFFFCFFDC; - cemu_assert_debug((uknR6 * transferSizeUknAligned) != 0); // todo: do zero-sized writes need special treatment? - fsCmdBlockBody->fsCmdBlockBodyMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBody)); - fsCmdBlockBody->ipcData.cmdDefault.fileHandle = _swapEndianU32(fileHandle); - fsCmdBlockBody->ukn0898 = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBody) + 0x580); // verified - fsCmdBlockBody->ipcData.cmdDefault.ukn0008 = _swapEndianU32(uknR6); - fsCmdBlockBody->ipcData.cmdDefault.ukn000C = _swapEndianU32(transferSizeUknAligned); - uint32 fullTransferSize = transferSizeUknAligned * uknR6; - fsCmdBlockBody->ukn090B = 1; // byte - verified (note: This member holds 2 for read operations) - fsCmdBlockBody->ukn089C = _swapEndianU32(0x293); - fsCmdBlockBody->ukn0890 = _swapEndianU32(fullTransferSize); - fsCmdBlockBody->ukn0884 = _swapEndianU32(0x520); // verified - fsCmdBlockBody->destBuffer88CMPTR = _swapEndianU32(destMPTR); - fsCmdBlockBody->ukn090A = 1; - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_WRITE; - fsCmdBlockBody->ipcData.cmdDefault.destBufferMPTR = _swapEndianU32(destMPTR); - fsCmdBlockBody->ipcData.cmdDefault.transferFilePos = _swapEndianU32(filePos); - fsCmdBlockBody->ipcData.cmdDefault.cmdFlag = _swapEndianU32(flag); - return (FSStatus)FS_RESULT::SUCCESS; + return FSA_RESULT::INVALID_ALIGNMENT; + + fsaShimBuffer->fsaDevHandle = fsaHandle; + fsaShimBuffer->ipcReqType = 1; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::WRITE; + + fsaShimBuffer->ioctlvVecIn = 2; + fsaShimBuffer->ioctlvVecOut = 1; + + fsaShimBuffer->ioctlvVec[0].baseVirt = fsaShimBuffer; + fsaShimBuffer->ioctlvVec[0].size = sizeof(iosu::fsa::FSARequest); + + fsaShimBuffer->ioctlvVec[1].baseVirt = destMPTR; + fsaShimBuffer->ioctlvVec[1].size = size * count; + + fsaShimBuffer->ioctlvVec[2].baseVirt = &fsaShimBuffer->response; + fsaShimBuffer->ioctlvVec[2].size = sizeof(iosu::fsa::FSAResponse); + + fsaShimBuffer->request.cmdWriteFile.dest = dest; + fsaShimBuffer->request.cmdWriteFile.size = size; + fsaShimBuffer->request.cmdWriteFile.count = count; + fsaShimBuffer->request.cmdWriteFile.filePos = filePos; + fsaShimBuffer->request.cmdWriteFile.fileHandle = fileHandle; + fsaShimBuffer->request.cmdWriteFile.flag = flag; + + return FSA_RESULT::SUCCESS; } sint32 __FSWriteFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dest, uint32 size, uint32 count, bool useFilePos, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) @@ -907,19 +1091,22 @@ namespace coreinit cemu_assert(false); return -0x400; } - uint32 transferSize = (uint32)transferSizeS64; - fsCmdBlockBody->transferSize = _swapEndianU32(transferSize); - fsCmdBlockBody->transferElemSize = _swapEndianU32(size); - fsCmdBlockBody->uknVal094C = _swapEndianU32(0); - fsCmdBlockBody->uknVal0954 = _swapEndianU32(transferSize); + + // coreinit.rpl splits up each write into smaller chunks (probably to support canceling big writes). This is handled by a specific + // callback for the __FSQueueCmd functions. Whenever a chunk is written, it's getting re-queued until the writing has been completed. + // For this it writes values into the fsCmdBlockBody->returnValues struct. At the moment we go the lazy route of just writing everything + // at once, so we can skip the initialization of these values. + if (useFilePos) flag |= FSA_CMD_FLAG_SET_POS; else flag &= ~FSA_CMD_FLAG_SET_POS; - fsError = __FSPrepareCmd_WriteFile(fsCmdBlockBody, dest, 1, transferSize, filePos, fileHandle, flag); - if (fsError != (FSStatus)FS_RESULT::SUCCESS) - return fsError; - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + + FSA_RESULT prepareResult = __FSPrepareCmd_WriteFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, dest, size, count, filePos, fileHandle, flag); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -949,23 +1136,26 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - uint32 __FSPrepareCmd_SetPosFile(FSCmdBlockBody_t* fsCmdBlockBody, uint32 fileHandle, uint32 filePos) + FSA_RESULT __FSPrepareCmd_SetPosFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, uint32 fileHandle, uint32 filePos) { - if (fsCmdBlockBody == NULL) - return 0xFFFCFFDD; - fsCmdBlockBody->ipcData.cmdDefault.destBufferMPTR = _swapEndianU32(fileHandle); - fsCmdBlockBody->ipcData.cmdDefault.ukn0008 = _swapEndianU32(filePos); - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_SETPOS; - return 0; + if (fsaShimBuffer == NULL) + return FSA_RESULT::INVALID_BUFFER; + + fsaShimBuffer->fsaDevHandle = fsaHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->request.cmdSetPosFile.fileHandle = fileHandle; + fsaShimBuffer->request.cmdSetPosFile.filePos = filePos; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::SETPOS; + return FSA_RESULT::SUCCESS; } sint32 FSSetPosFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 filePos, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { _FSCmdIntro(); - fsError = __FSPrepareCmd_SetPosFile(fsCmdBlockBody, fileHandle, filePos); - if (fsError != (FSStatus)FS_RESULT::SUCCESS) - return fsError; - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + FSA_RESULT prepareResult = __FSPrepareCmd_SetPosFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle, filePos); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -978,24 +1168,26 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - uint32 __FSPrepareCmd_GetPosFile(FSCmdBlockBody_t* fsCmdBlockBody, uint32 fileHandle) + FSA_RESULT __FSPrepareCmd_GetPosFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, uint32 fileHandle) { - if (fsCmdBlockBody == NULL) - return 0xFFFCFFDD; - fsCmdBlockBody->ipcData.cmdDefault.destBufferMPTR = _swapEndianU32(fileHandle); - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_GETPOS; - return 0; + if (fsaShimBuffer == NULL) + return FSA_RESULT::INVALID_BUFFER; + fsaShimBuffer->fsaDevHandle = fsaHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->request.cmdGetPosFile.fileHandle = fileHandle; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::GETPOS; + return FSA_RESULT::SUCCESS; } sint32 FSGetPosFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32be* returnedFilePos, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { // games using this: Darksiders Warmastered Edition _FSCmdIntro(); - fsCmdBlockBody->returnValueMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(returnedFilePos)); - fsError = __FSPrepareCmd_GetPosFile(fsCmdBlockBody, fileHandle); - if (fsError != (FSStatus)FS_RESULT::SUCCESS) - return fsError; - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + fsCmdBlockBody->returnValues.cmdGetPosFile.filePosPtr = returnedFilePos; + FSA_RESULT prepareResult = __FSPrepareCmd_GetPosFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1007,17 +1199,17 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - sint32 __FSPrepareCmd_OpenDir(FSCmdBlockBody_t* fsCmdBlockBody, char* path) + FSA_RESULT __FSPrepareCmd_OpenDir(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, char* path) { - fsCmdBlockBody->fsCmdBlockBodyMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBody)); - if (fsCmdBlockBody == nullptr) - return 0xFFFCFFDD; + if (fsaShimBuffer == nullptr) + return FSA_RESULT::INVALID_BUFFER; if (path == nullptr) - return 0xFFFCFFDD + 1; + return FSA_RESULT::INVALID_PATH; + + fsaShimBuffer->fsaDevHandle = fsaHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::OPENDIR; - fsCmdBlockBody->fsCmdBlockBodyMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(fsCmdBlockBody)); - fsCmdBlockBody->ipcData.cmdOpenDir.dirHandleOutput = -1; - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_OPENDIR; // path sint32 pathLen = (sint32)strlen((char*)path); if (pathLen >= FSA_CMD_PATH_MAX_LENGTH) @@ -1026,21 +1218,24 @@ namespace coreinit pathLen = FSA_CMD_PATH_MAX_LENGTH - 1; } for (sint32 i = 0; i < pathLen; i++) - fsCmdBlockBody->ipcData.cmdOpenDir.path[i] = path[i]; + fsaShimBuffer->request.cmdOpenDir.path[i] = path[i]; for (sint32 i = pathLen; i < FSA_CMD_PATH_MAX_LENGTH; i++) - fsCmdBlockBody->ipcData.cmdOpenDir.path[i] = '\0'; - return 0; + fsaShimBuffer->request.cmdOpenDir.path[i] = '\0'; + + fsaShimBuffer->response.cmdOpenDir.dirHandleOutput = -1; + + return FSA_RESULT::SUCCESS; } sint32 FSOpenDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, FSDirHandlePtr dirHandleOut, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { _FSCmdIntro(); cemu_assert(dirHandleOut && path); - fsCmdBlockBody->returnValueMPTR = _swapEndianU32(dirHandleOut.GetMPTR()); - fsError = __FSPrepareCmd_OpenDir(fsCmdBlockBody, path); - if (fsError != (FSStatus)FS_RESULT::SUCCESS) - return fsError; - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + fsCmdBlockBody->returnValues.cmdOpenDir.handlePtr = dirHandleOut.GetMPTR(); + FSA_RESULT prepareResult = __FSPrepareCmd_OpenDir(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, path); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1052,18 +1247,25 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - void __FSPrepareCmd_ReadDir(FSCmdBlockBody_t* fsCmdBlockBody, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut) + FSA_RESULT __FSPrepareCmd_ReadDir(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, FSDirHandle2 dirHandle) { - fsCmdBlockBody->returnValueMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(dirEntryOut)); - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_READDIR; - fsCmdBlockBody->ipcData.cmdReadDir.dirHandle = dirHandle; + if (fsaShimBuffer == nullptr) + return FSA_RESULT::INVALID_BUFFER; + fsaShimBuffer->fsaDevHandle = fsaHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::READDIR; + fsaShimBuffer->request.cmdReadDir.dirHandle = dirHandle; + return FSA_RESULT::SUCCESS; } sint32 FSReadDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, FSDirEntry_t* dirEntryOut, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { _FSCmdIntro(); - __FSPrepareCmd_ReadDir(fsCmdBlockBody, dirHandle, dirEntryOut); - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + FSA_RESULT prepareResult = __FSPrepareCmd_ReadDir(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, dirHandle); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + fsCmdBlockBody->returnValues.cmdReadDir.dirEntryPtr = dirEntryOut; + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1075,17 +1277,25 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - void __FSPrepareCmd_CloseDir(FSCmdBlockBody_t* fsCmdBlockBody, FSDirHandle2 dirHandle) + FSA_RESULT __FSPrepareCmd_CloseDir(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, FSDirHandle2 dirHandle) { - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_CLOSEDIR; - fsCmdBlockBody->ipcData.cmdCloseDir.dirHandle = dirHandle; + if (fsaShimBuffer == nullptr) + return FSA_RESULT::INVALID_BUFFER; + fsaShimBuffer->fsaDevHandle = fsaHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::CLOSEDIR; + fsaShimBuffer->request.cmdCloseDir.dirHandle = dirHandle; + return FSA_RESULT::SUCCESS; } sint32 FSCloseDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSDirHandle2 dirHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { _FSCmdIntro(); - __FSPrepareCmd_CloseDir(fsCmdBlockBody, dirHandle); - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + FSA_RESULT prepareResult = __FSPrepareCmd_CloseDir(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, dirHandle); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1097,20 +1307,30 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - void __FSPrepareCmd_AppendFile(FSCmdBlockBody_t* fsCmdBlockBody, uint32 fileHandle, uint32 size, uint32 count, uint32 uknParam) + FSA_RESULT __FSPrepareCmd_AppendFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, uint32 fileHandle, uint32 size, uint32 count, uint32 uknParam) { - fsCmdBlockBody->ipcData.cmdAppendFile.fileHandle = _swapEndianU32(fileHandle); - fsCmdBlockBody->ipcData.cmdAppendFile.count = _swapEndianU32(size); - fsCmdBlockBody->ipcData.cmdAppendFile.size = _swapEndianU32(count); - fsCmdBlockBody->ipcData.cmdAppendFile.uknParam = _swapEndianU32(uknParam); - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_APPENDFILE; + if (fsaShimBuffer == nullptr) + return FSA_RESULT::INVALID_BUFFER; + fsaShimBuffer->fsaDevHandle = fsaHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::APPENDFILE; + + fsaShimBuffer->request.cmdAppendFile.fileHandle = fileHandle; + fsaShimBuffer->request.cmdAppendFile.count = size; + fsaShimBuffer->request.cmdAppendFile.size = count; + fsaShimBuffer->request.cmdAppendFile.uknParam = uknParam; + + return FSA_RESULT::SUCCESS; } sint32 FSAppendFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 size, uint32 count, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { _FSCmdIntro(); - __FSPrepareCmd_AppendFile(fsCmdBlockBody, fileHandle, size, count, 0); - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + FSA_RESULT prepareResult = __FSPrepareCmd_AppendFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle, size, count, 0); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1122,18 +1342,27 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - void __FSPrepareCmd_TruncateFile(FSCmdBlockBody_t* fsCmdBlockBody, FSFileHandle2 fileHandle) + FSA_RESULT __FSPrepareCmd_TruncateFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, FSFileHandle2 fileHandle) { - fsCmdBlockBody->ipcData.cmdTruncateFile.fileHandle = fileHandle; - fsCmdBlockBody->ipcData.cmdTruncateFile.ukn0008 = 0; - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_TRUNCATEFILE; + if (fsaShimBuffer == nullptr) + return FSA_RESULT::INVALID_BUFFER; + fsaShimBuffer->fsaDevHandle = fsaHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::TRUNCATEFILE; + + fsaShimBuffer->request.cmdTruncateFile.fileHandle = fileHandle; + + return FSA_RESULT::SUCCESS; } sint32 FSTruncateFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { _FSCmdIntro(); - __FSPrepareCmd_TruncateFile(fsCmdBlockBody, fileHandle); - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + FSA_RESULT prepareResult = __FSPrepareCmd_TruncateFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1145,12 +1374,17 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - sint32 __FSPrepareCmd_Rename(FSCmdBlockBody_t* fsCmdBlockBody, char* srcPath, char* dstPath) + FSA_RESULT __FSPrepareCmd_Rename(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle fsaHandle, char* srcPath, char* dstPath) { - if (fsCmdBlockBody == NULL) - return 0xFFFCFFDD; + if (fsaShimBuffer == nullptr) + return FSA_RESULT::INVALID_BUFFER; if (srcPath == NULL || dstPath == NULL) - return 0xFFFCFFDE; + return FSA_RESULT::INVALID_PATH; + + fsaShimBuffer->fsaDevHandle = fsaHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::RENAME; + // source path size_t stringLen = strlen((char*)srcPath); if (stringLen >= FSA_CMD_PATH_MAX_LENGTH) @@ -1160,9 +1394,9 @@ namespace coreinit } for (sint32 i = 0; i < stringLen; i++) { - fsCmdBlockBody->ipcData.cmdRename.srcPath[i] = srcPath[i]; + fsaShimBuffer->request.cmdRename.srcPath[i] = srcPath[i]; } - fsCmdBlockBody->ipcData.cmdRename.srcPath[stringLen] = '\0'; + fsaShimBuffer->request.cmdRename.srcPath[stringLen] = '\0'; // destination path stringLen = strlen((char*)dstPath); if (stringLen >= FSA_CMD_PATH_MAX_LENGTH) @@ -1172,11 +1406,11 @@ namespace coreinit } for (sint32 i = 0; i < stringLen; i++) { - fsCmdBlockBody->ipcData.cmdRename.dstPath[i] = dstPath[i]; + fsaShimBuffer->request.cmdRename.dstPath[i] = dstPath[i]; } - fsCmdBlockBody->ipcData.cmdRename.dstPath[stringLen] = '\0'; - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_RENAME; - return 0; + fsaShimBuffer->request.cmdRename.dstPath[stringLen] = '\0'; + + return FSA_RESULT::SUCCESS; } sint32 FSRenameAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* srcPath, char* dstPath, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) @@ -1188,10 +1422,11 @@ namespace coreinit cemu_assert_debug(false); // path must not be NULL return -0x400; } - fsError = __FSPrepareCmd_Rename(fsCmdBlockBody, srcPath, dstPath); - if (fsError != (FSStatus)FS_RESULT::SUCCESS) - return fsError; - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + FSA_RESULT prepareResult = __FSPrepareCmd_Rename(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, srcPath, dstPath); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1203,12 +1438,17 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - sint32 __FSPrepareCmd_Remove(FSCmdBlockBody_t* fsCmdBlockBody, uint8* path) + FSA_RESULT __FSPrepareCmd_Remove(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle, uint8* path) { - if (fsCmdBlockBody == NULL) - return 0xFFFCFFDD; + if (fsaShimBuffer == NULL) + return FSA_RESULT::INVALID_BUFFER; if (path == NULL) - return 0xFFFCFFDE; + return FSA_RESULT::INVALID_PATH; + + fsaShimBuffer->fsaDevHandle = devHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::REMOVE; + size_t pathLen = strlen((char*)path); if (pathLen >= FSA_CMD_PATH_MAX_LENGTH) { @@ -1217,11 +1457,11 @@ namespace coreinit } for (sint32 i = 0; i < pathLen; i++) { - fsCmdBlockBody->ipcData.cmdRemove.path[i] = path[i]; + fsaShimBuffer->request.cmdRemove.path[i] = path[i]; } - fsCmdBlockBody->ipcData.cmdRemove.path[pathLen] = '\0'; - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_REMOVE; - return 0; + fsaShimBuffer->request.cmdRemove.path[pathLen] = '\0'; + + return FSA_RESULT::SUCCESS; } sint32 FSRemoveAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* filePath, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) @@ -1233,14 +1473,11 @@ namespace coreinit cemu_assert_debug(false); // path must not be NULL return -0x400; } - uint32 ukn1444 = _swapEndianU32(fsClientBody->iosuFSAHandle); - fsError = __FSPrepareCmd_Remove(fsCmdBlockBody, filePath); - if (fsError != (FSStatus)FS_RESULT::SUCCESS) - { - cemu_assert_debug(false); - return fsError; - } - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + FSA_RESULT prepareResult = __FSPrepareCmd_Remove(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, filePath); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1252,12 +1489,17 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - uint32 __FSPrepareCmd_MakeDir(FSCmdBlockBody_t* fsCmdBlockBody, const uint8* path, uint32 uknVal660) + FSA_RESULT __FSPrepareCmd_MakeDir(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle, const uint8* path, uint32 uknVal660) { - if (fsCmdBlockBody == NULL) - return 0xFFFCFFDD; + if (fsaShimBuffer == NULL) + return FSA_RESULT::INVALID_BUFFER; if (path == NULL) - return 0xFFFCFFDE; + return FSA_RESULT::INVALID_PATH; + + fsaShimBuffer->fsaDevHandle = devHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::MAKEDIR; + size_t pathLen = strlen((char*)path); if (pathLen >= FSA_CMD_PATH_MAX_LENGTH) { @@ -1266,12 +1508,12 @@ namespace coreinit } for (sint32 i = 0; i < pathLen; i++) { - fsCmdBlockBody->ipcData.cmdMakeDir.path[i] = path[i]; + fsaShimBuffer->request.cmdMakeDir.path[i] = path[i]; } - fsCmdBlockBody->ipcData.cmdMakeDir.path[pathLen] = '\0'; - fsCmdBlockBody->ipcData.cmdMakeDir.uknParam = _swapEndianU32(uknVal660); - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_MAKEDIR; - return 0; + fsaShimBuffer->request.cmdMakeDir.path[pathLen] = '\0'; + fsaShimBuffer->request.cmdMakeDir.uknParam = uknVal660; + + return FSA_RESULT::SUCCESS; } sint32 FSMakeDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, const uint8* dirPath, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) @@ -1283,14 +1525,11 @@ namespace coreinit cemu_assert_debug(false); // path must not be NULL return -0x400; } - uint32 ukn1444 = _swapEndianU32(fsClientBody->iosuFSAHandle); - fsError = __FSPrepareCmd_MakeDir(fsCmdBlockBody, dirPath, 0x660); - if (fsError != (FSStatus)FS_RESULT::SUCCESS) - { - cemu_assert_debug(false); - return fsError; - } - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + FSA_RESULT prepareResult = __FSPrepareCmd_MakeDir(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, dirPath, 0x660); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1302,12 +1541,17 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - sint32 __FSPrepareCmd_ChangeDir(FSCmdBlockBody_t* fsCmdBlockBody, uint8* path) + FSA_RESULT __FSPrepareCmd_ChangeDir(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle, uint8* path) { - if (fsCmdBlockBody == NULL) - return 0xFFFCFFDD; + if (fsaShimBuffer == NULL) + return FSA_RESULT::INVALID_BUFFER; if (path == NULL) - return 0xFFFCFFDE; + return FSA_RESULT::INVALID_PATH; + + fsaShimBuffer->fsaDevHandle = devHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::CHANGEDIR; + size_t pathLen = strlen((char*)path); if (pathLen >= FSA_CMD_PATH_MAX_LENGTH) { @@ -1315,10 +1559,11 @@ namespace coreinit pathLen = FSA_CMD_PATH_MAX_LENGTH - 1; } for (sint32 i = 0; i < pathLen; i++) - fsCmdBlockBody->ipcData.cmdChangeDir.path[i] = path[i]; - fsCmdBlockBody->ipcData.cmdChangeDir.path[pathLen] = '\0'; - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_CHANGEDIR; - return 0; + fsaShimBuffer->request.cmdChangeDir.path[i] = path[i]; + + fsaShimBuffer->request.cmdChangeDir.path[pathLen] = '\0'; + + return FSA_RESULT::SUCCESS; } sint32 FSChangeDirAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) @@ -1329,10 +1574,11 @@ namespace coreinit cemu_assert_debug(false); // path must not be NULL return -0x400; } - fsError = __FSPrepareCmd_ChangeDir(fsCmdBlockBody, (uint8*)path); - if (fsError != (FSStatus)FS_RESULT::SUCCESS) - return fsError; - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + FSA_RESULT prepareResult = __FSPrepareCmd_ChangeDir(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, (uint8*)path); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1344,24 +1590,30 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - sint32 __FSPrepareCmd_GetCwd(FSCmdBlockBody_t* fsCmdBlockBody) + FSA_RESULT __FSPrepareCmd_GetCwd(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle) { - if (fsCmdBlockBody == NULL) - return 0xFFFCFFDD; - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_GETCWD; - return 0; + if (fsaShimBuffer == NULL) + return FSA_RESULT::INVALID_BUFFER; + + fsaShimBuffer->fsaDevHandle = devHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::GETCWD; + + return FSA_RESULT::SUCCESS; } sint32 FSGetCwdAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* dirPathOut, sint32 dirPathMaxLen, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { // used by titles: Super Mario Maker _FSCmdIntro(); - fsCmdBlockBody->returnValueMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(dirPathOut)); - fsCmdBlockBody->transferSize = _swapEndianU32(dirPathMaxLen); - fsError = __FSPrepareCmd_GetCwd(fsCmdBlockBody); - if (fsError != (FSStatus)FS_RESULT::SUCCESS) - return fsError; - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + fsCmdBlockBody->returnValues.cmdGetCwd.pathPtr = dirPathOut; + fsCmdBlockBody->returnValues.cmdGetCwd.transferSize = dirPathMaxLen; + + FSA_RESULT prepareResult = __FSPrepareCmd_GetCwd(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1374,8 +1626,17 @@ namespace coreinit return r; } - void __FSPrepareCmd_FlushQuota(FSCmdBlockBody_t* fsCmdBlockBody, char* path) + FSA_RESULT __FSPrepareCmd_FlushQuota(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle, char* path) { + if (fsaShimBuffer == NULL) + return FSA_RESULT::INVALID_BUFFER; + if (path == NULL) + return FSA_RESULT::INVALID_PATH; + + fsaShimBuffer->fsaDevHandle = devHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::FLUSHQUOTA; + size_t pathLen = strlen((char*)path); if (pathLen >= FSA_CMD_PATH_MAX_LENGTH) { @@ -1383,17 +1644,21 @@ namespace coreinit pathLen = FSA_CMD_PATH_MAX_LENGTH - 1; } for (sint32 i = 0; i < pathLen; i++) - fsCmdBlockBody->ipcData.cmdFlushQuota.path[i] = path[i]; - fsCmdBlockBody->ipcData.cmdFlushQuota.path[pathLen] = '\0'; - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_FLUSHQUOTA; + fsaShimBuffer->request.cmdFlushQuota.path[i] = path[i]; + fsaShimBuffer->request.cmdFlushQuota.path[pathLen] = '\0'; + + return FSA_RESULT::SUCCESS; } sint32 FSFlushQuotaAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { _FSCmdIntro(); - fsCmdBlockBody->returnValueMPTR = 0; - __FSPrepareCmd_FlushQuota(fsCmdBlockBody, path); - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + + FSA_RESULT prepareResult = __FSPrepareCmd_FlushQuota(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, path); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1405,9 +1670,19 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - uint32 __FSPrepareCmd_QueryInfo(FSCmdBlockBody_t* fsCmdBlockBody, uint8* queryString, uint32 queryType) + FSA_RESULT __FSPrepareCmd_QueryInfo(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle, uint8* queryString, uint32 queryType) { - // note: The output result is stored to fsCmdBlockBody+0x944 + if (fsaShimBuffer == NULL) + return FSA_RESULT::INVALID_BUFFER; + if (queryString == NULL) + return FSA_RESULT::INVALID_PATH; + if (queryType > 8) + return FSA_RESULT::INVALID_PARAM; + + fsaShimBuffer->fsaDevHandle = devHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::QUERYINFO; + size_t stringLen = strlen((char*)queryString); if (stringLen >= FSA_CMD_PATH_MAX_LENGTH) { @@ -1416,23 +1691,26 @@ namespace coreinit } for (sint32 i = 0; i < stringLen; i++) { - fsCmdBlockBody->ipcData.cmdQueryInfo.query[i] = queryString[i]; + fsaShimBuffer->request.cmdQueryInfo.query[i] = queryString[i]; } - fsCmdBlockBody->ipcData.cmdQueryInfo.query[stringLen] = '\0'; - fsCmdBlockBody->ipcData.cmdQueryInfo.queryType = _swapEndianU32(queryType); - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_QUERYINFO; - return 0; + + fsaShimBuffer->request.cmdQueryInfo.query[stringLen] = '\0'; + fsaShimBuffer->request.cmdQueryInfo.queryType = queryType; + + return FSA_RESULT::SUCCESS; } sint32 __FSQueryInfoAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint8* queryString, uint32 queryType, void* queryResult, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { _FSCmdIntro(); cemu_assert(queryString && queryResult); // query string and result must not be null - fsCmdBlockBody->returnValueMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(queryResult)); - fsError = __FSPrepareCmd_QueryInfo(fsCmdBlockBody, queryString, queryType); - if (fsError != (FSStatus)FS_RESULT::SUCCESS) - return fsError; - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + fsCmdBlockBody->returnValues.cmdQueryInfo.queryResultPtr = queryResult; + + FSA_RESULT prepareResult = __FSPrepareCmd_QueryInfo(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, queryString, queryType); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1451,19 +1729,29 @@ namespace coreinit return ret; } - void __FSPrepareCmd_GetStatFile(FSCmdBlockBody_t* fsCmdBlockBody, FSFileHandle2 fileHandle, FSStat_t* statOut) + FSA_RESULT __FSPrepareCmd_GetStatFile(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle, FSFileHandle2 fileHandle, FSStat_t* statOut) { - fsCmdBlockBody->ipcData.cmdGetStatFile.fileHandle = fileHandle; - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_GETSTATFILE; - fsCmdBlockBody->returnValueMPTR = _swapEndianU32(memory_getVirtualOffsetFromPointer(statOut)); + if (fsaShimBuffer == NULL) + return FSA_RESULT::INVALID_BUFFER; + + fsaShimBuffer->fsaDevHandle = devHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->request.cmdGetStatFile.fileHandle = fileHandle; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::GETSTATFILE; + return FSA_RESULT::SUCCESS; } sint32 FSGetStatFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, FSFileHandle2 fileHandle, FSStat_t* statOut, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { _FSCmdIntro(); cemu_assert(statOut); // statOut must not be null - __FSPrepareCmd_GetStatFile(fsCmdBlockBody, fileHandle, statOut); - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + fsCmdBlockBody->returnValues.cmdStatFile.resultPtr = statOut; + + FSA_RESULT prepareResult = __FSPrepareCmd_GetStatFile(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle, statOut); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1490,19 +1778,30 @@ namespace coreinit return __FSProcessAsyncResult(fsClient, fsCmdBlock, fsAsyncRet, errorMask); } - uint32 __FSPrepareCmd_IsEof(FSCmdBlockBody_t* fsCmdBlockBody, uint32 fileHandle) + FSA_RESULT __FSPrepareCmd_IsEof(iosu::fsa::FSAShimBuffer* fsaShimBuffer, IOSDevHandle devHandle, uint32 fileHandle) { - fsCmdBlockBody->ipcData.cmdDefault.destBufferMPTR = _swapEndianU32(fileHandle); - fsCmdBlockBody->operationType = FSA_CMD_OPERATION_TYPE_ISEOF; - return 0; + if (fsaShimBuffer == NULL) + return FSA_RESULT::INVALID_BUFFER; + + fsaShimBuffer->fsaDevHandle = devHandle; + fsaShimBuffer->ipcReqType = 0; + fsaShimBuffer->operationType = (uint32)FSA_CMD_OPERATION_TYPE::ISEOF; + + fsaShimBuffer->request.cmdIsEof.fileHandle = fileHandle; + + return FSA_RESULT::SUCCESS; } sint32 FSIsEofAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, uint32 fileHandle, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams) { // used by Paper Monsters Recut _FSCmdIntro(); - __FSPrepareCmd_IsEof(fsCmdBlockBody, fileHandle); - __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, FS_CB_PLACEHOLDER_FINISHCMD); + + FSA_RESULT prepareResult = __FSPrepareCmd_IsEof(&fsCmdBlockBody->fsaShimBuffer, fsClientBody->iosuFSAHandle, fileHandle); + if (prepareResult != FSA_RESULT::SUCCESS) + return (FSStatus)_FSAStatusToFSStatus(prepareResult); + + __FSQueueCmd(&fsClientBody->fsCmdQueue, fsCmdBlockBody, RPLLoader_MakePPCCallable(export___FSQueueDefaultFinishFunc)); return (FSStatus)FS_RESULT::SUCCESS; } @@ -1622,7 +1921,7 @@ namespace coreinit cafeExportRegister("coreinit", FSChangeDirAsync, LogType::CoreinitFile); cafeExportRegister("coreinit", FSChangeDir, LogType::CoreinitFile); cafeExportRegister("coreinit", FSGetCwdAsync, LogType::CoreinitFile); - cafeExportRegister("coreinit", FSGetCwd, LogType::CoreinitFile); + cafeExportRegister("coreinit", FSGetCwd, LogType::CoreinitFile); cafeExportRegister("coreinit", FSIsEofAsync, LogType::CoreinitFile); cafeExportRegister("coreinit", FSIsEof, LogType::CoreinitFile); @@ -1634,7 +1933,7 @@ namespace coreinit cafeExportRegister("coreinit", FSReadDir, LogType::CoreinitFile); cafeExportRegister("coreinit", FSCloseDirAsync, LogType::CoreinitFile); cafeExportRegister("coreinit", FSCloseDir, LogType::CoreinitFile); - + // stat cafeExportRegister("coreinit", FSGetFreeSpaceSizeAsync, LogType::CoreinitFile); cafeExportRegister("coreinit", FSGetFreeSpaceSize, LogType::CoreinitFile); @@ -1660,4 +1959,4 @@ namespace coreinit g_fsRegisteredClientBodies = nullptr; } -} +} // namespace coreinit diff --git a/src/Cafe/OS/libs/coreinit/coreinit_FS.h b/src/Cafe/OS/libs/coreinit/coreinit_FS.h index cdda692a..e6b7a29c 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_FS.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_FS.h @@ -8,25 +8,25 @@ typedef struct { uint32be fileHandle; -}FSFileHandleDepr_t; +} FSFileHandleDepr_t; typedef MEMPTR> FSDirHandlePtr; typedef struct { - MEMPTR userCallback; - MEMPTR userContext; - MEMPTR ioMsgQueue; -}FSAsyncParamsNew_t; + MEMPTR userCallback; + MEMPTR userContext; + MEMPTR ioMsgQueue; +} FSAsyncParamsNew_t; static_assert(sizeof(FSAsyncParamsNew_t) == 0xC); typedef struct { - MPTR userCallback; // 0x96C - MPTR userContext; - MPTR ioMsgQueue; -}FSAsyncParams_t; // legacy struct. Replace with FSAsyncParamsNew_t + MPTR userCallback; // 0x96C + MPTR userContext; + MPTR ioMsgQueue; +} FSAsyncParams_t; // legacy struct. Replace with FSAsyncParamsNew_t namespace coreinit { @@ -48,8 +48,8 @@ namespace coreinit }; DEFINE_ENUM_FLAG_OPERATORS(FSCmdQueue::QUEUE_FLAG); - #define FS_CLIENT_BUFFER_SIZE (5888) - #define FS_CMD_BLOCK_SIZE (2688) +#define FS_CLIENT_BUFFER_SIZE (5888) +#define FS_CMD_BLOCK_SIZE (2688) struct FSClient_t { @@ -64,7 +64,7 @@ namespace coreinit struct { uint32 mount_it; - }data; + } data; }; }; @@ -116,7 +116,7 @@ namespace coreinit uint32 ukn1608; uint32 ukn160C; uint32 ukn1610; - MEMPTR fsClientBodyNext; // next FSClientBody_t* in list of registered clients (list is circular, the last element points to the first element) + MEMPTR fsClientBodyNext; // next FSClientBody_t* in list of registered clients (list is circular, the last element points to the first element) uint32 ukn1618; /* +0x161C */ MEMPTR selfClient; // pointer to FSClient struct which holds this FSClientBody uint32 ukn1620; @@ -127,81 +127,89 @@ namespace coreinit /* +0x00 */ FSAsyncParamsNew_t fsAsyncParamsNew; // fs message storage - struct FSMessage + struct FSMessage { - /* +0x0C / 0x0978 */ MEMPTR fsAsyncResult; - /* +0x10 */ MPTR fsClientMPTR2; // 0x097C - /* +0x14 */ MPTR fsCmdBlockMPTR; // 0x0980 - /* +0x18 */ MPTR commandType; // 0x0984 + /* +0x0C / 0x0978 */ MEMPTR fsAsyncResult; + /* +0x10 */ MPTR fsClientMPTR2; // 0x097C + /* +0x14 */ MPTR fsCmdBlockMPTR; // 0x0980 + /* +0x18 */ MPTR commandType; // 0x0984 }; union { OSMessage osMsg; FSMessage fsMsg; - }msgUnion; + } msgUnion; - /* +0x1C */ MEMPTR fsClient; // 0x0988 + /* +0x1C */ MEMPTR fsClient; // 0x0988 /* +0x20 */ MEMPTR fsCmdBlock; // 0x98C - /* +0x24 */ uint32be fsStatusNew; // 0x990 + /* +0x24 */ uint32be fsStatusNew; // 0x990 }; static_assert(sizeof(FSAsyncResult) == 0x28); + struct FSCmdBlockReturnValues_t + { + union + { + uint8 ukn0[0x14]; + struct + { + MEMPTR handlePtr; + } cmdOpenFile; + struct + { + MEMPTR filePosPtr; + } cmdGetPosFile; + struct + { + uint32be transferSize; + uint32be uknVal094C; + uint32be transferElemSize; + uint32be uknVal0954; + } cmdReadFile; + struct + { + uint32be transferSize; + uint32be uknVal094C; + uint32be transferElemSize; + uint32be uknVal0954; + } cmdWriteFile; + struct + { + MEMPTR handlePtr; + } cmdOpenDir; + struct + { + MEMPTR dirEntryPtr; + } cmdReadDir; + struct + { + MEMPTR pathPtr; + uint32be transferSize; + } cmdGetCwd; + struct + { + MEMPTR queryResultPtr; + } cmdQueryInfo; + struct + { + MEMPTR resultPtr; + } cmdStatFile; + }; + }; + + static_assert(sizeof(FSCmdBlockReturnValues_t) == 0x14); + struct FSCmdBlockBody_t { - iosu::fsa::FSAIpcCommand ipcData; - uint8 ukn0820[0x10]; - uint8 ukn0830[0x10]; - uint8 ukn0840[0x10]; - uint8 ukn0850[0x10]; - uint8 ukn0860[0x10]; - uint8 ukn0870[0x10]; - MPTR fsCmdBlockBodyMPTR; - uint32 ukn0884; - uint32 ukn0888; - uint32 destBuffer88CMPTR; - uint32 ukn0890; - uint32 ukn0894; - uint32 ukn0898; - uint32 ukn089C; - uint32 ukn08A0; - uint32 ukn08A4; - uint32 ukn08A8; - uint32 ukn08AC; - uint8 ukn08B0[0x10]; - uint8 ukn08C0[0x10]; - uint8 ukn08D0[0x10]; - uint8 ukn08E0[0x10]; - uint8 ukn08F0[0x10]; - /* +0x0900 */ uint32be operationType; - betype fsaDevHandle; - /* +0x0908 */ uint16be ipcReqType; // 0 -> IoctlAsync, 1 -> IoctlvAsync - uint8 ukn090A; - uint8 ukn090B; - uint32 ukn090C; - uint32 ukn0910; - uint32 ukn0914; - uint32 ukn0918; - uint32 ukn091C; - uint32 ukn0920; - uint32 ukn0924; - uint32 ukn0928; - uint32 ukn092C; - uint32 ukn0930; - uint32 ukn0934; + iosu::fsa::FSAShimBuffer fsaShimBuffer; /* +0x0938 */ MEMPTR fsClientBody; - /* +0x093C */ uint32 statusCode; // not a status code but rather the state? Uses weird values for some reason + /* +0x093C */ uint32 statusCode; // not a status code but rather the state? Uses weird values for some reason /* +0x0940 */ uint32be cancelState; // bitmask. Bit 0 -> If set command has been canceled - // return values - /* +0x0944 */ uint32 returnValueMPTR; // returnedFilePos (used to store pointer to variable that holds return value?), also used by QUERYINFO to store pointer for result. Also used for GetCwd() to hold the pointer for the returned dir path. Also used by OPENFILE to hold returned fileHandle - /* +0x0948 */ uint32 transferSize; // number of bytes to transfer - // transfer control? - uint32 uknVal094C; - uint32 transferElemSize; // number of bytes of a single transferred element (count of elements can be calculated via count = transferSize/transferElemSize) - uint32 uknVal0954; // this is set to max(0x10, transferSize) for reads and to min(0x40000, transferSize) for writes? + FSCmdBlockReturnValues_t returnValues; // link for cmd queue - MPTR nextMPTR; // points towards FSCmdQueue->first + MPTR nextMPTR; // points towards FSCmdQueue->first MPTR previousMPTR; // points towards FSCmdQueue->last /* +0x960 */ betype lastFSAStatus; @@ -226,34 +234,12 @@ namespace coreinit static_assert(sizeof(FSAsyncParams_t) == 0xC); static_assert(sizeof(FSCmdBlock_t) == 0xA80); - #define FSA_CMD_FLAG_SET_POS (1<<0) +#define FSA_CMD_FLAG_SET_POS (1 << 0) - #define FSA_CMD_OPERATION_TYPE_CHANGEDIR (0x5) - #define FSA_CMD_OPERATION_TYPE_GETCWD (0x6) - #define FSA_CMD_OPERATION_TYPE_MAKEDIR (0x7) - #define FSA_CMD_OPERATION_TYPE_REMOVE (0x8) - #define FSA_CMD_OPERATION_TYPE_RENAME (0x9) - #define FSA_CMD_OPERATION_TYPE_OPENDIR (0xA) - #define FSA_CMD_OPERATION_TYPE_READDIR (0xB) - #define FSA_CMD_OPERATION_TYPE_CLOSEDIR (0xD) - #define FSA_CMD_OPERATION_TYPE_OPENFILE (0xE) - #define FSA_CMD_OPERATION_TYPE_READ (0xF) - #define FSA_CMD_OPERATION_TYPE_WRITE (0x10) - #define FSA_CMD_OPERATION_TYPE_GETPOS (0x11) - #define FSA_CMD_OPERATION_TYPE_SETPOS (0x12) - #define FSA_CMD_OPERATION_TYPE_ISEOF (0x13) - #define FSA_CMD_OPERATION_TYPE_GETSTATFILE (0x14) - #define FSA_CMD_OPERATION_TYPE_CLOSEFILE (0x15) - #define FSA_CMD_OPERATION_TYPE_QUERYINFO (0x18) - #define FSA_CMD_OPERATION_TYPE_APPENDFILE (0x19) - #define FSA_CMD_OPERATION_TYPE_TRUNCATEFILE (0x1A) - #define FSA_CMD_OPERATION_TYPE_FLUSHQUOTA (0x1E) - - - #define FSA_CMD_STATUS_CODE_D900A21 0xD900A21 // cmd block is initialized - #define FSA_CMD_STATUS_CODE_D900A22 0xD900A22 // cmd block is queued - #define FSA_CMD_STATUS_CODE_D900A24 0xD900A24 // cmd block was processed and is available again - #define FSA_CMD_STATUS_CODE_D900A26 0xD900A26 // cmd block result is being processed +#define FSA_CMD_STATUS_CODE_D900A21 0xD900A21 // cmd block is initialized +#define FSA_CMD_STATUS_CODE_D900A22 0xD900A22 // cmd block is queued +#define FSA_CMD_STATUS_CODE_D900A24 0xD900A24 // cmd block was processed and is available again +#define FSA_CMD_STATUS_CODE_D900A26 0xD900A26 // cmd block result is being processed enum FS_VOLSTATE : sint32 { @@ -272,12 +258,12 @@ namespace coreinit sint32 FSOpenFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandleDepr_t* fileHandle, uint32 errHandling, FSAsyncParamsNew_t* asyncParams); sint32 FSOpenFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, char* path, char* mode, FSFileHandleDepr_t* fileHandle, uint32 errHandling); - + sint32 FSReadFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams); sint32 FSReadFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask); sint32 FSReadFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams); sint32 FSReadFileWithPos(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* dst, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask); - + sint32 FSWriteFileAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams); sint32 FSWriteFile(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 fileHandle, uint32 flag, uint32 errorMask); sint32 FSWriteFileWithPosAsync(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, void* src, uint32 size, uint32 count, uint32 filePos, uint32 fileHandle, uint32 flag, uint32 errorMask, FSAsyncParamsNew_t* fsAsyncParams); @@ -321,5 +307,4 @@ namespace coreinit FS_VOLSTATE FSGetVolumeState(FSClient_t* fsClient); void InitializeFS(); -}; - +}; // namespace coreinit