mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
Fix some issues + update PoCs.
ncaStorageSetPatchOriginalSubStorage: allow Patch title version to be equal to the Base title version (e.g. sparse titles). ncaStorageGetHashTargetExtents: actually set proper storage extents. bktrGetTreeNodeEntryIndex: fix index lookup algorithm. bktrStorageNodeFind: fix binary search. bktrVisitorMoveNext / bktrVisitorMovePrevious: fix integer overflows.
This commit is contained in:
parent
de6eb1a7e8
commit
91dc20b7f3
9 changed files with 123 additions and 121 deletions
|
@ -20,7 +20,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "nxdt_utils.h"
|
#include "nxdt_utils.h"
|
||||||
#include "bktr.h"
|
#include "romfs.h"
|
||||||
#include "gamecard.h"
|
#include "gamecard.h"
|
||||||
#include "title.h"
|
#include "title.h"
|
||||||
|
|
||||||
|
@ -37,7 +37,6 @@ typedef struct
|
||||||
{
|
{
|
||||||
FILE *fd;
|
FILE *fd;
|
||||||
RomFileSystemContext *romfs_ctx;
|
RomFileSystemContext *romfs_ctx;
|
||||||
BktrContext *bktr_ctx;
|
|
||||||
void *data;
|
void *data;
|
||||||
size_t data_size;
|
size_t data_size;
|
||||||
size_t data_written;
|
size_t data_written;
|
||||||
|
@ -87,7 +86,7 @@ static void consolePrint(const char *text, ...)
|
||||||
static void read_thread_func(void *arg)
|
static void read_thread_func(void *arg)
|
||||||
{
|
{
|
||||||
ThreadSharedData *shared_data = (ThreadSharedData*)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))
|
if (!shared_data || shared_data->fd || !shared_data->data || !shared_data->total_size || !shared_data->romfs_ctx)
|
||||||
{
|
{
|
||||||
shared_data->read_error = true;
|
shared_data->read_error = true;
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -101,7 +100,7 @@ static void read_thread_func(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 file_table_offset = 0;
|
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);
|
u64 file_table_size = shared_data->romfs_ctx->file_table_size;
|
||||||
RomFileSystemFileEntry *file_entry = NULL;
|
RomFileSystemFileEntry *file_entry = NULL;
|
||||||
|
|
||||||
char path[FS_MAX_PATH] = {0};
|
char path[FS_MAX_PATH] = {0};
|
||||||
|
@ -130,15 +129,8 @@ static void read_thread_func(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve RomFS file entry information. */
|
/* Retrieve RomFS file entry information. */
|
||||||
if (shared_data->bktr_ctx)
|
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));
|
||||||
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)
|
if (shared_data->read_error)
|
||||||
{
|
{
|
||||||
condvarWakeAll(&g_writeCondvar);
|
condvarWakeAll(&g_writeCondvar);
|
||||||
|
@ -168,8 +160,7 @@ static void read_thread_func(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read current file data chunk. */
|
/* Read current file data chunk. */
|
||||||
shared_data->read_error = (shared_data->bktr_ctx ? !bktrReadFileEntryData(shared_data->bktr_ctx, file_entry, buf, blksize, offset) : \
|
shared_data->read_error = !romfsReadFileEntryData(shared_data->romfs_ctx, file_entry, buf, blksize, offset);
|
||||||
!romfsReadFileEntryData(shared_data->romfs_ctx, file_entry, buf, blksize, offset));
|
|
||||||
if (shared_data->read_error)
|
if (shared_data->read_error)
|
||||||
{
|
{
|
||||||
condvarWakeAll(&g_writeCondvar);
|
condvarWakeAll(&g_writeCondvar);
|
||||||
|
@ -406,7 +397,6 @@ int main(int argc, char *argv[])
|
||||||
NcaContext *base_nca_ctx = NULL, *update_nca_ctx = NULL;
|
NcaContext *base_nca_ctx = NULL, *update_nca_ctx = NULL;
|
||||||
|
|
||||||
RomFileSystemContext romfs_ctx = {0};
|
RomFileSystemContext romfs_ctx = {0};
|
||||||
BktrContext bktr_ctx = {0};
|
|
||||||
|
|
||||||
ThreadSharedData shared_data = {0};
|
ThreadSharedData shared_data = {0};
|
||||||
Thread read_thread = {0}, write_thread = {0};
|
Thread read_thread = {0}, write_thread = {0};
|
||||||
|
@ -586,9 +576,18 @@ int main(int argc, char *argv[])
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user_app_data.patch_info)
|
TitleInfo *latest_patch = NULL;
|
||||||
|
if (user_app_data.patch_info) latest_patch = get_latest_patch_info(user_app_data.patch_info);
|
||||||
|
|
||||||
|
if (base_nca_ctx->fs_ctx[1].has_sparse_layer && (!latest_patch || latest_patch->version.value < user_app_data.app_info->version.value))
|
||||||
{
|
{
|
||||||
TitleInfo *latest_patch = get_latest_patch_info(user_app_data.patch_info);
|
consolePrint("base app is a sparse title and no v%u or greater update could be found\n", user_app_data.app_info->version.value);
|
||||||
|
goto out2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (latest_patch)
|
||||||
|
{
|
||||||
|
consolePrint("using patch romfs with update v%u\n", latest_patch->version.value);
|
||||||
|
|
||||||
if (!ncaInitializeContext(update_nca_ctx, latest_patch->storage_id, (latest_patch->storage_id == NcmStorageId_GameCard ? GameCardHashFileSystemPartitionType_Secure : 0), \
|
if (!ncaInitializeContext(update_nca_ctx, latest_patch->storage_id, (latest_patch->storage_id == NcmStorageId_GameCard ? GameCardHashFileSystemPartitionType_Secure : 0), \
|
||||||
titleGetContentInfoByTypeAndIdOffset(latest_patch, NcmContentType_Program, program_id_offset), latest_patch->version.value, NULL))
|
titleGetContentInfoByTypeAndIdOffset(latest_patch, NcmContentType_Program, program_id_offset), latest_patch->version.value, NULL))
|
||||||
|
@ -597,29 +596,26 @@ int main(int argc, char *argv[])
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bktrInitializeContext(&bktr_ctx, &(base_nca_ctx->fs_ctx[1]), &(update_nca_ctx->fs_ctx[1])))
|
if (!romfsInitializeContext(&romfs_ctx, &(base_nca_ctx->fs_ctx[1]), &(update_nca_ctx->fs_ctx[1])))
|
||||||
{
|
{
|
||||||
consolePrint("bktr initialize ctx failed\n");
|
consolePrint("romfs initialize ctx failed (update)\n");
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_data.bktr_ctx = &bktr_ctx;
|
|
||||||
bktrGetTotalDataSize(&bktr_ctx, &(shared_data.total_size));
|
|
||||||
|
|
||||||
consolePrint("bktr initialize ctx succeeded\n");
|
|
||||||
} else {
|
} else {
|
||||||
if (!romfsInitializeContext(&romfs_ctx, &(base_nca_ctx->fs_ctx[1])))
|
consolePrint("using base romfs only\n");
|
||||||
|
|
||||||
|
if (!romfsInitializeContext(&romfs_ctx, &(base_nca_ctx->fs_ctx[1]), NULL))
|
||||||
{
|
{
|
||||||
consolePrint("romfs initialize ctx failed\n");
|
consolePrint("romfs initialize ctx failed (base)\n");
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_data.romfs_ctx = &romfs_ctx;
|
|
||||||
romfsGetTotalDataSize(&romfs_ctx, &(shared_data.total_size));
|
|
||||||
|
|
||||||
consolePrint("romfs initialize ctx succeeded\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.fd = NULL;
|
||||||
shared_data.data = buf;
|
shared_data.data = buf;
|
||||||
shared_data.data_size = 0;
|
shared_data.data_size = 0;
|
||||||
|
@ -718,7 +714,6 @@ out2:
|
||||||
}
|
}
|
||||||
|
|
||||||
romfsFreeContext(&romfs_ctx);
|
romfsFreeContext(&romfs_ctx);
|
||||||
bktrFreeContext(&bktr_ctx);
|
|
||||||
|
|
||||||
if (update_nca_ctx) free(update_nca_ctx);
|
if (update_nca_ctx) free(update_nca_ctx);
|
||||||
|
|
||||||
|
|
|
@ -167,7 +167,7 @@ static void dumpRomFs(TitleInfo *info, NcaFsSectionContext *nca_fs_ctx)
|
||||||
size_t path_len = 0;
|
size_t path_len = 0;
|
||||||
*path = '\0';
|
*path = '\0';
|
||||||
|
|
||||||
if (!romfsInitializeContext(&romfs_ctx, nca_fs_ctx))
|
if (!romfsInitializeContext(&romfs_ctx, nca_fs_ctx, NULL))
|
||||||
{
|
{
|
||||||
consolePrint("romfs initialize ctx failed!\n");
|
consolePrint("romfs initialize ctx failed!\n");
|
||||||
goto end;
|
goto end;
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "nxdt_utils.h"
|
#include "nxdt_utils.h"
|
||||||
#include "bktr.h"
|
#include "romfs.h"
|
||||||
#include "gamecard.h"
|
#include "gamecard.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include "title.h"
|
#include "title.h"
|
||||||
|
@ -38,7 +38,6 @@ typedef struct
|
||||||
{
|
{
|
||||||
//FILE *fileobj;
|
//FILE *fileobj;
|
||||||
RomFileSystemContext *romfs_ctx;
|
RomFileSystemContext *romfs_ctx;
|
||||||
BktrContext *bktr_ctx;
|
|
||||||
void *data;
|
void *data;
|
||||||
size_t data_size;
|
size_t data_size;
|
||||||
size_t data_written;
|
size_t data_written;
|
||||||
|
@ -88,7 +87,7 @@ static void consolePrint(const char *text, ...)
|
||||||
static void read_thread_func(void *arg)
|
static void read_thread_func(void *arg)
|
||||||
{
|
{
|
||||||
ThreadSharedData *shared_data = (ThreadSharedData*)arg;
|
ThreadSharedData *shared_data = (ThreadSharedData*)arg;
|
||||||
if (!shared_data || !shared_data->data || !shared_data->total_size || (!shared_data->romfs_ctx && !shared_data->bktr_ctx))
|
if (!shared_data || !shared_data->data || !shared_data->total_size || !shared_data->romfs_ctx)
|
||||||
{
|
{
|
||||||
shared_data->read_error = true;
|
shared_data->read_error = true;
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -102,7 +101,7 @@ static void read_thread_func(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 file_table_offset = 0;
|
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);
|
u64 file_table_size = shared_data->romfs_ctx->file_table_size;
|
||||||
RomFileSystemFileEntry *file_entry = NULL;
|
RomFileSystemFileEntry *file_entry = NULL;
|
||||||
char path[FS_MAX_PATH] = {0};
|
char path[FS_MAX_PATH] = {0};
|
||||||
|
|
||||||
|
@ -116,15 +115,8 @@ static void read_thread_func(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve RomFS file entry information */
|
/* Retrieve RomFS file entry information */
|
||||||
if (shared_data->bktr_ctx)
|
shared_data->read_error = (!(file_entry = romfsGetFileEntryByOffset(shared_data->romfs_ctx, file_table_offset)) || \
|
||||||
{
|
!romfsGeneratePathFromFileEntry(shared_data->romfs_ctx, file_entry, path, FS_MAX_PATH, RomFileSystemPathIllegalCharReplaceType_IllegalFsChars));
|
||||||
shared_data->read_error = (!(file_entry = bktrGetFileEntryByOffset(shared_data->bktr_ctx, file_table_offset)) || \
|
|
||||||
!bktrGeneratePathFromFileEntry(shared_data->bktr_ctx, file_entry, path, FS_MAX_PATH, RomFileSystemPathIllegalCharReplaceType_IllegalFsChars));
|
|
||||||
} else {
|
|
||||||
shared_data->read_error = (!(file_entry = romfsGetFileEntryByOffset(shared_data->romfs_ctx, file_table_offset)) || \
|
|
||||||
!romfsGeneratePathFromFileEntry(shared_data->romfs_ctx, file_entry, path, FS_MAX_PATH, RomFileSystemPathIllegalCharReplaceType_IllegalFsChars));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shared_data->read_error)
|
if (shared_data->read_error)
|
||||||
{
|
{
|
||||||
condvarWakeAll(&g_writeCondvar);
|
condvarWakeAll(&g_writeCondvar);
|
||||||
|
@ -157,8 +149,7 @@ static void read_thread_func(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read current file data chunk */
|
/* Read current file data chunk */
|
||||||
shared_data->read_error = (shared_data->bktr_ctx ? !bktrReadFileEntryData(shared_data->bktr_ctx, file_entry, buf, blksize, offset) : \
|
shared_data->read_error = !romfsReadFileEntryData(shared_data->romfs_ctx, file_entry, buf, blksize, offset);
|
||||||
!romfsReadFileEntryData(shared_data->romfs_ctx, file_entry, buf, blksize, offset));
|
|
||||||
if (shared_data->read_error)
|
if (shared_data->read_error)
|
||||||
{
|
{
|
||||||
condvarWakeAll(&g_writeCondvar);
|
condvarWakeAll(&g_writeCondvar);
|
||||||
|
@ -385,7 +376,6 @@ int main(int argc, char *argv[])
|
||||||
NcaContext *base_nca_ctx = NULL, *update_nca_ctx = NULL;
|
NcaContext *base_nca_ctx = NULL, *update_nca_ctx = NULL;
|
||||||
|
|
||||||
RomFileSystemContext romfs_ctx = {0};
|
RomFileSystemContext romfs_ctx = {0};
|
||||||
BktrContext bktr_ctx = {0};
|
|
||||||
|
|
||||||
ThreadSharedData shared_data = {0};
|
ThreadSharedData shared_data = {0};
|
||||||
Thread read_thread = {0}, write_thread = {0};
|
Thread read_thread = {0}, write_thread = {0};
|
||||||
|
@ -559,9 +549,18 @@ int main(int argc, char *argv[])
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user_app_data.patch_info)
|
TitleInfo *latest_patch = NULL;
|
||||||
|
if (user_app_data.patch_info) latest_patch = get_latest_patch_info(user_app_data.patch_info);
|
||||||
|
|
||||||
|
if (base_nca_ctx->fs_ctx[1].has_sparse_layer && (!latest_patch || latest_patch->version.value < user_app_data.app_info->version.value))
|
||||||
{
|
{
|
||||||
TitleInfo *latest_patch = get_latest_patch_info(user_app_data.patch_info);
|
consolePrint("base app is a sparse title and no v%u or greater update could be found\n", user_app_data.app_info->version.value);
|
||||||
|
goto out2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (latest_patch)
|
||||||
|
{
|
||||||
|
consolePrint("using patch romfs with update v%u\n", latest_patch->version.value);
|
||||||
|
|
||||||
if (!ncaInitializeContext(update_nca_ctx, latest_patch->storage_id, (latest_patch->storage_id == NcmStorageId_GameCard ? GameCardHashFileSystemPartitionType_Secure : 0), \
|
if (!ncaInitializeContext(update_nca_ctx, latest_patch->storage_id, (latest_patch->storage_id == NcmStorageId_GameCard ? GameCardHashFileSystemPartitionType_Secure : 0), \
|
||||||
titleGetContentInfoByTypeAndIdOffset(latest_patch, NcmContentType_Program, program_id_offset), latest_patch->version.value, NULL))
|
titleGetContentInfoByTypeAndIdOffset(latest_patch, NcmContentType_Program, program_id_offset), latest_patch->version.value, NULL))
|
||||||
|
@ -570,29 +569,26 @@ int main(int argc, char *argv[])
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bktrInitializeContext(&bktr_ctx, &(base_nca_ctx->fs_ctx[1]), &(update_nca_ctx->fs_ctx[1])))
|
if (!romfsInitializeContext(&romfs_ctx, &(base_nca_ctx->fs_ctx[1]), &(update_nca_ctx->fs_ctx[1])))
|
||||||
{
|
{
|
||||||
consolePrint("bktr initialize ctx failed\n");
|
consolePrint("romfs initialize ctx failed (update)\n");
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_data.bktr_ctx = &bktr_ctx;
|
|
||||||
bktrGetTotalDataSize(&bktr_ctx, &(shared_data.total_size));
|
|
||||||
|
|
||||||
consolePrint("bktr initialize ctx succeeded\n");
|
|
||||||
} else {
|
} else {
|
||||||
if (!romfsInitializeContext(&romfs_ctx, &(base_nca_ctx->fs_ctx[1])))
|
consolePrint("using base romfs only\n");
|
||||||
|
|
||||||
|
if (!romfsInitializeContext(&romfs_ctx, &(base_nca_ctx->fs_ctx[1]), NULL))
|
||||||
{
|
{
|
||||||
consolePrint("romfs initialize ctx failed\n");
|
consolePrint("romfs initialize ctx failed (base)\n");
|
||||||
goto out2;
|
goto out2;
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_data.romfs_ctx = &romfs_ctx;
|
|
||||||
romfsGetTotalDataSize(&romfs_ctx, &(shared_data.total_size));
|
|
||||||
|
|
||||||
consolePrint("romfs initialize ctx succeeded\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shared_data.romfs_ctx = &romfs_ctx;
|
||||||
|
romfsGetTotalDataSize(&romfs_ctx, &(shared_data.total_size));
|
||||||
|
|
||||||
|
consolePrint("romfs initialize ctx succeeded\n");
|
||||||
|
|
||||||
shared_data.data = buf;
|
shared_data.data = buf;
|
||||||
shared_data.data_size = 0;
|
shared_data.data_size = 0;
|
||||||
shared_data.data_written = 0;
|
shared_data.data_written = 0;
|
||||||
|
@ -719,7 +715,6 @@ out2:
|
||||||
}
|
}
|
||||||
|
|
||||||
romfsFreeContext(&romfs_ctx);
|
romfsFreeContext(&romfs_ctx);
|
||||||
bktrFreeContext(&bktr_ctx);
|
|
||||||
|
|
||||||
if (update_nca_ctx) free(update_nca_ctx);
|
if (update_nca_ctx) free(update_nca_ctx);
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
#ifndef __LEGAL_INFO_H__
|
#ifndef __LEGAL_INFO_H__
|
||||||
#define __LEGAL_INFO_H__
|
#define __LEGAL_INFO_H__
|
||||||
|
|
||||||
#include "nca.h"
|
#include "romfs.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -123,7 +123,7 @@ NX_INLINE bool bktrIsExistOffsetL2OnL1(BucketTreeContext *ctx);
|
||||||
static void bktrInitializeStorageNode(BucketTreeStorageNode *out, u64 entry_size, u32 entry_count);
|
static void bktrInitializeStorageNode(BucketTreeStorageNode *out, u64 entry_size, u32 entry_count);
|
||||||
static void bktrStorageNodeFind(BucketTreeStorageNode *storage_node, const BucketTreeNodeHeader *node_header, u64 virtual_offset);
|
static void bktrStorageNodeFind(BucketTreeStorageNode *storage_node, const BucketTreeNodeHeader *node_header, u64 virtual_offset);
|
||||||
NX_INLINE BucketTreeStorageNodeOffset bktrStorageNodeOffsetAdd(BucketTreeStorageNodeOffset *ofs, u64 value);
|
NX_INLINE BucketTreeStorageNodeOffset bktrStorageNodeOffsetAdd(BucketTreeStorageNodeOffset *ofs, u64 value);
|
||||||
NX_INLINE u64 bktrStorageNodeOffsetSubstract(BucketTreeStorageNodeOffset *ofs1, BucketTreeStorageNodeOffset *ofs2);
|
NX_INLINE const u64 bktrStorageNodeOffsetGetEntryVirtualOffset(const BucketTreeNodeHeader *node_header, const BucketTreeStorageNodeOffset *ofs);
|
||||||
|
|
||||||
NX_INLINE bool bktrVisitorIsValid(BucketTreeVisitor *visitor);
|
NX_INLINE bool bktrVisitorIsValid(BucketTreeVisitor *visitor);
|
||||||
NX_INLINE bool bktrVisitorCanMoveNext(BucketTreeVisitor *visitor);
|
NX_INLINE bool bktrVisitorCanMoveNext(BucketTreeVisitor *visitor);
|
||||||
|
@ -1104,21 +1104,27 @@ static bool bktrGetTreeNodeEntryIndex(const u64 *start_ptr, const u64 *end_ptr,
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 *pos = (u64*)start_ptr;
|
u64 *pos = (u64*)start_ptr;
|
||||||
bool found = false;
|
u32 index = 0;
|
||||||
|
|
||||||
while(pos < end_ptr)
|
while(pos < end_ptr)
|
||||||
{
|
{
|
||||||
if (start_ptr < pos && *pos > virtual_offset)
|
if (start_ptr < pos)
|
||||||
{
|
{
|
||||||
*out_index = ((u32)(pos - start_ptr) - 1);
|
/* Stop looking if we have found the right offset node. */
|
||||||
found = true;
|
if (*pos > virtual_offset) break;
|
||||||
break;
|
|
||||||
|
/* Increment index. */
|
||||||
|
index++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Increment offset node pointer. */
|
||||||
pos++;
|
pos++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return found;
|
/* Update output index. */
|
||||||
|
*out_index = index;
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bktrGetEntryNodeEntryIndex(const BucketTreeNodeHeader *node_header, u64 entry_size, u64 virtual_offset, u32 *out_index)
|
static bool bktrGetEntryNodeEntryIndex(const BucketTreeNodeHeader *node_header, u64 entry_size, u64 virtual_offset, u32 *out_index)
|
||||||
|
@ -1299,25 +1305,41 @@ static void bktrInitializeStorageNode(BucketTreeStorageNode *out, u64 entry_size
|
||||||
|
|
||||||
static void bktrStorageNodeFind(BucketTreeStorageNode *storage_node, const BucketTreeNodeHeader *node_header, u64 virtual_offset)
|
static void bktrStorageNodeFind(BucketTreeStorageNode *storage_node, const BucketTreeNodeHeader *node_header, u64 virtual_offset)
|
||||||
{
|
{
|
||||||
u32 end = storage_node->count;
|
/* Check for edge case, short circuit. */
|
||||||
BucketTreeStorageNodeOffset pos = storage_node->start;
|
if (storage_node->count == 1)
|
||||||
|
|
||||||
while(end > 0)
|
|
||||||
{
|
{
|
||||||
u32 half = (end / 2);
|
storage_node->index = 0;
|
||||||
BucketTreeStorageNodeOffset mid = bktrStorageNodeOffsetAdd(&pos, half);
|
return;
|
||||||
|
|
||||||
const u64 offset = *((const u64*)((const u8*)node_header + mid.offset));
|
|
||||||
if (offset <= virtual_offset)
|
|
||||||
{
|
|
||||||
pos = bktrStorageNodeOffsetAdd(&mid, 1);
|
|
||||||
end -= (half + 1);
|
|
||||||
} else {
|
|
||||||
end = half;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
storage_node->index = ((u32)bktrStorageNodeOffsetSubstract(&pos, &(storage_node->start)) - 1);
|
/* Perform a binary search. */
|
||||||
|
u32 entry_count = storage_node->count, low = 0, high = (entry_count - 1);
|
||||||
|
BucketTreeStorageNodeOffset *start = &(storage_node->start);
|
||||||
|
|
||||||
|
while(low <= high)
|
||||||
|
{
|
||||||
|
/* Get the offset to the middle entry within our current lookup range. */
|
||||||
|
u32 half = ((low + high) / 2);
|
||||||
|
BucketTreeStorageNodeOffset mid = bktrStorageNodeOffsetAdd(start, half);
|
||||||
|
|
||||||
|
/* Check middle entry's virtual offset. */
|
||||||
|
if (bktrStorageNodeOffsetGetEntryVirtualOffset(node_header, &mid) > virtual_offset)
|
||||||
|
{
|
||||||
|
/* Update our upper limit. */
|
||||||
|
high = (half - 1);
|
||||||
|
} else {
|
||||||
|
/* Check for success. */
|
||||||
|
BucketTreeStorageNodeOffset pos = bktrStorageNodeOffsetAdd(&mid, 1);
|
||||||
|
if (half == (entry_count - 1) || bktrStorageNodeOffsetGetEntryVirtualOffset(node_header, &pos) > virtual_offset)
|
||||||
|
{
|
||||||
|
storage_node->index = half;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update our lower limit. */
|
||||||
|
low = (half + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NX_INLINE BucketTreeStorageNodeOffset bktrStorageNodeOffsetAdd(BucketTreeStorageNodeOffset *ofs, u64 value)
|
NX_INLINE BucketTreeStorageNodeOffset bktrStorageNodeOffsetAdd(BucketTreeStorageNodeOffset *ofs, u64 value)
|
||||||
|
@ -1326,9 +1348,9 @@ NX_INLINE BucketTreeStorageNodeOffset bktrStorageNodeOffsetAdd(BucketTreeStorage
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
NX_INLINE u64 bktrStorageNodeOffsetSubstract(BucketTreeStorageNodeOffset *ofs1, BucketTreeStorageNodeOffset *ofs2)
|
NX_INLINE const u64 bktrStorageNodeOffsetGetEntryVirtualOffset(const BucketTreeNodeHeader *node_header, const BucketTreeStorageNodeOffset *ofs)
|
||||||
{
|
{
|
||||||
return (u64)((ofs1->offset - ofs2->offset) / ofs1->stride);
|
return *((const u64*)((const u8*)node_header + ofs->offset));
|
||||||
}
|
}
|
||||||
|
|
||||||
NX_INLINE bool bktrVisitorIsValid(BucketTreeVisitor *visitor)
|
NX_INLINE bool bktrVisitorIsValid(BucketTreeVisitor *visitor)
|
||||||
|
@ -1356,12 +1378,12 @@ static bool bktrVisitorMoveNext(BucketTreeVisitor *visitor)
|
||||||
|
|
||||||
BucketTreeContext *ctx = visitor->bktr_ctx;
|
BucketTreeContext *ctx = visitor->bktr_ctx;
|
||||||
BucketTreeEntrySetHeader *entry_set = &(visitor->entry_set);
|
BucketTreeEntrySetHeader *entry_set = &(visitor->entry_set);
|
||||||
|
u32 entry_index = (visitor->entry_index + 1);
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
/* Invalidate index. */
|
/* Invalidate index. */
|
||||||
visitor->entry_index = UINT32_MAX;
|
visitor->entry_index = UINT32_MAX;
|
||||||
|
|
||||||
u32 entry_index = (visitor->entry_index + 1);
|
|
||||||
if (entry_index == entry_set->header.count)
|
if (entry_index == entry_set->header.count)
|
||||||
{
|
{
|
||||||
/* We have reached the end of this entry node. Let's try to retrieve the first entry from the next one. */
|
/* We have reached the end of this entry node. Let's try to retrieve the first entry from the next one. */
|
||||||
|
@ -1428,12 +1450,12 @@ static bool bktrVisitorMovePrevious(BucketTreeVisitor *visitor)
|
||||||
|
|
||||||
BucketTreeContext *ctx = visitor->bktr_ctx;
|
BucketTreeContext *ctx = visitor->bktr_ctx;
|
||||||
BucketTreeEntrySetHeader *entry_set = &(visitor->entry_set);
|
BucketTreeEntrySetHeader *entry_set = &(visitor->entry_set);
|
||||||
|
u32 entry_index = visitor->entry_index;
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
/* Invalidate index. */
|
/* Invalidate index. */
|
||||||
visitor->entry_index = UINT32_MAX;
|
visitor->entry_index = UINT32_MAX;
|
||||||
|
|
||||||
u32 entry_index = visitor->entry_index;
|
|
||||||
if (entry_index == 0)
|
if (entry_index == 0)
|
||||||
{
|
{
|
||||||
/* We have reached the start of this entry node. Let's try to retrieve the last entry from the previous one. */
|
/* We have reached the start of this entry node. Let's try to retrieve the last entry from the previous one. */
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
|
|
||||||
#include "nxdt_utils.h"
|
#include "nxdt_utils.h"
|
||||||
#include "legal_info.h"
|
#include "legal_info.h"
|
||||||
#include "romfs.h"
|
|
||||||
|
|
||||||
bool legalInfoInitializeContext(LegalInfoContext *out, NcaContext *nca_ctx)
|
bool legalInfoInitializeContext(LegalInfoContext *out, NcaContext *nca_ctx)
|
||||||
{
|
{
|
||||||
|
|
|
@ -119,7 +119,7 @@ bool ncaStorageSetPatchOriginalSubStorage(NcaStorageContext *patch_ctx, NcaStora
|
||||||
!(patch_nca_ctx = (NcaContext*)patch_ctx->nca_fs_ctx->nca_ctx) || !(base_nca_ctx = (NcaContext*)base_ctx->nca_fs_ctx->nca_ctx) || \
|
!(patch_nca_ctx = (NcaContext*)patch_ctx->nca_fs_ctx->nca_ctx) || !(base_nca_ctx = (NcaContext*)base_ctx->nca_fs_ctx->nca_ctx) || \
|
||||||
patch_ctx->nca_fs_ctx->section_type != NcaFsSectionType_PatchRomFs || base_ctx->nca_fs_ctx->section_type != NcaFsSectionType_RomFs || \
|
patch_ctx->nca_fs_ctx->section_type != NcaFsSectionType_PatchRomFs || base_ctx->nca_fs_ctx->section_type != NcaFsSectionType_RomFs || \
|
||||||
patch_nca_ctx->header.program_id != base_nca_ctx->header.program_id || patch_nca_ctx->header.content_type != base_nca_ctx->header.content_type || \
|
patch_nca_ctx->header.program_id != base_nca_ctx->header.program_id || patch_nca_ctx->header.content_type != base_nca_ctx->header.content_type || \
|
||||||
patch_nca_ctx->id_offset != base_nca_ctx->id_offset || patch_nca_ctx->title_version <= base_nca_ctx->title_version || !patch_ctx->indirect_storage)
|
patch_nca_ctx->id_offset != base_nca_ctx->id_offset || patch_nca_ctx->title_version < base_nca_ctx->title_version || !patch_ctx->indirect_storage)
|
||||||
{
|
{
|
||||||
LOG_MSG("Invalid parameters!");
|
LOG_MSG("Invalid parameters!");
|
||||||
return false;
|
return false;
|
||||||
|
@ -170,26 +170,19 @@ bool ncaStorageGetHashTargetExtents(NcaStorageContext *ctx, u64 *out_offset, u64
|
||||||
switch(ctx->base_storage_type)
|
switch(ctx->base_storage_type)
|
||||||
{
|
{
|
||||||
case NcaStorageBaseStorageType_Regular:
|
case NcaStorageBaseStorageType_Regular:
|
||||||
|
case NcaStorageBaseStorageType_Sparse:
|
||||||
|
case NcaStorageBaseStorageType_Indirect:
|
||||||
{
|
{
|
||||||
/* Just provide the NCA FS section hash target extents. */
|
/* Regular: just provide the NCA FS section hash target extents -- they already represent physical information. */
|
||||||
|
/* Sparse/Indirect: the base storage's virtual section encompasses the hash layers, too. The NCA FS section hash target extents represent valid virtual information. */
|
||||||
if (out_offset) *out_offset = hash_target_offset;
|
if (out_offset) *out_offset = hash_target_offset;
|
||||||
if (out_size) *out_size = hash_target_size;
|
if (out_size) *out_size = hash_target_size;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case NcaStorageBaseStorageType_Sparse:
|
|
||||||
case NcaStorageBaseStorageType_Indirect:
|
|
||||||
{
|
|
||||||
/* Sparse/Indirect storages encompass the entire virtual section. */
|
|
||||||
/* Let's substract the NCA FS section hash target offset from the storage's virtual end offset. */
|
|
||||||
BucketTreeContext *bktr_ctx = (ctx->base_storage_type == NcaStorageBaseStorageType_Sparse ? ctx->sparse_storage : ctx->indirect_storage);
|
|
||||||
if (out_offset) *out_offset = hash_target_offset;
|
|
||||||
if (out_size) *out_size = (bktr_ctx->end_offset - hash_target_offset);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case NcaStorageBaseStorageType_Compressed:
|
case NcaStorageBaseStorageType_Compressed:
|
||||||
{
|
{
|
||||||
/* Compressed sections already reference the hash target section, so there's no need calculate the full size. */
|
/* Compressed sections already point to the hash target layer. */
|
||||||
if (out_offset) *out_offset = 0;
|
if (out_offset) *out_offset = ctx->compressed_storage->start_offset;
|
||||||
if (out_size) *out_size = ctx->compressed_storage->end_offset;
|
if (out_size) *out_size = ctx->compressed_storage->end_offset;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -232,7 +225,7 @@ bool ncaStorageRead(NcaStorageContext *ctx, void *out, u64 read_size, u64 offset
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!success) LOG_MSG("Failed to read 0x%lX-byte long block from offset 0x%lX in base storage! (%u).", read_size, offset, ctx->base_storage_type);
|
if (!success) LOG_MSG("Failed to read 0x%lX-byte long block from offset 0x%lX in base storage! (type: %u).", read_size, offset, ctx->base_storage_type);
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,14 +31,14 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base
|
||||||
{
|
{
|
||||||
u64 dir_table_offset = 0, file_table_offset = 0;
|
u64 dir_table_offset = 0, file_table_offset = 0;
|
||||||
NcaContext *base_nca_ctx = NULL, *patch_nca_ctx = NULL;
|
NcaContext *base_nca_ctx = NULL, *patch_nca_ctx = NULL;
|
||||||
bool dump_fs_header = false, is_patch = (patch_nca_fs_ctx != NULL), success = false;
|
bool dump_fs_header = false, success = false;
|
||||||
|
|
||||||
if (!out || !base_nca_fs_ctx || !base_nca_fs_ctx->enabled || (base_nca_fs_ctx->has_sparse_layer && !is_patch) || !(base_nca_ctx = (NcaContext*)base_nca_fs_ctx->nca_ctx) || \
|
if (!out || !base_nca_fs_ctx || !base_nca_fs_ctx->enabled || (base_nca_fs_ctx->has_sparse_layer && !patch_nca_fs_ctx) || !(base_nca_ctx = (NcaContext*)base_nca_fs_ctx->nca_ctx) || \
|
||||||
(base_nca_ctx->format_version == NcaVersion_Nca0 && (base_nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs || \
|
(base_nca_ctx->format_version == NcaVersion_Nca0 && (base_nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs || \
|
||||||
base_nca_fs_ctx->hash_type != NcaHashType_HierarchicalSha256)) || (base_nca_ctx->format_version != NcaVersion_Nca0 && \
|
base_nca_fs_ctx->hash_type != NcaHashType_HierarchicalSha256)) || (base_nca_ctx->format_version != NcaVersion_Nca0 && \
|
||||||
(base_nca_fs_ctx->section_type != NcaFsSectionType_RomFs || (base_nca_fs_ctx->hash_type != NcaHashType_HierarchicalIntegrity && \
|
(base_nca_fs_ctx->section_type != NcaFsSectionType_RomFs || (base_nca_fs_ctx->hash_type != NcaHashType_HierarchicalIntegrity && \
|
||||||
base_nca_fs_ctx->hash_type != NcaHashType_HierarchicalIntegritySha3))) || (base_nca_ctx->rights_id_available && !base_nca_ctx->titlekey_retrieved) || \
|
base_nca_fs_ctx->hash_type != NcaHashType_HierarchicalIntegritySha3))) || (base_nca_ctx->rights_id_available && !base_nca_ctx->titlekey_retrieved) || \
|
||||||
(is_patch && (!patch_nca_fs_ctx->enabled || !(patch_nca_ctx = (NcaContext*)patch_nca_fs_ctx->nca_ctx) || patch_nca_ctx->format_version != base_nca_ctx->format_version || \
|
(patch_nca_fs_ctx && (!patch_nca_fs_ctx->enabled || !(patch_nca_ctx = (NcaContext*)patch_nca_fs_ctx->nca_ctx) || patch_nca_ctx->format_version != base_nca_ctx->format_version || \
|
||||||
patch_nca_fs_ctx->section_type != NcaFsSectionType_PatchRomFs || (patch_nca_ctx->rights_id_available && !patch_nca_ctx->titlekey_retrieved))))
|
patch_nca_fs_ctx->section_type != NcaFsSectionType_PatchRomFs || (patch_nca_ctx->rights_id_available && !patch_nca_ctx->titlekey_retrieved))))
|
||||||
{
|
{
|
||||||
LOG_MSG("Invalid parameters!");
|
LOG_MSG("Invalid parameters!");
|
||||||
|
@ -58,9 +58,7 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
out->is_patch = is_patch;
|
if (patch_nca_fs_ctx)
|
||||||
|
|
||||||
if (is_patch)
|
|
||||||
{
|
{
|
||||||
/* Initialize base NCA storage context. */
|
/* Initialize base NCA storage context. */
|
||||||
if (!ncaStorageInitializeContext(patch_storage_ctx, patch_nca_fs_ctx))
|
if (!ncaStorageInitializeContext(patch_storage_ctx, patch_nca_fs_ctx))
|
||||||
|
@ -77,9 +75,11 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set default NCA FS storage context. */
|
/* Set default NCA FS storage context. */
|
||||||
|
out->is_patch = true;
|
||||||
out->default_storage_ctx = patch_storage_ctx;
|
out->default_storage_ctx = patch_storage_ctx;
|
||||||
} else {
|
} else {
|
||||||
/* Set default NCA FS storage context. */
|
/* Set default NCA FS storage context. */
|
||||||
|
out->is_patch = false;
|
||||||
out->default_storage_ctx = base_storage_ctx;
|
out->default_storage_ctx = base_storage_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
6
todo.txt
6
todo.txt
|
@ -1,7 +1,7 @@
|
||||||
todo:
|
todo:
|
||||||
|
|
||||||
nca: support for sparse sections
|
nca / nca_storage / bktr: re-test support for all section types
|
||||||
nca: support for compressed fs sections
|
nca: add function to retrieve a pointer to a nca fs ctx based on section type? (e.g. like titleGetContentInfoByTypeAndIdOffset)
|
||||||
|
|
||||||
log: verbosity levels
|
log: verbosity levels
|
||||||
log: nxlink output for advanced users
|
log: nxlink output for advanced users
|
||||||
|
@ -18,8 +18,6 @@ todo:
|
||||||
|
|
||||||
romfs: functions to display filelist
|
romfs: functions to display filelist
|
||||||
|
|
||||||
bktr: functions to display filelist (wrappers for romfs functions tbh)
|
|
||||||
|
|
||||||
usb: change buffer size?
|
usb: change buffer size?
|
||||||
usb: change chunk size?
|
usb: change chunk size?
|
||||||
usb: improve abi (make it rest-like?)
|
usb: improve abi (make it rest-like?)
|
||||||
|
|
Loading…
Reference in a new issue