From b59682652d1ed9ea4371f15a94fc2845a866cd2e Mon Sep 17 00:00:00 2001 From: Adubbz Date: Thu, 25 Jul 2019 01:28:05 +1000 Subject: [PATCH] Implement various SaveDataExtraData commands (#315) * Implement fsReadSaveDataFileSystemExtraData * Implement fsReadSaveDataFileSystemExtraDataBySaveDataSpaceId and fsWriteSaveDataFileSystemExtraData --- nx/include/switch/services/fs.h | 25 ++++++- nx/source/services/fs.c | 115 ++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+), 1 deletion(-) diff --git a/nx/include/switch/services/fs.h b/nx/include/switch/services/fs.h index 6061a965..14155c5a 100644 --- a/nx/include/switch/services/fs.h +++ b/nx/include/switch/services/fs.h @@ -77,13 +77,26 @@ typedef struct u64 unk_x38; ///< 0 for SystemSaveData/SaveData. } FsSave; +/// SaveDataExtraData Struct +typedef struct { + FsSave save; ///< Save struct. + u64 ownerId; ///< Title id of the owner of this save data. 0 for SystemSaveData. + u64 timestamp; ///< POSIX timestamp. + u32 flags; ///< Save data flags. See \ref FsSaveDataFlags. + u32 unk_x54; ///< Normally 0. Possibly unused? + u64 dataSize; ///< Usable save data size. + u64 journalSize; ///< Journal size of the save data. + u64 commitId; ///< Id of the latest commit. + u8 unused[0x190]; ///< Uninitialized. +} FsSaveDataExtraData; + /// SaveCreate Struct typedef struct { u64 size; ///< Size of the save data. u64 journalSize; ///< Journal size of the save data. u64 blockSize; ///< Block size of the save data. u64 ownerId; ///< Title id of the owner of this save data. 0 for SystemSaveData. - u32 flags; ///< Save data flags. + u32 flags; ///< Save data flags. See \ref FsSaveDataFlags. u8 saveDataSpaceId; ///< See \ref FsSaveDataSpaceId. u8 unk; ///< 0 for SystemSaveData. u8 padding[0x1A]; ///< Uninitialized for SystemSaveData. @@ -186,6 +199,13 @@ typedef enum FsSaveDataType_CacheStorage = 5, ///< [3.0.0+] } FsSaveDataType; +/// SaveDataFlags +typedef enum { + FsSaveDataFlags_SurviveFactoryReset = BIT(0), + FsSaveDataFlags_SurviveFactoryResetForRefurbishment = BIT(1), + FsSaveDataFlags_SurviveFactoryResetWithoutUserSaveData = BIT(2), +} FsSaveDataFlags; + typedef enum { FsGameCardAttribute_AutoBoot = (1 << 0), ///< Causes the cartridge to automatically start on bootup FsGameCardAttribute_ForceError = (1 << 1), ///< Causes NS to throw an error on attempt to load the cartridge @@ -249,6 +269,9 @@ Result fsDeleteSaveDataFileSystemBySaveDataSpaceId(FsSaveDataSpaceId saveDataSpa Result fsIsExFatSupported(bool* out); Result fsOpenGameCardFileSystem(FsFileSystem* out, const FsGameCardHandle* handle, FsGameCardPartiton partition); +Result fsReadSaveDataFileSystemExtraDataBySaveDataSpaceId(void* buf, size_t len, FsSaveDataSpaceId saveDataSpaceId, u64 saveID); +Result fsReadSaveDataFileSystemExtraData(void* buf, size_t len, u64 saveID); +Result fsWriteSaveDataFileSystemExtraData(const void* buf, size_t len, FsSaveDataSpaceId saveDataSpaceId, u64 saveID); /// Do not call this directly, see fs_dev.h. Result fsMountSdcard(FsFileSystem* out); diff --git a/nx/source/services/fs.c b/nx/source/services/fs.c index f520c771..5e4fdbb2 100644 --- a/nx/source/services/fs.c +++ b/nx/source/services/fs.c @@ -776,6 +776,121 @@ Result fsOpenGameCardFileSystem(FsFileSystem* out, const FsGameCardHandle* handl return rc; } +Result fsReadSaveDataFileSystemExtraDataBySaveDataSpaceId(void* buf, size_t len, FsSaveDataSpaceId saveDataSpaceId, u64 saveID) { + if (hosversionBefore(3,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + IpcCommand c; + ipcInitialize(&c); + ipcAddRecvBuffer(&c, buf, len, BufferType_Normal); + + struct { + u64 magic; + u64 cmd_id; + u64 saveDataSpaceId; + u64 saveID; + } *raw; + + raw = serviceIpcPrepareHeader(&g_fsSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 57; + raw->saveDataSpaceId = saveDataSpaceId; + raw->saveID = saveID; + + Result rc = serviceIpcDispatch(&g_fsSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_fsSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result fsReadSaveDataFileSystemExtraData(void* buf, size_t len, u64 saveID) { + IpcCommand c; + ipcInitialize(&c); + ipcAddRecvBuffer(&c, buf, len, BufferType_Normal); + + struct { + u64 magic; + u64 cmd_id; + u64 saveID; + } *raw; + + raw = serviceIpcPrepareHeader(&g_fsSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 58; + raw->saveID = saveID; + + Result rc = serviceIpcDispatch(&g_fsSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_fsSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + +Result fsWriteSaveDataFileSystemExtraData(const void* buf, size_t len, FsSaveDataSpaceId saveDataSpaceId, u64 saveID) { + if (hosversionBefore(2,0,0)) + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + + IpcCommand c; + ipcInitialize(&c); + ipcAddSendBuffer(&c, buf, len, BufferType_Normal); + + struct { + u64 magic; + u64 cmd_id; + u64 saveDataSpaceId; + u64 saveID; + } *raw; + + raw = serviceIpcPrepareHeader(&g_fsSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 59; + raw->saveDataSpaceId = saveDataSpaceId; + raw->saveID = saveID; + + Result rc = serviceIpcDispatch(&g_fsSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + } *resp; + + serviceIpcParse(&g_fsSrv, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + } + + return rc; +} + // Wrapper(s) for fsCreateSaveDataFileSystemBySystemSaveDataId. Result fsCreate_SystemSaveDataWithOwner(FsSaveDataSpaceId saveDataSpaceId, u64 saveID, u128 userID, u64 ownerId, u64 size, u64 journalSize, u32 flags) { FsSave save = {