Added ability to open savedatas and trophys decrypted.

This commit is contained in:
TheFloW 2018-03-27 17:15:16 +02:00
parent 6717abf9c6
commit 61b7b03194
17 changed files with 309 additions and 92 deletions

View File

@ -14,7 +14,7 @@ project(VitaShell)
include("${VITASDK}/share/vita.cmake" REQUIRED)
set(VITA_APP_NAME "VitaShell")
set(VITA_TITLEID "VITASHELL")
set(VITA_VERSION "01.83")
set(VITA_VERSION "01.90")
# Flags and includes
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -O3 -Wno-unused-variable -Wno-unused-but-set-variable -Wno-format-truncation -fno-lto")

View File

@ -107,6 +107,10 @@ Credits
Changelog
---------
### Changelog 1.9
- Added ability to open decrypted trophys, savedatas and appmetas.
- Moved `Open Decrypted` entry to main context menu for faster access.
### Changelog 1.83
- Fixed automatic network update by using rawgit. This was needed because github removed support for TLS 1.0/1.1.
- Removed changelog support, because the files at ux0:patch must now be pfs encrypted.

1
init.c
View File

@ -329,6 +329,7 @@ void initVitaShell() {
// Allow writing to ux0:app/VITASHELL
sceAppMgrUmount("app0:");
sceAppMgrUmount("savedata0:");
// Is safe mode
if (sceIoDevctl("ux0:", 0x3001, NULL, 0, NULL, 0) == 0x80010030)

14
main.c
View File

@ -137,7 +137,7 @@ static void dirUp() {
strcmp(file_list.path, pfs_mounted_path) == 0 && // we're about to leave the pfs path
!strstr(copy_list.path, pfs_mounted_path)) { // nothing has been copied from pfs path
// Then umount
gameDataUmount();
pfsUmount();
}
removeEndSlash(file_list.path);
@ -611,8 +611,10 @@ static int dialogSteps() {
fileListEmpty(&copy_list);
// Umount and remove from clipboard after pasting
if (pfs_mounted_path[0] && strstr(copy_list.path, pfs_mounted_path)) {
gameDataUmount();
if (pfs_mounted_path[0] &&
!strstr(file_list.path, pfs_mounted_path) &&
strstr(copy_list.path, pfs_mounted_path)) {
pfsUmount();
fileListEmpty(&copy_list);
}
@ -1713,7 +1715,7 @@ static int shellMain() {
// Refresh on app resume
if (event.systemEvent == SCE_APPMGR_SYSTEMEVENT_ON_RESUME) {
sceShellUtilLock(SCE_SHELL_UTIL_LOCK_TYPE_USB_CONNECTION);
gameDataUmount(); // umount game data at resume
pfsUmount(); // umount game data at resume
refresh = REFRESH_MODE_NORMAL;
}
@ -1931,7 +1933,7 @@ int main(int argc, const char *argv[]) {
readPad();
if (current_pad[PAD_LTRIGGER])
use_custom_config = 0;
// Load settings
loadSettingsConfig();
@ -1944,7 +1946,7 @@ int main(int argc, const char *argv[]) {
// Init context menu width
initContextMenuWidth();
initTextContextMenuWidth();
// Automatic network update
if (!vitashell_config.disable_autoupdate) {
SceUID thid = sceKernelCreateThread("network_update_thread", (SceKernelThreadEntry)network_update_thread, 0x10000100, 0x100000, 0, 0, NULL);

2
main.h
View File

@ -53,7 +53,7 @@
// VitaShell version major.minor
#define VITASHELL_VERSION_MAJOR 0x01
#define VITASHELL_VERSION_MINOR 0x83
#define VITASHELL_VERSION_MINOR 0x90
#define VITASHELL_VERSION ((VITASHELL_VERSION_MAJOR << 0x18) | (VITASHELL_VERSION_MINOR << 0x10))

View File

@ -31,6 +31,7 @@
char pfs_mounted_path[MAX_PATH_LENGTH];
char pfs_mount_point[MAX_MOUNT_POINT_LENGTH];
int read_only = 0;
enum MenuHomeEntrys {
MENU_HOME_ENTRY_REFRESH_LIVEAREA,
@ -53,6 +54,7 @@ MenuEntry menu_home_entries[] = {
#define N_MENU_HOME_ENTRIES (sizeof(menu_home_entries) / sizeof(MenuEntry))
enum MenuMainEntrys {
MENU_MAIN_ENTRY_OPEN_DECRYPTED,
MENU_MAIN_ENTRY_MARK_UNMARK_ALL,
MENU_MAIN_ENTRY_MOVE,
MENU_MAIN_ENTRY_COPY,
@ -68,18 +70,19 @@ enum MenuMainEntrys {
};
MenuEntry menu_main_entries[] = {
{ MARK_ALL, 0, 0, CTX_INVISIBLE },
{ MOVE, 2, 0, CTX_INVISIBLE },
{ COPY, 3, 0, CTX_INVISIBLE },
{ PASTE, 4, 0, CTX_INVISIBLE },
{ DELETE, 6, 0, CTX_INVISIBLE },
{ RENAME, 7, 0, CTX_INVISIBLE },
{ NEW_FOLDER, 9, 0, CTX_INVISIBLE },
{ PROPERTIES, 10, 0, CTX_INVISIBLE },
{ SORT_BY, 12, CTX_FLAG_MORE, CTX_VISIBLE },
{ MORE, 13, CTX_FLAG_MORE, CTX_INVISIBLE },
{ SEND, 17, 0, CTX_INVISIBLE }, // CTX_FLAG_BARRIER
{ RECEIVE, 18, 0, CTX_INVISIBLE },
{ OPEN_DECRYPTED, 0, 0, CTX_INVISIBLE },
{ MARK_ALL, 1, 0, CTX_INVISIBLE },
{ MOVE, 3, 0, CTX_INVISIBLE },
{ COPY, 4, 0, CTX_INVISIBLE },
{ PASTE, 5, 0, CTX_INVISIBLE },
{ DELETE, 7, 0, CTX_INVISIBLE },
{ RENAME, 8, 0, CTX_INVISIBLE },
{ NEW_FOLDER, 10, 0, CTX_INVISIBLE },
{ PROPERTIES, 11, 0, CTX_INVISIBLE },
{ SORT_BY, 13, CTX_FLAG_MORE, CTX_VISIBLE },
{ MORE, 14, CTX_FLAG_MORE, CTX_INVISIBLE },
{ SEND, 17, 0, CTX_INVISIBLE }, // CTX_FLAG_BARRIER
{ RECEIVE, 18, 0, CTX_INVISIBLE },
};
#define N_MENU_MAIN_ENTRIES (sizeof(menu_main_entries) / sizeof(MenuEntry))
@ -104,7 +107,6 @@ enum MenuMoreEntrys {
MENU_MORE_ENTRY_INSTALL_FOLDER,
MENU_MORE_ENTRY_EXPORT_MEDIA,
MENU_MORE_ENTRY_CALCULATE_SHA1,
MENU_MORE_ENTRY_OPEN_DECRYPTED,
};
MenuEntry menu_more_entries[] = {
@ -113,7 +115,6 @@ MenuEntry menu_more_entries[] = {
{ INSTALL_FOLDER, 14, 0, CTX_INVISIBLE },
{ EXPORT_MEDIA, 15, 0, CTX_INVISIBLE },
{ CALCULATE_SHA1, 16, 0, CTX_INVISIBLE },
{ OPEN_DECRYPTED, 17, 0, CTX_INVISIBLE },
};
#define N_MENU_MORE_ENTRIES (sizeof(menu_more_entries) / sizeof(MenuEntry))
@ -159,13 +160,73 @@ ContextMenu context_menu_more = {
.sel = -1,
};
int gameDataMount(const char *path) {
int res = sceAppMgrGameDataMount(path, 0, 0, pfs_mount_point);
debugPrintf("res: 0x%08X, %s\n", res, pfs_mount_point);
return res;
/*
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 - 1, "%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 gameDataUmount() {
int pfsUmount() {
if (pfs_mount_point[0] == 0)
return -1;
@ -275,6 +336,7 @@ void setContextMenuMainVisibilities() {
// Invisble entries when on '..'
if (strcmp(file_entry->name, DIR_UP) == 0) {
menu_main_entries[MENU_MAIN_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
menu_main_entries[MENU_MAIN_ENTRY_MARK_UNMARK_ALL].visibility = CTX_INVISIBLE;
menu_main_entries[MENU_MAIN_ENTRY_MOVE].visibility = CTX_INVISIBLE;
menu_main_entries[MENU_MAIN_ENTRY_COPY].visibility = CTX_INVISIBLE;
@ -309,9 +371,10 @@ void setContextMenuMainVisibilities() {
}
}
// Invisible write operations in archives or pfs mounted paths
// Invisible write operations in archives
// TODO: read-only mount points
if (isInArchive() || (pfs_mounted_path[0] && strstr(file_list.path, pfs_mounted_path))) {
if (isInArchive() || (pfs_mounted_path[0] && strstr(file_list.path, pfs_mounted_path) && read_only)) {
menu_main_entries[MENU_MAIN_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
menu_main_entries[MENU_MAIN_ENTRY_MOVE].visibility = CTX_INVISIBLE;
menu_main_entries[MENU_MAIN_ENTRY_PASTE].visibility = CTX_INVISIBLE;
menu_main_entries[MENU_MAIN_ENTRY_DELETE].visibility = CTX_INVISIBLE;
@ -333,6 +396,17 @@ void setContextMenuMainVisibilities() {
}
}
// Invisible if it's not folder or sce_pfs does not exist
if (!file_entry->is_folder) {
menu_main_entries[MENU_MAIN_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
} else {
char path[MAX_PATH_LENGTH];
snprintf(path, MAX_PATH_LENGTH - 1, "%s%ssce_pfs", file_list.path, file_entry->name);
if (!checkFolderExist(path))
menu_main_entries[MENU_MAIN_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
}
// Go to first entry
for (i = 0; i < N_MENU_MAIN_ENTRIES; i++) {
if (menu_main_entries[i].visibility == CTX_VISIBLE) {
@ -394,17 +468,15 @@ void setContextMenuMoreVisibilities() {
menu_more_entries[MENU_MORE_ENTRY_INSTALL_FOLDER].visibility = CTX_INVISIBLE;
menu_more_entries[MENU_MORE_ENTRY_EXPORT_MEDIA].visibility = CTX_INVISIBLE;
menu_more_entries[MENU_MORE_ENTRY_CALCULATE_SHA1].visibility = CTX_INVISIBLE;
menu_more_entries[MENU_MORE_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
}
// Invisble operations in archives
if (isInArchive()) {
if (isInArchive() || (pfs_mounted_path[0] && strstr(file_list.path, pfs_mounted_path) && read_only)) {
menu_more_entries[MENU_MORE_ENTRY_COMPRESS].visibility = CTX_INVISIBLE;
menu_more_entries[MENU_MORE_ENTRY_INSTALL_ALL].visibility = CTX_INVISIBLE;
menu_more_entries[MENU_MORE_ENTRY_INSTALL_FOLDER].visibility = CTX_INVISIBLE;
menu_more_entries[MENU_MORE_ENTRY_EXPORT_MEDIA].visibility = CTX_INVISIBLE;
menu_more_entries[MENU_MORE_ENTRY_CALCULATE_SHA1].visibility = CTX_INVISIBLE;
menu_more_entries[MENU_MORE_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
}
if (file_entry->is_folder) {
@ -447,17 +519,6 @@ void setContextMenuMoreVisibilities() {
menu_more_entries[MENU_MORE_ENTRY_EXPORT_MEDIA].visibility = CTX_INVISIBLE;
}
// Invisible if it's not folder or sce_pfs does not exist
if (!file_entry->is_folder) {
menu_more_entries[MENU_MORE_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
} else {
char path[MAX_PATH_LENGTH];
snprintf(path, MAX_PATH_LENGTH - 1, "%s%ssce_pfs", file_list.path, file_entry->name);
if (!checkFolderExist(path))
menu_more_entries[MENU_MORE_ENTRY_OPEN_DECRYPTED].visibility = CTX_INVISIBLE;
}
// Go to first entry
for (i = 0; i < N_MENU_MORE_ENTRIES; i++) {
if (menu_more_entries[i].visibility == CTX_VISIBLE) {
@ -557,6 +618,57 @@ static int contextMenuHomeEnterCallback(int sel, void *context) {
static int contextMenuMainEnterCallback(int sel, void *context) {
switch (sel) {
case MENU_MAIN_ENTRY_OPEN_DECRYPTED:
{
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
if (file_entry) {
char path[MAX_PATH_LENGTH];
int res;
pfsUmount();
snprintf(path, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name);
res = pfsMount(path);
// In case we're at ux0:patch or grw0:patch we need to apply the mounting at ux0:app or gro0:app
if (res < 0) {
if (strncasecmp(file_list.path, "ux0:patch", 9) == 0 ||
strncasecmp(file_list.path, "grw0:patch", 10) == 0) {
snprintf(path, MAX_PATH_LENGTH - 1, "ux0:app/%s", file_entry->name);
res = pfsMount(path);
if (res < 0) {
snprintf(path, MAX_PATH_LENGTH - 1, "gro0:app/%s", file_entry->name);
res = pfsMount(path);
}
}
}
if (res < 0)
errorDialog(res);
if (res >= 0) {
addEndSlash(file_list.path);
strcat(file_list.path, file_entry->name);
strcpy(pfs_mounted_path, file_list.path);
dirLevelUp();
// Save last dir
WriteFile(VITASHELL_LASTDIR, file_list.path, strlen(file_list.path) + 1);
// Open folder
int res = refreshFileList();
if (res < 0)
errorDialog(res);
} else {
errorDialog(res);
}
}
break;
}
case MENU_MAIN_ENTRY_MARK_UNMARK_ALL:
{
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
@ -596,7 +708,7 @@ static int contextMenuMainEnterCallback(int sel, void *context) {
if (pfs_mounted_path[0] &&
!strstr(file_list.path, pfs_mounted_path) &&
strstr(copy_list.path, pfs_mounted_path)) {
gameDataUmount();
pfsUmount();
}
// Mode
@ -907,47 +1019,6 @@ static int contextMenuMoreEnterCallback(int sel, void *context) {
setDialogStep(DIALOG_STEP_HASH_QUESTION);
break;
}
case MENU_MORE_ENTRY_OPEN_DECRYPTED:
{
FileListEntry *file_entry = fileListGetNthEntry(&file_list, base_pos + rel_pos);
if (file_entry) {
char path[MAX_PATH_LENGTH];
int res;
gameDataUmount();
snprintf(path, MAX_PATH_LENGTH - 1, "%s%s", file_list.path, file_entry->name);
res = gameDataMount(path);
// In case we're at ux0:patch or grw0:patch we need to apply the mounting at ux0:app or gro0:app
snprintf(path, MAX_PATH_LENGTH - 1, "ux0:app/%s", file_entry->name);
if (res < 0)
res = gameDataMount(path);
snprintf(path, MAX_PATH_LENGTH - 1, "gro:app/%s", file_entry->name);
if (res < 0)
res = gameDataMount(path);
if (res >= 0) {
addEndSlash(file_list.path);
strcat(file_list.path, file_entry->name);
strcpy(pfs_mounted_path, file_list.path);
dirLevelUp();
// Save last dir
WriteFile(VITASHELL_LASTDIR, file_list.path, strlen(file_list.path) + 1);
// Open folder
int res = refreshFileList();
if (res < 0)
errorDialog(res);
} else {
errorDialog(res);
}
}
break;
}
}
return CONTEXT_MENU_CLOSING;

View File

@ -28,8 +28,8 @@ extern ContextMenu context_menu_main;
extern ContextMenu context_menu_sort;
extern ContextMenu context_menu_more;
int gameDataMount(const char *path);
int gameDataUmount();
int pfsMount(const char *path);
int pfsUmount();
void initContextMenuWidth();
void setContextMenuHomeVisibilities();

View File

@ -22,9 +22,10 @@ target_link_libraries(kernel
SceIofilemgrForDriver_stub
SceSysclibForDriver_stub
SceSysmemForDriver_stub
SceModulemgrForKernel_stub
SceModulemgrForDriver_stub
SceThreadmgrForDriver_stub
SceProcessmgrForDriver_stub
SceNpDrmForDriver_stub
taihenForKernel_stub
taihenModuleUtils_stub
)

View File

@ -12,4 +12,6 @@ VitaShellKernel2:
functions:
- shellKernelIsUx0Redirected
- shellKernelRedirectUx0
- shellKernelUnredirectUx0
- shellKernelUnredirectUx0
- shellKernelMountById
- shellKernelGetRifVitaKey

View File

@ -19,6 +19,7 @@
#include <psp2kern/kernel/cpu.h>
#include <psp2kern/kernel/modulemgr.h>
#include <psp2kern/kernel/sysmem.h>
#include <psp2kern/kernel/threadmgr.h>
#include <psp2kern/io/fcntl.h>
#include <stdio.h>
@ -26,8 +27,11 @@
#include <taihen.h>
#include "vitashell_kernel.h"
#define MOUNT_POINT_ID 0x800
int module_get_export_func(SceUID pid, const char *modname, uint32_t libnid, uint32_t funcnid, uintptr_t *func);
int module_get_offset(SceUID pid, SceUID modid, int segidx, size_t offset, uintptr_t *addr);
typedef struct {
@ -138,6 +142,113 @@ int shellKernelUnredirectUx0() {
return 0;
}
int _shellKernelMountById(ShellMountIdArgs *args) {
int res;
void *(* sceAppMgrFindProcessInfoByPid)(void *data, SceUID pid);
int (* sceAppMgrMountById)(SceUID pid, void *info, int id, const char *titleid, const char *path, const char *desired_mount_point, const void *klicensee, char *mount_point);
int (* _ksceKernelGetModuleInfo)(SceUID pid, SceUID modid, SceKernelModuleInfo *info);
// Get tai module info
tai_module_info_t tai_info;
tai_info.size = sizeof(tai_module_info_t);
if (taiGetModuleInfoForKernel(KERNEL_PID, "SceAppMgr", &tai_info) < 0)
return SCE_KERNEL_START_SUCCESS;
switch (tai_info.module_nid) {
case 0xDBB29DB7: // 3.60 retail
module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x2DE1, (uintptr_t *)&sceAppMgrFindProcessInfoByPid);
module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x19B51, (uintptr_t *)&sceAppMgrMountById);
break;
case 0x1C9879D6: // 3.65 retail
module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x2DE1, (uintptr_t *)&sceAppMgrFindProcessInfoByPid);
module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x19E61, (uintptr_t *)&sceAppMgrMountById);
break;
case 0x54E2E984: // 3.67 retail
module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x2DE1, (uintptr_t *)&sceAppMgrFindProcessInfoByPid);
module_get_offset(KERNEL_PID, tai_info.modid, 0, 0x19E6D, (uintptr_t *)&sceAppMgrMountById);
break;
}
res = module_get_export_func(KERNEL_PID, "SceKernelModulemgr", 0xC445FA63, 0xD269F915, (uintptr_t *)&_ksceKernelGetModuleInfo);
if (res < 0)
res = module_get_export_func(KERNEL_PID, "SceKernelModulemgr", 0x92C9FFC2, 0xDAA90093, (uintptr_t *)&_ksceKernelGetModuleInfo);
if (res < 0)
return res;
// Module info
SceKernelModuleInfo mod_info;
mod_info.size = sizeof(SceKernelModuleInfo);
res = _ksceKernelGetModuleInfo(KERNEL_PID, tai_info.modid, &mod_info);
if (res < 0)
return res;
uint32_t appmgr_data_addr = (uint32_t)mod_info.segments[1].vaddr;
SceUID process_id = ksceKernelGetProcessId();
void *info = sceAppMgrFindProcessInfoByPid((void *)(appmgr_data_addr + 0x500), process_id);
if (!info)
return -1;
char process_titleid[12];
char path[256];
char desired_mount_point[16];
char mount_point[16];
char klicensee[16];
memset(mount_point, 0, sizeof(mount_point));
if (args->process_titleid)
ksceKernelStrncpyUserToKernel(process_titleid, (uintptr_t)args->process_titleid, 11);
if (args->path)
ksceKernelStrncpyUserToKernel(path, (uintptr_t)args->path, 255);
if (args->desired_mount_point)
ksceKernelStrncpyUserToKernel(desired_mount_point, (uintptr_t)args->desired_mount_point, 15);
if (args->klicensee)
ksceKernelMemcpyUserToKernel(klicensee, (uintptr_t)args->klicensee, 0x10);
res = sceAppMgrMountById(process_id, info + 0x580, args->id, args->process_titleid ? process_titleid : NULL, args->path ? path : NULL,
args->desired_mount_point ? desired_mount_point : NULL, args->klicensee ? klicensee : NULL, mount_point);
if (args->mount_point)
ksceKernelStrncpyKernelToUser((uintptr_t)args->mount_point, mount_point, 15);
return res;
}
int shellKernelMountById(ShellMountIdArgs *args) {
uint32_t state;
ENTER_SYSCALL(state);
ShellMountIdArgs k_args;
ksceKernelMemcpyUserToKernel(&k_args, (uintptr_t)args, sizeof(ShellMountIdArgs));
int res = ksceKernelRunWithStack(0x2000, (void *)_shellKernelMountById, &k_args);
EXIT_SYSCALL(state);
return res;
}
int shellKernelGetRifVitaKey(const void *license_buf, void *klicensee) {
char k_license_buf[0x200];
char k_klicensee[0x10];
memset(k_klicensee, 0, sizeof(k_klicensee));
if (license_buf)
ksceKernelMemcpyUserToKernel(k_license_buf, license_buf, sizeof(k_license_buf));
int res = ksceNpDrmGetRifVitaKey(k_license_buf, k_klicensee, NULL, NULL, NULL, NULL);
if (klicensee)
ksceKernelMemcpyKernelToUser(klicensee, k_klicensee, sizeof(k_klicensee));
return res;
}
void _start() __attribute__ ((weak, alias("module_start")));
int module_start(SceSize args, void *argp) {
SceUID tmp1, tmp2;

View File

@ -19,8 +19,19 @@
#ifndef __VITASHELL_KERNEL_H__
#define __VITASHELL_KERNEL_H__
typedef struct {
int id;
const char *process_titleid;
const char *path;
const char *desired_mount_point;
const void *klicensee;
char *mount_point;
} ShellMountIdArgs;
int shellKernelIsUx0Redirected();
int shellKernelRedirectUx0();
int shellKernelUnredirectUx0();
int shellKernelMountById(ShellMountIdArgs *args);
int shellKernelGetRifVitaKey(const void *license_buf, void *klicensee);
#endif

View File

@ -12,4 +12,6 @@ VitaShellUser:
functions:
- shellUserIsUx0Redirected
- shellUserRedirectUx0
- shellUserUnredirectUx0
- shellUserUnredirectUx0
- shellUserMountById
- shellUserGetRifVitaKey

View File

@ -24,7 +24,7 @@
#include <string.h>
#include <stdarg.h>
#include <vitashell_kernel.h>
#include "vitashell_user.h"
int shellUserIsUx0Redirected() {
return shellKernelIsUx0Redirected();
@ -38,6 +38,14 @@ int shellUserUnredirectUx0() {
return shellKernelUnredirectUx0();
}
int shellUserMountById(ShellMountIdArgs *args) {
return shellKernelMountById(args);
}
int shellUserGetRifVitaKey(const void *license_buf, void *klicensee) {
return shellKernelGetRifVitaKey(license_buf, klicensee);
}
void _start() __attribute__ ((weak, alias("module_start")));
int module_start(SceSize args, void *argp) {
return SCE_KERNEL_START_SUCCESS;

View File

@ -19,8 +19,12 @@
#ifndef __VITASHELL_USER_H__
#define __VITASHELL_USER_H__
#include <vitashell_kernel.h>
int shellUserIsUx0Redirected();
int shellUserRedirectUx0();
int shellUserUnredirectUx0();
int shellUserMountById(ShellMountIdArgs *args);
int shellUserGetRifVitaKey(const void *license_buf, void *klicensee);
#endif

View File

@ -28,7 +28,7 @@
<frame id="frame4">
<liveitem>
<text align="left" text-align="left" word-wrap="off" ellipsis="on">
<str size="18" color="#ffffff" shadow="on">v1.83</str>
<str size="18" color="#ffffff" shadow="on">v1.9</str>
</text>
</liveitem>
</frame>

Binary file not shown.

Binary file not shown.