1
0
Fork 0
mirror of https://github.com/DarkMatterCore/nxdumptool.git synced 2024-12-22 16:42:11 +00:00

Fix Patch RomFS ctx init w/missing base NCA FS.

This bug was introduced in c474435ea8.

Other changes include:

* nxdt_rw_poc, bktr: minor cosmetic code changes.
* cnmt: add ContentMetaPlatform enum.
This commit is contained in:
Pablo Curiel 2023-10-12 11:24:03 +02:00
parent bb4608118d
commit ecaeddf356
7 changed files with 44 additions and 28 deletions

View file

@ -934,7 +934,7 @@ int main(int argc, char *argv[])
}
consoleClear();
consolePrint(APP_TITLE " v" APP_VERSION " (" GIT_REV "). Built on " BUILD_TIMESTAMP ".\n");
consolePrint(APP_TITLE " v" APP_VERSION " (" GIT_REV ").\nBuilt on " BUILD_TIMESTAMP ".\n");
consolePrint("______________________________\n\n");
if (cur_menu->parent) consolePrint("press b to go back\n");
if (g_umsDeviceCount) consolePrint("press x to safely remove all ums devices\n");

View file

@ -41,6 +41,11 @@ typedef enum {
ContentMetaAttribute_Count = 3 ///< Total values supported by this enum.
} ContentMetaAttribute;
typedef enum {
ContentMetaPlatform_Nx = 0,
ContentMetaPlatform_Count = 1 ///< Total values supported by this enum.
} ContentMetaPlatform;
typedef enum {
ContentMetaInstallState_None = 0,
ContentMetaInstallState_Committed = BIT(0),
@ -55,17 +60,17 @@ typedef enum {
typedef struct {
u64 title_id;
Version version;
u8 content_meta_type; ///< NcmContentMetaType.
u8 reserved_1;
u16 extended_header_size; ///< Must match the size from the extended header struct for this content meta type (SystemUpdate, Application, Patch, AddOnContent, Delta).
u16 content_count; ///< Determines how many NcmPackagedContentInfo entries are available after the extended header.
u16 content_meta_count; ///< Determines how many NcmContentMetaInfo entries are available after the NcmPackagedContentInfo entries. Only used for SystemUpdate.
u8 content_meta_attribute; ///< ContentMetaAttribute.
u8 storage_id; ///< NcmStorageId.
u8 content_install_type; ///< NcmContentInstallType.
u8 install_state; ///< ContentMetaInstallState.
u8 content_meta_type; ///< NcmContentMetaType.
u8 content_meta_platform; ///< ContentMetaPlatform.
u16 extended_header_size; ///< Must match the size from the extended header struct for this content meta type (SystemUpdate, Application, Patch, AddOnContent, Delta).
u16 content_count; ///< Determines how many NcmPackagedContentInfo entries are available after the extended header.
u16 content_meta_count; ///< Determines how many NcmContentMetaInfo entries are available after the NcmPackagedContentInfo entries. Only used for SystemUpdate.
u8 content_meta_attribute; ///< ContentMetaAttribute.
u8 storage_id; ///< NcmStorageId.
u8 content_install_type; ///< NcmContentInstallType.
u8 install_state; ///< ContentMetaInstallState.
Version required_download_system_version;
u8 reserved_2[0x4];
u8 reserved[0x4];
} ContentMetaPackagedContentMetaHeader;
NXDT_ASSERT(ContentMetaPackagedContentMetaHeader, 0x20);

View file

@ -50,9 +50,8 @@ typedef struct {
} NcaStorageContext;
/// Initializes a NCA storage context using a NCA FS section context, optionally providing a pointer to a base NcaStorageContext.
/// 'base_ctx' must be provided if dealing with a patch NCA. One of its storages will be set as the original substorage for the initialized NcaStorageContext's Indirect Storage.
/// This is needed to perform combined reads between a base NCA and a patch NCA.
/// 'base_ctx' shall be NULL if dealing with a base NCA.
/// 'base_ctx' shall be provided if dealing with a patch NCA with available base NCA data. This is needed to perform combined reads between a base NCA and a patch NCA.
/// 'base_ctx' shall be NULL if dealing with a base NCA *or* a patch NCA with missing base NCA data.
bool ncaStorageInitializeContext(NcaStorageContext *out, NcaFsSectionContext *nca_fs_ctx, NcaStorageContext *base_ctx);
/// Retrieves the underlying NCA FS section's hierarchical hash target layer extents. Virtual extents may be returned, depending on the base storage type.

View file

@ -1138,8 +1138,8 @@ static bool bktrReadCompressedStorage(BucketTreeVisitor *visitor, void *out, u64
}
/* Decompress LZ4 block. */
int lz4_res = 0;
if ((lz4_res = LZ4_decompress_safe((char*)read_ptr, (char*)buffer, (int)compressed_data_size, (int)buffer_size)) != (int)decompressed_data_size)
int lz4_res = LZ4_decompress_safe((char*)read_ptr, (char*)buffer, (int)compressed_data_size, (int)buffer_size);
if (lz4_res != (int)decompressed_data_size)
{
LOG_MSG_ERROR("Failed to decompress 0x%lX-byte long compressed block! (%d).", compressed_data_size, lz4_res);
free(buffer);

View file

@ -146,6 +146,12 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx)
goto end;
}
if (out->packaged_header->content_meta_platform >= ContentMetaPlatform_Count)
{
LOG_MSG_ERROR("Invalid platform!");
goto end;
}
if (!out->packaged_header->content_count && out->packaged_header->content_meta_type != NcmContentMetaType_SystemUpdate)
{
LOG_MSG_ERROR("Invalid content count!");

View file

@ -25,13 +25,13 @@
/* Function prototypes. */
static bool ncaStorageInitializeBucketTreeContext(BucketTreeContext **out, NcaFsSectionContext *nca_fs_ctx, u8 storage_type);
static bool ncaStorageSetPatchOriginalSubStorage(NcaStorageContext *patch_ctx, NcaFsSectionContext *patch_nca_fs_ctx, NcaStorageContext *base_ctx);
static bool ncaStorageSetPatchOriginalSubStorage(NcaStorageContext *patch_ctx, NcaStorageContext *base_ctx);
static bool ncaStorageInitializeCompressedStorageBucketTreeContext(NcaStorageContext *out, NcaFsSectionContext *nca_fs_ctx);
bool ncaStorageInitializeContext(NcaStorageContext *out, NcaFsSectionContext *nca_fs_ctx, NcaStorageContext *base_ctx)
{
if (!out || !nca_fs_ctx || !nca_fs_ctx->enabled || (nca_fs_ctx->section_type == NcaFsSectionType_PatchRomFs && \
(!nca_fs_ctx->has_patch_indirect_layer || !nca_fs_ctx->has_patch_aes_ctr_ex_layer || nca_fs_ctx->has_sparse_layer || !base_ctx)))
(!nca_fs_ctx->has_patch_indirect_layer || !nca_fs_ctx->has_patch_aes_ctr_ex_layer || nca_fs_ctx->has_sparse_layer)))
{
LOG_MSG_ERROR("Invalid parameters!");
return false;
@ -61,7 +61,7 @@ bool ncaStorageInitializeContext(NcaStorageContext *out, NcaFsSectionContext *nc
/* Check if both Indirect and AesCtrEx layers are available. */
if (nca_fs_ctx->section_type == NcaFsSectionType_PatchRomFs)
{
/* Initialize AesCtrEx and Indirect layers. */
/* Initialize AesCtrEx layer. */
if (!ncaStorageInitializeBucketTreeContext(&(out->aes_ctr_ex_storage), nca_fs_ctx, BucketTreeStorageType_AesCtrEx) || \
!ncaStorageInitializeBucketTreeContext(&(out->indirect_storage), nca_fs_ctx, BucketTreeStorageType_Indirect)) goto end;
@ -69,8 +69,8 @@ bool ncaStorageInitializeContext(NcaStorageContext *out, NcaFsSectionContext *nc
if (!bktrSetRegularSubStorage(out->aes_ctr_ex_storage, nca_fs_ctx)) goto end;
/* Set Indirect layer's substorages (Base + AesCtrEx). */
if (!ncaStorageSetPatchOriginalSubStorage(out, nca_fs_ctx, base_ctx)) goto end;
if (!bktrSetBucketTreeSubStorage(out->indirect_storage, out->aes_ctr_ex_storage, 1)) goto end;
if (!ncaStorageSetPatchOriginalSubStorage(out, base_ctx) || \
!bktrSetBucketTreeSubStorage(out->indirect_storage, out->aes_ctr_ex_storage, 1)) goto end;
/* Update base storage type. */
out->base_storage_type = NcaStorageBaseStorageType_Indirect;
@ -261,21 +261,27 @@ end:
return success;
}
static bool ncaStorageSetPatchOriginalSubStorage(NcaStorageContext *patch_ctx, NcaFsSectionContext *patch_nca_fs_ctx, NcaStorageContext *base_ctx)
static bool ncaStorageSetPatchOriginalSubStorage(NcaStorageContext *patch_ctx, NcaStorageContext *base_ctx)
{
NcaFsSectionContext *patch_nca_fs_ctx = NULL, *base_nca_fs_ctx = NULL;
NcaContext *patch_nca_ctx = NULL, *base_nca_ctx = NULL;
if (!patch_ctx || !patch_ctx->indirect_storage || !patch_ctx->aes_ctr_ex_storage || !patch_nca_fs_ctx || !ncaStorageIsValidContext(base_ctx) || \
!(patch_nca_ctx = patch_nca_fs_ctx->nca_ctx) || !(base_nca_ctx = base_ctx->nca_fs_ctx->nca_ctx) || \
patch_nca_fs_ctx->section_type != NcaFsSectionType_PatchRomFs || base_ctx->nca_fs_ctx->section_type != NcaFsSectionType_RomFs || \
bool missing_base_ctx = !ncaStorageIsValidContext(base_ctx);
bool success = false;
if (!patch_ctx || !patch_ctx->indirect_storage || !patch_ctx->aes_ctr_ex_storage || !(patch_nca_fs_ctx = patch_ctx->indirect_storage->nca_fs_ctx) || \
patch_nca_fs_ctx->section_type != NcaFsSectionType_PatchRomFs || !(patch_nca_ctx = patch_nca_fs_ctx->nca_ctx) || \
(!missing_base_ctx && (!(base_nca_fs_ctx = base_ctx->nca_fs_ctx) || base_nca_fs_ctx->section_type != NcaFsSectionType_RomFs || !(base_nca_ctx = base_nca_fs_ctx->nca_ctx) || \
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.value < base_nca_ctx->title_version.value)
patch_nca_ctx->id_offset != base_nca_ctx->id_offset || patch_nca_ctx->title_version.value < base_nca_ctx->title_version.value)))
{
LOG_MSG_ERROR("Invalid parameters!");
return false;
}
bool success = false;
/* Return immediately if we passed all patch context checks, but we're missing a base context. */
if (missing_base_ctx) return true;
/* Set original substorage. */
switch(base_ctx->base_storage_type)

View file

@ -66,7 +66,7 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base
if (patch_nca_fs_ctx)
{
/* Initialize base NCA storage context. */
if (!ncaStorageInitializeContext(patch_storage_ctx, patch_nca_fs_ctx, base_storage_ctx))
if (!ncaStorageInitializeContext(patch_storage_ctx, patch_nca_fs_ctx, missing_base_romfs ? NULL : base_storage_ctx))
{
LOG_MSG_ERROR("Failed to initialize patch NCA storage context!");
goto end;