From 2c5a46522d7b23fb4dd1433b4d3e3764cf7e787c Mon Sep 17 00:00:00 2001 From: d0k3 Date: Sat, 26 Nov 2016 14:25:10 +0100 Subject: [PATCH] Handle Virtual Game Drive via image.h --- source/fatfs/diskio.c | 4 +++- source/fatfs/image.c | 40 ++++++++++++++++++------------- source/fatfs/image.h | 2 ++ source/fs.c | 15 ++++++++---- source/game/cia.h | 1 + source/godmode.c | 21 ++++------------- source/virtual/vgame.c | 53 ++++++++++++++++++------------------------ source/virtual/vgame.h | 2 +- 8 files changed, 68 insertions(+), 70 deletions(-) diff --git a/source/fatfs/diskio.c b/source/fatfs/diskio.c index 89472b3..b681256 100644 --- a/source/fatfs/diskio.c +++ b/source/fatfs/diskio.c @@ -139,7 +139,9 @@ DSTATUS disk_initialize ( nand_type_emu = CheckNandType(NAND_EMUNAND); if (!nand_type_emu) return STA_NOINIT|STA_NODISK; } else if (pdrv < 10) { - if (!GetMountState()) return STA_NOINIT|STA_NODISK; + UINT mount_state = GetMountState(); + if ((mount_state != IMG_NAND) && (mount_state != IMG_FAT) && (mount_state != IMG_RAMDRV)) + return STA_NOINIT|STA_NODISK; nand_type_img = CheckNandType(NAND_IMGNAND); if ((!nand_type_img) && (pdrv != 7)) return STA_NOINIT|STA_NODISK; } diff --git a/source/fatfs/image.c b/source/fatfs/image.c index 614b544..2a17a22 100644 --- a/source/fatfs/image.c +++ b/source/fatfs/image.c @@ -8,38 +8,47 @@ static u32 ramdrv_size = 0; static FIL mount_file; static u32 mount_state = 0; -int ReadImageSectors(u8* buffer, u32 sector, u32 count) { + +int ReadImageBytes(u8* buffer, u32 offset, u32 count) { UINT bytes_read; UINT ret; if (!count) return -1; if (mount_state == IMG_RAMDRV) { - if ((sector + count) * 0x200 > ramdrv_size) return -1; - memcpy(buffer, ramdrv_buffer + (sector * 0x200), count * 0x200); + if ((offset + count) > ramdrv_size) return -1; + memcpy(buffer, ramdrv_buffer + (offset), count); return 0; } if (!mount_state) return FR_INVALID_OBJECT; - if (f_tell(&mount_file) != sector * 0x200) { - if (f_size(&mount_file) < sector * 0x200) return -1; - f_lseek(&mount_file, sector * 0x200); + if (f_tell(&mount_file) != offset) { + if (f_size(&mount_file) < offset) return -1; + f_lseek(&mount_file, offset); } - ret = f_read(&mount_file, buffer, count * 0x200, &bytes_read); - return (ret != 0) ? (int) ret : (bytes_read != count * 0x200) ? -1 : 0; + ret = f_read(&mount_file, buffer, count, &bytes_read); + return (ret != 0) ? (int) ret : (bytes_read != count) ? -1 : 0; } -int WriteImageSectors(const u8* buffer, u32 sector, u32 count) { +int WriteImageBytes(const u8* buffer, u32 offset, u32 count) { UINT bytes_written; UINT ret; if (!count) return -1; if (mount_state == IMG_RAMDRV) { - if ((sector + count) * 0x200 > ramdrv_size) return -1; - memcpy(ramdrv_buffer + (sector * 0x200), buffer, count * 0x200); + if ((offset + count) > ramdrv_size) return -1; + memcpy(ramdrv_buffer + (offset), buffer, count); return 0; } if (!mount_state) return FR_INVALID_OBJECT; - if (f_tell(&mount_file) != sector * 0x200) - f_lseek(&mount_file, sector * 0x200); - ret = f_write(&mount_file, buffer, count * 0x200, &bytes_written); - return (ret != 0) ? (int) ret : (bytes_written != count * 0x200) ? -1 : 0; + if (f_tell(&mount_file) != offset) + f_lseek(&mount_file, offset); + ret = f_write(&mount_file, buffer, count, &bytes_written); + return (ret != 0) ? (int) ret : (bytes_written != count) ? -1 : 0; +} + +int ReadImageSectors(u8* buffer, u32 sector, u32 count) { + return ReadImageBytes(buffer, sector * 0x200, count * 0x200); +} + +int WriteImageSectors(const u8* buffer, u32 sector, u32 count) { + return WriteImageBytes(buffer, sector * 0x200, count * 0x200); } int SyncImage(void) { @@ -76,7 +85,6 @@ u32 MountImage(const char* path) { mount_state = 0; } if (!path || !type) return 0; - if ((type != IMG_FAT) && (type != IMG_NAND)) return 0; if (f_open(&mount_file, path, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK) return 0; f_lseek(&mount_file, 0); diff --git a/source/fatfs/image.h b/source/fatfs/image.h index b6e1472..0154edb 100644 --- a/source/fatfs/image.h +++ b/source/fatfs/image.h @@ -5,6 +5,8 @@ #define IMG_RAMDRV 100 // just so there are no conflicts with file type defines +int ReadImageBytes(u8* buffer, u32 offset, u32 count); +int WriteImageBytes(const u8* buffer, u32 offset, u32 count); int ReadImageSectors(u8* buffer, u32 sector, u32 count); int WriteImageSectors(const u8* buffer, u32 sector, u32 count); int SyncImage(void); diff --git a/source/fs.c b/source/fs.c index b9528cc..a2e6c89 100644 --- a/source/fs.c +++ b/source/fs.c @@ -66,13 +66,18 @@ void DeinitExtFS() { f_mount(NULL, fsname, 1); fs_mounted[i] = false; } + if ((i == 7) && (GetMountState() != IMG_RAMDRV)) { // unmount image + MountImage(NULL); + InitVGameDrive(); + } } } void DeinitSDCardFS() { - if (GetMountState() != IMG_RAMDRV) + if (GetMountState() != IMG_RAMDRV) { MountImage(NULL); - MountVGameFile(NULL); + InitVGameDrive(); + } if (fs_mounted[0]) { f_mount(NULL, "0:", 1); fs_mounted[0] = false; @@ -138,7 +143,7 @@ int DriveType(const char* path) { } else if (vsrc == VRT_MEMORY) { type = DRV_VIRTUAL | DRV_MEMORY; } else if (vsrc == VRT_GAME) { - type = DRV_VIRTUAL | DRV_GAME; + type = DRV_VIRTUAL | DRV_GAME | DRV_IMAGE; } } else if (CheckAliasDrive(path)) { type = DRV_FAT | DRV_ALIAS; @@ -1015,14 +1020,14 @@ bool GetRootDirContentsWorker(DirStruct* contents) { "SYSNAND CTRNAND", "SYSNAND TWLN", "SYSNAND TWLP", "EMUNAND CTRNAND", "EMUNAND TWLN", "EMUNAND TWLP", "IMGNAND CTRNAND", "IMGNAND TWLN", "IMGNAND TWLP", - "SYSNAND SD", "EMUNAND SD", "GAME IMAGE", + "SYSNAND SD", "EMUNAND SD", "SYSNAND VIRTUAL", "EMUNAND VIRTUAL", "IMGNAND VIRTUAL", "MEMORY VIRTUAL", "LAST SEARCH" }; static const char* drvnum[] = { - "0:", "1:", "2:", "3:", "4:", "5:", "6:", "7:", "8:", "9:", "A:", "B:", "G:", "S:", "E:", "I:", "M:", "Z:" + "0:", "1:", "2:", "3:", "4:", "5:", "6:", "7:", "8:", "9:", "G:", "A:", "B:", "S:", "E:", "I:", "M:", "Z:" }; u32 n_entries = 0; diff --git a/source/game/cia.h b/source/game/cia.h index e5bf497..b83f2b4 100644 --- a/source/game/cia.h +++ b/source/game/cia.h @@ -108,6 +108,7 @@ typedef struct { CiaHeader header; u8 header_padding[0x40 - (CIA_HEADER_SIZE % 0x40)]; u8 cert[CIA_CERT_SIZE]; + // cert is aligned and needs no padding Ticket ticket; u8 ticket_padding[0x40 - (CIA_TICKET_SIZE % 0x40)]; TitleMetaData tmd; diff --git a/source/godmode.c b/source/godmode.c index e09c91a..7fa4e12 100644 --- a/source/godmode.c +++ b/source/godmode.c @@ -686,29 +686,18 @@ u32 GodMode() { ShowPrompt(false, "Failed injecting %s", origstr); clipboard->n_entries = 0; } - } else if (((int) user_select == mountable) && // -> mount as NAND / FAT image - ((file_type == IMG_NAND) || (file_type == IMG_FAT))) { + } else if ((int) user_select == mountable) { // -> mount file as image if (clipboard->n_entries && (DriveType(clipboard->entry[0].path) & DRV_IMAGE)) clipboard->n_entries = 0; // remove last mounted image clipboard entries DeinitExtFS(); u32 mount_state = MountImage(curr_entry->path); InitExtFS(); - if (!mount_state || !(DriveType("7:")||DriveType("8:")||DriveType("9:"))) { + InitVGameDrive(); + if (!mount_state || !(DriveType("7:")||DriveType("8:")||DriveType("9:")||DriveType("G:"))) { ShowPrompt(false, "Mounting image: failed"); DeinitExtFS(); - MountImage(NULL); InitExtFS(); - } else { - *current_path = '\0'; - GetDirContents(current_dir, current_path); - cursor = 0; - } - } else if ((int) user_select == mountable) { // -> mount as game image - if (clipboard->n_entries && (DriveType(clipboard->entry[0].path) & DRV_GAME)) - clipboard->n_entries = 0; // remove last mounted game clipboard entries - if (!MountVGameFile(curr_entry->path)) { - ShowPrompt(false, "Mounting game: failed"); - MountVGameFile(NULL); + InitVGameDrive(); } else { *current_path = '\0'; GetDirContents(current_dir, current_path); @@ -808,9 +797,9 @@ u32 GodMode() { if (switched && (pad_state & BUTTON_X)) { // unmount image if (clipboard->n_entries && (DriveType(clipboard->entry[0].path) & DRV_IMAGE)) clipboard->n_entries = 0; // remove last mounted image clipboard entries - DeinitExtFS(); if (!GetMountState()) MountRamDrive(); else MountImage(NULL); + DeinitExtFS(); InitExtFS(); GetDirContents(current_dir, current_path); } else if (switched && (pad_state & BUTTON_Y)) { diff --git a/source/virtual/vgame.c b/source/virtual/vgame.c index 52d9fbe..7278643 100644 --- a/source/virtual/vgame.c +++ b/source/virtual/vgame.c @@ -1,4 +1,5 @@ #include "vgame.h" +#include "image.h" #include "game.h" #include "aes.h" #include "ff.h" @@ -13,41 +14,38 @@ #define NAME_CIA_META "meta.bin" #define NAME_CIA_CONTENT "%04X.%08lX.app" // index.id.app -static FIL mount_file; -static u32 mount_state = 0; - +static u32 vgame_type = 0; static VirtualFile* templates = (VirtualFile*) VGAME_BUFFER; // first 128kb reserved static int n_templates = -1; static CiaStub* cia = (CiaStub*) (VGAME_BUFFER + 0xF4000); // 48kB reserved - should be enough by far -static u8 titlekey[16]; -u32 MountVGameFile(const char* path) { - u32 type = IdentifyFileType(path); - if (mount_state) { - f_close(&mount_file); - mount_state = 0; - } - if (!path || !type) return 0; +u32 InitVGameDrive(void) { // prerequisite: game file mounted as image + u32 type = GetMountState(); + vgame_type = 0; if (type == GAME_CIA) { // for CIAs: load the CIA stub and keep it in memory - LoadCiaStub(cia, path); - GetTitleKey(titlekey, &(cia->ticket)); - } else return 0; // NCSD / NCCH handling still required - if (f_open(&mount_file, path, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK) - return false; - f_lseek(&mount_file, false); - f_sync(&mount_file); - return (mount_state = type); + CiaInfo info; + if ((ReadImageBytes((u8*) cia, 0, 0x20) != 0) || + (ValidateCiaHeader(&(cia->header)) != 0) || + (GetCiaInfo(&info, &(cia->header)) != 0) || + (ReadImageBytes((u8*) cia, 0, info.offset_content) != 0)) + return 0; + } else if ((type == GAME_NCCH) || (type == GAME_NCSD)) { + } else return 0; // not a mounted game file + + vgame_type = type; + return type; } u32 CheckVGameDrive(void) { - return mount_state; + if (vgame_type != GetMountState()) vgame_type = 0; // very basic sanity check + return vgame_type; } bool BuildVGameCiaVDir(void) { CiaInfo info; - if ((mount_state != GAME_CIA) || (GetCiaInfo(&info, &(cia->header)) != 0)) + if ((CheckVGameDrive() != GAME_CIA) || (GetCiaInfo(&info, &(cia->header)) != 0)) return false; // safety check // header @@ -153,16 +151,9 @@ bool ReadVGameDir(VirtualFile* vfile, const char* path) { } int ReadVGameFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count) { - UINT bytes_read; - UINT ret; u32 vfoffset = vfile->offset; - if (!count) return -1; - if (!mount_state) return FR_INVALID_OBJECT; - if (f_tell(&mount_file) != vfoffset + offset) { - if (f_size(&mount_file) < vfoffset + offset) return -1; - f_lseek(&mount_file, vfoffset + offset); - } - ret = f_read(&mount_file, buffer, count, &bytes_read); + int ret = ReadImageBytes(buffer, vfoffset + offset, count); + if (ret != 0) return ret; /*if ((ret != 0) && (vfile->keyslot <= 0x40)) { // crypto // relies on first template being the header and everything aligned to AES_BLOCK_SIZE u32 offset_base = 0; // vfoffset - (*templates).offset; @@ -174,5 +165,5 @@ int ReadVGameFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count) { ctr_decrypt_boffset(buffer, buffer, bytes_read, offset - offset_base, AES_CNT_TITLEKEY_DECRYPT_MODE, ctr); }*/ - return (ret != 0) ? (int) ret : (bytes_read != count) ? -1 : 0; + return 0; } diff --git a/source/virtual/vgame.h b/source/virtual/vgame.h index 80b5cd3..dce6fcd 100644 --- a/source/virtual/vgame.h +++ b/source/virtual/vgame.h @@ -4,7 +4,7 @@ #include "filetype.h" #include "virtual.h" -u32 MountVGameFile(const char* path); +u32 InitVGameDrive(void); u32 CheckVGameDrive(void); bool ReadVGameDir(VirtualFile* vfile, const char* path);