From dce3effdea0434d36570f5179b0a52242b1f3d3c Mon Sep 17 00:00:00 2001 From: 0verjoY <59394546+0verjoY@users.noreply.github.com> Date: Mon, 27 Feb 2023 12:57:14 +0100 Subject: [PATCH] Commit --- source/fat.h | 6 +- source/fileops.c | 17 +++ source/menu.c | 290 +++++++++++++++++++++++++++++++------------ source/menu.h | 2 + source/nand.c | 3 +- source/wad-manager.c | 13 +- source/wad.c | 65 ++++++++-- 7 files changed, 302 insertions(+), 94 deletions(-) diff --git a/source/fat.h b/source/fat.h index 26538f2..ce10779 100644 --- a/source/fat.h +++ b/source/fat.h @@ -1,8 +1,10 @@ #ifndef _FAT_H_ #define _FAT_H_ + /* 'FAT File' structure */ -typedef struct { +typedef struct +{ /* Filename */ char filename[128]; /* 1 = Batch Install, 2 = Batch Uninstall - Leathl */ @@ -18,9 +20,7 @@ typedef struct { size_t fsize; } fatFile; - /* Prototypes */ - void FatMount(); void FatUnmount(); char* FatGetDeviceName(u8 index); diff --git a/source/fileops.c b/source/fileops.c index 5b52bd7..785fff3 100644 --- a/source/fileops.c +++ b/source/fileops.c @@ -1,5 +1,6 @@ #include #include +#include #include "fileops.h" @@ -57,6 +58,22 @@ void FSOPMakeFolder(const char* path) if (FSOPFolderExists(path)) return; + char* pos = strchr(path, '/'); + s32 current = pos - path; + current++; + pos = strchr(path + current, '/'); + + while (pos) + { + *pos = 0; + mkdir(path, S_IREAD | S_IWRITE); + *pos = '/'; + + current = pos - path; + current++; + pos = strchr(path + current, '/'); + } + mkdir(path, S_IREAD | S_IWRITE); } diff --git a/source/menu.c b/source/menu.c index de46ab2..a94f606 100644 --- a/source/menu.c +++ b/source/menu.c @@ -21,6 +21,7 @@ #include "iospatch.h" #include "appboot.h" #include "fileops.h" +#include "menu.h" /* NAND device list */ nandDevice ndevList[] = @@ -42,6 +43,8 @@ static char gMenuRegion = '\0'; static u16 gMenuVersion = 0; static u8 gSelected = 0; +static bool gNeedPriiloaderOption = false; + /* Macros */ //#define NB_FAT_DEVICES (sizeof(fdevList) / sizeof(fatDevice)) #define NB_NAND_DEVICES (sizeof(ndevList) / sizeof(nandDevice)) @@ -106,14 +109,18 @@ s32 __Menu_RetrieveList(char *inPath, fatFile **outbuf, u32 *outlen) cnt++; } - if (cnt > 0) { + if (cnt > 0) + { /* Allocate memory */ buffer = malloc(sizeof(fatFile) * cnt); - if (!buffer) { + if (!buffer) + { closedir(dir); return -2; } + memset(buffer, 0, sizeof(fatFile) * cnt); + /* Reset directory */ rewinddir(dir); @@ -213,7 +220,9 @@ void Menu_SelectIOS(void) qsort(iosVersion, iosCnt, sizeof(u8), __Menu_IsGreater); if (gConfig.cIOSVersion < 0) + { tmpVersion = CIOS_VERSION; + } else { tmpVersion = (u8)gConfig.cIOSVersion; @@ -223,7 +232,8 @@ void Menu_SelectIOS(void) } /* Set default version */ - for (cnt = 0; cnt < iosCnt; cnt++) { + for (cnt = 0; cnt < iosCnt; cnt++) + { u8 version = iosVersion[cnt]; /* Custom IOS available */ @@ -277,26 +287,32 @@ void Menu_SelectIOS(void) } } - u8 version = iosVersion[selected]; if (IOS_GetVersion() != version) { /* Shutdown subsystems */ + FatUnmount(); Wpad_Disconnect(); - //mload_close(); + /* Load IOS */ - - if(!loadIOS(version)) Wpad_Init(), Menu_SelectIOS(); + if (!loadIOS(version)) + { + Wpad_Init(); + Menu_SelectIOS(); + } /* Initialize subsystems */ Wpad_Init(); + FatMount(); } } void Menu_FatDevice(void) { FatMount(); + if (gSelected >= FatGetDeviceCount()) + gSelected = 0; const u16 konamiCode[] = { @@ -314,30 +330,34 @@ void Menu_FatDevice(void) { /* Clear console */ Con_Clear(); + bool deviceOk = (FatGetDeviceCount() > 0); - if (!FatGetDeviceCount()) + if (!deviceOk) { - printf("\t[+] No source device: < %s >\n\n", FatGetDeviceName(gSelected)); + printf("\t[+] No source devices found\n\n"); + } + else + { + printf("\t>> Select source device: < %s >\n\n", FatGetDeviceName(gSelected)); + printf("\t Press LEFT/RIGHT to change the selected device.\n\n"); + printf("\t Press A button to continue.\n"); } - /* Selected device */ //printf("\tWii menu version: %d, region: %s\n\n", gMenuVersion, GetSysMenuRegionString(&gMenuRegion)); - printf("\t>> Select source device: < %s >\n\n", FatGetDeviceName(gSelected)); - printf("\t Press LEFT/RIGHT to change the selected device.\n\n"); - printf("\t Press A button to continue.\n"); - printf("\t Press B button to remount source devices.\n"); + + printf("\t Press 1 button to remount source devices.\n"); printf("\t Press HOME button to restart.\n\n"); if (skipRegionSafetyCheck) { printf("[+] WARNING: SM Region checks disabled!\n\n"); - printf("\t Press 1 button to reset.\n"); + printf("\t Press 2 button to reset.\n"); } u32 buttons = WaitButtons(); - if (buttons & (WPAD_BUTTON_UP | WPAD_BUTTON_DOWN | WPAD_BUTTON_RIGHT | WPAD_BUTTON_LEFT | WPAD_BUTTON_A | WPAD_BUTTON_B)) + if (deviceOk && buttons & (WPAD_BUTTON_UP | WPAD_BUTTON_DOWN | WPAD_BUTTON_RIGHT | WPAD_BUTTON_LEFT | WPAD_BUTTON_A | WPAD_BUTTON_B)) { if (!skipRegionSafetyCheck) { @@ -347,16 +367,12 @@ void Menu_FatDevice(void) codePosition = 0; } } - if (buttons & WPAD_BUTTON_LEFT) + if (deviceOk && buttons & WPAD_BUTTON_LEFT) { if ((s8)(--gSelected) < 0) gSelected = FatGetDeviceCount() - 1; } - else if (buttons & WPAD_BUTTON_1 && skipRegionSafetyCheck) - { - skipRegionSafetyCheck = false; - } - else if (buttons & WPAD_BUTTON_RIGHT) + else if (deviceOk && buttons & WPAD_BUTTON_RIGHT) { if ((++gSelected) >= FatGetDeviceCount()) gSelected = 0; @@ -365,7 +381,7 @@ void Menu_FatDevice(void) { Restart(); } - else if (buttons & WPAD_BUTTON_B && !codePosition) + else if (buttons & WPAD_BUTTON_1) { printf("\t\t[-] Mounting devices."); usleep(500000); @@ -380,7 +396,11 @@ void Menu_FatDevice(void) gSelected = 0; usleep(500000); } - else if (buttons & WPAD_BUTTON_A) + else if (buttons & WPAD_BUTTON_2 && skipRegionSafetyCheck) + { + skipRegionSafetyCheck = false; + } + else if (deviceOk && buttons & WPAD_BUTTON_A) { if (codePosition == sizeof(konamiCode) / sizeof(konamiCode[0])) { @@ -388,7 +408,6 @@ void Menu_FatDevice(void) printf("[+] Disabled SM region checks\n"); sleep(3); } - break; } } } @@ -509,7 +528,8 @@ int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath, int i printf(" Do you want to proceed?\n"); } else { - printf("[+] %d file%s marked for installation and %d file%s for uninstallation.\n", installCnt, (installCnt == 1) ? "" : "s", uninstallCnt, (uninstallCnt == 1) ? "" : "s"); + printf("[+] %d file%s marked for installation.\n", installCnt, (installCnt == 1) ? "" : "s"); + printf("[+] %d file%s marked for uninstallation.\n", uninstallCnt, (uninstallCnt == 1) ? "" : "s"); printf(" Do you want to proceed?\n"); } @@ -534,30 +554,52 @@ int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath, int i { fatFile *thisFile = &files[count]; - if ((thisFile->install == 1) | (thisFile->install == 2)) { - int mode = thisFile->install; + int mode = thisFile->install; + if (mode) + { Con_Clear(); + printf("[+] Processing WAD: %d/%d...\n\n", (errors + success + 1), (installCnt + uninstallCnt)); printf("[+] Opening \"%s\", please wait...\n\n", thisFile->filename); sprintf(gTmpFilePath, "%s/%s", inFilePath, thisFile->filename); FILE *fp = fopen(gTmpFilePath, "rb"); - if (!fp) { + if (!fp) + { printf(" ERROR!\n"); errors += 1; continue; - } - - printf("[+] %s WAD, please wait...\n", (mode == 2) ? "Uninstalling" : "Installing"); - if (mode == 2) { + } + + if (mode == 2) + { + printf(">> Uninstalling WAD, please wait...\n\n"); ret = Wad_Uninstall(fp); } - else { + else + { + printf(">> Installing WAD, please wait...\n\n"); ret = Wad_Install(fp); } - if (ret < 0) errors += 1; - else success += 1; + if (ret < 0) + { + if ((errors + success + 1) < (installCnt + uninstallCnt)) + { + s32 i; + for (i = 5; i > 0; i--) + { + printf("\r Continue in: %d", i); + sleep(1); + } + } + + errors++; + } + else + { + success++; + } thisFile->installstate = ret; @@ -566,7 +608,7 @@ int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath, int i } } - WiiLightControl (WII_LIGHT_OFF); + WiiLightControl(WII_LIGHT_OFF); printf("\n"); printf(" %d titles succeeded and %d failed...\n", success, errors); @@ -583,24 +625,52 @@ int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath, int i { Con_Clear(); - int i=0; + int i = 0; for (count = 0; count < fileCount; count++) { fatFile *thisFile = &files[count]; - if (thisFile->installstate <0) + if (thisFile->installstate < 0) { char str[41]; strncpy(str, thisFile->filename, 40); //Only 40 chars to fit the screen str[40]=0; i++; - if(thisFile->installstate == -999) printf(" %s BRICK BLOCKED\n", str); - else if(thisFile->installstate == -998) printf(" %s Skipped\n", str); - else if(thisFile->installstate == -106) printf(" %s Not installed?\n", str); - else if(thisFile->installstate == -1036 ) printf(" %s Needed IOS missing\n", str); - else if(thisFile->installstate == -4100 ) printf(" %s No trucha bug?\n", str); - else printf(" %s error %d\n", str, thisFile->installstate); - if( i == 17 ) + + + switch (thisFile->installstate) + { + case -106: + { + printf(" %s Not installed?\n", str); + } break; + case -996: + { + printf(" %s Read error\n", str); + } break; + case -998: + { + printf(" %s Skipped\n", str); + } break; + case -999: + { + printf(" %s BRICK BLOCKED\n", str); + } break; + case -1036: + { + printf(" %s Needed IOS missing\n", str); + } break; + case -4100: + { + printf(" %s No trucha bug?\n", str); + } break; + default: + { + printf(" %s error %d\n", str, thisFile->installstate); + } break; + } + + if(i == 17) { printf("\n Press any button to continue\n"); WaitButtons(); @@ -610,8 +680,30 @@ int Menu_BatchProcessWads(fatFile *files, int fileCount, char *inFilePath, int i } } } - printf("\n Press any button to continue...\n"); - WaitButtons(); + + if (gNeedPriiloaderOption) + { + printf("\n Priiloader has been retained, but all hacks were reset.\n\n"); + printf(" Press A launch Priiloader now.\n"); + printf(" Press any other button to continue...\n"); + + u32 buttons = WaitButtons(); + + if (buttons & WPAD_BUTTON_A) + { + gNeedPriiloaderOption = false; + *(vu32*)0x8132FFFB = 0x4461636f; + DCFlushRange((void*)0x8132FFFB, 4); + SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); + } + + gNeedPriiloaderOption = false; + } + else + { + printf("\n Press any button to continue...\n"); + WaitButtons(); + } return 1; } @@ -741,33 +833,71 @@ void Menu_WadManage(fatFile *file, char *inFilePath) /* Generate filepath */ // sprintf(filepath, "%s:" WAD_DIRECTORY "/%s", fdev->mount, file->filename); sprintf(gTmpFilePath, "%s/%s", inFilePath, file->filename); // wiiNinja - if(file->iswad) { - /* Open WAD */ - fp = fopen(gTmpFilePath, "rb"); - if (!fp) { - printf(" ERROR!\n"); - goto out; - } else - printf(" OK!\n\n"); + if(file->iswad) + { + /* Open WAD */ + fp = fopen(gTmpFilePath, "rb"); + if (!fp) + { + printf(" ERROR!\n"); + goto out; + } + else + { + printf(" OK!\n\n"); + } - printf("[+] %s WAD, please wait...\n", (!mode) ? "Installing" : "Uninstalling"); + printf("[+] %s WAD, please wait...\n", (!mode) ? "Installing" : "Uninstalling"); - /* Do install/uninstall */ - WiiLightControl (WII_LIGHT_ON); - if (!mode) - Wad_Install(fp); - else - Wad_Uninstall(fp); - WiiLightControl (WII_LIGHT_OFF); + /* Do install/uninstall */ + WiiLightControl (WII_LIGHT_ON); + + if (!mode) + { + Wad_Install(fp); + WiiLightControl(WII_LIGHT_OFF); + + if (gNeedPriiloaderOption) + { + printf("\n Priiloader has been retained, but all hacks were reset.\n\n"); + printf(" Press A launch Priiloader now.\n"); + printf(" Press any other button to continue...\n"); + + u32 buttons = WaitButtons(); + + if (fp) + fclose(fp); + + if (buttons & WPAD_BUTTON_A) + { + gNeedPriiloaderOption = false; + *(vu32*)0x8132FFFB = 0x4461636f; + DCFlushRange((void*)0x8132FFFB, 4); + SYS_ResetSystem(SYS_RETURNTOMENU, 0, 0); + } + + gNeedPriiloaderOption = false; + + return; + } + } + else + { + + Wad_Uninstall(fp); + WiiLightControl(WII_LIGHT_OFF); + } } - else { + else + { printf("launch dol/elf here \n"); - if(LoadApp(inFilePath, file->filename)) { + if(LoadApp(inFilePath, file->filename)) LaunchApp(); - } + return; } + out: /* Close file */ if (fp) @@ -860,6 +990,7 @@ getList: { fatFile *file = &fileList[counter]; file->install = 0; + file->installstate = 0; } for (;;) @@ -927,7 +1058,7 @@ getList: /** Controls **/ u32 buttons = WaitButtons(); - + /* DPAD buttons */ if (buttons & WPAD_BUTTON_UP) { @@ -967,13 +1098,13 @@ getList: { installCnt = 0; int i = 0; - while( i < fileCnt) + while(i < fileCnt) { fatFile *file = &fileList[i]; if (((file->isdir) == false) && (file->install == 0)) { file->install = 1; - installCnt += 1; + installCnt++; } else if (((file->isdir) == false) && (file->install == 1)) { @@ -1026,7 +1157,7 @@ getList: installCnt = 0; int i = 0; - while( i < fileCnt) + while(i < fileCnt) { fatFile *file = &fileList[i]; if (((file->isdir) == false) && (file->install == 0)) @@ -1066,7 +1197,7 @@ getList: else if (((file->isdir) == false) && (file->install == 2)) { file->install = 0; - uninstallCnt -= 1; + uninstallCnt--; } selected++; @@ -1155,6 +1286,7 @@ getList: { fatFile *temp = &fileList[counter]; temp->install = 0; + temp->installstate = 0; } installCnt = 0; @@ -1165,7 +1297,7 @@ getList: //else use standard wadmanage menu - Leathl else { - tmpCurPath = PeekCurrentDir (); + tmpCurPath = PeekCurrentDir(); if (tmpCurPath != NULL) Menu_WadManage(tmpFile, tmpCurPath); } @@ -1229,11 +1361,13 @@ void Menu_Loop(void) ndev = &ndevList[0]; /* NAND device menu */ - if ((iosVersion == CIOS_VERSION || iosVersion == 250) && IOS_GetRevision() >13) + if ((iosVersion == CIOS_VERSION || iosVersion == 250) && IOS_GetRevision() > 13) { Menu_NandDevice(); } - for (;;) { + + for (;;) + { /* FAT device menu */ Menu_FatDevice(); @@ -1242,8 +1376,12 @@ void Menu_Loop(void) } } -// Start of wiiNinja's added routines +void SetPriiloaderOption(bool enabled) +{ + gNeedPriiloaderOption = enabled; +} +// Start of wiiNinja's added routines int PushCurrentDir (char *dirStr, int Selected, int Start) { int retval = 0; diff --git a/source/menu.h b/source/menu.h index 92cd259..0cb95a2 100644 --- a/source/menu.h +++ b/source/menu.h @@ -3,6 +3,8 @@ /* Prototypes */ void Menu_Loop(void); +void SetPriiloaderOption(bool enabled); +bool MenuTestDevice(); #endif diff --git a/source/nand.c b/source/nand.c index a7447dc..4196dd6 100644 --- a/source/nand.c +++ b/source/nand.c @@ -354,6 +354,8 @@ s32 NANDGetNameList(const char* src, NameList** entries, s32* count) s32 NANDDumpFile(const char* src, const char* dst) { + printf("Dump file: %s\n", src); + s32 fd = ISFS_Open(src, ISFS_OPEN_READ); if (fd < 0) return fd; @@ -371,7 +373,6 @@ s32 NANDDumpFile(const char* src, const char* dst) } FSOPDeleteFile(dst); - FILE* file = fopen(dst, "wb"); if (!file) diff --git a/source/wad-manager.c b/source/wad-manager.c index be5ef1b..54377e5 100644 --- a/source/wad-manager.c +++ b/source/wad-manager.c @@ -18,6 +18,7 @@ #include "nand.h" #include "globals.h" #include "iospatch.h" +#include "fileops.h" // Globals CONFIG gConfig; @@ -217,14 +218,17 @@ int ReadConfigFile(char* configFilePath) if (tmpStr == NULL) return (-1); - // Just check if at least one device is available for (i = 0; i < FatGetDeviceCount(); i++) - { + { snprintf(path, sizeof(path), "%s%s", FatGetDevicePrefix(i), configFilePath); - found = true; + if (FSOPFileExists(path)) + { + found = true; + break; + } } - if (!found) + if (!found) { printf(" ERROR! (ret = %d)\n", ret); // goto err; @@ -282,7 +286,6 @@ int ReadConfigFile(char* configFilePath) GetStringParam (tmpOutStr, tmpStr, MAX_FAT_DEVICE_LENGTH); for (i = 0; i < 5; i++) { - //if (strncmp (fdevList[i].mount, tmpOutStr, 4) == 0) if (strncmp(FatGetDevicePrefix(i), tmpOutStr, 4) == 0) { gConfig.fatDeviceIndex = i; diff --git a/source/wad.c b/source/wad.c index e0c9cc9..3f593be 100644 --- a/source/wad.c +++ b/source/wad.c @@ -14,6 +14,8 @@ #include "nand.h" #include "fileops.h" #include "sha1.h" +#include "menu.h" +#include "iospatch.h" // Turn upper and lower into a full title ID #define TITLE_ID(x,y) (((u64)(x) << 32) | (y)) @@ -166,10 +168,10 @@ static char* GetTitleExec(u64 tId, bool tweaked) u32 size; const u8 buffer[MAX_SIGNED_TMD_SIZE] ATTRIBUTE_ALIGN(32); - s32 ret = ES_GetStoredTMDSize(0x100000002, &size); + s32 ret = ES_GetStoredTMDSize(0x100000002LL, &size); signed_blob* tmdRaw = (signed_blob*)buffer; - ret = ES_GetStoredTMD(0x100000002, tmdRaw, size); + ret = ES_GetStoredTMD(0x100000002LL, tmdRaw, size); if (ret < 0) { printf("Error! ES_GetStoredTMDSize: Failed! (Error: %d)\n", ret); @@ -479,6 +481,10 @@ bool skipRegionSafetyCheck = false; s32 Wad_Install(FILE *fp) { + //fseek(fp, 0, SEEK_END); + //s32 wadSize = ftell(fp); + //fseek(fp, 0, SEEK_CUR); + SetPRButtons(false); wadHeader *header = NULL; signed_blob *p_certs = NULL, *p_crl = NULL, *p_tik = NULL, *p_tmd = NULL; @@ -633,7 +639,13 @@ s32 Wad_Install(FILE *fp) } if(region != RegionLookupList[(tmd_data->title_version & 0x0F)]) { - printf("\n I won't install the wrong regions SM\n"); + printf("\n I won't install the wrong regions SM by default.\n\n"); + + printf("\n Are you region changing?\n"); + + printf("\n If you're really sure what you're doing, next time\n"); + printf(" select your device using Konami...\n\n"); + ret = -999; goto err; } @@ -648,10 +660,14 @@ skipChecks: } } - if (!gForcedInstall && IsPriiloaderInstalled()) + if (!gForcedInstall && AHBPROT_DISABLED && IsPriiloaderInstalled()) { cleanupPriiloader = true; printf("\n Priiloader is installed next to the system menu.\n\n"); + printf(" It is recommended to retain Priiloader as it can\n"); + printf(" protect your console from being bricked.\n\n"); + + printf(" Press A to retain Priiloader or B to remove."); u32 buttons = WaitButtons(); @@ -661,6 +677,7 @@ skipChecks: retainPriiloader = (BackUpPriiloader() && CompareHashes(true)); if (retainPriiloader) { + SetPriiloaderOption(true); Con_ClearLine(); printf("\r[+] Priiloader will be retained.\n"); fflush(stdout); @@ -685,11 +702,16 @@ skipChecks: if (!retainPriiloader) { + SetPriiloaderOption(false); Con_ClearLine(); printf("\r[+] Priiloader will be removed.\n"); fflush(stdout); } } + else + { + SetPriiloaderOption(false); + } } if (gForcedInstall) @@ -701,6 +723,12 @@ skipChecks: /* Fix ticket */ __Wad_FixTicket(p_tik); + //if (!MenuTestDevice()) + //{ + // ret = -996; + // goto err; + //} + printf("\t\t>> Installing ticket..."); fflush(stdout); @@ -720,7 +748,8 @@ skipChecks: goto err; /* Install contents */ - for (cnt = 0; cnt < tmd_data->num_contents; cnt++) { + for (cnt = 0; cnt < tmd_data->num_contents; cnt++) + { tmd_content *content = &tmd_data->contents[cnt]; u32 idx = 0, len; @@ -736,13 +765,15 @@ skipChecks: /* Install content */ cfd = ES_AddContentStart(tmd_data->title_id, content->cid); - if (cfd < 0) { + if (cfd < 0) + { ret = cfd; goto err; } /* Install content data */ - while (idx < len) { + while (idx < len) + { u32 size; /* Data length */ @@ -750,15 +781,25 @@ skipChecks: if (size > BLOCK_SIZE) size = BLOCK_SIZE; + //if (offset + size > wadSize) + // size = wadSize - offset; + + //printf("\n>> Read Offset: %X (%d) Length: %d/%d", offset, size, idx, len); /* Read data */ ret = FSOPReadOpenFile(fp, &wadBuffer, offset, size); if (ret != 1) + { + ES_AddContentFinish(cfd); goto err; - + } + /* Install data */ ret = ES_AddContentData(cfd, wadBuffer, size); if (ret < 0) + { + ret = ES_AddContentFinish(cfd); goto err; + } /* Increase variables */ idx += size; @@ -770,7 +811,7 @@ skipChecks: if (ret < 0) goto err; } - + Con_ClearLine(); printf("\r\t\t>> Finishing installation..."); @@ -778,6 +819,7 @@ skipChecks: /* Finish title install */ ret = ES_AddTitleFinish(); + if (ret >= 0) { printf(" OK!\n"); @@ -879,6 +921,11 @@ skipChecks: err: printf("\n ERROR! (ret = %d)\n", ret); + if (retainPriiloader) + SetPriiloaderOption(false); + + if (ret == 0) + ret = -996; /* Cancel install */ ES_AddTitleCancel();