From 26d2e6d7f40d4611c8caab53efc1f9980f603dad Mon Sep 17 00:00:00 2001 From: yellows8 Date: Mon, 26 Mar 2018 14:45:12 -0400 Subject: [PATCH] Implemented FsSaveDataIterator (aka ISaveDataInfoReader). In fs*Close(), set the handle to INVALID_HANDLE after closing the handle. Changed ContentStorageId in FsSave to SaveDataType. Added enums FsSaveDataSpaceId and FsSaveDataType. Removed FS_MOUNTSAVEDATA_INVAL_DEFAULT/FS_MOUNTSYSTEMSAVEDATA_INVAL_DEFAULT. --- nx/include/switch/services/fs.h | 56 ++++++++++++--- nx/source/services/fs.c | 123 +++++++++++++++++++++++++++++--- 2 files changed, 162 insertions(+), 17 deletions(-) diff --git a/nx/include/switch/services/fs.h b/nx/include/switch/services/fs.h index aa8a37df..1f1a0b6b 100644 --- a/nx/include/switch/services/fs.h +++ b/nx/include/switch/services/fs.h @@ -1,7 +1,7 @@ /** * @file fs.h * @brief Filesystem (fsp-srv) service IPC wrapper. - * Normally applications should just use standard stdio not FS-serv directly. However this can be used if obtaining a FsFileSystem, FsFile, or FsStorage, for mounting with fs_dev/romfs_dev. + * Normally applications should just use standard stdio not FS-serv directly. However this can be used if obtaining a FsFileSystem, FsFile, or FsStorage, for mounting with fs_dev/romfs_dev, etc. * @author plutoo * @author yellows8 * @copyright libnx Authors @@ -14,16 +14,10 @@ #define FS_MAX_PATH 0x301 -/// For use with fsMountSaveData(). -#define FS_MOUNTSAVEDATA_INVAL_DEFAULT 0x1 - -/// For use with fsMountSystemSaveData(). -#define FS_MOUNTSYSTEMSAVEDATA_INVAL_DEFAULT 0x0 - /// For use with FsSave. #define FS_SAVEDATA_CURRENT_TITLEID 0 -/// For use with FsSave. +/// For use with \ref FsSave and \ref FsSaveDataInfo. #define FS_SAVEDATA_USERID_COMMONSAVE 0 typedef struct { @@ -42,6 +36,10 @@ typedef struct { Handle h; } FsStorage; +typedef struct { + Handle h; +} FsSaveDataIterator; + /// Directory entry. typedef struct { @@ -58,12 +56,25 @@ typedef struct u64 titleID; ///< titleID of the savedata to access when accessing other titles' savedata via SaveData, otherwise FS_SAVEDATA_CURRENT_TITLEID. u128 userID; ///< userID of the user-specific savedata to access, otherwise FS_SAVEDATA_USERID_COMMONSAVE. See account.h. u64 saveID; ///< saveID, 0 for SaveData. - u64 ContentStorageId; ///< ContentStorageId? See FsContentStorageId. + u64 SaveDataType; ///< See \ref FsSaveDataType. u64 unk_x28; ///< 0 for SystemSaveData/SaveData. u64 unk_x30; ///< 0 for SystemSaveData/SaveData. u64 unk_x38; ///< 0 for SystemSaveData/SaveData. } PACKED FsSave; +typedef struct +{ + u64 saveID_unk; + u8 SaveDataSpaceId; ///< See \ref FsSaveDataSpaceId. + u8 SaveDataType; ///< See \ref FsSaveDataType. + u8 pad[6]; + u128 userID; ///< See userID for \ref FsSave. + u64 saveID; ///< See saveID for \ref FsSave. + u64 titleID; ///< titleID for FsSaveDataType_SaveData. + u64 size; ///< Raw saveimage size. + u8 unk_x38[0x28]; ///< Unknown. Usually zeros? +} PACKED FsSaveDataInfo; + typedef enum { ENTRYTYPE_DIR = 0, ENTRYTYPE_FILE = 1 @@ -90,6 +101,26 @@ typedef enum FS_CONTENTSTORAGEID_SdCard = 2, } FsContentStorageId; +typedef enum +{ + FsSaveDataSpaceId_NandSystem = 0, + FsSaveDataSpaceId_NandUser = 1, + FsSaveDataSpaceId_SdCard = 2, + FsSaveDataSpaceId_TemporaryStorage = 3, + + FsSaveDataSpaceId_All = -1, ///< Pseudo value for fsOpenSaveDataIterator(). +} FsSaveDataSpaceId; + +typedef enum +{ + FsSaveDataType_SystemSaveData = 0, + FsSaveDataType_SaveData = 1, + FsSaveDataType_BcatDeliveryCacheStorage = 2, + FsSaveDataType_DeviceSaveData = 3, + FsSaveDataType_TemporaryStorage = 4, ///< [3.0.0+] + FsSaveDataType_CacheStorage = 5, ///< [3.0.0+] +} FsSaveDataType; + Result fsInitialize(void); void fsExit(void); @@ -100,6 +131,7 @@ Result fsMountSdcard(FsFileSystem* out); Result fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save); Result fsMountSystemSaveData(FsFileSystem* out, u8 inval, FsSave *save); +Result fsOpenSaveDataIterator(FsSaveDataIterator* out, s32 SaveDataSpaceId); Result fsOpenDataStorageByCurrentProcess(FsStorage* out); // todo: Rest of commands here @@ -145,3 +177,9 @@ void fsDirClose(FsDir* d); // IStorage Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len); void fsStorageClose(FsStorage* s); + +// ISaveDataInfoReader + +/// Read FsSaveDataInfo data into the buf array. +Result fsSaveDataIteratorRead(FsSaveDataIterator *s, FsSaveDataInfo* buf, size_t max_entries, size_t* total_entries); +void fsSaveDataIteratorClose(FsSaveDataIterator *s); diff --git a/nx/source/services/fs.c b/nx/source/services/fs.c index c02d3edb..3826c952 100644 --- a/nx/source/services/fs.c +++ b/nx/source/services/fs.c @@ -177,6 +177,56 @@ Result fsMountSystemSaveData(FsFileSystem* out, u8 inval, FsSave *save) { return rc; } +Result fsOpenSaveDataIterator(FsSaveDataIterator* out, s32 SaveDataSpaceId) { + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + struct { + u64 magic; + u64 cmd_id; + u8 SaveDataSpaceId; + } *raw2; + + if (SaveDataSpaceId == FsSaveDataSpaceId_All) { + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 60; + } + else { + raw2 = ipcPrepareHeader(&c, sizeof(*raw2)); + + raw2->magic = SFCI_MAGIC; + raw2->cmd_id = 61; + raw2->SaveDataSpaceId = SaveDataSpaceId; + } + + Result rc = serviceIpcDispatch(&g_fsSrv); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + out->h = r.Handles[0]; + } + } + + return rc; +} + Result fsOpenDataStorageByCurrentProcess(FsStorage* out) { IpcCommand c; ipcInitialize(&c); @@ -219,9 +269,9 @@ Result fsMount_SaveData(FsFileSystem* out, u64 titleID, u128 userID) { memset(&save, 0, sizeof(save)); save.titleID = titleID; save.userID = userID; - save.ContentStorageId = FS_CONTENTSTORAGEID_NandUser; + save.SaveDataType = FsSaveDataType_SaveData; - return fsMountSaveData(out, FS_MOUNTSAVEDATA_INVAL_DEFAULT, &save); + return fsMountSaveData(out, FsSaveDataSpaceId_NandUser, &save); } Result fsMount_SystemSaveData(FsFileSystem* out, u64 saveID) { @@ -229,9 +279,9 @@ Result fsMount_SystemSaveData(FsFileSystem* out, u64 saveID) { memset(&save, 0, sizeof(save)); save.saveID = saveID; - save.ContentStorageId = FS_CONTENTSTORAGEID_NandSystem; + save.SaveDataType = FsSaveDataType_SystemSaveData; - return fsMountSystemSaveData(out, FS_MOUNTSYSTEMSAVEDATA_INVAL_DEFAULT, &save); + return fsMountSystemSaveData(out, FsSaveDataSpaceId_NandSystem, &save); } // IFileSystem impl @@ -686,7 +736,10 @@ Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out) { } void fsFsClose(FsFileSystem* fs) { - if(fs->h != INVALID_HANDLE) svcCloseHandle(fs->h); + if(fs->h != INVALID_HANDLE) { + svcCloseHandle(fs->h); + fs->h = INVALID_HANDLE; + } } // IFile implementation @@ -869,12 +922,18 @@ Result fsFileGetSize(FsFile* f, u64* out) { } void fsFileClose(FsFile* f) { - if(f->h != INVALID_HANDLE) svcCloseHandle(f->h); + if(f->h != INVALID_HANDLE) { + svcCloseHandle(f->h); + f->h = INVALID_HANDLE; + } } // IDirectory implementation void fsDirClose(FsDir* d) { - if(d->h != INVALID_HANDLE) svcCloseHandle(d->h); + if(d->h != INVALID_HANDLE) { + svcCloseHandle(d->h); + d->h = INVALID_HANDLE; + } } Result fsDirRead(FsDir* d, u64 inval, size_t* total_entries, size_t max_entries, FsDirectoryEntry *buf) { @@ -987,6 +1046,54 @@ Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len) { } void fsStorageClose(FsStorage* s) { - if(s->h != INVALID_HANDLE) svcCloseHandle(s->h); + if(s->h != INVALID_HANDLE) { + svcCloseHandle(s->h); + s->h = INVALID_HANDLE; + } +} + +// ISaveDataInfoReader +Result fsSaveDataIteratorRead(FsSaveDataIterator *s, FsSaveDataInfo* buf, size_t max_entries, size_t* total_entries) { + IpcCommand c; + ipcInitialize(&c); + ipcAddRecvBuffer(&c, buf, sizeof(FsSaveDataInfo)*max_entries, 0); + + struct { + u64 magic; + u64 cmd_id; + } *raw; + + raw = ipcPrepareHeader(&c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 0; + + Result rc = ipcDispatch(s->h); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + ipcParse(&r); + + struct { + u64 magic; + u64 result; + u64 total_entries; + } *resp = r.Raw; + + rc = resp->result; + + if (R_SUCCEEDED(rc)) { + if (total_entries) *total_entries = resp->total_entries; + } + } + + return rc; +} + +void fsSaveDataIteratorClose(FsSaveDataIterator* s) { + if(s->h != INVALID_HANDLE) { + svcCloseHandle(s->h); + s->h = INVALID_HANDLE; + } }