mirror of
https://github.com/switchbrew/libnx.git
synced 2025-08-05 16:09:24 +02:00
Check for invalid handle in fs*Close(). Added fsOpenDataStorageByCurrentProcess(), fsStorageRead(), and fsStorageClose(). Added fsdevGetDefaultFileSystem(). Imported nro.h from nx-hbmenu. Implemented proper RomFS support.
This commit is contained in:
parent
9e96639681
commit
4c1b09d6b9
@ -12,6 +12,8 @@ extern "C" {
|
||||
#include "switch/types.h"
|
||||
#include "switch/result.h"
|
||||
|
||||
#include "switch/nro.h"
|
||||
|
||||
#include "switch/kernel/svc.h"
|
||||
#include "switch/kernel/tmem.h"
|
||||
#include "switch/kernel/shmem.h"
|
||||
@ -59,6 +61,7 @@ extern "C" {
|
||||
#include "switch/runtime/devices/console.h"
|
||||
#include "switch/runtime/devices/usb_comms.h"
|
||||
#include "switch/runtime/devices/fs_dev.h"
|
||||
#include "switch/runtime/devices/romfs_dev.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
54
nx/include/switch/nro.h
Normal file
54
nx/include/switch/nro.h
Normal file
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* @file nro.h
|
||||
* @brief NRO headers.
|
||||
* @copyright libnx Authors
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define NROHEADER_MAGICNUM 0x304f524e
|
||||
|
||||
#define ASSETHEADER_MAGICNUM 0x54455341
|
||||
#define ASSETHEADER_VERSION 0
|
||||
|
||||
/// Entry for each segment in the codebin.
|
||||
typedef struct {
|
||||
u32 FileOff;
|
||||
u32 Size;
|
||||
} NsoSegment;
|
||||
|
||||
/// Offset 0x0 in the NRO.
|
||||
typedef struct {
|
||||
u32 unused;
|
||||
u32 modOffset;
|
||||
u8 Padding[8];
|
||||
} NroStart;
|
||||
|
||||
/// This follows NroStart, the actual nro-header.
|
||||
typedef struct {
|
||||
u32 Magic;
|
||||
u32 Unk1;
|
||||
u32 size;
|
||||
u32 Unk2;
|
||||
NsoSegment Segments[3];
|
||||
u32 bssSize;
|
||||
u32 Unk3;
|
||||
u8 BuildId[0x20];
|
||||
u8 Padding[0x20];
|
||||
} NroHeader;
|
||||
|
||||
/// Custom asset section.
|
||||
typedef struct {
|
||||
u64 offset;
|
||||
u64 size;
|
||||
} AssetSection;
|
||||
|
||||
/// Custom asset header.
|
||||
typedef struct {
|
||||
u32 magic;
|
||||
u32 version;
|
||||
AssetSection icon;
|
||||
AssetSection nacp;
|
||||
AssetSection romfs;
|
||||
} AssetHeader;
|
||||
|
@ -38,3 +38,6 @@ int fsdevUnmountDevice(const char *name);
|
||||
/// Uses fsFsCommit() with the specified device. This must be used after any savedata-write operations(not just file-write).
|
||||
/// This is not used automatically at device unmount.
|
||||
Result fsdevCommitDevice(const char *name);
|
||||
|
||||
/// Returns the FsFileSystem for the default device (SD card), if mounted. Used internally by romfs_dev.
|
||||
FsFileSystem* fsdevGetDefaultFileSystem(void);
|
||||
|
@ -66,7 +66,7 @@ static inline Result romfsInit(void)
|
||||
|
||||
/**
|
||||
* @brief Mounts RomFS from an open file.
|
||||
* @param file Handle of the RomFS file.
|
||||
* @param file FsFile of the RomFS image.
|
||||
* @param offset Offset of the RomFS within the file.
|
||||
* @param mount Output mount handle
|
||||
*/
|
||||
@ -76,6 +76,18 @@ static inline Result romfsInitFromFile(FsFile file, u64 offset)
|
||||
return romfsMountFromFile(file, offset, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Mounts RomFS from an open storage.
|
||||
* @param storage FsStorage of the RomFS image.
|
||||
* @param offset Offset of the RomFS within the storage.
|
||||
* @param mount Output mount handle
|
||||
*/
|
||||
Result romfsMountFromStorage(FsStorage storage, u64 offset, struct romfs_mount **mount);
|
||||
static inline Result romfsInitFromStorage(FsStorage storage, u64 offset)
|
||||
{
|
||||
return romfsMountFromStorage(storage, offset, NULL);
|
||||
}
|
||||
|
||||
/// Bind the RomFS mount
|
||||
Result romfsBind(struct romfs_mount *mount);
|
||||
|
||||
|
@ -93,6 +93,7 @@ Service* fsGetServiceSession(void);
|
||||
|
||||
Result fsMountSdcard(FsFileSystem* out);
|
||||
Result fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save);
|
||||
Result fsOpenDataStorageByCurrentProcess(FsStorage* out);
|
||||
// todo: Rest of commands here
|
||||
|
||||
/// FsFileSystem can be mounted with fs_dev for use with stdio, see fs_dev.h.
|
||||
@ -130,4 +131,6 @@ Result fsDirRead(FsDir* d, u64 inval, size_t* total_entries, size_t max_entries,
|
||||
Result fsDirGetEntryCount(FsDir* d, u64* count);
|
||||
void fsDirClose(FsDir* d);
|
||||
|
||||
// todo: IStorage
|
||||
// IStorage
|
||||
Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len);
|
||||
void fsStorageClose(FsStorage* s);
|
||||
|
@ -469,6 +469,13 @@ Result fsdevExit(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
FsFileSystem* fsdevGetDefaultFileSystem(void)
|
||||
{
|
||||
if(fsdev_fsdevice_default==-1) return NULL;
|
||||
|
||||
return &fsdev_fsdevices[fsdev_fsdevice_default].fs;
|
||||
}
|
||||
|
||||
/*! Open a file
|
||||
*
|
||||
* @param[in,out] r newlib reentrancy struct
|
||||
|
@ -9,14 +9,17 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "runtime/devices/romfs_dev.h"
|
||||
#include "runtime/devices/fs_dev.h"
|
||||
#include "runtime/util/utf.h"
|
||||
#include "services/fs.h"
|
||||
|
||||
/// WARNING: This is not ready to be used.
|
||||
#include "runtime/env.h"
|
||||
#include "nro.h"
|
||||
|
||||
typedef struct romfs_mount
|
||||
{
|
||||
bool fd_type;
|
||||
FsFile fd;
|
||||
FsStorage fd_storage;
|
||||
time_t mtime;
|
||||
u64 offset;
|
||||
romfs_header header;
|
||||
@ -30,7 +33,6 @@ extern int __system_argc;
|
||||
extern char** __system_argv;
|
||||
|
||||
static char __component[PATH_MAX+1];
|
||||
//static uint16_t __utf16path[PATH_MAX+1];
|
||||
|
||||
#define romFS_root(m) ((romfs_dir*)(m)->dirTable)
|
||||
#define romFS_dir(m,x) ((romfs_dir*) ((u8*)(m)->dirTable + (x)))
|
||||
@ -39,16 +41,25 @@ static char __component[PATH_MAX+1];
|
||||
#define romFS_dir_mode (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH)
|
||||
#define romFS_file_mode (S_IFREG | S_IRUSR | S_IRGRP | S_IROTH)
|
||||
|
||||
static ssize_t _romfs_read(romfs_mount *mount, u64 offset, void* buffer, u32 size)
|
||||
static ssize_t _romfs_read(romfs_mount *mount, u64 offset, void* buffer, u64 size)
|
||||
{
|
||||
u64 pos = mount->offset + offset;
|
||||
size_t read = 0;
|
||||
Result rc = fsFileRead(&mount->fd, pos, buffer, size, &read);
|
||||
Result rc = 0;
|
||||
if(!mount->fd_type)
|
||||
{
|
||||
rc = fsFileRead(&mount->fd, pos, buffer, size, &read);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = fsStorageRead(&mount->fd_storage, pos, buffer, size);
|
||||
read = size;
|
||||
}
|
||||
if (R_FAILED(rc)) return -1;
|
||||
return read;
|
||||
}
|
||||
|
||||
static bool _romfs_read_chk(romfs_mount *mount, u64 offset, void* buffer, u32 size)
|
||||
static bool _romfs_read_chk(romfs_mount *mount, u64 offset, void* buffer, u64 size)
|
||||
{
|
||||
return _romfs_read(mount, offset, buffer, size) == size;
|
||||
}
|
||||
@ -104,26 +115,8 @@ static devoptab_t romFS_devoptab =
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// File header
|
||||
/*#define _3DSX_MAGIC 0x58534433 // '3DSX'
|
||||
typedef struct
|
||||
{
|
||||
u32 magic;
|
||||
u16 headerSize, relocHdrSize;
|
||||
u32 formatVer;
|
||||
u32 flags;
|
||||
|
||||
// Sizes of the code, rodata and data segments +
|
||||
// size of the BSS section (uninitialized latter half of the data segment)
|
||||
u32 codeSegSize, rodataSegSize, dataSegSize, bssSize;
|
||||
// offset and size of smdh
|
||||
u32 smdhOffset, smdhSize;
|
||||
// offset to filesystem
|
||||
u32 fsOffset;
|
||||
} _3DSX_Header;*/
|
||||
|
||||
static Result romfsMountCommon(romfs_mount *mount);
|
||||
//static void romfsInitMtime(romfs_mount *mount, FS_ArchiveID archId, FS_Path archPath, FS_Path filePath);
|
||||
static void romfsInitMtime(romfs_mount *mount);
|
||||
|
||||
__attribute__((weak)) const char* __romfs_path = NULL;
|
||||
|
||||
@ -173,9 +166,19 @@ Result romfsMount(struct romfs_mount **p)
|
||||
if(mount == NULL)
|
||||
return 99;
|
||||
|
||||
if (/*envIsHomebrew()*/1)//TODO: How to handle?
|
||||
if (!envIsNso())
|
||||
{
|
||||
// RomFS appended to a 3DSX file
|
||||
// RomFS embedded in a NRO
|
||||
|
||||
mount->fd_type = 0;
|
||||
|
||||
FsFileSystem *sdfs = fsdevGetDefaultFileSystem();
|
||||
if(sdfs==NULL)
|
||||
{
|
||||
romfs_free(mount);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char* filename = __romfs_path;
|
||||
if (__system_argc > 0 && __system_argv[0])
|
||||
filename = __system_argv[0];
|
||||
@ -187,69 +190,57 @@ Result romfsMount(struct romfs_mount **p)
|
||||
|
||||
if (strncmp(filename, "sdmc:/", 6) == 0)
|
||||
filename += 5;
|
||||
/*else if (strncmp(filename, "3dslink:/", 9) == 0)
|
||||
else if (strncmp(filename, "nxlink:/", 8) == 0)
|
||||
{
|
||||
strncpy(__component, "/3ds", PATH_MAX);
|
||||
strncat(__component, filename+8, PATH_MAX);
|
||||
strncpy(__component, "/switch", PATH_MAX);
|
||||
strncat(__component, filename+7, PATH_MAX);
|
||||
__component[PATH_MAX] = 0;
|
||||
filename = __component;
|
||||
}*/
|
||||
}
|
||||
else
|
||||
{
|
||||
romfs_free(mount);
|
||||
return 2;
|
||||
}
|
||||
|
||||
//TODO
|
||||
/*ssize_t units = utf8_to_utf16(__utf16path, (const uint8_t*)filename, PATH_MAX);
|
||||
if (units < 0)
|
||||
{
|
||||
romfs_free(mount);
|
||||
return 3;
|
||||
}
|
||||
if (units >= PATH_MAX)
|
||||
{
|
||||
romfs_free(mount);
|
||||
return 4;
|
||||
}
|
||||
__utf16path[units] = 0;
|
||||
|
||||
FS_Path archPath = { PATH_EMPTY, 1, (u8*)"" };
|
||||
FS_Path filePath = { PATH_UTF16, (units+1)*2, (u8*)__utf16path };
|
||||
|
||||
Result rc = FSUSER_OpenFileDirectly(&mount->fd, ARCHIVE_SDMC, archPath, filePath, FS_OPEN_READ, 0);
|
||||
Result rc = fsFsOpenFile(sdfs, filename, FS_OPEN_READ, &mount->fd);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
romfs_free(mount);
|
||||
return rc;
|
||||
}
|
||||
|
||||
//romfsInitMtime(mount, ARCHIVE_SDMC, archPath, filePath);
|
||||
romfsInitMtime(mount);
|
||||
|
||||
_3DSX_Header hdr;
|
||||
if (!_romfs_read_chk(mount, 0, &hdr, sizeof(hdr))) goto _fail0;
|
||||
if (hdr.magic != _3DSX_MAGIC) goto _fail0;
|
||||
if (hdr.headerSize < sizeof(hdr)) goto _fail0;
|
||||
mount->offset = hdr.fsOffset;
|
||||
if (!mount->offset) goto _fail0;*/
|
||||
NroHeader hdr;
|
||||
AssetHeader asset_header;
|
||||
|
||||
if (!_romfs_read_chk(mount, sizeof(NroStart), &hdr, sizeof(hdr))) goto _fail0;
|
||||
if (hdr.Magic != NROHEADER_MAGICNUM) goto _fail0;
|
||||
if (!_romfs_read_chk(mount, hdr.size, &asset_header, sizeof(asset_header))) goto _fail0;
|
||||
|
||||
if (asset_header.magic != ASSETHEADER_MAGICNUM
|
||||
|| asset_header.version > ASSETHEADER_VERSION
|
||||
|| asset_header.romfs.offset == 0
|
||||
|| asset_header.romfs.size == 0)
|
||||
goto _fail0;
|
||||
|
||||
mount->offset = hdr.size + asset_header.romfs.offset;
|
||||
}
|
||||
else//TODO
|
||||
else
|
||||
{
|
||||
// Regular RomFS
|
||||
/*u8 zeros[0xC];
|
||||
memset(zeros, 0, sizeof(zeros));
|
||||
|
||||
FS_Path archPath = { PATH_EMPTY, 1, (u8*)"" };
|
||||
FS_Path filePath = { PATH_BINARY, sizeof(zeros), zeros };
|
||||
mount->fd_type = 1;
|
||||
|
||||
Result rc = FSUSER_OpenFileDirectly(&mount->fd, ARCHIVE_ROMFS, archPath, filePath, FS_OPEN_READ, 0);
|
||||
Result rc = fsOpenDataStorageByCurrentProcess(&mount->fd_storage);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
romfs_free(mount);
|
||||
return rc;
|
||||
}
|
||||
|
||||
//romfsInitMtime(mount, ARCHIVE_ROMFS, archPath, filePath);*/
|
||||
romfsInitMtime(mount);
|
||||
}
|
||||
|
||||
Result ret = romfsMountCommon(mount);
|
||||
@ -258,8 +249,9 @@ Result romfsMount(struct romfs_mount **p)
|
||||
|
||||
return ret;
|
||||
|
||||
//_fail0:
|
||||
fsFileClose(&mount->fd);
|
||||
_fail0:
|
||||
if(!mount->fd_type)fsFileClose(&mount->fd);
|
||||
if(mount->fd_type)fsStorageClose(&mount->fd_storage);
|
||||
romfs_free(mount);
|
||||
return 10;
|
||||
}
|
||||
@ -270,6 +262,7 @@ Result romfsMountFromFile(FsFile file, u64 offset, struct romfs_mount **p)
|
||||
if(mount == NULL)
|
||||
return 99;
|
||||
|
||||
mount->fd_type = 0;
|
||||
mount->fd = file;
|
||||
mount->offset = offset;
|
||||
|
||||
@ -280,6 +273,23 @@ Result romfsMountFromFile(FsFile file, u64 offset, struct romfs_mount **p)
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result romfsMountFromStorage(FsStorage storage, u64 offset, struct romfs_mount **p)
|
||||
{
|
||||
romfs_mount *mount = romfs_alloc();
|
||||
if(mount == NULL)
|
||||
return 99;
|
||||
|
||||
mount->fd_type = 1;
|
||||
mount->fd_storage = storage;
|
||||
mount->offset = offset;
|
||||
|
||||
Result ret = romfsMountCommon(mount);
|
||||
if(R_SUCCEEDED(ret) && p)
|
||||
*p = mount;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Result romfsMountCommon(romfs_mount *mount)
|
||||
{
|
||||
if (_romfs_read(mount, 0, &mount->header, sizeof(mount->header)) != sizeof(mount->header))
|
||||
@ -318,35 +328,16 @@ Result romfsMountCommon(romfs_mount *mount)
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
fsFileClose(&mount->fd);
|
||||
if(!mount->fd_type)fsFileClose(&mount->fd);
|
||||
if(mount->fd_type)fsStorageClose(&mount->fd_storage);
|
||||
romfs_free(mount);
|
||||
return 10;
|
||||
}
|
||||
|
||||
/*static void romfsInitMtime(romfs_mount *mount, FS_ArchiveID archId, FS_Path archPath, FS_Path filePath)
|
||||
static void romfsInitMtime(romfs_mount *mount)
|
||||
{
|
||||
u64 mtime;
|
||||
FS_Archive arch;
|
||||
Result rc;
|
||||
|
||||
mount->mtime = time(NULL);
|
||||
rc = FSUSER_OpenArchive(&arch, archId, archPath);
|
||||
if (R_FAILED(rc))
|
||||
return;
|
||||
|
||||
rc = FSUSER_ControlArchive(arch, ARCHIVE_ACTION_GET_TIMESTAMP,
|
||||
(void*)filePath.data, filePath.size,
|
||||
&mtime, sizeof(mtime));
|
||||
FSUSER_CloseArchive(arch);
|
||||
if (R_FAILED(rc))
|
||||
return;*/
|
||||
|
||||
/* convert from milliseconds to seconds */
|
||||
//mtime /= 1000;
|
||||
/* convert from 2000-based timestamp to UNIX timestamp */
|
||||
/*mtime += 946684800;
|
||||
mount->mtime = mtime;
|
||||
}*/
|
||||
}
|
||||
|
||||
Result romfsBind(struct romfs_mount *mount)
|
||||
{
|
||||
@ -368,7 +359,8 @@ Result romfsUnmount(struct romfs_mount *mount)
|
||||
if(mount)
|
||||
{
|
||||
// unmount specific
|
||||
fsFileClose(&mount->fd);
|
||||
if(!mount->fd_type)fsFileClose(&mount->fd);
|
||||
if(mount->fd_type)fsStorageClose(&mount->fd_storage);
|
||||
romfs_free(mount);
|
||||
}
|
||||
else
|
||||
@ -376,7 +368,8 @@ Result romfsUnmount(struct romfs_mount *mount)
|
||||
// unmount everything
|
||||
while(romfs_mount_list)
|
||||
{
|
||||
fsFileClose(&romfs_mount_list->fd);
|
||||
if(!romfs_mount_list->fd_type)fsFileClose(&romfs_mount_list->fd);
|
||||
if(romfs_mount_list->fd_type)fsStorageClose(&romfs_mount_list->fd_storage);
|
||||
romfs_free(romfs_mount_list);
|
||||
}
|
||||
}
|
||||
@ -483,7 +476,7 @@ static int navigateToDir(romfs_mount *mount, romfs_dir** ppDir, const char** pPa
|
||||
}
|
||||
}
|
||||
|
||||
*ppDir = searchForDir(mount, *ppDir, (uint8_t*)component, strlen(component)+1);
|
||||
*ppDir = searchForDir(mount, *ppDir, (uint8_t*)component, strlen(component));
|
||||
if (!*ppDir)
|
||||
return EEXIST;
|
||||
}
|
||||
@ -551,7 +544,7 @@ int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags,
|
||||
if (r->_errno != 0)
|
||||
return -1;
|
||||
|
||||
romfs_file* file = searchForFile(fileobj->mount, curDir, (uint8_t*)path, strlen(path)+1);
|
||||
romfs_file* file = searchForFile(fileobj->mount, curDir, (uint8_t*)path, strlen(path));
|
||||
if (!file)
|
||||
{
|
||||
if(flags & O_CREAT)
|
||||
@ -567,7 +560,7 @@ int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags,
|
||||
}
|
||||
|
||||
fileobj->file = file;
|
||||
fileobj->offset = (u64)fileobj->mount->header.fileDataOff + file->dataOff;
|
||||
fileobj->offset = fileobj->mount->header.fileDataOff + file->dataOff;
|
||||
fileobj->pos = 0;
|
||||
|
||||
return 0;
|
||||
@ -669,7 +662,7 @@ int romfs_stat(struct _reent *r, const char *path, struct stat *st)
|
||||
if(r->_errno != 0)
|
||||
return -1;
|
||||
|
||||
romfs_dir* dir = searchForDir(mount, curDir, (uint8_t*)path, strlen(path)+1);
|
||||
romfs_dir* dir = searchForDir(mount, curDir, (uint8_t*)path, strlen(path));
|
||||
if(dir)
|
||||
{
|
||||
memset(st, 0, sizeof(*st));
|
||||
@ -684,7 +677,7 @@ int romfs_stat(struct _reent *r, const char *path, struct stat *st)
|
||||
return 0;
|
||||
}
|
||||
|
||||
romfs_file* file = searchForFile(mount, curDir, (uint8_t*)path, strlen(path)+1);
|
||||
romfs_file* file = searchForFile(mount, curDir, (uint8_t*)path, strlen(path));
|
||||
if(file)
|
||||
{
|
||||
memset(st, 0, sizeof(*st));
|
||||
|
@ -131,6 +131,41 @@ Result fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
Result fsOpenDataStorageByCurrentProcess(FsStorage* out) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 200;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Wrapper(s) for fsMountSaveData.
|
||||
Result fsMount_SaveData(FsFileSystem* out, u64 titleID, u128 userID) {
|
||||
FsSave save;
|
||||
@ -595,7 +630,7 @@ Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out) {
|
||||
}
|
||||
|
||||
void fsFsClose(FsFileSystem* fs) {
|
||||
svcCloseHandle(fs->h);
|
||||
if(fs->h != INVALID_HANDLE) svcCloseHandle(fs->h);
|
||||
}
|
||||
|
||||
// IFile implementation
|
||||
@ -778,12 +813,12 @@ Result fsFileGetSize(FsFile* f, u64* out) {
|
||||
}
|
||||
|
||||
void fsFileClose(FsFile* f) {
|
||||
svcCloseHandle(f->h);
|
||||
if(f->h != INVALID_HANDLE) svcCloseHandle(f->h);
|
||||
}
|
||||
|
||||
// IDirectory implementation
|
||||
void fsDirClose(FsDir* d) {
|
||||
svcCloseHandle(d->h);
|
||||
if(d->h != INVALID_HANDLE) svcCloseHandle(d->h);
|
||||
}
|
||||
|
||||
Result fsDirRead(FsDir* d, u64 inval, size_t* total_entries, size_t max_entries, FsDirectoryEntry *buf) {
|
||||
@ -858,3 +893,44 @@ Result fsDirGetEntryCount(FsDir* d, u64* count) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
// IStorage implementation
|
||||
Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len) {
|
||||
IpcCommand c;
|
||||
ipcInitialize(&c);
|
||||
ipcAddRecvBuffer(&c, buf, len, 1);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 cmd_id;
|
||||
u64 offset;
|
||||
u64 read_size;
|
||||
} *raw;
|
||||
|
||||
raw = ipcPrepareHeader(&c, sizeof(*raw));
|
||||
|
||||
raw->magic = SFCI_MAGIC;
|
||||
raw->cmd_id = 0;
|
||||
raw->offset = off;
|
||||
raw->read_size = len;
|
||||
|
||||
Result rc = ipcDispatch(s->h);
|
||||
|
||||
if (R_SUCCEEDED(rc)) {
|
||||
IpcParsedCommand r;
|
||||
ipcParse(&r);
|
||||
|
||||
struct {
|
||||
u64 magic;
|
||||
u64 result;
|
||||
} *resp = r.Raw;
|
||||
|
||||
rc = resp->result;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void fsStorageClose(FsStorage* s) {
|
||||
if(s->h != INVALID_HANDLE) svcCloseHandle(s->h);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user