1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-11-22 18:26:39 +00:00

poc: add NCA FS section submenu.

Other changes include:

* nca: add section_size_str field to NcaFsSectionContext struct.
* config: add support for "nca_fs/write_section_image" flag.
This commit is contained in:
Pablo Curiel 2023-05-26 20:23:23 +02:00
parent 8e2b0a74b8
commit c6a84f68de
5 changed files with 152 additions and 43 deletions

View file

@ -75,10 +75,11 @@ typedef enum {
MenuId_NSP = 7, MenuId_NSP = 7,
MenuId_TicketTitleTypes = 8, MenuId_TicketTitleTypes = 8,
MenuId_Ticket = 9, MenuId_Ticket = 9,
MenuId_NCATitleTypes = 10, MenuId_NcaTitleTypes = 10,
MenuId_NCA = 11, MenuId_Nca = 11,
MenuId_NCAFsSections = 12, MenuId_NcaFsSections = 12,
MenuId_Count = 13 MenuId_NcaFsSectionsSubMenu = 13,
MenuId_Count = 14
} MenuId; } MenuId;
typedef struct typedef struct
@ -233,6 +234,12 @@ static void setNspAppendAuthoringToolDataOption(u32 idx);
static u32 getTicketRemoveConsoleDataOption(void); static u32 getTicketRemoveConsoleDataOption(void);
static void setTicketRemoveConsoleDataOption(u32 idx); static void setTicketRemoveConsoleDataOption(u32 idx);
static u32 getNcaFsWriteSectionImageOption(void);
static void setNcaFsWriteSectionImageOption(u32 idx);
static u32 getNcaFsUseLayeredFsDirOption(void);
static void setNcaFsUseLayeredFsDirOption(u32 idx);
/* Global variables. */ /* Global variables. */
bool g_borealisInitialized = false; bool g_borealisInitialized = false;
@ -611,11 +618,56 @@ static Menu g_ticketMenu = {
static bool g_ncaMenuRawMode = false; static bool g_ncaMenuRawMode = false;
static NcaContext *g_ncaFsSectionsMenuCtx = NULL; static NcaContext *g_ncaFsSectionsMenuCtx = NULL;
static MenuElement *g_ncaFsSectionsSubMenuElements[] = {
&(MenuElement){
.str = "start nca fs dump",
.child_menu = NULL,
.task_func = NULL,
.element_options = NULL,
.userdata = NULL // Dynamically set
},
// TODO: place base/patch selector here? display selector at runtime?
&(MenuElement){
.str = "write section image",
.child_menu = NULL,
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 0,
.getter_func = &getNcaFsWriteSectionImageOption,
.setter_func = &setNcaFsWriteSectionImageOption,
.options = g_noYesStrings
},
.userdata = NULL
},
&(MenuElement){
.str = "use layeredfs dir",
.child_menu = NULL,
.task_func = NULL,
.element_options = &(MenuElementOption){
.selected = 0,
.getter_func = &getNcaFsUseLayeredFsDirOption,
.setter_func = &setNcaFsUseLayeredFsDirOption,
.options = g_noYesStrings
},
.userdata = NULL
},
&g_storageMenuElement,
NULL
};
static Menu g_ncaFsSectionsSubMenu = {
.id = MenuId_NcaFsSectionsSubMenu,
.parent = NULL,
.selected = 0,
.scroll = 0,
.elements = g_ncaFsSectionsSubMenuElements
};
static MenuElement **g_ncaFsSectionsMenuElements = NULL; static MenuElement **g_ncaFsSectionsMenuElements = NULL;
// Dynamically populated using g_ncaFsSectionsMenuElements. // Dynamically populated using g_ncaFsSectionsMenuElements.
static Menu g_ncaFsSectionsMenu = { static Menu g_ncaFsSectionsMenu = {
.id = MenuId_NCAFsSections, .id = MenuId_NcaFsSections,
.parent = NULL, .parent = NULL,
.selected = 0, .selected = 0,
.scroll = 0, .scroll = 0,
@ -626,7 +678,7 @@ static MenuElement **g_ncaMenuElements = NULL;
// Dynamically populated using g_ncaMenuElements. // Dynamically populated using g_ncaMenuElements.
static Menu g_ncaMenu = { static Menu g_ncaMenu = {
.id = MenuId_NCA, .id = MenuId_Nca,
.parent = NULL, .parent = NULL,
.selected = 0, .selected = 0,
.scroll = 0, .scroll = 0,
@ -700,7 +752,7 @@ static MenuElement *g_userTitlesSubMenuElements[] = {
&(MenuElement){ &(MenuElement){
.str = "nca / nca fs dump options", .str = "nca / nca fs dump options",
.child_menu = &(Menu){ .child_menu = &(Menu){
.id = MenuId_NCATitleTypes, .id = MenuId_NcaTitleTypes,
.parent = NULL, .parent = NULL,
.selected = 0, .selected = 0,
.scroll = 0, .scroll = 0,
@ -822,7 +874,7 @@ int main(int argc, char *argv[])
g_titleTypesMenuElements[0]->child_menu = g_titleTypesMenuElements[1]->child_menu = \ g_titleTypesMenuElements[0]->child_menu = g_titleTypesMenuElements[1]->child_menu = \
g_titleTypesMenuElements[2]->child_menu = g_titleTypesMenuElements[3]->child_menu = (child_id == MenuId_NSPTitleTypes ? &g_nspMenu : \ g_titleTypesMenuElements[2]->child_menu = g_titleTypesMenuElements[3]->child_menu = (child_id == MenuId_NSPTitleTypes ? &g_nspMenu : \
(child_id == MenuId_TicketTitleTypes ? &g_ticketMenu : \ (child_id == MenuId_TicketTitleTypes ? &g_ticketMenu : \
(child_id == MenuId_NCATitleTypes ? &g_ncaMenu : NULL))); (child_id == MenuId_NcaTitleTypes ? &g_ncaMenu : NULL)));
} }
consoleClear(); consoleClear();
@ -845,12 +897,14 @@ int main(int argc, char *argv[])
consolePrint("title info:\n\n"); consolePrint("title info:\n\n");
consolePrint("name: %s\n", app_metadata->lang_entry.name); consolePrint("name: %s\n", app_metadata->lang_entry.name);
consolePrint("publisher: %s\n", app_metadata->lang_entry.author); consolePrint("publisher: %s\n", app_metadata->lang_entry.author);
if (cur_menu->id == MenuId_UserTitlesSubMenu) consolePrint("title id: %016lX\n", app_metadata->title_id); if (cur_menu->id == MenuId_UserTitlesSubMenu || cur_menu->id == MenuId_NSPTitleTypes || cur_menu->id == MenuId_TicketTitleTypes || \
cur_menu->id == MenuId_NcaTitleTypes) consolePrint("title id: %016lX\n", app_metadata->title_id);
consolePrint("______________________________\n\n"); consolePrint("______________________________\n\n");
if (cur_menu->id == MenuId_NSP || cur_menu->id == MenuId_Ticket || cur_menu->id == MenuId_NCA || cur_menu->id == MenuId_NCAFsSections) if (cur_menu->id == MenuId_NSP || cur_menu->id == MenuId_Ticket || cur_menu->id == MenuId_Nca || \
cur_menu->id == MenuId_NcaFsSections || cur_menu->id == MenuId_NcaFsSectionsSubMenu)
{ {
if (cur_menu->id != MenuId_NCAFsSections && (title_info->previous || title_info->next)) if (cur_menu->id != MenuId_NcaFsSections && cur_menu->id != MenuId_NcaFsSectionsSubMenu && (title_info->previous || title_info->next))
{ {
consolePrint("press l/zl and/or r/zr to change the selected title\n"); consolePrint("press l/zl and/or r/zr to change the selected title\n");
consolePrint("title: %u / %u\n", title_info_idx, title_info_count); consolePrint("title: %u / %u\n", title_info_idx, title_info_count);
@ -871,13 +925,13 @@ int main(int argc, char *argv[])
if (cur_menu->id == MenuId_Ticket) g_ticketMenuElements[0]->userdata = title_info; if (cur_menu->id == MenuId_Ticket) g_ticketMenuElements[0]->userdata = title_info;
if (cur_menu->id == MenuId_NCA) if (cur_menu->id == MenuId_Nca)
{ {
consolePrint("press y to switch to %s mode\n", g_ncaMenuRawMode ? "nca fs section" : "raw nca"); consolePrint("press y to switch to %s mode\n", g_ncaMenuRawMode ? "nca fs section" : "raw nca");
consolePrint("______________________________\n\n"); consolePrint("______________________________\n\n");
} }
if (cur_menu->id == MenuId_NCAFsSections) if (cur_menu->id == MenuId_NcaFsSections || cur_menu->id == MenuId_NcaFsSectionsSubMenu)
{ {
consolePrint("selected nca info:\n\n"); consolePrint("selected nca info:\n\n");
consolePrint("content id: %s\n", g_ncaFsSectionsMenuCtx->content_id_str); consolePrint("content id: %s\n", g_ncaFsSectionsMenuCtx->content_id_str);
@ -886,6 +940,16 @@ int main(int argc, char *argv[])
consolePrint("size: %s\n", g_ncaFsSectionsMenuCtx->content_size_str); consolePrint("size: %s\n", g_ncaFsSectionsMenuCtx->content_size_str);
consolePrint("______________________________\n\n"); consolePrint("______________________________\n\n");
} }
if (cur_menu->id == MenuId_NcaFsSectionsSubMenu)
{
NcaFsSectionContext *nca_fs_ctx = (NcaFsSectionContext*)g_ncaFsSectionsSubMenuElements[0]->userdata;
consolePrint("selected nca fs section info:\n");
consolePrint("section index: %u\n", nca_fs_ctx->section_idx);
consolePrint("section type: %s\n", ncaGetFsSectionTypeName(nca_fs_ctx));
consolePrint("section size: %s\n", nca_fs_ctx->section_size_str);
consolePrint("______________________________\n\n");
}
} }
} }
@ -972,7 +1036,7 @@ int main(int argc, char *argv[])
error = !titleGetUserApplicationData(app_metadata->title_id, &user_app_data); error = !titleGetUserApplicationData(app_metadata->title_id, &user_app_data);
if (error) consolePrint("\nfailed to get user application data for %016lX!\n", app_metadata->title_id); if (error) consolePrint("\nfailed to get user application data for %016lX!\n", app_metadata->title_id);
} else } else
if (child_menu->id == MenuId_NSP || child_menu->id == MenuId_Ticket || child_menu->id == MenuId_NCA) if (child_menu->id == MenuId_NSP || child_menu->id == MenuId_Ticket || child_menu->id == MenuId_Nca)
{ {
u32 title_type = *((u32*)selected_element->userdata); u32 title_type = *((u32*)selected_element->userdata);
@ -997,7 +1061,7 @@ int main(int argc, char *argv[])
if (title_info) if (title_info)
{ {
if (child_menu->id == MenuId_NCA) if (child_menu->id == MenuId_Nca)
{ {
updateNcaList(title_info); updateNcaList(title_info);
@ -1021,7 +1085,7 @@ int main(int argc, char *argv[])
error = true; error = true;
} }
} else } else
if (child_menu->id == MenuId_NCAFsSections) if (child_menu->id == MenuId_NcaFsSections)
{ {
updateNcaFsSectionsList((NcaUserData*)selected_element->userdata); updateNcaFsSectionsList((NcaUserData*)selected_element->userdata);
@ -1030,6 +1094,18 @@ int main(int argc, char *argv[])
consolePrint("failed to generate nca fs sections list\n"); consolePrint("failed to generate nca fs sections list\n");
error = true; error = true;
} }
} else
if (child_menu->id == MenuId_NcaFsSectionsSubMenu)
{
NcaFsSectionContext *nca_fs_ctx = selected_element->userdata;
if (nca_fs_ctx->enabled)
{
// TODO: add sparse / patch checks here
g_ncaFsSectionsSubMenuElements[0]->userdata = nca_fs_ctx;
} else {
consolePrint("can't dump an invalid nca fs section!\n");
error = true;
}
} }
if (!error) if (!error)
@ -1142,7 +1218,7 @@ int main(int argc, char *argv[])
g_titleTypesMenuElements[0]->child_menu = g_titleTypesMenuElements[1]->child_menu = \ g_titleTypesMenuElements[0]->child_menu = g_titleTypesMenuElements[1]->child_menu = \
g_titleTypesMenuElements[2]->child_menu = g_titleTypesMenuElements[3]->child_menu = NULL; g_titleTypesMenuElements[2]->child_menu = g_titleTypesMenuElements[3]->child_menu = NULL;
} else } else
if (cur_menu->id == MenuId_NSPTitleTypes || cur_menu->id == MenuId_TicketTitleTypes || cur_menu->id == MenuId_NCATitleTypes) if (cur_menu->id == MenuId_NSPTitleTypes || cur_menu->id == MenuId_TicketTitleTypes || cur_menu->id == MenuId_NcaTitleTypes)
{ {
title_info = NULL; title_info = NULL;
title_info_idx = title_info_count = 0; title_info_idx = title_info_count = 0;
@ -1155,13 +1231,17 @@ int main(int argc, char *argv[])
{ {
g_ticketMenuElements[0]->userdata = NULL; g_ticketMenuElements[0]->userdata = NULL;
} else } else
if (cur_menu->id == MenuId_NCA) if (cur_menu->id == MenuId_Nca)
{ {
freeNcaList(); freeNcaList();
} else } else
if (cur_menu->id == MenuId_NCAFsSections) if (cur_menu->id == MenuId_NcaFsSections)
{ {
freeNcaFsSectionsList(); freeNcaFsSectionsList();
} else
if (cur_menu->id == MenuId_NcaFsSectionsSubMenu)
{
g_ncaFsSectionsSubMenuElements[0]->userdata = NULL;
} }
cur_menu->selected = 0; cur_menu->selected = 0;
@ -1175,19 +1255,19 @@ int main(int argc, char *argv[])
for(u32 i = 0; i < g_umsDeviceCount; i++) usbHsFsUnmountDevice(&(g_umsDevices[i]), false); for(u32 i = 0; i < g_umsDeviceCount; i++) usbHsFsUnmountDevice(&(g_umsDevices[i]), false);
updateStorageList(); updateStorageList();
} else } else
if (((btn_down & (HidNpadButton_L)) || (btn_held & HidNpadButton_ZL)) && (cur_menu->id == MenuId_NSP || cur_menu->id == MenuId_Ticket || cur_menu->id == MenuId_NCA) && title_info->previous) if (((btn_down & (HidNpadButton_L)) || (btn_held & HidNpadButton_ZL)) && (cur_menu->id == MenuId_NSP || cur_menu->id == MenuId_Ticket || cur_menu->id == MenuId_Nca) && title_info->previous)
{ {
title_info = title_info->previous; title_info = title_info->previous;
title_info_idx--; title_info_idx--;
switchNcaListTitle(cur_menu, &element_count, title_info); switchNcaListTitle(cur_menu, &element_count, title_info);
} else } else
if (((btn_down & (HidNpadButton_R)) || (btn_held & HidNpadButton_ZR)) && (cur_menu->id == MenuId_NSP || cur_menu->id == MenuId_Ticket || cur_menu->id == MenuId_NCA) && title_info->next) if (((btn_down & (HidNpadButton_R)) || (btn_held & HidNpadButton_ZR)) && (cur_menu->id == MenuId_NSP || cur_menu->id == MenuId_Ticket || cur_menu->id == MenuId_Nca) && title_info->next)
{ {
title_info = title_info->next; title_info = title_info->next;
title_info_idx++; title_info_idx++;
switchNcaListTitle(cur_menu, &element_count, title_info); switchNcaListTitle(cur_menu, &element_count, title_info);
} else } else
if ((btn_down & HidNpadButton_Y) && cur_menu->id == MenuId_NCA) if ((btn_down & HidNpadButton_Y) && cur_menu->id == MenuId_Nca)
{ {
/* Change NCA menu element properties. */ /* Change NCA menu element properties. */
g_ncaMenuRawMode ^= 1; g_ncaMenuRawMode ^= 1;
@ -1523,7 +1603,7 @@ void updateNcaList(TitleInfo *title_info)
static void switchNcaListTitle(Menu *cur_menu, u32 *element_count, TitleInfo *title_info) static void switchNcaListTitle(Menu *cur_menu, u32 *element_count, TitleInfo *title_info)
{ {
if (!cur_menu || cur_menu->id != MenuId_NCA || !element_count) return; if (!cur_menu || cur_menu->id != MenuId_Nca || !element_count) return;
updateNcaList(title_info); updateNcaList(title_info);
@ -1595,7 +1675,7 @@ void updateNcaFsSectionsList(NcaUserData *nca_user_data)
for(u32 i = 0; i < NCA_FS_HEADER_COUNT; i++) for(u32 i = 0; i < NCA_FS_HEADER_COUNT; i++)
{ {
NcaFsSectionContext *cur_nca_fs_ctx = &(g_ncaFsSectionsMenuCtx->fs_ctx[i]); NcaFsSectionContext *cur_nca_fs_ctx = &(g_ncaFsSectionsMenuCtx->fs_ctx[i]);
char *nca_fs_info_str = NULL, nca_fs_size_str[16] = {0}; char *nca_fs_info_str = NULL;
g_ncaFsSectionsMenuElements[idx] = calloc(1, sizeof(MenuElement)); g_ncaFsSectionsMenuElements[idx] = calloc(1, sizeof(MenuElement));
if (!g_ncaFsSectionsMenuElements[idx]) continue; if (!g_ncaFsSectionsMenuElements[idx]) continue;
@ -1603,11 +1683,15 @@ void updateNcaFsSectionsList(NcaUserData *nca_user_data)
nca_fs_info_str = calloc(128, sizeof(char)); nca_fs_info_str = calloc(128, sizeof(char));
if (!nca_fs_info_str) continue; if (!nca_fs_info_str) continue;
utilsGenerateFormattedSizeString((double)cur_nca_fs_ctx->section_size, nca_fs_size_str, sizeof(nca_fs_size_str)); if (cur_nca_fs_ctx->enabled)
sprintf(nca_fs_info_str, "FS section #%u: %s (%s)", i + 1, ncaGetFsSectionTypeName(cur_nca_fs_ctx), nca_fs_size_str); {
sprintf(nca_fs_info_str, "FS section #%u: %s (%s)", i + 1, ncaGetFsSectionTypeName(cur_nca_fs_ctx), cur_nca_fs_ctx->section_size_str);
} else {
sprintf(nca_fs_info_str, "FS section #%u: %s", i + 1, ncaGetFsSectionTypeName(cur_nca_fs_ctx));
}
g_ncaFsSectionsMenuElements[idx]->str = nca_fs_info_str; g_ncaFsSectionsMenuElements[idx]->str = nca_fs_info_str;
g_ncaFsSectionsMenuElements[idx]->child_menu = NULL; g_ncaFsSectionsMenuElements[idx]->child_menu = &g_ncaFsSectionsSubMenu;
g_ncaFsSectionsMenuElements[idx]->userdata = cur_nca_fs_ctx; g_ncaFsSectionsMenuElements[idx]->userdata = cur_nca_fs_ctx;
idx++; idx++;
@ -3473,11 +3557,11 @@ static void nspThreadFunc(void *arg)
if (!ncaInitializeContext(meta_nca_ctx, title_info->storage_id, (title_info->storage_id == NcmStorageId_GameCard ? HashFileSystemPartitionType_Secure : 0), \ if (!ncaInitializeContext(meta_nca_ctx, title_info->storage_id, (title_info->storage_id == NcmStorageId_GameCard ? HashFileSystemPartitionType_Secure : 0), \
titleGetContentInfoByTypeAndIdOffset(title_info, NcmContentType_Meta, 0), title_info->version.value, &tik)) titleGetContentInfoByTypeAndIdOffset(title_info, NcmContentType_Meta, 0), title_info->version.value, &tik))
{ {
consolePrint("Meta nca initialize ctx failed\n"); consolePrint("meta nca initialize ctx failed\n");
goto end; goto end;
} }
consolePrint("Meta nca initialize ctx succeeded\n"); consolePrint("meta nca initialize ctx succeeded\n");
if (!cnmtInitializeContext(&cnmt_ctx, meta_nca_ctx)) if (!cnmtInitializeContext(&cnmt_ctx, meta_nca_ctx))
{ {
@ -4313,3 +4397,23 @@ static void setTicketRemoveConsoleDataOption(u32 idx)
{ {
configSetBoolean("ticket/remove_console_data", (bool)idx); configSetBoolean("ticket/remove_console_data", (bool)idx);
} }
static u32 getNcaFsWriteSectionImageOption(void)
{
return (u32)configGetBoolean("nca_fs/write_section_image");
}
static void setNcaFsWriteSectionImageOption(u32 idx)
{
configSetBoolean("nca_fs/write_section_image", (bool)idx);
}
static u32 getNcaFsUseLayeredFsDirOption(void)
{
return (u32)configGetBoolean("nca_fs/use_layeredfs_dir");
}
static void setNcaFsUseLayeredFsDirOption(u32 idx)
{
configSetBoolean("nca_fs/use_layeredfs_dir", (bool)idx);
}

View file

@ -376,6 +376,7 @@ typedef struct {
u8 section_idx; ///< Index within [0 - 3]. u8 section_idx; ///< Index within [0 - 3].
u64 section_offset; ///< Relative to the start of the NCA content file. Placed here for convenience. u64 section_offset; ///< Relative to the start of the NCA content file. Placed here for convenience.
u64 section_size; ///< Placed here for convenience. u64 section_size; ///< Placed here for convenience.
char section_size_str[0x10]; ///< Placed here for convenience.
u8 hash_type; ///< NcaHashType. u8 hash_type; ///< NcaHashType.
u8 encryption_type; ///< NcaEncryptionType. u8 encryption_type; ///< NcaEncryptionType.
u8 section_type; ///< NcaFsSectionType. u8 section_type; ///< NcaFsSectionType.
@ -436,7 +437,7 @@ struct _NcaContext {
u8 format_version; ///< NcaVersion. u8 format_version; ///< NcaVersion.
u8 content_type; ///< NcmContentType. Retrieved from NcmContentInfo. u8 content_type; ///< NcmContentType. Retrieved from NcmContentInfo.
u64 content_size; ///< Retrieved from NcmContentInfo. u64 content_size; ///< Retrieved from NcmContentInfo.
char content_size_str[0x10]; char content_size_str[0x10]; ///< Placed here for convenience.
u8 key_generation; ///< NcaKeyGeneration. Retrieved from the decrypted header. u8 key_generation; ///< NcaKeyGeneration. Retrieved from the decrypted header.
u8 id_offset; ///< Retrieved from NcmContentInfo. u8 id_offset; ///< Retrieved from NcmContentInfo.
u32 title_version; u32 title_version;

View file

@ -25,6 +25,7 @@
"remove_console_data": true "remove_console_data": true
}, },
"nca_fs": { "nca_fs": {
"write_section_image": false,
"use_layeredfs_dir": false "use_layeredfs_dir": false
} }
} }

View file

@ -285,17 +285,18 @@ end:
static bool configValidateJsonNcaFsObject(const struct json_object *obj) static bool configValidateJsonNcaFsObject(const struct json_object *obj)
{ {
bool ret = false, use_layeredfs_dir_found = false; bool ret = false, write_section_image_found = false, use_layeredfs_dir_found = false;
if (!jsonValidateObject(obj)) goto end; if (!jsonValidateObject(obj)) goto end;
json_object_object_foreach(obj, key, val) json_object_object_foreach(obj, key, val)
{ {
CONFIG_VALIDATE_FIELD(Boolean, write_section_image);
CONFIG_VALIDATE_FIELD(Boolean, use_layeredfs_dir); CONFIG_VALIDATE_FIELD(Boolean, use_layeredfs_dir);
goto end; goto end;
} }
ret = use_layeredfs_dir_found; ret = (write_section_image_found && use_layeredfs_dir_found);
end: end:
return ret; return ret;

View file

@ -545,7 +545,7 @@ const char *ncaGetFsSectionTypeName(NcaFsSectionContext *ctx)
const char *str = "Invalid"; const char *str = "Invalid";
bool is_exefs = false; bool is_exefs = false;
if (!ctx || !ctx->nca_ctx) return str; if (!ctx || !ctx->enabled) return str;
is_exefs = (ctx->nca_ctx->content_type == NcmContentType_Program && ctx->section_idx == 0); is_exefs = (ctx->nca_ctx->content_type == NcmContentType_Program && ctx->section_idx == 0);
@ -825,6 +825,8 @@ static bool ncaInitializeFsSectionContext(NcaContext *nca_ctx, u32 section_idx)
fs_ctx->section_offset = NCA_FS_SECTOR_OFFSET(fs_info->start_sector); fs_ctx->section_offset = NCA_FS_SECTOR_OFFSET(fs_info->start_sector);
fs_ctx->section_size = (NCA_FS_SECTOR_OFFSET(fs_info->end_sector) - fs_ctx->section_offset); fs_ctx->section_size = (NCA_FS_SECTOR_OFFSET(fs_info->end_sector) - fs_ctx->section_offset);
utilsGenerateFormattedSizeString((double)fs_ctx->section_size, fs_ctx->section_size_str, sizeof(fs_ctx->section_size_str));
/* Check if we're dealing with an invalid start offset or an empty size. */ /* Check if we're dealing with an invalid start offset or an empty size. */
if (fs_ctx->section_offset < sizeof(NcaHeader) || !fs_ctx->section_size) if (fs_ctx->section_offset < sizeof(NcaHeader) || !fs_ctx->section_size)
{ {