Enable mounting RomFS and ExeFS as virtual game images

This commit is contained in:
d0k3 2016-12-09 21:57:53 +01:00
parent 8947db2037
commit 4dc92abef6
8 changed files with 46 additions and 24 deletions

View File

@ -24,9 +24,10 @@ This tool would not have been possible without the help of numerous people. Than
* **Archshift**, for providing the base project infrastructure
* **Normmatt**, for sdmmc.c / sdmmc.h
* **Cha(N)**, **Kane49**, and all other FatFS contributors for FatFS
* **b1l1s**, for helping me figure out A9LH compatibility
* **SciResM** for helping me figure out RomFS
* **b1l1s** for helping me figure out A9LH compatibility
* **Gelex** and **AuroraWright** for helping me figure out various things
* **dark_samus** for the new 6x10 font and help on various things
* **Al3x_10m**, **Supster131** and all other fearless testers
* **Al3x_10m**, **Supster131**, **imanoob**, **Kasher_CS** and all other fearless testers
* The fine folks on **freenode #Cakey**
* Everyone I possibly forgot, if you think you deserve to be mentioned, just contact me!

View File

@ -38,7 +38,7 @@
(((v) % (a)) ? ((v) + (a) - ((v) % (a))) : (v))
// GodMode9 version
#define VERSION "0.8.4"
#define VERSION "0.8.5"
// input / output paths
#define INPUT_PATHS "0:", "0:/files9", "0:/Decrypt9"

View File

@ -5,6 +5,8 @@
u32 IdentifyFileType(const char* path) {
u8 header[0x200] __attribute__((aligned(32))); // minimum required size
const u8 romfs_magic[] = { ROMFS_MAGIC };
FIL file;
if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK)
return 0;
@ -46,6 +48,10 @@ u32 IdentifyFileType(const char* path) {
NcchHeader* ncch = (NcchHeader*) (void*) header;
if (fsize >= (ncch->size * NCCH_MEDIA_UNIT))
return GAME_NCCH; // NCSD (".3DS") file
} else if (ValidateExeFsHeader((ExeFsHeader*) (void*) header, fsize) == 0) {
return GAME_EXEFS; // ExeFS file
} else if (memcmp(header, romfs_magic, sizeof(romfs_magic)) == 0) {
return GAME_ROMFS; // RomFS file (check could be better)
} else if (strncmp(CIA_TMD_ISSUER, (char*) (header + 0x140), 0x40) == 0) {
if (fsize >= CIA_TMD_SIZE_N(getbe16(header + 0x1DE)))
return GAME_TMD; // TMD file

View File

@ -9,10 +9,10 @@
#define GAME_NCSD (1<<3)
#define GAME_NCCH (1<<4)
#define GAME_TMD (1<<5)
// #define GAME_EXEFS (1<<6)
// #define GAME_ROMFS (1<<7)
#define GAME_EXEFS (1<<6)
#define GAME_ROMFS (1<<7)
#define FTYPE_MOUNTABLE (IMG_FAT|IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH)
#define FTYPE_MOUNTABLE (IMG_FAT|IMG_NAND|GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_EXEFS|GAME_ROMFS)
#define FYTPE_VERIFICABLE (GAME_CIA|GAME_NCSD|GAME_NCCH|GAME_TMD)
u32 IdentifyFileType(const char* path);

View File

@ -1187,9 +1187,11 @@ bool GetRootDirContentsWorker(DirStruct* contents) {
(GetMountState() == IMG_FAT) ? "FAT IMAGE" : "RAMDRIVE");
else if (pdrv == 10) // Game drive special handling
snprintf(entry->path + 4, 32, "[%s] %s %s", drvnum[pdrv],
(GetMountState() == GAME_CIA) ? "CIA" :
(GetMountState() == GAME_NCSD) ? "NCSD" :
(GetMountState() == GAME_NCCH) ? "NCCH" : "UNK", drvname[pdrv]);
(GetMountState() == GAME_CIA ) ? "CIA" :
(GetMountState() == GAME_NCSD ) ? "NCSD" :
(GetMountState() == GAME_NCCH ) ? "NCCH" :
(GetMountState() == GAME_EXEFS) ? "EXEFS" :
(GetMountState() == GAME_ROMFS) ? "ROMFS" : "UNK", drvname[pdrv]);
else snprintf(entry->path + 4, 32, "[%s] %s", drvnum[pdrv], drvname[pdrv]);
entry->name = entry->path + 4;
entry->size = GetTotalSpace(entry->path);

View File

@ -1,16 +1,19 @@
#include "exefs.h"
u32 ValidateExeFsHeader(ExeFsHeader* exefs, u32 size) {
u8 zeroes[32] = { 0 };
u32 data_size = 0;
u32 n_files = 0;
for (u32 i = 0; i < 10; i++) {
ExeFsFileHeader* file = exefs->files + i;
if ((file->offset == 0) && (file->size == 0))
continue;
if (file->offset < data_size)
return 1; // overlapping data, failed
u8* hash = exefs->hashes[9 - i];
if (file->size == 0) continue;
if (file->offset < data_size) return 1; // overlapping data, failed
if (memcmp(hash, zeroes, 32) == 0) return 1; // hash not set, failed
data_size = file->offset + file->size;
n_files++;
}
if (size && (data_size > (size - sizeof(ExeFsHeader)))) // exefs header not included in table
return 1;
return 0;
return (n_files) ? 0 : 1;
}

View File

@ -692,11 +692,13 @@ u32 GodMode() {
if (verificable > 0) optionstr[verificable-1] = "Verify game image";
if (injectable > 0) optionstr[injectable-1] = "Inject data @offset";
if (mountable > 0) optionstr[mountable-1] =
(filetype == IMG_NAND) ? "Mount as NAND image" :
(filetype == IMG_FAT) ? "Mount as FAT image" :
(filetype == GAME_CIA) ? "Mount as CIA image" :
(filetype == GAME_NCSD) ? "Mount as NCSD image" :
(filetype == GAME_NCCH) ? "Mount as NCCH image" : "???";
(filetype == IMG_NAND ) ? "Mount as NAND image" :
(filetype == IMG_FAT ) ? "Mount as FAT image" :
(filetype == GAME_CIA ) ? "Mount as CIA image" :
(filetype == GAME_NCSD ) ? "Mount as NCSD image" :
(filetype == GAME_NCCH ) ? "Mount as NCCH image" :
(filetype == GAME_EXEFS) ? "Mount as EXEFS image" :
(filetype == GAME_ROMFS) ? "Mount as ROMFS image" : "???";
if (searchdrv > 0) optionstr[searchdrv-1] = "Open containing folder";
int user_select = 0;

View File

@ -78,7 +78,8 @@ bool BuildVGameExeFsDir(void) {
snprintf(templates[n].name, 32, "%.8s", file->name);
templates[n].offset = offset_exefs + sizeof(ExeFsHeader) + file->offset;
templates[n].size = file->size;
templates[n].keyslot = NCCH_ENCRYPTED(ncch) ? 0x2C : 0xFF; // actual keyslot may be different
templates[n].keyslot = ((offset_ncch != (u64) -1) && NCCH_ENCRYPTED(ncch)) ?
0x2C : 0xFF; // actual keyslot may be different
templates[n].flags = VFLAG_EXEFS_FILE;
n++;
}
@ -335,7 +336,12 @@ u32 InitVGameDrive(void) { // prerequisite: game file mounted as image
offset_lv3 = (u64) -1;
offset_lv3fd = (u64) -1;
base_vdir = (type == GAME_CIA) ? VFLAG_CIA : (type == GAME_NCSD) ? VFLAG_NCSD : (type == GAME_NCCH) ? VFLAG_NCCH : 0;
base_vdir =
(type == GAME_CIA ) ? VFLAG_CIA :
(type == GAME_NCSD ) ? VFLAG_NCSD :
(type == GAME_NCCH ) ? VFLAG_NCCH :
(type == GAME_EXEFS) ? VFLAG_EXEFS :
(type == GAME_ROMFS) ? VFLAG_ROMFS : 0;
if (!base_vdir) return 0;
vgame_type = type;
@ -446,7 +452,8 @@ bool OpenVGameDir(VirtualDir* vdir, VirtualFile* ventry) {
bool ReadVGameDirLv3(VirtualFile* vfile, VirtualDir* vdir) {
BuildLv3Index(&lv3idx, romfslv3);
vfile->flags = VFLAG_LV3;
vfile->keyslot = NCCH_ENCRYPTED(ncch) ? 0x2C : 0xFF; // actual keyslot may be different
vfile->keyslot = ((offset_ncch != (u64) -1) && NCCH_ENCRYPTED(ncch)) ?
0x2C : 0xFF; // actual keyslot may be different
// start from parent dir object
if (vdir->index == -1) vdir->index = 0;
@ -551,7 +558,7 @@ int ReadVGameFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count) {
lv3file = LV3_GET_FILE(vfile->offset, &lv3idx);
vfoffset = offset_lv3fd + lv3file->offset_data;
}
if (NCCH_ENCRYPTED(ncch) && (vfile->keyslot < 0x40) &&
if ((vfile->keyslot < 0x40) && (offset_ncch != (u64) -1) && NCCH_ENCRYPTED(ncch) &&
(vfile->flags & (VFLAG_EXEFS_FILE|VFLAG_EXTHDR|VFLAG_EXEFS|VFLAG_ROMFS|VFLAG_LV3|VFLAG_NCCH)))
return ReadNcchImageBytes(buffer, vfoffset + offset, count);
else return ReadImageBytes(buffer, vfoffset + offset, count);
@ -560,7 +567,8 @@ int ReadVGameFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count) {
bool FindVirtualFileInLv3Dir(VirtualFile* vfile, const VirtualDir* vdir, const char* name) {
vfile->name[0] = '\0';
vfile->flags = vdir->flags & ~VFLAG_DIR;
vfile->keyslot = NCCH_ENCRYPTED(ncch) ? 0x2C : 0xFF; // actual keyslot may be different
vfile->keyslot = ((offset_ncch != (u64) -1) && NCCH_ENCRYPTED(ncch)) ?
0x2C : 0xFF; // actual keyslot may be different
RomFsLv3DirMeta* lv3dir = GetLv3DirMeta(name, vdir->offset, &lv3idx);
if (lv3dir) {