Handle Virtual Game Drive via image.h

This commit is contained in:
d0k3 2016-11-26 14:25:10 +01:00
parent 9d42c04271
commit 2c5a46522d
8 changed files with 68 additions and 70 deletions

View File

@ -139,7 +139,9 @@ DSTATUS disk_initialize (
nand_type_emu = CheckNandType(NAND_EMUNAND); nand_type_emu = CheckNandType(NAND_EMUNAND);
if (!nand_type_emu) return STA_NOINIT|STA_NODISK; if (!nand_type_emu) return STA_NOINIT|STA_NODISK;
} else if (pdrv < 10) { } 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); nand_type_img = CheckNandType(NAND_IMGNAND);
if ((!nand_type_img) && (pdrv != 7)) return STA_NOINIT|STA_NODISK; if ((!nand_type_img) && (pdrv != 7)) return STA_NOINIT|STA_NODISK;
} }

View File

@ -8,38 +8,47 @@ static u32 ramdrv_size = 0;
static FIL mount_file; static FIL mount_file;
static u32 mount_state = 0; 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 bytes_read;
UINT ret; UINT ret;
if (!count) return -1; if (!count) return -1;
if (mount_state == IMG_RAMDRV) { if (mount_state == IMG_RAMDRV) {
if ((sector + count) * 0x200 > ramdrv_size) return -1; if ((offset + count) > ramdrv_size) return -1;
memcpy(buffer, ramdrv_buffer + (sector * 0x200), count * 0x200); memcpy(buffer, ramdrv_buffer + (offset), count);
return 0; return 0;
} }
if (!mount_state) return FR_INVALID_OBJECT; if (!mount_state) return FR_INVALID_OBJECT;
if (f_tell(&mount_file) != sector * 0x200) { if (f_tell(&mount_file) != offset) {
if (f_size(&mount_file) < sector * 0x200) return -1; if (f_size(&mount_file) < offset) return -1;
f_lseek(&mount_file, sector * 0x200); f_lseek(&mount_file, offset);
} }
ret = f_read(&mount_file, buffer, count * 0x200, &bytes_read); ret = f_read(&mount_file, buffer, count, &bytes_read);
return (ret != 0) ? (int) ret : (bytes_read != count * 0x200) ? -1 : 0; 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 bytes_written;
UINT ret; UINT ret;
if (!count) return -1; if (!count) return -1;
if (mount_state == IMG_RAMDRV) { if (mount_state == IMG_RAMDRV) {
if ((sector + count) * 0x200 > ramdrv_size) return -1; if ((offset + count) > ramdrv_size) return -1;
memcpy(ramdrv_buffer + (sector * 0x200), buffer, count * 0x200); memcpy(ramdrv_buffer + (offset), buffer, count);
return 0; return 0;
} }
if (!mount_state) return FR_INVALID_OBJECT; if (!mount_state) return FR_INVALID_OBJECT;
if (f_tell(&mount_file) != sector * 0x200) if (f_tell(&mount_file) != offset)
f_lseek(&mount_file, sector * 0x200); f_lseek(&mount_file, offset);
ret = f_write(&mount_file, buffer, count * 0x200, &bytes_written); ret = f_write(&mount_file, buffer, count, &bytes_written);
return (ret != 0) ? (int) ret : (bytes_written != count * 0x200) ? -1 : 0; 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) { int SyncImage(void) {
@ -76,7 +85,6 @@ u32 MountImage(const char* path) {
mount_state = 0; mount_state = 0;
} }
if (!path || !type) return 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) if (f_open(&mount_file, path, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK)
return 0; return 0;
f_lseek(&mount_file, 0); f_lseek(&mount_file, 0);

View File

@ -5,6 +5,8 @@
#define IMG_RAMDRV 100 // just so there are no conflicts with file type defines #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 ReadImageSectors(u8* buffer, u32 sector, u32 count);
int WriteImageSectors(const u8* buffer, u32 sector, u32 count); int WriteImageSectors(const u8* buffer, u32 sector, u32 count);
int SyncImage(void); int SyncImage(void);

View File

@ -66,13 +66,18 @@ void DeinitExtFS() {
f_mount(NULL, fsname, 1); f_mount(NULL, fsname, 1);
fs_mounted[i] = false; fs_mounted[i] = false;
} }
if ((i == 7) && (GetMountState() != IMG_RAMDRV)) { // unmount image
MountImage(NULL);
InitVGameDrive();
}
} }
} }
void DeinitSDCardFS() { void DeinitSDCardFS() {
if (GetMountState() != IMG_RAMDRV) if (GetMountState() != IMG_RAMDRV) {
MountImage(NULL); MountImage(NULL);
MountVGameFile(NULL); InitVGameDrive();
}
if (fs_mounted[0]) { if (fs_mounted[0]) {
f_mount(NULL, "0:", 1); f_mount(NULL, "0:", 1);
fs_mounted[0] = false; fs_mounted[0] = false;
@ -138,7 +143,7 @@ int DriveType(const char* path) {
} else if (vsrc == VRT_MEMORY) { } else if (vsrc == VRT_MEMORY) {
type = DRV_VIRTUAL | DRV_MEMORY; type = DRV_VIRTUAL | DRV_MEMORY;
} else if (vsrc == VRT_GAME) { } else if (vsrc == VRT_GAME) {
type = DRV_VIRTUAL | DRV_GAME; type = DRV_VIRTUAL | DRV_GAME | DRV_IMAGE;
} }
} else if (CheckAliasDrive(path)) { } else if (CheckAliasDrive(path)) {
type = DRV_FAT | DRV_ALIAS; type = DRV_FAT | DRV_ALIAS;
@ -1015,14 +1020,14 @@ bool GetRootDirContentsWorker(DirStruct* contents) {
"SYSNAND CTRNAND", "SYSNAND TWLN", "SYSNAND TWLP", "SYSNAND CTRNAND", "SYSNAND TWLN", "SYSNAND TWLP",
"EMUNAND CTRNAND", "EMUNAND TWLN", "EMUNAND TWLP", "EMUNAND CTRNAND", "EMUNAND TWLN", "EMUNAND TWLP",
"IMGNAND CTRNAND", "IMGNAND TWLN", "IMGNAND TWLP", "IMGNAND CTRNAND", "IMGNAND TWLN", "IMGNAND TWLP",
"SYSNAND SD", "EMUNAND SD",
"GAME IMAGE", "GAME IMAGE",
"SYSNAND SD", "EMUNAND SD",
"SYSNAND VIRTUAL", "EMUNAND VIRTUAL", "IMGNAND VIRTUAL", "SYSNAND VIRTUAL", "EMUNAND VIRTUAL", "IMGNAND VIRTUAL",
"MEMORY VIRTUAL", "MEMORY VIRTUAL",
"LAST SEARCH" "LAST SEARCH"
}; };
static const char* drvnum[] = { 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; u32 n_entries = 0;

View File

@ -108,6 +108,7 @@ typedef struct {
CiaHeader header; CiaHeader header;
u8 header_padding[0x40 - (CIA_HEADER_SIZE % 0x40)]; u8 header_padding[0x40 - (CIA_HEADER_SIZE % 0x40)];
u8 cert[CIA_CERT_SIZE]; u8 cert[CIA_CERT_SIZE];
// cert is aligned and needs no padding
Ticket ticket; Ticket ticket;
u8 ticket_padding[0x40 - (CIA_TICKET_SIZE % 0x40)]; u8 ticket_padding[0x40 - (CIA_TICKET_SIZE % 0x40)];
TitleMetaData tmd; TitleMetaData tmd;

View File

@ -686,29 +686,18 @@ u32 GodMode() {
ShowPrompt(false, "Failed injecting %s", origstr); ShowPrompt(false, "Failed injecting %s", origstr);
clipboard->n_entries = 0; clipboard->n_entries = 0;
} }
} else if (((int) user_select == mountable) && // -> mount as NAND / FAT image } else if ((int) user_select == mountable) { // -> mount file as image
((file_type == IMG_NAND) || (file_type == IMG_FAT))) {
if (clipboard->n_entries && (DriveType(clipboard->entry[0].path) & DRV_IMAGE)) if (clipboard->n_entries && (DriveType(clipboard->entry[0].path) & DRV_IMAGE))
clipboard->n_entries = 0; // remove last mounted image clipboard entries clipboard->n_entries = 0; // remove last mounted image clipboard entries
DeinitExtFS(); DeinitExtFS();
u32 mount_state = MountImage(curr_entry->path); u32 mount_state = MountImage(curr_entry->path);
InitExtFS(); 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"); ShowPrompt(false, "Mounting image: failed");
DeinitExtFS(); DeinitExtFS();
MountImage(NULL);
InitExtFS(); InitExtFS();
} else { InitVGameDrive();
*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);
} else { } else {
*current_path = '\0'; *current_path = '\0';
GetDirContents(current_dir, current_path); GetDirContents(current_dir, current_path);
@ -808,9 +797,9 @@ u32 GodMode() {
if (switched && (pad_state & BUTTON_X)) { // unmount image if (switched && (pad_state & BUTTON_X)) { // unmount image
if (clipboard->n_entries && (DriveType(clipboard->entry[0].path) & DRV_IMAGE)) if (clipboard->n_entries && (DriveType(clipboard->entry[0].path) & DRV_IMAGE))
clipboard->n_entries = 0; // remove last mounted image clipboard entries clipboard->n_entries = 0; // remove last mounted image clipboard entries
DeinitExtFS();
if (!GetMountState()) MountRamDrive(); if (!GetMountState()) MountRamDrive();
else MountImage(NULL); else MountImage(NULL);
DeinitExtFS();
InitExtFS(); InitExtFS();
GetDirContents(current_dir, current_path); GetDirContents(current_dir, current_path);
} else if (switched && (pad_state & BUTTON_Y)) { } else if (switched && (pad_state & BUTTON_Y)) {

View File

@ -1,4 +1,5 @@
#include "vgame.h" #include "vgame.h"
#include "image.h"
#include "game.h" #include "game.h"
#include "aes.h" #include "aes.h"
#include "ff.h" #include "ff.h"
@ -13,41 +14,38 @@
#define NAME_CIA_META "meta.bin" #define NAME_CIA_META "meta.bin"
#define NAME_CIA_CONTENT "%04X.%08lX.app" // index.id.app #define NAME_CIA_CONTENT "%04X.%08lX.app" // index.id.app
static FIL mount_file; static u32 vgame_type = 0;
static u32 mount_state = 0;
static VirtualFile* templates = (VirtualFile*) VGAME_BUFFER; // first 128kb reserved static VirtualFile* templates = (VirtualFile*) VGAME_BUFFER; // first 128kb reserved
static int n_templates = -1; static int n_templates = -1;
static CiaStub* cia = (CiaStub*) (VGAME_BUFFER + 0xF4000); // 48kB reserved - should be enough by far static CiaStub* cia = (CiaStub*) (VGAME_BUFFER + 0xF4000); // 48kB reserved - should be enough by far
static u8 titlekey[16];
u32 MountVGameFile(const char* path) { u32 InitVGameDrive(void) { // prerequisite: game file mounted as image
u32 type = IdentifyFileType(path); u32 type = GetMountState();
if (mount_state) { vgame_type = 0;
f_close(&mount_file);
mount_state = 0;
}
if (!path || !type) return 0;
if (type == GAME_CIA) { // for CIAs: load the CIA stub and keep it in memory if (type == GAME_CIA) { // for CIAs: load the CIA stub and keep it in memory
LoadCiaStub(cia, path); CiaInfo info;
GetTitleKey(titlekey, &(cia->ticket)); if ((ReadImageBytes((u8*) cia, 0, 0x20) != 0) ||
} else return 0; // NCSD / NCCH handling still required (ValidateCiaHeader(&(cia->header)) != 0) ||
if (f_open(&mount_file, path, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK) (GetCiaInfo(&info, &(cia->header)) != 0) ||
return false; (ReadImageBytes((u8*) cia, 0, info.offset_content) != 0))
f_lseek(&mount_file, false); return 0;
f_sync(&mount_file); } else if ((type == GAME_NCCH) || (type == GAME_NCSD)) {
return (mount_state = type); } else return 0; // not a mounted game file
vgame_type = type;
return type;
} }
u32 CheckVGameDrive(void) { u32 CheckVGameDrive(void) {
return mount_state; if (vgame_type != GetMountState()) vgame_type = 0; // very basic sanity check
return vgame_type;
} }
bool BuildVGameCiaVDir(void) { bool BuildVGameCiaVDir(void) {
CiaInfo info; 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 return false; // safety check
// header // header
@ -153,16 +151,9 @@ bool ReadVGameDir(VirtualFile* vfile, const char* path) {
} }
int ReadVGameFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count) { int ReadVGameFile(const VirtualFile* vfile, u8* buffer, u32 offset, u32 count) {
UINT bytes_read;
UINT ret;
u32 vfoffset = vfile->offset; u32 vfoffset = vfile->offset;
if (!count) return -1; int ret = ReadImageBytes(buffer, vfoffset + offset, count);
if (!mount_state) return FR_INVALID_OBJECT; if (ret != 0) return ret;
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);
/*if ((ret != 0) && (vfile->keyslot <= 0x40)) { // crypto /*if ((ret != 0) && (vfile->keyslot <= 0x40)) { // crypto
// relies on first template being the header and everything aligned to AES_BLOCK_SIZE // relies on first template being the header and everything aligned to AES_BLOCK_SIZE
u32 offset_base = 0; // vfoffset - (*templates).offset; 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, ctr_decrypt_boffset(buffer, buffer, bytes_read, offset - offset_base,
AES_CNT_TITLEKEY_DECRYPT_MODE, ctr); AES_CNT_TITLEKEY_DECRYPT_MODE, ctr);
}*/ }*/
return (ret != 0) ? (int) ret : (bytes_read != count) ? -1 : 0; return 0;
} }

View File

@ -4,7 +4,7 @@
#include "filetype.h" #include "filetype.h"
#include "virtual.h" #include "virtual.h"
u32 MountVGameFile(const char* path); u32 InitVGameDrive(void);
u32 CheckVGameDrive(void); u32 CheckVGameDrive(void);
bool ReadVGameDir(VirtualFile* vfile, const char* path); bool ReadVGameDir(VirtualFile* vfile, const char* path);