From d7de7edebe84e5e7c8c70e894dde52188da0a31e Mon Sep 17 00:00:00 2001 From: TheRadziu Date: Thu, 22 Nov 2018 08:56:12 +0100 Subject: [PATCH] Finished "Refresh LiveArea" function rework, added patches support (#515) * Changed how content type is determined Also added some code related to non-working (at this moment) theme promotion * revoked code related to theme promotion I give up, can't continue with the undocumented scePromoterUtilityPromotePkgWithRif error. * Added PoC Patch refresh code Note: right now it does not check if installed app_ver == patch app_ver, so it promotes ALL patches for installed titles. * Move pfs related functions to pfs.c/pfs.h * Reverted some unintended changes * Cleaned up debug prints * Cleaned up unused PFS code * Patch refresh PoC v2 * Fixed Misplaced pfsUmount() * Removed rest of the debug prints, feature is now fully functional --- CMakeLists.txt | 1 + browser.c | 1 + main.c | 1 + main_context.c | 84 +----------------------------------------- main_context.h | 5 --- pfs.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++ pfs.h | 30 +++++++++++++++ refresh.c | 72 +++++++++++++++++++++++++++++++++--- 8 files changed, 200 insertions(+), 93 deletions(-) create mode 100644 pfs.c create mode 100644 pfs.h diff --git a/CMakeLists.txt b/CMakeLists.txt index fb46b1a..ee4b3b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,7 @@ add_resources(vitashell_res add_executable(VitaShell ${vitashell_res} main.c + pfs.c main_context.c browser.c init.c diff --git a/browser.c b/browser.c index 14935b4..6809ad7 100644 --- a/browser.c +++ b/browser.c @@ -44,6 +44,7 @@ #include "coredump.h" #include "usb.h" #include "qr.h" +#include "pfs.h" // File lists FileList file_list, mark_list, copy_list, install_list; diff --git a/main.c b/main.c index 786262a..e6fd1e0 100644 --- a/main.c +++ b/main.c @@ -46,6 +46,7 @@ #include "coredump.h" #include "usb.h" #include "qr.h" +#include "pfs.h" int _newlib_heap_size_user = 128 * 1024 * 1024; diff --git a/main_context.c b/main_context.c index 15c569d..be0fd5e 100644 --- a/main_context.c +++ b/main_context.c @@ -29,10 +29,7 @@ #include "ime_dialog.h" #include "utils.h" #include "usb.h" - -char pfs_mounted_path[MAX_PATH_LENGTH]; -char pfs_mount_point[MAX_MOUNT_POINT_LENGTH]; -int read_only = 0; +#include "pfs.h" enum MenuHomeEntrys { MENU_HOME_ENTRY_REFRESH_LIVEAREA, @@ -241,85 +238,6 @@ ContextMenu context_menu_new = { .sel = -1, }; -/* - SceAppMgr mount IDs: - 0x64: ux0:picture - 0x65: ur0:user/00/psnfriend - 0x66: ur0:user/00/psnmsg - 0x69: ux0:music - 0x6E: ux0:appmeta - 0xC8: ur0:temp/sqlite - 0xCD: ux0:cache - 0x12E: ur0:user/00/trophy/data/sce_trop - 0x12F: ur0:user/00/trophy/data - 0x3E8: ux0:app, vs0:app, gro0:app - 0x3E9: ux0:patch - 0x3EB: ? - 0x3EA: ux0:addcont - 0x3EC: ux0:theme - 0x3ED: ux0:user/00/savedata - 0x3EE: ur0:user/00/savedata - 0x3EF: vs0:sys/external - 0x3F0: vs0:data/external -*/ - -int known_pfs_ids[] = { - 0x6E, - 0x12E, - 0x12F, - 0x3ED, -}; - -int pfsMount(const char *path) { - int res; - char work_path[MAX_PATH_LENGTH]; - char klicensee[0x10]; - char license_buf[0x200]; - ShellMountIdArgs args; - - memset(klicensee, 0, sizeof(klicensee)); - -/* - snprintf(work_path, MAX_PATH_LENGTH, "%ssce_sys/package/work.bin", path); - if (ReadFile(work_path, license_buf, sizeof(license_buf)) == sizeof(license_buf)) { - int res = shellUserGetRifVitaKey(license_buf, klicensee); - debugPrintf("read license: 0x%08X\n", res); - } -*/ - args.process_titleid = VITASHELL_TITLEID; - args.path = path; - args.desired_mount_point = NULL; - args.klicensee = klicensee; - args.mount_point = pfs_mount_point; - - read_only = 0; - - int i; - for (i = 0; i < sizeof(known_pfs_ids) / sizeof(int); i++) { - args.id = known_pfs_ids[i]; - - res = shellUserMountById(&args); - if (res >= 0) - return res; - } - - read_only = 1; - return sceAppMgrGameDataMount(path, 0, 0, pfs_mount_point); -} - -int pfsUmount() { - if (pfs_mount_point[0] == 0) - return -1; - - int res = sceAppMgrUmount(pfs_mount_point); - if (res >= 0) { - memset(pfs_mount_point, 0, sizeof(pfs_mount_point)); - memset(pfs_mounted_path, 0, sizeof(pfs_mounted_path)); - } - - return res; -} - void initContextMenuWidth() { int i; diff --git a/main_context.h b/main_context.h index 94d349d..d52be97 100644 --- a/main_context.h +++ b/main_context.h @@ -21,16 +21,11 @@ #include "context_menu.h" -extern char pfs_mounted_path[MAX_PATH_LENGTH]; - extern ContextMenu context_menu_home; extern ContextMenu context_menu_main; extern ContextMenu context_menu_sort; extern ContextMenu context_menu_more; -int pfsMount(const char *path); -int pfsUmount(); - void initContextMenuWidth(); void setContextMenuHomeVisibilities(); void setContextMenuMainVisibilities(); diff --git a/pfs.c b/pfs.c new file mode 100644 index 0000000..b162a10 --- /dev/null +++ b/pfs.c @@ -0,0 +1,99 @@ +/* + VitaShell + Copyright (C) 2015-2018, TheFloW + + 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 . +*/ + +#include "main.h" +#include "pfs.h" + +/* + SceAppMgr mount IDs: + 0x64: ux0:picture + 0x65: ur0:user/00/psnfriend + 0x66: ur0:user/00/psnmsg + 0x69: ux0:music + 0x6E: ux0:appmeta + 0xC8: ur0:temp/sqlite + 0xCD: ux0:cache + 0x12E: ur0:user/00/trophy/data/sce_trop + 0x12F: ur0:user/00/trophy/data + 0x3E8: ux0:app, vs0:app, gro0:app + 0x3E9: ux0:patch + 0x3EB: ? + 0x3EA: ux0:addcont + 0x3EC: ux0:theme + 0x3ED: ux0:user/00/savedata + 0x3EE: ur0:user/00/savedata + 0x3EF: vs0:sys/external + 0x3F0: vs0:data/external +*/ + +int known_pfs_ids[] = { + 0x6E, + 0x12E, + 0x12F, + 0x3ED, +}; + +int pfsMount(const char *path) { + int res; + char work_path[MAX_PATH_LENGTH]; + char klicensee[0x10]; + char license_buf[0x200]; + ShellMountIdArgs args; + + memset(klicensee, 0, sizeof(klicensee)); + +/* + snprintf(work_path, MAX_PATH_LENGTH, "%ssce_sys/package/work.bin", path); + if (ReadFile(work_path, license_buf, sizeof(license_buf)) == sizeof(license_buf)) { + int res = shellUserGetRifVitaKey(license_buf, klicensee); + debugPrintf("read license: 0x%08X\n", res); + } +*/ + args.process_titleid = VITASHELL_TITLEID; + args.path = path; + args.desired_mount_point = NULL; + args.klicensee = klicensee; + args.mount_point = pfs_mount_point; + + read_only = 0; + + int i; + for (i = 0; i < sizeof(known_pfs_ids) / sizeof(int); i++) { + args.id = known_pfs_ids[i]; + + res = shellUserMountById(&args); + if (res >= 0) + return res; + } + + read_only = 1; + return sceAppMgrGameDataMount(path, 0, 0, pfs_mount_point); +} + +int pfsUmount() { + if (pfs_mount_point[0] == 0) + return -1; + + int res = sceAppMgrUmount(pfs_mount_point); + if (res >= 0) { + memset(pfs_mount_point, 0, sizeof(pfs_mount_point)); + memset(pfs_mounted_path, 0, sizeof(pfs_mounted_path)); + } + + return res; +} \ No newline at end of file diff --git a/pfs.h b/pfs.h new file mode 100644 index 0000000..c1bc491 --- /dev/null +++ b/pfs.h @@ -0,0 +1,30 @@ +/* + VitaShell + Copyright (C) 2015-2018, TheFloW + + 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 . +*/ + +#ifndef __PFS_H__ +#define __PFS_H__ + +char pfs_mounted_path[MAX_PATH_LENGTH]; +char pfs_mount_point[MAX_MOUNT_POINT_LENGTH]; +int read_only; + +int known_pfs_ids[4]; +int pfsMount(const char *path); +int pfsUmount(); + +#endif diff --git a/refresh.c b/refresh.c index 7d213c4..e38f060 100644 --- a/refresh.c +++ b/refresh.c @@ -2,6 +2,7 @@ VitaShell Copyright (C) 2015-2018, TheFloW Copyright (C) 2017, VitaSmith + Copyright (C) 2018, TheRadziu 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 @@ -28,11 +29,13 @@ #include "language.h" #include "utils.h" #include "rif.h" +#include "pfs.h" // Note: The promotion process is *VERY* sensitive to the directories used below // Don't change them unless you know what you are doing! #define APP_TEMP "ux0:temp/app" #define DLC_TEMP "ux0:temp/addcont" +#define PATCH_TEMP "ux0:temp/patch" #define PSM_TEMP "ux0:temp/psm" #define THEME_TEMP "ux0:temp/theme" @@ -55,6 +58,9 @@ int isCustomHomebrew(const char* path) int refreshNeeded(const char *app_path, const char* content_type) { char sfo_path[MAX_PATH_LENGTH]; + char appmeta_path[MAX_PATH_LENGTH]; + char appmeta_param[MAX_PATH_LENGTH]; + int mounted_appmeta; // Read param.sfo snprintf(sfo_path, MAX_PATH_LENGTH, "%s/sce_sys/param.sfo", app_path); @@ -64,15 +70,16 @@ int refreshNeeded(const char *app_path, const char* content_type) return sfo_size; // Get title and content ids - char titleid[12], contentid[50]; + char titleid[12], contentid[50], appver[8]; getSfoString(sfo_buffer, "TITLE_ID", titleid, sizeof(titleid)); getSfoString(sfo_buffer, "CONTENT_ID", contentid, sizeof(contentid)); + getSfoString(sfo_buffer, "APP_VER", appver, sizeof(appver)); // Free sfo buffer free(sfo_buffer); - // Check if app exists - if (checkAppExist(titleid)) { + // Check if app or dlc exists + if (((strcmp(content_type, "app") == 0)||(strcmp(content_type, "dlc") == 0))&&(checkAppExist(titleid))) { char rif_name[48]; uint64_t aid; @@ -96,7 +103,29 @@ int refreshNeeded(const char *app_path, const char* content_type) if (checkFileExist(sfo_path)) return 0; } - + + // Check if patch for installed app exists + else if (strcmp(content_type, "patch") == 0) { + if (!checkAppExist(titleid)) + return 0; + if (checkFileExist(sfo_path)) { + snprintf(appmeta_path, MAX_PATH_LENGTH, "ux0:appmeta/%s", titleid); + pfsUmount(); + if(pfsMount(appmeta_path)<0) + return 0; + //Now read it + snprintf(appmeta_param, MAX_PATH_LENGTH, "ux0:appmeta/%s/param.sfo", titleid); + int sfo_size = allocateReadFile(appmeta_param, &sfo_buffer); + if (sfo_size < 0) + return sfo_size; + char promoted_appver[8]; + getSfoString(sfo_buffer, "APP_VER", promoted_appver, sizeof(promoted_appver)); + pfsUmount(); + //Finally compare it + if (strcmp(appver, promoted_appver) == 0) + return 0; + } + } return 1; } @@ -131,7 +160,7 @@ int refreshApp(const char *app_path) free(sfo_buffer); } - // Promote vita app/vita dlc + // Promote vita app/vita dlc/vita patch (if needed) res = promoteApp(app_path); return (res < 0) ? res : 1; } @@ -274,6 +303,29 @@ void dlc_callback_outer(void* data, const char* dir, const char* subdir) } } +void patch_callback(void* data, const char* dir, const char* subdir) +{ + refresh_data_t *refresh_data = (refresh_data_t*)data; + char path[MAX_PATH_LENGTH]; + + if (refresh_data->refresh_pass) { + snprintf(path, MAX_PATH_LENGTH, "%s/%s", dir, subdir); + if (refreshNeeded(path, "patch")) { + // Move the directory to temp for installation + removePath(PATCH_TEMP, NULL); + sceIoRename(path, PATCH_TEMP); + if (refreshApp(PATCH_TEMP) == 1) + refresh_data->refreshed++; + else + // Restore folder on error + sceIoRename(PATCH_TEMP, path); + } + SetProgress(++refresh_data->processed, refresh_data->count); + } else { + refresh_data->count++; + } +} + int refresh_thread(SceSize args, void *argp) { SceUID thid = -1; @@ -294,12 +346,17 @@ int refresh_thread(SceSize args, void *argp) if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:addcont", dlc_callback_outer, &refresh_data) < 0) goto EXIT; + // Get the patch count + if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:patch", patch_callback, &refresh_data) < 0) + goto EXIT; + // Update thread thid = createStartUpdateThread(refresh_data.count, 0); // Make sure we have the temp directories we need sceIoMkdir("ux0:temp", 0006); sceIoMkdir("ux0:temp/addcont", 0006); + sceIoMkdir("ux0:temp/patch", 0006); refresh_data.refresh_pass = 1; // Refresh apps @@ -309,8 +366,13 @@ int refresh_thread(SceSize args, void *argp) // Refresh dlc if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:addcont", dlc_callback_outer, &refresh_data) < 0) goto EXIT; + + // Refresh patch + if (parse_dir_with_callback(SCE_S_IFDIR, "ux0:patch", patch_callback, &refresh_data) < 0) + goto EXIT; sceIoRmdir("ux0:temp/addcont"); + sceIoRmdir("ux0:temp/patch"); // Set progress to 100% sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 100);