mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-10-29 23:11:45 +00:00
bis_storage: add menu option.
Makes it possible to browse eMMC partitions and dump data from them. Since we're manually parsing FAT partitions, reading files protected by the FS sysmodule at runtime is possible.
This commit is contained in:
parent
596928a3c6
commit
4589614183
4 changed files with 138 additions and 50 deletions
|
@ -37,8 +37,8 @@ Currently planned changes for this branch include:
|
|||
* Control.nacp patching while dumping NSPs (lets you patch screenshot, video, user account and HDCP restrictions). :white_check_mark:
|
||||
* Partition FS / Hash FS / RomFS browser using custom devoptab wrappers. :white_check_mark:
|
||||
* Full system update dumps with checksum and signature verification. :white_check_mark:
|
||||
* `FsStorage` + `FatFs` based eMMC browser using a custom devoptab wrapper (allows copying files protected by the FS sysmodule at runtime). :white_check_mark:
|
||||
* Batch NSP dumps. :x:
|
||||
* `FsFileSystem` + `FatFs` based eMMC browser using a custom devoptab wrapper (allows copying files protected by the FS sysmodule at runtime). :x:
|
||||
* New UI using a [customized borealis fork](https://github.com/DarkMatterCore/borealis/tree/nxdumptool-legacy). :warning:
|
||||
|
||||
Legend:
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <core/usb.h>
|
||||
#include <core/devoptab/nxdt_devoptab.h>
|
||||
#include <core/system_update.h>
|
||||
#include <core/bis_storage.h>
|
||||
|
||||
#define BLOCK_SIZE USB_TRANSFER_BUFFER_SIZE
|
||||
#define WAIT_TIME_LIMIT 30
|
||||
|
@ -85,7 +86,8 @@ typedef enum {
|
|||
MenuId_NcaFsSectionsSubMenu = 14,
|
||||
MenuId_SystemTitles = 15,
|
||||
MenuId_SystemUpdate = 16,
|
||||
MenuId_Count = 17
|
||||
MenuId_BrowseEmmc = 17,
|
||||
MenuId_Count = 18
|
||||
} MenuId;
|
||||
|
||||
typedef struct
|
||||
|
@ -233,8 +235,11 @@ static bool browseNintendoContentArchiveFsSection(void *userdata);
|
|||
|
||||
static bool saveSystemUpdateDump(void *userdata);
|
||||
|
||||
static bool browseEmmcPartition(void *userdata);
|
||||
|
||||
static bool fsBrowser(const char *mount_name, const char *base_out_path);
|
||||
static bool fsBrowserGetDirEntries(const char *dir_path, FsBrowserEntry **out_entries, u32 *out_entry_count);
|
||||
static int fsBrowserDirEntrySortFunction(const void *a, const void *b);
|
||||
static bool fsBrowserDumpFile(const char *dir_path, const FsBrowserEntry *entry, const char *base_out_path);
|
||||
static bool fsBrowserDumpHighlightedEntries(const char *dir_path, const FsBrowserEntry *entries, u32 entries_count, const char *base_out_path);
|
||||
|
||||
|
@ -989,12 +994,42 @@ static MenuElement *g_dumpSystemUpdateMenuElements[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
static Menu g_dumpSystemUpdateMenu = {
|
||||
.id = MenuId_SystemUpdate,
|
||||
.parent = NULL,
|
||||
.selected = 0,
|
||||
.scroll = 0,
|
||||
.elements = g_dumpSystemUpdateMenuElements
|
||||
static u8 g_emmcProdinfofPartition = FsBisPartitionId_CalibrationFile;
|
||||
static u8 g_emmcSafePartition = FsBisPartitionId_SafeMode;
|
||||
static u8 g_emmcUserPartition = FsBisPartitionId_User;
|
||||
static u8 g_emmcSystemPartition = FsBisPartitionId_System;
|
||||
|
||||
static MenuElement *g_emmcBrowseMenuElements[] = {
|
||||
&(MenuElement){
|
||||
.str = "browse prodinfof emmc partition",
|
||||
.child_menu = NULL,
|
||||
.task_func = &browseEmmcPartition,
|
||||
.element_options = NULL,
|
||||
.userdata = &g_emmcProdinfofPartition
|
||||
},
|
||||
&(MenuElement){
|
||||
.str = "browse safe emmc partition",
|
||||
.child_menu = NULL,
|
||||
.task_func = &browseEmmcPartition,
|
||||
.element_options = NULL,
|
||||
.userdata = &g_emmcSafePartition
|
||||
},
|
||||
&(MenuElement){
|
||||
.str = "browse user emmc partition",
|
||||
.child_menu = NULL,
|
||||
.task_func = &browseEmmcPartition,
|
||||
.element_options = NULL,
|
||||
.userdata = &g_emmcUserPartition
|
||||
},
|
||||
&(MenuElement){
|
||||
.str = "browse system mmc partition",
|
||||
.child_menu = NULL,
|
||||
.task_func = &browseEmmcPartition,
|
||||
.element_options = NULL,
|
||||
.userdata = &g_emmcSystemPartition
|
||||
},
|
||||
&g_storageMenuElement,
|
||||
NULL
|
||||
};
|
||||
|
||||
static MenuElement *g_rootMenuElements[] = {
|
||||
|
@ -1027,7 +1062,26 @@ static MenuElement *g_rootMenuElements[] = {
|
|||
},
|
||||
&(MenuElement){
|
||||
.str = "dump system update",
|
||||
.child_menu = &g_dumpSystemUpdateMenu,
|
||||
.child_menu = &(Menu){
|
||||
.id = MenuId_SystemUpdate,
|
||||
.parent = NULL,
|
||||
.selected = 0,
|
||||
.scroll = 0,
|
||||
.elements = g_dumpSystemUpdateMenuElements
|
||||
},
|
||||
.task_func = NULL,
|
||||
.element_options = NULL,
|
||||
.userdata = NULL
|
||||
},
|
||||
&(MenuElement){
|
||||
.str = "browse emmc partitions",
|
||||
.child_menu = &(Menu){
|
||||
.id = MenuId_BrowseEmmc,
|
||||
.parent = NULL,
|
||||
.selected = 0,
|
||||
.scroll = 0,
|
||||
.elements = g_emmcBrowseMenuElements
|
||||
},
|
||||
.task_func = NULL,
|
||||
.element_options = NULL,
|
||||
.userdata = NULL
|
||||
|
@ -1382,7 +1436,7 @@ int main(int argc, char *argv[])
|
|||
break;
|
||||
}
|
||||
|
||||
if ((cur_menu->id == MenuId_NcaFsSectionsSubMenu && cur_menu->selected == 1) || cur_menu->id == MenuId_BrowseHFS)
|
||||
if ((cur_menu->id == MenuId_NcaFsSectionsSubMenu && cur_menu->selected == 1) || cur_menu->id == MenuId_BrowseHFS || cur_menu->id == MenuId_BrowseEmmc)
|
||||
{
|
||||
show_button_prompt = false;
|
||||
|
||||
|
@ -3668,6 +3722,49 @@ end:
|
|||
return success;
|
||||
}
|
||||
|
||||
static bool browseEmmcPartition(void *userdata)
|
||||
{
|
||||
u8 bis_partition_id = (userdata ? *((u8*)userdata) : 0);
|
||||
const char *mount_name = NULL;
|
||||
char *base_out_path = NULL;
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (bis_partition_id < FsBisPartitionId_CalibrationFile || bis_partition_id > FsBisPartitionId_System)
|
||||
{
|
||||
consolePrint("invalid bis partition id! (%u)\n", bis_partition_id);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Mount BIS partition. */
|
||||
if (!bisStorageMountPartition(bis_partition_id, &mount_name))
|
||||
{
|
||||
consolePrint("failed to mount bis partition %u!\n", bis_partition_id);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Generate output base path. */
|
||||
base_out_path = generateOutputGameCardFileName(utilsGetAtmosphereEmummcStatus() ? "emuMMC" : "sysMMC", mount_name, false);
|
||||
if (!base_out_path) goto end;
|
||||
|
||||
/* Display file browser. */
|
||||
success = fsBrowser(mount_name, base_out_path);
|
||||
|
||||
end:
|
||||
/* Free data. */
|
||||
if (base_out_path) free(base_out_path);
|
||||
|
||||
if (mount_name) bisStorageUnmountPartition(bis_partition_id);
|
||||
|
||||
if (!success && g_appletStatus)
|
||||
{
|
||||
consolePrint("press any button to continue\n");
|
||||
utilsWaitForButtonPress(0);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool fsBrowser(const char *mount_name, const char *base_out_path)
|
||||
{
|
||||
char dir_path[FS_MAX_PATH] = {0};
|
||||
|
@ -3701,8 +3798,13 @@ static bool fsBrowser(const char *mount_name, const char *base_out_path)
|
|||
consolePrint("press + to exit\n");
|
||||
consolePrint("______________________________\n\n");
|
||||
|
||||
if (entries_count)
|
||||
{
|
||||
consolePrint("entry: %u / %u\n", selected + 1, entries_count);
|
||||
consolePrint("highlighted: %u / %u\n", highlighted, entries_count);
|
||||
consolePrint("selected: %s\n", entries[selected].dt.d_name);
|
||||
}
|
||||
|
||||
consolePrint("current path: %s\n", dir_path);
|
||||
consolePrint("______________________________\n\n");
|
||||
|
||||
|
@ -3957,6 +4059,9 @@ static bool fsBrowserGetDirEntries(const char *dir_path, FsBrowserEntry **out_en
|
|||
goto end;
|
||||
}
|
||||
|
||||
/* Sort entries. */
|
||||
if (count > 1) qsort(entries, count, sizeof(FsBrowserEntry), &fsBrowserDirEntrySortFunction);
|
||||
|
||||
/* Update output pointers. */
|
||||
*out_entries = entries;
|
||||
*out_entry_count = count;
|
||||
|
@ -3972,6 +4077,23 @@ end:
|
|||
return success;
|
||||
}
|
||||
|
||||
static int fsBrowserDirEntrySortFunction(const void *a, const void *b)
|
||||
{
|
||||
const FsBrowserEntry *entry_1 = (const FsBrowserEntry*)a;
|
||||
const FsBrowserEntry *entry_2 = (const FsBrowserEntry*)b;
|
||||
|
||||
if (entry_1->dt.d_type < entry_2->dt.d_type)
|
||||
{
|
||||
return -1;
|
||||
} else
|
||||
if (entry_1->dt.d_type > entry_2->dt.d_type)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
return strcasecmp(entry_1->dt.d_name, entry_2->dt.d_name);
|
||||
}
|
||||
|
||||
static bool fsBrowserDumpFile(const char *dir_path, const FsBrowserEntry *entry, const char *base_out_path)
|
||||
{
|
||||
u64 free_space = 0;
|
||||
|
|
|
@ -43,10 +43,10 @@ static BisStorageFatFsContext *g_bisStorageContexts[FF_VOLUMES] = {0};
|
|||
|
||||
/// Required by FatFs.
|
||||
const char *VolumeStr[FF_VOLUMES] = {
|
||||
"prodinfof",
|
||||
"safe",
|
||||
"user",
|
||||
"system",
|
||||
"PRODINFOF",
|
||||
"SAFE",
|
||||
"USER",
|
||||
"SYSTEM",
|
||||
};
|
||||
|
||||
/* Function prototypes. */
|
||||
|
|
|
@ -1738,40 +1738,6 @@ save_ctx_t *save_open_savefile(const char *path, u32 action)
|
|||
goto end;
|
||||
}
|
||||
|
||||
/* Code to dump the requested file in its entirety. Useful to retrieve protected system savefiles without exiting HOS. */
|
||||
/*char sd_path[FS_MAX_PATH] = {0};
|
||||
snprintf(sd_path, MAX_ELEMENTS(sd_path), DEVOPTAB_SDMC_DEVICE "/%s", strrchr(path, '/') + 1);
|
||||
|
||||
utilsCreateDirectoryTree(sd_path, false);
|
||||
|
||||
u64 blksize = 0x100000;
|
||||
u8 *buf = malloc(blksize);
|
||||
FILE *sd_fp = fopen(sd_path, "wb");
|
||||
|
||||
if (buf && sd_fp)
|
||||
{
|
||||
fseek(save_fp, 0, SEEK_END);
|
||||
u64 size = ftell(save_fp);
|
||||
rewind(save_fp);
|
||||
|
||||
for(u64 offset = 0; offset < size; offset += blksize)
|
||||
{
|
||||
if ((size - offset) < blksize) blksize = (size - offset);
|
||||
if (fread(buf, 1, blksize, save_fp) != blksize) break;
|
||||
fwrite(buf, 1, blksize, sd_fp);
|
||||
}
|
||||
|
||||
rewind(save_fp);
|
||||
}
|
||||
|
||||
if (sd_fp)
|
||||
{
|
||||
fclose(sd_fp);
|
||||
utilsCommitSdCardFileSystemChanges();
|
||||
}
|
||||
|
||||
if (buf) free(buf);*/
|
||||
|
||||
save_ctx = calloc(1, sizeof(save_ctx_t));
|
||||
if (!save_ctx)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue