mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2024-11-22 18:26:39 +00:00
Optimize modified NCA header(s) write code.
This commit is contained in:
parent
d777183d9f
commit
da5290189b
3 changed files with 27 additions and 10 deletions
|
@ -115,7 +115,7 @@ static void nspDump(TitleInfo *title_info)
|
||||||
pfsInitializeFileContext(&pfs_file_ctx);
|
pfsInitializeFileContext(&pfs_file_ctx);
|
||||||
|
|
||||||
char entry_name[64] = {0};
|
char entry_name[64] = {0};
|
||||||
u64 nsp_header_size = 0, nsp_size = 0;
|
u64 nsp_header_size = 0, nsp_size = 0, nsp_offset = 0;
|
||||||
|
|
||||||
Sha256Context sha256_ctx = {0};
|
Sha256Context sha256_ctx = {0};
|
||||||
u8 sha256_hash[SHA256_HASH_SIZE] = {0};
|
u8 sha256_hash[SHA256_HASH_SIZE] = {0};
|
||||||
|
@ -457,13 +457,14 @@ static void nspDump(TitleInfo *title_info)
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
consolePrint("dump process started. please wait... yes, i'm too lazy to print progress here...\n");
|
consolePrint("dump process started. please wait...\n");
|
||||||
|
|
||||||
time_t start = time(NULL);
|
time_t start = time(NULL);
|
||||||
|
|
||||||
// write placeholder header
|
// write placeholder header
|
||||||
memset(buf, 0, nsp_header_size);
|
memset(buf, 0, nsp_header_size);
|
||||||
fwrite(buf, 1, nsp_header_size, fd);
|
fwrite(buf, 1, nsp_header_size, fd);
|
||||||
|
nsp_offset += nsp_header_size;
|
||||||
|
|
||||||
// write ncas
|
// write ncas
|
||||||
for(u32 i = 0; i < title_info->content_count; i++)
|
for(u32 i = 0; i < title_info->content_count; i++)
|
||||||
|
@ -482,7 +483,7 @@ static void nspDump(TitleInfo *title_info)
|
||||||
|
|
||||||
bool dirty_header = ncaIsHeaderDirty(cur_nca_ctx);
|
bool dirty_header = ncaIsHeaderDirty(cur_nca_ctx);
|
||||||
|
|
||||||
for(u64 offset = 0; offset < cur_nca_ctx->content_size; offset += blksize)
|
for(u64 offset = 0; offset < cur_nca_ctx->content_size; offset += blksize, nsp_offset += blksize)
|
||||||
{
|
{
|
||||||
if ((cur_nca_ctx->content_size - offset) < blksize) blksize = (cur_nca_ctx->content_size - offset);
|
if ((cur_nca_ctx->content_size - offset) < blksize) blksize = (cur_nca_ctx->content_size - offset);
|
||||||
|
|
||||||
|
@ -496,7 +497,7 @@ static void nspDump(TitleInfo *title_info)
|
||||||
if (dirty_header)
|
if (dirty_header)
|
||||||
{
|
{
|
||||||
// write re-encrypted headers
|
// write re-encrypted headers
|
||||||
ncaWriteEncryptedHeaderDataToMemoryBuffer(cur_nca_ctx, buf, blksize, offset);
|
if (!cur_nca_ctx->header_written) ncaWriteEncryptedHeaderDataToMemoryBuffer(cur_nca_ctx, buf, blksize, offset);
|
||||||
|
|
||||||
if (cur_nca_ctx->content_type_ctx_patch)
|
if (cur_nca_ctx->content_type_ctx_patch)
|
||||||
{
|
{
|
||||||
|
@ -521,6 +522,9 @@ static void nspDump(TitleInfo *title_info)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// update flag to avoid entering this code block if it's not needed anymore
|
||||||
|
dirty_header = (!cur_nca_ctx->header_written || cur_nca_ctx->content_type_ctx_patch);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update hash calculation
|
// update hash calculation
|
||||||
|
@ -560,6 +564,7 @@ static void nspDump(TitleInfo *title_info)
|
||||||
|
|
||||||
// write cnmt xml
|
// write cnmt xml
|
||||||
fwrite(cnmt_ctx.authoring_tool_xml, 1, cnmt_ctx.authoring_tool_xml_size, fd);
|
fwrite(cnmt_ctx.authoring_tool_xml, 1, cnmt_ctx.authoring_tool_xml_size, fd);
|
||||||
|
nsp_offset += cnmt_ctx.authoring_tool_xml_size;
|
||||||
|
|
||||||
// update cnmt xml pfs entry name
|
// update cnmt xml pfs entry name
|
||||||
if (!pfsUpdateEntryNameFromFileContext(&pfs_file_ctx, meta_nca_ctx->content_type_ctx_data_idx, meta_nca_ctx->content_id_str))
|
if (!pfsUpdateEntryNameFromFileContext(&pfs_file_ctx, meta_nca_ctx->content_type_ctx_data_idx, meta_nca_ctx->content_id_str))
|
||||||
|
@ -600,6 +605,7 @@ static void nspDump(TitleInfo *title_info)
|
||||||
|
|
||||||
// write icon
|
// write icon
|
||||||
fwrite(icon_ctx->icon_data, 1, icon_ctx->icon_size, fd);
|
fwrite(icon_ctx->icon_data, 1, icon_ctx->icon_size, fd);
|
||||||
|
nsp_offset += icon_ctx->icon_size;
|
||||||
|
|
||||||
// update pfs entry name
|
// update pfs entry name
|
||||||
if (!pfsUpdateEntryNameFromFileContext(&pfs_file_ctx, data_idx++, cur_nca_ctx->content_id_str))
|
if (!pfsUpdateEntryNameFromFileContext(&pfs_file_ctx, data_idx++, cur_nca_ctx->content_id_str))
|
||||||
|
@ -624,6 +630,7 @@ static void nspDump(TitleInfo *title_info)
|
||||||
|
|
||||||
// write xml
|
// write xml
|
||||||
fwrite(authoring_tool_xml, 1, authoring_tool_xml_size, fd);
|
fwrite(authoring_tool_xml, 1, authoring_tool_xml_size, fd);
|
||||||
|
nsp_offset += authoring_tool_xml_size;
|
||||||
|
|
||||||
// update pfs entry name
|
// update pfs entry name
|
||||||
if (!pfsUpdateEntryNameFromFileContext(&pfs_file_ctx, data_idx, cur_nca_ctx->content_id_str))
|
if (!pfsUpdateEntryNameFromFileContext(&pfs_file_ctx, data_idx, cur_nca_ctx->content_id_str))
|
||||||
|
@ -637,9 +644,11 @@ static void nspDump(TitleInfo *title_info)
|
||||||
{
|
{
|
||||||
// write ticket
|
// write ticket
|
||||||
fwrite(tik.data, 1, tik.size, fd);
|
fwrite(tik.data, 1, tik.size, fd);
|
||||||
|
nsp_offset += tik.size;
|
||||||
|
|
||||||
// write cert
|
// write cert
|
||||||
fwrite(raw_cert_chain, 1, raw_cert_chain_size, fd);
|
fwrite(raw_cert_chain, 1, raw_cert_chain_size, fd);
|
||||||
|
nsp_offset += raw_cert_chain_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// write new pfs0 header
|
// write new pfs0 header
|
||||||
|
|
18
source/nca.c
18
source/nca.c
|
@ -436,23 +436,29 @@ bool ncaEncryptHeader(NcaContext *ctx)
|
||||||
|
|
||||||
void ncaWriteEncryptedHeaderDataToMemoryBuffer(NcaContext *ctx, void *buf, u64 buf_size, u64 buf_offset)
|
void ncaWriteEncryptedHeaderDataToMemoryBuffer(NcaContext *ctx, void *buf, u64 buf_size, u64 buf_offset)
|
||||||
{
|
{
|
||||||
/* Return right away if we're dealing with invalid parameters, or if the buffer data is not part of the range covered by the encrypted header data (NCA2/3 optimization, last condition). */
|
/* Return right away if we're dealing with invalid parameters. */
|
||||||
/* In order to avoid taking up too much execution time when this function is called (ideally inside a loop), we won't use ncaIsHeaderDirty() here. Let the user take care of it instead. */
|
/* In order to avoid taking up too much execution time when this function is called (ideally inside a loop), we won't use ncaIsHeaderDirty() here. Let the user take care of it instead. */
|
||||||
if (!ctx || ctx->content_size < NCA_FULL_HEADER_LENGTH || !buf || !buf_size || (buf_offset + buf_size) > ctx->content_size || \
|
if (!ctx || ctx->header_written || ctx->content_size < NCA_FULL_HEADER_LENGTH || !buf || !buf_size || (buf_offset + buf_size) > ctx->content_size) return;
|
||||||
(ctx->format_version != NcaVersion_Nca0 && buf_offset >= NCA_FULL_HEADER_LENGTH)) return;
|
|
||||||
|
ctx->header_written = true;
|
||||||
|
|
||||||
/* Attempt to write the NCA header. */
|
/* Attempt to write the NCA header. */
|
||||||
/* Return right away if the NCA header was only partially written. */
|
/* Return right away if the NCA header was only partially written. */
|
||||||
if (buf_offset < sizeof(NcaHeader) && !ncaWritePatchToMemoryBuffer(ctx, &(ctx->encrypted_header), sizeof(NcaHeader), 0, buf, buf_size, buf_offset)) return;
|
if (buf_offset < sizeof(NcaHeader) && !ncaWritePatchToMemoryBuffer(ctx, &(ctx->encrypted_header), sizeof(NcaHeader), 0, buf, buf_size, buf_offset))
|
||||||
|
{
|
||||||
|
ctx->header_written = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Attempt to write NCA FS section headers. */
|
/* Attempt to write NCA FS section headers. */
|
||||||
for(u8 i = 0; i < NCA_FS_HEADER_COUNT; i++)
|
for(u8 i = 0; i < NCA_FS_HEADER_COUNT; i++)
|
||||||
{
|
{
|
||||||
NcaFsSectionContext *fs_ctx = &(ctx->fs_ctx[i]);
|
NcaFsSectionContext *fs_ctx = &(ctx->fs_ctx[i]);
|
||||||
if (!fs_ctx->enabled) continue;
|
if (!fs_ctx->enabled || fs_ctx->header_written) continue;
|
||||||
|
|
||||||
u64 fs_header_offset = (ctx->format_version != NcaVersion_Nca0 ? (sizeof(NcaHeader) + (i * sizeof(NcaFsHeader))) : fs_ctx->section_offset);
|
u64 fs_header_offset = (ctx->format_version != NcaVersion_Nca0 ? (sizeof(NcaHeader) + (i * sizeof(NcaFsHeader))) : fs_ctx->section_offset);
|
||||||
ncaWritePatchToMemoryBuffer(ctx, &(fs_ctx->encrypted_header), sizeof(NcaFsHeader), fs_header_offset, buf, buf_size, buf_offset);
|
fs_ctx->header_written = ncaWritePatchToMemoryBuffer(ctx, &(fs_ctx->encrypted_header), sizeof(NcaFsHeader), fs_header_offset, buf, buf_size, buf_offset);
|
||||||
|
if (!fs_ctx->header_written) ctx->header_written = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -278,6 +278,7 @@ typedef struct {
|
||||||
NcaFsHeader header; ///< Plaintext NCA FS section header.
|
NcaFsHeader header; ///< Plaintext NCA FS section header.
|
||||||
NcaFsHeader encrypted_header; ///< Encrypted NCA FS section header. If the plaintext NCA FS section header is modified, this will hold an encrypted copy of it.
|
NcaFsHeader encrypted_header; ///< Encrypted NCA FS section header. If the plaintext NCA FS section header is modified, this will hold an encrypted copy of it.
|
||||||
///< Otherwise, this holds the unmodified, encrypted NCA FS section header.
|
///< Otherwise, this holds the unmodified, encrypted NCA FS section header.
|
||||||
|
bool header_written; ///< Set to true after this FS section header has been written to an output dump.
|
||||||
u8 section_num;
|
u8 section_num;
|
||||||
u64 section_offset;
|
u64 section_offset;
|
||||||
u64 section_size;
|
u64 section_size;
|
||||||
|
@ -322,6 +323,7 @@ typedef struct {
|
||||||
u8 header_hash[SHA256_HASH_SIZE]; ///< Plaintext NCA header hash. Used to determine if it's necessary to replace the NCA header while dumping this NCA.
|
u8 header_hash[SHA256_HASH_SIZE]; ///< Plaintext NCA header hash. Used to determine if it's necessary to replace the NCA header while dumping this NCA.
|
||||||
NcaHeader encrypted_header; ///< Encrypted NCA header. If the plaintext NCA header is modified, this will hold an encrypted copy of it.
|
NcaHeader encrypted_header; ///< Encrypted NCA header. If the plaintext NCA header is modified, this will hold an encrypted copy of it.
|
||||||
///< Otherwise, this holds the unmodified, encrypted NCA header.
|
///< Otherwise, this holds the unmodified, encrypted NCA header.
|
||||||
|
bool header_written; ///< Set to true after the NCA header and the FS section headers have been written to an output dump.
|
||||||
NcaFsSectionContext fs_ctx[NCA_FS_HEADER_COUNT];
|
NcaFsSectionContext fs_ctx[NCA_FS_HEADER_COUNT];
|
||||||
NcaDecryptedKeyArea decrypted_key_area;
|
NcaDecryptedKeyArea decrypted_key_area;
|
||||||
void *content_type_ctx; ///< Pointer to a content type context (e.g. ContentMetaContext, ProgramInfoContext, NacpContext, LegalInfoContext). Set to NULL if unused.
|
void *content_type_ctx; ///< Pointer to a content type context (e.g. ContentMetaContext, ProgramInfoContext, NacpContext, LegalInfoContext). Set to NULL if unused.
|
||||||
|
|
Loading…
Reference in a new issue