mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 13:42:47 +00:00
Handle Virtual Game Drive via image.h
This commit is contained in:
parent
9d42c04271
commit
2c5a46522d
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
15
source/fs.c
15
source/fs.c
@ -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;
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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)) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user