forked from Mirror/GodMode9
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);
|
||||
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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
15
source/fs.c
15
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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user