diff --git a/arm9/source/filesys/fsdrive.c b/arm9/source/filesys/fsdrive.c index f1104d1..658674f 100644 --- a/arm9/source/filesys/fsdrive.c +++ b/arm9/source/filesys/fsdrive.c @@ -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; diff --git a/arm9/source/filesys/fsdrive.h b/arm9/source/filesys/fsdrive.h index a9a6ed7..d0922d6 100644 --- a/arm9/source/filesys/fsdrive.h +++ b/arm9/source/filesys/fsdrive.h @@ -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" \ diff --git a/arm9/source/filesys/fsutil.c b/arm9/source/filesys/fsutil.c index bae7e8b..ab73c28 100644 --- a/arm9/source/filesys/fsutil.c +++ b/arm9/source/filesys/fsutil.c @@ -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; diff --git a/arm9/source/virtual/vbdri.c b/arm9/source/virtual/vbdri.c new file mode 100644 index 0000000..7575146 --- /dev/null +++ b/arm9/source/virtual/vbdri.c @@ -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; +} diff --git a/arm9/source/virtual/vbdri.h b/arm9/source/virtual/vbdri.h new file mode 100644 index 0000000..2128a04 --- /dev/null +++ b/arm9/source/virtual/vbdri.h @@ -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); diff --git a/arm9/source/virtual/vdisadiff.c b/arm9/source/virtual/vdisadiff.c index 91ff82c..c218fee 100644 --- a/arm9/source/virtual/vdisadiff.c +++ b/arm9/source/virtual/vdisadiff.c @@ -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 diff --git a/arm9/source/virtual/virtual.c b/arm9/source/virtual/virtual.c index 98fd83b..55e7431 100644 --- a/arm9/source/virtual/virtual.c +++ b/arm9/source/virtual/virtual.c @@ -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) diff --git a/arm9/source/virtual/virtual.h b/arm9/source/virtual/virtual.h index fbb85c8..4c0f135 100644 --- a/arm9/source/virtual/virtual.h +++ b/arm9/source/virtual/virtual.h @@ -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); diff --git a/arm9/source/virtual/vtickdb.c b/arm9/source/virtual/vtickdb.c deleted file mode 100644 index 0028e76..0000000 --- a/arm9/source/virtual/vtickdb.c +++ /dev/null @@ -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; -} diff --git a/arm9/source/virtual/vtickdb.h b/arm9/source/virtual/vtickdb.h deleted file mode 100644 index 4c841df..0000000 --- a/arm9/source/virtual/vtickdb.h +++ /dev/null @@ -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);