diff --git a/nx/include/switch/runtime/devices/fs_dev.h b/nx/include/switch/runtime/devices/fs_dev.h index 5f4b9e99..50e84866 100644 --- a/nx/include/switch/runtime/devices/fs_dev.h +++ b/nx/include/switch/runtime/devices/fs_dev.h @@ -48,6 +48,9 @@ int fsdevTranslatePath(const char *path, FsFileSystem** device, char *outpath); /// This calls fsFsSetArchiveBit on the filesystem specified by the input path (as used in stdio). Result fsdevSetArchiveBit(const char *path); +/// This calls fsFsCreateFile on the filesystem specified by the input path (as used in stdio). +Result fsdevCreateFile(const char* path, size_t size, int flags); + /// Recursively deletes the directory specified by the input path (as used in stdio). Result fsdevDeleteDirectoryRecursively(const char *path); diff --git a/nx/include/switch/services/fs.h b/nx/include/switch/services/fs.h index ddae115d..2923c64e 100644 --- a/nx/include/switch/services/fs.h +++ b/nx/include/switch/services/fs.h @@ -109,13 +109,30 @@ typedef enum FS_OPEN_APPEND = BIT(2), ///< Append file. } FsFileFlags; +typedef enum +{ + FS_CREATE_BIG_FILE = BIT(0), ///< Creates a ConcatenationFile (dir with archive bit) instead of file. +} FsFileCreateFlags; + /// For use with fsFsOpenDirectory. typedef enum { - FS_DIROPEN_DIRECTORY = BIT(0), ///< Enable reading directory entries. - FS_DIROPEN_FILE = BIT(1), ///< Enable reading file entries. + FS_DIROPEN_DIRECTORY = BIT(0), ///< Enable reading directory entries. + FS_DIROPEN_FILE = BIT(1), ///< Enable reading file entries. + FS_DIROPEN_NO_FILE_SIZE = BIT(31), ///< Causes result entries to not contain filesize information (always 0). } FsDirectoryFlags; +typedef enum +{ + FS_READOPTION_NONE = 0, ///< No Option. +} FsReadOption; + +typedef enum +{ + FS_WRITEOPTION_NONE = 0, ///< No option. + FS_WRITEOPTION_FLUSH = BIT(0), ///< Forces a flush after write. +} FsWriteOption; + typedef enum { FsStorageId_None = 0, @@ -163,6 +180,19 @@ typedef struct { u32 value; } FsGameCardHandle; +typedef struct { + u32 aes_ctr_key_type; ///< Contains bitflags describing how data is AES encrypted + u32 speed_emulation_type; ///< Contains bitflags describing how data is emulated. + u32 reserved[0x38/sizeof(u32)]; +} FsRangeInfo; + +typedef enum { + FsOperationId_Clear, ///< Fill range with zero for supported file/storage. + FsOperationId_ClearSignature, ///< Clears signature for supported file/storage. + FsOperationId_InvalidateCache, ///< Invalidates cache for supported file/storage. + FsOperationId_QueryRange, ///< Retrieves information on data for supported file/storage. +} FsOperationId; + Result fsInitialize(void); void fsExit(void); @@ -213,6 +243,7 @@ typedef enum /// Mount requested filesystem type from content file Result fsOpenFileSystem(FsFileSystem* out, FsFileSystemType fsType, const char* contentPath); /// same as calling fsOpenFileSystemWithId with 0 as titleId Result fsOpenFileSystemWithId(FsFileSystem* out, u64 titleId, FsFileSystemType fsType, const char* contentPath); /// works on all firmwares, titleId is ignored on 1.0.0 +Result fsOpenFileSystemWithPatch(FsFileSystem* out, u64 titleId, FsFileSystemType fsType); /// 2.0.0+, like OpenFileSystemWithId but without content path. // IFileSystem Result fsFsCreateFile(FsFileSystem* fs, const char* path, size_t size, int flags); @@ -220,8 +251,8 @@ Result fsFsDeleteFile(FsFileSystem* fs, const char* path); Result fsFsCreateDirectory(FsFileSystem* fs, const char* path); Result fsFsDeleteDirectory(FsFileSystem* fs, const char* path); Result fsFsDeleteDirectoryRecursively(FsFileSystem* fs, const char* path); -Result fsFsRenameFile(FsFileSystem* fs, const char* path0, const char* path1); -Result fsFsRenameDirectory(FsFileSystem* fs, const char* path0, const char* path1); +Result fsFsRenameFile(FsFileSystem* fs, const char* cur_path, const char* new_path); +Result fsFsRenameDirectory(FsFileSystem* fs, const char* cur_path, const char* new_path); Result fsFsGetEntryType(FsFileSystem* fs, const char* path, FsEntryType* out); Result fsFsOpenFile(FsFileSystem* fs, const char* path, int flags, FsFile* out); Result fsFsOpenDirectory(FsFileSystem* fs, const char* path, int flags, FsDir* out); @@ -238,11 +269,12 @@ void fsFsClose(FsFileSystem* fs); Result fsFsSetArchiveBit(FsFileSystem* fs, const char *path); // IFile -Result fsFileRead(FsFile* f, u64 off, void* buf, size_t len, size_t* out); -Result fsFileWrite(FsFile* f, u64 off, const void* buf, size_t len); +Result fsFileRead(FsFile* f, u64 off, void* buf, size_t len, u32 option, size_t* out); +Result fsFileWrite(FsFile* f, u64 off, const void* buf, size_t len, u32 option); Result fsFileFlush(FsFile* f); Result fsFileSetSize(FsFile* f, u64 sz); Result fsFileGetSize(FsFile* f, u64* out); +Result fsFileOperateRange(FsFile* f, FsOperationId op_id, u64 off, size_t len, FsRangeInfo* out); void fsFileClose(FsFile* f); // IDirectory @@ -256,6 +288,7 @@ Result fsStorageWrite(FsStorage* s, u64 off, const void* buf, size_t len); Result fsStorageFlush(FsStorage* s); Result fsStorageSetSize(FsStorage* s, u64 sz); Result fsStorageGetSize(FsStorage* s, u64* out); +Result fsStorageOperateRange(FsStorage* s, FsOperationId op_id, u64 off, size_t len, FsRangeInfo* out); void fsStorageClose(FsStorage* s); // ISaveDataInfoReader diff --git a/nx/source/runtime/devices/fs_dev.c b/nx/source/runtime/devices/fs_dev.c index 88fd29a6..b5a54a1e 100644 --- a/nx/source/runtime/devices/fs_dev.c +++ b/nx/source/runtime/devices/fs_dev.c @@ -381,6 +381,16 @@ Result fsdevSetArchiveBit(const char *path) { return fsFsSetArchiveBit(&device->fs, fs_path); } +Result fsdevCreateFile(const char* path, size_t size, int flags) { + char fs_path[FS_MAX_PATH]; + fsdev_fsdevice *device = NULL; + + if(fsdev_getfspath(_REENT, path, &device, fs_path)==-1) + return MAKERESULT(Module_Libnx, LibnxError_NotFound); + + return fsFsCreateFile(&device->fs, fs_path, size, flags); +} + Result fsdevDeleteDirectoryRecursively(const char *path) { char fs_path[FS_MAX_PATH]; fsdev_fsdevice *device = NULL; @@ -680,7 +690,7 @@ fsdev_write(struct _reent *r, } } - rc = fsFileWrite(&file->fd, file->offset, ptr, len); + rc = fsFileWrite(&file->fd, file->offset, ptr, len, FS_WRITEOPTION_NONE); if(rc == 0xD401) return fsdev_write_safe(r, fd, ptr, len); if(R_FAILED(rc)) @@ -734,7 +744,7 @@ fsdev_write_safe(struct _reent *r, memcpy(tmp_buffer, ptr, toWrite); /* write the data */ - rc = fsFileWrite(&file->fd, file->offset, tmp_buffer, toWrite); + rc = fsFileWrite(&file->fd, file->offset, tmp_buffer, toWrite, FS_WRITEOPTION_NONE); if(R_FAILED(rc)) { @@ -789,7 +799,7 @@ fsdev_read(struct _reent *r, } /* read the data */ - rc = fsFileRead(&file->fd, file->offset, ptr, len, &bytes); + rc = fsFileRead(&file->fd, file->offset, ptr, len, FS_READOPTION_NONE, &bytes); if(rc == 0xD401) return fsdev_read_safe(r, fd, ptr, len); if(R_SUCCEEDED(rc)) @@ -836,7 +846,7 @@ fsdev_read_safe(struct _reent *r, toRead = sizeof(tmp_buffer); /* read the data */ - rc = fsFileRead(&file->fd, file->offset, tmp_buffer, toRead, &bytes); + rc = fsFileRead(&file->fd, file->offset, tmp_buffer, toRead, FS_READOPTION_NONE, &bytes); if(bytes > toRead) bytes = toRead; diff --git a/nx/source/runtime/devices/romfs_dev.c b/nx/source/runtime/devices/romfs_dev.c index 719cb1f0..cd9a5d92 100644 --- a/nx/source/runtime/devices/romfs_dev.c +++ b/nx/source/runtime/devices/romfs_dev.c @@ -56,7 +56,7 @@ static ssize_t _romfs_read(romfs_mount *mount, u64 offset, void* buffer, u64 siz Result rc = 0; if(mount->fd_type == RomfsSource_FsFile) { - rc = fsFileRead(&mount->fd, pos, buffer, size, &read); + rc = fsFileRead(&mount->fd, pos, buffer, size, FS_READOPTION_NONE, &read); } else if(mount->fd_type == RomfsSource_FsStorage) { diff --git a/nx/source/services/fs.c b/nx/source/services/fs.c index 4f2ef42e..f9218305 100644 --- a/nx/source/services/fs.c +++ b/nx/source/services/fs.c @@ -19,7 +19,7 @@ Result fsInitialize(void) return 0; Result rc = smGetService(&g_fsSrv, "fsp-srv"); - + if (R_SUCCEEDED(rc)) { rc = serviceConvertToDomain(&g_fsSrv); } @@ -549,9 +549,9 @@ Result fsOpenFileSystemWithId(FsFileSystem* out, u64 titleId, FsFileSystemType f u32 fsType; u64 titleId; } *raw; - + raw = serviceIpcPrepareHeader(&g_fsSrv, &c, sizeof(*raw)); - + raw->magic = SFCI_MAGIC; raw->cmd_id = 8; raw->fsType = fsType; @@ -563,9 +563,9 @@ Result fsOpenFileSystemWithId(FsFileSystem* out, u64 titleId, FsFileSystemType f u64 cmd_id; u32 fsType; } *raw; - + raw = serviceIpcPrepareHeader(&g_fsSrv, &c, sizeof(*raw)); - + raw->magic = SFCI_MAGIC; raw->cmd_id = 0; raw->fsType = fsType; @@ -593,6 +593,50 @@ Result fsOpenFileSystemWithId(FsFileSystem* out, u64 titleId, FsFileSystemType f return rc; } +Result fsOpenFileSystemWithPatch(FsFileSystem* out, u64 titleId, FsFileSystemType fsType) { + if (hosversionBefore(2,0,0)) { + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + } + + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 fsType; + u64 titleId; + } *raw; + + raw = serviceIpcPrepareHeader(&g_fsSrv, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 7; + raw->fsType = fsType; + raw->titleId = titleId; + + 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; + + if (R_SUCCEEDED(rc)) { + serviceCreateSubservice(&out->s, &g_fsSrv, &r, 0); + } + } + + return rc; +} + // IFileSystem impl Result fsFsCreateFile(FsFileSystem* fs, const char* path, size_t size, int flags) { IpcCommand c; @@ -602,7 +646,6 @@ Result fsFsCreateFile(FsFileSystem* fs, const char* path, size_t size, int flags struct { u64 magic; u64 cmd_id; - u64 zero; u32 flags; u64 size; } *raw; @@ -611,7 +654,6 @@ Result fsFsCreateFile(FsFileSystem* fs, const char* path, size_t size, int flags raw->magic = SFCI_MAGIC; raw->cmd_id = 0; - raw->zero = 0; raw->flags = flags; raw->size = size; @@ -765,11 +807,11 @@ Result fsFsDeleteDirectoryRecursively(FsFileSystem* fs, const char* path) { return rc; } -Result fsFsRenameFile(FsFileSystem* fs, const char* path0, const char* path1) { +Result fsFsRenameFile(FsFileSystem* fs, const char* cur_path, const char* new_path) { IpcCommand c; ipcInitialize(&c); - ipcAddSendStatic(&c, path0, FS_MAX_PATH, 0); - ipcAddSendStatic(&c, path1, FS_MAX_PATH, 1); + ipcAddSendStatic(&c, cur_path, FS_MAX_PATH, 0); + ipcAddSendStatic(&c, new_path, FS_MAX_PATH, 1); struct { u64 magic; @@ -799,11 +841,11 @@ Result fsFsRenameFile(FsFileSystem* fs, const char* path0, const char* path1) { return rc; } -Result fsFsRenameDirectory(FsFileSystem* fs, const char* path0, const char* path1) { +Result fsFsRenameDirectory(FsFileSystem* fs, const char* cur_path, const char* new_path) { IpcCommand c; ipcInitialize(&c); - ipcAddSendStatic(&c, path0, FS_MAX_PATH, 0); - ipcAddSendStatic(&c, path1, FS_MAX_PATH, 1); + ipcAddSendStatic(&c, cur_path, FS_MAX_PATH, 0); + ipcAddSendStatic(&c, new_path, FS_MAX_PATH, 1); struct { u64 magic; @@ -1187,7 +1229,7 @@ void fsFsClose(FsFileSystem* fs) { } // IFile implementation -Result fsFileRead(FsFile* f, u64 off, void* buf, size_t len, size_t* out) { +Result fsFileRead(FsFile* f, u64 off, void* buf, size_t len, u32 option, size_t* out) { IpcCommand c; ipcInitialize(&c); ipcAddRecvBuffer(&c, buf, len, 1); @@ -1195,7 +1237,7 @@ Result fsFileRead(FsFile* f, u64 off, void* buf, size_t len, size_t* out) { struct { u64 magic; u64 cmd_id; - u64 zero; + u32 option; u64 offset; u64 read_size; } *raw; @@ -1204,7 +1246,7 @@ Result fsFileRead(FsFile* f, u64 off, void* buf, size_t len, size_t* out) { raw->magic = SFCI_MAGIC; raw->cmd_id = 0; - raw->zero = 0; + raw->option = option; raw->offset = off; raw->read_size = len; @@ -1231,7 +1273,7 @@ Result fsFileRead(FsFile* f, u64 off, void* buf, size_t len, size_t* out) { return rc; } -Result fsFileWrite(FsFile* f, u64 off, const void* buf, size_t len) { +Result fsFileWrite(FsFile* f, u64 off, const void* buf, size_t len, u32 option) { IpcCommand c; ipcInitialize(&c); ipcAddSendBuffer(&c, buf, len, 1); @@ -1239,7 +1281,7 @@ Result fsFileWrite(FsFile* f, u64 off, const void* buf, size_t len) { struct { u64 magic; u64 cmd_id; - u64 zero; + u32 option; u64 offset; u64 write_size; } *raw; @@ -1248,7 +1290,7 @@ Result fsFileWrite(FsFile* f, u64 off, const void* buf, size_t len) { raw->magic = SFCI_MAGIC; raw->cmd_id = 1; - raw->zero = 0; + raw->option = option; raw->offset = off; raw->write_size = len; @@ -1370,6 +1412,51 @@ Result fsFileGetSize(FsFile* f, u64* out) { return rc; } +Result fsFileOperateRange(FsFile* f, FsOperationId op_id, u64 off, size_t len, FsRangeInfo* out) { + if (hosversionBefore(4,0,0)) { + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + } + + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 op_id; + u64 off; + u64 len; + } *raw; + + raw = serviceIpcPrepareHeader(&f->s, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 5; + raw->op_id = op_id; + raw->off = off; + raw->len = len; + + Result rc = serviceIpcDispatch(&f->s); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + FsRangeInfo range_info; + } *resp; + + serviceIpcParse(&f->s, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc) && out) *out = resp->range_info; + } + + return rc; + +} + void fsFileClose(FsFile* f) { serviceClose(&f->s); } @@ -1628,6 +1715,50 @@ Result fsStorageGetSize(FsStorage* s, u64* out) { return rc; } +Result fsStorageOperateRange(FsStorage* s, FsOperationId op_id, u64 off, size_t len, FsRangeInfo* out) { + if (hosversionBefore(4,0,0)) { + return MAKERESULT(Module_Libnx, LibnxError_IncompatSysVer); + } + + IpcCommand c; + ipcInitialize(&c); + + struct { + u64 magic; + u64 cmd_id; + u32 op_id; + u64 off; + u64 len; + } *raw; + + raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw)); + + raw->magic = SFCI_MAGIC; + raw->cmd_id = 5; + raw->op_id = op_id; + raw->off = off; + raw->len = len; + + Result rc = serviceIpcDispatch(&s->s); + + if (R_SUCCEEDED(rc)) { + IpcParsedCommand r; + struct { + u64 magic; + u64 result; + FsRangeInfo range_info; + } *resp; + + serviceIpcParse(&s->s, &r, sizeof(*resp)); + resp = r.Raw; + + rc = resp->result; + if (R_SUCCEEDED(rc) && out) *out = resp->range_info; + } + + return rc; +} + void fsStorageClose(FsStorage* s) { serviceClose(&s->s); }