Basic uninstaller support for title.db entries

This commit is contained in:
d0k3 2020-08-07 13:06:09 +02:00
parent 6eb546dfab
commit f0ad45dd60
4 changed files with 121 additions and 2 deletions

View File

@ -53,6 +53,7 @@
#define FTYPE_CIABUILD_L(tp) (FTYPE_CIABUILD(tp) && (tp&(GAME_TMD))) #define FTYPE_CIABUILD_L(tp) (FTYPE_CIABUILD(tp) && (tp&(GAME_TMD)))
#define FTYPE_CIAINSTALL(tp) ((tp&(GAME_NCSD|GAME_NCCH|GAME_CIA)) || ((tp&GAME_NDS)&&(tp&(FLAG_DSIW))) || (tp&(GAME_TMD)&&(tp&(FLAG_NUSCDN)))) #define FTYPE_CIAINSTALL(tp) ((tp&(GAME_NCSD|GAME_NCCH|GAME_CIA)) || ((tp&GAME_NDS)&&(tp&(FLAG_DSIW))) || (tp&(GAME_TMD)&&(tp&(FLAG_NUSCDN))))
#define FTYPE_CXIDUMP(tp) (tp&(GAME_TMD)) #define FTYPE_CXIDUMP(tp) (tp&(GAME_TMD))
#define FTYPE_UNINSTALL(tp) (tp&(GAME_TIE))
#define FTYPE_TIKBUILD(tp) (tp&(GAME_TICKET|SYS_TICKDB|BIN_TIKDB)) #define FTYPE_TIKBUILD(tp) (tp&(GAME_TICKET|SYS_TICKDB|BIN_TIKDB))
#define FTYPE_KEYBUILD(tp) (tp&(BIN_KEYDB|BIN_LEGKEY)) #define FTYPE_KEYBUILD(tp) (tp&(BIN_KEYDB|BIN_LEGKEY))
#define FTYPE_TITLEINFO(tp) (tp&(GAME_TIE|GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_NDS|GAME_GBA|GAME_TAD|GAME_3DSX)) #define FTYPE_TITLEINFO(tp) (tp&(GAME_TIE|GAME_SMDH|GAME_NCCH|GAME_NCSD|GAME_CIA|GAME_TMD|GAME_NDS|GAME_GBA|GAME_TAD|GAME_3DSX))

View File

