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:
yellows8 2018-02-23 22:29:21 -05:00
parent 9e96639681
commit 4c1b09d6b9
8 changed files with 251 additions and 100 deletions

View File

@ -12,6 +12,8 @@ extern "C" {
#include "switch/types.h" #include "switch/types.h"
#include "switch/result.h" #include "switch/result.h"
#include "switch/nro.h"
#include "switch/kernel/svc.h" #include "switch/kernel/svc.h"
#include "switch/kernel/tmem.h" #include "switch/kernel/tmem.h"
#include "switch/kernel/shmem.h" #include "switch/kernel/shmem.h"
@ -59,6 +61,7 @@ extern "C" {
#include "switch/runtime/devices/console.h" #include "switch/runtime/devices/console.h"
#include "switch/runtime/devices/usb_comms.h" #include "switch/runtime/devices/usb_comms.h"
#include "switch/runtime/devices/fs_dev.h" #include "switch/runtime/devices/fs_dev.h"
#include "switch/runtime/devices/romfs_dev.h"
#ifdef __cplusplus #ifdef __cplusplus
} }

54
nx/include/switch/nro.h Normal file
View 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;

View File

@ -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). /// 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. /// This is not used automatically at device unmount.
Result fsdevCommitDevice(const char *name); Result fsdevCommitDevice(const char *name);
/// Returns the FsFileSystem for the default device (SD card), if mounted. Used internally by romfs_dev.
FsFileSystem* fsdevGetDefaultFileSystem(void);

View File

@ -66,7 +66,7 @@ static inline Result romfsInit(void)
/** /**
* @brief Mounts RomFS from an open file. * @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 offset Offset of the RomFS within the file.
* @param mount Output mount handle * @param mount Output mount handle
*/ */
@ -76,6 +76,18 @@ static inline Result romfsInitFromFile(FsFile file, u64 offset)
return romfsMountFromFile(file, offset, NULL); 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 /// Bind the RomFS mount
Result romfsBind(struct romfs_mount *mount); Result romfsBind(struct romfs_mount *mount);

View File

@ -93,6 +93,7 @@ Service* fsGetServiceSession(void);
Result fsMountSdcard(FsFileSystem* out); Result fsMountSdcard(FsFileSystem* out);
Result fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save); Result fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save);
Result fsOpenDataStorageByCurrentProcess(FsStorage* out);
// todo: Rest of commands here // todo: Rest of commands here
/// FsFileSystem can be mounted with fs_dev for use with stdio, see fs_dev.h. /// 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); Result fsDirGetEntryCount(FsDir* d, u64* count);
void fsDirClose(FsDir* d); void fsDirClose(FsDir* d);
// todo: IStorage // IStorage
Result fsStorageRead(FsStorage* s, u64 off, void* buf, size_t len);
void fsStorageClose(FsStorage* s);

View File

