2016-08-06 06:59:41 +00:00
|
|
|
/*
|
|
|
|
VitaShell
|
2017-01-12 16:45:52 +00:00
|
|
|
Copyright (C) 2015-2017, TheFloW
|
2016-08-06 06:59:41 +00:00
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2016-11-30 17:21:56 +00:00
|
|
|
#include <psp2/sysmodule.h>
|
|
|
|
#include <psp2/promoterutil.h>
|
|
|
|
|
2016-08-06 06:59:41 +00:00
|
|
|
#include "main.h"
|
|
|
|
#include "io_process.h"
|
|
|
|
#include "package_installer.h"
|
|
|
|
#include "archive.h"
|
|
|
|
#include "file.h"
|
|
|
|
#include "message_dialog.h"
|
2016-08-27 17:16:39 +00:00
|
|
|
#include "language.h"
|
2016-08-06 06:59:41 +00:00
|
|
|
#include "utils.h"
|
2016-09-01 16:20:47 +00:00
|
|
|
#include "sfo.h"
|
2016-08-06 06:59:41 +00:00
|
|
|
#include "sha1.h"
|
2016-09-20 14:18:24 +00:00
|
|
|
|
2016-08-06 06:59:41 +00:00
|
|
|
#include "resources/base_head_bin.h"
|
|
|
|
|
2017-02-12 15:27:43 +00:00
|
|
|
static int patchRetailContents() {
|
2016-09-06 19:57:04 +00:00
|
|
|
int res;
|
2016-09-08 19:37:02 +00:00
|
|
|
|
|
|
|
SceIoStat stat;
|
|
|
|
memset(&stat, 0, sizeof(SceIoStat));
|
|
|
|
res = sceIoGetstat(PACKAGE_DIR "/sce_sys/retail/livearea", &stat);
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
2016-09-06 19:57:04 +00:00
|
|
|
|
2016-09-08 19:37:02 +00:00
|
|
|
res = sceIoRename(PACKAGE_DIR "/sce_sys/livearea", PACKAGE_DIR "/sce_sys/livearea_org");
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
2016-09-06 19:57:04 +00:00
|
|
|
|
2016-09-08 19:37:02 +00:00
|
|
|
res = sceIoRename(PACKAGE_DIR "/sce_sys/retail/livearea", PACKAGE_DIR "/sce_sys/livearea");
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
2016-09-06 19:57:04 +00:00
|
|
|
|
2016-09-08 19:37:02 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-12 15:27:43 +00:00
|
|
|
static int restoreRetailContents(const char *titleid) {
|
2016-09-08 19:37:02 +00:00
|
|
|
int res;
|
|
|
|
char src_path[128], dst_path[128];
|
|
|
|
|
|
|
|
sprintf(src_path, "ux0:app/%s/sce_sys/livearea", titleid);
|
|
|
|
sprintf(dst_path, "ux0:app/%s/sce_sys/retail/livearea", titleid);
|
|
|
|
res = sceIoRename(src_path, dst_path);
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
sprintf(src_path, "ux0:app/%s/sce_sys/livearea_org", titleid);
|
|
|
|
sprintf(dst_path, "ux0:app/%s/sce_sys/livearea", titleid);
|
|
|
|
res = sceIoRename(src_path, dst_path);
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-12 15:27:43 +00:00
|
|
|
int promoteUpdate(const char *path, const char *titleid, const char *category, void *sfo_buffer, int sfo_size) {
|
2016-09-08 19:37:02 +00:00
|
|
|
int res;
|
2016-09-06 19:57:04 +00:00
|
|
|
|
|
|
|
// Update installation
|
|
|
|
if (strcmp(category, "gp") == 0) {
|
2016-09-07 17:19:07 +00:00
|
|
|
// Change category to 'gd'
|
|
|
|
setSfoString(sfo_buffer, "CATEGORY", "gd");
|
|
|
|
WriteFile(PACKAGE_DIR "/sce_sys/param.sfo", sfo_buffer, sfo_size);
|
|
|
|
|
|
|
|
// App path
|
2016-09-06 19:57:04 +00:00
|
|
|
char app_path[MAX_PATH_LENGTH];
|
|
|
|
snprintf(app_path, MAX_PATH_LENGTH, "ux0:app/%s", titleid);
|
|
|
|
|
2016-09-08 19:37:02 +00:00
|
|
|
/*
|
|
|
|
Without the following trick, the livearea won't be updated and the game will even crash
|
|
|
|
*/
|
|
|
|
|
2016-09-07 17:19:07 +00:00
|
|
|
// Integrate patch to app
|
2016-09-10 12:35:15 +00:00
|
|
|
res = movePath(path, app_path, MOVE_INTEGRATE | MOVE_REPLACE, NULL);
|
2016-09-08 19:37:02 +00:00
|
|
|
if (res < 0)
|
2016-09-06 19:57:04 +00:00
|
|
|
return res;
|
|
|
|
|
2016-09-07 17:19:07 +00:00
|
|
|
// Move app to promotion directory
|
2016-09-10 12:35:15 +00:00
|
|
|
res = movePath(app_path, path, 0, NULL);
|
2016-09-08 19:37:02 +00:00
|
|
|
if (res < 0)
|
2016-09-06 19:57:04 +00:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-12 15:27:43 +00:00
|
|
|
int promoteApp(const char *path) {
|
2016-08-06 06:59:41 +00:00
|
|
|
int res;
|
|
|
|
|
2016-09-08 19:37:02 +00:00
|
|
|
// Read param.sfo
|
|
|
|
void *sfo_buffer = NULL;
|
|
|
|
int sfo_size = allocateReadFile(PACKAGE_DIR "/sce_sys/param.sfo", &sfo_buffer);
|
|
|
|
if (sfo_size < 0)
|
|
|
|
return sfo_size;
|
|
|
|
|
|
|
|
// Get titleid
|
|
|
|
char titleid[12];
|
|
|
|
getSfoString(sfo_buffer, "TITLE_ID", titleid, sizeof(titleid));
|
|
|
|
|
|
|
|
// Get category
|
|
|
|
char category[4];
|
|
|
|
getSfoString(sfo_buffer, "CATEGORY", category, sizeof(category));
|
|
|
|
|
|
|
|
// Promote update
|
|
|
|
promoteUpdate(path, titleid, category, sfo_buffer, sfo_size);
|
|
|
|
|
|
|
|
// Free sfo buffer
|
|
|
|
free(sfo_buffer);
|
|
|
|
|
|
|
|
// Patch to use retail contents so the game is not shown as test version
|
|
|
|
int patch_retail_contents = patchRetailContents();
|
2016-09-06 19:57:04 +00:00
|
|
|
|
2016-08-06 06:59:41 +00:00
|
|
|
res = scePromoterUtilityInit();
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
res = scePromoterUtilityPromotePkg(path, 0);
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
int state = 0;
|
|
|
|
do {
|
|
|
|
res = scePromoterUtilityGetState(&state);
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
2016-09-04 10:55:15 +00:00
|
|
|
sceKernelDelayThread(100 * 1000);
|
2016-08-06 06:59:41 +00:00
|
|
|
} while (state);
|
|
|
|
|
2017-02-12 15:27:43 +00:00
|
|
|
int ret = 0;
|
|
|
|
res = scePromoterUtilityGetResult(&ret);
|
2016-08-06 06:59:41 +00:00
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
res = scePromoterUtilityExit();
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
2016-09-08 19:37:02 +00:00
|
|
|
// Restore
|
|
|
|
if (patch_retail_contents >= 0)
|
|
|
|
restoreRetailContents(titleid);
|
|
|
|
|
|
|
|
// Using the promoteUpdate trick, we get 0x80870005 as result, but it installed correctly though, so return ok
|
2017-02-12 15:27:43 +00:00
|
|
|
return ret == 0x80870005 ? 0 : ret;
|
2016-08-06 06:59:41 +00:00
|
|
|
}
|
|
|
|
|
2017-02-12 15:27:43 +00:00
|
|
|
int deleteApp(const char *titleid) {
|
2016-09-20 14:18:24 +00:00
|
|
|
int res;
|
|
|
|
|
2017-02-12 15:27:43 +00:00
|
|
|
res = sceAppMgrDestroyOtherApp();
|
|
|
|
if (res < 0)
|
2016-09-20 14:18:24 +00:00
|
|
|
return res;
|
|
|
|
|
|
|
|
res = scePromoterUtilityInit();
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
res = scePromoterUtilityDeletePkg(titleid);
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
int state = 0;
|
|
|
|
do {
|
|
|
|
res = scePromoterUtilityGetState(&state);
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
2017-02-12 15:27:43 +00:00
|
|
|
sceKernelDelayThread(300 * 1000);
|
2016-09-20 14:18:24 +00:00
|
|
|
} while (state);
|
|
|
|
|
2017-02-12 15:27:43 +00:00
|
|
|
int ret = 0;
|
|
|
|
res = scePromoterUtilityGetResult(&ret);
|
2016-09-20 14:18:24 +00:00
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
res = scePromoterUtilityExit();
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
2017-02-12 15:27:43 +00:00
|
|
|
return ret;
|
2016-09-20 14:18:24 +00:00
|
|
|
}
|
|
|
|
|
2017-02-12 15:27:43 +00:00
|
|
|
static void fpkg_hmac(const uint8_t *data, unsigned int len, uint8_t hmac[16]) {
|
2016-08-06 06:59:41 +00:00
|
|
|
SHA1_CTX ctx;
|
|
|
|
uint8_t sha1[20];
|
|
|
|
uint8_t buf[64];
|
|
|
|
|
|
|
|
sha1_init(&ctx);
|
|
|
|
sha1_update(&ctx, data, len);
|
|
|
|
sha1_final(&ctx, sha1);
|
|
|
|
|
|
|
|
memset(buf, 0, 64);
|
|
|
|
memcpy(&buf[0], &sha1[4], 8);
|
|
|
|
memcpy(&buf[8], &sha1[4], 8);
|
|
|
|
memcpy(&buf[16], &sha1[12], 4);
|
|
|
|
buf[20] = sha1[16];
|
|
|
|
buf[21] = sha1[1];
|
|
|
|
buf[22] = sha1[2];
|
|
|
|
buf[23] = sha1[3];
|
|
|
|
memcpy(&buf[24], &buf[16], 8);
|
|
|
|
|
|
|
|
sha1_init(&ctx);
|
|
|
|
sha1_update(&ctx, buf, 64);
|
|
|
|
sha1_final(&ctx, sha1);
|
|
|
|
memcpy(hmac, sha1, 16);
|
|
|
|
}
|
|
|
|
|
|
|
|
int makeHeadBin() {
|
|
|
|
uint8_t hmac[16];
|
|
|
|
uint32_t off;
|
|
|
|
uint32_t len;
|
|
|
|
uint32_t out;
|
|
|
|
|
2016-09-05 20:05:05 +00:00
|
|
|
// Read param.sfo
|
|
|
|
void *sfo_buffer = NULL;
|
|
|
|
int res = allocateReadFile(PACKAGE_DIR "/sce_sys/param.sfo", &sfo_buffer);
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
2016-08-06 06:59:41 +00:00
|
|
|
// Get title id
|
2016-09-05 20:05:05 +00:00
|
|
|
char titleid[12];
|
2016-09-07 17:19:07 +00:00
|
|
|
memset(titleid, 0, sizeof(titleid));
|
2016-09-05 20:05:05 +00:00
|
|
|
getSfoString(sfo_buffer, "TITLE_ID", titleid, sizeof(titleid));
|
2016-09-07 17:19:07 +00:00
|
|
|
|
|
|
|
// Enforce TITLE_ID format
|
|
|
|
if (strlen(titleid) != 9)
|
2016-12-19 22:00:37 +00:00
|
|
|
return -1;
|
2016-08-06 06:59:41 +00:00
|
|
|
|
2016-09-07 17:19:07 +00:00
|
|
|
// Get content id
|
|
|
|
char contentid[48];
|
|
|
|
memset(contentid, 0, sizeof(contentid));
|
|
|
|
getSfoString(sfo_buffer, "CONTENT_ID", contentid, sizeof(contentid));
|
|
|
|
|
2016-09-05 20:05:05 +00:00
|
|
|
// Free sfo buffer
|
|
|
|
free(sfo_buffer);
|
|
|
|
|
2016-08-06 06:59:41 +00:00
|
|
|
// Allocate head.bin buffer
|
|
|
|
uint8_t *head_bin = malloc(sizeof(base_head_bin));
|
|
|
|
memcpy(head_bin, base_head_bin, sizeof(base_head_bin));
|
|
|
|
|
2016-09-07 17:19:07 +00:00
|
|
|
// Write full title id
|
|
|
|
char full_title_id[48];
|
2016-09-05 20:05:05 +00:00
|
|
|
snprintf(full_title_id, sizeof(full_title_id), "EP9000-%s_00-XXXXXXXXXXXXXXXX", titleid);
|
2016-09-07 17:19:07 +00:00
|
|
|
strncpy((char *)&head_bin[0x30], strlen(contentid) > 0 ? contentid : full_title_id, 48);
|
2016-08-06 06:59:41 +00:00
|
|
|
|
|
|
|
// hmac of pkg header
|
|
|
|
len = ntohl(*(uint32_t *)&head_bin[0xD0]);
|
|
|
|
fpkg_hmac(&head_bin[0], len, hmac);
|
|
|
|
memcpy(&head_bin[len], hmac, 16);
|
|
|
|
|
|
|
|
// hmac of pkg info
|
|
|
|
off = ntohl(*(uint32_t *)&head_bin[0x8]);
|
|
|
|
len = ntohl(*(uint32_t *)&head_bin[0x10]);
|
|
|
|
out = ntohl(*(uint32_t *)&head_bin[0xD4]);
|
|
|
|
fpkg_hmac(&head_bin[off], len - 64, hmac);
|
|
|
|
memcpy(&head_bin[out], hmac, 16);
|
|
|
|
|
|
|
|
// hmac of everything
|
|
|
|
len = ntohl(*(uint32_t *)&head_bin[0xE8]);
|
|
|
|
fpkg_hmac(&head_bin[0], len, hmac);
|
|
|
|
memcpy(&head_bin[len], hmac, 16);
|
|
|
|
|
|
|
|
// Make dir
|
|
|
|
sceIoMkdir(PACKAGE_DIR "/sce_sys/package", 0777);
|
|
|
|
|
|
|
|
// Write head.bin
|
|
|
|
WriteFile(HEAD_BIN, head_bin, sizeof(base_head_bin));
|
|
|
|
|
|
|
|
free(head_bin);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-02-12 15:27:43 +00:00
|
|
|
int installPackage(const char *file) {
|
2016-09-06 16:00:45 +00:00
|
|
|
int res;
|
|
|
|
|
2016-11-06 09:32:47 +00:00
|
|
|
// Recursively clean up pkg directory
|
|
|
|
removePath(PACKAGE_DIR, NULL);
|
2016-09-06 16:00:45 +00:00
|
|
|
|
|
|
|
// Open archive
|
|
|
|
res = archiveOpen(file);
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
// Src path
|
|
|
|
char src_path[MAX_PATH_LENGTH];
|
|
|
|
strcpy(src_path, file);
|
|
|
|
addEndSlash(src_path);
|
|
|
|
|
|
|
|
// Extract process
|
2016-09-10 12:35:15 +00:00
|
|
|
res = extractArchivePath(src_path, PACKAGE_DIR "/", NULL);
|
2016-09-06 16:00:45 +00:00
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
// Close archive
|
|
|
|
res = archiveClose();
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
// Make head.bin
|
|
|
|
res = makeHeadBin();
|
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
2016-09-20 14:18:24 +00:00
|
|
|
// Promote app
|
|
|
|
res = promoteApp(PACKAGE_DIR);
|
2016-09-06 16:00:45 +00:00
|
|
|
if (res < 0)
|
|
|
|
return res;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-08-06 06:59:41 +00:00
|
|
|
int install_thread(SceSize args_size, InstallArguments *args) {
|
2016-09-06 16:16:29 +00:00
|
|
|
int res;
|
2016-08-06 06:59:41 +00:00
|
|
|
SceUID thid = -1;
|
2016-09-06 16:16:29 +00:00
|
|
|
char path[MAX_PATH_LENGTH];
|
2016-09-24 07:11:14 +00:00
|
|
|
SceIoStat stat;
|
2016-09-24 07:18:18 +00:00
|
|
|
int isFolder = 0;
|
2016-08-06 06:59:41 +00:00
|
|
|
|
2016-08-23 15:38:31 +00:00
|
|
|
// Lock power timers
|
|
|
|
powerLock();
|
|
|
|
|
2016-09-06 16:00:45 +00:00
|
|
|
// Set progress to 0%
|
|
|
|
sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 0);
|
|
|
|
sceKernelDelayThread(DIALOG_WAIT); // Needed to see the percentage
|
2016-08-06 06:59:41 +00:00
|
|
|
|
2016-11-06 09:32:47 +00:00
|
|
|
// Recursively clean up pkg directory
|
|
|
|
removePath(PACKAGE_DIR, NULL);
|
2016-08-06 06:59:41 +00:00
|
|
|
|
2016-09-24 07:11:14 +00:00
|
|
|
res = sceIoGetstat(args->file, &stat);
|
2016-08-06 06:59:41 +00:00
|
|
|
if (res < 0) {
|
2016-09-06 16:00:45 +00:00
|
|
|
closeWaitDialog();
|
|
|
|
errorDialog(res);
|
2016-08-06 06:59:41 +00:00
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
|
2016-09-24 07:11:14 +00:00
|
|
|
if (SCE_S_ISDIR(stat.st_mode)) {
|
|
|
|
// Check for param.sfo
|
|
|
|
snprintf(path, MAX_PATH_LENGTH, "%s/sce_sys/param.sfo", args->file);
|
|
|
|
if (sceIoGetstat(path, &stat) < 0 || SCE_S_ISDIR(stat.st_mode)) {
|
|
|
|
closeWaitDialog();
|
|
|
|
errorDialog(-2);
|
|
|
|
goto EXIT;
|
|
|
|
}
|
2016-09-13 21:09:47 +00:00
|
|
|
|
2016-09-24 07:11:14 +00:00
|
|
|
// Check permissions
|
|
|
|
snprintf(path, MAX_PATH_LENGTH, "%s/eboot.bin", args->file);
|
|
|
|
SceUID fd = sceIoOpen(path, SCE_O_RDONLY, 0);
|
|
|
|
if (fd >= 0) {
|
|
|
|
char buffer[0x88];
|
|
|
|
sceIoRead(fd, buffer, sizeof(buffer));
|
|
|
|
sceIoClose(fd);
|
|
|
|
|
|
|
|
// Team molecule's request: Full permission access warning
|
|
|
|
uint64_t authid = *(uint64_t *)(buffer + 0x80);
|
2016-12-19 21:54:53 +00:00
|
|
|
if (authid != 0x2F00000000000002) {
|
2016-09-24 07:11:14 +00:00
|
|
|
closeWaitDialog();
|
2016-09-06 16:16:29 +00:00
|
|
|
|
2016-09-24 07:11:14 +00:00
|
|
|
initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[INSTALL_WARNING]);
|
2017-02-24 17:42:34 +00:00
|
|
|
setDialogStep(DIALOG_STEP_INSTALL_WARNING);
|
2016-09-24 07:11:14 +00:00
|
|
|
|
|
|
|
// Wait for response
|
2017-02-24 17:42:34 +00:00
|
|
|
while (getDialogStep() == DIALOG_STEP_INSTALL_WARNING) {
|
2016-09-24 07:11:14 +00:00
|
|
|
sceKernelDelayThread(10 * 1000);
|
|
|
|
}
|
2016-09-04 14:41:00 +00:00
|
|
|
|
2016-09-24 07:11:14 +00:00
|
|
|
// Cancelled
|
2017-02-24 17:42:34 +00:00
|
|
|
if (getDialogStep() == DIALOG_STEP_CANCELLED) {
|
2016-09-24 07:11:14 +00:00
|
|
|
closeWaitDialog();
|
|
|
|
goto EXIT;
|
|
|
|
}
|
2016-09-04 14:41:00 +00:00
|
|
|
|
2016-09-24 07:11:14 +00:00
|
|
|
// Init again
|
|
|
|
initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[INSTALLING]);
|
2017-02-24 17:42:34 +00:00
|
|
|
setDialogStep(DIALOG_STEP_INSTALLING);
|
2016-09-06 16:00:45 +00:00
|
|
|
}
|
2016-09-24 07:11:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
res = sceIoRename(args->file, PACKAGE_DIR);
|
|
|
|
if (res < 0) {
|
|
|
|
closeWaitDialog();
|
2017-02-24 17:42:34 +00:00
|
|
|
setDialogStep(DIALOG_STEP_CANCELLED);
|
2016-09-24 07:11:14 +00:00
|
|
|
errorDialog(res);
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 50);
|
|
|
|
sceKernelDelayThread(COUNTUP_WAIT);
|
2016-09-24 07:18:18 +00:00
|
|
|
|
|
|
|
isFolder = 1;
|
2016-09-24 07:11:14 +00:00
|
|
|
} else {
|
|
|
|
// Open archive
|
|
|
|
res = archiveOpen(args->file);
|
|
|
|
if (res < 0) {
|
|
|
|
closeWaitDialog();
|
|
|
|
errorDialog(res);
|
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
// If you cancelled at the time archiveOpen was working,
|
|
|
|
// it would still open the full permission dialog instead of termiating.
|
|
|
|
// So terminate now
|
|
|
|
if (cancelHandler()) {
|
|
|
|
closeWaitDialog();
|
2017-02-24 17:42:34 +00:00
|
|
|
setDialogStep(DIALOG_STEP_CANCELLED);
|
2016-09-24 07:11:14 +00:00
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check for param.sfo
|
|
|
|
snprintf(path, MAX_PATH_LENGTH, "%s/sce_sys/param.sfo", args->file);
|
|
|
|
if (archiveFileGetstat(path, NULL) < 0) {
|
|
|
|
closeWaitDialog();
|
|
|
|
errorDialog(-2);
|
|
|
|
goto EXIT;
|
|
|
|
}
|
2016-09-04 14:41:00 +00:00
|
|
|
|
2016-10-15 09:53:10 +00:00
|
|
|
// Team molecule's request: Full permission access warning
|
2016-10-27 18:17:20 +00:00
|
|
|
int unsafe = archiveCheckFilesForUnsafeFself(); // 0: Safe, 1: Unsafe, 2: Dangerous
|
|
|
|
if (unsafe) {
|
2016-10-15 09:53:10 +00:00
|
|
|
closeWaitDialog();
|
2016-09-24 07:11:14 +00:00
|
|
|
|
2016-10-27 18:17:20 +00:00
|
|
|
initMessageDialog(SCE_MSG_DIALOG_BUTTON_TYPE_YESNO, language_container[unsafe == 2 ? INSTALL_BRICK_WARNING : INSTALL_WARNING]);
|
2017-02-24 17:42:34 +00:00
|
|
|
setDialogStep(DIALOG_STEP_INSTALL_WARNING);
|
2016-09-24 07:11:14 +00:00
|
|
|
|
2016-10-15 09:53:10 +00:00
|
|
|
// Wait for response
|
2017-02-24 17:42:34 +00:00
|
|
|
while (getDialogStep() == DIALOG_STEP_INSTALL_WARNING) {
|
2016-10-15 09:53:10 +00:00
|
|
|
sceKernelDelayThread(10 * 1000);
|
|
|
|
}
|
2016-09-24 07:11:14 +00:00
|
|
|
|
2016-10-15 09:53:10 +00:00
|
|
|
// Cancelled
|
2017-02-24 17:42:34 +00:00
|
|
|
if (getDialogStep() == DIALOG_STEP_CANCELLED) {
|
2016-10-15 09:53:10 +00:00
|
|
|
closeWaitDialog();
|
|
|
|
goto EXIT;
|
2016-09-24 07:11:14 +00:00
|
|
|
}
|
2016-10-15 09:53:10 +00:00
|
|
|
|
|
|
|
// Init again
|
|
|
|
initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[INSTALLING]);
|
2017-02-24 17:42:34 +00:00
|
|
|
setDialogStep(DIALOG_STEP_INSTALLING);
|
2016-08-27 17:16:39 +00:00
|
|
|
}
|
|
|
|
|
2016-09-24 07:11:14 +00:00
|
|
|
// Src path
|
|
|
|
char src_path[MAX_PATH_LENGTH];
|
|
|
|
strcpy(src_path, args->file);
|
|
|
|
addEndSlash(src_path);
|
2016-08-06 06:59:41 +00:00
|
|
|
|
2016-09-24 07:11:14 +00:00
|
|
|
// Get archive path info
|
|
|
|
uint64_t size = 0;
|
|
|
|
uint32_t folders = 0, files = 0;
|
|
|
|
getArchivePathInfo(src_path, &size, &folders, &files);
|
2016-09-06 16:00:45 +00:00
|
|
|
|
2016-09-24 07:11:14 +00:00
|
|
|
// Check memory card free space
|
|
|
|
if (checkMemoryCardFreeSpace(size))
|
|
|
|
goto EXIT;
|
2016-09-12 20:34:03 +00:00
|
|
|
|
2016-09-24 07:11:14 +00:00
|
|
|
// Update thread
|
2017-02-25 09:27:52 +00:00
|
|
|
thid = createStartUpdateThread(size + folders*DIRECTORY_SIZE, 1);
|
2016-09-05 20:19:46 +00:00
|
|
|
|
2016-09-24 07:11:14 +00:00
|
|
|
// Extract process
|
|
|
|
uint64_t value = 0;
|
2016-09-10 12:35:15 +00:00
|
|
|
|
2016-09-24 07:11:14 +00:00
|
|
|
FileProcessParam param;
|
|
|
|
param.value = &value;
|
2016-10-25 08:43:10 +00:00
|
|
|
param.max = size + folders * DIRECTORY_SIZE;
|
2016-09-24 07:11:14 +00:00
|
|
|
param.SetProgress = SetProgress;
|
|
|
|
param.cancelHandler = cancelHandler;
|
2016-09-10 12:35:15 +00:00
|
|
|
|
2016-09-24 07:11:14 +00:00
|
|
|
res = extractArchivePath(src_path, PACKAGE_DIR "/", ¶m);
|
|
|
|
if (res <= 0) {
|
|
|
|
closeWaitDialog();
|
2017-02-24 17:42:34 +00:00
|
|
|
setDialogStep(DIALOG_STEP_CANCELLED);
|
2016-09-24 07:11:14 +00:00
|
|
|
errorDialog(res);
|
|
|
|
goto EXIT;
|
|
|
|
}
|
2016-08-06 06:59:41 +00:00
|
|
|
|
2016-09-24 07:11:14 +00:00
|
|
|
// Close archive
|
|
|
|
res = archiveClose();
|
|
|
|
if (res < 0) {
|
|
|
|
closeWaitDialog();
|
|
|
|
errorDialog(res);
|
|
|
|
goto EXIT;
|
|
|
|
}
|
2016-09-05 20:19:46 +00:00
|
|
|
}
|
|
|
|
|
2016-08-06 06:59:41 +00:00
|
|
|
// Make head.bin
|
|
|
|
res = makeHeadBin();
|
|
|
|
if (res < 0) {
|
2016-09-06 16:00:45 +00:00
|
|
|
closeWaitDialog();
|
|
|
|
errorDialog(res);
|
2016-09-24 07:18:18 +00:00
|
|
|
// If failed, move package folder back
|
|
|
|
if (isFolder) sceIoRename(PACKAGE_DIR, args->file);
|
2016-08-06 06:59:41 +00:00
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
|
2016-09-20 14:18:24 +00:00
|
|
|
// Promote app
|
|
|
|
res = promoteApp(PACKAGE_DIR);
|
2016-08-06 06:59:41 +00:00
|
|
|
if (res < 0) {
|
2016-09-06 16:00:45 +00:00
|
|
|
closeWaitDialog();
|
|
|
|
errorDialog(res);
|
2016-09-24 07:18:18 +00:00
|
|
|
// If failed, move package folder back
|
|
|
|
if (isFolder) sceIoRename(PACKAGE_DIR, args->file);
|
2016-08-06 06:59:41 +00:00
|
|
|
goto EXIT;
|
|
|
|
}
|
|
|
|
|
2016-09-06 16:00:45 +00:00
|
|
|
// Set progress to 100%
|
|
|
|
sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 100);
|
|
|
|
sceKernelDelayThread(COUNTUP_WAIT);
|
2016-08-06 06:59:41 +00:00
|
|
|
|
2016-09-06 16:00:45 +00:00
|
|
|
// Close
|
|
|
|
sceMsgDialogClose();
|
2016-08-06 06:59:41 +00:00
|
|
|
|
2017-02-24 17:42:34 +00:00
|
|
|
setDialogStep(DIALOG_STEP_INSTALLED);
|
2016-09-04 14:41:00 +00:00
|
|
|
|
2016-08-06 06:59:41 +00:00
|
|
|
EXIT:
|
|
|
|
if (thid >= 0)
|
|
|
|
sceKernelWaitThreadEnd(thid, NULL, NULL);
|
|
|
|
|
2016-09-12 20:34:03 +00:00
|
|
|
// Recursively clean up package_temp directory
|
2016-11-06 09:32:47 +00:00
|
|
|
removePath(PACKAGE_DIR, NULL);
|
2016-09-12 20:34:03 +00:00
|
|
|
|
2016-08-23 15:38:31 +00:00
|
|
|
// Unlock power timers
|
|
|
|
powerUnlock();
|
|
|
|
|
2016-09-06 16:00:45 +00:00
|
|
|
return sceKernelExitDeleteThread(0);
|
2016-09-21 18:07:07 +00:00
|
|
|
}
|