@ -1094,6 +1094,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
bool cia_buildable_legit = (FTYPE_CIABUILD_L(filetype)); bool cia_buildable_legit = (FTYPE_CIABUILD_L(filetype));
bool cia_installable = (FTYPE_CIAINSTALL(filetype)) && !(drvtype & DRV_CTRNAND) && bool cia_installable = (FTYPE_CIAINSTALL(filetype)) && !(drvtype & DRV_CTRNAND) &&
!(drvtype & DRV_TWLNAND) && !(drvtype & DRV_ALIAS); !(drvtype & DRV_TWLNAND) && !(drvtype & DRV_ALIAS);
bool uninstallable = (FTYPE_UNINSTALL(filetype));
bool cxi_dumpable = (FTYPE_CXIDUMP(filetype)); bool cxi_dumpable = (FTYPE_CXIDUMP(filetype));
bool tik_buildable = (FTYPE_TIKBUILD(filetype)) && !in_output_path; bool tik_buildable = (FTYPE_TIKBUILD(filetype)) && !in_output_path;
bool key_buildable = (FTYPE_KEYBUILD(filetype)) && !in_output_path && bool key_buildable = (FTYPE_KEYBUILD(filetype)) && !in_output_path &&
@ -1165,7 +1166,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
(filetype & GAME_EXEFS) ? "Mount as EXEFS image" : (filetype & GAME_EXEFS) ? "Mount as EXEFS image" :
(filetype & GAME_ROMFS) ? "Mount as ROMFS image" : (filetype & GAME_ROMFS) ? "Mount as ROMFS image" :
(filetype & GAME_TMD ) ? "TMD file options..." : (filetype & GAME_TMD ) ? "TMD file options..." :
(filetype & GAME_TIE ) ? "Show title info" : (filetype & GAME_TIE ) ? "Manage Title..." :
(filetype & GAME_BOSS ) ? "BOSS file options..." : (filetype & GAME_BOSS ) ? "BOSS file options..." :
(filetype & GAME_NUSCDN)? "Decrypt NUS/CDN file" : (filetype & GAME_NUSCDN)? "Decrypt NUS/CDN file" :
(filetype & GAME_SMDH) ? "Show SMDH title info" : (filetype & GAME_SMDH) ? "Show SMDH title info" :
@ -1315,6 +1316,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
int cia_build_legit = (cia_buildable_legit) ? ++n_opt : -1; int cia_build_legit = (cia_buildable_legit) ? ++n_opt : -1;
int cxi_dump = (cxi_dumpable) ? ++n_opt : -1; int cxi_dump = (cxi_dumpable) ? ++n_opt : -1;
int cia_install = (cia_installable) ? ++n_opt : -1; int cia_install = (cia_installable) ? ++n_opt : -1;
int uninstall = (uninstallable) ? ++n_opt : -1;
int tik_build_enc = (tik_buildable) ? ++n_opt : -1; int tik_build_enc = (tik_buildable) ? ++n_opt : -1;
int tik_build_dec = (tik_buildable) ? ++n_opt : -1; int tik_build_dec = (tik_buildable) ? ++n_opt : -1;
int key_build = (key_buildable) ? ++n_opt : -1; int key_build = (key_buildable) ? ++n_opt : -1;
@ -1347,7 +1349,8 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
if (cia_build > 0) optionstr[cia_build-1] = (cia_build_legit < 0) ? "Build CIA from file" : "Build CIA (standard)"; if (cia_build > 0) optionstr[cia_build-1] = (cia_build_legit < 0) ? "Build CIA from file" : "Build CIA (standard)";
if (cia_build_legit > 0) optionstr[cia_build_legit-1] = "Build CIA (legit)"; if (cia_build_legit > 0) optionstr[cia_build_legit-1] = "Build CIA (legit)";
if (cxi_dump > 0) optionstr[cxi_dump-1] = "Dump CXI/NDS file"; if (cxi_dump > 0) optionstr[cxi_dump-1] = "Dump CXI/NDS file";
if (cia_install > 0) optionstr[cia_install-1] = "Install game file"; if (cia_install > 0) optionstr[cia_install-1] = "Install game image";
if (uninstall > 0) optionstr[uninstall-1] = "Uninstall title";
if (tik_build_enc > 0) optionstr[tik_build_enc-1] = "Build " TIKDB_NAME_ENC; if (tik_build_enc > 0) optionstr[tik_build_enc-1] = "Build " TIKDB_NAME_ENC;
if (tik_build_dec > 0) optionstr[tik_build_dec-1] = "Build " TIKDB_NAME_DEC; if (tik_build_dec > 0) optionstr[tik_build_dec-1] = "Build " TIKDB_NAME_DEC;
if (key_build > 0) optionstr[key_build-1] = "Build " KEYDB_NAME; if (key_build > 0) optionstr[key_build-1] = "Build " KEYDB_NAME;
@ -1601,6 +1604,43 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan
} }
return 0; return 0;
} }
else if (user_select == uninstall) { // -> uninstall title
bool full_uninstall = false;
// safety confirmation
optionstr[0] = "Keep ticket & savegame";
optionstr[1] = "Uninstall everything";
optionstr[2] = "Abort uninstall";
user_select = (int) (n_marked > 1) ?
ShowSelectPrompt(3, optionstr, "Uninstall %lu selected titles?", n_marked) :
ShowSelectPrompt(3, optionstr, "%s\nUninstall selected title?", pathstr);
full_uninstall = (user_select == 2);
if (!user_select || (user_select == 3))
return 0;
// batch uninstall
if (n_marked > 1) {
u32 n_success = 0;
u32 num = 0;
ShowProgress(0, 0, "batch uninstall");
for (u32 i = 0; i < current_dir->n_entries; i++) {
const char* path = current_dir->entry[i].path;
if (!current_dir->entry[i].marked) continue;
if (!(IdentifyFileType(path) & filetype & TYPE_BASE)) continue;
if (!ShowProgress(++num, n_marked, path)) break;
if (UninstallGameDataTie(path, true, full_uninstall, full_uninstall) == 0)
n_success++;
}
ShowPrompt(false, "%lu/%lu titles uninstalled", n_success, n_marked);
} else {
ShowString("%s\nUninstalling, please wait...", pathstr);
if (UninstallGameDataTie(file_path, true, full_uninstall, full_uninstall) != 0)
ShowPrompt(false, "%s\nUninstall failed!", pathstr);
}
GetDirContents(current_dir, current_path);
return 0;
}
else if (user_select == verify) { // -> verify game / nand file else if (user_select == verify) { // -> verify game / nand file
if ((n_marked > 1) && ShowPrompt(true, "Try to verify all %lu selected files?", n_marked)) { if ((n_marked > 1) && ShowPrompt(true, "Try to verify all %lu selected files?", n_marked)) {
u32 n_success = 0; u32 n_success = 0;

View File

@ -1353,6 +1353,83 @@ u32 GetInstallSavePath(char* path, const char* drv, u64 tid64) {
} }
} }
u32 UninstallGameData(u64 tid64, bool remove_tie, bool remove_ticket, bool remove_save, bool from_emunand) {
char drv[3];
// check permissions for SysNAND (this includes everything we need)
if (!CheckWritePermissions(from_emunand ? "4:" : "1:")) return 1;
// determine the drive
if (GetInstallDataDrive(drv, tid64, from_emunand) != 0) return 1;
// remove data path
char path_data[256];
if (GetInstallPath(path_data, drv, tid64, NULL, remove_save ? NULL : "content") != 0) return 1;
fvx_runlink(path_data);
// clear leftovers
if (GetInstallPath(path_data, drv, tid64, NULL, NULL) != 0)
fvx_unlink(path_data);
// system save is *not* cleared in any case (!!!)
// remove titledb entry / ticket
u32 ret = 0;
if (remove_tie || remove_ticket) {
// ensure remounting the old mount path
char path_store[256] = { 0 };
char* path_bak = NULL;
strncpy(path_store, GetMountPath(), 256);
if (*path_store) path_bak = path_store;
// we need the big endian title ID
u8 title_id[8];
for (u32 i = 0; i < 8; i++)
title_id[i] = (tid64 >> ((7-i)*8)) & 0xFF;
// ticket database
if (remove_ticket) {
char path_ticketdb[256];
if ((GetInstallDbsPath(path_ticketdb, drv, "ticket.db") != 0) || !InitImgFS(path_ticketdb) ||
((RemoveTicketFromDB("D:/partitionA.bin", title_id)) != 0)) ret = 1;
}
// title database
if (remove_tie) {
char path_titledb[256];
if ((GetInstallDbsPath(path_titledb, drv, "title.db") != 0) || !InitImgFS(path_titledb) ||
((RemoveTitleInfoEntryFromDB("D:/partitionA.bin", title_id)) != 0)) ret = 1;
}
// restore old mount path
InitImgFS(path_bak);
}
return ret;
}
u32 UninstallGameDataTie(const char* path, bool remove_tie, bool remove_ticket, bool remove_save) {
// requirements for this to work:
// * title.db from standard path mounted to T:/
// * entry filename starts with title id
// * these two conditions need to be fulfilled for all ties
bool from_emunand = false;
u64 tid64;
const char* mntpath = GetMountPath();
if (!mntpath) return 1;
// title.db from emunand?
if ((strncasecmp(mntpath, "B:/dbs/title.db", 16) == 0) ||
(strncasecmp(mntpath, "4:/dbs/title.db", 16) == 0))
from_emunand = true;
// get title ID
if (sscanf(path, "T:/%016llx", &tid64) != 1)
return 1;
return UninstallGameData(tid64, remove_tie, remove_ticket, remove_save, from_emunand);
}
u32 InstallCiaContent(const char* drv, const char* path_content, u32 offset, u32 size, u32 InstallCiaContent(const char* drv, const char* path_content, u32 offset, u32 size,
TmdContentChunk* chunk, const u8* title_id, const u8* titlekey, bool cxi_fix) { TmdContentChunk* chunk, const u8* title_id, const u8* titlekey, bool cxi_fix) {
char dest[256]; char dest[256];

View File

@ -15,6 +15,7 @@ u32 TrimGameFile(const char* path);
u32 ShowGameFileTitleInfoF(const char* path, u16* screen, bool clear); u32 ShowGameFileTitleInfoF(const char* path, u16* screen, bool clear);
u32 ShowGameFileTitleInfo(const char* path); u32 ShowGameFileTitleInfo(const char* path);
u32 ShowCiaCheckerInfo(const char* path); u32 ShowCiaCheckerInfo(const char* path);
u32 UninstallGameDataTie(const char* path, bool remove_tie, bool remove_ticket, bool remove_save);
u32 GetTmdContentPath(char* path_content, const char* path_tmd); u32 GetTmdContentPath(char* path_content, const char* path_tmd);
u32 BuildNcchInfoXorpads(const char* destdir, const char* path); u32 BuildNcchInfoXorpads(const char* destdir, const char* path);
u32 CheckHealthAndSafetyInject(const char* hsdrv); u32 CheckHealthAndSafetyInject(const char* hsdrv);