@ -469,6 +469,13 @@ Result fsdevExit(void)
return 0; return 0;
} }
FsFileSystem* fsdevGetDefaultFileSystem(void)
{
if(fsdev_fsdevice_default==-1) return NULL;
return &fsdev_fsdevices[fsdev_fsdevice_default].fs;
}
/*! Open a file /*! Open a file
* *
* @param[in,out] r newlib reentrancy struct * @param[in,out] r newlib reentrancy struct

View File

@ -9,14 +9,17 @@
#include <unistd.h> #include <unistd.h>
#include "runtime/devices/romfs_dev.h" #include "runtime/devices/romfs_dev.h"
#include "runtime/devices/fs_dev.h"
#include "runtime/util/utf.h" #include "runtime/util/utf.h"
#include "services/fs.h" #include "services/fs.h"
#include "runtime/env.h"
/// WARNING: This is not ready to be used. #include "nro.h"
typedef struct romfs_mount typedef struct romfs_mount
{ {
bool fd_type;
FsFile fd; FsFile fd;
FsStorage fd_storage;
time_t mtime; time_t mtime;
u64 offset; u64 offset;
romfs_header header; romfs_header header;
@ -30,7 +33,6 @@ extern int __system_argc;
extern char** __system_argv; extern char** __system_argv;
static char __component[PATH_MAX+1]; static char __component[PATH_MAX+1];
//static uint16_t __utf16path[PATH_MAX+1];
#define romFS_root(m) ((romfs_dir*)(m)->dirTable) #define romFS_root(m) ((romfs_dir*)(m)->dirTable)
#define romFS_dir(m,x) ((romfs_dir*) ((u8*)(m)->dirTable + (x))) #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_dir_mode (S_IFDIR | S_IRUSR | S_IRGRP | S_IROTH)
#define romFS_file_mode (S_IFREG | 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; u64 pos = mount->offset + offset;
size_t read = 0; 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; if (R_FAILED(rc)) return -1;
return read; 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; 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 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; __attribute__((weak)) const char* __romfs_path = NULL;
@ -173,9 +166,19 @@ Result romfsMount(struct romfs_mount **p)
if(mount == NULL) if(mount == NULL)
return 99; 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; const char* filename = __romfs_path;
if (__system_argc > 0 && __system_argv[0]) if (__system_argc > 0 && __system_argv[0])
filename = __system_argv[0]; filename = __system_argv[0];
@ -187,69 +190,57 @@ Result romfsMount(struct romfs_mount **p)
if (strncmp(filename, "sdmc:/", 6) == 0) if (strncmp(filename, "sdmc:/", 6) == 0)
filename += 5; filename += 5;
/*else if (strncmp(filename, "3dslink:/", 9) == 0) else if (strncmp(filename, "nxlink:/", 8) == 0)
{ {
strncpy(__component, "/3ds", PATH_MAX); strncpy(__component, "/switch", PATH_MAX);
strncat(__component, filename+8, PATH_MAX); strncat(__component, filename+7, PATH_MAX);
__component[PATH_MAX] = 0; __component[PATH_MAX] = 0;
filename = __component; filename = __component;
}*/ }
else else
{ {
romfs_free(mount); romfs_free(mount);
return 2; return 2;
} }
//TODO Result rc = fsFsOpenFile(sdfs, filename, FS_OPEN_READ, &mount->fd);
/*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);
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
romfs_free(mount); romfs_free(mount);
return rc; return rc;
} }
//romfsInitMtime(mount, ARCHIVE_SDMC, archPath, filePath); romfsInitMtime(mount);
_3DSX_Header hdr; NroHeader hdr;
if (!_romfs_read_chk(mount, 0, &hdr, sizeof(hdr))) goto _fail0; AssetHeader asset_header;
if (hdr.magic != _3DSX_MAGIC) goto _fail0;
if (hdr.headerSize < sizeof(hdr)) goto _fail0; if (!_romfs_read_chk(mount, sizeof(NroStart), &hdr, sizeof(hdr))) goto _fail0;
mount->offset = hdr.fsOffset; if (hdr.Magic != NROHEADER_MAGICNUM) goto _fail0;
if (!mount->offset) 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 // Regular RomFS
/*u8 zeros[0xC];
memset(zeros, 0, sizeof(zeros));
FS_Path archPath = { PATH_EMPTY, 1, (u8*)"" }; mount->fd_type = 1;
FS_Path filePath = { PATH_BINARY, sizeof(zeros), zeros };
Result rc = FSUSER_OpenFileDirectly(&mount->fd, ARCHIVE_ROMFS, archPath, filePath, FS_OPEN_READ, 0); Result rc = fsOpenDataStorageByCurrentProcess(&mount->fd_storage);
if (R_FAILED(rc)) if (R_FAILED(rc))
{ {
romfs_free(mount); romfs_free(mount);
return rc; return rc;
} }
//romfsInitMtime(mount, ARCHIVE_ROMFS, archPath, filePath);*/ romfsInitMtime(mount);
} }
Result ret = romfsMountCommon(mount); Result ret = romfsMountCommon(mount);
@ -258,8 +249,9 @@ Result romfsMount(struct romfs_mount **p)
return ret; return ret;
//_fail0: _fail0:
fsFileClose(&mount->fd); if(!mount->fd_type)fsFileClose(&mount->fd);
if(mount->fd_type)fsStorageClose(&mount->fd_storage);
romfs_free(mount); romfs_free(mount);
return 10; return 10;
} }
@ -270,6 +262,7 @@ Result romfsMountFromFile(FsFile file, u64 offset, struct romfs_mount **p)
if(mount == NULL) if(mount == NULL)
return 99; return 99;
mount->fd_type = 0;
mount->fd = file; mount->fd = file;
mount->offset = offset; mount->offset = offset;
@ -280,6 +273,23 @@ Result romfsMountFromFile(FsFile file, u64 offset, struct romfs_mount **p)
return ret; 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) Result romfsMountCommon(romfs_mount *mount)
{ {
if (_romfs_read(mount, 0, &mount->header, sizeof(mount->header)) != sizeof(mount->header)) if (_romfs_read(mount, 0, &mount->header, sizeof(mount->header)) != sizeof(mount->header))
@ -318,35 +328,16 @@ Result romfsMountCommon(romfs_mount *mount)
return 0; return 0;
fail: fail:
fsFileClose(&mount->fd); if(!mount->fd_type)fsFileClose(&mount->fd);
if(mount->fd_type)fsStorageClose(&mount->fd_storage);
romfs_free(mount); romfs_free(mount);
return 10; 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); 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) Result romfsBind(struct romfs_mount *mount)
{ {
@ -368,7 +359,8 @@ Result romfsUnmount(struct romfs_mount *mount)
if(mount) if(mount)
{ {
// unmount specific // unmount specific
fsFileClose(&mount->fd); if(!mount->fd_type)fsFileClose(&mount->fd);
if(mount->fd_type)fsStorageClose(&mount->fd_storage);
romfs_free(mount); romfs_free(mount);
} }
else else
@ -376,7 +368,8 @@ Result romfsUnmount(struct romfs_mount *mount)
// unmount everything // unmount everything
while(romfs_mount_list) 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); 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) if (!*ppDir)
return EEXIST; return EEXIST;
} }
@ -551,7 +544,7 @@ int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags,
if (r->_errno != 0) if (r->_errno != 0)
return -1; 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 (!file)
{ {
if(flags & O_CREAT) 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->file = file;
fileobj->offset = (u64)fileobj->mount->header.fileDataOff + file->dataOff; fileobj->offset = fileobj->mount->header.fileDataOff + file->dataOff;
fileobj->pos = 0; fileobj->pos = 0;
return 0; return 0;
@ -669,7 +662,7 @@ int romfs_stat(struct _reent *r, const char *path, struct stat *st)
if(r->_errno != 0) if(r->_errno != 0)
return -1; 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) if(dir)
{ {
memset(st, 0, sizeof(*st)); memset(st, 0, sizeof(*st));
@ -684,7 +677,7 @@ int romfs_stat(struct _reent *r, const char *path, struct stat *st)
return 0; 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) if(file)
{ {
memset(st, 0, sizeof(*st)); memset(st, 0, sizeof(*st));

View File

@ -131,6 +131,41 @@ Result fsMountSaveData(FsFileSystem* out, u8 inval, FsSave *save) {
return rc; 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. // Wrapper(s) for fsMountSaveData.
Result fsMount_SaveData(FsFileSystem* out, u64 titleID, u128 userID) { Result fsMount_SaveData(FsFileSystem* out, u64 titleID, u128 userID) {
FsSave save; FsSave save;
@ -595,7 +630,7 @@ Result fsFsGetTotalSpace(FsFileSystem* fs, const char* path, u64* out) {
} }
void fsFsClose(FsFileSystem* fs) { void fsFsClose(FsFileSystem* fs) {
svcCloseHandle(fs->h); if(fs->h != INVALID_HANDLE) svcCloseHandle(fs->h);
} }
// IFile implementation // IFile implementation
@ -778,12 +813,12 @@ Result fsFileGetSize(FsFile* f, u64* out) {
} }
void fsFileClose(FsFile* f) { void fsFileClose(FsFile* f) {
svcCloseHandle(f->h); if(f->h != INVALID_HANDLE) svcCloseHandle(f->h);
} }
// IDirectory implementation // IDirectory implementation
void fsDirClose(FsDir* d) { 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) { 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; 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);
}