mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
romfs: add support for Patch RomFS.
Uses the new NCA storage interface. Also implemented ncaStorageGetHashTargetExtents().
This commit is contained in:
parent
aad7af702f
commit
de6eb1a7e8
13 changed files with 158 additions and 66 deletions
|
@ -488,10 +488,10 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
|
||||||
/// Input offset must be relative to the start of the NCA content file.
|
/// Input offset must be relative to the start of the NCA content file.
|
||||||
bool ncaReadContentFile(NcaContext *ctx, void *out, u64 read_size, u64 offset);
|
bool ncaReadContentFile(NcaContext *ctx, void *out, u64 read_size, u64 offset);
|
||||||
|
|
||||||
/// Retrieves the offset and/or size from the FS section hierarchical hash target layer.
|
/// Retrieves the FS section's hierarchical hash target layer extents.
|
||||||
/// Output offset is relative to the start of the FS section.
|
/// Output offset is relative to the start of the FS section.
|
||||||
/// Either 'out_offset' or 'out_size' can be NULL, but at least one of them must be a valid pointer.
|
/// Either 'out_offset' or 'out_size' can be NULL, but at least one of them must be a valid pointer.
|
||||||
bool ncaGetFsSectionHashTargetProperties(NcaFsSectionContext *ctx, u64 *out_offset, u64 *out_size);
|
bool ncaGetFsSectionHashTargetExtents(NcaFsSectionContext *ctx, u64 *out_offset, u64 *out_size);
|
||||||
|
|
||||||
/// Reads decrypted data from a NCA FS section using an input context.
|
/// Reads decrypted data from a NCA FS section using an input context.
|
||||||
/// Input offset must be relative to the start of the NCA FS section.
|
/// Input offset must be relative to the start of the NCA FS section.
|
||||||
|
|
|
@ -38,7 +38,7 @@ typedef enum {
|
||||||
NcaStorageBaseStorageType_Compressed = 4
|
NcaStorageBaseStorageType_Compressed = 4
|
||||||
} NcaStorageBaseStorageType;
|
} NcaStorageBaseStorageType;
|
||||||
|
|
||||||
/// Used to perform multi-layer reads within a single NCA FS section.
|
/// Used to perform multi-layered reads within a single NCA FS section.
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u8 base_storage_type; ///< NcaStorageBaseStorageType.
|
u8 base_storage_type; ///< NcaStorageBaseStorageType.
|
||||||
NcaFsSectionContext *nca_fs_ctx; ///< NCA FS section context used to initialize this context.
|
NcaFsSectionContext *nca_fs_ctx; ///< NCA FS section context used to initialize this context.
|
||||||
|
@ -55,6 +55,11 @@ bool ncaStorageInitializeContext(NcaStorageContext *out, NcaFsSectionContext *nc
|
||||||
/// Needed to perform combined reads between a base NCA and a patch NCA.
|
/// Needed to perform combined reads between a base NCA and a patch NCA.
|
||||||
bool ncaStorageSetPatchOriginalSubStorage(NcaStorageContext *patch_ctx, NcaStorageContext *base_ctx);
|
bool ncaStorageSetPatchOriginalSubStorage(NcaStorageContext *patch_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.
|
||||||
|
/// Output offset is relative to the start of the NCA FS section.
|
||||||
|
/// Either 'out_offset' or 'out_size' can be NULL, but at least one of them must be a valid pointer.
|
||||||
|
bool ncaStorageGetHashTargetExtents(NcaStorageContext *ctx, u64 *out_offset, u64 *out_size);
|
||||||
|
|
||||||
/// Reads data from the NCA storage using a previously initialized NcaStorageContext.
|
/// Reads data from the NCA storage using a previously initialized NcaStorageContext.
|
||||||
bool ncaStorageRead(NcaStorageContext *ctx, void *out, u64 read_size, u64 offset);
|
bool ncaStorageRead(NcaStorageContext *ctx, void *out, u64 read_size, u64 offset);
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,8 @@ NX_INLINE PartitionFileSystemEntry *pfsGetEntryByName(PartitionFileSystemContext
|
||||||
|
|
||||||
NX_INLINE void pfsWriteEntryPatchToMemoryBuffer(PartitionFileSystemContext *ctx, NcaHierarchicalSha256Patch *patch, void *buf, u64 buf_size, u64 buf_offset)
|
NX_INLINE void pfsWriteEntryPatchToMemoryBuffer(PartitionFileSystemContext *ctx, NcaHierarchicalSha256Patch *patch, void *buf, u64 buf_size, u64 buf_offset)
|
||||||
{
|
{
|
||||||
if (!ctx || !ncaStorageIsValidContext(&(ctx->storage_ctx)) || ctx->nca_fs_ctx != ctx->storage_ctx.nca_fs_ctx) return;
|
if (!ctx || !ncaStorageIsValidContext(&(ctx->storage_ctx)) || ctx->nca_fs_ctx != ctx->storage_ctx.nca_fs_ctx || \
|
||||||
|
ctx->storage_ctx.base_storage_type != NcaStorageBaseStorageType_Regular) return;
|
||||||
ncaWriteHierarchicalSha256PatchToMemoryBuffer((NcaContext*)ctx->nca_fs_ctx->nca_ctx, patch, buf, buf_size, buf_offset);
|
ncaWriteHierarchicalSha256PatchToMemoryBuffer((NcaContext*)ctx->nca_fs_ctx->nca_ctx, patch, buf, buf_size, buf_offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -107,8 +107,9 @@ typedef struct {
|
||||||
NXDT_ASSERT(RomFileSystemFileEntry, 0x20);
|
NXDT_ASSERT(RomFileSystemFileEntry, 0x20);
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
NcaStorageContext storage_ctx; ///< Used to read NCA FS section data.
|
bool is_patch; ///< Set to true if this we're dealing with a Patch RomFS.
|
||||||
NcaFsSectionContext *nca_fs_ctx; ///< Same as storage_ctx.nca_fs_ctx. Placed here for convenience.
|
NcaStorageContext storage_ctx[2]; ///< Used to read NCA FS section data. Index 0: base storage. Index 1: patch storage.
|
||||||
|
NcaStorageContext *default_storage_ctx; ///< Default NCA storage context. Points to one of the two contexts from 'storage_ctx'. Placed here for convenience.
|
||||||
u64 offset; ///< RomFS offset (relative to the start of the NCA FS section).
|
u64 offset; ///< RomFS offset (relative to the start of the NCA FS section).
|
||||||
u64 size; ///< RomFS size.
|
u64 size; ///< RomFS size.
|
||||||
RomFileSystemHeader header; ///< RomFS header.
|
RomFileSystemHeader header; ///< RomFS header.
|
||||||
|
@ -133,8 +134,10 @@ typedef enum {
|
||||||
RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly = 2
|
RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly = 2
|
||||||
} RomFileSystemPathIllegalCharReplaceType;
|
} RomFileSystemPathIllegalCharReplaceType;
|
||||||
|
|
||||||
/// Initializes a RomFS context.
|
/// Initializes a RomFS or Patch RomFS context.
|
||||||
bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_fs_ctx);
|
/// 'base_nca_fs_ctx' must always be provided.
|
||||||
|
/// 'patch_nca_fs_ctx' shall be NULL if not dealing with a Patch RomFS.
|
||||||
|
bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base_nca_fs_ctx, NcaFsSectionContext *patch_nca_fs_ctx);
|
||||||
|
|
||||||
/// Reads raw filesystem data using a RomFS context.
|
/// Reads raw filesystem data using a RomFS context.
|
||||||
/// Input offset must be relative to the start of the RomFS.
|
/// Input offset must be relative to the start of the RomFS.
|
||||||
|
@ -175,7 +178,8 @@ bool romfsGenerateFileEntryPatch(RomFileSystemContext *ctx, RomFileSystemFileEnt
|
||||||
NX_INLINE void romfsFreeContext(RomFileSystemContext *ctx)
|
NX_INLINE void romfsFreeContext(RomFileSystemContext *ctx)
|
||||||
{
|
{
|
||||||
if (!ctx) return;
|
if (!ctx) return;
|
||||||
ncaStorageFreeContext(&(ctx->storage_ctx));
|
ncaStorageFreeContext(&(ctx->storage_ctx[0]));
|
||||||
|
ncaStorageFreeContext(&(ctx->storage_ctx[1]));
|
||||||
if (ctx->dir_table) free(ctx->dir_table);
|
if (ctx->dir_table) free(ctx->dir_table);
|
||||||
if (ctx->file_table) free(ctx->file_table);
|
if (ctx->file_table) free(ctx->file_table);
|
||||||
memset(ctx, 0, sizeof(RomFileSystemContext));
|
memset(ctx, 0, sizeof(RomFileSystemContext));
|
||||||
|
@ -195,11 +199,11 @@ NX_INLINE RomFileSystemFileEntry *romfsGetFileEntryByOffset(RomFileSystemContext
|
||||||
|
|
||||||
NX_INLINE void romfsWriteFileEntryPatchToMemoryBuffer(RomFileSystemContext *ctx, RomFileSystemFileEntryPatch *patch, void *buf, u64 buf_size, u64 buf_offset)
|
NX_INLINE void romfsWriteFileEntryPatchToMemoryBuffer(RomFileSystemContext *ctx, RomFileSystemFileEntryPatch *patch, void *buf, u64 buf_size, u64 buf_offset)
|
||||||
{
|
{
|
||||||
if (!ctx || !ncaStorageIsValidContext(&(ctx->storage_ctx)) || ctx->nca_fs_ctx != ctx->storage_ctx.nca_fs_ctx || !patch || \
|
if (!ctx || ctx->is_patch || !ncaStorageIsValidContext(ctx->default_storage_ctx) || ctx->default_storage_ctx->base_storage_type != NcaStorageBaseStorageType_Regular || !patch || \
|
||||||
(!patch->use_old_format_patch && ctx->nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs) || \
|
(!patch->use_old_format_patch && ctx->default_storage_ctx->nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs) || \
|
||||||
(patch->use_old_format_patch && ctx->nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs)) return;
|
(patch->use_old_format_patch && ctx->default_storage_ctx->nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs)) return;
|
||||||
|
|
||||||
NcaContext *nca_ctx = (NcaContext*)ctx->nca_fs_ctx->nca_ctx;
|
NcaContext *nca_ctx = (NcaContext*)ctx->default_storage_ctx->nca_fs_ctx->nca_ctx;
|
||||||
|
|
||||||
if (patch->use_old_format_patch)
|
if (patch->use_old_format_patch)
|
||||||
{
|
{
|
||||||
|
|
|
@ -113,7 +113,7 @@ bool bfttfInitialize(void)
|
||||||
|
|
||||||
/* Initialize RomFS context. */
|
/* Initialize RomFS context. */
|
||||||
/* This will also free a previous RomFS context, if available. */
|
/* This will also free a previous RomFS context, if available. */
|
||||||
if (!romfsInitializeContext(&romfs_ctx, &(nca_ctx->fs_ctx[0])))
|
if (!romfsInitializeContext(&romfs_ctx, &(nca_ctx->fs_ctx[0]), NULL))
|
||||||
{
|
{
|
||||||
LOG_MSG("Failed to initialize RomFS context for Data NCA from %016lX!", font_info->title_id);
|
LOG_MSG("Failed to initialize RomFS context for Data NCA from %016lX!", font_info->title_id);
|
||||||
continue;
|
continue;
|
||||||
|
|
|
@ -439,7 +439,7 @@ static bool bktrReadIndirectStorage(BucketTreeVisitor *visitor, void *out, u64 r
|
||||||
if (cur_entry.storage_index == BucketTreeIndirectStorageIndex_Original)
|
if (cur_entry.storage_index == BucketTreeIndirectStorageIndex_Original)
|
||||||
{
|
{
|
||||||
/* Retrieve data from the original data storage. */
|
/* Retrieve data from the original data storage. */
|
||||||
/* This may either be a Regular/Compressed storage from the base NCA (Indirect) or a Regular storage from this very same NCA (Sparse). */
|
/* This may either be a Regular/Sparse/Compressed storage from the base NCA (Indirect) or a Regular storage from this very same NCA (Sparse). */
|
||||||
success = bktrReadSubStorage(&(ctx->substorages[0]), ¶ms);
|
success = bktrReadSubStorage(&(ctx->substorages[0]), ¶ms);
|
||||||
if (!success) LOG_MSG("Failed to read 0x%lX-byte long chunk from offset 0x%lX in original data storage!", read_size, data_offset);
|
if (!success) LOG_MSG("Failed to read 0x%lX-byte long chunk from offset 0x%lX in original data storage!", read_size, data_offset);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -42,7 +42,7 @@ bool legalInfoInitializeContext(LegalInfoContext *out, NcaContext *nca_ctx)
|
||||||
legalInfoFreeContext(out);
|
legalInfoFreeContext(out);
|
||||||
|
|
||||||
/* Initialize RomFS context. */
|
/* Initialize RomFS context. */
|
||||||
if (!romfsInitializeContext(&romfs_ctx, &(nca_ctx->fs_ctx[0])))
|
if (!romfsInitializeContext(&romfs_ctx, &(nca_ctx->fs_ctx[0]), NULL))
|
||||||
{
|
{
|
||||||
LOG_MSG("Failed to initialize RomFS context!");
|
LOG_MSG("Failed to initialize RomFS context!");
|
||||||
goto end;
|
goto end;
|
||||||
|
|
|
@ -248,7 +248,7 @@ bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx)
|
||||||
nacpFreeContext(out);
|
nacpFreeContext(out);
|
||||||
|
|
||||||
/* Initialize RomFS context. */
|
/* Initialize RomFS context. */
|
||||||
if (!romfsInitializeContext(&(out->romfs_ctx), &(nca_ctx->fs_ctx[0])))
|
if (!romfsInitializeContext(&(out->romfs_ctx), &(nca_ctx->fs_ctx[0]), NULL))
|
||||||
{
|
{
|
||||||
LOG_MSG("Failed to initialize RomFS context!");
|
LOG_MSG("Failed to initialize RomFS context!");
|
||||||
goto end;
|
goto end;
|
||||||
|
|
|
@ -209,7 +209,7 @@ bool ncaReadContentFile(NcaContext *ctx, void *out, u64 read_size, u64 offset)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ncaGetFsSectionHashTargetProperties(NcaFsSectionContext *ctx, u64 *out_offset, u64 *out_size)
|
bool ncaGetFsSectionHashTargetExtents(NcaFsSectionContext *ctx, u64 *out_offset, u64 *out_size)
|
||||||
{
|
{
|
||||||
if (!ctx || (!out_offset && !out_size))
|
if (!ctx || (!out_offset && !out_size))
|
||||||
{
|
{
|
||||||
|
@ -865,7 +865,7 @@ static bool ncaInitializeFsSectionContext(NcaContext *nca_ctx, u32 section_idx)
|
||||||
u64 raw_storage_size = compression_bucket->size;
|
u64 raw_storage_size = compression_bucket->size;
|
||||||
|
|
||||||
/* Get target hash layer offset. */
|
/* Get target hash layer offset. */
|
||||||
if (!ncaGetFsSectionHashTargetProperties(fs_ctx, &raw_storage_offset, NULL))
|
if (!ncaGetFsSectionHashTargetExtents(fs_ctx, &raw_storage_offset, NULL))
|
||||||
{
|
{
|
||||||
LOG_MSG("Invalid hash type for FS section #%u in \"%s\" (0x%02X). Skipping FS section.", fs_ctx->section_idx, nca_ctx->content_id_str, fs_ctx->hash_type);
|
LOG_MSG("Invalid hash type for FS section #%u in \"%s\" (0x%02X). Skipping FS section.", fs_ctx->section_idx, nca_ctx->content_id_str, fs_ctx->hash_type);
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -948,7 +948,7 @@ static bool ncaInitializeFsSectionContext(NcaContext *nca_ctx, u32 section_idx)
|
||||||
|
|
||||||
/* Get hash layer region size (offset must always be 0). */
|
/* Get hash layer region size (offset must always be 0). */
|
||||||
fs_ctx->hash_region.offset = 0;
|
fs_ctx->hash_region.offset = 0;
|
||||||
if (!ncaGetFsSectionHashTargetProperties(fs_ctx, &(fs_ctx->hash_region.size), NULL))
|
if (!ncaGetFsSectionHashTargetExtents(fs_ctx, &(fs_ctx->hash_region.size), NULL))
|
||||||
{
|
{
|
||||||
LOG_MSG("Invalid hash type for FS section #%u in \"%s\" (0x%02X). Skipping FS section.", fs_ctx->section_idx, nca_ctx->content_id_str, fs_ctx->hash_type);
|
LOG_MSG("Invalid hash type for FS section #%u in \"%s\" (0x%02X). Skipping FS section.", fs_ctx->section_idx, nca_ctx->content_id_str, fs_ctx->hash_type);
|
||||||
goto end;
|
goto end;
|
||||||
|
|
|
@ -127,7 +127,7 @@ bool ncaStorageSetPatchOriginalSubStorage(NcaStorageContext *patch_ctx, NcaStora
|
||||||
|
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
/* Set base storage. */
|
/* Set original substorage. */
|
||||||
switch(base_ctx->base_storage_type)
|
switch(base_ctx->base_storage_type)
|
||||||
{
|
{
|
||||||
case NcaStorageBaseStorageType_Regular:
|
case NcaStorageBaseStorageType_Regular:
|
||||||
|
@ -148,6 +148,62 @@ bool ncaStorageSetPatchOriginalSubStorage(NcaStorageContext *patch_ctx, NcaStora
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ncaStorageGetHashTargetExtents(NcaStorageContext *ctx, u64 *out_offset, u64 *out_size)
|
||||||
|
{
|
||||||
|
if (!ncaStorageIsValidContext(ctx) || (!out_offset && !out_size))
|
||||||
|
{
|
||||||
|
LOG_MSG("Invalid parameters!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 hash_target_offset = 0, hash_target_size = 0;
|
||||||
|
bool success = false;
|
||||||
|
|
||||||
|
/* Get hash target extents from the NCA FS section. */
|
||||||
|
if (!ncaGetFsSectionHashTargetExtents(ctx->nca_fs_ctx, &hash_target_offset, &hash_target_size))
|
||||||
|
{
|
||||||
|
LOG_MSG("Failed to retrieve NCA FS section's hash target extents!");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set proper hash target extents. */
|
||||||
|
switch(ctx->base_storage_type)
|
||||||
|
{
|
||||||
|
case NcaStorageBaseStorageType_Regular:
|
||||||
|
{
|
||||||
|
/* Just provide the NCA FS section hash target extents. */
|
||||||
|
if (out_offset) *out_offset = hash_target_offset;
|
||||||
|
if (out_size) *out_size = hash_target_size;
|
||||||
|
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:
|
||||||
|
{
|
||||||
|
/* Compressed sections already reference the hash target section, so there's no need calculate the full size. */
|
||||||
|
if (out_offset) *out_offset = 0;
|
||||||
|
if (out_size) *out_size = ctx->compressed_storage->end_offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update return value. */
|
||||||
|
success = true;
|
||||||
|
|
||||||
|
end:
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
bool ncaStorageRead(NcaStorageContext *ctx, void *out, u64 read_size, u64 offset)
|
bool ncaStorageRead(NcaStorageContext *ctx, void *out, u64 read_size, u64 offset)
|
||||||
{
|
{
|
||||||
if (!ncaStorageIsValidContext(ctx) || !out || !read_size)
|
if (!ncaStorageIsValidContext(ctx) || !out || !read_size)
|
||||||
|
|
|
@ -113,7 +113,7 @@ bool bfsarInitialize(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Initialize RomFS context. */
|
/* Initialize RomFS context. */
|
||||||
if (!romfsInitializeContext(&romfs_ctx, &(nca_ctx->fs_ctx[1])))
|
if (!romfsInitializeContext(&romfs_ctx, &(nca_ctx->fs_ctx[1]), NULL))
|
||||||
{
|
{
|
||||||
LOG_MSG("Failed to initialize RomFS context for qlaunch Program NCA!");
|
LOG_MSG("Failed to initialize RomFS context for qlaunch Program NCA!");
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -57,9 +57,9 @@ bool pfsInitializeContext(PartitionFileSystemContext *out, NcaFsSectionContext *
|
||||||
out->nca_fs_ctx = storage_ctx->nca_fs_ctx;
|
out->nca_fs_ctx = storage_ctx->nca_fs_ctx;
|
||||||
|
|
||||||
/* Get Partition FS offset and size. */
|
/* Get Partition FS offset and size. */
|
||||||
if (!ncaGetFsSectionHashTargetProperties(nca_fs_ctx, &(out->offset), &(out->size)))
|
if (!ncaStorageGetHashTargetExtents(storage_ctx, &(out->offset), &(out->size)))
|
||||||
{
|
{
|
||||||
LOG_MSG("Failed to get target hash layer properties!");
|
LOG_MSG("Failed to get target hash layer extents!");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,17 +27,19 @@
|
||||||
static RomFileSystemDirectoryEntry *romfsGetChildDirectoryEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name);
|
static RomFileSystemDirectoryEntry *romfsGetChildDirectoryEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name);
|
||||||
static RomFileSystemFileEntry *romfsGetChildFileEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name);
|
static RomFileSystemFileEntry *romfsGetChildFileEntryByName(RomFileSystemContext *ctx, RomFileSystemDirectoryEntry *dir_entry, const char *name);
|
||||||
|
|
||||||
bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_fs_ctx)
|
bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base_nca_fs_ctx, NcaFsSectionContext *patch_nca_fs_ctx)
|
||||||
{
|
{
|
||||||
NcaContext *nca_ctx = NULL;
|
|
||||||
u64 dir_table_offset = 0, file_table_offset = 0;
|
u64 dir_table_offset = 0, file_table_offset = 0;
|
||||||
bool success = false, dump_fs_header = false;
|
NcaContext *base_nca_ctx = NULL, *patch_nca_ctx = NULL;
|
||||||
|
bool dump_fs_header = false, is_patch = (patch_nca_fs_ctx != NULL), success = false;
|
||||||
|
|
||||||
if (!out || !nca_fs_ctx || !nca_fs_ctx->enabled || nca_fs_ctx->has_sparse_layer || !(nca_ctx = (NcaContext*)nca_fs_ctx->nca_ctx) || \
|
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) || \
|
||||||
(nca_ctx->format_version == NcaVersion_Nca0 && (nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs || nca_fs_ctx->hash_type != NcaHashType_HierarchicalSha256)) || \
|
(base_nca_ctx->format_version == NcaVersion_Nca0 && (base_nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs || \
|
||||||
(nca_ctx->format_version != NcaVersion_Nca0 && (nca_fs_ctx->section_type != NcaFsSectionType_RomFs || \
|
base_nca_fs_ctx->hash_type != NcaHashType_HierarchicalSha256)) || (base_nca_ctx->format_version != NcaVersion_Nca0 && \
|
||||||
(nca_fs_ctx->hash_type != NcaHashType_HierarchicalIntegrity && nca_fs_ctx->hash_type != NcaHashType_HierarchicalIntegritySha3))) || \
|
(base_nca_fs_ctx->section_type != NcaFsSectionType_RomFs || (base_nca_fs_ctx->hash_type != NcaHashType_HierarchicalIntegrity && \
|
||||||
(nca_ctx->rights_id_available && !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->section_type != NcaFsSectionType_PatchRomFs || (patch_nca_ctx->rights_id_available && !patch_nca_ctx->titlekey_retrieved))))
|
||||||
{
|
{
|
||||||
LOG_MSG("Invalid parameters!");
|
LOG_MSG("Invalid parameters!");
|
||||||
return false;
|
return false;
|
||||||
|
@ -46,32 +48,56 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_
|
||||||
/* Free output context beforehand. */
|
/* Free output context beforehand. */
|
||||||
romfsFreeContext(out);
|
romfsFreeContext(out);
|
||||||
|
|
||||||
/* Initialize NCA storage context. */
|
NcaStorageContext *base_storage_ctx = &(out->storage_ctx[0]), *patch_storage_ctx = &(out->storage_ctx[1]);
|
||||||
NcaStorageContext *storage_ctx = &(out->storage_ctx);
|
bool is_nca0_romfs = (base_nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs);
|
||||||
if (!ncaStorageInitializeContext(storage_ctx, nca_fs_ctx))
|
|
||||||
|
/* Initialize base NCA storage context. */
|
||||||
|
if (!ncaStorageInitializeContext(base_storage_ctx, base_nca_fs_ctx))
|
||||||
{
|
{
|
||||||
LOG_MSG("Failed to initialize NCA storage context!");
|
LOG_MSG("Failed to initialize base NCA storage context!");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
out->nca_fs_ctx = storage_ctx->nca_fs_ctx;
|
out->is_patch = is_patch;
|
||||||
|
|
||||||
|
if (is_patch)
|
||||||
|
{
|
||||||
|
/* Initialize base NCA storage context. */
|
||||||
|
if (!ncaStorageInitializeContext(patch_storage_ctx, patch_nca_fs_ctx))
|
||||||
|
{
|
||||||
|
LOG_MSG("Failed to initialize patch NCA storage context!");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set patch NCA storage original substorage. */
|
||||||
|
if (!ncaStorageSetPatchOriginalSubStorage(patch_storage_ctx, base_storage_ctx))
|
||||||
|
{
|
||||||
|
LOG_MSG("Failed to set patch NCA storage context's original substorage!");
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set default NCA FS storage context. */
|
||||||
|
out->default_storage_ctx = patch_storage_ctx;
|
||||||
|
} else {
|
||||||
|
/* Set default NCA FS storage context. */
|
||||||
|
out->default_storage_ctx = base_storage_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
/* Get RomFS offset and size. */
|
/* Get RomFS offset and size. */
|
||||||
if (!ncaGetFsSectionHashTargetProperties(nca_fs_ctx, &(out->offset), &(out->size)))
|
if (!ncaStorageGetHashTargetExtents(out->default_storage_ctx, &(out->offset), &(out->size)))
|
||||||
{
|
{
|
||||||
LOG_MSG("Failed to get target hash layer properties!");
|
LOG_MSG("Failed to get target hash layer extents!");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read RomFS header. */
|
/* Read RomFS header. */
|
||||||
if (!ncaStorageRead(storage_ctx, &(out->header), sizeof(RomFileSystemHeader), out->offset))
|
if (!ncaStorageRead(out->default_storage_ctx, &(out->header), sizeof(RomFileSystemHeader), out->offset))
|
||||||
{
|
{
|
||||||
LOG_MSG("Failed to read RomFS header!");
|
LOG_MSG("Failed to read RomFS header!");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs && out->header.old_format.header_size != ROMFS_OLD_HEADER_SIZE) || \
|
if ((is_nca0_romfs && out->header.old_format.header_size != ROMFS_OLD_HEADER_SIZE) || (!is_nca0_romfs && out->header.cur_format.header_size != ROMFS_HEADER_SIZE))
|
||||||
(nca_fs_ctx->section_type == NcaFsSectionType_RomFs && out->header.cur_format.header_size != ROMFS_HEADER_SIZE))
|
|
||||||
{
|
{
|
||||||
LOG_MSG("Invalid RomFS header size!");
|
LOG_MSG("Invalid RomFS header size!");
|
||||||
dump_fs_header = true;
|
dump_fs_header = true;
|
||||||
|
@ -79,8 +105,8 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read directory entries table. */
|
/* Read directory entries table. */
|
||||||
dir_table_offset = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.directory_entry_offset : out->header.cur_format.directory_entry_offset);
|
dir_table_offset = (is_nca0_romfs ? (u64)out->header.old_format.directory_entry_offset : out->header.cur_format.directory_entry_offset);
|
||||||
out->dir_table_size = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.directory_entry_size : out->header.cur_format.directory_entry_size);
|
out->dir_table_size = (is_nca0_romfs ? (u64)out->header.old_format.directory_entry_size : out->header.cur_format.directory_entry_size);
|
||||||
|
|
||||||
if (!out->dir_table_size || (dir_table_offset + out->dir_table_size) > out->size)
|
if (!out->dir_table_size || (dir_table_offset + out->dir_table_size) > out->size)
|
||||||
{
|
{
|
||||||
|
@ -96,15 +122,15 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ncaStorageRead(storage_ctx, out->dir_table, out->dir_table_size, out->offset + dir_table_offset))
|
if (!ncaStorageRead(out->default_storage_ctx, out->dir_table, out->dir_table_size, out->offset + dir_table_offset))
|
||||||
{
|
{
|
||||||
LOG_MSG("Failed to read RomFS directory entries table!");
|
LOG_MSG("Failed to read RomFS directory entries table!");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read file entries table. */
|
/* Read file entries table. */
|
||||||
file_table_offset = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.file_entry_offset : out->header.cur_format.file_entry_offset);
|
file_table_offset = (is_nca0_romfs ? (u64)out->header.old_format.file_entry_offset : out->header.cur_format.file_entry_offset);
|
||||||
out->file_table_size = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.file_entry_size : out->header.cur_format.file_entry_size);
|
out->file_table_size = (is_nca0_romfs ? (u64)out->header.old_format.file_entry_size : out->header.cur_format.file_entry_size);
|
||||||
|
|
||||||
if (!out->file_table_size || (file_table_offset + out->file_table_size) > out->size)
|
if (!out->file_table_size || (file_table_offset + out->file_table_size) > out->size)
|
||||||
{
|
{
|
||||||
|
@ -120,14 +146,14 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ncaStorageRead(storage_ctx, out->file_table, out->file_table_size, out->offset + file_table_offset))
|
if (!ncaStorageRead(out->default_storage_ctx, out->file_table, out->file_table_size, out->offset + file_table_offset))
|
||||||
{
|
{
|
||||||
LOG_MSG("Failed to read RomFS file entries table!");
|
LOG_MSG("Failed to read RomFS file entries table!");
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get file data body offset. */
|
/* Get file data body offset. */
|
||||||
out->body_offset = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.body_offset : out->header.cur_format.body_offset);
|
out->body_offset = (is_nca0_romfs ? (u64)out->header.old_format.body_offset : out->header.cur_format.body_offset);
|
||||||
if (out->body_offset >= out->size)
|
if (out->body_offset >= out->size)
|
||||||
{
|
{
|
||||||
LOG_MSG("Invalid RomFS file data body!");
|
LOG_MSG("Invalid RomFS file data body!");
|
||||||
|
@ -151,14 +177,14 @@ end:
|
||||||
|
|
||||||
bool romfsReadFileSystemData(RomFileSystemContext *ctx, void *out, u64 read_size, u64 offset)
|
bool romfsReadFileSystemData(RomFileSystemContext *ctx, void *out, u64 read_size, u64 offset)
|
||||||
{
|
{
|
||||||
if (!ctx || !ncaStorageIsValidContext(&(ctx->storage_ctx)) || !ctx->size || !out || !read_size || (offset + read_size) > ctx->size)
|
if (!ctx || !ncaStorageIsValidContext(ctx->default_storage_ctx) || !ctx->size || !out || !read_size || (offset + read_size) > ctx->size)
|
||||||
{
|
{
|
||||||
LOG_MSG("Invalid parameters!");
|
LOG_MSG("Invalid parameters!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read filesystem data. */
|
/* Read filesystem data. */
|
||||||
if (!ncaStorageRead(&(ctx->storage_ctx), out, read_size, ctx->offset + offset))
|
if (!ncaStorageRead(ctx->default_storage_ctx, out, read_size, ctx->offset + offset))
|
||||||
{
|
{
|
||||||
LOG_MSG("Failed to read RomFS data!");
|
LOG_MSG("Failed to read RomFS data!");
|
||||||
return false;
|
return false;
|
||||||
|
@ -314,8 +340,8 @@ RomFileSystemFileEntry *romfsGetFileEntryByPath(RomFileSystemContext *ctx, const
|
||||||
RomFileSystemDirectoryEntry *dir_entry = NULL;
|
RomFileSystemDirectoryEntry *dir_entry = NULL;
|
||||||
NcaContext *nca_ctx = NULL;
|
NcaContext *nca_ctx = NULL;
|
||||||
|
|
||||||
if (!ctx || !ctx->file_table || !ctx->file_table_size || !ncaStorageIsValidContext(&(ctx->storage_ctx)) || !(nca_ctx = (NcaContext*)ctx->nca_fs_ctx->nca_ctx) || \
|
if (!ctx || !ctx->file_table || !ctx->file_table_size || !ncaStorageIsValidContext(ctx->default_storage_ctx) || \
|
||||||
!path || *path != '/' || (path_len = strlen(path)) <= 1)
|
!(nca_ctx = (NcaContext*)ctx->default_storage_ctx->nca_fs_ctx->nca_ctx) || !path || *path != '/' || (path_len = strlen(path)) <= 1)
|
||||||
{
|
{
|
||||||
LOG_MSG("Invalid parameters!");
|
LOG_MSG("Invalid parameters!");
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -506,15 +532,15 @@ bool romfsGeneratePathFromFileEntry(RomFileSystemContext *ctx, RomFileSystemFile
|
||||||
|
|
||||||
bool romfsGenerateFileEntryPatch(RomFileSystemContext *ctx, RomFileSystemFileEntry *file_entry, const void *data, u64 data_size, u64 data_offset, RomFileSystemFileEntryPatch *out)
|
bool romfsGenerateFileEntryPatch(RomFileSystemContext *ctx, RomFileSystemFileEntry *file_entry, const void *data, u64 data_size, u64 data_offset, RomFileSystemFileEntryPatch *out)
|
||||||
{
|
{
|
||||||
if (!ctx || !ncaStorageIsValidContext(&(ctx->storage_ctx)) || ctx->storage_ctx.base_storage_type != NcaStorageBaseStorageType_Regular || !ctx->body_offset || \
|
if (!ctx || ctx->is_patch || !ncaStorageIsValidContext(ctx->default_storage_ctx) || ctx->default_storage_ctx->base_storage_type != NcaStorageBaseStorageType_Regular || \
|
||||||
(ctx->nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs && ctx->nca_fs_ctx->section_type != NcaFsSectionType_RomFs) || !file_entry || \
|
!ctx->body_offset || (ctx->default_storage_ctx->nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs && ctx->default_storage_ctx->nca_fs_ctx->section_type != NcaFsSectionType_RomFs) || \
|
||||||
!file_entry->size || (file_entry->offset + file_entry->size) > ctx->size || !data || !data_size || (data_offset + data_size) > file_entry->size || !out)
|
!file_entry || !file_entry->size || (file_entry->offset + file_entry->size) > ctx->size || !data || !data_size || (data_offset + data_size) > file_entry->size || !out)
|
||||||
{
|
{
|
||||||
LOG_MSG("Invalid parameters!");
|
LOG_MSG("Invalid parameters!");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
NcaFsSectionContext *nca_fs_ctx = ctx->nca_fs_ctx;
|
NcaFsSectionContext *nca_fs_ctx = ctx->default_storage_ctx->nca_fs_ctx;
|
||||||
u64 fs_offset = (ctx->body_offset + file_entry->offset + data_offset);
|
u64 fs_offset = (ctx->body_offset + file_entry->offset + data_offset);
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue