mirror of
https://github.com/d0k3/GodMode9.git
synced 2025-06-26 05:32:47 +00:00
implement virtual mounting of BDRI files
This commit is contained in:
parent
2b94b585eb
commit
c70546d5ca
@ -46,13 +46,13 @@ int DriveType(const char* path) {
|
||||
type = DRV_VIRTUAL | DRV_SYSNAND;
|
||||
} else if (vsrc == VRT_EMUNAND) {
|
||||
type = DRV_VIRTUAL | DRV_EMUNAND;
|
||||
} else if ((vsrc == VRT_IMGNAND) || (vsrc == VRT_DISADIFF)) {
|
||||
} else if ((vsrc == VRT_IMGNAND) || (vsrc == VRT_DISADIFF) || (vsrc == VRT_BDRI)) {
|
||||
type = DRV_VIRTUAL | DRV_IMAGE;
|
||||
} else if (vsrc == VRT_XORPAD) {
|
||||
type = DRV_VIRTUAL | DRV_XORPAD;
|
||||
} else if (vsrc == VRT_MEMORY) {
|
||||
type = DRV_VIRTUAL | DRV_MEMORY;
|
||||
} else if ((vsrc == VRT_GAME) || (vsrc == VRT_KEYDB) || (vsrc == VRT_TICKDB)) {
|
||||
} else if ((vsrc == VRT_GAME) || (vsrc == VRT_KEYDB)) {
|
||||
type = DRV_VIRTUAL | DRV_GAME | DRV_IMAGE;
|
||||
} else if (vsrc == VRT_CART) {
|
||||
type = DRV_VIRTUAL | DRV_CART;
|
||||
|
@ -36,7 +36,7 @@
|
||||
"EMUNAND CTRNAND", "EMUNAND TWLN", "EMUNAND TWLP", "EMUNAND SD", "EMUNAND VIRTUAL", \
|
||||
"IMGNAND CTRNAND", "IMGNAND TWLN", "IMGNAND TWLP", "IMGNAND VIRTUAL", \
|
||||
"GAMECART", \
|
||||
"GAME IMAGE", "AESKEYDB IMAGE", "TICKET.DB IMAGE", "DISA/DIFF IMAGE", \
|
||||
"GAME IMAGE", "AESKEYDB IMAGE", "BDRI IMAGE", "DISA/DIFF IMAGE", \
|
||||
"MEMORY VIRTUAL", \
|
||||
"VRAM VIRTUAL", \
|
||||
"LAST SEARCH" \
|
||||
|
@ -689,7 +689,7 @@ bool PathMoveCopy(const char* dest, const char* orig, u32* flags, bool move) {
|
||||
bool force_unmount = false;
|
||||
|
||||
// handle NAND image unmounts
|
||||
if (ddrvtype & (DRV_SYSNAND|DRV_EMUNAND|DRV_IMAGE)) {
|
||||
if ((ddrvtype & (DRV_SYSNAND|DRV_EMUNAND|DRV_IMAGE)) && !(GetVirtualSource(dest) & (VRT_DISADIFF | VRT_BDRI))) {
|
||||
FILINFO fno;
|
||||
// virtual NAND files over 4 MB require unmount, totally arbitrary limit (hacky!)
|
||||
if ((fvx_stat(ldest, &fno) == FR_OK) && (fno.fsize > 4 * 1024 * 1024))
|
||||
@ -733,7 +733,7 @@ bool PathCopy(const char* destdir, const char* orig, u32* flags) {
|
||||
snprintf(dest, 255, "%s/%s", destdir, (++oname));
|
||||
|
||||
// virtual destination special handling
|
||||
if (GetVirtualSource(destdir)) {
|
||||
if (GetVirtualSource(destdir) & ~VRT_BDRI) {
|
||||
u64 osize = FileGetSize(orig);
|
||||
VirtualFile dvfile;
|
||||
if (!osize) return false;
|
||||
|
318
arm9/source/virtual/vbdri.c
Normal file
318
arm9/source/virtual/vbdri.c
Normal file
@ -0,0 +1,318 @@
|
||||
#include "vbdri.h"
|
||||
#include "image.h"
|
||||
#include "disadiff.h"
|
||||
#include "vdisadiff.h"
|
||||
#include "bdri.h"
|
||||
#include "vff.h"
|
||||
|
||||
#define VBDRI_MAX_ENTRIES 8192 // Completely arbitrary
|
||||
|
||||
#define VFLAG_UNKNOWN (1UL<<28)
|
||||
#define VFLAG_HOMEBREW (1UL<<29)
|
||||
#define VFLAG_ESHOP (1UL<<30)
|
||||
#define VFLAG_SYSTEM (1UL<<31)
|
||||
#define VFLAG_TICKDIR (VFLAG_UNKNOWN|VFLAG_HOMEBREW|VFLAG_ESHOP|VFLAG_SYSTEM)
|
||||
|
||||
#define NAME_TIE "%016llX"
|
||||
#define NAME_TIK "%016llX.%08lX.tik" // title id / console id
|
||||
|
||||
#define PART_PATH "D:/partitionA.bin"
|
||||
|
||||
|
||||
typedef struct {
|
||||
u8 type; // 0 for eshop, 1 for homebrew, 2 for system, 3 for unknown
|
||||
u32 size;
|
||||
u8 console_id[4];
|
||||
} PACKED_STRUCT TickInfoEntry;
|
||||
|
||||
// only for the main directory
|
||||
static const VirtualFile VTickDbFileTemplates[] = {
|
||||
{ "system" , 0x00000000, 0x00000000, 0xFF, VFLAG_DIR | VFLAG_SYSTEM },
|
||||
{ "homebrew", 0x00000000, 0x00000000, 0xFF, VFLAG_DIR | VFLAG_HOMEBREW },
|
||||
{ "eshop" , 0x00000000, 0x00000000, 0xFF, VFLAG_DIR | VFLAG_ESHOP },
|
||||
{ "unknown" , 0x00000000, 0x00000000, 0xFF, VFLAG_DIR | VFLAG_UNKNOWN },
|
||||
};
|
||||
|
||||
static bool is_tickdb;
|
||||
static u32 num_entries = 0;
|
||||
static u8* title_ids = NULL;
|
||||
static TickInfoEntry* tick_info = NULL;
|
||||
static u8* cached_entry = NULL;
|
||||
static int cache_index;
|
||||
//static u32 cache_size;
|
||||
|
||||
void DeinitVBDRIDrive(void) {
|
||||
free(title_ids);
|
||||
free(tick_info);
|
||||
free(cached_entry);
|
||||
title_ids = NULL;
|
||||
tick_info = NULL;
|
||||
cached_entry = NULL;
|
||||
num_entries = 0;
|
||||
cache_index = -1;
|
||||
}
|
||||
|
||||
u64 InitVBDRIDrive(void) { // prerequisite: .db file mounted as virtual diff image
|
||||
u64 mount_state = CheckVDisaDiffDrive();
|
||||
if (!(mount_state & SYS_DIFF)) return 0;
|
||||
is_tickdb = (mount_state & SYS_TICKDB);
|
||||
|
||||
DeinitVBDRIDrive();
|
||||
|
||||
num_entries = min(is_tickdb ? GetNumTickets(PART_PATH) : GetNumTitleInfoEntries(PART_PATH), VBDRI_MAX_ENTRIES);
|
||||
title_ids = (u8*) malloc(num_entries * 8);
|
||||
if (!title_ids ||
|
||||
((is_tickdb ? ListTicketTitleIDs(PART_PATH, title_ids, num_entries) : ListTitleInfoEntryTitleIDs(PART_PATH, title_ids, num_entries)) != 0)) {
|
||||
DeinitVBDRIDrive();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_tickdb) {
|
||||
tick_info = (TickInfoEntry*) malloc(num_entries * sizeof(TickInfoEntry));
|
||||
if (!tick_info) {
|
||||
DeinitVBDRIDrive();
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < num_entries; i++) {
|
||||
Ticket* ticket;
|
||||
if (ReadTicketFromDB(PART_PATH, title_ids + (i * 8), &ticket) != 0) {
|
||||
DeinitVBDRIDrive();
|
||||
return 0;
|
||||
}
|
||||
tick_info[i].type = (ticket->commonkey_idx == 0) ? ((ValidateTicketSignature(ticket) == 0) ? 0 : 1) : ((ticket->commonkey_idx == 1) ? 2 : 3);
|
||||
tick_info[i].size = GetTicketSize(ticket);
|
||||
memcpy(tick_info[i].console_id, ticket->console_id, 4);
|
||||
free(ticket);
|
||||
}
|
||||
} else if ((cached_entry = malloc(sizeof(TitleInfoEntry))) == NULL)
|
||||
return 0;
|
||||
|
||||
return mount_state;
|
||||
}
|
||||
|
||||
u64 CheckVBDRIDrive(void) {
|
||||
u64 mount_state = CheckVDisaDiffDrive();
|
||||
return (title_ids && (mount_state & SYS_DIFF) && (!is_tickdb || ((mount_state & SYS_TICKDB) && tick_info))) ?
|
||||
mount_state : 0;
|
||||
}
|
||||
|
||||
bool ReadVBDRIDir(VirtualFile* vfile, VirtualDir* vdir) {
|
||||
if (!CheckVBDRIDrive())
|
||||
return false;
|
||||
|
||||
if (vdir->flags & VFLAG_TICKDIR) { // ticket dir
|
||||
if (!is_tickdb)
|
||||
return false;
|
||||
|
||||
while (++vdir->index < (int) num_entries) {
|
||||
u32 type = tick_info[vdir->index].type;
|
||||
u64 tid = getbe64(title_ids + (vdir->index * 8));
|
||||
|
||||
if ((tid == 0) || !(
|
||||
((vdir->flags & VFLAG_ESHOP) && (type == 0)) ||
|
||||
((vdir->flags & VFLAG_HOMEBREW) && (type == 1)) ||
|
||||
((vdir->flags & VFLAG_SYSTEM) && (type == 2)) ||
|
||||
((vdir->flags & VFLAG_UNKNOWN) && (type == 3))))
|
||||
continue;
|
||||
|
||||
memset(vfile, 0, sizeof(VirtualFile));
|
||||
snprintf(vfile->name, 32, NAME_TIK, tid, getbe32(tick_info[vdir->index].console_id));
|
||||
vfile->offset = vdir->index; // "offset" is the internal buffer index
|
||||
vfile->size = tick_info[vdir->index].size;
|
||||
vfile->keyslot = 0xFF;
|
||||
vfile->flags = (vdir->flags | VFLAG_DELETABLE) & ~VFLAG_DIR;
|
||||
|
||||
return true; // found
|
||||
}
|
||||
} else { // root dir
|
||||
if (is_tickdb) {
|
||||
int n_templates = sizeof(VTickDbFileTemplates) / sizeof(VirtualFile);
|
||||
const VirtualFile* templates = VTickDbFileTemplates;
|
||||
while (++vdir->index < n_templates) {
|
||||
// copy current template to vfile
|
||||
memcpy(vfile, templates + vdir->index, sizeof(VirtualFile));
|
||||
return true; // found
|
||||
}
|
||||
} else { // title dbs display all entries in root
|
||||
while (++vdir->index < (int) num_entries) {
|
||||
u64 tid = getbe64(title_ids + (vdir->index * 8));
|
||||
if (tid == 0)
|
||||
continue;
|
||||
memset(vfile, 0, sizeof(VirtualFile));
|
||||
snprintf(vfile->name, 32, NAME_TIE, tid);
|
||||
vfile->offset = vdir->index; // "offset" is the internal buffer index
|
||||
vfile->size = sizeof(TitleInfoEntry);
|
||||
vfile->keyslot = 0xFF;
|
||||
vfile->flags = (vdir->flags | VFLAG_DELETABLE) & ~VFLAG_DIR;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GetNewVBDRIFile(VirtualFile* vfile, VirtualDir* vdir, const char* path) {
|
||||
size_t len = strlen(path);
|
||||
char buf[31];
|
||||
|
||||
strcpy(buf, path + len - (is_tickdb ? 30 : 17));
|
||||
if (is_tickdb && ((strcmp(buf + 26, ".tik") != 0) || buf[17] != '.'))
|
||||
return false;
|
||||
|
||||
for (char* ptr = buf + 1; ptr < buf + 17; ptr++)
|
||||
*ptr = toupper(*ptr);
|
||||
|
||||
u64 tid;
|
||||
if (sscanf(buf, "/%016llX", &tid) != 1) return false;
|
||||
if (tid == 0)
|
||||
return false;
|
||||
tid = getbe64((u8*)&tid);
|
||||
|
||||
int entry_index = -1;
|
||||
for (u32 i = 0; i < num_entries; i++) {
|
||||
if ((entry_index == -1) && (*((u64*)(void*)(title_ids + 8 * i)) == 0))
|
||||
entry_index = i;
|
||||
|
||||
if (memcmp(&tid, title_ids + 8 * i, 8) == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (entry_index == -1) {
|
||||
if (num_entries == VBDRI_MAX_ENTRIES)
|
||||
return false;
|
||||
|
||||
u32 new_num_entries = min(num_entries + 128, VBDRI_MAX_ENTRIES);
|
||||
u8* new_title_ids = realloc(title_ids, new_num_entries * 8);
|
||||
if (!new_title_ids)
|
||||
return false;
|
||||
if (is_tickdb) {
|
||||
TickInfoEntry* new_tick_info = realloc(tick_info, new_num_entries * sizeof(TickInfoEntry));
|
||||
if (!new_tick_info)
|
||||
return false;
|
||||
tick_info = new_tick_info;
|
||||
}
|
||||
|
||||
entry_index = num_entries;
|
||||
num_entries = new_num_entries;
|
||||
title_ids = new_title_ids;
|
||||
|
||||
memset(title_ids + entry_index * 8, 0, (num_entries - entry_index) * 8);
|
||||
}
|
||||
|
||||
u32 size = is_tickdb ? TICKET_COMMON_SIZE : sizeof(TitleInfoEntry);
|
||||
u8 entry[size];
|
||||
if (is_tickdb)
|
||||
*((u32*)(void*)(entry + 0x2A8)) = 0xAC000000;
|
||||
if ((is_tickdb ? AddTicketToDB(PART_PATH, (u8*)&tid, (Ticket*)(void*)entry, false) :
|
||||
AddTitleInfoEntryToDB(PART_PATH, (u8*)&tid, (TitleInfoEntry*)(void*)entry, false)) != 0)
|
||||
return false;
|
||||
|
||||
memcpy(title_ids + entry_index * 8, &tid, 8);
|
||||
|
||||
if (is_tickdb) {
|
||||
tick_info[entry_index].type = 3;
|
||||
tick_info[entry_index].size = TICKET_COMMON_SIZE;
|
||||
memset(tick_info[entry_index].console_id, 0, 4);
|
||||
}
|
||||
|
||||
memset(vfile, 0, sizeof(VirtualFile));
|
||||
strcpy(vfile->name, buf);
|
||||
vfile->offset = entry_index; // "offset" is the internal buffer index
|
||||
vfile->size = size;
|
||||
vfile->keyslot = 0xFF;
|
||||
vfile->flags = (vdir->flags | VFLAG_DELETABLE) & ~VFLAG_DIR;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int ReadVBDRIFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count) {
|
||||
if ((int) vfile->offset == cache_index) {
|
||||
memcpy(buffer, cached_entry + offset, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_tickdb && (cache_index != -1))
|
||||
free(cached_entry);
|
||||
if ((is_tickdb ? ReadTicketFromDB(PART_PATH, title_ids + vfile->offset * 8, (Ticket**) &cached_entry) :
|
||||
ReadTitleInfoEntryFromDB(PART_PATH, title_ids + vfile->offset * 8, (TitleInfoEntry*) cached_entry)) != 0)
|
||||
return 1;
|
||||
cache_index = (int) vfile->offset;
|
||||
|
||||
memcpy(buffer, cached_entry + offset, count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WriteVBDRIFile(VirtualFile* vfile, const void* buffer, u64 offset, u64 count) {
|
||||
bool resize = false;
|
||||
|
||||
if (offset + count > vfile->size) {
|
||||
if (!is_tickdb)
|
||||
return false;
|
||||
vfile->size = offset + count;
|
||||
resize = true;
|
||||
}
|
||||
|
||||
if (is_tickdb && (cache_index != -1))
|
||||
free(cached_entry);
|
||||
if ((is_tickdb ? ReadTicketFromDB(PART_PATH, title_ids + vfile->offset * 8, (Ticket**) &cached_entry) :
|
||||
ReadTitleInfoEntryFromDB(PART_PATH, title_ids + vfile->offset * 8, (TitleInfoEntry*) cached_entry)) != 0) {
|
||||
if (resize) vfile->size = tick_info[vfile->offset].size;
|
||||
return 1;
|
||||
}
|
||||
cache_index = (int) vfile->offset;
|
||||
|
||||
if (resize) {
|
||||
u8* new_cached_entry = realloc(cached_entry, vfile->size);
|
||||
if (!new_cached_entry) {
|
||||
vfile->size = tick_info[vfile->offset].size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
cached_entry = new_cached_entry;
|
||||
|
||||
if (RemoveTicketFromDB(PART_PATH, title_ids + vfile->offset * 8) != 0) {
|
||||
vfile->size = tick_info[vfile->offset].size;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(cached_entry + offset, buffer, count);
|
||||
|
||||
if ((is_tickdb ? AddTicketToDB(PART_PATH, title_ids + vfile->offset * 8, (Ticket*)(void*)cached_entry, true) :
|
||||
AddTitleInfoEntryToDB(PART_PATH, title_ids + vfile->offset * 8, (TitleInfoEntry*)(void*)cached_entry, true)) != 0) {
|
||||
if (resize) vfile->size = tick_info[vfile->offset].size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (resize) tick_info[vfile->offset].size = vfile->size;
|
||||
|
||||
if (is_tickdb && ((offset <= 0x1F1 && offset + count > 0x1F1) || (cached_entry[0x1F1] == 0 && offset <= 0x104 && offset + count > 4)))
|
||||
tick_info[vfile->offset].type = (cached_entry[0x1F1] == 0) ? ((ValidateTicketSignature((Ticket*)(void*)cached_entry) == 0) ? 0 : 1) : ((cached_entry[0x1F1] == 1) ? 2 : 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DeleteVBDRIFile(const VirtualFile* vfile) {
|
||||
int ret = (int) (is_tickdb ? RemoveTicketFromDB(PART_PATH, title_ids + vfile->offset * 8) : RemoveTitleInfoEntryFromDB(PART_PATH, title_ids + vfile->offset * 8));
|
||||
|
||||
if (ret == 0) {
|
||||
if ((int) vfile->offset == cache_index) {
|
||||
cache_index = -1;
|
||||
if (is_tickdb) {
|
||||
free(cached_entry);
|
||||
cached_entry = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
memset(title_ids + vfile->offset * 8, 0, 8);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
u64 GetVBDRIDriveSize(void) {
|
||||
return CheckVBDRIDrive() ? fvx_qsize(PART_PATH) : 0;
|
||||
}
|
15
arm9/source/virtual/vbdri.h
Normal file
15
arm9/source/virtual/vbdri.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "virtual.h"
|
||||
|
||||
void DeinitVBDRIDrive(void);
|
||||
u64 InitVBDRIDrive(void);
|
||||
u64 CheckVBDRIDrive(void);
|
||||
|
||||
bool ReadVBDRIDir(VirtualFile* vfile, VirtualDir* vdir);
|
||||
bool GetNewVBDRIFile(VirtualFile* vfile, VirtualDir* vdir, const char* path);
|
||||
int ReadVBDRIFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count);
|
||||
int WriteVBDRIFile(VirtualFile* vfile, const void* buffer, u64 offset, u64 count);
|
||||
int DeleteVBDRIFile(const VirtualFile* vfile);
|
||||
u64 GetVBDRIDriveSize(void);
|
@ -2,7 +2,7 @@
|
||||
#include "disadiff.h"
|
||||
#include "common.h"
|
||||
#include "image.h"
|
||||
#include "vtickdb.h" // So we can mount a file as vdisadiff and vtickdb simeltaneously
|
||||
#include "vbdri.h" // So we can mount a file as vdisadiff and vbdri simeltaneously
|
||||
|
||||
#define VFLAG_PARTITION_B (1 << 31)
|
||||
|
||||
@ -194,15 +194,15 @@ u64 InitVDisaDiffDrive(void) {
|
||||
partitionB_info->rw_info = info;
|
||||
}
|
||||
|
||||
InitVTickDbDrive();
|
||||
InitVBDRIDrive();
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
u64 CheckVDisaDiffDrive(void) {
|
||||
u64 type = GetMountState() & (SYS_DISA | SYS_DIFF);
|
||||
u64 type = GetMountState();
|
||||
|
||||
return (type && partitionA_info) ? type : 0;
|
||||
return ((type & (SYS_DISA | SYS_DIFF)) && partitionA_info) ? type : 0;
|
||||
}
|
||||
|
||||
// Can be very lazy here because there are only two files that can appear
|
||||
|
@ -2,7 +2,7 @@
|
||||
#include "vnand.h"
|
||||
#include "vmem.h"
|
||||
#include "vgame.h"
|
||||
#include "vtickdb.h"
|
||||
#include "vbdri.h"
|
||||
#include "vkeydb.h"
|
||||
#include "vcart.h"
|
||||
#include "vvram.h"
|
||||
@ -27,7 +27,7 @@ u32 GetVirtualSource(const char* path) {
|
||||
|
||||
void DeinitVirtualImageDrive(void) {
|
||||
DeinitVGameDrive();
|
||||
DeinitVTickDbDrive();
|
||||
DeinitVBDRIDrive();
|
||||
DeinitVKeyDbDrive();
|
||||
DeinitVDisaDiffDrive();
|
||||
}
|
||||
@ -45,8 +45,8 @@ bool CheckVirtualDrive(const char* path) {
|
||||
return CheckVVramDrive();
|
||||
else if (virtual_src & VRT_GAME)
|
||||
return CheckVGameDrive();
|
||||
else if (virtual_src & VRT_TICKDB)
|
||||
return CheckVTickDbDrive();
|
||||
else if (virtual_src & VRT_BDRI)
|
||||
return CheckVBDRIDrive();
|
||||
else if (virtual_src & VRT_KEYDB)
|
||||
return CheckVKeyDbDrive();
|
||||
else if (virtual_src & VRT_DISADIFF)
|
||||
@ -63,8 +63,8 @@ bool ReadVirtualDir(VirtualFile* vfile, VirtualDir* vdir) {
|
||||
ret = ReadVMemDir(vfile, vdir);
|
||||
} else if (virtual_src & VRT_GAME) {
|
||||
ret = ReadVGameDir(vfile, vdir);
|
||||
} else if (virtual_src & VRT_TICKDB) {
|
||||
ret = ReadVTickDbDir(vfile, vdir);
|
||||
} else if (virtual_src & VRT_BDRI) {
|
||||
ret = ReadVBDRIDir(vfile, vdir);
|
||||
} else if (virtual_src & VRT_KEYDB) {
|
||||
ret = ReadVKeyDbDir(vfile, vdir);
|
||||
} else if (virtual_src & VRT_CART) {
|
||||
@ -129,7 +129,7 @@ bool GetVirtualFile(VirtualFile* vfile, const char* path) {
|
||||
for (name = strtok(lpath + 3, "/"); name && vdir.flags; name = strtok(NULL, "/")) {
|
||||
if (!(vdir.flags & VFLAG_LV3)) { // standard method
|
||||
while (true) {
|
||||
if (!ReadVirtualDir(vfile, &vdir)) return false;
|
||||
if (!ReadVirtualDir(vfile, &vdir)) return ((vdir.flags & VRT_BDRI) && GetNewVBDRIFile(vfile, &vdir, path));
|
||||
if ((!(vfile->flags & (VRT_GAME|VRT_VRAM)) && (strncasecmp(name, vfile->name, 32) == 0)) ||
|
||||
((vfile->flags & VRT_GAME) && MatchVGameFilename(name, vfile, 256)) ||
|
||||
((vfile->flags & VRT_VRAM) && MatchVVramFilename(name, vfile)))
|
||||
@ -173,8 +173,8 @@ int ReadVirtualFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 coun
|
||||
return ReadVMemFile(vfile, buffer, offset, count);
|
||||
} else if (vfile->flags & VRT_GAME) {
|
||||
return ReadVGameFile(vfile, buffer, offset, count);
|
||||
} else if (vfile->flags & VRT_TICKDB) {
|
||||
return ReadVTickDbFile(vfile, buffer, offset, count);
|
||||
} else if (vfile->flags & VRT_BDRI) {
|
||||
return ReadVBDRIFile(vfile, buffer, offset, count);
|
||||
} else if (vfile->flags & VRT_KEYDB) {
|
||||
return ReadVKeyDbFile(vfile, buffer, offset, count);
|
||||
} else if (vfile->flags & VRT_CART) {
|
||||
@ -188,11 +188,11 @@ int ReadVirtualFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 coun
|
||||
return -1;
|
||||
}
|
||||
|
||||
int WriteVirtualFile(const VirtualFile* vfile, const void* buffer, u64 offset, u64 count, u32* bytes_written) {
|
||||
int WriteVirtualFile(VirtualFile* vfile, const void* buffer, u64 offset, u64 count, u32* bytes_written) {
|
||||
// basic check of offset / count
|
||||
if (offset >= vfile->size)
|
||||
return 0;
|
||||
else if ((offset + count) > vfile->size)
|
||||
else if (!(vfile->flags & VRT_BDRI) && ((offset + count) > vfile->size))
|
||||
count = vfile->size - offset;
|
||||
if (bytes_written) *bytes_written = count;
|
||||
|
||||
@ -206,7 +206,9 @@ int WriteVirtualFile(const VirtualFile* vfile, const void* buffer, u64 offset, u
|
||||
return WriteVDisaDiffFile(vfile, buffer, offset, count);
|
||||
} else if (vfile->flags & VRT_CART) {
|
||||
return WriteVCartFile(vfile, buffer, offset, count);
|
||||
} // no write support for virtual game / tickdb / keydb / vram files
|
||||
} else if (vfile->flags & VRT_BDRI) {
|
||||
return WriteVBDRIFile(vfile, buffer, offset, count);
|
||||
} // no write support for virtual game / keydb / vram files
|
||||
|
||||
return -1;
|
||||
}
|
||||
@ -214,6 +216,11 @@ int WriteVirtualFile(const VirtualFile* vfile, const void* buffer, u64 offset, u
|
||||
int DeleteVirtualFile(const VirtualFile* vfile) {
|
||||
if (!(vfile->flags & VFLAG_DELETABLE)) return -1;
|
||||
|
||||
// Special handling for deleting BDRI entries
|
||||
if (vfile->flags & VRT_BDRI)
|
||||
return DeleteVBDRIFile(vfile);
|
||||
|
||||
// For anything else, "deleting" is just filling with 0s
|
||||
u32 zeroes_size = STD_BUFFER_SIZE;
|
||||
u8* zeroes = (u8*) malloc(zeroes_size);
|
||||
if (!zeroes) return -1;
|
||||
@ -222,7 +229,7 @@ int DeleteVirtualFile(const VirtualFile* vfile) {
|
||||
int result = 0;
|
||||
for (u64 pos = 0; pos < vfile->size; pos += zeroes_size) {
|
||||
u64 wipe_bytes = min(zeroes_size, vfile->size - pos);
|
||||
result = WriteVirtualFile(vfile, zeroes, pos, wipe_bytes, NULL);
|
||||
result = WriteVirtualFile((VirtualFile*)vfile, zeroes, pos, wipe_bytes, NULL);
|
||||
if (result != 0) break;
|
||||
}
|
||||
|
||||
@ -236,8 +243,8 @@ u64 GetVirtualDriveSize(const char* path) {
|
||||
return GetVNandDriveSize(virtual_src);
|
||||
else if (virtual_src & VRT_GAME)
|
||||
return GetVGameDriveSize();
|
||||
else if (virtual_src & VRT_TICKDB)
|
||||
return GetVTickDbDriveSize();
|
||||
else if (virtual_src & VRT_BDRI)
|
||||
return GetVBDRIDriveSize();
|
||||
else if (virtual_src & VRT_KEYDB)
|
||||
return GetVKeyDbDriveSize();
|
||||
else if (virtual_src & VRT_CART)
|
||||
|
@ -9,13 +9,13 @@
|
||||
#define VRT_XORPAD NAND_ZERONAND
|
||||
#define VRT_MEMORY (1UL<<4)
|
||||
#define VRT_GAME (1UL<<5)
|
||||
#define VRT_TICKDB (1UL<<6)
|
||||
#define VRT_BDRI (1UL<<6)
|
||||
#define VRT_KEYDB (1UL<<7)
|
||||
#define VRT_CART (1UL<<8)
|
||||
#define VRT_VRAM (1UL<<9)
|
||||
#define VRT_DISADIFF (1UL<<10)
|
||||
|
||||
#define VRT_SOURCE (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND|VRT_XORPAD|VRT_MEMORY|VRT_GAME|VRT_TICKDB|VRT_KEYDB|VRT_CART|VRT_VRAM|VRT_DISADIFF)
|
||||
#define VRT_SOURCE (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND|VRT_XORPAD|VRT_MEMORY|VRT_GAME|VRT_BDRI|VRT_KEYDB|VRT_CART|VRT_VRAM|VRT_DISADIFF)
|
||||
|
||||
#define VFLAG_DIR (1UL<<11)
|
||||
#define VFLAG_ROOT (1UL<<12)
|
||||
@ -25,7 +25,7 @@
|
||||
|
||||
|
||||
#define VRT_DRIVES {'S', VRT_SYSNAND}, {'E', VRT_EMUNAND}, {'I', VRT_IMGNAND}, {'X', VRT_XORPAD }, \
|
||||
{'M', VRT_MEMORY}, {'G', VRT_GAME}, {'K', VRT_KEYDB}, {'T', VRT_TICKDB}, {'C', VRT_CART}, {'V', VRT_VRAM}, {'D', VRT_DISADIFF}
|
||||
{'M', VRT_MEMORY}, {'G', VRT_GAME}, {'K', VRT_KEYDB}, {'T', VRT_BDRI}, {'C', VRT_CART}, {'V', VRT_VRAM}, {'D', VRT_DISADIFF}
|
||||
|
||||
// virtual file flag (subject to change):
|
||||
// bits 0...3 : reserved for NAND virtual sources and info
|
||||
@ -62,7 +62,7 @@ bool GetVirtualDir(VirtualDir* vdir, const char* path);
|
||||
bool GetVirtualFilename(char* name, const VirtualFile* vfile, u32 n_chars);
|
||||
|
||||
int ReadVirtualFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count, u32* bytes_read);
|
||||
int WriteVirtualFile(const VirtualFile* vfile, const void* buffer, u64 offset, u64 count, u32* bytes_written);
|
||||
int WriteVirtualFile(VirtualFile* vfile, const void* buffer, u64 offset, u64 count, u32* bytes_written);
|
||||
int DeleteVirtualFile(const VirtualFile* vfile);
|
||||
|
||||
u64 GetVirtualDriveSize(const char* path);
|
||||
|
@ -1,212 +0,0 @@
|
||||
#include "vtickdb.h"
|
||||
#include "image.h"
|
||||
#include "disadiff.h"
|
||||
#include "ticketdb.h"
|
||||
#include "ui.h" // this takes long - we need a way to keep the user in check
|
||||
|
||||
#define VTICKDB_BUFFER_SIZE 0x100000 // 1MB, enough for ~20000 entries
|
||||
|
||||
#define VFLAG_HIDDEN (1UL<<28)
|
||||
#define VFLAG_UNKNOWN (1UL<<29)
|
||||
#define VFLAG_ESHOP (1UL<<30)
|
||||
#define VFLAG_SYSTEM (1UL<<31)
|
||||
#define VFLAG_TICKDIR (VFLAG_HIDDEN|VFLAG_UNKNOWN|VFLAG_ESHOP|VFLAG_SYSTEM)
|
||||
#define OFLAG_RAW (1lu << 31)
|
||||
|
||||
#define NAME_TIK "%016llX.%08lX.tik" // title id / console id
|
||||
|
||||
|
||||
typedef struct {
|
||||
u32 commonkey_idx;
|
||||
u32 offset;
|
||||
u32 size;
|
||||
u8 title_id[8];
|
||||
u8 titlekey[16];
|
||||
u8 ticket_id[8];
|
||||
u8 console_id[4];
|
||||
u8 eshop_id[4];
|
||||
} PACKED_STRUCT TickDbEntry;
|
||||
|
||||
typedef struct {
|
||||
u32 n_entries;
|
||||
u8 reserved[12];
|
||||
TickDbEntry entries[256]; // this number is only a placeholder (dangerous?)
|
||||
} PACKED_STRUCT TickDbInfo;
|
||||
|
||||
// only for the main directory
|
||||
static const VirtualFile vTickDbFileTemplates[] = {
|
||||
{ "system" , 0x00000000, 0x00000000, 0xFF, VFLAG_DIR | VFLAG_SYSTEM },
|
||||
{ "eshop" , 0x00000000, 0x00000000, 0xFF, VFLAG_DIR | VFLAG_ESHOP },
|
||||
{ "unknown" , 0x00000000, 0x00000000, 0xFF, VFLAG_DIR | VFLAG_UNKNOWN },
|
||||
{ "hidden" , 0x00000000, 0x00000000, 0xFF, VFLAG_DIR | VFLAG_HIDDEN }
|
||||
};
|
||||
|
||||
|
||||
static TickDbInfo* tick_info = NULL;
|
||||
static u8* lvl2_cache = NULL;
|
||||
static DisaDiffRWInfo diff_info;
|
||||
static bool scanned_raw = false;
|
||||
|
||||
|
||||
u32 AddTickDbInfo(TickDbInfo* info, Ticket* ticket, u32 offset, bool replace) {
|
||||
if (ValidateTicket(ticket) != 0) return 1;
|
||||
|
||||
// build ticket entry
|
||||
TickDbEntry* entry = info->entries + info->n_entries;
|
||||
entry->commonkey_idx = ticket->commonkey_idx;
|
||||
entry->offset = offset;
|
||||
entry->size = GetTicketSize(ticket);
|
||||
memcpy(entry->title_id, ticket->title_id, 8);
|
||||
memcpy(entry->titlekey, ticket->titlekey, 16);
|
||||
memcpy(entry->ticket_id, ticket->ticket_id, 8);
|
||||
memcpy(entry->console_id, ticket->console_id, 4);
|
||||
memcpy(entry->eshop_id, ticket->eshop_id, 4);
|
||||
|
||||
// check for duplicate
|
||||
u32 t = 0;
|
||||
for (; t < info->n_entries; t++) {
|
||||
TickDbEntry* entry0 = info->entries + t;
|
||||
if (memcmp(entry->title_id, entry0->title_id, 8) != 0) continue;
|
||||
if (replace && !getbe32(entry0->console_id)) // replace this
|
||||
memcpy(entry0, entry, sizeof(TickDbEntry));
|
||||
break;
|
||||
}
|
||||
if (t >= info->n_entries)
|
||||
info->n_entries++; // new entry
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ScanTickDb(bool raw_mode, bool replace) {
|
||||
// set up buffer
|
||||
u8* data = (u8*) malloc(TICKDB_AREA_SIZE);
|
||||
if (!data) return;
|
||||
|
||||
if (!raw_mode) { // proper DIFF decoding
|
||||
// read and decode ticket.db DIFF partition
|
||||
ShowString("Loading DIFF data...");
|
||||
if (ReadDisaDiffIvfcLvl4(NULL, &diff_info, TICKDB_AREA_OFFSET, TICKDB_AREA_SIZE, data) == TICKDB_AREA_SIZE) {
|
||||
// parse the decoded data for valid tickets
|
||||
for (u32 i = 0; i <= TICKDB_AREA_SIZE - 0x400; i += 0x200) {
|
||||
if (!(i % 0x10000) && !ShowProgress(i, TICKDB_AREA_SIZE, "Scanning for tickets")) break;
|
||||
Ticket* ticket = TicketFromTickDbChunk(data + i, NULL, true);
|
||||
if (!ticket) continue;
|
||||
AddTickDbInfo(tick_info, ticket, TICKDB_AREA_OFFSET + i + 0x18, replace);
|
||||
}
|
||||
}
|
||||
} else { // scan RAW data
|
||||
const u32 area_offsets[] = { TICKDB_AREA_RAW };
|
||||
for (u32 p = 0; p < sizeof(area_offsets) / sizeof(u32); p++) {
|
||||
u32 offset_area = area_offsets[p];
|
||||
ShowString("Loading raw data (%lu)...", p);
|
||||
if (ReadImageBytes(data, offset_area, TICKDB_AREA_SIZE) != 0)
|
||||
continue;
|
||||
for (u32 i = 0; i <= TICKDB_AREA_SIZE - 0x400; i += 0x200) {
|
||||
if (!(i % 0x10000) && !ShowProgress(i, TICKDB_AREA_SIZE, "Scanning for tickets")) break;
|
||||
Ticket* ticket = TicketFromTickDbChunk(data + i, NULL, true);
|
||||
if (!ticket) continue;
|
||||
AddTickDbInfo(tick_info, ticket, (offset_area + i + 0x18) | OFLAG_RAW, replace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClearScreenF(true, false, COLOR_STD_BG);
|
||||
free(data);
|
||||
}
|
||||
|
||||
void DeinitVTickDbDrive(void) {
|
||||
free(tick_info);
|
||||
free(lvl2_cache);
|
||||
tick_info = NULL;
|
||||
lvl2_cache = NULL;
|
||||
scanned_raw = false;
|
||||
}
|
||||
|
||||
u64 InitVTickDbDrive(void) { // prerequisite: ticket.db mounted as image
|
||||
if (!(GetMountState() & SYS_TICKDB)) return 0;
|
||||
|
||||
// set up drive buffer / internal db
|
||||
DeinitVTickDbDrive();
|
||||
tick_info = (TickDbInfo*) malloc(VTICKDB_BUFFER_SIZE);
|
||||
if (!tick_info) return 0;
|
||||
memset(tick_info, 0, 16);
|
||||
|
||||
// setup DIFF reading
|
||||
if ((GetDisaDiffRWInfo(NULL, &diff_info, false) != 0) ||
|
||||
!(lvl2_cache = (u8*) malloc(diff_info.size_dpfs_lvl2)) ||
|
||||
(BuildDisaDiffDpfsLvl2Cache(NULL, &diff_info, lvl2_cache, diff_info.size_dpfs_lvl2) != 0)) {
|
||||
DeinitVTickDbDrive();
|
||||
return 0;
|
||||
}
|
||||
|
||||
ScanTickDb(false, true);
|
||||
|
||||
if (!tick_info->n_entries)
|
||||
DeinitVTickDbDrive();
|
||||
|
||||
return tick_info ? SYS_TICKDB : 0;
|
||||
}
|
||||
|
||||
u64 CheckVTickDbDrive(void) {
|
||||
if ((GetMountState() & SYS_TICKDB) && tick_info) // very basic sanity check
|
||||
return SYS_TICKDB;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ReadVTickDbDir(VirtualFile* vfile, VirtualDir* vdir) {
|
||||
if (!tick_info)
|
||||
return false;
|
||||
|
||||
if (vdir->flags & VFLAG_TICKDIR) { // ticket dir
|
||||
// raw scan required?
|
||||
if ((vdir->flags & VFLAG_HIDDEN) && !scanned_raw) {
|
||||
ScanTickDb(true, false);
|
||||
scanned_raw = true;
|
||||
}
|
||||
|
||||
while (++vdir->index < (int) tick_info->n_entries) {
|
||||
TickDbEntry* tick_entry = tick_info->entries + vdir->index;
|
||||
|
||||
u64 ticket_id = getbe64(tick_entry->ticket_id);
|
||||
u32 ck_idx = tick_entry->commonkey_idx;
|
||||
bool hidden = tick_entry->offset & OFLAG_RAW;
|
||||
if (hidden && !(vdir->flags & VFLAG_HIDDEN)) continue;
|
||||
if (!(((vdir->flags & VFLAG_HIDDEN) && hidden) ||
|
||||
((vdir->flags & VFLAG_ESHOP) && ticket_id && (ck_idx == 0)) ||
|
||||
((vdir->flags & VFLAG_SYSTEM) && ticket_id && (ck_idx == 1)) ||
|
||||
((vdir->flags & VFLAG_UNKNOWN) && (!ticket_id || (ck_idx >= 2)))))
|
||||
continue;
|
||||
|
||||
memset(vfile, 0, sizeof(VirtualFile));
|
||||
snprintf(vfile->name, 32, NAME_TIK, getbe64(tick_entry->title_id), getbe32(tick_entry->console_id));
|
||||
vfile->offset = tick_entry->offset & ~OFLAG_RAW;
|
||||
vfile->size = tick_entry->size;
|
||||
vfile->keyslot = 0xFF;
|
||||
vfile->flags = (vdir->flags | VFLAG_READONLY) & ~VFLAG_DIR;
|
||||
|
||||
return true; // found
|
||||
}
|
||||
} else { // root dir
|
||||
int n_templates = sizeof(vTickDbFileTemplates) / sizeof(VirtualFile);
|
||||
const VirtualFile* templates = vTickDbFileTemplates;
|
||||
while (++vdir->index < n_templates) {
|
||||
// copy current template to vfile
|
||||
memcpy(vfile, templates + vdir->index, sizeof(VirtualFile));
|
||||
vfile->flags |= VFLAG_READONLY;
|
||||
return true; // found
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int ReadVTickDbFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count) {
|
||||
u64 foffset = vfile->offset+ offset;
|
||||
bool hidden = vfile->flags & VFLAG_HIDDEN;
|
||||
if (hidden) return (ReadImageBytes(buffer, foffset, count) == 0) ? 0 : 1;
|
||||
else return (ReadDisaDiffIvfcLvl4(NULL, &diff_info, (u32) foffset, (u32) count, buffer) == (u32) count) ? 0 : 1;
|
||||
}
|
||||
|
||||
u64 GetVTickDbDriveSize(void) {
|
||||
return (tick_info->n_entries) ? GetMountSize() : 0;
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "common.h"
|
||||
#include "virtual.h"
|
||||
|
||||
void DeinitVTickDbDrive(void);
|
||||
u64 InitVTickDbDrive(void);
|
||||
u64 CheckVTickDbDrive(void);
|
||||
|
||||
bool ReadVTickDbDir(VirtualFile* vfile, VirtualDir* vdir);
|
||||
int ReadVTickDbFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count);
|
||||
// int WriteVTickDbFile(const VirtualFile* vfile, const void* buffer, u64 offset, u64 count); // no writing
|
||||
u64 GetVTickDbDriveSize(void);
|
Loading…
x
Reference in New Issue
Block a user