mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-10 00:41:19 +12:00
coreinit: Implement several FSA functions and fix some bugs (#844)
This commit is contained in:
parent
ae4cb45cf3
commit
f1ebfa9941
10 changed files with 1032 additions and 121 deletions
|
@ -17,9 +17,11 @@ enum class FS_RESULT : sint32 // aka FSStatus
|
|||
|
||||
enum class FSA_RESULT : sint32 // aka FSError/FSAStatus
|
||||
{
|
||||
SUCCESS = 0,
|
||||
END_DIR = -0x30000 - 0x04,
|
||||
END_FILE = -0x30000 - 0x05,
|
||||
OK = 0,
|
||||
NOT_INIT = -0x30000 - 0x01,
|
||||
END_OF_DIRECTORY = -0x30000 - 0x04,
|
||||
END_OF_FILE = -0x30000 - 0x05,
|
||||
MAX_CLIENTS = -0x30000 - 0x12,
|
||||
MAX_FILES = -0x30000 - 0x13,
|
||||
MAX_DIRS = -0x30000 - 0x14,
|
||||
ALREADY_EXISTS = -0x30000 - 0x16,
|
||||
|
@ -34,6 +36,7 @@ enum class FSA_RESULT : sint32 // aka FSError/FSAStatus
|
|||
INVALID_DIR_HANDLE = -0x30000 - 0x27,
|
||||
NOT_FILE = -0x30000 - 0x28,
|
||||
NOT_DIR = -0x30000 - 0x29,
|
||||
OUT_OF_RESOURCES = -0x30000 - 0x2C,
|
||||
FATAL_ERROR = -0x30000 - 0x400,
|
||||
};
|
||||
|
||||
|
@ -46,6 +49,7 @@ enum class FSA_CMD_OPERATION_TYPE : uint32
|
|||
RENAME = 0x9,
|
||||
OPENDIR = 0xA,
|
||||
READDIR = 0xB,
|
||||
REWINDDIR = 0xC,
|
||||
CLOSEDIR = 0xD,
|
||||
OPENFILE = 0xE,
|
||||
READ = 0xF,
|
||||
|
@ -55,6 +59,7 @@ enum class FSA_CMD_OPERATION_TYPE : uint32
|
|||
ISEOF = 0x13,
|
||||
GETSTATFILE = 0x14,
|
||||
CLOSEFILE = 0x15,
|
||||
FLUSHFILE = 0x17,
|
||||
QUERYINFO = 0x18,
|
||||
APPENDFILE = 0x19,
|
||||
TRUNCATEFILE = 0x1A,
|
||||
|
@ -81,6 +86,7 @@ enum class FSFlag : uint32
|
|||
{
|
||||
NONE = 0,
|
||||
IS_DIR = 0x80000000,
|
||||
IS_FILE = 0x01000000,
|
||||
};
|
||||
DEFINE_ENUM_FLAG_OPERATORS(FSFlag);
|
||||
|
||||
|
@ -111,8 +117,18 @@ struct FSDirEntry_t
|
|||
|
||||
static_assert(sizeof(FSDirEntry_t) == 0xE4);
|
||||
|
||||
struct FSADeviceInfo_t
|
||||
{
|
||||
uint8 ukn0[0x8];
|
||||
uint64be deviceSizeInSectors;
|
||||
uint32be deviceSectorSize;
|
||||
uint8 ukn014[0x14];
|
||||
};
|
||||
static_assert(sizeof(FSADeviceInfo_t) == 0x28);
|
||||
|
||||
#pragma pack()
|
||||
|
||||
// query types for QueryInfo
|
||||
#define FSA_QUERY_TYPE_FREESPACE 0
|
||||
#define FSA_QUERY_TYPE_DEVICE_INFO 4
|
||||
#define FSA_QUERY_TYPE_STAT 5
|
||||
|
|
|
@ -54,7 +54,7 @@ namespace iosu
|
|||
FSA_RESULT FSA_convertFSCtoFSAStatus(sint32 fscError)
|
||||
{
|
||||
if (fscError == FSC_STATUS_OK)
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
else if (fscError == FSC_STATUS_FILE_NOT_FOUND)
|
||||
return FSA_RESULT::NOT_FOUND;
|
||||
else if (fscError == FSC_STATUS_ALREADY_EXISTS)
|
||||
|
@ -175,7 +175,7 @@ namespace iosu
|
|||
it.isAllocated = true;
|
||||
uint32 handleVal = ((uint32)i << 16) | (uint32)checkValue;
|
||||
handleOut = (FSResHandle)handleVal;
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
cemuLog_log(LogType::Force, "FSA: Ran out of file handles");
|
||||
return FSA_RESULT::FATAL_ERROR;
|
||||
|
@ -194,7 +194,7 @@ namespace iosu
|
|||
return FSA_RESULT::INVALID_FILE_HANDLE;
|
||||
it.fscFile = nullptr;
|
||||
it.isAllocated = false;
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSCVirtualFile* GetByHandle(FSResHandle handle)
|
||||
|
@ -229,10 +229,9 @@ namespace iosu
|
|||
accessModifier = FSC_ACCESS_FLAG::READ_PERMISSION;
|
||||
else if (strcmp(accessModifierStr, "r+") == 0)
|
||||
{
|
||||
// r+ will create a new file if it doesn't exist
|
||||
// the cursor will be set to the beginning of the file
|
||||
// allows read and write access
|
||||
accessModifier = FSC_ACCESS_FLAG::READ_PERMISSION | FSC_ACCESS_FLAG::WRITE_PERMISSION | FSC_ACCESS_FLAG::FILE_ALLOW_CREATE; // create if non exists, read, write
|
||||
accessModifier = FSC_ACCESS_FLAG::READ_PERMISSION | FSC_ACCESS_FLAG::WRITE_PERMISSION; // read, write
|
||||
}
|
||||
else if (strcmp(accessModifierStr, "w") == 0)
|
||||
{
|
||||
|
@ -252,10 +251,12 @@ namespace iosu
|
|||
}
|
||||
else if (strcmp(accessModifierStr, "a+") == 0)
|
||||
{
|
||||
cemu_assert_debug(false); // a+ is kind of special. Writing always happens at the end but the read cursor can dynamically move
|
||||
// but Cafe OS might not support this. Needs investigation.
|
||||
// this also used to be FILE_ALWAYS_CREATE in 1.26.2 and before
|
||||
accessModifier = FSC_ACCESS_FLAG::READ_PERMISSION | FSC_ACCESS_FLAG::WRITE_PERMISSION | FSC_ACCESS_FLAG::FILE_ALLOW_CREATE;
|
||||
accessModifier = FSC_ACCESS_FLAG::READ_PERMISSION | FSC_ACCESS_FLAG::WRITE_PERMISSION | FSC_ACCESS_FLAG::FILE_ALLOW_CREATE | FSC_ACCESS_FLAG::IS_APPEND;
|
||||
isAppend = true;
|
||||
}
|
||||
else if (strcmp(accessModifierStr, "a") == 0)
|
||||
{
|
||||
accessModifier = FSC_ACCESS_FLAG::WRITE_PERMISSION | FSC_ACCESS_FLAG::FILE_ALLOW_CREATE | FSC_ACCESS_FLAG::IS_APPEND;
|
||||
isAppend = true;
|
||||
}
|
||||
else
|
||||
|
@ -275,7 +276,7 @@ namespace iosu
|
|||
fsc_setFileSeek(fscFile, fsc_getFileSize(fscFile));
|
||||
FSResHandle fsFileHandle;
|
||||
FSA_RESULT r = sFileHandleTable.AllocateHandle(fsFileHandle, fscFile);
|
||||
if (r != FSA_RESULT::SUCCESS)
|
||||
if (r != FSA_RESULT::OK)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Exceeded maximum number of FSA file handles");
|
||||
delete fscFile;
|
||||
|
@ -283,7 +284,7 @@ namespace iosu
|
|||
}
|
||||
*fileHandle = fsFileHandle;
|
||||
cemuLog_log(LogType::CoreinitFile, "Open file {} (access: {} result: ok handle: 0x{})", path, accessModifierStr, (uint32)*fileHandle);
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSA_RESULT __FSAOpenDirectory(FSAClient* client, std::string_view path, sint32* dirHandle)
|
||||
|
@ -300,14 +301,14 @@ namespace iosu
|
|||
}
|
||||
FSResHandle fsDirHandle;
|
||||
FSA_RESULT r = sDirHandleTable.AllocateHandle(fsDirHandle, fscFile);
|
||||
if (r != FSA_RESULT::SUCCESS)
|
||||
if (r != FSA_RESULT::OK)
|
||||
{
|
||||
delete fscFile;
|
||||
return FSA_RESULT::MAX_DIRS;
|
||||
}
|
||||
*dirHandle = fsDirHandle;
|
||||
cemuLog_log(LogType::CoreinitFile, "Open directory {} (result: ok handle: 0x{})", path, (uint32)*dirHandle);
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSA_RESULT __FSACloseFile(uint32 fileHandle)
|
||||
|
@ -322,7 +323,7 @@ namespace iosu
|
|||
// unregister file
|
||||
sFileHandleTable.ReleaseHandle(fileHandle); // todo - use the error code of this
|
||||
fsc_close(fscFile);
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSA_RESULT FSAProcessCmd_remove(FSAClient* client, FSAShimBuffer* shimBuffer)
|
||||
|
@ -383,7 +384,7 @@ namespace iosu
|
|||
return FSA_convertFSCtoFSAStatus(fscStatus);
|
||||
__FSA_GetStatFromFSCFile(fscFile, fsStatOut);
|
||||
delete fscFile;
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSA_RESULT FSAProcessCmd_queryInfo(FSAClient* client, FSAShimBuffer* shimBuffer)
|
||||
|
@ -407,7 +408,16 @@ namespace iosu
|
|||
betype<uint64>* fsStatSize = &shimBuffer->response.cmdQueryInfo.queryFreeSpace.freespace;
|
||||
*fsStatSize = 30ull * 1024 * 1024 * 1024; // placeholder value. How is this determined?
|
||||
delete fscFile;
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
else if (queryType == FSA_QUERY_TYPE_DEVICE_INFO)
|
||||
{
|
||||
FSADeviceInfo_t* deviceInfo = &shimBuffer->response.cmdQueryInfo.queryDeviceInfo.info;
|
||||
// always report hardcoded values for now.
|
||||
deviceInfo->deviceSectorSize = 512;
|
||||
deviceInfo->deviceSizeInSectors = (32ull * 1024 * 1024 * 1024) / deviceInfo->deviceSectorSize;
|
||||
cemu_assert_suspicious();
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
else
|
||||
cemu_assert_unimplemented();
|
||||
|
@ -423,7 +433,7 @@ namespace iosu
|
|||
return FSA_RESULT::NOT_FOUND;
|
||||
cemu_assert_debug(fsc_isFile(fscFile));
|
||||
__FSA_GetStatFromFSCFile(fscFile, statOut);
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSA_RESULT FSAProcessCmd_read(FSAClient* client, FSAShimBuffer* shimBuffer, MEMPTR<void> destPtr, uint32be transferSize)
|
||||
|
@ -444,7 +454,7 @@ namespace iosu
|
|||
// todo: File permissions
|
||||
uint32 bytesSuccessfullyRead = fsc_readFile(fscFile, destPtr, bytesToRead);
|
||||
if (transferElementSize == 0)
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
|
||||
LatteBufferCache_notifyDCFlush(destPtr.GetMPTR(), bytesToRead);
|
||||
|
||||
|
@ -485,7 +495,7 @@ namespace iosu
|
|||
if (!fscFile)
|
||||
return FSA_RESULT::INVALID_FILE_HANDLE;
|
||||
fsc_setFileSeek(fscFile, filePos);
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSA_RESULT FSAProcessCmd_getPos(FSAClient* client, FSAShimBuffer* shimBuffer)
|
||||
|
@ -496,7 +506,7 @@ namespace iosu
|
|||
return FSA_RESULT::INVALID_FILE_HANDLE;
|
||||
uint32 filePos = fsc_getFileSeek(fscFile);
|
||||
shimBuffer->response.cmdGetPosFile.filePos = filePos;
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSA_RESULT FSAProcessCmd_openFile(FSAClient* client, FSAShimBuffer* shimBuffer)
|
||||
|
@ -528,7 +538,7 @@ namespace iosu
|
|||
FSDirEntry_t* dirEntryOut = &shimBuffer->response.cmdReadDir.dirEntry;
|
||||
FSCDirEntry fscDirEntry;
|
||||
if (fsc_nextDir(fscFile, &fscDirEntry) == false)
|
||||
return FSA_RESULT::END_DIR;
|
||||
return FSA_RESULT::END_OF_DIRECTORY;
|
||||
strcpy(dirEntryOut->name, fscDirEntry.path);
|
||||
FSFlag statFlag = FSFlag::NONE;
|
||||
dirEntryOut->stat.size = 0;
|
||||
|
@ -538,11 +548,12 @@ namespace iosu
|
|||
}
|
||||
else if (fscDirEntry.isFile)
|
||||
{
|
||||
statFlag |= FSFlag::IS_FILE;
|
||||
dirEntryOut->stat.size = fscDirEntry.fileSize;
|
||||
}
|
||||
dirEntryOut->stat.flag = statFlag;
|
||||
dirEntryOut->stat.permissions = 0x777;
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSA_RESULT FSAProcessCmd_closeDir(FSAClient* client, FSAShimBuffer* shimBuffer)
|
||||
|
@ -555,12 +566,31 @@ namespace iosu
|
|||
}
|
||||
sDirHandleTable.ReleaseHandle(shimBuffer->request.cmdReadDir.dirHandle);
|
||||
fsc_close(fscFile);
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSA_RESULT FSAProcessCmd_flushQuota(FSAClient* client, FSAShimBuffer* shimBuffer)
|
||||
{
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSA_RESULT FSAProcessCmd_rewindDir(FSAClient* client, FSAShimBuffer* shimBuffer)
|
||||
{
|
||||
FSCVirtualFile* fscFile = sDirHandleTable.GetByHandle((sint32)shimBuffer->request.cmdRewindDir.dirHandle);
|
||||
if (!fscFile)
|
||||
{
|
||||
cemuLog_logDebug(LogType::Force, "RewindDir: Invalid handle (0x{:08x})", (sint32)shimBuffer->request.cmdRewindDir.dirHandle);
|
||||
return FSA_RESULT::INVALID_DIR_HANDLE;
|
||||
}
|
||||
if (!fscFile->fscRewindDir())
|
||||
return FSA_RESULT::FATAL_ERROR;
|
||||
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSA_RESULT FSAProcessCmd_flushFile(FSAClient* client, FSAShimBuffer* shimBuffer)
|
||||
{
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSA_RESULT FSAProcessCmd_appendFile(FSAClient* client, FSAShimBuffer* shimBuffer)
|
||||
|
@ -582,7 +612,7 @@ namespace iosu
|
|||
if (!fscFile)
|
||||
return FSA_RESULT::INVALID_FILE_HANDLE;
|
||||
fsc_setFileLength(fscFile, fsc_getFileSeek(fscFile));
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSA_RESULT FSAProcessCmd_isEof(FSAClient* client, FSAShimBuffer* shimBuffer)
|
||||
|
@ -594,8 +624,8 @@ namespace iosu
|
|||
uint32 filePos = fsc_getFileSeek(fscFile);
|
||||
uint32 fileSize = fsc_getFileSize(fscFile);
|
||||
if (filePos >= fileSize)
|
||||
return FSA_RESULT::END_FILE;
|
||||
return FSA_RESULT::SUCCESS;
|
||||
return FSA_RESULT::END_OF_FILE;
|
||||
return FSA_RESULT::OK;
|
||||
}
|
||||
|
||||
FSA_RESULT FSAProcessCmd_getCwd(FSAClient* client, FSAShimBuffer* shimBuffer)
|
||||
|
@ -764,17 +794,22 @@ namespace iosu
|
|||
fsaResult = FSAProcessCmd_flushQuota(client, shimBuffer);
|
||||
break;
|
||||
}
|
||||
case FSA_CMD_OPERATION_TYPE::REWINDDIR:
|
||||
{
|
||||
fsaResult = FSAProcessCmd_rewindDir(client, shimBuffer);
|
||||
break;
|
||||
}
|
||||
case FSA_CMD_OPERATION_TYPE::FLUSHFILE:
|
||||
{
|
||||
fsaResult = FSAProcessCmd_flushFile(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);
|
||||
}
|
||||
|
|
|
@ -111,10 +111,25 @@ namespace iosu
|
|||
{
|
||||
uint32be fileHandle;
|
||||
} cmdIsEof;
|
||||
struct
|
||||
{
|
||||
uint32be dirHandle;
|
||||
} cmdRewindDir;
|
||||
struct
|
||||
{
|
||||
uint32be fileHandle;
|
||||
} cmdFlushFile;
|
||||
struct
|
||||
{
|
||||
uint8 path[FSA_CMD_PATH_MAX_LENGTH];
|
||||
uint32be mode1;
|
||||
uint32be mode2;
|
||||
} cmdChangeMode;
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(FSARequest) == 0x520);
|
||||
|
||||
#pragma pack(1)
|
||||
struct FSAResponse
|
||||
{
|
||||
uint32be ukn0;
|
||||
|
@ -158,11 +173,16 @@ namespace iosu
|
|||
{
|
||||
FSStat_t stat;
|
||||
} queryStat;
|
||||
struct
|
||||
{
|
||||
FSADeviceInfo_t info;
|
||||
} queryDeviceInfo;
|
||||
};
|
||||
} cmdQueryInfo;
|
||||
};
|
||||
};
|
||||
// static_assert(sizeof(FSAResponse) == 0x293);
|
||||
static_assert(sizeof(FSAResponse) == 0x293);
|
||||
#pragma pack()
|
||||
|
||||
struct FSAShimBuffer
|
||||
{
|
||||
|
@ -189,7 +209,7 @@ namespace iosu
|
|||
uint32 ukn0930;
|
||||
uint32 ukn0934;
|
||||
};
|
||||
// static_assert(sizeof(FSAShimBuffer) == 0x938); // exact size of this is not known
|
||||
static_assert(sizeof(FSAShimBuffer) == 0x938); // exact size of this is not known
|
||||
|
||||
void Initialize();
|
||||
void Shutdown();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue