mirror of
https://github.com/ApfelTeeSaft/Itemzflow.git
synced 2026-08-27 03:33:39 +00:00
- Fixed dumping DLCs and AC w/p data - Added an Install all PKGs option for folders with more than 1 PKG - Installing a PKG will no longer boot you back to settings - Carried over some improvements from the PS5 version of IF - Replaced reg. vectors for ThreadSafeVectors - Added the Chinese lang files - Fixed a bug that would cause the Utility thread to deadlock - Fixed a Bug that caused the daemon not to give a backtrace on 9.00
374 lines
10 KiB
C++
374 lines
10 KiB
C++
#include "utils.h"
|
|
#include <stdarg.h>
|
|
#include <installpkg.h>
|
|
#include <stdbool.h>
|
|
#include "defines.h"
|
|
#include <string>
|
|
|
|
extern std::string tmp;
|
|
|
|
int PKG_ERROR(const char* name, int ret)
|
|
{
|
|
msgok(MSG_DIALOG::WARNING, fmt::format("{0:}\nHEX: {1:#x} Int: {2:d}\n{3:}", getLangSTR(LANG_STR::INSTALL_FAILED), ret, ret, name));
|
|
log_error( "%s error: %x", name, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
/* we use bgft heap menagement as init/fini as flatz already shown at
|
|
* https://github.com/flatz/ps4_remote_pkg_installer/blob/master/installer.c
|
|
*/
|
|
|
|
#define BGFT_HEAP_SIZE (1 * 1024 * 1024)
|
|
|
|
extern bool sceAppInst_done;
|
|
static bool s_bgft_initialized = false;
|
|
static struct bgft_init_params s_bgft_init_params;
|
|
|
|
bool app_inst_util_init(void) {
|
|
int ret;
|
|
|
|
if (sceAppInst_done) {
|
|
goto done;
|
|
}
|
|
|
|
ret = sceAppInstUtilInitialize();
|
|
if (ret) {
|
|
log_debug( "sceAppInstUtilInitialize failed: 0x%08X", ret);
|
|
goto err;
|
|
}
|
|
|
|
sceAppInst_done = true;
|
|
|
|
done:
|
|
return true;
|
|
|
|
err:
|
|
sceAppInst_done = false;
|
|
|
|
return false;
|
|
}
|
|
|
|
void app_inst_util_fini(void) {
|
|
int ret;
|
|
|
|
if (!sceAppInst_done) {
|
|
return;
|
|
}
|
|
|
|
ret = sceAppInstUtilTerminate();
|
|
if (ret) {
|
|
log_debug( "sceAppInstUtilTerminate failed: 0x%08X", ret);
|
|
}
|
|
|
|
sceAppInst_done = false;
|
|
}
|
|
|
|
bool bgft_init(void) {
|
|
int ret;
|
|
|
|
if (s_bgft_initialized) {
|
|
goto done;
|
|
}
|
|
|
|
memset(&s_bgft_init_params, 0, sizeof(s_bgft_init_params));
|
|
{
|
|
s_bgft_init_params.heapSize = BGFT_HEAP_SIZE;
|
|
s_bgft_init_params.heap = (uint8_t*)malloc(s_bgft_init_params.heapSize);
|
|
if (!s_bgft_init_params.heap) {
|
|
log_debug( "No memory for BGFT heap.");
|
|
goto err;
|
|
}
|
|
memset(s_bgft_init_params.heap, 0, s_bgft_init_params.heapSize);
|
|
}
|
|
|
|
ret = sceBgftServiceInit(&s_bgft_init_params);
|
|
if (ret) {
|
|
log_debug( "sceBgftInitialize failed: 0x%08X", ret);
|
|
goto err_bgft_heap_free;
|
|
}
|
|
|
|
s_bgft_initialized = true;
|
|
|
|
done:
|
|
return true;
|
|
|
|
err_bgft_heap_free:
|
|
if (s_bgft_init_params.heap) {
|
|
free(s_bgft_init_params.heap);
|
|
s_bgft_init_params.heap = NULL;
|
|
}
|
|
|
|
memset(&s_bgft_init_params, 0, sizeof(s_bgft_init_params));
|
|
|
|
err:
|
|
s_bgft_initialized = false;
|
|
|
|
return false;
|
|
}
|
|
|
|
void bgft_fini(void) {
|
|
int ret;
|
|
|
|
if (!s_bgft_initialized) {
|
|
return;
|
|
}
|
|
|
|
ret = sceBgftServiceTerm();
|
|
if (ret) {
|
|
log_debug( "sceBgftServiceTerm failed: 0x%08X", ret);
|
|
}
|
|
|
|
if (s_bgft_init_params.heap) {
|
|
free(s_bgft_init_params.heap);
|
|
s_bgft_init_params.heap = NULL;
|
|
}
|
|
|
|
memset(&s_bgft_init_params, 0, sizeof(s_bgft_init_params));
|
|
|
|
s_bgft_initialized = false;
|
|
}
|
|
|
|
bool app_inst_util_is_exists(const char* title_id, bool* exists) {
|
|
int flag;
|
|
|
|
if (!title_id) return false;
|
|
|
|
if (!sceAppInst_done) {
|
|
log_debug("Starting app_inst_util_init..");
|
|
if (!app_inst_util_init()) {
|
|
log_error("app_inst_util_init has failed...");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
int ret = sceAppInstUtilAppExists(title_id, &flag);
|
|
if (ret) {
|
|
log_error("sceAppInstUtilAppExists failed: 0x%08X\n", ret);
|
|
return false;
|
|
}
|
|
|
|
if (exists) *exists = flag;
|
|
|
|
return true;
|
|
}
|
|
|
|
/* sample ends */
|
|
/* install package wrapper:
|
|
init, (install), then clean AppInstUtil and BGFT
|
|
for next install */
|
|
extern bool Download_icons;
|
|
|
|
bool pkg_is_patch(const char* src_dest) {
|
|
|
|
// Read PKG header
|
|
struct pkg_header hdr;
|
|
static const uint8_t magic[] = { '\x7F', 'C', 'N', 'T' };
|
|
// Open path
|
|
int pkg = sceKernelOpen(src_dest, O_RDONLY, 0);
|
|
if (pkg < 0) return false;
|
|
|
|
sceKernelLseek(pkg, 0, SEEK_SET);
|
|
sceKernelRead(pkg, &hdr, sizeof(struct pkg_header));
|
|
|
|
sceKernelClose(pkg);
|
|
|
|
if (memcmp(hdr.magic, magic, sizeof(magic)) != 0) {
|
|
log_error("PKG Format is wrong");
|
|
return false;
|
|
}
|
|
|
|
unsigned int flags = BE32(hdr.content_flags);
|
|
|
|
if (flags & PKG_CONTENT_FLAGS_FIRST_PATCH || flags & PKG_CONTENT_FLAGS_SUBSEQUENT_PATCH ||
|
|
flags & PKG_CONTENT_FLAGS_DELTA_PATCH || flags & PKG_CONTENT_FLAGS_CUMULATIVE_PATCH)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void *install_prog(void* argument)
|
|
{
|
|
struct install_args* args = (install_args*)argument;
|
|
SceBgftTaskProgress progress_info;
|
|
bool is_threaded = args->is_thread;
|
|
|
|
tmp = fmt::format("{0:.60}\n\n{1:} {2:d}/{3:d}", args->fname, getLangSTR(LANG_STR::INSTALLING), args->curr_pkg, args->max_pkgs);
|
|
|
|
if (!is_threaded)
|
|
progstart(tmp.c_str());
|
|
else
|
|
log_info("Starting PKG Install");
|
|
|
|
int prog = 0;
|
|
while (prog < 100)
|
|
{
|
|
memset(&progress_info, 0, sizeof(progress_info));
|
|
|
|
int ret = sceBgftServiceDownloadGetProgress(args->task_id, &progress_info);
|
|
if (ret)
|
|
return (void *)(intptr_t)PKG_ERROR("sceBgftDownloadGetProgress", ret);
|
|
|
|
if (progress_info.transferred > 0 && progress_info.error_result != 0) {
|
|
|
|
if (!is_threaded)
|
|
return (void *)(intptr_t)PKG_ERROR("BGFT_ERROR", progress_info.error_result);
|
|
else
|
|
{
|
|
log_error("BGFT_ERROR error: %x", progress_info.error_result);
|
|
return NULL;
|
|
}
|
|
|
|
}
|
|
|
|
prog = (uint32_t)(((float)progress_info.transferred / progress_info.length) * 100.f);
|
|
|
|
|
|
if (!is_threaded)
|
|
ProgSetMessagewText(prog, tmp.c_str());
|
|
|
|
if (progress_info.transferred % (4096 * 128) == 0){
|
|
log_debug("%s, Install_Thread: reading data, %lub / %lub (%%%i) ERR: %i", __FUNCTION__, progress_info.transferred, progress_info.length, prog, progress_info.error_result);
|
|
// log_debug("ERR: %llu %llu %llu %llu", progress_info.transferred, progress_info.transferredTotal, progress_info.length, progress_info.lengthTotal);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
if (progress_info.error_result == 0) {
|
|
if (!is_threaded) {
|
|
if(args->curr_pkg >= args->max_pkgs)
|
|
sceMsgDialogTerminate();
|
|
|
|
ani_notify(NOTIFI::GAME, getLangSTR(LANG_STR::PKG_INST_SUCCESS), fmt::format("{0:}", args->title_id));
|
|
}
|
|
if(args->delete_pkg)
|
|
unlink(args->path);
|
|
}
|
|
else {
|
|
if (!is_threaded) {
|
|
sceMsgDialogTerminate();
|
|
ani_notify(NOTIFI::WARNING, getLangSTR(LANG_STR::PKG_INST_FAILED),fmt::format("{0:#x}", progress_info.error_result));
|
|
msgok(MSG_DIALOG::WARNING, fmt::format("{0:} {1:} {2:} {3:#X}", getLangSTR(LANG_STR::INSTALL_OF), args->title_id, getLangSTR(LANG_STR::INSTALL_FAILED), progress_info.error_result));
|
|
}
|
|
else
|
|
log_error("Installation of %s has failed with code 0x%x", args->title_id, progress_info.error_result);
|
|
}
|
|
|
|
log_info("Finalizing Memory...");
|
|
free(args->title_id);
|
|
free(args->path);
|
|
free(args->fname);
|
|
free(args);
|
|
bgft_fini();
|
|
|
|
if(is_threaded)
|
|
pthread_exit(NULL);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
uint32_t pkginstall(const char *fullpath, const char* filename,
|
|
bool Show_install_prog, bool delete_pkg_after, int max_pkgs, int curr_pkg )
|
|
{
|
|
char title_id[16];
|
|
int is_app, ret = -1;
|
|
int task_id = -1;
|
|
bool is_app_exists = false;
|
|
std::string tmp;
|
|
|
|
if( if_exists(fullpath) )
|
|
{
|
|
if (sceAppInst_done) {
|
|
log_info("Initializing AppInstUtil...");
|
|
|
|
if (!app_inst_util_init())
|
|
return PKG_ERROR("AppInstUtil", ret);
|
|
}
|
|
|
|
log_info("Initializing BGFT...");
|
|
if (!bgft_init()) {
|
|
return PKG_ERROR("BGFT_initialization", ret);
|
|
}
|
|
|
|
ret = sceAppInstUtilGetTitleIdFromPkg(fullpath, title_id, &is_app);
|
|
if (ret)
|
|
return PKG_ERROR("sceAppInstUtilGetTitleIdFromPkg", ret);
|
|
|
|
if(pkg_is_patch(fullpath) && app_inst_util_is_exists(title_id, &is_app_exists) && !is_app_exists)
|
|
return PKG_ERROR("BASE_GAME_NOT_INSTALLED", ret);
|
|
|
|
|
|
tmp = fmt::format("ItemzFlow: {}", title_id);
|
|
struct bgft_download_param_ex download_params;
|
|
memset(&download_params, 0, sizeof(download_params));
|
|
download_params.param.entitlement_type = 5;
|
|
download_params.param.id = "";
|
|
download_params.param.content_url = fullpath;
|
|
download_params.param.content_name = tmp.c_str();
|
|
download_params.param.icon_path = "/update/fakepic.png";
|
|
download_params.param.playgo_scenario_id = "0";
|
|
if(Show_install_prog)
|
|
download_params.param.option = BGFT_TASK_OPTION_INVISIBLE;
|
|
else
|
|
download_params.param.option = BGFT_TASK_OPTION_DISABLE_CDN_QUERY_PARAM;
|
|
|
|
download_params.slot = 0;
|
|
|
|
retry:
|
|
log_info("%s 1", __FUNCTION__);
|
|
ret = sceBgftServiceIntDownloadRegisterTaskByStorageEx(&download_params, &task_id);
|
|
if(ret == 0x80990088 || ret == 0x80990015)
|
|
{
|
|
if(Confirmation_Msg(getLangSTR(LANG_STR::REINSTALL_APP_CONFIRMATION)) == YES){
|
|
ret = sceAppInstUtilAppUnInstall(&title_id[0]);
|
|
if(ret != 0)
|
|
return PKG_ERROR("sceAppInstUtilAppUnInstall", ret);
|
|
|
|
goto retry;
|
|
}
|
|
else
|
|
return PKG_ERROR("APP_ALREADY_EXISTS", ret);
|
|
}
|
|
else if(ret)
|
|
return PKG_ERROR("sceBgftServiceIntDownloadRegisterTaskByStorageEx", ret);
|
|
|
|
|
|
log_info("Task ID(s): 0x%08X", task_id);
|
|
|
|
ret = sceBgftServiceDownloadStartTask(task_id);
|
|
if(ret)
|
|
return PKG_ERROR("sceBgftDownloadStartTask", ret);
|
|
}
|
|
else//bgft_download_get_task_progress
|
|
return PKG_ERROR("no file at", ret);
|
|
|
|
|
|
struct install_args* args = (struct install_args*)malloc(sizeof(struct install_args));
|
|
args->title_id = strdup(title_id);
|
|
args->task_id = task_id;
|
|
// args->size = size;
|
|
args->path = strdup(fullpath);
|
|
args->fname = strdup(filename);
|
|
args->is_thread = !Show_install_prog;
|
|
args->delete_pkg = delete_pkg_after;
|
|
args->max_pkgs = max_pkgs;
|
|
args->curr_pkg = curr_pkg;
|
|
|
|
if (Show_install_prog){
|
|
install_prog((void*)args);
|
|
}
|
|
else {
|
|
pthread_t thread = 0;
|
|
ret = pthread_create(&thread, NULL, install_prog, (void*)args);
|
|
log_debug("pthread_create for %x, ret:%d", task_id, ret);
|
|
|
|
return 0;
|
|
}
|
|
|
|
log_info( "%s(%s) done.", __FUNCTION__, fullpath);
|
|
|
|
return 0;
|
|
} |