1
0
Fork 0
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:
Pablo Curiel 2020-10-25 20:03:02 -04:00
parent d777183d9f
commit da5290189b
3 changed files with 27 additions and 10 deletions

View file

@ -115,7 +115,7 @@ static void nspDump(TitleInfo *title_info)
pfsInitializeFileContext(&pfs_file_ctx);
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};
u8 sha256_hash[SHA256_HASH_SIZE] = {0};
@ -457,13 +457,14 @@ static void nspDump(TitleInfo *title_info)
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);
// write placeholder header
memset(buf, 0, nsp_header_size);
fwrite(buf, 1, nsp_header_size, fd);
nsp_offset += nsp_header_size;
// write ncas
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);
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);
@ -496,7 +497,7 @@ static void nspDump(TitleInfo *title_info)
if (dirty_header)
{
// 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)
{
@ -521,6 +522,9 @@ static void nspDump(TitleInfo *title_info)
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
@ -560,6 +564,7 @@ static void nspDump(TitleInfo *title_info)
// write cnmt xml
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
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
fwrite(icon_ctx->icon_data, 1, icon_ctx->icon_size, fd);
nsp_offset += icon_ctx->icon_size;
// update pfs entry name
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
fwrite(authoring_tool_xml, 1, authoring_tool_xml_size, fd);
nsp_offset += authoring_tool_xml_size;
// update pfs entry name
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
fwrite(tik.data, 1, tik.size, fd);
nsp_offset += tik.size;
// write cert
fwrite(raw_cert_chain, 1, raw_cert_chain_size, fd);
nsp_offset += raw_cert_chain_size;
}
// write new pfs0 header

View file

@ -436,23 +436,29 @@ bool ncaEncryptHeader(NcaContext *ctx)
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. */
if (!ctx || ctx->content_size < NCA_FULL_HEADER_LENGTH || !buf || !buf_size || (buf_offset + buf_size) > ctx->content_size || \
(ctx->format_version != NcaVersion_Nca0 && buf_offset >= NCA_FULL_HEADER_LENGTH)) return;
if (!ctx || ctx->header_written || ctx->content_size < NCA_FULL_HEADER_LENGTH || !buf || !buf_size || (buf_offset + buf_size) > ctx->content_size) return;
ctx->header_written = true;
/* Attempt to write the NCA header. */
/* 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. */
for(u8 i = 0; i < NCA_FS_HEADER_COUNT; 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);
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;
}
}

View file

@ -278,6 +278,7 @@ typedef struct {
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.
///< 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;
u64 section_offset;
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.
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.
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];
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.