From f08e517906ecc9a17f6f3deb5b2bc219748d6b99 Mon Sep 17 00:00:00 2001 From: Steven Smith Date: Sat, 7 May 2016 22:57:15 -0700 Subject: [PATCH] Add support for importing title seeds. --- source/core/util.c | 42 ++++++++++++++++++++++++++ source/core/util.h | 4 ++- source/ui/section/action/action.h | 1 + source/ui/section/action/importseed.c | 39 ++++++++++++++++++++++++ source/ui/section/action/installcdn.c | 3 ++ source/ui/section/action/installcias.c | 2 ++ source/ui/section/networkinstall.c | 3 ++ source/ui/section/qrinstall.c | 3 ++ source/ui/section/titles.c | 6 ++++ 9 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 source/ui/section/action/importseed.c diff --git a/source/core/util.c b/source/core/util.c index b2d7d27..d0a9477 100644 --- a/source/core/util.c +++ b/source/core/util.c @@ -234,4 +234,46 @@ void util_get_parent_path(char* out, const char* path, u32 size) { u32 terminatorPos = end - path + 1 < size - 1 ? end - path + 1 : size - 1; strncpy(out, path, terminatorPos); out[terminatorPos] = '\0'; +} + +static Result FSUSER_AddSeed(u64 titleId, const void* seed) { + u32 *cmdbuf = getThreadCommandBuffer(); + + cmdbuf[0] = 0x087a0180; + cmdbuf[1] = (u32) (titleId & 0xFFFFFFFF); + cmdbuf[2] = (u32) (titleId >> 32); + memcpy(&cmdbuf[3], seed, 16); + + Result ret = 0; + if(R_FAILED(ret = svcSendSyncRequest(*fsGetSessionHandle()))) return ret; + + ret = cmdbuf[1]; + return ret; +} + +Result util_import_seed(u64 titleId) { + char pathBuf[64]; + snprintf(pathBuf, 64, "/fbi/seed/%016llX.dat", titleId); + + Result res = 0; + + FS_Path* fsPath = util_make_path_utf8(pathBuf); + if(fsPath != NULL) { + Handle fileHandle = 0; + if(R_SUCCEEDED(res = FSUSER_OpenFileDirectly(&fileHandle, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, ""), *fsPath, FS_OPEN_READ, 0))) { + u32 bytesRead = 0; + u8 seed[16]; + if(R_SUCCEEDED(res = FSFILE_Read(fileHandle, &bytesRead, 0, seed, sizeof(seed)))) { + res = FSUSER_AddSeed(titleId, seed); + } + + FSFILE_Close(fileHandle); + } + + util_free_path_utf8(fsPath); + } else { + res = R_FBI_OUT_OF_MEMORY; + } + + return res; } \ No newline at end of file diff --git a/source/core/util.h b/source/core/util.h index d0219da..f265b86 100644 --- a/source/core/util.h +++ b/source/core/util.h @@ -49,4 +49,6 @@ bool util_is_dir(FS_Archive archive, const char* path); Result util_ensure_dir(FS_Archive archive, const char* path); void util_get_path_file(char* out, const char* path, u32 size); -void util_get_parent_path(char* out, const char* path, u32 size); \ No newline at end of file +void util_get_parent_path(char* out, const char* path, u32 size); + +Result util_import_seed(u64 titleId); \ No newline at end of file diff --git a/source/ui/section/action/action.h b/source/ui/section/action/action.h index 90b16a9..1273b97 100644 --- a/source/ui/section/action/action.h +++ b/source/ui/section/action/action.h @@ -36,6 +36,7 @@ void action_install_cdn_noprompt(volatile bool* done, ticket_info* info, bool fi void action_delete_title(linked_list* items, list_item* selected); void action_launch_title(linked_list* items, list_item* selected); void action_extract_smdh(linked_list* items, list_item* selected); +void action_import_seed(linked_list* items, list_item* selected); void action_browse_title_save_data(linked_list* items, list_item* selected); void action_import_secure_value(linked_list* items, list_item* selected); void action_export_secure_value(linked_list* items, list_item* selected); diff --git a/source/ui/section/action/importseed.c b/source/ui/section/action/importseed.c new file mode 100644 index 0000000..6b996c5 --- /dev/null +++ b/source/ui/section/action/importseed.c @@ -0,0 +1,39 @@ +#include + +#include <3ds.h> + +#include "action.h" +#include "../task/task.h" +#include "../../error.h" +#include "../../info.h" +#include "../../list.h" +#include "../../prompt.h" +#include "../../ui.h" +#include "../../../core/linkedlist.h" +#include "../../../core/screen.h" +#include "../../../core/util.h" + +static void action_import_seed_update(ui_view* view, void* data, float* progress, char* text) { + title_info* info = (title_info*) data; + + Result res = util_import_seed(info->titleId); + + ui_pop(); + info_destroy(view); + + if(R_SUCCEEDED(res)) { + prompt_display("Success", "Seed imported.", COLOR_TEXT, false, info, NULL, ui_draw_title_info, NULL); + } else { + error_display_res(NULL, info, ui_draw_title_info, res, "Failed to import seed."); + } +} + +static void action_import_seed_onresponse(ui_view* view, void* data, bool response) { + if(response) { + info_display("Importing Seed", "", false, data, action_import_seed_update, ui_draw_title_info); + } +} + +void action_import_seed(linked_list* items, list_item* selected) { + prompt_display("Confirmation", "Import the seed of the selected title?", COLOR_TEXT, true, selected->data, NULL, ui_draw_title_info, action_import_seed_onresponse); +} \ No newline at end of file diff --git a/source/ui/section/action/installcdn.c b/source/ui/section/action/installcdn.c index 0470e81..df7e409 100644 --- a/source/ui/section/action/installcdn.c +++ b/source/ui/section/action/installcdn.c @@ -12,6 +12,7 @@ #include "../../ui.h" #include "../../../core/linkedlist.h" #include "../../../core/screen.h" +#include "../../../core/util.h" #define CONTENTS_MAX 64 @@ -181,6 +182,8 @@ static void action_install_cdn_update(ui_view* view, void* data, float* progress if(R_SUCCEEDED(installData->installInfo.result)) { if(R_SUCCEEDED(res = AM_InstallTitleFinish()) && R_SUCCEEDED(res = AM_CommitImportTitles(((installData->ticket->titleId >> 32) & 0x8010) != 0 ? MEDIATYPE_NAND : MEDIATYPE_SD, 1, false, &installData->ticket->titleId))) { + util_import_seed(installData->ticket->titleId); + if(installData->ticket->titleId == 0x0004013800000002 || installData->ticket->titleId == 0x0004013820000002) { res = AM_InstallFirm(installData->ticket->titleId); } diff --git a/source/ui/section/action/installcias.c b/source/ui/section/action/installcias.c index 427edf2..b7ed9da 100644 --- a/source/ui/section/action/installcias.c +++ b/source/ui/section/action/installcias.c @@ -156,6 +156,8 @@ static Result action_install_cias_close_dst(void* data, u32 index, bool succeede Result res = 0; if(R_SUCCEEDED(res = AM_FinishCiaInstall(handle))) { + util_import_seed(installData->currTitleId); + if(installData->currTitleId == 0x0004013800000002 || installData->currTitleId == 0x0004013820000002) { res = AM_InstallFirm(installData->currTitleId); } diff --git a/source/ui/section/networkinstall.c b/source/ui/section/networkinstall.c index 4a1f334..71d98d2 100644 --- a/source/ui/section/networkinstall.c +++ b/source/ui/section/networkinstall.c @@ -16,6 +16,7 @@ #include "../prompt.h" #include "../ui.h" #include "../../core/screen.h" +#include "../../core/util.h" typedef struct { int serverSocket; @@ -171,6 +172,8 @@ static Result networkinstall_close_dst(void* data, u32 index, bool succeeded, u3 } } else { if(R_SUCCEEDED(res = AM_FinishCiaInstall(handle))) { + util_import_seed(networkInstallData->currTitleId); + if(networkInstallData->currTitleId == 0x0004013800000002 || networkInstallData->currTitleId == 0x0004013820000002) { res = AM_InstallFirm(networkInstallData->currTitleId); } diff --git a/source/ui/section/qrinstall.c b/source/ui/section/qrinstall.c index f4c12fc..2dda19f 100644 --- a/source/ui/section/qrinstall.c +++ b/source/ui/section/qrinstall.c @@ -12,6 +12,7 @@ #include "../prompt.h" #include "../ui.h" #include "../../core/screen.h" +#include "../../core/util.h" #include "../../quirc/quirc_internal.h" #define IMAGE_WIDTH 400 @@ -171,6 +172,8 @@ static Result qrinstall_close_dst(void* data, u32 index, bool succeeded, u32 han } } else { if(R_SUCCEEDED(res = AM_FinishCiaInstall(handle))) { + util_import_seed(qrInstallData->currTitleId); + if(qrInstallData->currTitleId == 0x0004013800000002 || qrInstallData->currTitleId == 0x0004013820000002) { res = AM_InstallFirm(qrInstallData->currTitleId); } diff --git a/source/ui/section/titles.c b/source/ui/section/titles.c index 0124974..2f6c7f2 100644 --- a/source/ui/section/titles.c +++ b/source/ui/section/titles.c @@ -15,6 +15,7 @@ static list_item launch_title = {"Launch Title", COLOR_TEXT, action_launch_title}; static list_item delete_title = {"Delete Title", COLOR_TEXT, action_delete_title}; static list_item extract_smdh = {"Extract SMDH", COLOR_TEXT, action_extract_smdh}; +static list_item import_seed = {"Import Seed", COLOR_TEXT, action_import_seed}; static list_item browse_save_data = {"Browse Save Data", COLOR_TEXT, action_browse_title_save_data}; static list_item import_secure_value = {"Import Secure Value", COLOR_TEXT, action_import_secure_value}; static list_item export_secure_value = {"Export Secure Value", COLOR_TEXT, action_export_secure_value}; @@ -71,6 +72,11 @@ static void titles_action_update(ui_view* view, void* data, linked_list* items, if(!info->twl) { linked_list_add(items, &extract_smdh); + + if(info->mediaType != MEDIATYPE_GAME_CARD) { + linked_list_add(items, &import_seed); + } + linked_list_add(items, &browse_save_data); if(info->mediaType != MEDIATYPE_GAME_CARD) {