From e8956c0e4ba28ec321aae949e7bdad09251c5b5e Mon Sep 17 00:00:00 2001 From: Pablo Curiel Date: Sun, 8 Nov 2020 15:08:30 -0400 Subject: [PATCH] Various changes. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Cancel USB file transfer if something goes wrong during a NSP transfer via USB. * Added SD card RomFS dumper. * Further optimizations to the *WriteNcaPatch() functions. * Change struct naming in nso.c/h (thanks @0Liam !). * Replace fsp-usb with libusbhsfs. ( ͡° ͜ʖ ͡°) --- Makefile | 4 +- code_templates/nsp_dumper_usb.c | 6 +- code_templates/sd_romfs_dumper.c | 657 +++++++++++++++++++++++++++++++ source/cnmt.c | 15 +- source/fspusb.c | 76 ---- source/fspusb.h | 50 --- source/legal_info.c | 2 +- source/nacp.c | 15 +- source/npdm.c | 15 +- source/npdm.h | 4 +- source/nso.c | 72 ++-- source/nso.h | 16 +- source/program_info.c | 2 +- source/services.c | 16 - source/utils.c | 14 + 15 files changed, 753 insertions(+), 211 deletions(-) create mode 100644 code_templates/sd_romfs_dumper.c delete mode 100644 source/fspusb.c delete mode 100644 source/fspusb.h diff --git a/Makefile b/Makefile index 1740fa3..19bf442 100644 --- a/Makefile +++ b/Makefile @@ -69,13 +69,13 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions ASFLAGS := -g $(ARCH) LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) -LIBS := -lcurl -lmbedtls -lmbedx509 -lmbedcrypto -lxml2 -lz -lnx -ljson-c -lm `freetype-config --libs` -lturbojpeg +LIBS := -lcurl -lmbedtls -lmbedx509 -lmbedcrypto -lxml2 -lz -lusbhsfsd -lnx -ljson-c -lm `freetype-config --libs` -lturbojpeg #--------------------------------------------------------------------------------- # list of directories containing libraries, this must be the top level containing # include and lib #--------------------------------------------------------------------------------- -LIBDIRS := $(PORTLIBS) $(LIBNX) +LIBDIRS := $(PORTLIBS) $(LIBNX) $(CURDIR)/../libusbhsfs #--------------------------------------------------------------------------------- diff --git a/code_templates/nsp_dumper_usb.c b/code_templates/nsp_dumper_usb.c index 9d64bd4..7f10bd9 100644 --- a/code_templates/nsp_dumper_usb.c +++ b/code_templates/nsp_dumper_usb.c @@ -94,6 +94,7 @@ static void nspDump(TitleInfo *title_info) bool patch_sua = options[4].val; bool patch_screenshot = options[5].val; bool patch_video_capture = options[6].val; + bool success = false, usb_conn = false; u8 *buf = NULL; char *dump_name = NULL, *path = NULL; @@ -458,7 +459,6 @@ static void nspDump(TitleInfo *title_info) consolePrint("waiting for usb connection... "); time_t start = time(NULL); - bool usb_conn = false; while(true) { @@ -727,7 +727,11 @@ static void nspDump(TitleInfo *title_info) start = (time(NULL) - start); consolePrint("process successfully completed in %lu seconds!\n", start); + success = true; + end: + if (usb_conn && !success) usbCancelFileTransfer(); + pfsFreeFileContext(&pfs_file_ctx); if (raw_cert_chain) free(raw_cert_chain); diff --git a/code_templates/sd_romfs_dumper.c b/code_templates/sd_romfs_dumper.c new file mode 100644 index 0000000..11889af --- /dev/null +++ b/code_templates/sd_romfs_dumper.c @@ -0,0 +1,657 @@ +/* + * main.c + * + * Copyright (c) 2020, DarkMatterCore . + * + * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). + * + * nxdumptool is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * nxdumptool is distributed in the hope 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 "utils.h" +#include "bktr.h" +#include "gamecard.h" +#include "title.h" + +#define BLOCK_SIZE 0x800000 + +static Mutex g_fileMutex = 0; +static CondVar g_readCondvar = 0, g_writeCondvar = 0; + +typedef struct +{ + FILE *fd; + RomFileSystemContext *romfs_ctx; + BktrContext *bktr_ctx; + void *data; + size_t data_size; + size_t data_written; + size_t total_size; + bool read_error; + bool write_error; + bool transfer_cancelled; +} ThreadSharedData; + +static void consolePrint(const char *text, ...) +{ + va_list v; + va_start(v, text); + vfprintf(stdout, text, v); + va_end(v); + consoleUpdate(NULL); +} + +static void read_thread_func(void *arg) +{ + ThreadSharedData *shared_data = (ThreadSharedData*)arg; + if (!shared_data || shared_data->fd || !shared_data->data || !shared_data->total_size || (!shared_data->romfs_ctx && !shared_data->bktr_ctx)) + { + shared_data->read_error = true; + goto end; + } + + u8 *buf = malloc(BLOCK_SIZE); + if (!buf) + { + shared_data->read_error = true; + goto end; + } + + u64 file_table_offset = 0; + u64 file_table_size = (shared_data->bktr_ctx ? shared_data->bktr_ctx->patch_romfs_ctx.file_table_size : shared_data->romfs_ctx->file_table_size); + RomFileSystemFileEntry *file_entry = NULL; + + char path[FS_MAX_PATH] = {0}; + sprintf(path, "sdmc:/romfs"); + + while(file_table_offset < file_table_size) + { + /* Check if the transfer has been cancelled by the user. */ + if (shared_data->transfer_cancelled) + { + condvarWakeAll(&g_writeCondvar); + break; + } + + /* Wait until the previous file data chunk has been written. */ + mutexLock(&g_fileMutex); + if (shared_data->data_size && !shared_data->write_error) condvarWait(&g_readCondvar, &g_fileMutex); + mutexUnlock(&g_fileMutex); + if (shared_data->write_error) break; + + /* Close file. */ + if (shared_data->fd) + { + fclose(shared_data->fd); + shared_data->fd = NULL; + } + + /* Retrieve RomFS file entry information. */ + if (shared_data->bktr_ctx) + { + shared_data->read_error = (!(file_entry = bktrGetFileEntryByOffset(shared_data->bktr_ctx, file_table_offset)) || \ + !bktrGeneratePathFromFileEntry(shared_data->bktr_ctx, file_entry, path + 11, FS_MAX_PATH - 11, RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly)); + } else { + shared_data->read_error = (!(file_entry = romfsGetFileEntryByOffset(shared_data->romfs_ctx, file_table_offset)) || \ + !romfsGeneratePathFromFileEntry(shared_data->romfs_ctx, file_entry, path + 11, FS_MAX_PATH - 11, RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly)); + } + + if (shared_data->read_error) + { + condvarWakeAll(&g_writeCondvar); + break; + } + + /* Create directory tree. */ + utilsCreateDirectoryTree(path, false); + + /* Create file. */ + shared_data->read_error = ((shared_data->fd = fopen(path, "wb")) == NULL); + if (shared_data->read_error) + { + condvarWakeAll(&g_writeCondvar); + break; + } + + for(u64 offset = 0, blksize = BLOCK_SIZE; offset < file_entry->size; offset += blksize) + { + if (blksize > (file_entry->size - offset)) blksize = (file_entry->size - offset); + + /* Check if the transfer has been cancelled by the user. */ + if (shared_data->transfer_cancelled) + { + condvarWakeAll(&g_writeCondvar); + break; + } + + /* Read current file data chunk. */ + shared_data->read_error = (shared_data->bktr_ctx ? !bktrReadFileEntryData(shared_data->bktr_ctx, file_entry, buf, blksize, offset) : \ + !romfsReadFileEntryData(shared_data->romfs_ctx, file_entry, buf, blksize, offset)); + if (shared_data->read_error) + { + condvarWakeAll(&g_writeCondvar); + break; + } + + /* Wait until the previous file data chunk has been written. */ + mutexLock(&g_fileMutex); + + if (shared_data->data_size && !shared_data->write_error) condvarWait(&g_readCondvar, &g_fileMutex); + + if (shared_data->write_error) + { + mutexUnlock(&g_fileMutex); + break; + } + + /* Copy current file data chunk to the shared buffer. */ + memcpy(shared_data->data, buf, blksize); + shared_data->data_size = blksize; + + /* Wake up the write thread to continue writing data. */ + mutexUnlock(&g_fileMutex); + condvarWakeAll(&g_writeCondvar); + } + + if (shared_data->read_error || shared_data->write_error || shared_data->transfer_cancelled) break; + + file_table_offset += ALIGN_UP(sizeof(RomFileSystemFileEntry) + file_entry->name_length, 4); + } + + /* Wait until the previous file data chunk has been written. */ + mutexLock(&g_fileMutex); + if (shared_data->data_size && !shared_data->write_error) condvarWait(&g_readCondvar, &g_fileMutex); + mutexUnlock(&g_fileMutex); + + if (shared_data->fd) + { + fclose(shared_data->fd); + shared_data->fd = NULL; + } + + if ((shared_data->read_error || shared_data->write_error || shared_data->transfer_cancelled) && *path) remove(path); + + free(buf); + +end: + threadExit(); +} + +static void write_thread_func(void *arg) +{ + ThreadSharedData *shared_data = (ThreadSharedData*)arg; + if (!shared_data || !shared_data->data) + { + shared_data->write_error = true; + goto end; + } + + while(shared_data->data_written < shared_data->total_size) + { + /* Wait until the current file data chunk has been read */ + mutexLock(&g_fileMutex); + + if (!shared_data->data_size && !shared_data->read_error) condvarWait(&g_writeCondvar, &g_fileMutex); + + if (shared_data->read_error || shared_data->transfer_cancelled || !shared_data->fd) + { + mutexUnlock(&g_fileMutex); + break; + } + + /* Write current file data chunk */ + shared_data->write_error = (fwrite(shared_data->data, 1, shared_data->data_size, shared_data->fd) != shared_data->data_size); + if (!shared_data->write_error) + { + shared_data->data_written += shared_data->data_size; + shared_data->data_size = 0; + } + + /* Wake up the read thread to continue reading data */ + mutexUnlock(&g_fileMutex); + condvarWakeAll(&g_readCondvar); + + if (shared_data->write_error) break; + } + +end: + threadExit(); +} + +u8 get_program_id_offset(TitleInfo *info, u32 program_count) +{ + if (program_count <= 1) return 0; + + u8 id_offset = 0; + u32 selected_idx = 0, page_size = 30, scroll = 0; + char nca_id_str[0x21] = {0}; + + NcmContentInfo **content_infos = calloc(program_count, sizeof(NcmContentInfo*)); + if (!content_infos) return 0; + + for(u32 i = 0, j = 0; i < info->content_count && j < program_count; i++) + { + if (info->content_infos[i].content_type != NcmContentType_Program) continue; + content_infos[j++] = &(info->content_infos[i]); + } + + while(true) + { + consoleClear(); + printf("select a program nca to dump the romfs from.\n\n"); + + for(u32 i = scroll; i < program_count; i++) + { + if (i >= (scroll + page_size)) break; + utilsGenerateHexStringFromData(nca_id_str, sizeof(nca_id_str), content_infos[i]->content_id.c, SHA256_HASH_SIZE / 2); + printf("%s%s.nca (ID offset #%u)\n", i == selected_idx ? " -> " : " ", nca_id_str, content_infos[i]->id_offset); + } + + printf("\n"); + + consoleUpdate(NULL); + + u64 btn_down = 0, btn_held = 0; + while(true) + { + hidScanInput(); + btn_down = utilsHidKeysAllDown(); + btn_held = utilsHidKeysAllHeld(); + if (btn_down || btn_held) break; + } + + if (btn_down & KEY_A) + { + id_offset = content_infos[selected_idx]->id_offset; + break; + } else + if ((btn_down & KEY_DDOWN) || (btn_held & (KEY_LSTICK_DOWN | KEY_RSTICK_DOWN))) + { + selected_idx++; + + if (selected_idx >= program_count) + { + if (btn_down & KEY_DDOWN) + { + selected_idx = scroll = 0; + } else { + selected_idx = (program_count - 1); + } + } else + if (selected_idx >= (scroll + (page_size / 2)) && program_count > (scroll + page_size)) + { + scroll++; + } + } else + if ((btn_down & KEY_DUP) || (btn_held & (KEY_LSTICK_UP | KEY_RSTICK_UP))) + { + selected_idx--; + + if (selected_idx == UINT32_MAX) + { + if (btn_down & KEY_DUP) + { + selected_idx = (program_count - 1); + scroll = (program_count >= page_size ? (program_count - page_size) : 0); + } else { + selected_idx = 0; + } + } else + if (selected_idx < (scroll + (page_size / 2)) && scroll > 0) + { + scroll--; + } + } + + if (btn_held & (KEY_LSTICK_DOWN | KEY_RSTICK_DOWN | KEY_LSTICK_UP | KEY_RSTICK_UP)) svcSleepThread(50000000); // 50 ms + } + + free(content_infos); + + return id_offset; +} + +int main(int argc, char *argv[]) +{ + (void)argc; + (void)argv; + + int ret = 0; + + consoleInit(NULL); + + consolePrint("initializing...\n"); + + if (!utilsInitializeResources()) + { + ret = -1; + goto out; + } + + u32 app_count = 0; + TitleApplicationMetadata **app_metadata = NULL; + TitleUserApplicationData user_app_data = {0}; + + u32 selected_idx = 0, page_size = 30, scroll = 0; + bool exit_prompt = true; + + u8 *buf = NULL; + + NcaContext *base_nca_ctx = NULL, *update_nca_ctx = NULL; + + RomFileSystemContext romfs_ctx = {0}; + BktrContext bktr_ctx = {0}; + + ThreadSharedData shared_data = {0}; + Thread read_thread = {0}, write_thread = {0}; + + app_metadata = titleGetApplicationMetadataEntries(false, &app_count); + if (!app_metadata || !app_count) + { + consolePrint("app metadata failed\n"); + goto out2; + } + + consolePrint("app metadata succeeded\n"); + + buf = malloc(BLOCK_SIZE); + if (!buf) + { + consolePrint("buf failed\n"); + goto out2; + } + + consolePrint("buf succeeded\n"); + + base_nca_ctx = calloc(1, sizeof(NcaContext)); + if (!base_nca_ctx) + { + consolePrint("base nca ctx buf failed\n"); + goto out2; + } + + consolePrint("base nca ctx buf succeeded\n"); + + update_nca_ctx = calloc(1, sizeof(NcaContext)); + if (!update_nca_ctx) + { + consolePrint("update nca ctx buf failed\n"); + goto out2; + } + + consolePrint("update nca ctx buf succeeded\n"); + + utilsSleep(1); + + while(true) + { + consoleClear(); + printf("select a user application to dump its romfs.\nif an update is available, patch romfs data will be dumped instead.\ndata will be saved to \"sdmc:/romfs\".\npress b to exit.\n\n"); + printf("title: %u / %u\n", selected_idx + 1, app_count); + printf("selected title: %016lX - %s\n\n", app_metadata[selected_idx]->title_id, app_metadata[selected_idx]->lang_entry.name); + + for(u32 i = scroll; i < app_count; i++) + { + if (i >= (scroll + page_size)) break; + printf("%s%016lX - %s\n", i == selected_idx ? " -> " : " ", app_metadata[i]->title_id, app_metadata[i]->lang_entry.name); + } + + printf("\n"); + + consoleUpdate(NULL); + + u64 btn_down = 0, btn_held = 0; + while(true) + { + hidScanInput(); + btn_down = utilsHidKeysAllDown(); + btn_held = utilsHidKeysAllHeld(); + if (btn_down || btn_held) break; + + if (titleIsGameCardInfoUpdated()) + { + free(app_metadata); + + app_metadata = titleGetApplicationMetadataEntries(false, &app_count); + if (!app_metadata) + { + consolePrint("\napp metadata failed\n"); + goto out2; + } + + selected_idx = scroll = 0; + break; + } + } + + if (btn_down & KEY_A) + { + if (!titleGetUserApplicationData(app_metadata[selected_idx]->title_id, &user_app_data) || !user_app_data.app_info) + { + consolePrint("\nthe selected title doesn't have available base content.\n"); + utilsSleep(3); + continue; + } + + break; + } else + if ((btn_down & KEY_DDOWN) || (btn_held & (KEY_LSTICK_DOWN | KEY_RSTICK_DOWN))) + { + selected_idx++; + + if (selected_idx >= app_count) + { + if (btn_down & KEY_DDOWN) + { + selected_idx = scroll = 0; + } else { + selected_idx = (app_count - 1); + } + } else + if (selected_idx >= (scroll + (page_size / 2)) && app_count > (scroll + page_size)) + { + scroll++; + } + } else + if ((btn_down & KEY_DUP) || (btn_held & (KEY_LSTICK_UP | KEY_RSTICK_UP))) + { + selected_idx--; + + if (selected_idx == UINT32_MAX) + { + if (btn_down & KEY_DUP) + { + selected_idx = (app_count - 1); + scroll = (app_count >= page_size ? (app_count - page_size) : 0); + } else { + selected_idx = 0; + } + } else + if (selected_idx < (scroll + (page_size / 2)) && scroll > 0) + { + scroll--; + } + } else + if (btn_down & KEY_B) + { + exit_prompt = false; + goto out2; + } + + if (btn_held & (KEY_LSTICK_DOWN | KEY_RSTICK_DOWN | KEY_LSTICK_UP | KEY_RSTICK_UP)) svcSleepThread(50000000); // 50 ms + } + + u32 program_count = titleGetContentCountByType(user_app_data.app_info, NcmContentType_Program); + if (!program_count) + { + consolePrint("base app has no program ncas!\n"); + goto out2; + } + + u8 program_id_offset = get_program_id_offset(user_app_data.app_info, program_count); + + consoleClear(); + consolePrint("selected title:\n%s (%016lX)\n\n", app_metadata[selected_idx]->lang_entry.name, app_metadata[selected_idx]->title_id + program_id_offset); + + if (!ncaInitializeContext(base_nca_ctx, user_app_data.app_info->storage_id, (user_app_data.app_info->storage_id == NcmStorageId_GameCard ? GameCardHashFileSystemPartitionType_Secure : 0), \ + titleGetContentInfoByTypeAndIdOffset(user_app_data.app_info, NcmContentType_Program, program_id_offset), NULL)) + { + consolePrint("nca initialize base ctx failed\n"); + goto out2; + } + + if (user_app_data.patch_info) + { + if (!ncaInitializeContext(update_nca_ctx, user_app_data.patch_info->storage_id, (user_app_data.patch_info->storage_id == NcmStorageId_GameCard ? GameCardHashFileSystemPartitionType_Secure : 0), \ + titleGetContentInfoByTypeAndIdOffset(user_app_data.patch_info, NcmContentType_Program, program_id_offset), NULL)) + { + consolePrint("nca initialize update ctx failed\n"); + goto out2; + } + + if (!bktrInitializeContext(&bktr_ctx, &(base_nca_ctx->fs_ctx[1]), &(update_nca_ctx->fs_ctx[1]))) + { + consolePrint("bktr initialize ctx failed\n"); + goto out2; + } + + shared_data.bktr_ctx = &bktr_ctx; + bktrGetTotalDataSize(&bktr_ctx, &(shared_data.total_size)); + + consolePrint("bktr initialize ctx succeeded\n"); + } else { + if (!romfsInitializeContext(&romfs_ctx, &(base_nca_ctx->fs_ctx[1]))) + { + consolePrint("romfs initialize ctx failed\n"); + goto out2; + } + + shared_data.romfs_ctx = &romfs_ctx; + romfsGetTotalDataSize(&romfs_ctx, &(shared_data.total_size)); + + consolePrint("romfs initialize ctx succeeded\n"); + } + + shared_data.fd = NULL; + shared_data.data = buf; + shared_data.data_size = 0; + shared_data.data_written = 0; + + consolePrint("creating threads\n"); + utilsCreateThread(&read_thread, read_thread_func, &shared_data, 2); + utilsCreateThread(&write_thread, write_thread_func, &shared_data, 2); + + u8 prev_time = 0; + u64 prev_size = 0; + u8 percent = 0; + + time_t btn_cancel_start_tmr = 0, btn_cancel_end_tmr = 0; + bool btn_cancel_cur_state = false, btn_cancel_prev_state = false; + + utilsChangeHomeButtonBlockStatus(true); + + consolePrint("hold b to cancel\n\n"); + + time_t start = time(NULL); + + while(shared_data.data_written < shared_data.total_size) + { + if (shared_data.read_error || shared_data.write_error) break; + + time_t now = time(NULL); + struct tm *ts = localtime(&now); + size_t size = shared_data.data_written; + + hidScanInput(); + btn_cancel_cur_state = (utilsHidKeysAllHeld() & KEY_B); + + if (btn_cancel_cur_state && btn_cancel_cur_state != btn_cancel_prev_state) + { + btn_cancel_start_tmr = now; + } else + if (btn_cancel_cur_state && btn_cancel_cur_state == btn_cancel_prev_state) + { + btn_cancel_end_tmr = now; + if ((btn_cancel_end_tmr - btn_cancel_start_tmr) >= 3) + { + mutexLock(&g_fileMutex); + shared_data.transfer_cancelled = true; + mutexUnlock(&g_fileMutex); + break; + } + } else { + btn_cancel_start_tmr = btn_cancel_end_tmr = 0; + } + + btn_cancel_prev_state = btn_cancel_cur_state; + + if (prev_time == ts->tm_sec || prev_size == size) continue; + + percent = (u8)((size * 100) / shared_data.total_size); + + prev_time = ts->tm_sec; + prev_size = size; + + printf("%lu / %lu (%u%%) | Time elapsed: %lu\n", size, shared_data.total_size, percent, (now - start)); + consoleUpdate(NULL); + } + + start = (time(NULL) - start); + + consolePrint("\nwaiting for threads to join\n"); + utilsJoinThread(&read_thread); + consolePrint("read_thread done: %lu\n", time(NULL)); + utilsJoinThread(&write_thread); + consolePrint("write_thread done: %lu\n", time(NULL)); + + utilsChangeHomeButtonBlockStatus(false); + + if (shared_data.read_error || shared_data.write_error) + { + consolePrint("i/o error\n"); + goto out2; + } + + if (shared_data.transfer_cancelled) + { + consolePrint("process cancelled\n"); + goto out2; + } + + consolePrint("process completed in %lu seconds\n", start); + +out2: + if (exit_prompt) + { + consolePrint("press any button to exit\n"); + utilsWaitForButtonPress(KEY_ANY); + } + + romfsFreeContext(&romfs_ctx); + bktrFreeContext(&bktr_ctx); + + if (update_nca_ctx) free(update_nca_ctx); + + if (base_nca_ctx) free(base_nca_ctx); + + if (buf) free(buf); + + if (app_metadata) free(app_metadata); + +out: + utilsCloseResources(); + + consoleExit(NULL); + + return ret; +} diff --git a/source/cnmt.c b/source/cnmt.c index 13f98a4..67ba7a0 100644 --- a/source/cnmt.c +++ b/source/cnmt.c @@ -43,7 +43,7 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx) { if (!out || !nca_ctx || !*(nca_ctx->content_id_str) || nca_ctx->content_type != NcmContentType_Meta || nca_ctx->content_size < NCA_FULL_HEADER_LENGTH || \ (nca_ctx->storage_id != NcmStorageId_GameCard && !nca_ctx->ncm_storage) || (nca_ctx->storage_id == NcmStorageId_GameCard && !nca_ctx->gamecard_offset) || \ - nca_ctx->header.content_type != NcaContentType_Meta || !out) + nca_ctx->header.content_type != NcaContentType_Meta || nca_ctx->content_type_ctx || !out) { LOGFILE("Invalid parameters!"); return false; @@ -317,17 +317,20 @@ bool cnmtGenerateNcaPatch(ContentMetaContext *cnmt_ctx) void cnmtWriteNcaPatch(ContentMetaContext *cnmt_ctx, void *buf, u64 buf_size, u64 buf_offset) { + NcaContext *nca_ctx = NULL; + NcaHierarchicalSha256Patch *nca_patch = (cnmt_ctx ? &(cnmt_ctx->nca_patch) : NULL); + /* Using cnmtIsValidContext() here would probably take up precious CPU cycles. */ - if (!cnmt_ctx || !cnmt_ctx->nca_ctx || cnmt_ctx->nca_ctx->content_type != NcmContentType_Meta || !cnmt_ctx->nca_ctx->content_type_ctx_patch || cnmt_ctx->nca_patch.written) return; + if (!nca_patch || nca_patch->written || !(nca_ctx = cnmt_ctx->nca_ctx) || nca_ctx->content_type != NcmContentType_Meta || !nca_ctx->content_type_ctx_patch) return; /* Attempt to write Partition FS entry patch. */ - pfsWriteEntryPatchToMemoryBuffer(&(cnmt_ctx->pfs_ctx), &(cnmt_ctx->nca_patch), buf, buf_size, buf_offset); + pfsWriteEntryPatchToMemoryBuffer(&(cnmt_ctx->pfs_ctx), nca_patch, buf, buf_size, buf_offset); /* Check if we need to update the NCA content type context patch status. */ - if (cnmt_ctx->nca_patch.written) + if (nca_patch->written) { - cnmt_ctx->nca_ctx->content_type_ctx_patch = false; - LOGFILE("CNMT Partition FS entry patch successfully written to NCA \"%s\"!", cnmt_ctx->nca_ctx->content_id_str); + nca_ctx->content_type_ctx_patch = false; + LOGFILE("CNMT Partition FS entry patch successfully written to NCA \"%s\"!", nca_ctx->content_id_str); } } diff --git a/source/fspusb.c b/source/fspusb.c deleted file mode 100644 index 724d8d8..0000000 --- a/source/fspusb.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * fspusb.c - * - * Copyright (c) 2019-2020, XorTroll. - * Copyright (c) 2019-2020, DarkMatterCore . - * - * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). - * - * nxdumptool is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * nxdumptool is distributed in the hope 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 . - */ - -#define NX_SERVICE_ASSUME_NON_DOMAIN - -#include "utils.h" -#include "fspusb.h" -#include "service_guard.h" - -static Service g_fspusbSrv; - -NX_GENERATE_SERVICE_GUARD(fspusb); - -Result _fspusbInitialize(void) { - return smGetService(&g_fspusbSrv, "fsp-usb"); -} - -void _fspusbCleanup(void) { - serviceClose(&g_fspusbSrv); -} - -Service* fspusbGetServiceSession(void) { - return &g_fspusbSrv; -} - -Result fspusbListMountedDrives(s32 *drives_buf, size_t drive_count, s32 *out_total) { - return serviceDispatchOut(&g_fspusbSrv, 0, *out_total, - .buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias }, - .buffers = { { drives_buf, drive_count * sizeof(s32) } }, - ); -} - -Result fspusbGetDriveFileSystemType(s32 interface_id, FspUsbFileSystemType *out_type) { - return serviceDispatchInOut(&g_fspusbSrv, 1, interface_id, *out_type); -} - -Result fspusbGetDriveLabel(s32 interface_id, char *out_label, size_t out_label_size) { - return serviceDispatchIn(&g_fspusbSrv, 2, interface_id, - .buffer_attrs = { SfBufferAttr_Out | SfBufferAttr_HipcMapAlias }, - .buffers = { { out_label, out_label_size } }, - ); -} - -Result fspusbSetDriveLabel(s32 interface_id, const char *label) { - char inputlbl[11 + 1] = {0}; /* Actual limit is 11 characters. */ - strncpy(inputlbl, label, 11); - return serviceDispatchIn(&g_fspusbSrv, 3, interface_id, - .buffer_attrs = { SfBufferAttr_In | SfBufferAttr_HipcMapAlias }, - .buffers = { { inputlbl, 11 + 1 } }, - ); -} - -Result fspusbOpenDriveFileSystem(s32 interface_id, FsFileSystem *out_fs) { - return serviceDispatchIn(&g_fspusbSrv, 4, interface_id, - .out_num_objects = 1, - .out_objects = &out_fs->s, - ); -} \ No newline at end of file diff --git a/source/fspusb.h b/source/fspusb.h deleted file mode 100644 index b944b27..0000000 --- a/source/fspusb.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * fspusb.h - * - * Copyright (c) 2019-2020, XorTroll. - * Copyright (c) 2019-2020, DarkMatterCore . - * - * This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool). - * - * nxdumptool is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * nxdumptool is distributed in the hope 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 . - */ - -#pragma once - -#ifndef __FSPUSB_H__ -#define __FSPUSB_H__ - -/// This is basically FatFs' file system types. -typedef enum { - FspUsbFileSystemType_FAT12 = 1, - FspUsbFileSystemType_FAT16 = 2, - FspUsbFileSystemType_FAT32 = 3, - FspUsbFileSystemType_exFAT = 4 -} FspUsbFileSystemType; - -/// Initialize fsp-usb. -Result fspusbInitialize(void); - -/// Exit fsp-usb. -void fspusbExit(void); - -/// Gets the Service object for the actual fsp-usb service session. -Service* fspusbGetServiceSession(void); - -Result fspusbListMountedDrives(s32 *drives_buf, size_t drive_count, s32 *out_total); -Result fspusbGetDriveFileSystemType(s32 interface_id, FspUsbFileSystemType *out_type); -Result fspusbGetDriveLabel(s32 interface_id, char *out_label, size_t out_label_size); -Result fspusbSetDriveLabel(s32 interface_id, const char *label); -Result fspusbOpenDriveFileSystem(s32 interface_id, FsFileSystem *out_fs); - -#endif /* __FSPUSB_H__ */ diff --git a/source/legal_info.c b/source/legal_info.c index e7fe7f9..8a2329e 100644 --- a/source/legal_info.c +++ b/source/legal_info.c @@ -26,7 +26,7 @@ bool legalInfoInitializeContext(LegalInfoContext *out, NcaContext *nca_ctx) { if (!out || !nca_ctx || !*(nca_ctx->content_id_str) || nca_ctx->content_type != NcmContentType_LegalInformation || nca_ctx->content_size < NCA_FULL_HEADER_LENGTH || \ (nca_ctx->storage_id != NcmStorageId_GameCard && !nca_ctx->ncm_storage) || (nca_ctx->storage_id == NcmStorageId_GameCard && !nca_ctx->gamecard_offset) || \ - nca_ctx->header.content_type != NcaContentType_Manual || !out) + nca_ctx->header.content_type != NcaContentType_Manual || nca_ctx->content_type_ctx || !out) { LOGFILE("Invalid parameters!"); return false; diff --git a/source/nacp.c b/source/nacp.c index ca5cfa8..1e32359 100644 --- a/source/nacp.c +++ b/source/nacp.c @@ -199,7 +199,7 @@ bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx) { if (!out || !nca_ctx || !*(nca_ctx->content_id_str) || nca_ctx->content_type != NcmContentType_Control || nca_ctx->content_size < NCA_FULL_HEADER_LENGTH || \ (nca_ctx->storage_id != NcmStorageId_GameCard && !nca_ctx->ncm_storage) || (nca_ctx->storage_id == NcmStorageId_GameCard && !nca_ctx->gamecard_offset) || \ - nca_ctx->header.content_type != NcaContentType_Control || !out) + nca_ctx->header.content_type != NcaContentType_Control || nca_ctx->content_type_ctx || !out) { LOGFILE("Invalid parameters!"); return false; @@ -380,17 +380,20 @@ bool nacpGenerateNcaPatch(NacpContext *nacp_ctx, bool patch_sua, bool patch_scre void nacpWriteNcaPatch(NacpContext *nacp_ctx, void *buf, u64 buf_size, u64 buf_offset) { + NcaContext *nca_ctx = NULL; + RomFileSystemFileEntryPatch *nca_patch = (nacp_ctx ? &(nacp_ctx->nca_patch) : NULL); + /* Using nacpIsValidContext() here would probably take up precious CPU cycles. */ - if (!nacp_ctx || !nacp_ctx->nca_ctx || nacp_ctx->nca_ctx->content_type != NcmContentType_Control || !nacp_ctx->nca_ctx->content_type_ctx_patch || nacp_ctx->nca_patch.written) return; + if (!nca_patch || nca_patch->written || !(nca_ctx = nacp_ctx->nca_ctx) || nca_ctx->content_type != NcmContentType_Control || !nca_ctx->content_type_ctx_patch) return; /* Attempt to write RomFS file entry patch. */ - romfsWriteFileEntryPatchToMemoryBuffer(&(nacp_ctx->romfs_ctx), &(nacp_ctx->nca_patch), buf, buf_size, buf_offset); + romfsWriteFileEntryPatchToMemoryBuffer(&(nacp_ctx->romfs_ctx), nca_patch, buf, buf_size, buf_offset); /* Check if we need to update the NCA content type context patch status. */ - if (nacp_ctx->nca_patch.written) + if (nca_patch->written) { - nacp_ctx->nca_ctx->content_type_ctx_patch = false; - LOGFILE("NACP RomFS file entry patch successfully written to NCA \"%s\"!", nacp_ctx->nca_ctx->content_id_str); + nca_ctx->content_type_ctx_patch = false; + LOGFILE("NACP RomFS file entry patch successfully written to NCA \"%s\"!", nca_ctx->content_id_str); } } diff --git a/source/npdm.c b/source/npdm.c index b447258..2b1182b 100644 --- a/source/npdm.c +++ b/source/npdm.c @@ -39,6 +39,7 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx npdmFreeContext(out); /* Get 'main.npdm' file entry. */ + out->nca_ctx = nca_ctx; out->pfs_ctx = pfs_ctx; if (!(out->pfs_entry = pfsGetEntryByName(out->pfs_ctx, "main.npdm"))) { @@ -260,14 +261,14 @@ end: bool npdmGenerateNcaPatch(NpdmContext *npdm_ctx) { - NcaContext *nca_ctx = NULL; - - if (!npdmIsValidContext(npdm_ctx) || !(nca_ctx = (NcaContext*)npdm_ctx->pfs_ctx->nca_fs_ctx->nca_ctx) || nca_ctx->content_type != NcmContentType_Program) + if (!npdmIsValidContext(npdm_ctx) || npdm_ctx->nca_ctx->content_type != NcmContentType_Program) { LOGFILE("Invalid parameters!"); return false; } + NcaContext *nca_ctx = npdm_ctx->nca_ctx; + /* Check if we really need to generate this patch. */ if (!ncaIsHeaderDirty(nca_ctx)) { @@ -301,16 +302,16 @@ bool npdmGenerateNcaPatch(NpdmContext *npdm_ctx) void npdmWriteNcaPatch(NpdmContext *npdm_ctx, void *buf, u64 buf_size, u64 buf_offset) { NcaContext *nca_ctx = NULL; + NcaHierarchicalSha256Patch *nca_patch = (npdm_ctx ? &(npdm_ctx->nca_patch) : NULL); /* Using npdmIsValidContext() here would probably take up precious CPU cycles. */ - if (!npdm_ctx || !npdm_ctx->pfs_ctx || !npdm_ctx->pfs_ctx->nca_fs_ctx || !(nca_ctx = (NcaContext*)npdm_ctx->pfs_ctx->nca_fs_ctx->nca_ctx) || nca_ctx->content_type != NcmContentType_Program || \ - !nca_ctx->content_type_ctx_patch || npdm_ctx->nca_patch.written) return; + if (!nca_patch || nca_patch->written || !(nca_ctx = npdm_ctx->nca_ctx) || nca_ctx->content_type != NcmContentType_Program || !nca_ctx->content_type_ctx_patch) return; /* Attempt to write Partition FS entry patch. */ - pfsWriteEntryPatchToMemoryBuffer(npdm_ctx->pfs_ctx, &(npdm_ctx->nca_patch), buf, buf_size, buf_offset); + pfsWriteEntryPatchToMemoryBuffer(npdm_ctx->pfs_ctx, nca_patch, buf, buf_size, buf_offset); /* Check if we need to update the NCA content type context patch status. */ - if (npdm_ctx->nca_patch.written) + if (nca_patch->written) { nca_ctx->content_type_ctx_patch = false; LOGFILE("NPDM Partition FS entry patch successfully written to NCA \"%s\"!", nca_ctx->content_id_str); diff --git a/source/npdm.h b/source/npdm.h index 2bfa680..9206f4f 100644 --- a/source/npdm.h +++ b/source/npdm.h @@ -534,6 +534,7 @@ typedef struct { } NpdmKernelCapabilityDescriptorEntry; typedef struct { + NcaContext *nca_ctx; ///< Pointer to the NCA context for the Program NCA from which NPDM data is retrieved. PartitionFileSystemContext *pfs_ctx; ///< PartitionFileSystemContext for the Program NCA FS section #0, which is where the NPDM is stored. PartitionFileSystemEntry *pfs_entry; ///< PartitionFileSystemEntry for the NPDM in the Program NCA FS section #0. Used to generate a NcaHierarchicalSha256Patch if needed. NcaHierarchicalSha256Patch nca_patch; ///< NcaHierarchicalSha256Patch generated if NPDM modifications are needed. Used to seamlessly replace Program NCA data while writing it. @@ -572,7 +573,8 @@ NX_INLINE void npdmFreeContext(NpdmContext *npdm_ctx) NX_INLINE bool npdmIsValidContext(NpdmContext *npdm_ctx) { - return (npdm_ctx && npdm_ctx->pfs_ctx && npdm_ctx->pfs_entry && npdm_ctx->raw_data && npdm_ctx->raw_data_size && npdm_ctx->meta_header && npdm_ctx->acid_header && npdm_ctx->acid_fac_descriptor && \ + return (npdm_ctx && npdm_ctx->nca_ctx && npdm_ctx->pfs_ctx && npdm_ctx->pfs_entry && npdm_ctx->raw_data && npdm_ctx->raw_data_size && npdm_ctx->meta_header && npdm_ctx->acid_header && \ + npdm_ctx->acid_fac_descriptor && \ ((npdm_ctx->acid_header->srv_access_control_size && npdm_ctx->acid_sac_descriptor) || (!npdm_ctx->acid_header->srv_access_control_size && !npdm_ctx->acid_sac_descriptor)) && \ ((npdm_ctx->acid_header->kernel_capability_size && npdm_ctx->acid_kc_descriptor) || (!npdm_ctx->acid_header->kernel_capability_size && !npdm_ctx->acid_kc_descriptor)) && \ npdm_ctx->aci_header && npdm_ctx->aci_fac_data && \ diff --git a/source/nso.c b/source/nso.c index 1bb71d5..2726c66 100644 --- a/source/nso.c +++ b/source/nso.c @@ -72,33 +72,33 @@ bool nsoInitializeContext(NsoContext *out, PartitionFileSystemContext *pfs_ctx, goto end; } - if (out->nso_header.text_segment_header.file_offset < sizeof(NsoHeader) || !out->nso_header.text_segment_header.size || \ - ((out->nso_header.flags & NsoFlags_TextCompress) && (!out->nso_header.text_file_size || out->nso_header.text_file_size > out->nso_header.text_segment_header.size)) || \ - (!(out->nso_header.flags & NsoFlags_TextCompress) && out->nso_header.text_file_size != out->nso_header.text_segment_header.size) || \ - (out->nso_header.text_segment_header.file_offset + out->nso_header.text_file_size) > pfs_entry->size) + if (out->nso_header.text_segment_info.file_offset < sizeof(NsoHeader) || !out->nso_header.text_segment_info.size || \ + ((out->nso_header.flags & NsoFlags_TextCompress) && (!out->nso_header.text_file_size || out->nso_header.text_file_size > out->nso_header.text_segment_info.size)) || \ + (!(out->nso_header.flags & NsoFlags_TextCompress) && out->nso_header.text_file_size != out->nso_header.text_segment_info.size) || \ + (out->nso_header.text_segment_info.file_offset + out->nso_header.text_file_size) > pfs_entry->size) { - LOGFILE("Invalid .text segment offset/size for NSO \"%s\"! (0x%08X, 0x%08X, 0x%08X).", out->nso_filename, out->nso_header.text_segment_header.file_offset, out->nso_header.text_file_size, \ - out->nso_header.text_segment_header.size); + LOGFILE("Invalid .text segment offset/size for NSO \"%s\"! (0x%08X, 0x%08X, 0x%08X).", out->nso_filename, out->nso_header.text_segment_info.file_offset, out->nso_header.text_file_size, \ + out->nso_header.text_segment_info.size); goto end; } - if (out->nso_header.rodata_segment_header.file_offset < sizeof(NsoHeader) || !out->nso_header.rodata_segment_header.size || \ - ((out->nso_header.flags & NsoFlags_RoCompress) && (!out->nso_header.rodata_file_size || out->nso_header.rodata_file_size > out->nso_header.rodata_segment_header.size)) || \ - (!(out->nso_header.flags & NsoFlags_RoCompress) && out->nso_header.rodata_file_size != out->nso_header.rodata_segment_header.size) || \ - (out->nso_header.rodata_segment_header.file_offset + out->nso_header.rodata_file_size) > pfs_entry->size) + if (out->nso_header.rodata_segment_info.file_offset < sizeof(NsoHeader) || !out->nso_header.rodata_segment_info.size || \ + ((out->nso_header.flags & NsoFlags_RoCompress) && (!out->nso_header.rodata_file_size || out->nso_header.rodata_file_size > out->nso_header.rodata_segment_info.size)) || \ + (!(out->nso_header.flags & NsoFlags_RoCompress) && out->nso_header.rodata_file_size != out->nso_header.rodata_segment_info.size) || \ + (out->nso_header.rodata_segment_info.file_offset + out->nso_header.rodata_file_size) > pfs_entry->size) { - LOGFILE("Invalid .rodata segment offset/size for NSO \"%s\"! (0x%08X, 0x%08X, 0x%08X).", out->nso_filename, out->nso_header.rodata_segment_header.file_offset, out->nso_header.rodata_file_size, \ - out->nso_header.rodata_segment_header.size); + LOGFILE("Invalid .rodata segment offset/size for NSO \"%s\"! (0x%08X, 0x%08X, 0x%08X).", out->nso_filename, out->nso_header.rodata_segment_info.file_offset, out->nso_header.rodata_file_size, \ + out->nso_header.rodata_segment_info.size); goto end; } - if (out->nso_header.data_segment_header.file_offset < sizeof(NsoHeader) || !out->nso_header.data_segment_header.size || \ - ((out->nso_header.flags & NsoFlags_DataCompress) && (!out->nso_header.data_file_size || out->nso_header.data_file_size > out->nso_header.data_segment_header.size)) || \ - (!(out->nso_header.flags & NsoFlags_DataCompress) && out->nso_header.data_file_size != out->nso_header.data_segment_header.size) || \ - (out->nso_header.data_segment_header.file_offset + out->nso_header.data_file_size) > pfs_entry->size) + if (out->nso_header.data_segment_info.file_offset < sizeof(NsoHeader) || !out->nso_header.data_segment_info.size || \ + ((out->nso_header.flags & NsoFlags_DataCompress) && (!out->nso_header.data_file_size || out->nso_header.data_file_size > out->nso_header.data_segment_info.size)) || \ + (!(out->nso_header.flags & NsoFlags_DataCompress) && out->nso_header.data_file_size != out->nso_header.data_segment_info.size) || \ + (out->nso_header.data_segment_info.file_offset + out->nso_header.data_file_size) > pfs_entry->size) { - LOGFILE("Invalid .data segment offset/size for NSO \"%s\"! (0x%08X, 0x%08X, 0x%08X).", out->nso_filename, out->nso_header.data_segment_header.file_offset, out->nso_header.data_file_size, \ - out->nso_header.data_segment_header.size); + LOGFILE("Invalid .data segment offset/size for NSO \"%s\"! (0x%08X, 0x%08X, 0x%08X).", out->nso_filename, out->nso_header.data_segment_info.file_offset, out->nso_header.data_file_size, \ + out->nso_header.data_segment_info.size); goto end; } @@ -107,19 +107,19 @@ bool nsoInitializeContext(NsoContext *out, PartitionFileSystemContext *pfs_ctx, LOGFILE("Invalid module name offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.module_name_offset, out->nso_header.module_name_size); } - if (out->nso_header.api_info_section_header.size && (out->nso_header.api_info_section_header.offset + out->nso_header.api_info_section_header.size) > out->nso_header.rodata_segment_header.size) + if (out->nso_header.api_info_section_info.size && (out->nso_header.api_info_section_info.offset + out->nso_header.api_info_section_info.size) > out->nso_header.rodata_segment_info.size) { - LOGFILE("Invalid .api_info section offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.api_info_section_header.offset, out->nso_header.api_info_section_header.size); + LOGFILE("Invalid .api_info section offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.api_info_section_info.offset, out->nso_header.api_info_section_info.size); } - if (!out->nso_header.dynstr_section_header.size || (out->nso_header.dynstr_section_header.offset + out->nso_header.dynstr_section_header.size) > out->nso_header.rodata_segment_header.size) + if (!out->nso_header.dynstr_section_info.size || (out->nso_header.dynstr_section_info.offset + out->nso_header.dynstr_section_info.size) > out->nso_header.rodata_segment_info.size) { - LOGFILE("Invalid .dynstr section offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.dynstr_section_header.offset, out->nso_header.dynstr_section_header.size); + LOGFILE("Invalid .dynstr section offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.dynstr_section_info.offset, out->nso_header.dynstr_section_info.size); } - if (!out->nso_header.dynsym_section_header.size || (out->nso_header.dynsym_section_header.offset + out->nso_header.dynsym_section_header.size) > out->nso_header.rodata_segment_header.size) + if (!out->nso_header.dynsym_section_info.size || (out->nso_header.dynsym_section_info.offset + out->nso_header.dynsym_section_info.size) > out->nso_header.rodata_segment_info.size) { - LOGFILE("Invalid .dynsym section offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.dynsym_section_header.offset, out->nso_header.dynsym_section_header.size); + LOGFILE("Invalid .dynsym section offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.dynsym_section_info.offset, out->nso_header.dynsym_section_info.size); } /* Get module name. */ @@ -132,16 +132,16 @@ bool nsoInitializeContext(NsoContext *out, PartitionFileSystemContext *pfs_ctx, if (!nsoGetModuleInfoName(out, rodata_buf)) goto end; /* Get .api_info section data. */ - if (!nsoGetSectionFromRodataSegment(out, rodata_buf, (u8**)&(out->rodata_api_info_section), out->nso_header.api_info_section_header.offset, out->nso_header.api_info_section_header.size)) goto end; - out->rodata_api_info_section_size = out->nso_header.api_info_section_header.size; + if (!nsoGetSectionFromRodataSegment(out, rodata_buf, (u8**)&(out->rodata_api_info_section), out->nso_header.api_info_section_info.offset, out->nso_header.api_info_section_info.size)) goto end; + out->rodata_api_info_section_size = out->nso_header.api_info_section_info.size; /* Get .dynstr section data. */ - if (!nsoGetSectionFromRodataSegment(out, rodata_buf, (u8**)&(out->rodata_dynstr_section), out->nso_header.dynstr_section_header.offset, out->nso_header.dynstr_section_header.size)) goto end; - out->rodata_dynstr_section_size = out->nso_header.dynstr_section_header.size; + if (!nsoGetSectionFromRodataSegment(out, rodata_buf, (u8**)&(out->rodata_dynstr_section), out->nso_header.dynstr_section_info.offset, out->nso_header.dynstr_section_info.size)) goto end; + out->rodata_dynstr_section_size = out->nso_header.dynstr_section_info.size; /* Get .dynsym section data. */ - if (!nsoGetSectionFromRodataSegment(out, rodata_buf, &(out->rodata_dynsym_section), out->nso_header.dynsym_section_header.offset, out->nso_header.dynsym_section_header.size)) goto end; - out->rodata_dynsym_section_size = out->nso_header.dynsym_section_header.size; + if (!nsoGetSectionFromRodataSegment(out, rodata_buf, &(out->rodata_dynsym_section), out->nso_header.dynsym_section_info.offset, out->nso_header.dynsym_section_info.size)) goto end; + out->rodata_dynsym_section_size = out->nso_header.dynsym_section_info.size; success = true; @@ -197,10 +197,10 @@ static u8 *nsoGetRodataSegment(NsoContext *nso_ctx) bool compressed = (nso_ctx->nso_header.flags & NsoFlags_RoCompress), verify = (nso_ctx->nso_header.flags & NsoFlags_RoHash); u8 *rodata_buf = NULL; - u64 rodata_buf_size = (compressed ? LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(nso_ctx->nso_header.rodata_segment_header.size) : nso_ctx->nso_header.rodata_segment_header.size); + u64 rodata_buf_size = (compressed ? LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(nso_ctx->nso_header.rodata_segment_info.size) : nso_ctx->nso_header.rodata_segment_info.size); u8 *rodata_read_ptr = NULL; - u64 rodata_read_size = (compressed ? nso_ctx->nso_header.rodata_file_size : nso_ctx->nso_header.rodata_segment_header.size); + u64 rodata_read_size = (compressed ? nso_ctx->nso_header.rodata_file_size : nso_ctx->nso_header.rodata_segment_info.size); u8 rodata_hash[SHA256_HASH_SIZE] = {0}; @@ -216,7 +216,7 @@ static u8 *nsoGetRodataSegment(NsoContext *nso_ctx) rodata_read_ptr = (compressed ? (rodata_buf + (rodata_buf_size - nso_ctx->nso_header.rodata_file_size)) : rodata_buf); /* Read .rodata segment data. */ - if (!pfsReadEntryData(nso_ctx->pfs_ctx, nso_ctx->pfs_entry, rodata_read_ptr, rodata_read_size, nso_ctx->nso_header.rodata_segment_header.file_offset)) + if (!pfsReadEntryData(nso_ctx->pfs_ctx, nso_ctx->pfs_entry, rodata_read_ptr, rodata_read_size, nso_ctx->nso_header.rodata_segment_info.file_offset)) { LOGFILE("Failed to read %s .rodata segment in NRO \"%s\"!", nso_ctx->nso_filename); goto end; @@ -226,7 +226,7 @@ static u8 *nsoGetRodataSegment(NsoContext *nso_ctx) { /* Decompress .rodata segment in-place. */ if ((lz4_res = LZ4_decompress_safe((char*)rodata_read_ptr, (char*)rodata_buf, (int)nso_ctx->nso_header.rodata_file_size, (int)rodata_buf_size)) != \ - (int)nso_ctx->nso_header.rodata_segment_header.size) + (int)nso_ctx->nso_header.rodata_segment_info.size) { LOGFILE("LZ4 decompression failed for NRO \"%s\"! (0x%08X).", nso_ctx->nso_filename, (u32)lz4_res); goto end; @@ -236,7 +236,7 @@ static u8 *nsoGetRodataSegment(NsoContext *nso_ctx) if (verify) { /* Verify .rodata segment hash. */ - sha256CalculateHash(rodata_hash, rodata_buf, nso_ctx->nso_header.rodata_segment_header.size); + sha256CalculateHash(rodata_hash, rodata_buf, nso_ctx->nso_header.rodata_segment_info.size); if (memcmp(rodata_hash, nso_ctx->nso_header.rodata_segment_hash, SHA256_HASH_SIZE) != 0) { LOGFILE(".rodata segment checksum mismatch for NRO \"%s\"!", nso_ctx->nso_filename); @@ -277,7 +277,7 @@ static bool nsoGetModuleInfoName(NsoContext *nso_ctx, u8 *rodata_buf) static bool nsoGetSectionFromRodataSegment(NsoContext *nso_ctx, u8 *rodata_buf, u8 **section_ptr, u64 section_offset, u64 section_size) { - if (!section_size || (section_offset + section_size) > nso_ctx->nso_header.rodata_segment_header.size) return true; + if (!section_size || (section_offset + section_size) > nso_ctx->nso_header.rodata_segment_info.size) return true; /* Allocate memory for the desired .rodata section. */ if (!(*section_ptr = malloc(section_size))) diff --git a/source/nso.h b/source/nso.h index 8220926..f2b92a9 100644 --- a/source/nso.h +++ b/source/nso.h @@ -41,12 +41,12 @@ typedef struct { u32 file_offset; ///< NSO segment offset. u32 memory_offset; ///< Memory segment offset. u32 size; ///< Decompressed segment size. -} NsoSegmentHeader; +} NsoSegmentInfo; typedef struct { u32 offset; ///< Relative to the .rodata segment start. u32 size; -} NsoSectionHeader; +} NsoSectionInfo; /// This is the start of every NSO. /// This is always followed by a NsoModuleName block. @@ -55,20 +55,20 @@ typedef struct { u32 version; ///< Always set to 0. u8 reserved_1[0x4]; u32 flags; ///< NsoFlags. - NsoSegmentHeader text_segment_header; + NsoSegmentInfo text_segment_info; u32 module_name_offset; ///< NsoModuleName block offset. - NsoSegmentHeader rodata_segment_header; + NsoSegmentInfo rodata_segment_info; u32 module_name_size; ///< NsoModuleName block size. - NsoSegmentHeader data_segment_header; + NsoSegmentInfo data_segment_info; u32 bss_size; u8 module_id[0x20]; ///< Also known as build ID. u32 text_file_size; ///< .text segment compressed size (if NsoFlags_TextCompress is enabled). u32 rodata_file_size; ///< .rodata segment compressed size (if NsoFlags_RoCompress is enabled). u32 data_file_size; ///< .data segment compressed size (if NsoFlags_DataCompress is enabled). u8 reserved_2[0x1C]; - NsoSectionHeader api_info_section_header; - NsoSectionHeader dynstr_section_header; - NsoSectionHeader dynsym_section_header; + NsoSectionInfo api_info_section_info; + NsoSectionInfo dynstr_section_info; + NsoSectionInfo dynsym_section_info; u8 text_segment_hash[0x20]; ///< Decompressed .text segment SHA-256 checksum. u8 rodata_segment_hash[0x20]; ///< Decompressed .rodata segment SHA-256 checksum. u8 data_segment_hash[0x20]; ///< Decompressed .data segment SHA-256 checksum. diff --git a/source/program_info.c b/source/program_info.c index 5e632a8..7e2613e 100644 --- a/source/program_info.c +++ b/source/program_info.c @@ -56,7 +56,7 @@ bool programInfoInitializeContext(ProgramInfoContext *out, NcaContext *nca_ctx) { if (!out || !nca_ctx || !*(nca_ctx->content_id_str) || nca_ctx->content_type != NcmContentType_Program || nca_ctx->content_size < NCA_FULL_HEADER_LENGTH || \ (nca_ctx->storage_id != NcmStorageId_GameCard && !nca_ctx->ncm_storage) || (nca_ctx->storage_id == NcmStorageId_GameCard && !nca_ctx->gamecard_offset) || \ - nca_ctx->header.content_type != NcaContentType_Program || !out) + nca_ctx->header.content_type != NcaContentType_Program || nca_ctx->content_type_ctx || !out) { LOGFILE("Invalid parameters!"); return false; diff --git a/source/services.c b/source/services.c index d59cdc5..91f21f5 100644 --- a/source/services.c +++ b/source/services.c @@ -21,7 +21,6 @@ #include "utils.h" #include "services.h" #include "es.h" -#include "fspusb.h" /* Type definitions. */ @@ -44,7 +43,6 @@ static Result smHasService(bool *out_has_service, SmServiceName name); static Result servicesNifmUserInitialize(void); static bool servicesClkGetServiceType(void *arg); static bool servicesSplCryptoCheckAvailability(void *arg); -static bool servicesFspUsbCheckAvailability(void *arg); /* Global variables. */ @@ -58,7 +56,6 @@ static ServiceInfo g_serviceInfo[] = { { false, "psm", NULL, &psmInitialize, &psmExit }, { false, "nifm:u", NULL, &servicesNifmUserInitialize, &nifmExit }, { false, "clk", &servicesClkGetServiceType, NULL, NULL }, /* Placeholder for pcv / clkrst. */ - { false, "fsp-usb", &servicesFspUsbCheckAvailability, &fspusbInitialize, &fspusbExit }, /* Checks if fsp-usb really is available. */ { false, "es", NULL, &esInitialize, &esExit }, { false, "set:cal", NULL, &setcalInitialize, &setcalExit } }; @@ -290,16 +287,3 @@ static bool servicesSplCryptoCheckAvailability(void *arg) /* Check if spl:mig is available (sysver equal to or greater than 4.0.0). */ return !hosversionBefore(4, 0, 0); } - -static bool servicesFspUsbCheckAvailability(void *arg) -{ - if (!arg) return false; - - ServiceInfo *info = (ServiceInfo*)arg; - if (strlen(info->name) != 7 || strcmp(info->name, "fsp-usb") != 0 || info->init_func == NULL || info->close_func == NULL) return false; - - /* Check if fsp-usb is actually running in the background. */ - bool has_service = false; - return (utilsGetCustomFirmwareType() == UtilsCustomFirmwareType_Atmosphere ? (R_SUCCEEDED(servicesAtmosphereHasService(&has_service, info->name)) && has_service) : \ - servicesCheckRunningServiceByName(info->name)); -} diff --git a/source/utils.c b/source/utils.c index 965e92d..c56d261 100644 --- a/source/utils.c +++ b/source/utils.c @@ -19,6 +19,8 @@ * along with this program. If not, see . */ +#include + #include "utils.h" //#include "freetype_helper.h" //#include "lvgl_helper.h" @@ -75,6 +77,7 @@ bool utilsInitializeResources(void) { mutexLock(&g_resourcesMutex); + Result rc = 0; bool ret = g_resourcesInitialized; if (ret) goto end; @@ -107,6 +110,14 @@ bool utilsInitializeResources(void) goto end; } + /* Initialize USB host FS interface. */ + rc = usbHsFsInitialize(); + if (R_FAILED(rc)) + { + LOGFILE("Failed to initialize USB host FS interface! (0x%08X).", rc); + goto end; + } + /* Load NCA keyset. */ if (!keysLoadNcaKeyset()) { @@ -216,6 +227,9 @@ void utilsCloseResources(void) /* Free NCA crypto buffer. */ ncaFreeCryptoBuffer(); + /* Close USB host FS interface. */ + usbHsFsExit(); + /* Close USB interface. */ usbExit();