diff --git a/Makefile b/Makefile
index 28a323d..6434aec 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,8 @@ RESOURCES_PNG = resources/folder_icon.png resources/file_icon.png resources/arch
resources/battery_bar_charge.png resources/headphone.png resources/audio_previous.png resources/audio_pause.png \
resources/audio_play.png resources/audio_next.png
RESOURCES_TXT = resources/theme.txt resources/colors.txt resources/english_us.txt
-OBJS += $(RESOURCES_PNG:.png=.o) $(RESOURCES_TXT:.txt=.o)
+RESOURCES_BIN = resources/updater_eboot.bin resources/updater_param.bin
+OBJS += $(RESOURCES_PNG:.png=.o) $(RESOURCES_TXT:.txt=.o) $(RESOURCES_BIN:.bin=.o)
LIBS = -lftpvita -lvita2d -lpng -ljpeg -lz -lm -lc \
-lSceAppMgr_stub -lSceAppUtil_stub -lSceCommonDialog_stub \
@@ -59,6 +60,8 @@ $(TARGET).elf: $(OBJS)
$(PREFIX)-ld -r -b binary -o $@ $^
%.o: %.txt
$(PREFIX)-ld -r -b binary -o $@ $^
+%.o: %.bin
+ $(PREFIX)-ld -r -b binary -o $@ $^
clean:
@rm -rf $(TARGET).vpk $(TARGET).velf $(TARGET).elf $(OBJS) \
diff --git a/VitaShellUpdater/main.c b/VitaShellUpdater/main.c
deleted file mode 100644
index e69de29..0000000
diff --git a/file.c b/file.c
index 6d55625..e5b3baa 100644
--- a/file.c
+++ b/file.c
@@ -356,14 +356,16 @@ typedef struct {
static ExtensionType extension_types[] = {
{ ".BMP", FILE_TYPE_BMP },
+ { ".INI", FILE_TYPE_INI },
{ ".JPG", FILE_TYPE_JPEG },
{ ".JPEG", FILE_TYPE_JPEG },
- { ".PNG", FILE_TYPE_PNG },
{ ".MP3", FILE_TYPE_MP3 },
+ { ".PNG", FILE_TYPE_PNG },
{ ".SFO", FILE_TYPE_SFO },
- { ".VPK", FILE_TYPE_VPK },
- { ".ZIP", FILE_TYPE_ZIP },
{ ".TXT", FILE_TYPE_TXT },
+ { ".VPK", FILE_TYPE_VPK },
+ { ".XML", FILE_TYPE_XML },
+ { ".ZIP", FILE_TYPE_ZIP },
};
int getFileType(char *file) {
diff --git a/file.h b/file.h
index 8e64930..70b861b 100644
--- a/file.h
+++ b/file.h
@@ -32,13 +32,15 @@
enum FileTypes {
FILE_TYPE_UNKNOWN,
FILE_TYPE_BMP,
+ FILE_TYPE_INI,
FILE_TYPE_JPEG,
- FILE_TYPE_PNG,
FILE_TYPE_MP3,
+ FILE_TYPE_PNG,
FILE_TYPE_SFO,
- FILE_TYPE_VPK,
- FILE_TYPE_ZIP,
FILE_TYPE_TXT,
+ FILE_TYPE_VPK,
+ FILE_TYPE_XML,
+ FILE_TYPE_ZIP,
};
enum SortFlags {
diff --git a/language.c b/language.c
index 265d263..5242e3c 100644
--- a/language.c
+++ b/language.c
@@ -85,6 +85,7 @@ void loadLanguage(int id) {
LANGUAGE_ENTRY(DELETING),
LANGUAGE_ENTRY(INSTALLING),
LANGUAGE_ENTRY(DOWNLOADING),
+ LANGUAGE_ENTRY(EXTRACTING),
LANGUAGE_ENTRY(DELETE_FILE_QUESTION),
LANGUAGE_ENTRY(DELETE_FOLDER_QUESTION),
LANGUAGE_ENTRY(DELETE_FILES_FOLDERS_QUESTION),
diff --git a/language.h b/language.h
index f2c8df7..f4e3610 100644
--- a/language.h
+++ b/language.h
@@ -43,6 +43,7 @@ enum LanguageContainer {
DELETING,
INSTALLING,
DOWNLOADING,
+ EXTRACTING,
DELETE_FILE_QUESTION,
DELETE_FOLDER_QUESTION,
DELETE_FILES_FOLDERS_QUESTION,
diff --git a/main.c b/main.c
index 0ec9115..8d2d481 100644
--- a/main.c
+++ b/main.c
@@ -259,7 +259,9 @@ int handleFile(char *file, FileListEntry *entry) {
}
switch (type) {
+ case FILE_TYPE_INI:
case FILE_TYPE_TXT:
+ case FILE_TYPE_XML:
case FILE_TYPE_UNKNOWN:
res = textViewer(file);
break;
@@ -758,7 +760,6 @@ int dialogSteps() {
case DIALOG_STEP_COPIED:
case DIALOG_STEP_DELETED:
case DIALOG_STEP_INSTALLED:
- case DIALOG_STEP_DOWNLOADED:
if (msg_result == MESSAGE_DIALOG_RESULT_NONE || msg_result == MESSAGE_DIALOG_RESULT_FINISHED) {
refresh = 1;
dialog_step = DIALOG_STEP_NONE;
@@ -835,47 +836,6 @@ int dialogSteps() {
break;
- case DIALOG_STEP_INSTALL_QUESTION:
- if (msg_result == MESSAGE_DIALOG_RESULT_YES) {
- initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[INSTALLING]);
- dialog_step = DIALOG_STEP_INSTALL_CONFIRMED;
- } else if (msg_result == MESSAGE_DIALOG_RESULT_NO) {
- dialog_step = DIALOG_STEP_NONE;
- }
-
- break;
-
- case DIALOG_STEP_INSTALL_CONFIRMED:
- if (msg_result == MESSAGE_DIALOG_RESULT_RUNNING) {
- InstallArguments args;
- args.file = cur_file;
-
- SceUID thid = sceKernelCreateThread("install_thread", (SceKernelThreadEntry)install_thread, 0x40, 0x10000, 0, 0, NULL);
- if (thid >= 0)
- sceKernelStartThread(thid, sizeof(InstallArguments), &args);
-
- dialog_step = DIALOG_STEP_INSTALLING;
- }
-
- break;
-
- case DIALOG_STEP_INSTALL_WARNING:
- if (msg_result == MESSAGE_DIALOG_RESULT_YES) {
- dialog_step = DIALOG_STEP_INSTALL_WARNING_AGREED;
- } else if (msg_result == MESSAGE_DIALOG_RESULT_NO) {
- dialog_step = DIALOG_STEP_CANCELLED;
- }
-
- break;
-
- case DIALOG_STEP_UPDATE_QUESTION:
- if (msg_result == MESSAGE_DIALOG_RESULT_YES) {
- initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[DOWNLOADING]);
- dialog_step = DIALOG_STEP_UPDATE_CONFIRMED;
- } else if (msg_result == MESSAGE_DIALOG_RESULT_NO) {
- dialog_step = DIALOG_STEP_NONE;
- }
-
case DIALOG_STEP_RENAME:
if (ime_result == IME_DIALOG_RESULT_FINISHED) {
char *name = (char *)getImeDialogInputTextUTF8();
@@ -934,6 +894,65 @@ int dialogSteps() {
}
break;
+
+ case DIALOG_STEP_INSTALL_QUESTION:
+ if (msg_result == MESSAGE_DIALOG_RESULT_YES) {
+ initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[INSTALLING]);
+ dialog_step = DIALOG_STEP_INSTALL_CONFIRMED;
+ } else if (msg_result == MESSAGE_DIALOG_RESULT_NO) {
+ dialog_step = DIALOG_STEP_NONE;
+ }
+
+ break;
+
+ case DIALOG_STEP_INSTALL_CONFIRMED:
+ if (msg_result == MESSAGE_DIALOG_RESULT_RUNNING) {
+ InstallArguments args;
+ args.file = cur_file;
+
+ SceUID thid = sceKernelCreateThread("install_thread", (SceKernelThreadEntry)install_thread, 0x40, 0x10000, 0, 0, NULL);
+ if (thid >= 0)
+ sceKernelStartThread(thid, sizeof(InstallArguments), &args);
+
+ dialog_step = DIALOG_STEP_INSTALLING;
+ }
+
+ break;
+
+ case DIALOG_STEP_INSTALL_WARNING:
+ if (msg_result == MESSAGE_DIALOG_RESULT_YES) {
+ dialog_step = DIALOG_STEP_INSTALL_WARNING_AGREED;
+ } else if (msg_result == MESSAGE_DIALOG_RESULT_NO) {
+ dialog_step = DIALOG_STEP_CANCELLED;
+ }
+
+ break;
+
+ case DIALOG_STEP_UPDATE_QUESTION:
+ if (msg_result == MESSAGE_DIALOG_RESULT_YES) {
+ initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[DOWNLOADING]);
+ dialog_step = DIALOG_STEP_DOWNLOADING;
+ } else if (msg_result == MESSAGE_DIALOG_RESULT_NO) {
+ dialog_step = DIALOG_STEP_NONE;
+ }
+
+ case DIALOG_STEP_DOWNLOADED:
+ if (msg_result == MESSAGE_DIALOG_RESULT_FINISHED) {
+ initMessageDialog(MESSAGE_DIALOG_PROGRESS_BAR, language_container[INSTALLING]);
+
+ SceUID thid = sceKernelCreateThread("update_extract_thread", (SceKernelThreadEntry)update_extract_thread, 0x40, 0x10000, 0, 0, NULL);
+ if (thid >= 0)
+ sceKernelStartThread(thid, 0, NULL);
+
+ dialog_step = DIALOG_STEP_EXTRACTING;
+ }
+
+ break;
+
+ case DIALOG_STEP_EXTRACTED:
+ launchAppByUriExit("VSUPDATER");
+ dialog_step = DIALOG_STEP_NONE;
+ break;
}
return refresh;
@@ -1166,7 +1185,7 @@ int shellMain() {
} else if (file_entry->type == FILE_TYPE_SFO) { // SFO
// note: specific color to be determined
vita2d_draw_texture(sfo_icon, SHELL_MARGIN_X, y + 3.0f);
- } else if (file_entry->type == FILE_TYPE_TXT) { // TXT
+ } else if (file_entry->type == FILE_TYPE_INI || file_entry->type == FILE_TYPE_TXT || file_entry->type == FILE_TYPE_XML) { // TXT
// note: specific color to be determined
vita2d_draw_texture(text_icon, SHELL_MARGIN_X, y + 3.0f);
} else { // Other files
diff --git a/main.h b/main.h
index 207ba40..77fa9dd 100644
--- a/main.h
+++ b/main.h
@@ -175,8 +175,10 @@ enum DialogSteps {
DIALOG_STEP_RENAME,
DIALOG_STEP_UPDATE_QUESTION,
- DIALOG_STEP_UPDATE_CONFIRMED,
+ DIALOG_STEP_DOWNLOADING,
DIALOG_STEP_DOWNLOADED,
+ DIALOG_STEP_EXTRACTING,
+ DIALOG_STEP_EXTRACTED,
};
extern vita2d_pgf *font;
diff --git a/network_update.c b/network_update.c
index 1d3d715..28e4c00 100644
--- a/network_update.c
+++ b/network_update.c
@@ -19,11 +19,21 @@
#include "main.h"
#include "io_process.h"
#include "network_update.h"
+#include "package_installer.h"
+#include "archive.h"
#include "file.h"
#include "message_dialog.h"
#include "language.h"
#include "utils.h"
+#define BASE_ADDRESS "https://github.com/TheOfficialFloW/VitaShell/releases/download"
+#define VITASHELL_UPDATE_FILE "ux0:VitaShell/VitaShell.vpk"
+
+extern unsigned char _binary_resources_updater_eboot_bin_start;
+extern unsigned char _binary_resources_updater_eboot_bin_size;
+extern unsigned char _binary_resources_updater_param_bin_start;
+extern unsigned char _binary_resources_updater_param_bin_size;
+
int getDownloadFileSize(char *src, uint64_t *size) {
int tpl = sceHttpCreateTemplate("VitaShell/1.00 libhttp/1.1", SCE_HTTP_VERSION_1_1, 1);
if (tpl < 0)
@@ -117,7 +127,7 @@ int downloadProcess(char *version_string) {
// Download url
char url[128];
- sprintf(url, "https://github.com/TheOfficialFloW/VitaShell/releases/download/%s/VitaShell.vpk", version_string);
+ sprintf(url, BASE_ADDRESS "/%s/VitaShell.vpk", version_string);
// File size
uint64_t size = 0;
@@ -128,7 +138,7 @@ int downloadProcess(char *version_string) {
// Download
uint64_t value = 0;
- int res = downloadFile(url, "ux0:VitaShell/Vitashell.vpk", &value, size, SetProgress, cancelHandler);
+ int res = downloadFile(url, VITASHELL_UPDATE_FILE, &value, size, SetProgress, cancelHandler);
if (res <= 0) {
closeWaitDialog();
dialog_step = DIALOG_STEP_CANCELLED;
@@ -158,7 +168,7 @@ EXIT:
int network_update_thread(SceSize args, void *argp) {
sceHttpsDisableOption(SCE_HTTPS_FLAG_SERVER_VERIFY);
- if (downloadFile("http://github.com/TheOfficialFloW/VitaShell/releases/download/0.0/version.bin", "ux0:VitaShell/version.bin", NULL, 0, NULL, NULL) > 0) {
+ if (downloadFile(BASE_ADDRESS "/0.0/version.bin", "ux0:VitaShell/version.bin", NULL, 0, NULL, NULL) > 0) {
uint32_t version = 0;
ReadFile("ux0:VitaShell/version.bin", &version, sizeof(uint32_t));
sceIoRemove("ux0:VitaShell/version.bin");
@@ -195,5 +205,101 @@ int network_update_thread(SceSize args, void *argp) {
}
}
+ return sceKernelExitDeleteThread(0);
+}
+
+int installUpdater() {
+ // Recursively clean up package_temp directory
+ removePath(PACKAGE_PARENT, NULL, 0, NULL, NULL);
+ sceIoMkdir(PACKAGE_PARENT, 0777);
+
+ sceIoMkdir("ux0:ptmp", 0777);
+ sceIoMkdir("ux0:ptmp/pkg", 0777);
+ sceIoMkdir("ux0:ptmp/pkg/sce_sys", 0777);
+
+ WriteFile("ux0:ptmp/pkg/eboot.bin", (void *)&_binary_resources_updater_eboot_bin_start, (int)&_binary_resources_updater_eboot_bin_size);
+ WriteFile("ux0:ptmp/pkg/sce_sys/param.sfo", (void *)&_binary_resources_updater_param_bin_start, (int)&_binary_resources_updater_param_bin_size);
+
+ // Make head.bin
+ makeHeadBin();
+
+ // Promote
+ promote(PACKAGE_DIR);
+}
+
+int update_extract_thread(SceSize args, void *argp) {
+ SceUID thid = -1;
+
+ // Lock power timers
+ powerLock();
+
+ // Set progress to 0%
+ sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 0);
+ sceKernelDelayThread(DIALOG_WAIT); // Needed to see the percentage
+
+ // Install updater
+ installUpdater();
+
+ // Recursively clean up package_temp directory
+ removePath(PACKAGE_PARENT, NULL, 0, NULL, NULL);
+ sceIoMkdir(PACKAGE_PARENT, 0777);
+
+ // Open archive
+ int res = archiveOpen(VITASHELL_UPDATE_FILE);
+ if (res < 0) {
+ closeWaitDialog();
+ errorDialog(res);
+ goto EXIT;
+ }
+
+ // Src path
+ char *src_path = VITASHELL_UPDATE_FILE "/";
+
+ // Get archive path info
+ uint64_t size = 0;
+ uint32_t folders = 0, files = 0;
+ getArchivePathInfo(src_path, &size, &folders, &files);
+
+ // Update thread
+ thid = createStartUpdateThread(size + folders);
+
+ // Extract process
+ uint64_t value = 0;
+
+ res = extractArchivePath(src_path, PACKAGE_DIR "/", &value, size + folders, SetProgress, cancelHandler);
+ if (res <= 0) {
+ closeWaitDialog();
+ dialog_step = DIALOG_STEP_CANCELLED;
+ errorDialog(res);
+ goto EXIT;
+ }
+
+ // Remove update file
+ sceIoRemove(VITASHELL_UPDATE_FILE);
+
+ // Make head.bin
+ res = makeHeadBin();
+ if (res < 0) {
+ closeWaitDialog();
+ errorDialog(res);
+ goto EXIT;
+ }
+
+ // Set progress to 100%
+ sceMsgDialogProgressBarSetValue(SCE_MSG_DIALOG_PROGRESSBAR_TARGET_BAR_DEFAULT, 100);
+ sceKernelDelayThread(COUNTUP_WAIT);
+
+ // Close
+ sceMsgDialogClose();
+
+ dialog_step = DIALOG_STEP_EXTRACTED;
+
+EXIT:
+ if (thid >= 0)
+ sceKernelWaitThreadEnd(thid, NULL, NULL);
+
+ // Unlock power timers
+ powerUnlock();
+
return sceKernelExitDeleteThread(0);
}
\ No newline at end of file
diff --git a/network_update.h b/network_update.h
index 7611f27..fef701c 100644
--- a/network_update.h
+++ b/network_update.h
@@ -20,5 +20,6 @@
#define __NETWORK_UPDATE_H__
int network_update_thread(SceSize args, void *argp);
+int update_extract_thread(SceSize args, void *argp);
#endif
\ No newline at end of file
diff --git a/package_installer.c b/package_installer.c
index 58623ce..3afe032 100644
--- a/package_installer.c
+++ b/package_installer.c
@@ -31,12 +31,6 @@
#include "resources/base_head_bin.h"
-#define ntohl __builtin_bswap32
-
-#define PACKAGE_PARENT "ux0:ptmp"
-#define PACKAGE_DIR PACKAGE_PARENT "/pkg"
-#define HEAD_BIN PACKAGE_DIR "/sce_sys/package/head.bin"
-
void loadScePaf() {
uint32_t ptr[0x100] = { 0 };
ptr[0] = 0;
@@ -68,7 +62,7 @@ int promote(char *path) {
if (res < 0)
return res;
- sceKernelDelayThread(300 * 1000);
+ sceKernelDelayThread(100 * 1000);
} while (state);
int result = 0;
diff --git a/package_installer.h b/package_installer.h
index fe6a6a5..b45c296 100644
--- a/package_installer.h
+++ b/package_installer.h
@@ -19,10 +19,19 @@
#ifndef __PACKAGE_INSTALLER_H__
#define __PACKAGE_INSTALLER_H__
+#define ntohl __builtin_bswap32
+
+#define PACKAGE_PARENT "ux0:ptmp"
+#define PACKAGE_DIR PACKAGE_PARENT "/pkg"
+#define HEAD_BIN PACKAGE_DIR "/sce_sys/package/head.bin"
+
typedef struct {
char *file;
} InstallArguments;
+int promote(char *path);
+int makeHeadBin();
+
int install_thread(SceSize args_size, InstallArguments *args);
#endif
\ No newline at end of file
diff --git a/resources/english_us.txt b/resources/english_us.txt
index 6e9fe21..3a0d2db 100644
--- a/resources/english_us.txt
+++ b/resources/english_us.txt
@@ -23,6 +23,7 @@ COPYING = "Copying..."
DELETING = "Deleting..."
INSTALLING = "Installing..."
DOWNLOADING = "Downloading..."
+EXTRACTING = "Extracting..."
DELETE_FILE_QUESTION = "Are you sure you want to delete this file?"
DELETE_FOLDER_QUESTION = "Are you sure you want to delete this folder?"
DELETE_FILES_FOLDERS_QUESTION = "Are you sure you want to delete these files/folders?"
diff --git a/resources/updater_eboot.bin b/resources/updater_eboot.bin
new file mode 100644
index 0000000..568cda7
Binary files /dev/null and b/resources/updater_eboot.bin differ
diff --git a/resources/updater_param.bin b/resources/updater_param.bin
new file mode 100644
index 0000000..4dc8bc8
Binary files /dev/null and b/resources/updater_param.bin differ
diff --git a/VitaShellUpdater/Makefile b/updater/Makefile
similarity index 62%
rename from VitaShellUpdater/Makefile
rename to updater/Makefile
index de47c87..f9c7982 100644
--- a/VitaShellUpdater/Makefile
+++ b/updater/Makefile
@@ -1,24 +1,25 @@
TITLE_ID = VSUPDATER
-TARGET = VitaShellUpdater
+TARGET = updater
OBJS = main.o
-LIBS =
-PREFIX = arm-vita-eabi
-CC = $(PREFIX)-gcc
-CFLAGS = -Wl,-q -Wall -O3 -marm
-ASFLAGS = $(CFLAGS)
+LIBS = -lSceAppMgr_stub ../libpromoter/libScePromoterUtil_stub.a -lSceSysmodule_stub
+
+PREFIX = arm-vita-eabi
+CC = $(PREFIX)-gcc
+CFLAGS = -Wl,-q -Wall -O3 -marm
+ASFLAGS = $(CFLAGS)
all: $(TARGET).vpk
%.vpk: eboot.bin
- vita-mksfoex -s TITLE_ID=$(TITLE_ID) "$(TARGET)" param.sfo
+ vita-mksfoex -s TITLE_ID=$(TITLE_ID) "VitaShell Updater" param.sfo
vita-pack-vpk -s param.sfo -b eboot.bin $@
eboot.bin: $(TARGET).velf
vita-make-fself $< $@
%.velf: %.elf
- vita-elf-create $< $@
+ vita-elf-create $< $@ ../libpromoter/promoterutil.json
$(TARGET).elf: $(OBJS)
$(CC) $(CFLAGS) $^ $(LIBS) -o $@
diff --git a/updater/main.c b/updater/main.c
new file mode 100644
index 0000000..4c4013a
--- /dev/null
+++ b/updater/main.c
@@ -0,0 +1,199 @@
+/*
+ VitaShell
+ Copyright (C) 2015-2016, 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
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "../sysmodule_internal.h"
+#include "../libpromoter/promoterutil.h"
+
+#define TRANSFER_SIZE 64 * 1024
+
+#define PACKAGE_PARENT "ux0:ptmp"
+#define PACKAGE_DIR PACKAGE_PARENT "/pkg"
+#define HEAD_BIN PACKAGE_DIR "/sce_sys/package/head.bin"
+
+typedef struct SfoHeader {
+ uint32_t magic;
+ uint32_t version;
+ uint32_t keyofs;
+ uint32_t valofs;
+ uint32_t count;
+} __attribute__((packed)) SfoHeader;
+
+typedef struct SfoEntry {
+ uint16_t nameofs;
+ uint8_t alignment;
+ uint8_t type;
+ uint32_t valsize;
+ uint32_t totalsize;
+ uint32_t dataofs;
+} __attribute__((packed)) SfoEntry;
+
+int launchAppByUriExit(char *titleid) {
+ char uri[32];
+ sprintf(uri, "psgm:play?titleid=%s", titleid);
+
+ sceKernelDelayThread(10000);
+ sceAppMgrLaunchAppByUri(0xFFFFF, uri);
+ sceKernelDelayThread(10000);
+ sceAppMgrLaunchAppByUri(0xFFFFF, uri);
+
+ sceKernelExitProcess(0);
+
+ return 0;
+}
+
+int copyFile(char *src_path, char *dst_path) {
+ SceUID fdsrc = sceIoOpen(src_path, SCE_O_RDONLY, 0);
+ if (fdsrc < 0)
+ return fdsrc;
+
+ SceUID fddst = sceIoOpen(dst_path, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
+ if (fddst < 0) {
+ sceIoClose(fdsrc);
+ return fddst;
+ }
+
+ void *buf = malloc(TRANSFER_SIZE);
+
+ int read;
+ while ((read = sceIoRead(fdsrc, buf, TRANSFER_SIZE)) > 0) {
+ sceIoWrite(fddst, buf, read);
+ }
+
+ free(buf);
+
+ sceIoClose(fddst);
+ sceIoClose(fdsrc);
+
+ return 0;
+}
+
+void loadScePaf() {
+ uint32_t ptr[0x100] = { 0 };
+ ptr[0] = 0;
+ ptr[1] = (uint32_t)&ptr[0];
+ uint32_t scepaf_argp[] = { 0x400000, 0xEA60, 0x40000, 0, 0 };
+ sceSysmoduleLoadModuleInternalWithArg(0x80000008, sizeof(scepaf_argp), scepaf_argp, ptr);
+}
+
+int promote(char *path) {
+ int res;
+
+ loadScePaf();
+
+ res = sceSysmoduleLoadModuleInternal(SCE_SYSMODULE_PROMOTER_UTIL);
+ if (res < 0)
+ return res;
+
+ 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;
+
+ sceKernelDelayThread(100 * 1000);
+ } while (state);
+
+ int result = 0;
+ res = scePromoterUtilityGetResult(&result);
+ if (res < 0)
+ return res;
+
+ res = scePromoterUtilityExit();
+ if (res < 0)
+ return res;
+
+ res = sceSysmoduleUnloadModuleInternal(SCE_SYSMODULE_PROMOTER_UTIL);
+ if (res < 0)
+ return res;
+
+ return result;
+}
+
+char *get_title_id(const char *filename) {
+ char *res = NULL;
+ long size = 0;
+ FILE *fin = NULL;
+ char *buf = NULL;
+ int i;
+
+ SfoHeader *header;
+ SfoEntry *entry;
+
+ fin = fopen(filename, "rb");
+ if (!fin)
+ goto cleanup;
+ if (fseek(fin, 0, SEEK_END) != 0)
+ goto cleanup;
+ if ((size = ftell(fin)) == -1)
+ goto cleanup;
+ if (fseek(fin, 0, SEEK_SET) != 0)
+ goto cleanup;
+ buf = calloc(1, size + 1);
+ if (!buf)
+ goto cleanup;
+ if (fread(buf, size, 1, fin) != 1)
+ goto cleanup;
+
+ header = (SfoHeader*)buf;
+ entry = (SfoEntry*)(buf + sizeof(SfoHeader));
+ for (i = 0; i < header->count; ++i, ++entry) {
+ const char *name = buf + header->keyofs + entry->nameofs;
+ const char *value = buf + header->valofs + entry->dataofs;
+ if (name >= buf + size || value >= buf + size)
+ break;
+ if (strcmp(name, "TITLE_ID") == 0)
+ res = strdup(value);
+ }
+
+cleanup:
+ if (buf)
+ free(buf);
+ if (fin)
+ fclose(fin);
+
+ return res;
+}
+
+int main(int argc, const char *argv[]) {
+ char *titleid = get_title_id(PACKAGE_DIR "/sce_sys/param.sfo");
+ if (strcmp(titleid, "VITASHELL") == 0) {
+ copyFile(PACKAGE_DIR "/eboot.bin", "ux0:app/MLCL00001/eboot.bin");
+
+ if (promote(PACKAGE_DIR) >= 0)
+ launchAppByUriExit("VITASHELL");
+ }
+
+ return sceKernelExitProcess(0);
+}
\ No newline at end of file
diff --git a/utils.c b/utils.c
index f4a7c75..6a76714 100644
--- a/utils.c
+++ b/utils.c
@@ -299,5 +299,19 @@ int debugPrintf(char *text, ...) {
#endif
#endif
+ return 0;
+}
+
+int launchAppByUriExit(char *titleid) {
+ char uri[32];
+ sprintf(uri, "psgm:play?titleid=%s", titleid);
+
+ sceKernelDelayThread(10000);
+ sceAppMgrLaunchAppByUri(0xFFFFF, uri);
+ sceKernelDelayThread(10000);
+ sceAppMgrLaunchAppByUri(0xFFFFF, uri);
+
+ sceKernelExitProcess(0);
+
return 0;
}
\ No newline at end of file
diff --git a/utils.h b/utils.h
index dc6fc54..f96fb11 100644
--- a/utils.h
+++ b/utils.h
@@ -71,4 +71,6 @@ int randomNumber(int low, int high);
int debugPrintf(char *text, ...);
+int launchAppByUriExit(char *titleid);
+
#endif