mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2025-01-24 18:23:14 -03:00
New logfile handler.
* Ported the logfile handler from libusbhsfs, with some slight modifications. * Rewrote hash file system handling from scratch. I had been wanting to do this for some months now, it's a lot better now. * Code cleanup.
This commit is contained in:
parent
bcc688061e
commit
3bc14696ec
31 changed files with 1970 additions and 1326 deletions
|
@ -24,7 +24,7 @@ size_t aes128XtsNintendoCrypt(Aes128XtsContext *ctx, void *dst, const void *src,
|
|||
{
|
||||
if (!ctx || !dst || !src || !size || !sector_size || (size % sector_size) != 0)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ bool bfttfInitialize(void)
|
|||
nca_ctx = calloc(1, sizeof(NcaContext));
|
||||
if (!nca_ctx)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for temporary NCA context!");
|
||||
LOG_MSG("Failed to allocate memory for temporary NCA context!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -91,21 +91,21 @@ bool bfttfInitialize(void)
|
|||
/* Get title info. */
|
||||
if (!(title_info = titleGetInfoFromStorageByTitleId(NcmStorageId_BuiltInSystem, font_info->title_id)))
|
||||
{
|
||||
LOGFILE("Failed to get title info for %016lX!", font_info->title_id);
|
||||
LOG_MSG("Failed to get title info for %016lX!", font_info->title_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Initialize NCA context. */
|
||||
if (!ncaInitializeContext(nca_ctx, NcmStorageId_BuiltInSystem, 0, titleGetContentInfoByTypeAndIdOffset(title_info, NcmContentType_Data, 0), NULL))
|
||||
{
|
||||
LOGFILE("Failed to initialize Data NCA context for %016lX!", font_info->title_id);
|
||||
LOG_MSG("Failed to initialize Data NCA context for %016lX!", font_info->title_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Initialize RomFS context. */
|
||||
if (!romfsInitializeContext(&romfs_ctx, &(nca_ctx->fs_ctx[0])))
|
||||
{
|
||||
LOGFILE("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;
|
||||
}
|
||||
|
||||
|
@ -116,28 +116,28 @@ bool bfttfInitialize(void)
|
|||
/* Get RomFS file entry. */
|
||||
if (!(romfs_file_entry = romfsGetFileEntryByPath(&romfs_ctx, font_info->path)))
|
||||
{
|
||||
LOGFILE("Failed to retrieve RomFS file entry in %016lX!", font_info->title_id);
|
||||
LOG_MSG("Failed to retrieve RomFS file entry in %016lX!", font_info->title_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check file size. */
|
||||
if (!romfs_file_entry->size)
|
||||
{
|
||||
LOGFILE("Invalid file size for \"%s\" in %016lX!", font_info->path, font_info->title_id);
|
||||
LOG_MSG("File size for \"%s\" in %016lX is zero!", font_info->path, font_info->title_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Allocate memory for BFTTF data. */
|
||||
if (!(font_info->data = malloc(romfs_file_entry->size)))
|
||||
{
|
||||
LOGFILE("Failed to allocate 0x%lX bytes for \"%s\" in %016lX!", romfs_file_entry->size, font_info->path, font_info->title_id);
|
||||
LOG_MSG("Failed to allocate 0x%lX bytes for \"%s\" in %016lX!", romfs_file_entry->size, font_info->path, font_info->title_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Read BFTFF data. */
|
||||
if (!romfsReadFileEntryData(&romfs_ctx, romfs_file_entry, font_info->data, romfs_file_entry->size, 0))
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes long \"%s\" in %016lX!", romfs_file_entry->size, font_info->path, font_info->title_id);
|
||||
LOG_MSG("Failed to read 0x%lX bytes long \"%s\" in %016lX!", romfs_file_entry->size, font_info->path, font_info->title_id);
|
||||
free(font_info->data);
|
||||
font_info->data = NULL;
|
||||
continue;
|
||||
|
@ -149,7 +149,7 @@ bool bfttfInitialize(void)
|
|||
/* Decode BFTTF data. */
|
||||
if (!bfttfDecodeFont(font_info))
|
||||
{
|
||||
LOGFILE("Failed to decode 0x%lX bytes long \"%s\" in %016lX!", romfs_file_entry->size, font_info->path, font_info->title_id);
|
||||
LOG_MSG("Failed to decode 0x%lX bytes long \"%s\" in %016lX!", romfs_file_entry->size, font_info->path, font_info->title_id);
|
||||
free(font_info->data);
|
||||
font_info->data = NULL;
|
||||
font_info->size = 0;
|
||||
|
@ -161,7 +161,7 @@ bool bfttfInitialize(void)
|
|||
}
|
||||
|
||||
ret = g_bfttfInterfaceInit = (count > 0);
|
||||
if (!ret) LOGFILE("No BFTTF fonts retrieved!");
|
||||
if (!ret) LOG_MSG("No BFTTF fonts retrieved!");
|
||||
|
||||
end:
|
||||
romfsFreeContext(&romfs_ctx);
|
||||
|
@ -194,14 +194,14 @@ bool bfttfGetFontByType(BfttfFontData *font_data, u8 font_type)
|
|||
{
|
||||
if (!font_data || font_type >= BfttfFontType_Total)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
BfttfFontInfo *font_info = &(g_fontInfo[font_type]);
|
||||
if (font_info->size <= 8 || !font_info->data)
|
||||
{
|
||||
LOGFILE("BFTTF font data unavailable for type 0x%02X!", font_type);
|
||||
LOG_MSG("BFTTF font data unavailable for type 0x%02X!", font_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -216,11 +216,11 @@ static bool bfttfDecodeFont(BfttfFontInfo *font_info)
|
|||
{
|
||||
if (!font_info || font_info->size <= 8 || !IS_ALIGNED(font_info->size, 4) || !font_info->data)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
for(u32 i = 8; i < (font_info->size - 8); i += 4)
|
||||
for(u32 i = 8; i < font_info->size; i += 4)
|
||||
{
|
||||
u32 *ptr = (u32*)(font_info->data + i);
|
||||
*ptr = (*ptr ^ g_bfttfKey);
|
||||
|
|
|
@ -47,7 +47,7 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
|||
(update_nca_fs_ctx->header.patch_info.aes_ctr_ex_bucket.offset + update_nca_fs_ctx->header.patch_info.aes_ctr_ex_bucket.size) != update_nca_fs_ctx->section_size || \
|
||||
(base_nca_ctx->rights_id_available && !base_nca_ctx->titlekey_retrieved) || (update_nca_ctx->rights_id_available && !update_nca_ctx->titlekey_retrieved))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -60,26 +60,26 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
|||
/* Initialize base NCA RomFS context. */
|
||||
if (!out->missing_base_romfs && !romfsInitializeContext(&(out->base_romfs_ctx), base_nca_fs_ctx))
|
||||
{
|
||||
LOGFILE("Failed to initialize base NCA RomFS context!");
|
||||
LOG_MSG("Failed to initialize base NCA RomFS context!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Fill context. */
|
||||
bool success = false;
|
||||
bool success = false, dump_patch_romfs_header = false;
|
||||
NcaPatchInfo *patch_info = &(update_nca_fs_ctx->header.patch_info);
|
||||
|
||||
/* Allocate space for an extra (fake) indirect storage entry, to simplify our logic. */
|
||||
out->indirect_block = calloc(1, patch_info->indirect_bucket.size + ((0x3FF0 / sizeof(u64)) * sizeof(BktrIndirectStorageEntry)));
|
||||
if (!out->indirect_block)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the BKTR Indirect Storage Block!");
|
||||
LOG_MSG("Unable to allocate memory for the BKTR Indirect Storage Block!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read indirect storage block data. */
|
||||
if (!ncaReadFsSection(update_nca_fs_ctx, out->indirect_block, patch_info->indirect_bucket.size, patch_info->indirect_bucket.offset))
|
||||
{
|
||||
LOGFILE("Failed to read BKTR Indirect Storage Block data!");
|
||||
LOG_MSG("Failed to read BKTR Indirect Storage Block data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -87,20 +87,20 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
|||
out->aes_ctr_ex_block = calloc(1, patch_info->aes_ctr_ex_bucket.size + (((0x3FF0 / sizeof(u64)) + 1) * sizeof(BktrAesCtrExStorageEntry)));
|
||||
if (!out->aes_ctr_ex_block)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the BKTR AesCtrEx Storage Block!");
|
||||
LOG_MSG("Unable to allocate memory for the BKTR AesCtrEx Storage Block!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read AesCtrEx storage block data. */
|
||||
if (!ncaReadFsSection(update_nca_fs_ctx, out->aes_ctr_ex_block, patch_info->aes_ctr_ex_bucket.size, patch_info->aes_ctr_ex_bucket.offset))
|
||||
{
|
||||
LOGFILE("Failed to read BKTR AesCtrEx Storage Block data!");
|
||||
LOG_MSG("Failed to read BKTR AesCtrEx Storage Block data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->aes_ctr_ex_block->physical_size != patch_info->aes_ctr_ex_bucket.offset)
|
||||
{
|
||||
LOGFILE("Invalid BKTR AesCtrEx Storage Block size!");
|
||||
LOG_DATA(out->aes_ctr_ex_block, patch_info->aes_ctr_ex_bucket.size, "Invalid BKTR AesCtrEx Storage Block size! AesCtrEx Storage Block dump:");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -150,13 +150,14 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
|||
/* Read update NCA RomFS header. */
|
||||
if (!bktrPhysicalSectionRead(out, &(out->patch_romfs_ctx.header), sizeof(RomFileSystemHeader), out->patch_romfs_ctx.offset))
|
||||
{
|
||||
LOGFILE("Failed to read update NCA RomFS header!");
|
||||
LOG_MSG("Failed to read update NCA RomFS header!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->patch_romfs_ctx.header.cur_format.header_size != ROMFS_HEADER_SIZE)
|
||||
{
|
||||
LOGFILE("Invalid update NCA RomFS header size!");
|
||||
LOG_MSG("Invalid update NCA RomFS header size!");
|
||||
dump_patch_romfs_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -166,20 +167,21 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
|||
|
||||
if (!dir_table_offset || !out->patch_romfs_ctx.dir_table_size)
|
||||
{
|
||||
LOGFILE("Invalid update NCA RomFS directory entries table!");
|
||||
LOG_MSG("Invalid update NCA RomFS directory entries table!");
|
||||
dump_patch_romfs_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
out->patch_romfs_ctx.dir_table = malloc(out->patch_romfs_ctx.dir_table_size);
|
||||
if (!out->patch_romfs_ctx.dir_table)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the update NCA RomFS directory entries table!");
|
||||
LOG_MSG("Unable to allocate memory for the update NCA RomFS directory entries table!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!bktrPhysicalSectionRead(out, out->patch_romfs_ctx.dir_table, out->patch_romfs_ctx.dir_table_size, out->patch_romfs_ctx.offset + dir_table_offset))
|
||||
{
|
||||
LOGFILE("Failed to read update NCA RomFS directory entries table!");
|
||||
LOG_MSG("Failed to read update NCA RomFS directory entries table!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -189,20 +191,21 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
|||
|
||||
if (!file_table_offset || !out->patch_romfs_ctx.file_table_size)
|
||||
{
|
||||
LOGFILE("Invalid update NCA RomFS file entries table!");
|
||||
LOG_MSG("Invalid update NCA RomFS file entries table!");
|
||||
dump_patch_romfs_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
out->patch_romfs_ctx.file_table = malloc(out->patch_romfs_ctx.file_table_size);
|
||||
if (!out->patch_romfs_ctx.file_table)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the update NCA RomFS file entries table!");
|
||||
LOG_MSG("Unable to allocate memory for the update NCA RomFS file entries table!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!bktrPhysicalSectionRead(out, out->patch_romfs_ctx.file_table, out->patch_romfs_ctx.file_table_size, out->patch_romfs_ctx.offset + file_table_offset))
|
||||
{
|
||||
LOGFILE("Failed to read update NCA RomFS file entries table!");
|
||||
LOG_MSG("Failed to read update NCA RomFS file entries table!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -212,7 +215,12 @@ bool bktrInitializeContext(BktrContext *out, NcaFsSectionContext *base_nca_fs_ct
|
|||
success = true;
|
||||
|
||||
end:
|
||||
if (!success) bktrFreeContext(out);
|
||||
if (!success)
|
||||
{
|
||||
if (dump_patch_romfs_header) LOG_DATA(&(out->patch_romfs_ctx.header), sizeof(RomFileSystemHeader), "Update RomFS header dump:");
|
||||
|
||||
bktrFreeContext(out);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
@ -221,14 +229,14 @@ bool bktrReadFileSystemData(BktrContext *ctx, void *out, u64 read_size, u64 offs
|
|||
{
|
||||
if (!ctx || !ctx->size || !out || !read_size || (offset + read_size) > ctx->size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read filesystem data. */
|
||||
if (!bktrPhysicalSectionRead(ctx, out, read_size, ctx->offset + offset))
|
||||
{
|
||||
LOGFILE("Failed to read Patch RomFS data!");
|
||||
LOG_MSG("Failed to read Patch RomFS data!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -239,14 +247,14 @@ bool bktrReadFileEntryData(BktrContext *ctx, RomFileSystemFileEntry *file_entry,
|
|||
{
|
||||
if (!ctx || !ctx->body_offset || !file_entry || !file_entry->size || (file_entry->offset + file_entry->size) > ctx->size || !out || !read_size || (offset + read_size) > file_entry->size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read entry data. */
|
||||
if (!bktrReadFileSystemData(ctx, out, read_size, ctx->body_offset + file_entry->offset + offset))
|
||||
{
|
||||
LOGFILE("Failed to read Patch RomFS file entry data!");
|
||||
LOG_MSG("Failed to read Patch RomFS file entry data!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -257,7 +265,7 @@ bool bktrIsFileEntryUpdated(BktrContext *ctx, RomFileSystemFileEntry *file_entry
|
|||
{
|
||||
if (!ctx || !ctx->body_offset || !ctx->indirect_block || !file_entry || !file_entry->size || (file_entry->offset + file_entry->size) > ctx->size || !out)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -268,7 +276,7 @@ bool bktrIsFileEntryUpdated(BktrContext *ctx, RomFileSystemFileEntry *file_entry
|
|||
indirect_entry = bktrGetIndirectStorageEntry(ctx->indirect_block, file_offset);
|
||||
if (!indirect_entry)
|
||||
{
|
||||
LOGFILE("Error retrieving BKTR Indirect Storage Entry at offset 0x%lX!", file_offset);
|
||||
LOG_MSG("Error retrieving BKTR Indirect Storage Entry at offset 0x%lX!", file_offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -295,7 +303,7 @@ static bool bktrPhysicalSectionRead(BktrContext *ctx, void *out, u64 read_size,
|
|||
{
|
||||
if (!ctx || (!ctx->missing_base_romfs && !ctx->base_romfs_ctx.nca_fs_ctx) || !ctx->indirect_block || !out || !read_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -307,7 +315,7 @@ static bool bktrPhysicalSectionRead(BktrContext *ctx, void *out, u64 read_size,
|
|||
indirect_entry = bktrGetIndirectStorageEntry(ctx->indirect_block, offset);
|
||||
if (!indirect_entry)
|
||||
{
|
||||
LOGFILE("Error retrieving BKTR Indirect Storage Entry at offset 0x%lX!", offset);
|
||||
LOG_MSG("Error retrieving BKTR Indirect Storage Entry at offset 0x%lX!", offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -323,14 +331,14 @@ static bool bktrPhysicalSectionRead(BktrContext *ctx, void *out, u64 read_size,
|
|||
if (indirect_entry->indirect_storage_index == BktrIndirectStorageIndex_Patch)
|
||||
{
|
||||
success = bktrAesCtrExStorageRead(ctx, out, read_size, offset, section_offset);
|
||||
if (!success) LOGFILE("Failed to read 0x%lX bytes block from BKTR AesCtrEx storage at offset 0x%lX!", read_size, section_offset);
|
||||
if (!success) LOG_MSG("Failed to read 0x%lX bytes block from BKTR AesCtrEx storage at offset 0x%lX!", read_size, section_offset);
|
||||
} else
|
||||
if (!ctx->missing_base_romfs)
|
||||
{
|
||||
success = ncaReadFsSection(ctx->base_romfs_ctx.nca_fs_ctx, out, read_size, section_offset);
|
||||
if (!success) LOGFILE("Failed to read 0x%lX bytes block from base RomFS at offset 0x%lX!", read_size, section_offset);
|
||||
if (!success) LOG_MSG("Failed to read 0x%lX bytes block from base RomFS at offset 0x%lX!", read_size, section_offset);
|
||||
} else {
|
||||
LOGFILE("Attempting to read 0x%lX bytes block from non-existent base RomFS at offset 0x%lX!", read_size, section_offset);
|
||||
LOG_MSG("Attempting to read 0x%lX bytes block from non-existent base RomFS at offset 0x%lX!", read_size, section_offset);
|
||||
}
|
||||
} else {
|
||||
/* Handle reads that span multiple indirect storage entries. */
|
||||
|
@ -338,7 +346,7 @@ static bool bktrPhysicalSectionRead(BktrContext *ctx, void *out, u64 read_size,
|
|||
|
||||
success = (bktrPhysicalSectionRead(ctx, out, indirect_block_size, offset) && \
|
||||
bktrPhysicalSectionRead(ctx, (u8*)out + indirect_block_size, read_size - indirect_block_size, offset + indirect_block_size));
|
||||
if (!success) LOGFILE("Failed to read 0x%lX bytes block from multiple BKTR indirect storage entries at offset 0x%lX!", read_size, section_offset);
|
||||
if (!success) LOG_MSG("Failed to read 0x%lX bytes block from multiple BKTR indirect storage entries at offset 0x%lX!", read_size, section_offset);
|
||||
}
|
||||
|
||||
return success;
|
||||
|
@ -350,14 +358,14 @@ static bool bktrAesCtrExStorageRead(BktrContext *ctx, void *out, u64 read_size,
|
|||
|
||||
if (!ctx || !ctx->patch_romfs_ctx.nca_fs_ctx || !ctx->aes_ctr_ex_block || !out || !read_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
aes_ctr_ex_entry = bktrGetAesCtrExStorageEntry(ctx->aes_ctr_ex_block, section_offset);
|
||||
if (!aes_ctr_ex_entry)
|
||||
{
|
||||
LOGFILE("Error retrieving BKTR AesCtrEx Storage Entry at offset 0x%lX!", section_offset);
|
||||
LOG_MSG("Error retrieving BKTR AesCtrEx Storage Entry at offset 0x%lX!", section_offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -390,7 +398,7 @@ static BktrIndirectStorageEntry *bktrGetIndirectStorageEntry(BktrIndirectStorage
|
|||
{
|
||||
if (!block || !block->bucket_count || offset >= block->virtual_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -405,7 +413,7 @@ static BktrIndirectStorageEntry *bktrGetIndirectStorageEntry(BktrIndirectStorage
|
|||
bucket = bktrGetIndirectStorageBucket(block, bucket_num);
|
||||
if (!bucket || !bucket->entry_count)
|
||||
{
|
||||
LOGFILE("Error retrieving BKTR indirect storage bucket #%u!", bucket_num);
|
||||
LOG_MSG("Error retrieving BKTR indirect storage bucket #%u!", bucket_num);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -429,7 +437,7 @@ static BktrIndirectStorageEntry *bktrGetIndirectStorageEntry(BktrIndirectStorage
|
|||
}
|
||||
}
|
||||
|
||||
LOGFILE("Failed to find offset 0x%lX in BKTR indirect storage block!", offset);
|
||||
LOG_MSG("Failed to find offset 0x%lX in BKTR indirect storage block!", offset);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -443,7 +451,7 @@ static BktrAesCtrExStorageEntry *bktrGetAesCtrExStorageEntry(BktrAesCtrExStorage
|
|||
{
|
||||
if (!block || !block->bucket_count || offset >= block->physical_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -453,7 +461,7 @@ static BktrAesCtrExStorageEntry *bktrGetAesCtrExStorageEntry(BktrAesCtrExStorage
|
|||
last_bucket = bktrGetAesCtrExStorageBucket(block, block->bucket_count - 1);
|
||||
if (!last_bucket || !last_bucket->entry_count)
|
||||
{
|
||||
LOGFILE("Error retrieving last BKTR AesCtrEx storage bucket!");
|
||||
LOG_MSG("Error retrieving last BKTR AesCtrEx storage bucket!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -467,7 +475,7 @@ static BktrAesCtrExStorageEntry *bktrGetAesCtrExStorageEntry(BktrAesCtrExStorage
|
|||
bucket = bktrGetAesCtrExStorageBucket(block, bucket_num);
|
||||
if (!bucket || !bucket->entry_count)
|
||||
{
|
||||
LOGFILE("Error retrieving BKTR AesCtrEx storage bucket #%u!", bucket_num);
|
||||
LOG_MSG("Error retrieving BKTR AesCtrEx storage bucket #%u!", bucket_num);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -491,6 +499,6 @@ static BktrAesCtrExStorageEntry *bktrGetAesCtrExStorageEntry(BktrAesCtrExStorage
|
|||
}
|
||||
}
|
||||
|
||||
LOGFILE("Failed to find offset 0x%lX in BKTR AesCtrEx storage block!", offset);
|
||||
LOG_MSG("Failed to find offset 0x%lX in BKTR AesCtrEx storage block!", offset);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ bool certRetrieveCertificateByName(Certificate *dst, const char *name)
|
|||
|
||||
if (!dst || !name || !*name)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -77,11 +77,10 @@ bool certRetrieveCertificateChainBySignatureIssuer(CertificateChain *dst, const
|
|||
mutexLock(&g_esCertSaveMutex);
|
||||
|
||||
bool ret = false;
|
||||
size_t issuer_len = 0;
|
||||
|
||||
if (!dst || !issuer || (issuer_len = strlen(issuer)) <= 5 || strncmp(issuer, "Root-", 5) != 0)
|
||||
if (!dst || !issuer || strncmp(issuer, "Root-", 5) != 0)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -101,7 +100,7 @@ u8 *certGenerateRawCertificateChainBySignatureIssuer(const char *issuer, u64 *ou
|
|||
{
|
||||
if (!issuer || !*issuer || !out_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -111,7 +110,7 @@ u8 *certGenerateRawCertificateChainBySignatureIssuer(const char *issuer, u64 *ou
|
|||
|
||||
if (!certRetrieveCertificateChainBySignatureIssuer(&chain, issuer))
|
||||
{
|
||||
LOGFILE("Error retrieving certificate chain for \"%s\"!", issuer);
|
||||
LOG_MSG("Error retrieving certificate chain for \"%s\"!", issuer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -120,7 +119,7 @@ u8 *certGenerateRawCertificateChainBySignatureIssuer(const char *issuer, u64 *ou
|
|||
raw_chain = malloc(raw_chain_size);
|
||||
if (!raw_chain)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for raw \"%s\" certificate chain! (0x%lX).", issuer, raw_chain_size);
|
||||
LOG_MSG("Unable to allocate memory for raw \"%s\" certificate chain! (0x%lX).", issuer, raw_chain_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -137,7 +136,7 @@ u8 *certRetrieveRawCertificateChainFromGameCardByRightsId(const FsRightsId *id,
|
|||
{
|
||||
if (!id || !out_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -149,28 +148,28 @@ u8 *certRetrieveRawCertificateChainFromGameCardByRightsId(const FsRightsId *id,
|
|||
utilsGenerateHexStringFromData(raw_chain_filename, sizeof(raw_chain_filename), id->c, 0x10);
|
||||
strcat(raw_chain_filename, ".cert");
|
||||
|
||||
if (!gamecardGetEntryInfoFromHashFileSystemPartitionByName(GameCardHashFileSystemPartitionType_Secure, raw_chain_filename, &raw_chain_offset, &raw_chain_size))
|
||||
if (!gamecardGetHashFileSystemEntryInfoByName(GameCardHashFileSystemPartitionType_Secure, raw_chain_filename, &raw_chain_offset, &raw_chain_size))
|
||||
{
|
||||
LOGFILE("Error retrieving offset and size for \"%s\" entry in secure hash FS partition!", raw_chain_filename);
|
||||
LOG_MSG("Error retrieving offset and size for \"%s\" entry in secure hash FS partition!", raw_chain_filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (raw_chain_size < SIGNED_CERT_MIN_SIZE)
|
||||
{
|
||||
LOGFILE("Invalid size for \"%s\"! (0x%lX).", raw_chain_filename, raw_chain_size);
|
||||
LOG_MSG("Invalid size for \"%s\"! (0x%lX).", raw_chain_filename, raw_chain_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
raw_chain = malloc(raw_chain_size);
|
||||
if (!raw_chain)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for raw \"%s\" certificate chain! (0x%lX).", raw_chain_size);
|
||||
LOG_MSG("Unable to allocate memory for raw \"%s\" certificate chain! (0x%lX).", raw_chain_size);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!gamecardReadStorage(raw_chain, raw_chain_size, raw_chain_offset))
|
||||
{
|
||||
LOGFILE("Failed to read \"%s\" data from the inserted gamecard!", raw_chain_filename);
|
||||
LOG_MSG("Failed to read \"%s\" data from the inserted gamecard!", raw_chain_filename);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -194,7 +193,7 @@ static bool certOpenEsCertSaveFile(void)
|
|||
g_esCertSaveCtx = save_open_savefile(CERT_SAVEFILE_PATH, 0);
|
||||
if (!g_esCertSaveCtx)
|
||||
{
|
||||
LOGFILE("Failed to open ES certificate system savefile!");
|
||||
LOG_MSG("Failed to open ES certificate system savefile!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -212,7 +211,7 @@ static bool _certRetrieveCertificateByName(Certificate *dst, const char *name)
|
|||
{
|
||||
if (!g_esCertSaveCtx)
|
||||
{
|
||||
LOGFILE("ES certificate savefile not opened!");
|
||||
LOG_MSG("ES certificate savefile not opened!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -224,13 +223,13 @@ static bool _certRetrieveCertificateByName(Certificate *dst, const char *name)
|
|||
|
||||
if (!save_get_fat_storage_from_file_entry_by_path(g_esCertSaveCtx, cert_path, &fat_storage, &cert_size))
|
||||
{
|
||||
LOGFILE("Failed to locate certificate \"%s\" in ES certificate system save!", name);
|
||||
LOG_MSG("Failed to locate certificate \"%s\" in ES certificate system save!", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cert_size < SIGNED_CERT_MIN_SIZE || cert_size > SIGNED_CERT_MAX_SIZE)
|
||||
{
|
||||
LOGFILE("Invalid size for certificate \"%s\"! (0x%lX).", name, cert_size);
|
||||
LOG_MSG("Invalid size for certificate \"%s\"! (0x%lX).", name, cert_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -239,14 +238,14 @@ static bool _certRetrieveCertificateByName(Certificate *dst, const char *name)
|
|||
u64 br = save_allocation_table_storage_read(&fat_storage, dst->data, 0, dst->size);
|
||||
if (br != dst->size)
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes from certificate \"%s\"! Read 0x%lX bytes.", dst->size, name, br);
|
||||
LOG_MSG("Failed to read 0x%lX bytes from certificate \"%s\"! Read 0x%lX bytes.", dst->size, name, br);
|
||||
return false;
|
||||
}
|
||||
|
||||
dst->type = certGetCertificateType(dst->data, dst->size);
|
||||
if (dst->type == CertType_None)
|
||||
{
|
||||
LOGFILE("Invalid certificate type for \"%s\"!", name);
|
||||
LOG_MSG("Invalid certificate type for \"%s\"!", name);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -262,13 +261,13 @@ static u8 certGetCertificateType(void *data, u64 data_size)
|
|||
|
||||
if (!data || data_size < SIGNED_CERT_MIN_SIZE || data_size > SIGNED_CERT_MAX_SIZE)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return type;
|
||||
}
|
||||
|
||||
if (!(cert_common_block = certGetCommonBlock(data)) || !(signed_cert_size = certGetSignedCertificateSize(data)) || signed_cert_size > data_size)
|
||||
{
|
||||
LOGFILE("Input buffer doesn't hold a valid signed certificate!");
|
||||
LOG_MSG("Input buffer doesn't hold a valid signed certificate!");
|
||||
return type;
|
||||
}
|
||||
|
||||
|
@ -303,7 +302,7 @@ static bool _certRetrieveCertificateChainBySignatureIssuer(CertificateChain *dst
|
|||
{
|
||||
if (!g_esCertSaveCtx)
|
||||
{
|
||||
LOGFILE("ES certificate savefile not opened!");
|
||||
LOG_MSG("ES certificate savefile not opened!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -314,14 +313,14 @@ static bool _certRetrieveCertificateChainBySignatureIssuer(CertificateChain *dst
|
|||
dst->count = certGetCertificateCountInSignatureIssuer(issuer);
|
||||
if (!dst->count)
|
||||
{
|
||||
LOGFILE("Invalid signature issuer string!");
|
||||
LOG_MSG("Invalid signature issuer string!");
|
||||
return false;
|
||||
}
|
||||
|
||||
dst->certs = calloc(dst->count, sizeof(Certificate));
|
||||
if (!dst->certs)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the certificate chain! (0x%lX).", dst->count * sizeof(Certificate));
|
||||
LOG_MSG("Unable to allocate memory for the certificate chain! (0x%lX).", dst->count * sizeof(Certificate));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -334,7 +333,7 @@ static bool _certRetrieveCertificateChainBySignatureIssuer(CertificateChain *dst
|
|||
{
|
||||
if (!_certRetrieveCertificateByName(&(dst->certs[i]), pch))
|
||||
{
|
||||
LOGFILE("Unable to retrieve certificate \"%s\"!", pch);
|
||||
LOG_MSG("Unable to retrieve certificate \"%s\"!", pch);
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx)
|
|||
(nca_ctx->storage_id != NcmStorageId_GameCard && !nca_ctx->ncm_storage) || (nca_ctx->storage_id == NcmStorageId_GameCard && !nca_ctx->gamecard_offset) || \
|
||||
nca_ctx->header.content_type != NcaContentType_Meta || nca_ctx->content_type_ctx || !out)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -55,7 +55,7 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx)
|
|||
u8 content_meta_type = 0;
|
||||
u64 title_id = 0, cur_offset = 0;
|
||||
|
||||
bool success = false, invalid_ext_header_size = false, invalid_ext_data_size = false;
|
||||
bool success = false, invalid_ext_header_size = false, invalid_ext_data_size = false, dump_packaged_header = false;
|
||||
|
||||
/* Free output context beforehand. */
|
||||
cnmtFreeContext(out);
|
||||
|
@ -63,14 +63,14 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx)
|
|||
/* Initialize Partition FS context. */
|
||||
if (!pfsInitializeContext(&(out->pfs_ctx), &(nca_ctx->fs_ctx[0])))
|
||||
{
|
||||
LOGFILE("Failed to initialize Partition FS context!");
|
||||
LOG_MSG("Failed to initialize Partition FS context!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Get Partition FS entry count. Edge case, we should never trigger this. */
|
||||
if (!(pfs_entry_count = pfsGetEntryCount(&(out->pfs_ctx))))
|
||||
{
|
||||
LOGFILE("Partition FS has no file entries!");
|
||||
LOG_MSG("Partition FS has no file entries!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -83,11 +83,11 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx)
|
|||
|
||||
if (i >= pfs_entry_count)
|
||||
{
|
||||
LOGFILE("'.cnmt' entry unavailable in Partition FS!");
|
||||
LOG_MSG("'.cnmt' entry unavailable in Partition FS!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
//LOGFILE("Found '.cnmt' entry \"%s\" in Meta NCA \"%s\".", out->cnmt_filename, nca_ctx->content_id_str);
|
||||
//LOG_MSG("Found '.cnmt' entry \"%s\" in Meta NCA \"%s\".", out->cnmt_filename, nca_ctx->content_id_str);
|
||||
|
||||
/* Retrieve content meta type and title ID from the '.cnmt' filename. */
|
||||
if (!cnmtGetContentMetaTypeAndTitleIdFromFileName(out->cnmt_filename, cnmt_filename_len, &content_meta_type, &title_id)) goto end;
|
||||
|
@ -95,14 +95,14 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx)
|
|||
/* Get '.cnmt' file entry. */
|
||||
if (!(out->pfs_entry = pfsGetEntryByIndex(&(out->pfs_ctx), i)))
|
||||
{
|
||||
LOGFILE("Failed to get '.cnmt' entry from Partition FS!");
|
||||
LOG_MSG("Failed to get '.cnmt' entry from Partition FS!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Check raw CNMT size. */
|
||||
if (!out->pfs_entry->size)
|
||||
{
|
||||
LOGFILE("Invalid raw CNMT size!");
|
||||
LOG_DATA(out->pfs_entry, sizeof(PartitionFileSystemEntry), "Invalid raw CNMT size! Partition FS entry dump:");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -110,14 +110,14 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx)
|
|||
out->raw_data_size = out->pfs_entry->size;
|
||||
if (!(out->raw_data = malloc(out->raw_data_size)))
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for the raw CNMT data!");
|
||||
LOG_MSG("Failed to allocate memory for the raw CNMT data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read raw CNMT data into memory buffer. */
|
||||
if (!pfsReadEntryData(&(out->pfs_ctx), out->pfs_entry, out->raw_data, out->raw_data_size, 0))
|
||||
{
|
||||
LOGFILE("Failed to read raw CNMT data!");
|
||||
LOG_MSG("Failed to read raw CNMT data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -130,26 +130,30 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx)
|
|||
|
||||
if (out->packaged_header->title_id != title_id)
|
||||
{
|
||||
LOGFILE("CNMT title ID mismatch! (%016lX != %016lX).", out->packaged_header->title_id, title_id);
|
||||
LOG_MSG("CNMT title ID mismatch! (%016lX != %016lX).", out->packaged_header->title_id, title_id);
|
||||
dump_packaged_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->packaged_header->content_meta_type != content_meta_type)
|
||||
{
|
||||
LOGFILE("CNMT content meta type mismatch! (0x%02X != 0x%02X).", out->packaged_header->content_meta_type, content_meta_type);
|
||||
LOG_MSG("CNMT content meta type mismatch! (0x%02X != 0x%02X).", out->packaged_header->content_meta_type, content_meta_type);
|
||||
dump_packaged_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!out->packaged_header->content_count && out->packaged_header->content_meta_type != NcmContentMetaType_SystemUpdate)
|
||||
{
|
||||
LOGFILE("Invalid content count!");
|
||||
LOG_MSG("Invalid content count!");
|
||||
dump_packaged_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((out->packaged_header->content_meta_type == NcmContentMetaType_SystemUpdate && !out->packaged_header->content_meta_count) || \
|
||||
(out->packaged_header->content_meta_type != NcmContentMetaType_SystemUpdate && out->packaged_header->content_meta_count))
|
||||
{
|
||||
LOGFILE("Invalid content meta count!");
|
||||
LOG_MSG("Invalid content meta count!");
|
||||
dump_packaged_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -189,13 +193,15 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx)
|
|||
|
||||
if (invalid_ext_header_size)
|
||||
{
|
||||
LOGFILE("Invalid extended header size!");
|
||||
LOG_MSG("Invalid extended header size!");
|
||||
dump_packaged_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (invalid_ext_data_size)
|
||||
{
|
||||
LOGFILE("Invalid extended data size!");
|
||||
LOG_DATA(out->extended_header, out->packaged_header->extended_header_size, "Invalid extended data size! CNMT Extended Header dump:");
|
||||
dump_packaged_header = true;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
@ -228,7 +234,7 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx)
|
|||
/* Safety check: verify raw CNMT size. */
|
||||
if (cur_offset != out->raw_data_size)
|
||||
{
|
||||
LOGFILE("Raw CNMT size mismatch! (0x%lX != 0x%lX).", cur_offset, out->raw_data_size);
|
||||
LOG_MSG("Raw CNMT size mismatch! (0x%lX != 0x%lX).", cur_offset, out->raw_data_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -242,7 +248,12 @@ bool cnmtInitializeContext(ContentMetaContext *out, NcaContext *nca_ctx)
|
|||
success = true;
|
||||
|
||||
end:
|
||||
if (!success) cnmtFreeContext(out);
|
||||
if (!success)
|
||||
{
|
||||
if (dump_packaged_header) LOG_DATA(out->packaged_header, sizeof(ContentMetaPackagedContentMetaHeader), "CNMT Packaged Header dump:");
|
||||
|
||||
cnmtFreeContext(out);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
@ -251,7 +262,7 @@ bool cnmtUpdateContentInfo(ContentMetaContext *cnmt_ctx, NcaContext *nca_ctx)
|
|||
{
|
||||
if (!cnmtIsValidContext(cnmt_ctx) || !nca_ctx || !*(nca_ctx->content_id_str) || !*(nca_ctx->hash_str) || nca_ctx->content_type > NcmContentType_DeltaFragment || !nca_ctx->content_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -273,14 +284,15 @@ bool cnmtUpdateContentInfo(ContentMetaContext *cnmt_ctx, NcaContext *nca_ctx)
|
|||
/* Jackpot. Copy content ID and hash to our raw CNMT. */
|
||||
memcpy(packaged_content_info->hash, nca_ctx->hash, sizeof(nca_ctx->hash));
|
||||
memcpy(&(content_info->content_id), &(nca_ctx->content_id), sizeof(NcmContentId));
|
||||
LOGFILE("Updated CNMT content record #%u (size 0x%lX, type 0x%02X, ID offset 0x%02X).", i, content_size, content_info->content_type, content_info->id_offset);
|
||||
LOG_MSG("Updated CNMT content record #%u (Title ID %016lX, size 0x%lX, type 0x%02X, ID offset 0x%02X).", i, cnmt_ctx->packaged_header->title_id, content_size, content_info->content_type, \
|
||||
content_info->id_offset);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) LOGFILE("Unable to find CNMT content info entry for \"%s\" NCA! (size 0x%lX, type 0x%02X, ID offset 0x%02X).", nca_ctx->content_id_str, nca_ctx->content_size, nca_ctx->content_type, \
|
||||
nca_ctx->id_offset);
|
||||
if (!success) LOG_MSG("Unable to find CNMT content info entry for \"%s\" NCA! (Title ID %016lX, size 0x%lX, type 0x%02X, ID offset 0x%02X).", nca_ctx->content_id_str, \
|
||||
cnmt_ctx->packaged_header->title_id, nca_ctx->content_size, nca_ctx->content_type, nca_ctx->id_offset);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
@ -289,7 +301,7 @@ bool cnmtGenerateNcaPatch(ContentMetaContext *cnmt_ctx)
|
|||
{
|
||||
if (!cnmtIsValidContext(cnmt_ctx))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -298,14 +310,14 @@ bool cnmtGenerateNcaPatch(ContentMetaContext *cnmt_ctx)
|
|||
sha256CalculateHash(cnmt_hash, cnmt_ctx->raw_data, cnmt_ctx->raw_data_size);
|
||||
if (!memcmp(cnmt_hash, cnmt_ctx->raw_data_hash, sizeof(cnmt_hash)))
|
||||
{
|
||||
LOGFILE("Skipping CNMT patching - no content records have been changed.");
|
||||
LOG_MSG("Skipping CNMT patching - no content records have been changed.");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Generate Partition FS entry patch. */
|
||||
if (!pfsGenerateEntryPatch(&(cnmt_ctx->pfs_ctx), cnmt_ctx->pfs_entry, cnmt_ctx->raw_data, cnmt_ctx->raw_data_size, 0, &(cnmt_ctx->nca_patch)))
|
||||
{
|
||||
LOGFILE("Failed to generate Partition FS entry patch!");
|
||||
LOG_MSG("Failed to generate Partition FS entry patch!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -330,7 +342,7 @@ void cnmtWriteNcaPatch(ContentMetaContext *cnmt_ctx, void *buf, u64 buf_size, u6
|
|||
if (nca_patch->written)
|
||||
{
|
||||
nca_ctx->content_type_ctx_patch = false;
|
||||
LOGFILE("CNMT Partition FS entry patch successfully written to NCA \"%s\"!", nca_ctx->content_id_str);
|
||||
LOG_MSG("CNMT Partition FS entry patch successfully written to NCA \"%s\"!", nca_ctx->content_id_str);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -338,7 +350,7 @@ bool cnmtGenerateAuthoringToolXml(ContentMetaContext *cnmt_ctx, NcaContext *nca_
|
|||
{
|
||||
if (!cnmtIsValidContext(cnmt_ctx) || !nca_ctx || !nca_ctx_count || nca_ctx_count > ((u32)cnmt_ctx->packaged_header->content_count + 1))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -400,7 +412,7 @@ bool cnmtGenerateAuthoringToolXml(ContentMetaContext *cnmt_ctx, NcaContext *nca_
|
|||
|
||||
if (invalid_nca)
|
||||
{
|
||||
LOGFILE("NCA \"%s\" isn't referenced by this CNMT!", cur_nca_ctx->content_id_str);
|
||||
LOG_MSG("NCA \"%s\" isn't referenced by this CNMT!", cur_nca_ctx->content_id_str);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -452,7 +464,7 @@ bool cnmtGenerateAuthoringToolXml(ContentMetaContext *cnmt_ctx, NcaContext *nca_
|
|||
{
|
||||
if (!utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, \
|
||||
" <RequiredApplicationVersion>%u</RequiredApplicationVersion>\n", \
|
||||
((VersionType1*)(cnmt_ctx->extended_header + sizeof(u64) + sizeof(u32)))->value)) goto end;
|
||||
((ContentMetaApplicationMetaExtendedHeader*)cnmt_ctx->extended_header)->required_application_version.value)) goto end;
|
||||
}
|
||||
|
||||
if (!(success = utilsAppendFormattedStringToBuffer(&xml_buf, &xml_buf_size, "</ContentMeta>"))) goto end;
|
||||
|
@ -465,7 +477,7 @@ end:
|
|||
if (!success)
|
||||
{
|
||||
if (xml_buf) free(xml_buf);
|
||||
LOGFILE("Failed to generate CNMT AuthoringTool XML!");
|
||||
LOG_MSG("Failed to generate CNMT AuthoringTool XML!");
|
||||
}
|
||||
|
||||
return success;
|
||||
|
@ -475,7 +487,7 @@ static bool cnmtGetContentMetaTypeAndTitleIdFromFileName(const char *cnmt_filena
|
|||
{
|
||||
if (!cnmt_filename || cnmt_filename_len < CNMT_MINIMUM_FILENAME_LENGTH || !out_content_meta_type || !out_title_id)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -488,12 +500,13 @@ static bool cnmtGetContentMetaTypeAndTitleIdFromFileName(const char *cnmt_filena
|
|||
|
||||
if (!pch1 || !(content_meta_type_str_len = (pch1 - cnmt_filename)) || (pch2 - ++pch1) != 16)
|
||||
{
|
||||
LOGFILE("Invalid '.cnmt' filename in Partition FS!");
|
||||
LOG_MSG("Invalid '.cnmt' filename in Partition FS! (\"%s\").", cnmt_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
for(i = NcmContentMetaType_SystemProgram; i <= NcmContentMetaType_Delta; i++)
|
||||
{
|
||||
/* Dirty loop hack, but whatever. */
|
||||
if (i > NcmContentMetaType_BootImagePackageSafe && i < NcmContentMetaType_Application)
|
||||
{
|
||||
i = (NcmContentMetaType_Application - 1);
|
||||
|
@ -509,13 +522,13 @@ static bool cnmtGetContentMetaTypeAndTitleIdFromFileName(const char *cnmt_filena
|
|||
|
||||
if (i > NcmContentMetaType_Delta)
|
||||
{
|
||||
LOGFILE("Invalid content meta type \"%.*s\" in '.cnmt' filename!", (int)content_meta_type_str_len, cnmt_filename);
|
||||
LOG_MSG("Invalid content meta type \"%.*s\" in '.cnmt' filename! (\"%s\").", (int)content_meta_type_str_len, cnmt_filename, cnmt_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(*out_title_id = strtoull(pch1, NULL, 16)))
|
||||
{
|
||||
LOGFILE("Invalid title ID in '.cnmt' filename!");
|
||||
LOG_MSG("Invalid title ID in '.cnmt' filename! (\"%s\").", cnmt_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,25 @@
|
|||
#ifndef __COMMON_H__
|
||||
#define __COMMON_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <malloc.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdatomic.h>
|
||||
#include <assert.h>
|
||||
#include <switch.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "ums.h"
|
||||
|
||||
#define FS_SYSMODULE_TID (u64)0x0100000000000000
|
||||
#define BOOT_SYSMODULE_TID (u64)0x0100000000000005
|
||||
#define SPL_SYSMODULE_TID (u64)0x0100000000000028
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -24,6 +24,7 @@
|
|||
#define __GAMECARD_H__
|
||||
|
||||
#include "fs_ext.h"
|
||||
#include "hfs.h"
|
||||
|
||||
#define GAMECARD_HEAD_MAGIC 0x48454144 /* "HEAD". */
|
||||
|
||||
|
@ -195,7 +196,7 @@ UEvent *gamecardGetStatusChangeUserEvent(void);
|
|||
/// Returns the current GameCardStatus value.
|
||||
u8 gamecardGetStatus(void);
|
||||
|
||||
/// Used to read raw data from the inserted gamecard.
|
||||
/// Used to read raw data from the inserted gamecard. Supports unaligned reads.
|
||||
/// All required handles, changes between normal <-> secure storage areas and proper offset calculations are managed internally.
|
||||
/// 'offset' + 'read_size' must not exceed the value returned by gamecardGetTotalSize().
|
||||
bool gamecardReadStorage(void *out, u64 read_size, u64 offset);
|
||||
|
@ -224,19 +225,14 @@ bool gamecardGetRomCapacity(u64 *out);
|
|||
/// Fills the provided VersionType1 pointer with the bundled firmware update version in the inserted gamecard.
|
||||
bool gamecardGetBundledFirmwareUpdateVersion(VersionType1 *out);
|
||||
|
||||
/// Returns a pointer to a string holding the name of the provided hash file system partition type. Returns NULL if the provided value is invalid.
|
||||
const char *gamecardGetHashFileSystemPartitionName(u8 hfs_partition_type);
|
||||
/// Returns a pointer to a dynamically-allocated HashFileSystemContext for the provided Hash FS partition type.
|
||||
/// Hash FS functions can be used on the retrieved HashFileSystemContext. hfsFreeContext() must be used to free the returned context.
|
||||
/// Returns NULL if an error occurs.
|
||||
HashFileSystemContext *gamecardGetHashFileSystemContext(u8 hfs_partition_type);
|
||||
|
||||
/// Retrieves the entry count from a hash FS partition.
|
||||
bool gamecardGetEntryCountFromHashFileSystemPartition(u8 hfs_partition_type, u32 *out_count);
|
||||
|
||||
/// Retrieves info from a hash FS partition entry using an entry index.
|
||||
/// 'out_offset', 'out_size' or 'out_name' may be set to NULL, but at least one of them must be a valid pointer.
|
||||
/// If 'out_name' != NULL and the function call succeeds, a pointer to a heap allocated buffer is returned.
|
||||
bool gamecardGetEntryInfoFromHashFileSystemPartitionByIndex(u8 hfs_partition_type, u32 idx, u64 *out_offset, u64 *out_size, char **out_name);
|
||||
|
||||
/// Retrieves info from a hash FS partition entry using an entry name.
|
||||
/// 'out_offset' or 'out_size' may be set to NULL, but at least one of them must be a valid pointer.
|
||||
bool gamecardGetEntryInfoFromHashFileSystemPartitionByName(u8 hfs_partition_type, const char *name, u64 *out_offset, u64 *out_size);
|
||||
/// One-shot function to retrieve meaningful information from a Hash FS entry by name without using gamecardGetHashFileSystemContext() + Hash FS functions.
|
||||
/// 'out_offset' or 'out_size' may be set to NULL, but at least one of them must be a valid pointer. The returned offset is always relative to the start of the gamecard image.
|
||||
/// If you need to get entry information by index, just retrieve the Hash FS context for the target partition and use Hash FS functions on it.
|
||||
bool gamecardGetHashFileSystemEntryInfoByName(u8 hfs_partition_type, const char *entry_name, u64 *out_offset, u64 *out_size);
|
||||
|
||||
#endif /* __GAMECARD_H__ */
|
||||
|
|
124
source/hfs.c
Normal file
124
source/hfs.c
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* hfs.c
|
||||
*
|
||||
* Copyright (c) 2020-2021, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* nxdumptool is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
#include "gamecard.h"
|
||||
|
||||
bool hfsReadPartitionData(HashFileSystemContext *ctx, void *out, u64 read_size, u64 offset)
|
||||
{
|
||||
if (!ctx || !ctx->size || !out || !read_size || (offset + read_size) > ctx->size)
|
||||
{
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read partition data. */
|
||||
if (!gamecardReadStorage(out, read_size, ctx->offset + offset))
|
||||
{
|
||||
LOG_MSG("Failed to read Hash FS partition data!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hfsReadEntryData(HashFileSystemContext *ctx, HashFileSystemEntry *fs_entry, void *out, u64 read_size, u64 offset)
|
||||
{
|
||||
if (!ctx || !fs_entry || !fs_entry->size || (fs_entry->offset + fs_entry->size) > ctx->size || !out || !read_size || (offset + read_size) > fs_entry->size)
|
||||
{
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read entry data. */
|
||||
if (!hfsReadPartitionData(ctx, out, read_size, ctx->header_size + fs_entry->offset + offset))
|
||||
{
|
||||
LOG_MSG("Failed to read Partition FS entry data!");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hfsGetTotalDataSize(HashFileSystemContext *ctx, u64 *out_size)
|
||||
{
|
||||
u64 total_size = 0;
|
||||
u32 entry_count = hfsGetEntryCount(ctx);
|
||||
HashFileSystemEntry *fs_entry = NULL;
|
||||
|
||||
if (!entry_count || !out_size)
|
||||
{
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
for(u32 i = 0; i < entry_count; i++)
|
||||
{
|
||||
if (!(fs_entry = hfsGetEntryByIndex(ctx, i)))
|
||||
{
|
||||
LOG_MSG("Failed to retrieve Hash FS entry #%u!", i);
|
||||
return false;
|
||||
}
|
||||
|
||||
total_size += fs_entry->size;
|
||||
}
|
||||
|
||||
*out_size = total_size;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hfsGetEntryIndexByName(HashFileSystemContext *ctx, const char *name, u32 *out_idx)
|
||||
{
|
||||
HashFileSystemEntry *fs_entry = NULL;
|
||||
u32 entry_count = hfsGetEntryCount(ctx), name_table_size = 0;
|
||||
char *name_table = hfsGetNameTable(ctx);
|
||||
|
||||
if (!entry_count || !name_table || !name || !*name || !out_idx)
|
||||
{
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
name_table_size = ((HashFileSystemHeader*)ctx->header)->name_table_size;
|
||||
|
||||
for(u32 i = 0; i < entry_count; i++)
|
||||
{
|
||||
if (!(fs_entry = hfsGetEntryByIndex(ctx, i)))
|
||||
{
|
||||
LOG_MSG("Failed to retrieve Hash FS entry #%u!", i);
|
||||
break;
|
||||
}
|
||||
|
||||
if (fs_entry->name_offset >= name_table_size)
|
||||
{
|
||||
LOG_MSG("Name offset from Hash FS entry #%u exceeds name table size!", i);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!strcmp(name_table + fs_entry->name_offset, name))
|
||||
{
|
||||
*out_idx = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
122
source/hfs.h
Normal file
122
source/hfs.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* hfs.h
|
||||
*
|
||||
* Copyright (c) 2020-2021, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* nxdumptool is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __HFS_H__
|
||||
#define __HFS_H__
|
||||
|
||||
#define HFS0_MAGIC 0x48465330 /* "HFS0". */
|
||||
|
||||
typedef struct {
|
||||
u32 magic; ///< "HFS0".
|
||||
u32 entry_count;
|
||||
u32 name_table_size;
|
||||
u8 reserved[0x4];
|
||||
} HashFileSystemHeader;
|
||||
|
||||
typedef struct {
|
||||
u64 offset;
|
||||
u64 size;
|
||||
u32 name_offset;
|
||||
u32 hash_target_size;
|
||||
u64 hash_target_offset;
|
||||
u8 hash[SHA256_HASH_SIZE];
|
||||
} HashFileSystemEntry;
|
||||
|
||||
/// Internally used by gamecard functions.
|
||||
/// Use gamecardGetHashFileSystemContext() to retrieve a Hash FS context.
|
||||
typedef struct {
|
||||
char *name; ///< Dynamically allocated partition name.
|
||||
u64 offset; ///< Partition offset (relative to the start of gamecard image).
|
||||
u64 size; ///< Partition size.
|
||||
u64 header_size; ///< Full header size.
|
||||
u8 *header; ///< HashFileSystemHeader + (HashFileSystemEntry * entry_count) + Name Table.
|
||||
} HashFileSystemContext;
|
||||
|
||||
/// Retrieves a Hash FS entry index by its name.
|
||||
bool hfsGetEntryIndexByName(HashFileSystemContext *ctx, const char *name, u32 *out_idx);
|
||||
|
||||
/// Reads raw partition data using a Hash FS context.
|
||||
/// Input offset must be relative to the start of the Hash FS.
|
||||
bool hfsReadPartitionData(HashFileSystemContext *ctx, void *out, u64 read_size, u64 offset);
|
||||
|
||||
/// Reads data from a previously retrieved HashFileSystemEntry using a Hash FS context.
|
||||
/// Input offset must be relative to the start of the Hash FS entry.
|
||||
bool hfsReadEntryData(HashFileSystemContext *ctx, HashFileSystemEntry *fs_entry, void *out, u64 read_size, u64 offset);
|
||||
|
||||
/// Calculates the extracted Hash FS size.
|
||||
bool hfsGetTotalDataSize(HashFileSystemContext *ctx, u64 *out_size);
|
||||
|
||||
/// Miscellaneous functions.
|
||||
|
||||
NX_INLINE void hfsFreeContext(HashFileSystemContext **ctx)
|
||||
{
|
||||
if (!ctx || !*ctx) return;
|
||||
|
||||
if ((*ctx)->name) free((*ctx)->name);
|
||||
if ((*ctx)->header) free((*ctx)->header);
|
||||
|
||||
free(*ctx);
|
||||
*ctx = NULL;
|
||||
}
|
||||
|
||||
NX_INLINE u32 hfsGetEntryCount(HashFileSystemContext *ctx)
|
||||
{
|
||||
if (!ctx || !ctx->header_size || !ctx->header) return 0;
|
||||
return ((HashFileSystemHeader*)ctx->header)->entry_count;
|
||||
}
|
||||
|
||||
NX_INLINE HashFileSystemEntry *hfsGetEntryByIndex(HashFileSystemContext *ctx, u32 idx)
|
||||
{
|
||||
if (idx >= hfsGetEntryCount(ctx)) return NULL;
|
||||
return (HashFileSystemEntry*)(ctx->header + sizeof(HashFileSystemHeader) + (idx * sizeof(HashFileSystemEntry)));
|
||||
}
|
||||
|
||||
NX_INLINE char *hfsGetNameTable(HashFileSystemContext *ctx)
|
||||
{
|
||||
u32 entry_count = hfsGetEntryCount(ctx);
|
||||
if (!entry_count) return NULL;
|
||||
return (char*)(ctx->header + sizeof(HashFileSystemHeader) + (entry_count * sizeof(HashFileSystemEntry)));
|
||||
}
|
||||
|
||||
NX_INLINE char *hfsGetEntryName(HashFileSystemContext *ctx, HashFileSystemEntry *fs_entry)
|
||||
{
|
||||
char *name_table = hfsGetNameTable(ctx);
|
||||
if (!name_table || !fs_entry || fs_entry->name_offset >= ((HashFileSystemHeader*)ctx->header)->name_table_size || !name_table[fs_entry->name_offset]) return NULL;
|
||||
return (name_table + fs_entry->name_offset);
|
||||
}
|
||||
|
||||
NX_INLINE char *hfsGetEntryNameByIndex(HashFileSystemContext *ctx, u32 idx)
|
||||
{
|
||||
HashFileSystemEntry *fs_entry = hfsGetEntryByIndex(ctx, idx);
|
||||
char *name_table = hfsGetNameTable(ctx);
|
||||
if (!fs_entry || !name_table) return NULL;
|
||||
return (name_table + fs_entry->name_offset);
|
||||
}
|
||||
|
||||
NX_INLINE HashFileSystemEntry *hfsGetEntryByName(HashFileSystemContext *ctx, const char *name)
|
||||
{
|
||||
u32 idx = 0;
|
||||
if (!hfsGetEntryIndexByName(ctx, name, &idx)) return NULL;
|
||||
return hfsGetEntryByIndex(ctx, idx);
|
||||
}
|
||||
|
||||
#endif /* __HFS_H__ */
|
|
@ -150,25 +150,25 @@ bool keysLoadNcaKeyset(void)
|
|||
envIsSyscallHinted(0x69) && /* svcQueryDebugProcessMemory. */
|
||||
envIsSyscallHinted(0x6A))) /* svcReadDebugProcessMemory. */
|
||||
{
|
||||
LOGFILE("Debug SVC permissions not available!");
|
||||
LOG_MSG("Debug SVC permissions not available!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!keysRetrieveKeysFromProgramMemory(&g_fsRodataMemoryInfo))
|
||||
{
|
||||
LOGFILE("Unable to retrieve keys from FS .rodata segment!");
|
||||
LOG_MSG("Unable to retrieve keys from FS .rodata segment!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!keysRetrieveKeysFromProgramMemory(&g_fsDataMemoryInfo))
|
||||
{
|
||||
LOGFILE("Unable to retrieve keys from FS .data segment!");
|
||||
LOG_MSG("Unable to retrieve keys from FS .data segment!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!keysDeriveNcaHeaderKey())
|
||||
{
|
||||
LOGFILE("Unable to derive NCA header key!");
|
||||
LOG_MSG("Unable to derive NCA header key!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -203,7 +203,7 @@ const u8 *keysGetKeyAreaEncryptionKeySource(u8 kaek_index)
|
|||
ptr = (const u8*)(g_ncaKeyset.key_area_key_system_source);
|
||||
break;
|
||||
default:
|
||||
LOGFILE("Invalid KAEK index! (0x%02X).", kaek_index);
|
||||
LOG_MSG("Invalid KAEK index! (0x%02X).", kaek_index);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ const u8 *keysGetTitlekek(u8 key_generation)
|
|||
{
|
||||
if (key_generation > 0x20)
|
||||
{
|
||||
LOGFILE("Invalid key generation value! (0x%02X).", key_generation);
|
||||
LOG_MSG("Invalid key generation value! (0x%02X).", key_generation);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -232,13 +232,13 @@ const u8 *keysGetKeyAreaEncryptionKey(u8 key_generation, u8 kaek_index)
|
|||
{
|
||||
if (key_generation > 0x20)
|
||||
{
|
||||
LOGFILE("Invalid key generation value! (0x%02X).", key_generation);
|
||||
LOG_MSG("Invalid key generation value! (0x%02X).", key_generation);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (kaek_index > NcaKeyAreaEncryptionKeyIndex_System)
|
||||
{
|
||||
LOGFILE("Invalid KAEK index! (0x%02X).", kaek_index);
|
||||
LOG_MSG("Invalid KAEK index! (0x%02X).", kaek_index);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -251,7 +251,7 @@ static bool keysRetrieveKeysFromProgramMemory(KeysMemoryInfo *info)
|
|||
{
|
||||
if (!info || !info->key_count)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -269,7 +269,7 @@ static bool keysRetrieveKeysFromProgramMemory(KeysMemoryInfo *info)
|
|||
|
||||
if (!key->dst)
|
||||
{
|
||||
LOGFILE("Invalid destination pointer for key \"%s\" in program %016lX!", key->name, info->location.program_id);
|
||||
LOG_MSG("Invalid destination pointer for key \"%s\" in program %016lX!", key->name, info->location.program_id);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -291,7 +291,7 @@ static bool keysRetrieveKeysFromProgramMemory(KeysMemoryInfo *info)
|
|||
|
||||
if (!found)
|
||||
{
|
||||
LOGFILE("Unable to locate key \"%s\" in process memory from program %016lX!", key->name, info->location.program_id);
|
||||
LOG_MSG("Unable to locate key \"%s\" in process memory from program %016lX!", key->name, info->location.program_id);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
@ -311,21 +311,21 @@ static bool keysDeriveNcaHeaderKey(void)
|
|||
rc = splCryptoGenerateAesKek(g_ncaKeyset.header_kek_source, 0, 0, g_ncaKeyset.header_kek);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("splCryptoGenerateAesKek(header_kek_source) failed! (0x%08X).", rc);
|
||||
LOG_MSG("splCryptoGenerateAesKek(header_kek_source) failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = splCryptoGenerateAesKey(g_ncaKeyset.header_kek, g_ncaKeyset.header_key_source + 0x00, g_ncaKeyset.header_key + 0x00);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("splCryptoGenerateAesKey(header_key_source + 0x00) failed! (0x%08X).", rc);
|
||||
LOG_MSG("splCryptoGenerateAesKey(header_key_source + 0x00) failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = splCryptoGenerateAesKey(g_ncaKeyset.header_kek, g_ncaKeyset.header_key_source + 0x10, g_ncaKeyset.header_key + 0x10);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("splCryptoGenerateAesKey(header_key_source + 0x10) failed! (0x%08X).", rc);
|
||||
LOG_MSG("splCryptoGenerateAesKey(header_key_source + 0x10) failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -374,7 +374,7 @@ static int keysGetKeyAndValueFromFile(FILE *f, char **key, char **value)
|
|||
{
|
||||
if (!f || !key || !value)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
@ -483,13 +483,13 @@ static bool keysParseHexKey(u8 *out, const char *key, const char *value, u32 siz
|
|||
|
||||
if (!out || !key || !*key || !value || !(value_len = strlen(value)) || !size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (value_len != hex_str_len)
|
||||
{
|
||||
LOGFILE("Key \"%s\" must be %u hex digits long!", key, hex_str_len);
|
||||
LOG_MSG("Key \"%s\" must be %u hex digits long!", key, hex_str_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -500,7 +500,7 @@ static bool keysParseHexKey(u8 *out, const char *key, const char *value, u32 siz
|
|||
char val = keysConvertHexCharToBinary(value[i]);
|
||||
if (val == 'z')
|
||||
{
|
||||
LOGFILE("Invalid hex character in key \"%s\" at position %u!", key, i);
|
||||
LOG_MSG("Invalid hex character in key \"%s\" at position %u!", key, i);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -523,7 +523,7 @@ static bool keysReadKeysFromFile(void)
|
|||
keys_file = fopen(KEYS_FILE_PATH, "rb");
|
||||
if (!keys_file)
|
||||
{
|
||||
LOGFILE("Unable to open \"%s\" to retrieve keys!", KEYS_FILE_PATH);
|
||||
LOG_MSG("Unable to open \"%s\" to retrieve keys!", KEYS_FILE_PATH);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -591,13 +591,13 @@ static bool keysReadKeysFromFile(void)
|
|||
|
||||
if (parse_fail || !key_count)
|
||||
{
|
||||
if (!key_count) LOGFILE("Unable to parse necessary keys from \"%s\"! (keys file empty?).", KEYS_FILE_PATH);
|
||||
if (!key_count) LOG_MSG("Unable to parse necessary keys from \"%s\"! (keys file empty?).", KEYS_FILE_PATH);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!eticket_rsa_kek_available)
|
||||
{
|
||||
LOGFILE("\"eticket_rsa_kek\" unavailable in \"%s\"!", KEYS_FILE_PATH);
|
||||
LOG_MSG("\"eticket_rsa_kek\" unavailable in \"%s\"!", KEYS_FILE_PATH);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ bool legalInfoInitializeContext(LegalInfoContext *out, NcaContext *nca_ctx)
|
|||
(nca_ctx->storage_id != NcmStorageId_GameCard && !nca_ctx->ncm_storage) || (nca_ctx->storage_id == NcmStorageId_GameCard && !nca_ctx->gamecard_offset) || \
|
||||
nca_ctx->header.content_type != NcaContentType_Manual || nca_ctx->content_type_ctx || !out)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -43,23 +43,23 @@ bool legalInfoInitializeContext(LegalInfoContext *out, NcaContext *nca_ctx)
|
|||
/* Initialize RomFS context. */
|
||||
if (!romfsInitializeContext(&romfs_ctx, &(nca_ctx->fs_ctx[0])))
|
||||
{
|
||||
LOGFILE("Failed to initialize RomFS context!");
|
||||
LOG_MSG("Failed to initialize RomFS context!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Retrieve RomFS file entry for 'legalinfo.xml'. */
|
||||
if (!(xml_entry = romfsGetFileEntryByPath(&romfs_ctx, "/legalinfo.xml")))
|
||||
{
|
||||
LOGFILE("Failed to retrieve file entry for \"legalinfo.xml\" from RomFS!");
|
||||
LOG_MSG("Failed to retrieve file entry for \"legalinfo.xml\" from RomFS!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
//LOGFILE("Found 'legalinfo.xml' entry in LegalInformation NCA \"%s\".", nca_ctx->content_id_str);
|
||||
//LOG_MSG("Found 'legalinfo.xml' entry in LegalInformation NCA \"%s\".", nca_ctx->content_id_str);
|
||||
|
||||
/* Verify XML size. */
|
||||
if (!xml_entry->size)
|
||||
{
|
||||
LOGFILE("Invalid XML size!");
|
||||
LOG_MSG("Invalid XML size!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -67,14 +67,14 @@ bool legalInfoInitializeContext(LegalInfoContext *out, NcaContext *nca_ctx)
|
|||
out->authoring_tool_xml_size = xml_entry->size;
|
||||
if (!(out->authoring_tool_xml = malloc(out->authoring_tool_xml_size)))
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for the XML!");
|
||||
LOG_MSG("Failed to allocate memory for the XML!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read NACP data into memory buffer. */
|
||||
if (!romfsReadFileEntryData(&romfs_ctx, xml_entry, out->authoring_tool_xml, out->authoring_tool_xml_size, 0))
|
||||
{
|
||||
LOGFILE("Failed to read XML!");
|
||||
LOG_MSG("Failed to read XML!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
|
401
source/log.c
Normal file
401
source/log.c
Normal file
|
@ -0,0 +1,401 @@
|
|||
/*
|
||||
* log.c
|
||||
*
|
||||
* Copyright (c) 2020-2021, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* nxdumptool is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "utils.h"
|
||||
|
||||
#define LOG_FILE_PATH "./" APP_TITLE ".log"
|
||||
#define LOG_BUF_SIZE 0x400000 /* 4 MiB. */
|
||||
#define LOG_FORCE_FLUSH 0 /* Forces a log buffer flush each time the logfile is written to. */
|
||||
|
||||
/* Global variables. */
|
||||
|
||||
static Mutex g_logMutex = 0;
|
||||
|
||||
static FsFile g_logFile = {0};
|
||||
static s64 g_logFileOffset = 0;
|
||||
|
||||
static char *g_logBuffer = NULL;
|
||||
static size_t g_logBufferLength = 0;
|
||||
|
||||
static const char *g_logStrFormat = "[%d-%02d-%02d %02d:%02d:%02d.%lu] %s -> ";
|
||||
static const char *g_logLineBreak = "\r\n";
|
||||
|
||||
/* Function prototypes. */
|
||||
|
||||
static bool logAllocateLogBuffer(void);
|
||||
|
||||
static bool logOpenLogFile(void);
|
||||
static void _logFlushLogFile(bool lock);
|
||||
|
||||
static void _logWriteStringToLogFile(const char *src, bool lock);
|
||||
static void _logWriteFormattedStringToLogFile(const char *func_name, const char *fmt, va_list args, bool lock);
|
||||
|
||||
void logWriteStringToLogFile(const char *src)
|
||||
{
|
||||
_logWriteStringToLogFile(src, true);
|
||||
}
|
||||
|
||||
void logWriteFormattedStringToLogFile(const char *func_name, const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
_logWriteFormattedStringToLogFile(func_name, fmt, args, true);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void logWriteFormattedStringToBuffer(char **dst, size_t *dst_size, const char *func_name, const char *fmt, ...)
|
||||
{
|
||||
if (!dst || !dst_size || (!*dst && *dst_size) || (*dst && !*dst_size) || !func_name || !*func_name || !fmt || !*fmt) return;
|
||||
|
||||
va_list args;
|
||||
|
||||
size_t str1_len = 0, str2_len = 0, log_str_len = 0;
|
||||
|
||||
char *dst_ptr = *dst, *tmp_str = NULL;
|
||||
size_t dst_cur_size = *dst_size, dst_str_len = (dst_ptr ? strlen(dst_ptr) : 0);
|
||||
|
||||
if (dst_str_len >= dst_cur_size) return;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
/* Get current time with nanosecond precision. */
|
||||
struct timespec now = {0};
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
|
||||
/* Get local time. */
|
||||
struct tm *ts = localtime(&(now.tv_sec));
|
||||
ts->tm_year += 1900;
|
||||
ts->tm_mon++;
|
||||
|
||||
/* Get formatted string length. */
|
||||
str1_len = snprintf(NULL, 0, g_logStrFormat, ts->tm_year, ts->tm_mon, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec, now.tv_nsec, func_name);
|
||||
if ((int)str1_len <= 0) goto end;
|
||||
|
||||
str2_len = vsnprintf(NULL, 0, fmt, args);
|
||||
if ((int)str2_len <= 0) goto end;
|
||||
|
||||
log_str_len = (str1_len + str2_len + 3);
|
||||
|
||||
if (!dst_cur_size || log_str_len > (dst_cur_size - dst_str_len))
|
||||
{
|
||||
/* Update buffer size. */
|
||||
dst_cur_size = (dst_str_len + log_str_len);
|
||||
|
||||
/* Reallocate buffer. */
|
||||
tmp_str = realloc(dst_ptr, dst_cur_size);
|
||||
if (!tmp_str) goto end;
|
||||
|
||||
dst_ptr = tmp_str;
|
||||
tmp_str = NULL;
|
||||
|
||||
/* Clear allocated area. */
|
||||
memset(dst_ptr + dst_str_len, 0, log_str_len);
|
||||
|
||||
/* Update pointers. */
|
||||
*dst = dst_ptr;
|
||||
*dst_size = dst_cur_size;
|
||||
}
|
||||
|
||||
/* Generate formatted string. */
|
||||
sprintf(dst_ptr + dst_str_len, g_logStrFormat, ts->tm_year, ts->tm_mon, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec, now.tv_nsec, func_name);
|
||||
vsprintf(dst_ptr + dst_str_len + str1_len, fmt, args);
|
||||
strcat(dst_ptr, g_logLineBreak);
|
||||
|
||||
end:
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void logWriteBinaryDataToLogFile(const void *data, size_t data_size, const char *func_name, const char *fmt, ...)
|
||||
{
|
||||
if (!data || !data_size || !func_name || !*func_name || !fmt || !*fmt) return;
|
||||
|
||||
va_list args;
|
||||
size_t data_str_size = ((data_size * 2) + 3);
|
||||
char *data_str = NULL;
|
||||
|
||||
mutexLock(&g_logMutex);
|
||||
|
||||
/* Allocate memory for the hex string representation of the provided binary data. */
|
||||
data_str = calloc(data_str_size, sizeof(char));
|
||||
if (!data_str) goto end;
|
||||
|
||||
/* Generate hex string representation. */
|
||||
utilsGenerateHexStringFromData(data_str, data_str_size, data, data_size);
|
||||
strcat(data_str, g_logLineBreak);
|
||||
|
||||
/* Write formatted string. */
|
||||
va_start(args, fmt);
|
||||
_logWriteFormattedStringToLogFile(func_name, fmt, args, false);
|
||||
va_end(args);
|
||||
|
||||
/* Write hex string representation. */
|
||||
_logWriteStringToLogFile(data_str, false);
|
||||
|
||||
end:
|
||||
if (data_str) free(data_str);
|
||||
|
||||
mutexUnlock(&g_logMutex);
|
||||
}
|
||||
|
||||
void logFlushLogFile(void)
|
||||
{
|
||||
_logFlushLogFile(true);
|
||||
}
|
||||
|
||||
void logCloseLogFile(void)
|
||||
{
|
||||
mutexLock(&g_logMutex);
|
||||
|
||||
/* Flush log buffer. */
|
||||
_logFlushLogFile(false);
|
||||
|
||||
/* Close logfile. */
|
||||
if (serviceIsActive(&(g_logFile.s)))
|
||||
{
|
||||
fsFileClose(&g_logFile);
|
||||
memset(&g_logFile, 0, sizeof(FsFile));
|
||||
|
||||
/* Commit SD card filesystem changes. */
|
||||
utilsCommitSdCardFileSystemChanges();
|
||||
}
|
||||
|
||||
/* Free log buffer. */
|
||||
if (g_logBuffer)
|
||||
{
|
||||
free(g_logBuffer);
|
||||
g_logBuffer = NULL;
|
||||
}
|
||||
|
||||
g_logFileOffset = 0;
|
||||
|
||||
mutexUnlock(&g_logMutex);
|
||||
}
|
||||
|
||||
void logControlMutex(bool lock)
|
||||
{
|
||||
if (lock)
|
||||
{
|
||||
mutexLock(&g_logMutex);
|
||||
} else {
|
||||
mutexUnlock(&g_logMutex);
|
||||
}
|
||||
}
|
||||
|
||||
static bool logAllocateLogBuffer(void)
|
||||
{
|
||||
if (g_logBuffer) return true;
|
||||
g_logBuffer = memalign(LOG_BUF_SIZE, LOG_BUF_SIZE);
|
||||
return (g_logBuffer != NULL);
|
||||
}
|
||||
|
||||
static bool logOpenLogFile(void)
|
||||
{
|
||||
if (serviceIsActive(&(g_logFile.s))) return true;
|
||||
|
||||
Result rc = 0;
|
||||
|
||||
/* Get SD card FsFileSystem object. */
|
||||
FsFileSystem *sdmc_fs = utilsGetSdCardFileSystemObject();
|
||||
if (!sdmc_fs) return false;
|
||||
|
||||
/* Create file. This will fail if the logfile exists, so we don't check its return value. */
|
||||
fsFsCreateFile(sdmc_fs, LOG_FILE_PATH, 0, 0);
|
||||
|
||||
/* Open file. */
|
||||
rc = fsFsOpenFile(sdmc_fs, LOG_FILE_PATH, FsOpenMode_Write | FsOpenMode_Append, &g_logFile);
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
/* Get file size. */
|
||||
rc = fsFileGetSize(&g_logFile, &g_logFileOffset);
|
||||
if (R_FAILED(rc)) fsFileClose(&g_logFile);
|
||||
}
|
||||
|
||||
return R_SUCCEEDED(rc);
|
||||
}
|
||||
|
||||
static void _logFlushLogFile(bool lock)
|
||||
{
|
||||
if (lock) mutexLock(&g_logMutex);
|
||||
|
||||
if (!serviceIsActive(&(g_logFile.s)) || !g_logBuffer || !g_logBufferLength) goto end;
|
||||
|
||||
/* Write log buffer contents and flush the written data right away. */
|
||||
Result rc = fsFileWrite(&g_logFile, g_logFileOffset, g_logBuffer, g_logBufferLength, FsWriteOption_Flush);
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
/* Update global variables. */
|
||||
g_logFileOffset += (s64)g_logBufferLength;
|
||||
*g_logBuffer = '\0';
|
||||
g_logBufferLength = 0;
|
||||
}
|
||||
|
||||
end:
|
||||
if (lock) mutexUnlock(&g_logMutex);
|
||||
}
|
||||
|
||||
static void _logWriteStringToLogFile(const char *src, bool lock)
|
||||
{
|
||||
if (!src || !*src) return;
|
||||
|
||||
if (lock) mutexLock(&g_logMutex);
|
||||
|
||||
Result rc = 0;
|
||||
size_t src_len = strlen(src), tmp_len = 0;
|
||||
|
||||
/* Make sure we have allocated memory for the log buffer and opened the logfile. */
|
||||
if (!logAllocateLogBuffer() || !logOpenLogFile()) goto end;
|
||||
|
||||
/* Check if the formatted string length is lower than the log buffer size. */
|
||||
if (src_len < LOG_BUF_SIZE)
|
||||
{
|
||||
/* Flush log buffer contents (if needed). */
|
||||
if ((g_logBufferLength + src_len) >= LOG_BUF_SIZE)
|
||||
{
|
||||
_logFlushLogFile(false);
|
||||
if (g_logBufferLength) goto end;
|
||||
}
|
||||
|
||||
/* Copy string into the log buffer. */
|
||||
strcpy(g_logBuffer + g_logBufferLength, src);
|
||||
g_logBufferLength += src_len;
|
||||
} else {
|
||||
/* Flush log buffer. */
|
||||
_logFlushLogFile(false);
|
||||
if (g_logBufferLength) goto end;
|
||||
|
||||
/* Write string data until it no longer exceeds the log buffer size. */
|
||||
while(src_len >= LOG_BUF_SIZE)
|
||||
{
|
||||
rc = fsFileWrite(&g_logFile, g_logFileOffset, src + tmp_len, LOG_BUF_SIZE, FsWriteOption_Flush);
|
||||
if (R_FAILED(rc)) goto end;
|
||||
|
||||
g_logFileOffset += LOG_BUF_SIZE;
|
||||
tmp_len += LOG_BUF_SIZE;
|
||||
src_len -= LOG_BUF_SIZE;
|
||||
}
|
||||
|
||||
/* Copy any remaining data from the string into the log buffer. */
|
||||
if (src_len)
|
||||
{
|
||||
strcpy(g_logBuffer, src + tmp_len);
|
||||
g_logBufferLength = src_len;
|
||||
}
|
||||
}
|
||||
|
||||
#if LOG_FORCE_FLUSH == 1
|
||||
/* Flush log buffer. */
|
||||
_logFlushLogFile(false);
|
||||
#endif
|
||||
|
||||
end:
|
||||
if (lock) mutexUnlock(&g_logMutex);
|
||||
}
|
||||
|
||||
static void _logWriteFormattedStringToLogFile(const char *func_name, const char *fmt, va_list args, bool lock)
|
||||
{
|
||||
if (!func_name || !*func_name || !fmt || !*fmt) return;
|
||||
|
||||
if (lock) mutexLock(&g_logMutex);
|
||||
|
||||
Result rc = 0;
|
||||
size_t str1_len = 0, str2_len = 0, log_str_len = 0;
|
||||
|
||||
char *tmp_str = NULL;
|
||||
size_t tmp_len = 0;
|
||||
|
||||
/* Get current time with nanosecond precision. */
|
||||
struct timespec now = {0};
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
|
||||
/* Get local time. */
|
||||
struct tm *ts = localtime(&(now.tv_sec));
|
||||
ts->tm_year += 1900;
|
||||
ts->tm_mon++;
|
||||
|
||||
/* Make sure we have allocated memory for the log buffer and opened the logfile. */
|
||||
if (!logAllocateLogBuffer() || !logOpenLogFile()) goto end;
|
||||
|
||||
/* Get formatted string length. */
|
||||
str1_len = snprintf(NULL, 0, g_logStrFormat, ts->tm_year, ts->tm_mon, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec, now.tv_nsec, func_name);
|
||||
if ((int)str1_len <= 0) goto end;
|
||||
|
||||
str2_len = vsnprintf(NULL, 0, fmt, args);
|
||||
if ((int)str2_len <= 0) goto end;
|
||||
|
||||
log_str_len = (str1_len + str2_len + 2);
|
||||
|
||||
/* Check if the formatted string length is less than the log buffer size. */
|
||||
if (log_str_len < LOG_BUF_SIZE)
|
||||
{
|
||||
/* Flush log buffer contents (if needed). */
|
||||
if ((g_logBufferLength + log_str_len) >= LOG_BUF_SIZE)
|
||||
{
|
||||
_logFlushLogFile(false);
|
||||
if (g_logBufferLength) goto end;
|
||||
}
|
||||
|
||||
/* Nice and easy string formatting using the log buffer. */
|
||||
sprintf(g_logBuffer + g_logBufferLength, g_logStrFormat, ts->tm_year, ts->tm_mon, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec, now.tv_nsec, func_name);
|
||||
vsprintf(g_logBuffer + g_logBufferLength + str1_len, fmt, args);
|
||||
strcat(g_logBuffer, g_logLineBreak);
|
||||
g_logBufferLength += log_str_len;
|
||||
} else {
|
||||
/* Flush log buffer. */
|
||||
_logFlushLogFile(false);
|
||||
if (g_logBufferLength) goto end;
|
||||
|
||||
/* Allocate memory for a temporary buffer. This will hold the formatted string. */
|
||||
tmp_str = calloc(log_str_len + 1, sizeof(char));
|
||||
if (!tmp_str) goto end;
|
||||
|
||||
/* Generate formatted string. */
|
||||
sprintf(tmp_str, g_logStrFormat, ts->tm_year, ts->tm_mon, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec, now.tv_nsec, func_name);
|
||||
vsprintf(tmp_str + str1_len, fmt, args);
|
||||
strcat(tmp_str, g_logLineBreak);
|
||||
|
||||
/* Write formatted string data until it no longer exceeds the log buffer size. */
|
||||
while(log_str_len >= LOG_BUF_SIZE)
|
||||
{
|
||||
rc = fsFileWrite(&g_logFile, g_logFileOffset, tmp_str + tmp_len, LOG_BUF_SIZE, FsWriteOption_Flush);
|
||||
if (R_FAILED(rc)) goto end;
|
||||
|
||||
g_logFileOffset += LOG_BUF_SIZE;
|
||||
tmp_len += LOG_BUF_SIZE;
|
||||
log_str_len -= LOG_BUF_SIZE;
|
||||
}
|
||||
|
||||
/* Copy any remaining data from the formatted string into the log buffer. */
|
||||
if (log_str_len)
|
||||
{
|
||||
strcpy(g_logBuffer, tmp_str + tmp_len);
|
||||
g_logBufferLength = log_str_len;
|
||||
}
|
||||
}
|
||||
|
||||
#if LOG_FORCE_FLUSH == 1
|
||||
/* Flush log buffer. */
|
||||
_logFlushLogFile(false);
|
||||
#endif
|
||||
|
||||
end:
|
||||
if (tmp_str) free(tmp_str);
|
||||
|
||||
if (lock) mutexUnlock(&g_logMutex);
|
||||
}
|
53
source/log.h
Normal file
53
source/log.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* log.h
|
||||
*
|
||||
* Copyright (c) 2020-2021, DarkMatterCore <pabloacurielz@gmail.com>.
|
||||
*
|
||||
* This file is part of nxdumptool (https://github.com/DarkMatterCore/nxdumptool).
|
||||
*
|
||||
* nxdumptool is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* nxdumptool is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef __LOG_H__
|
||||
#define __LOG_H__
|
||||
|
||||
/// Helper macros.
|
||||
#define LOG_MSG(fmt, ...) logWriteFormattedStringToLogFile(__func__, fmt, ##__VA_ARGS__)
|
||||
#define LOG_MSG_BUF(dst, dst_size, fmt, ...) logWriteFormattedStringToBuffer(dst, dst_size, __func__, fmt, ##__VA_ARGS__)
|
||||
#define LOG_DATA(data, data_size, fmt, ...) logWriteBinaryDataToLogFile(data, data_size, __func__, fmt, ##__VA_ARGS__)
|
||||
|
||||
/// Writes the provided string to the logfile.
|
||||
void logWriteStringToLogFile(const char *src);
|
||||
|
||||
/// Writes a formatted log string to the logfile.
|
||||
void logWriteFormattedStringToLogFile(const char *func_name, const char *fmt, ...);
|
||||
|
||||
/// Writes a formatted log string to the provided buffer.
|
||||
/// If the buffer isn't big enough to hold both its current contents and the new formatted string, it will be resized.
|
||||
void logWriteFormattedStringToBuffer(char **dst, size_t *dst_size, const char *func_name, const char *fmt, ...);
|
||||
|
||||
/// Writes a formatted log string + a hex string representation of the provided binary data to the logfile.
|
||||
void logWriteBinaryDataToLogFile(const void *data, size_t data_size, const char *func_name, const char *fmt, ...);
|
||||
|
||||
/// Forces a flush operation on the logfile.
|
||||
void logFlushLogFile(void);
|
||||
|
||||
/// Closes the logfile.
|
||||
void logCloseLogFile(void);
|
||||
|
||||
/// (Un)locks the log mutex. Use with caution.
|
||||
void logControlMutex(bool lock);
|
||||
|
||||
#endif /* __LOG_H__ */
|
19
source/mem.c
19
source/mem.c
|
@ -22,13 +22,14 @@
|
|||
#include "utils.h"
|
||||
#include "mem.h"
|
||||
|
||||
#define MEMLOG(fmt, ...) LOGBUF(&g_memLogBuf, &g_memLogBufSize, fmt, ##__VA_ARGS__)
|
||||
#define MEMLOG(fmt, ...) LOG_MSG_BUF(&g_memLogBuf, &g_memLogBufSize, fmt, ##__VA_ARGS__)
|
||||
|
||||
/* Global variables. */
|
||||
|
||||
static Mutex g_memMutex = 0;
|
||||
|
||||
static char *g_memLogBuf = NULL;
|
||||
static size_t g_memLogBufSize = 0;
|
||||
static Mutex g_memMutex = 0;
|
||||
|
||||
/* Function prototypes. */
|
||||
|
||||
|
@ -39,7 +40,7 @@ bool memRetrieveProgramMemorySegment(MemoryLocation *location)
|
|||
{
|
||||
if (!location || !location->program_id || !location->mask || location->mask >= BIT(3))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -54,7 +55,7 @@ bool memRetrieveFullProgramMemory(MemoryLocation *location)
|
|||
{
|
||||
if (!location || !location->program_id)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -82,11 +83,11 @@ static bool memRetrieveProgramMemory(MemoryLocation *location, bool is_segment)
|
|||
/* Clear output MemoryLocation element. */
|
||||
memFreeMemoryLocation(location);
|
||||
|
||||
/* LOGFILE() will be useless if the target program is the FS sysmodule. */
|
||||
/* LOG_MSG() will be useless if the target program is the FS sysmodule. */
|
||||
/* This is because any FS I/O operation *will* lock up the console while FS itself is being debugged. */
|
||||
/* So we'll just temporarily log data to a char array using LOGBUF(), then write it all out after calling svcCloseHandle(). */
|
||||
/* So we'll just temporarily log data to a char array using LOG_MSG_BUF(), then write it all out after calling svcCloseHandle(). */
|
||||
/* However, we must prevent other threads from logging data as well in order to avoid a lock up, so we'll temporarily lock the logfile mutex. */
|
||||
utilsLogFileMutexControl(true);
|
||||
logControlMutex(true);
|
||||
|
||||
/* Retrieve debug handle by program ID. */
|
||||
if (!memRetrieveDebugHandleFromProgramById(&debug_handle, location->program_id))
|
||||
|
@ -163,7 +164,7 @@ end:
|
|||
if (debug_handle != INVALID_HANDLE) svcCloseHandle(debug_handle);
|
||||
|
||||
/* Unlock logfile mutex. */
|
||||
utilsLogFileMutexControl(false);
|
||||
logControlMutex(false);
|
||||
|
||||
if (success && (!location->data || !location->data_size))
|
||||
{
|
||||
|
@ -174,7 +175,7 @@ end:
|
|||
if (!success) memFreeMemoryLocation(location);
|
||||
|
||||
/* Write log buffer data. This will do nothing if the log buffer length is zero. */
|
||||
utilsWriteLogBufferToLogFile(g_memLogBuf);
|
||||
logWriteStringToLogFile(g_memLogBuf);
|
||||
|
||||
/* Free memory log buffer. */
|
||||
if (g_memLogBuf)
|
||||
|
|
|
@ -201,7 +201,7 @@ bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx)
|
|||
(nca_ctx->storage_id != NcmStorageId_GameCard && !nca_ctx->ncm_storage) || (nca_ctx->storage_id == NcmStorageId_GameCard && !nca_ctx->gamecard_offset) || \
|
||||
nca_ctx->header.content_type != NcaContentType_Control || nca_ctx->content_type_ctx || !out)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -218,37 +218,37 @@ bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx)
|
|||
/* Initialize RomFS context. */
|
||||
if (!romfsInitializeContext(&(out->romfs_ctx), &(nca_ctx->fs_ctx[0])))
|
||||
{
|
||||
LOGFILE("Failed to initialize RomFS context!");
|
||||
LOG_MSG("Failed to initialize RomFS context!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Retrieve RomFS file entry for 'control.nacp'. */
|
||||
if (!(out->romfs_file_entry = romfsGetFileEntryByPath(&(out->romfs_ctx), "/control.nacp")))
|
||||
{
|
||||
LOGFILE("Failed to retrieve file entry for \"control.nacp\" from RomFS!");
|
||||
LOG_MSG("Failed to retrieve file entry for \"control.nacp\" from RomFS!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
//LOGFILE("Found 'control.nacp' entry in Control NCA \"%s\".", nca_ctx->content_id_str);
|
||||
//LOG_MSG("Found 'control.nacp' entry in Control NCA \"%s\".", nca_ctx->content_id_str);
|
||||
|
||||
/* Verify NACP size. */
|
||||
if (out->romfs_file_entry->size != sizeof(_NacpStruct))
|
||||
{
|
||||
LOGFILE("Invalid NACP size!");
|
||||
LOG_MSG("Invalid NACP size!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Allocate memory for the NACP data. */
|
||||
if (!(out->data = malloc(sizeof(_NacpStruct))))
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for the NACP data!");
|
||||
LOG_MSG("Failed to allocate memory for the NACP data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read NACP data into memory buffer. */
|
||||
if (!romfsReadFileEntryData(&(out->romfs_ctx), out->romfs_file_entry, out->data, sizeof(_NacpStruct), 0))
|
||||
{
|
||||
LOGFILE("Failed to read NACP data!");
|
||||
LOG_MSG("Failed to read NACP data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -275,14 +275,14 @@ bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx)
|
|||
/* Check icon size. */
|
||||
if (!icon_entry->size || icon_entry->size > NACP_MAX_ICON_SIZE)
|
||||
{
|
||||
LOGFILE("Invalid NACP icon size!");
|
||||
LOG_MSG("Invalid NACP icon size!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Reallocate icon context buffer. */
|
||||
if (!(tmp_icon_ctx = realloc(out->icon_ctx, (out->icon_count + 1) * sizeof(NacpIconContext))))
|
||||
{
|
||||
LOGFILE("Failed to reallocate NACP icon context buffer!");
|
||||
LOG_MSG("Failed to reallocate NACP icon context buffer!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -295,14 +295,14 @@ bool nacpInitializeContext(NacpContext *out, NcaContext *nca_ctx)
|
|||
/* Allocate memory for this icon data. */
|
||||
if (!(icon_ctx->icon_data = malloc(icon_entry->size)))
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for NACP icon data!");
|
||||
LOG_MSG("Failed to allocate memory for NACP icon data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read icon data. */
|
||||
if (!romfsReadFileEntryData(&(out->romfs_ctx), icon_entry, icon_ctx->icon_data, icon_entry->size, 0))
|
||||
{
|
||||
LOGFILE("Failed to read NACP icon data!");
|
||||
LOG_MSG("Failed to read NACP icon data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -333,7 +333,7 @@ bool nacpGenerateNcaPatch(NacpContext *nacp_ctx, bool patch_sua, bool patch_scre
|
|||
{
|
||||
if (!nacpIsValidContext(nacp_ctx))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -361,14 +361,14 @@ bool nacpGenerateNcaPatch(NacpContext *nacp_ctx, bool patch_sua, bool patch_scre
|
|||
sha256CalculateHash(nacp_hash, data, sizeof(_NacpStruct));
|
||||
if (!memcmp(nacp_hash, nacp_ctx->data_hash, sizeof(nacp_hash)))
|
||||
{
|
||||
LOGFILE("Skipping NACP patching - no flags have changed.");
|
||||
LOG_MSG("Skipping NACP patching - no flags have changed.");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Generate RomFS file entry patch. */
|
||||
if (!romfsGenerateFileEntryPatch(&(nacp_ctx->romfs_ctx), nacp_ctx->romfs_file_entry, data, sizeof(_NacpStruct), 0, &(nacp_ctx->nca_patch)))
|
||||
{
|
||||
LOGFILE("Failed to generate RomFS file entry patch!");
|
||||
LOG_MSG("Failed to generate RomFS file entry patch!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -393,7 +393,7 @@ void nacpWriteNcaPatch(NacpContext *nacp_ctx, void *buf, u64 buf_size, u64 buf_o
|
|||
if (nca_patch->written)
|
||||
{
|
||||
nca_ctx->content_type_ctx_patch = false;
|
||||
LOGFILE("NACP RomFS file entry patch successfully written to NCA \"%s\"!", nca_ctx->content_id_str);
|
||||
LOG_MSG("NACP RomFS file entry patch successfully written to NCA \"%s\"!", nca_ctx->content_id_str);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -401,7 +401,7 @@ bool nacpGenerateAuthoringToolXml(NacpContext *nacp_ctx, u32 version, u32 requir
|
|||
{
|
||||
if (!nacpIsValidContext(nacp_ctx))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -785,7 +785,7 @@ end:
|
|||
if (!success)
|
||||
{
|
||||
if (xml_buf) free(xml_buf);
|
||||
LOGFILE("Failed to generate NACP AuthoringTool XML!");
|
||||
LOG_MSG("Failed to generate NACP AuthoringTool XML!");
|
||||
}
|
||||
|
||||
return success;
|
||||
|
@ -930,7 +930,7 @@ static bool nacpAddStringFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_si
|
|||
{
|
||||
if (!xml_buf || !xml_buf_size || !tag_name || !*tag_name || !value)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -942,7 +942,7 @@ static bool nacpAddEnumFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size
|
|||
{
|
||||
if (!xml_buf || !xml_buf_size || !tag_name || !*tag_name || !str_func)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -958,7 +958,7 @@ static bool nacpAddBitflagFieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_s
|
|||
if (!xml_buf || !xml_buf_size || !tag_name || !*tag_name || !flag || !flag_width || (flag_width > 1 && !IS_POWER_OF_TWO(flag_width)) || flag_width > 0x10 || \
|
||||
(flag_bitcount = (flag_width * 8)) < max_flag_idx || !str_func)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -996,7 +996,7 @@ static bool nacpAddU16FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size,
|
|||
{
|
||||
if (!xml_buf || !xml_buf_size || !tag_name || !*tag_name)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1009,7 +1009,7 @@ static bool nacpAddU32FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size,
|
|||
{
|
||||
if (!xml_buf || !xml_buf_size || !tag_name || !*tag_name)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1022,7 +1022,7 @@ static bool nacpAddU64FieldToAuthoringToolXml(char **xml_buf, u64 *xml_buf_size,
|
|||
{
|
||||
if (!xml_buf || !xml_buf_size || !tag_name || !*tag_name)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
106
source/nca.c
106
source/nca.c
|
@ -86,7 +86,7 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
|
|||
if (!out || (storage_id != NcmStorageId_GameCard && !(ncm_storage = titleGetNcmStorageByStorageId(storage_id))) || \
|
||||
(storage_id == NcmStorageId_GameCard && hfs_partition_type >= GameCardHashFileSystemPartitionType_Count) || !content_info || content_info->content_type > NcmContentType_DeltaFragment)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
|
|||
titleConvertNcmContentSizeToU64(content_info->size, &(out->content_size));
|
||||
if (out->content_size < NCA_FULL_HEADER_LENGTH)
|
||||
{
|
||||
LOGFILE("Invalid size for NCA \"%s\"!", out->content_id_str);
|
||||
LOG_MSG("Invalid size for NCA \"%s\"!", out->content_id_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -118,9 +118,9 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
|
|||
char nca_filename[0x30] = {0};
|
||||
sprintf(nca_filename, "%s.%s", out->content_id_str, out->content_type == NcmContentType_Meta ? "cnmt.nca" : "nca");
|
||||
|
||||
if (!gamecardGetEntryInfoFromHashFileSystemPartitionByName(hfs_partition_type, nca_filename, &(out->gamecard_offset), NULL))
|
||||
if (!gamecardGetHashFileSystemEntryInfoByName(hfs_partition_type, nca_filename, &(out->gamecard_offset), NULL))
|
||||
{
|
||||
LOGFILE("Error retrieving offset for \"%s\" entry in secure hash FS partition!", nca_filename);
|
||||
LOG_MSG("Error retrieving offset for \"%s\" entry in secure hash FS partition!", nca_filename);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
|
|||
/* Read decrypted NCA header and NCA FS section headers. */
|
||||
if (!ncaReadDecryptedHeader(out))
|
||||
{
|
||||
LOGFILE("Failed to read decrypted NCA \"%s\" header!", out->content_id_str);
|
||||
LOG_MSG("Failed to read decrypted NCA \"%s\" header!", out->content_id_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,7 @@ bool ncaInitializeContext(NcaContext *out, u8 storage_id, u8 hfs_partition_type,
|
|||
memcpy(out->titlekey, usable_tik->dec_titlekey, 0x10);
|
||||
out->titlekey_retrieved = true;
|
||||
} else {
|
||||
LOGFILE("Error retrieving ticket for NCA \"%s\"!", out->content_id_str);
|
||||
LOG_MSG("Error retrieving ticket for NCA \"%s\"!", out->content_id_str);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,7 +247,7 @@ bool ncaReadContentFile(NcaContext *ctx, void *out, u64 read_size, u64 offset)
|
|||
if (!ctx || !*(ctx->content_id_str) || (ctx->storage_id != NcmStorageId_GameCard && !ctx->ncm_storage) || (ctx->storage_id == NcmStorageId_GameCard && !ctx->gamecard_offset) || !out || \
|
||||
!read_size || (offset + read_size) > ctx->content_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -260,12 +260,12 @@ bool ncaReadContentFile(NcaContext *ctx, void *out, u64 read_size, u64 offset)
|
|||
/* This strips NAX0 crypto from SD card NCAs (not used on eMMC NCAs). */
|
||||
rc = ncmContentStorageReadContentIdFile(ctx->ncm_storage, out, read_size, &(ctx->content_id), offset);
|
||||
ret = R_SUCCEEDED(rc);
|
||||
if (!ret) LOGFILE("Failed to read 0x%lX bytes block at offset 0x%lX from NCA \"%s\"! (0x%08X) (ncm).", read_size, offset, ctx->content_id_str, rc);
|
||||
if (!ret) LOG_MSG("Failed to read 0x%lX bytes block at offset 0x%lX from NCA \"%s\"! (0x%08X) (ncm).", read_size, offset, ctx->content_id_str, rc);
|
||||
} else {
|
||||
/* Retrieve NCA data using raw gamecard reads. */
|
||||
/* Fixes NCA read issues with gamecards under HOS < 4.0.0 when using ncmContentStorageReadContentIdFile(). */
|
||||
ret = gamecardReadStorage(out, read_size, ctx->gamecard_offset + offset);
|
||||
if (!ret) LOGFILE("Failed to read 0x%lX bytes block at offset 0x%lX from NCA \"%s\"! (gamecard).", read_size, offset, ctx->content_id_str);
|
||||
if (!ret) LOG_MSG("Failed to read 0x%lX bytes block at offset 0x%lX from NCA \"%s\"! (gamecard).", read_size, offset, ctx->content_id_str);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
@ -335,14 +335,14 @@ void ncaSetDownloadDistributionType(NcaContext *ctx)
|
|||
if (!ctx || ctx->content_size < NCA_FULL_HEADER_LENGTH || !*(ctx->content_id_str) || ctx->content_type > NcmContentType_DeltaFragment || \
|
||||
ctx->header.distribution_type == NcaDistributionType_Download) return;
|
||||
ctx->header.distribution_type = NcaDistributionType_Download;
|
||||
LOGFILE("Set download distribution type to %s NCA \"%s\".", titleGetNcmContentTypeName(ctx->content_type), ctx->content_id_str);
|
||||
LOG_MSG("Set download distribution type to %s NCA \"%s\".", titleGetNcmContentTypeName(ctx->content_type), ctx->content_id_str);
|
||||
}
|
||||
|
||||
bool ncaRemoveTitlekeyCrypto(NcaContext *ctx)
|
||||
{
|
||||
if (!ctx || ctx->content_size < NCA_FULL_HEADER_LENGTH || !*(ctx->content_id_str) || ctx->content_type > NcmContentType_DeltaFragment)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -364,7 +364,7 @@ bool ncaRemoveTitlekeyCrypto(NcaContext *ctx)
|
|||
/* Encrypt NCA key area. */
|
||||
if (!ncaEncryptKeyArea(ctx))
|
||||
{
|
||||
LOGFILE("Error encrypting %s NCA \"%s\" key area!", titleGetNcmContentTypeName(ctx->content_type), ctx->content_id_str);
|
||||
LOG_MSG("Error encrypting %s NCA \"%s\" key area!", titleGetNcmContentTypeName(ctx->content_type), ctx->content_id_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -374,7 +374,7 @@ bool ncaRemoveTitlekeyCrypto(NcaContext *ctx)
|
|||
/* Update context flags. */
|
||||
ctx->rights_id_available = false;
|
||||
|
||||
LOGFILE("Removed titlekey crypto from %s NCA \"%s\".", titleGetNcmContentTypeName(ctx->content_type), ctx->content_id_str);
|
||||
LOG_MSG("Removed titlekey crypto from %s NCA \"%s\".", titleGetNcmContentTypeName(ctx->content_type), ctx->content_id_str);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -383,7 +383,7 @@ bool ncaEncryptHeader(NcaContext *ctx)
|
|||
{
|
||||
if (!ctx || !*(ctx->content_id_str) || ctx->content_size < NCA_FULL_HEADER_LENGTH)
|
||||
{
|
||||
LOGFILE("Invalid NCA context!");
|
||||
LOG_MSG("Invalid NCA context!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -402,7 +402,7 @@ bool ncaEncryptHeader(NcaContext *ctx)
|
|||
crypt_res = aes128XtsNintendoCrypt(&hdr_aes_ctx, &(ctx->encrypted_header), &(ctx->header), sizeof(NcaHeader), 0, NCA_AES_XTS_SECTOR_SIZE, true);
|
||||
if (crypt_res != sizeof(NcaHeader))
|
||||
{
|
||||
LOGFILE("Error encrypting NCA \"%s\" header!", ctx->content_id_str);
|
||||
LOG_MSG("Error encrypting NCA \"%s\" header!", ctx->content_id_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -426,7 +426,7 @@ bool ncaEncryptHeader(NcaContext *ctx)
|
|||
crypt_res = aes128XtsNintendoCrypt(aes_xts_ctx, &(fs_ctx->encrypted_header), &(fs_ctx->header), sizeof(NcaFsHeader), sector, NCA_AES_XTS_SECTOR_SIZE, true);
|
||||
if (crypt_res != sizeof(NcaFsHeader))
|
||||
{
|
||||
LOGFILE("Error encrypting NCA%u \"%s\" FS section header #%u!", ctx->format_version, ctx->content_id_str, i);
|
||||
LOG_MSG("Error encrypting NCA%u \"%s\" FS section header #%u!", ctx->format_version, ctx->content_id_str, i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -511,7 +511,7 @@ static bool ncaReadDecryptedHeader(NcaContext *ctx)
|
|||
{
|
||||
if (!ctx || !*(ctx->content_id_str) || ctx->content_size < NCA_FULL_HEADER_LENGTH)
|
||||
{
|
||||
LOGFILE("Invalid NCA context!");
|
||||
LOG_MSG("Invalid NCA context!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -523,7 +523,7 @@ static bool ncaReadDecryptedHeader(NcaContext *ctx)
|
|||
/* Read NCA header. */
|
||||
if (!ncaReadContentFile(ctx, &(ctx->encrypted_header), sizeof(NcaHeader), 0))
|
||||
{
|
||||
LOGFILE("Failed to read NCA \"%s\" header!", ctx->content_id_str);
|
||||
LOG_MSG("Failed to read NCA \"%s\" header!", ctx->content_id_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -536,7 +536,7 @@ static bool ncaReadDecryptedHeader(NcaContext *ctx)
|
|||
|
||||
if (crypt_res != sizeof(NcaHeader) || (magic != NCA_NCA3_MAGIC && magic != NCA_NCA2_MAGIC && magic != NCA_NCA0_MAGIC) || ctx->header.content_size != ctx->content_size)
|
||||
{
|
||||
LOGFILE("Error decrypting NCA \"%s\" header!", ctx->content_id_str);
|
||||
LOG_MSG("Error decrypting NCA \"%s\" header!", ctx->content_id_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -549,7 +549,7 @@ static bool ncaReadDecryptedHeader(NcaContext *ctx)
|
|||
/* Decrypt NCA key area (if needed). */
|
||||
if (!ctx->rights_id_available && !ncaDecryptKeyArea(ctx))
|
||||
{
|
||||
LOGFILE("Error decrypting NCA \"%s\" key area!", ctx->content_id_str);
|
||||
LOG_MSG("Error decrypting NCA \"%s\" key area!", ctx->content_id_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -570,7 +570,7 @@ static bool ncaReadDecryptedHeader(NcaContext *ctx)
|
|||
u64 fs_header_offset = (ctx->format_version != NcaVersion_Nca0 ? (sizeof(NcaHeader) + (i * sizeof(NcaFsHeader))) : NCA_FS_SECTOR_OFFSET(fs_info->start_sector));
|
||||
if (!ncaReadContentFile(ctx, &(fs_ctx->encrypted_header), sizeof(NcaFsHeader), fs_header_offset))
|
||||
{
|
||||
LOGFILE("Failed to read NCA%u \"%s\" FS section header #%u at offset 0x%lX!", ctx->format_version, ctx->content_id_str, i, fs_header_offset);
|
||||
LOG_MSG("Failed to read NCA%u \"%s\" FS section header #%u at offset 0x%lX!", ctx->format_version, ctx->content_id_str, i, fs_header_offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -584,7 +584,7 @@ static bool ncaReadDecryptedHeader(NcaContext *ctx)
|
|||
crypt_res = aes128XtsNintendoCrypt(aes_xts_ctx, &(fs_ctx->header), &(fs_ctx->encrypted_header), sizeof(NcaFsHeader), sector, NCA_AES_XTS_SECTOR_SIZE, false);
|
||||
if (crypt_res != sizeof(NcaFsHeader))
|
||||
{
|
||||
LOGFILE("Error decrypting NCA%u \"%s\" FS section header #%u!", ctx->format_version, ctx->content_id_str, i);
|
||||
LOG_MSG("Error decrypting NCA%u \"%s\" FS section header #%u!", ctx->format_version, ctx->content_id_str, i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -596,7 +596,7 @@ static bool ncaDecryptKeyArea(NcaContext *ctx)
|
|||
{
|
||||
if (!ctx)
|
||||
{
|
||||
LOGFILE("Invalid NCA context!");
|
||||
LOG_MSG("Invalid NCA context!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -614,14 +614,14 @@ static bool ncaDecryptKeyArea(NcaContext *ctx)
|
|||
kek_src = keysGetKeyAreaEncryptionKeySource(ctx->header.kaek_index);
|
||||
if (!kek_src)
|
||||
{
|
||||
LOGFILE("Unable to retrieve KAEK source for index 0x%02X!", ctx->header.kaek_index);
|
||||
LOG_MSG("Unable to retrieve KAEK source for index 0x%02X!", ctx->header.kaek_index);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = splCryptoGenerateAesKek(kek_src, ctx->key_generation, 0, tmp_kek);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("splCryptoGenerateAesKek failed! (0x%08X).", rc);
|
||||
LOG_MSG("splCryptoGenerateAesKek failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -632,7 +632,7 @@ static bool ncaDecryptKeyArea(NcaContext *ctx)
|
|||
rc = splCryptoGenerateAesKey(tmp_kek, (u8*)&(ctx->header.encrypted_key_area) + (i * AES_128_KEY_SIZE), (u8*)&(ctx->decrypted_key_area) + (i * AES_128_KEY_SIZE));
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("splCryptoGenerateAesKey failed to decrypt NCA key area entry #%u! (0x%08X).", i, rc);
|
||||
LOG_MSG("splCryptoGenerateAesKey failed to decrypt NCA key area entry #%u! (0x%08X).", i, rc);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -644,7 +644,7 @@ static bool ncaEncryptKeyArea(NcaContext *ctx)
|
|||
{
|
||||
if (!ctx)
|
||||
{
|
||||
LOGFILE("Invalid NCA context!");
|
||||
LOG_MSG("Invalid NCA context!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -662,7 +662,7 @@ static bool ncaEncryptKeyArea(NcaContext *ctx)
|
|||
kaek = keysGetKeyAreaEncryptionKey(ctx->key_generation, ctx->header.kaek_index);
|
||||
if (!kaek)
|
||||
{
|
||||
LOGFILE("Unable to retrieve KAEK for key generation 0x%02X and KAEK index 0x%02X!", ctx->key_generation, ctx->header.kaek_index);
|
||||
LOG_MSG("Unable to retrieve KAEK for key generation 0x%02X and KAEK index 0x%02X!", ctx->key_generation, ctx->header.kaek_index);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -719,7 +719,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
|||
ctx->section_type >= NcaFsSectionType_Invalid || ctx->encryption_type == NcaEncryptionType_Auto || ctx->encryption_type > NcaEncryptionType_AesCtrEx || !out || !read_size || \
|
||||
(offset + read_size) > ctx->section_size)
|
||||
{
|
||||
LOGFILE("Invalid NCA FS section header parameters!");
|
||||
LOG_MSG("Invalid NCA FS section header parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -735,7 +735,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
|||
if (!*(nca_ctx->content_id_str) || (nca_ctx->storage_id != NcmStorageId_GameCard && !nca_ctx->ncm_storage) || (nca_ctx->storage_id == NcmStorageId_GameCard && !nca_ctx->gamecard_offset) || \
|
||||
(nca_ctx->format_version != NcaVersion_Nca0 && nca_ctx->format_version != NcaVersion_Nca2 && nca_ctx->format_version != NcaVersion_Nca3) || (content_offset + read_size) > nca_ctx->content_size)
|
||||
{
|
||||
LOGFILE("Invalid NCA header parameters!");
|
||||
LOG_MSG("Invalid NCA header parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -747,7 +747,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
|||
/* Read data. */
|
||||
if (!ncaReadContentFile(nca_ctx, out, read_size, content_offset))
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", read_size, content_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
LOG_MSG("Failed to read 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", read_size, content_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -766,7 +766,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
|||
crypt_res = aes128XtsNintendoCrypt(&(ctx->xts_decrypt_ctx), out, out, read_size, sector_num, NCA_AES_XTS_SECTOR_SIZE, false);
|
||||
if (crypt_res != read_size)
|
||||
{
|
||||
LOGFILE("Failed to AES-XTS decrypt 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", read_size, content_offset, nca_ctx->content_id_str, \
|
||||
LOG_MSG("Failed to AES-XTS decrypt 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", read_size, content_offset, nca_ctx->content_id_str, \
|
||||
ctx->section_num);
|
||||
goto end;
|
||||
}
|
||||
|
@ -794,7 +794,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
|||
/* Read data. */
|
||||
if (!ncaReadContentFile(nca_ctx, g_ncaCryptoBuffer, chunk_size, block_start_offset))
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes encrypted data block at offset 0x%lX from NCA \"%s\" FS section #%u! (unaligned).", chunk_size, block_start_offset, nca_ctx->content_id_str, \
|
||||
LOG_MSG("Failed to read 0x%lX bytes encrypted data block at offset 0x%lX from NCA \"%s\" FS section #%u! (unaligned).", chunk_size, block_start_offset, nca_ctx->content_id_str, \
|
||||
ctx->section_num);
|
||||
goto end;
|
||||
}
|
||||
|
@ -807,7 +807,7 @@ static bool _ncaReadFsSection(NcaFsSectionContext *ctx, void *out, u64 read_size
|
|||
crypt_res = aes128XtsNintendoCrypt(&(ctx->xts_decrypt_ctx), g_ncaCryptoBuffer, g_ncaCryptoBuffer, chunk_size, sector_num, NCA_AES_XTS_SECTOR_SIZE, false);
|
||||
if (crypt_res != chunk_size)
|
||||
{
|
||||
LOGFILE("Failed to AES-XTS decrypt 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (unaligned).", chunk_size, block_start_offset, nca_ctx->content_id_str, \
|
||||
LOG_MSG("Failed to AES-XTS decrypt 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (unaligned).", chunk_size, block_start_offset, nca_ctx->content_id_str, \
|
||||
ctx->section_num);
|
||||
goto end;
|
||||
}
|
||||
|
@ -839,7 +839,7 @@ static bool _ncaReadAesCtrExStorageFromBktrSection(NcaFsSectionContext *ctx, voi
|
|||
if (!g_ncaCryptoBuffer || !ctx || !ctx->enabled || !ctx->nca_ctx || ctx->section_num >= NCA_FS_HEADER_COUNT || ctx->section_offset < sizeof(NcaHeader) || \
|
||||
ctx->section_type != NcaFsSectionType_PatchRomFs || ctx->encryption_type != NcaEncryptionType_AesCtrEx || !out || !read_size || (offset + read_size) > ctx->section_size)
|
||||
{
|
||||
LOGFILE("Invalid NCA FS section header parameters!");
|
||||
LOG_MSG("Invalid NCA FS section header parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -852,7 +852,7 @@ static bool _ncaReadAesCtrExStorageFromBktrSection(NcaFsSectionContext *ctx, voi
|
|||
if (!*(nca_ctx->content_id_str) || (nca_ctx->storage_id != NcmStorageId_GameCard && !nca_ctx->ncm_storage) || (nca_ctx->storage_id == NcmStorageId_GameCard && !nca_ctx->gamecard_offset) || \
|
||||
(content_offset + read_size) > nca_ctx->content_size)
|
||||
{
|
||||
LOGFILE("Invalid NCA header parameters!");
|
||||
LOG_MSG("Invalid NCA header parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -862,7 +862,7 @@ static bool _ncaReadAesCtrExStorageFromBktrSection(NcaFsSectionContext *ctx, voi
|
|||
/* Read data. */
|
||||
if (!ncaReadContentFile(nca_ctx, out, read_size, content_offset))
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", read_size, content_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
LOG_MSG("Failed to read 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", read_size, content_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -887,7 +887,7 @@ static bool _ncaReadAesCtrExStorageFromBktrSection(NcaFsSectionContext *ctx, voi
|
|||
/* Read data. */
|
||||
if (!ncaReadContentFile(nca_ctx, g_ncaCryptoBuffer, chunk_size, block_start_offset))
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes encrypted data block at offset 0x%lX from NCA \"%s\" FS section #%u! (unaligned).", chunk_size, block_start_offset, nca_ctx->content_id_str, \
|
||||
LOG_MSG("Failed to read 0x%lX bytes encrypted data block at offset 0x%lX from NCA \"%s\" FS section #%u! (unaligned).", chunk_size, block_start_offset, nca_ctx->content_id_str, \
|
||||
ctx->section_num);
|
||||
goto end;
|
||||
}
|
||||
|
@ -935,7 +935,7 @@ static bool ncaGenerateHashDataPatch(NcaFsSectionContext *ctx, const void *data,
|
|||
!(last_layer_size = ctx->header.hash_data.integrity_meta_info.info_level_hash.level_information[NCA_IVFC_LEVEL_COUNT - 1].size))) || !data || !data_size || \
|
||||
(data_offset + data_size) > last_layer_size || !out)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -985,7 +985,7 @@ static bool ncaGenerateHashDataPatch(NcaFsSectionContext *ctx, const void *data,
|
|||
if (hash_block_size <= 1 || !cur_layer_size || (cur_layer_offset + cur_layer_size) > ctx->section_size || (i > 1 && (!parent_layer_size || \
|
||||
(parent_layer_offset + parent_layer_size) > ctx->section_size)))
|
||||
{
|
||||
LOGFILE("Invalid hierarchical parent/child layer!");
|
||||
LOG_MSG("Invalid hierarchical parent/child layer!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1016,7 +1016,7 @@ static bool ncaGenerateHashDataPatch(NcaFsSectionContext *ctx, const void *data,
|
|||
cur_layer_block = calloc(cur_layer_read_size, sizeof(u8));
|
||||
if (!cur_layer_block)
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes for hierarchical layer #%u data block! (current).", cur_layer_read_size, i - 1);
|
||||
LOG_MSG("Unable to allocate 0x%lX bytes for hierarchical layer #%u data block! (current).", cur_layer_read_size, i - 1);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1030,7 +1030,7 @@ static bool ncaGenerateHashDataPatch(NcaFsSectionContext *ctx, const void *data,
|
|||
/* Read current layer block. */
|
||||
if (!_ncaReadFsSection(ctx, cur_layer_block, cur_layer_read_size, cur_layer_read_start_offset, false))
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes long hierarchical layer #%u data block from offset 0x%lX! (current).", cur_layer_read_size, i - 1, cur_layer_read_start_offset);
|
||||
LOG_MSG("Failed to read 0x%lX bytes long hierarchical layer #%u data block from offset 0x%lX! (current).", cur_layer_read_size, i - 1, cur_layer_read_start_offset);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1044,14 +1044,14 @@ static bool ncaGenerateHashDataPatch(NcaFsSectionContext *ctx, const void *data,
|
|||
parent_layer_block = calloc(parent_layer_read_size, sizeof(u8));
|
||||
if (!parent_layer_block)
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes for hierarchical layer #%u data block! (parent).", parent_layer_read_size, i - 2);
|
||||
LOG_MSG("Unable to allocate 0x%lX bytes for hierarchical layer #%u data block! (parent).", parent_layer_read_size, i - 2);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read parent layer block. */
|
||||
if (!_ncaReadFsSection(ctx, parent_layer_block, parent_layer_read_size, parent_layer_offset + parent_layer_read_start_offset, false))
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes long hierarchical layer #%u data block from offset 0x%lX! (parent).", parent_layer_read_size, i - 2, parent_layer_read_start_offset);
|
||||
LOG_MSG("Failed to read 0x%lX bytes long hierarchical layer #%u data block from offset 0x%lX! (parent).", parent_layer_read_size, i - 2, parent_layer_read_start_offset);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1074,7 +1074,7 @@ static bool ncaGenerateHashDataPatch(NcaFsSectionContext *ctx, const void *data,
|
|||
&(cur_layer_patch->size), &(cur_layer_patch->offset), false);
|
||||
if (!cur_layer_patch->data)
|
||||
{
|
||||
LOGFILE("Failed to generate encrypted 0x%lX bytes long hierarchical layer #%u data block!", cur_data_size, i - 1);
|
||||
LOG_MSG("Failed to generate encrypted 0x%lX bytes long hierarchical layer #%u data block!", cur_data_size, i - 1);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1143,7 +1143,7 @@ static bool ncaWritePatchToMemoryBuffer(NcaContext *ctx, const void *patch, u64
|
|||
|
||||
memcpy((u8*)buf + buf_block_offset, (const u8*)patch + patch_block_offset, buf_block_size);
|
||||
|
||||
LOGFILE("Overwrote 0x%lX bytes block at offset 0x%lX from raw %s NCA \"%s\" buffer (size 0x%lX, NCA offset 0x%lX).", buf_block_size, buf_block_offset, titleGetNcmContentTypeName(ctx->content_type), \
|
||||
LOG_MSG("Overwrote 0x%lX bytes block at offset 0x%lX from raw %s NCA \"%s\" buffer (size 0x%lX, NCA offset 0x%lX).", buf_block_size, buf_block_offset, titleGetNcmContentTypeName(ctx->content_type), \
|
||||
ctx->content_id_str, buf_size, buf_offset);
|
||||
|
||||
return ((patch_block_offset + buf_block_size) == patch_size);
|
||||
|
@ -1160,7 +1160,7 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
ctx->section_type >= NcaFsSectionType_Invalid || ctx->encryption_type == NcaEncryptionType_Auto || ctx->encryption_type >= NcaEncryptionType_AesCtrEx || !data || !data_size || \
|
||||
(data_offset + data_size) > ctx->section_size || !out_block_size || !out_block_offset)
|
||||
{
|
||||
LOGFILE("Invalid NCA FS section header parameters!");
|
||||
LOG_MSG("Invalid NCA FS section header parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1176,7 +1176,7 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
if (!*(nca_ctx->content_id_str) || (nca_ctx->storage_id != NcmStorageId_GameCard && !nca_ctx->ncm_storage) || (nca_ctx->storage_id == NcmStorageId_GameCard && !nca_ctx->gamecard_offset) || \
|
||||
(nca_ctx->format_version != NcaVersion_Nca0 && nca_ctx->format_version != NcaVersion_Nca2 && nca_ctx->format_version != NcaVersion_Nca3) || (content_offset + data_size) > nca_ctx->content_size)
|
||||
{
|
||||
LOGFILE("Invalid NCA header parameters!");
|
||||
LOG_MSG("Invalid NCA header parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1189,7 +1189,7 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
out = malloc(data_size);
|
||||
if (!out)
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes buffer! (aligned).", data_size);
|
||||
LOG_MSG("Unable to allocate 0x%lX bytes buffer! (aligned).", data_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1204,7 +1204,7 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
crypt_res = aes128XtsNintendoCrypt(&(ctx->xts_encrypt_ctx), out, out, data_size, sector_num, NCA_AES_XTS_SECTOR_SIZE, true);
|
||||
if (crypt_res != data_size)
|
||||
{
|
||||
LOGFILE("Failed to AES-XTS encrypt 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", data_size, content_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
LOG_MSG("Failed to AES-XTS encrypt 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", data_size, content_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
goto end;
|
||||
}
|
||||
} else
|
||||
|
@ -1234,14 +1234,14 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
out = malloc(block_size);
|
||||
if (!out)
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes buffer! (unaligned).", block_size);
|
||||
LOG_MSG("Unable to allocate 0x%lX bytes buffer! (unaligned).", block_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read decrypted data using aligned offset and size. */
|
||||
if (!_ncaReadFsSection(ctx, out, block_size, block_start_offset, false))
|
||||
{
|
||||
LOGFILE("Failed to read decrypted NCA \"%s\" FS section #%u data block!", nca_ctx->content_id_str, ctx->section_num);
|
||||
LOG_MSG("Failed to read decrypted NCA \"%s\" FS section #%u data block!", nca_ctx->content_id_str, ctx->section_num);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1256,7 +1256,7 @@ static void *_ncaGenerateEncryptedFsSectionBlock(NcaFsSectionContext *ctx, const
|
|||
crypt_res = aes128XtsNintendoCrypt(&(ctx->xts_encrypt_ctx), out, out, block_size, sector_num, NCA_AES_XTS_SECTOR_SIZE, true);
|
||||
if (crypt_res != block_size)
|
||||
{
|
||||
LOGFILE("Failed to AES-XTS encrypt 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", block_size, content_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
LOG_MSG("Failed to AES-XTS encrypt 0x%lX bytes data block at offset 0x%lX from NCA \"%s\" FS section #%u! (aligned).", block_size, content_offset, nca_ctx->content_id_str, ctx->section_num);
|
||||
goto end;
|
||||
}
|
||||
} else
|
||||
|
|
|
@ -26,12 +26,12 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
{
|
||||
NcaContext *nca_ctx = NULL;
|
||||
u64 cur_offset = 0;
|
||||
bool success = false;
|
||||
bool success = false, dump_meta_header = false, dump_acid_header = false, dump_aci_header = false;
|
||||
|
||||
if (!out || !pfs_ctx || !pfs_ctx->nca_fs_ctx || !(nca_ctx = (NcaContext*)pfs_ctx->nca_fs_ctx->nca_ctx) || nca_ctx->content_type != NcmContentType_Program || !pfs_ctx->offset || !pfs_ctx->size || \
|
||||
!pfs_ctx->is_exefs || pfs_ctx->header_size <= sizeof(PartitionFileSystemHeader) || !pfs_ctx->header)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -43,16 +43,16 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
out->pfs_ctx = pfs_ctx;
|
||||
if (!(out->pfs_entry = pfsGetEntryByName(out->pfs_ctx, "main.npdm")))
|
||||
{
|
||||
LOGFILE("'main.npdm' entry unavailable in ExeFS!");
|
||||
LOG_MSG("'main.npdm' entry unavailable in ExeFS!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
//LOGFILE("Found 'main.npdm' entry in Program NCA \"%s\".", nca_ctx->content_id_str);
|
||||
//LOG_MSG("Found 'main.npdm' entry in Program NCA \"%s\".", nca_ctx->content_id_str);
|
||||
|
||||
/* Check raw NPDM size. */
|
||||
if (!out->pfs_entry->size)
|
||||
{
|
||||
LOGFILE("Invalid raw NPDM size!");
|
||||
LOG_MSG("Invalid raw NPDM size!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -60,14 +60,14 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
out->raw_data_size = out->pfs_entry->size;
|
||||
if (!(out->raw_data = malloc(out->raw_data_size)))
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for the raw NPDM data!");
|
||||
LOG_MSG("Failed to allocate memory for the raw NPDM data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read raw NPDM data into memory buffer. */
|
||||
if (!pfsReadEntryData(out->pfs_ctx, out->pfs_entry, out->raw_data, out->raw_data_size, 0))
|
||||
{
|
||||
LOGFILE("Failed to read raw NPDM data!");
|
||||
LOG_MSG("Failed to read raw NPDM data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -77,50 +77,58 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
|
||||
if (__builtin_bswap32(out->meta_header->magic) != NPDM_META_MAGIC)
|
||||
{
|
||||
LOGFILE("Invalid meta header magic word! (0x%08X != 0x%08X).", __builtin_bswap32(out->meta_header->magic), __builtin_bswap32(NPDM_META_MAGIC));
|
||||
LOG_MSG("Invalid meta header magic word! (0x%08X != 0x%08X).", __builtin_bswap32(out->meta_header->magic), __builtin_bswap32(NPDM_META_MAGIC));
|
||||
dump_meta_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!out->meta_header->flags.is_64bit_instruction && (out->meta_header->flags.process_address_space == NpdmProcessAddressSpace_AddressSpace64BitOld || \
|
||||
out->meta_header->flags.process_address_space == NpdmProcessAddressSpace_AddressSpace64Bit))
|
||||
{
|
||||
LOGFILE("Invalid meta header flags! (0x%02X).", *((u8*)&(out->meta_header->flags)));
|
||||
LOG_MSG("Invalid meta header flags! (0x%02X).", *((u8*)&(out->meta_header->flags)));
|
||||
dump_meta_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->meta_header->main_thread_priority > NPDM_MAIN_THREAD_MAX_PRIORITY)
|
||||
{
|
||||
LOGFILE("Invalid main thread priority! (0x%02X).", out->meta_header->main_thread_priority);
|
||||
LOG_MSG("Invalid main thread priority! (0x%02X).", out->meta_header->main_thread_priority);
|
||||
dump_meta_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->meta_header->main_thread_core_number > NPDM_MAIN_THREAD_MAX_CORE_NUMBER)
|
||||
{
|
||||
LOGFILE("Invalid main thread core number! (%u).", out->meta_header->main_thread_core_number);
|
||||
LOG_MSG("Invalid main thread core number! (%u).", out->meta_header->main_thread_core_number);
|
||||
dump_meta_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->meta_header->system_resource_size > NPDM_SYSTEM_RESOURCE_MAX_SIZE)
|
||||
{
|
||||
LOGFILE("Invalid system resource size! (0x%08X).", out->meta_header->system_resource_size);
|
||||
LOG_MSG("Invalid system resource size! (0x%08X).", out->meta_header->system_resource_size);
|
||||
dump_meta_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!IS_ALIGNED(out->meta_header->main_thread_stack_size, NPDM_MAIN_THREAD_STACK_SIZE_ALIGNMENT))
|
||||
{
|
||||
LOGFILE("Invalid main thread stack size! (0x%08X).", out->meta_header->main_thread_stack_size);
|
||||
LOG_MSG("Invalid main thread stack size! (0x%08X).", out->meta_header->main_thread_stack_size);
|
||||
dump_meta_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->meta_header->aci_offset < sizeof(NpdmMetaHeader) || out->meta_header->aci_size < sizeof(NpdmAciHeader) || (out->meta_header->aci_offset + out->meta_header->aci_size) > out->raw_data_size)
|
||||
{
|
||||
LOGFILE("Invalid ACI0 offset/size! (0x%08X, 0x%08X).", out->meta_header->aci_offset, out->meta_header->aci_size);
|
||||
LOG_MSG("Invalid ACI0 offset/size! (0x%08X, 0x%08X).", out->meta_header->aci_offset, out->meta_header->aci_size);
|
||||
dump_meta_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->meta_header->acid_offset < sizeof(NpdmMetaHeader) || out->meta_header->acid_size < sizeof(NpdmAcidHeader) || (out->meta_header->acid_offset + out->meta_header->acid_size) > out->raw_data_size)
|
||||
{
|
||||
LOGFILE("Invalid ACID offset/size! (0x%08X, 0x%08X).", out->meta_header->acid_offset, out->meta_header->acid_size);
|
||||
LOG_MSG("Invalid ACID offset/size! (0x%08X, 0x%08X).", out->meta_header->acid_offset, out->meta_header->acid_size);
|
||||
dump_meta_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -128,7 +136,8 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
(out->meta_header->aci_offset > out->meta_header->acid_offset && out->meta_header->aci_offset < (out->meta_header->acid_offset + out->meta_header->acid_size)) || \
|
||||
(out->meta_header->acid_offset > out->meta_header->aci_offset && out->meta_header->acid_offset < (out->meta_header->aci_offset + out->meta_header->aci_size)))
|
||||
{
|
||||
LOGFILE("ACI0/ACID sections overlap! (0x%08X, 0x%08X | 0x%08X, 0x%08X).", out->meta_header->aci_offset, out->meta_header->aci_size, out->meta_header->acid_offset, out->meta_header->acid_size);
|
||||
LOG_MSG("ACI0/ACID sections overlap! (0x%08X, 0x%08X | 0x%08X, 0x%08X).", out->meta_header->aci_offset, out->meta_header->aci_size, out->meta_header->acid_offset, out->meta_header->acid_size);
|
||||
dump_meta_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -138,26 +147,30 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
|
||||
if (__builtin_bswap32(out->acid_header->magic) != NPDM_ACID_MAGIC)
|
||||
{
|
||||
LOGFILE("Invalid ACID header magic word! (0x%08X != 0x%08X).", __builtin_bswap32(out->acid_header->magic), __builtin_bswap32(NPDM_ACID_MAGIC));
|
||||
LOG_MSG("Invalid ACID header magic word! (0x%08X != 0x%08X).", __builtin_bswap32(out->acid_header->magic), __builtin_bswap32(NPDM_ACID_MAGIC));
|
||||
dump_meta_header = dump_acid_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->acid_header->size != (out->meta_header->acid_size - sizeof(out->acid_header->signature)))
|
||||
{
|
||||
LOGFILE("Invalid ACID header size! (0x%08X).", out->acid_header->size);
|
||||
LOG_MSG("Invalid ACID header size! (0x%08X).", out->acid_header->size);
|
||||
dump_meta_header = dump_acid_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->acid_header->program_id_min > out->acid_header->program_id_max)
|
||||
{
|
||||
LOGFILE("Invalid ACID program ID range! (%016lX - %016lX).", out->acid_header->program_id_min, out->acid_header->program_id_max);
|
||||
LOG_MSG("Invalid ACID program ID range! (%016lX - %016lX).", out->acid_header->program_id_min, out->acid_header->program_id_max);
|
||||
dump_meta_header = dump_acid_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->acid_header->fs_access_control_offset < sizeof(NpdmAcidHeader) || out->acid_header->fs_access_control_size < sizeof(NpdmFsAccessControlDescriptor) || \
|
||||
(out->acid_header->fs_access_control_offset + out->acid_header->fs_access_control_size) > out->meta_header->acid_size)
|
||||
{
|
||||
LOGFILE("Invalid ACID FsAccessControl offset/size! (0x%08X, 0x%08X).", out->acid_header->fs_access_control_offset, out->acid_header->fs_access_control_size);
|
||||
LOG_MSG("Invalid ACID FsAccessControl offset/size! (0x%08X, 0x%08X).", out->acid_header->fs_access_control_offset, out->acid_header->fs_access_control_size);
|
||||
dump_meta_header = dump_acid_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -168,7 +181,8 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
if (out->acid_header->srv_access_control_offset < sizeof(NpdmAcidHeader) || \
|
||||
(out->acid_header->srv_access_control_offset + out->acid_header->srv_access_control_size) > out->meta_header->acid_size)
|
||||
{
|
||||
LOGFILE("Invalid ACID SrvAccessControl offset/size! (0x%08X, 0x%08X).", out->acid_header->srv_access_control_offset, out->acid_header->srv_access_control_size);
|
||||
LOG_MSG("Invalid ACID SrvAccessControl offset/size! (0x%08X, 0x%08X).", out->acid_header->srv_access_control_offset, out->acid_header->srv_access_control_size);
|
||||
dump_meta_header = dump_acid_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -181,7 +195,8 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
out->acid_header->kernel_capability_offset < sizeof(NpdmAcidHeader) || \
|
||||
(out->acid_header->kernel_capability_offset + out->acid_header->kernel_capability_size) > out->meta_header->acid_size)
|
||||
{
|
||||
LOGFILE("Invalid ACID KernelCapability offset/size! (0x%08X, 0x%08X).", out->acid_header->kernel_capability_offset, out->acid_header->kernel_capability_size);
|
||||
LOG_MSG("Invalid ACID KernelCapability offset/size! (0x%08X, 0x%08X).", out->acid_header->kernel_capability_offset, out->acid_header->kernel_capability_size);
|
||||
dump_meta_header = dump_acid_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -194,26 +209,30 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
|
||||
if (__builtin_bswap32(out->aci_header->magic) != NPDM_ACI0_MAGIC)
|
||||
{
|
||||
LOGFILE("Invalid ACI0 header magic word! (0x%08X != 0x%08X).", __builtin_bswap32(out->aci_header->magic), __builtin_bswap32(NPDM_ACI0_MAGIC));
|
||||
LOG_MSG("Invalid ACI0 header magic word! (0x%08X != 0x%08X).", __builtin_bswap32(out->aci_header->magic), __builtin_bswap32(NPDM_ACI0_MAGIC));
|
||||
dump_meta_header = dump_acid_header = dump_aci_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->aci_header->program_id != nca_ctx->header.program_id)
|
||||
{
|
||||
LOGFILE("ACI0 program ID mismatch! (%016lX != %016lX).", out->aci_header->program_id, nca_ctx->header.program_id);
|
||||
LOG_MSG("ACI0 program ID mismatch! (%016lX != %016lX).", out->aci_header->program_id, nca_ctx->header.program_id);
|
||||
dump_meta_header = dump_acid_header = dump_aci_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->aci_header->program_id < out->acid_header->program_id_min || out->aci_header->program_id > out->acid_header->program_id_max)
|
||||
{
|
||||
LOGFILE("ACI0 program ID out of ACID program ID range! (%016lX, %016lX - %016lX).", out->aci_header->program_id, out->acid_header->program_id_min, out->acid_header->program_id_max);
|
||||
LOG_MSG("ACI0 program ID out of ACID program ID range! (%016lX, %016lX - %016lX).", out->aci_header->program_id, out->acid_header->program_id_min, out->acid_header->program_id_max);
|
||||
dump_meta_header = dump_acid_header = dump_aci_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->aci_header->fs_access_control_offset < sizeof(NpdmAciHeader) || out->aci_header->fs_access_control_size < sizeof(NpdmFsAccessControlData) || \
|
||||
(out->aci_header->fs_access_control_offset + out->aci_header->fs_access_control_size) > out->meta_header->aci_size)
|
||||
{
|
||||
LOGFILE("Invalid ACI0 FsAccessControl offset/size! (0x%08X, 0x%08X).", out->aci_header->fs_access_control_offset, out->aci_header->fs_access_control_size);
|
||||
LOG_MSG("Invalid ACI0 FsAccessControl offset/size! (0x%08X, 0x%08X).", out->aci_header->fs_access_control_offset, out->aci_header->fs_access_control_size);
|
||||
dump_meta_header = dump_acid_header = dump_aci_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -224,7 +243,8 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
if (out->aci_header->srv_access_control_offset < sizeof(NpdmAciHeader) || \
|
||||
(out->aci_header->srv_access_control_offset + out->aci_header->srv_access_control_size) > out->meta_header->aci_size)
|
||||
{
|
||||
LOGFILE("Invalid ACI0 SrvAccessControl offset/size! (0x%08X, 0x%08X).", out->aci_header->srv_access_control_offset, out->aci_header->srv_access_control_size);
|
||||
LOG_MSG("Invalid ACI0 SrvAccessControl offset/size! (0x%08X, 0x%08X).", out->aci_header->srv_access_control_offset, out->aci_header->srv_access_control_size);
|
||||
dump_meta_header = dump_acid_header = dump_aci_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -237,7 +257,8 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
out->aci_header->kernel_capability_offset < sizeof(NpdmAciHeader) || \
|
||||
(out->aci_header->kernel_capability_offset + out->aci_header->kernel_capability_size) > out->meta_header->aci_size)
|
||||
{
|
||||
LOGFILE("Invalid ACI0 KernelCapability offset/size! (0x%08X, 0x%08X).", out->aci_header->kernel_capability_offset, out->aci_header->kernel_capability_size);
|
||||
LOG_MSG("Invalid ACI0 KernelCapability offset/size! (0x%08X, 0x%08X).", out->aci_header->kernel_capability_offset, out->aci_header->kernel_capability_size);
|
||||
dump_meta_header = dump_acid_header = dump_aci_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -247,14 +268,21 @@ bool npdmInitializeContext(NpdmContext *out, PartitionFileSystemContext *pfs_ctx
|
|||
/* Safety check: verify raw NPDM size. */
|
||||
if (out->raw_data_size < cur_offset)
|
||||
{
|
||||
LOGFILE("Invalid raw NPDM size! (0x%lX < 0x%lX).", out->raw_data_size, cur_offset);
|
||||
LOG_MSG("Invalid raw NPDM size! (0x%lX < 0x%lX).", out->raw_data_size, cur_offset);
|
||||
goto end;
|
||||
}
|
||||
|
||||
success = true;
|
||||
|
||||
end:
|
||||
if (!success) npdmFreeContext(out);
|
||||
if (!success)
|
||||
{
|
||||
if (dump_aci_header) LOG_DATA(out->aci_header, sizeof(NpdmAciHeader), "NPDM ACI0 Header dump:");
|
||||
if (dump_acid_header) LOG_DATA(out->acid_header, sizeof(NpdmAcidHeader), "NPDM ACID Header dump:");
|
||||
if (dump_meta_header) LOG_DATA(out->meta_header, sizeof(NpdmMetaHeader), "NPDM Meta Header dump:");
|
||||
|
||||
npdmFreeContext(out);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
@ -263,7 +291,7 @@ bool npdmGenerateNcaPatch(NpdmContext *npdm_ctx)
|
|||
{
|
||||
if (!npdmIsValidContext(npdm_ctx) || npdm_ctx->nca_ctx->content_type != NcmContentType_Program)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -272,7 +300,7 @@ bool npdmGenerateNcaPatch(NpdmContext *npdm_ctx)
|
|||
/* Check if we really need to generate this patch. */
|
||||
if (!ncaIsHeaderDirty(nca_ctx))
|
||||
{
|
||||
LOGFILE("Skipping NPDM patching - NCA header hasn't been modified.");
|
||||
LOG_MSG("Skipping NPDM patching - NCA header hasn't been modified.");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -282,14 +310,14 @@ bool npdmGenerateNcaPatch(NpdmContext *npdm_ctx)
|
|||
/* Generate Partition FS entry patch. */
|
||||
if (!pfsGenerateEntryPatch(npdm_ctx->pfs_ctx, npdm_ctx->pfs_entry, npdm_ctx->raw_data, npdm_ctx->raw_data_size, 0, &(npdm_ctx->nca_patch)))
|
||||
{
|
||||
LOGFILE("Failed to generate Partition FS entry patch!");
|
||||
LOG_MSG("Failed to generate Partition FS entry patch!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Update NCA ACID signature. */
|
||||
if (!rsa2048GenerateSha256BasedPssSignature(nca_ctx->header.acid_signature, &(nca_ctx->header.magic), NCA_ACID_SIGNATURE_AREA_SIZE))
|
||||
{
|
||||
LOGFILE("Failed to generate RSA-2048-PSS NCA ACID signature!");
|
||||
LOG_MSG("Failed to generate RSA-2048-PSS NCA ACID signature!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -314,6 +342,6 @@ void npdmWriteNcaPatch(NpdmContext *npdm_ctx, void *buf, u64 buf_size, u64 buf_o
|
|||
if (nca_patch->written)
|
||||
{
|
||||
nca_ctx->content_type_ctx_patch = false;
|
||||
LOGFILE("NPDM Partition FS entry patch successfully written to NCA \"%s\"!", nca_ctx->content_id_str);
|
||||
LOG_MSG("NPDM Partition FS entry patch successfully written to NCA \"%s\"!", nca_ctx->content_id_str);
|
||||
}
|
||||
}
|
||||
|
|
69
source/nso.c
69
source/nso.c
|
@ -35,12 +35,12 @@ bool nsoInitializeContext(NsoContext *out, PartitionFileSystemContext *pfs_ctx,
|
|||
{
|
||||
NcaContext *nca_ctx = NULL;
|
||||
u8 *rodata_buf = NULL;
|
||||
bool success = false;
|
||||
bool success = false, dump_nso_header = false;
|
||||
|
||||
if (!out || !pfs_ctx || !pfs_ctx->nca_fs_ctx || !(nca_ctx = (NcaContext*)pfs_ctx->nca_fs_ctx->nca_ctx) || nca_ctx->content_type != NcmContentType_Program || !pfs_ctx->offset || !pfs_ctx->size || \
|
||||
!pfs_ctx->is_exefs || pfs_ctx->header_size <= sizeof(PartitionFileSystemHeader) || !pfs_ctx->header || !pfs_entry)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -54,21 +54,22 @@ bool nsoInitializeContext(NsoContext *out, PartitionFileSystemContext *pfs_ctx,
|
|||
/* Get entry filename. */
|
||||
if (!(out->nso_filename = pfsGetEntryName(pfs_ctx, pfs_entry)) || !*(out->nso_filename))
|
||||
{
|
||||
LOGFILE("Invalid Partition FS entry filename!");
|
||||
LOG_MSG("Invalid Partition FS entry filename!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read NSO header. */
|
||||
if (!pfsReadEntryData(pfs_ctx, pfs_entry, &(out->nso_header), sizeof(NsoHeader), 0))
|
||||
{
|
||||
LOGFILE("Failed to read NSO \"%s\" header!", out->nso_filename);;
|
||||
LOG_MSG("Failed to read NSO \"%s\" header!", out->nso_filename);;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Verify NSO header. */
|
||||
if (__builtin_bswap32(out->nso_header.magic) != NSO_HEADER_MAGIC)
|
||||
{
|
||||
LOGFILE("Invalid NSO \"%s\" header magic word! (0x%08X != 0x%08X).", out->nso_filename, __builtin_bswap32(out->nso_header.magic), __builtin_bswap32(NSO_HEADER_MAGIC));
|
||||
LOG_MSG("Invalid NSO \"%s\" header magic word! (0x%08X != 0x%08X).", out->nso_filename, __builtin_bswap32(out->nso_header.magic), __builtin_bswap32(NSO_HEADER_MAGIC));
|
||||
dump_nso_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -77,8 +78,9 @@ bool nsoInitializeContext(NsoContext *out, PartitionFileSystemContext *pfs_ctx,
|
|||
(!(out->nso_header.flags & NsoFlags_TextCompress) && out->nso_header.text_file_size != out->nso_header.text_segment_info.size) || \
|
||||
(out->nso_header.text_segment_info.file_offset + out->nso_header.text_file_size) > pfs_entry->size)
|
||||
{
|
||||
LOGFILE("Invalid .text segment offset/size for NSO \"%s\"! (0x%08X, 0x%08X, 0x%08X).", out->nso_filename, out->nso_header.text_segment_info.file_offset, out->nso_header.text_file_size, \
|
||||
LOG_MSG("Invalid .text segment offset/size for NSO \"%s\"! (0x%08X, 0x%08X, 0x%08X).", out->nso_filename, out->nso_header.text_segment_info.file_offset, out->nso_header.text_file_size, \
|
||||
out->nso_header.text_segment_info.size);
|
||||
dump_nso_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -87,8 +89,9 @@ bool nsoInitializeContext(NsoContext *out, PartitionFileSystemContext *pfs_ctx,
|
|||
(!(out->nso_header.flags & NsoFlags_RoCompress) && out->nso_header.rodata_file_size != out->nso_header.rodata_segment_info.size) || \
|
||||
(out->nso_header.rodata_segment_info.file_offset + out->nso_header.rodata_file_size) > pfs_entry->size)
|
||||
{
|
||||
LOGFILE("Invalid .rodata segment offset/size for NSO \"%s\"! (0x%08X, 0x%08X, 0x%08X).", out->nso_filename, out->nso_header.rodata_segment_info.file_offset, out->nso_header.rodata_file_size, \
|
||||
LOG_MSG("Invalid .rodata segment offset/size for NSO \"%s\"! (0x%08X, 0x%08X, 0x%08X).", out->nso_filename, out->nso_header.rodata_segment_info.file_offset, out->nso_header.rodata_file_size, \
|
||||
out->nso_header.rodata_segment_info.size);
|
||||
dump_nso_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -97,29 +100,38 @@ bool nsoInitializeContext(NsoContext *out, PartitionFileSystemContext *pfs_ctx,
|
|||
(!(out->nso_header.flags & NsoFlags_DataCompress) && out->nso_header.data_file_size != out->nso_header.data_segment_info.size) || \
|
||||
(out->nso_header.data_segment_info.file_offset + out->nso_header.data_file_size) > pfs_entry->size)
|
||||
{
|
||||
LOGFILE("Invalid .data segment offset/size for NSO \"%s\"! (0x%08X, 0x%08X, 0x%08X).", out->nso_filename, out->nso_header.data_segment_info.file_offset, out->nso_header.data_file_size, \
|
||||
LOG_MSG("Invalid .data segment offset/size for NSO \"%s\"! (0x%08X, 0x%08X, 0x%08X).", out->nso_filename, out->nso_header.data_segment_info.file_offset, out->nso_header.data_file_size, \
|
||||
out->nso_header.data_segment_info.size);
|
||||
dump_nso_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->nso_header.module_name_offset < sizeof(NsoHeader) || !out->nso_header.module_name_size || (out->nso_header.module_name_offset + out->nso_header.module_name_size) > pfs_entry->size)
|
||||
if (out->nso_header.module_name_size > 1 && (out->nso_header.module_name_offset < sizeof(NsoHeader) || (out->nso_header.module_name_offset + out->nso_header.module_name_size) > pfs_entry->size))
|
||||
{
|
||||
LOGFILE("Invalid module name offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.module_name_offset, out->nso_header.module_name_size);
|
||||
LOG_MSG("Invalid module name offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.module_name_offset, out->nso_header.module_name_size);
|
||||
dump_nso_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (out->nso_header.api_info_section_info.size && (out->nso_header.api_info_section_info.offset + out->nso_header.api_info_section_info.size) > out->nso_header.rodata_segment_info.size)
|
||||
{
|
||||
LOGFILE("Invalid .api_info section offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.api_info_section_info.offset, out->nso_header.api_info_section_info.size);
|
||||
LOG_MSG("Invalid .api_info section offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.api_info_section_info.offset, out->nso_header.api_info_section_info.size);
|
||||
dump_nso_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!out->nso_header.dynstr_section_info.size || (out->nso_header.dynstr_section_info.offset + out->nso_header.dynstr_section_info.size) > out->nso_header.rodata_segment_info.size)
|
||||
if (out->nso_header.dynstr_section_info.size && (out->nso_header.dynstr_section_info.offset + out->nso_header.dynstr_section_info.size) > out->nso_header.rodata_segment_info.size)
|
||||
{
|
||||
LOGFILE("Invalid .dynstr section offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.dynstr_section_info.offset, out->nso_header.dynstr_section_info.size);
|
||||
LOG_MSG("Invalid .dynstr section offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.dynstr_section_info.offset, out->nso_header.dynstr_section_info.size);
|
||||
dump_nso_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!out->nso_header.dynsym_section_info.size || (out->nso_header.dynsym_section_info.offset + out->nso_header.dynsym_section_info.size) > out->nso_header.rodata_segment_info.size)
|
||||
if (out->nso_header.dynsym_section_info.size && (out->nso_header.dynsym_section_info.offset + out->nso_header.dynsym_section_info.size) > out->nso_header.rodata_segment_info.size)
|
||||
{
|
||||
LOGFILE("Invalid .dynsym section offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.dynsym_section_info.offset, out->nso_header.dynsym_section_info.size);
|
||||
LOG_MSG("Invalid .dynsym section offset/size for NSO \"%s\"! (0x%08X, 0x%08X).", out->nso_filename, out->nso_header.dynsym_section_info.offset, out->nso_header.dynsym_section_info.size);
|
||||
dump_nso_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Get module name. */
|
||||
|
@ -148,7 +160,12 @@ bool nsoInitializeContext(NsoContext *out, PartitionFileSystemContext *pfs_ctx,
|
|||
end:
|
||||
if (rodata_buf) free(rodata_buf);
|
||||
|
||||
if (!success) nsoFreeContext(out);
|
||||
if (!success)
|
||||
{
|
||||
if (dump_nso_header) LOG_DATA(&(out->nso_header), sizeof(NsoHeader), "NSO header dump:");
|
||||
|
||||
nsoFreeContext(out);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
@ -162,14 +179,14 @@ static bool nsoGetModuleName(NsoContext *nso_ctx)
|
|||
/* Get module name. */
|
||||
if (!pfsReadEntryData(nso_ctx->pfs_ctx, nso_ctx->pfs_entry, &module_name, sizeof(NsoModuleName), nso_ctx->nso_header.module_name_offset))
|
||||
{
|
||||
LOGFILE("Failed to read NSO \"%s\" module name length!", nso_ctx->nso_filename);
|
||||
LOG_MSG("Failed to read NSO \"%s\" module name length!", nso_ctx->nso_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Verify module name length. */
|
||||
if (module_name.name_length != ((u8)nso_ctx->nso_header.module_name_size - 1))
|
||||
{
|
||||
LOGFILE("NSO \"%s\" module name length mismatch! (0x%02X != 0x%02X).", nso_ctx->nso_filename, module_name.name_length, (u8)nso_ctx->nso_header.module_name_size - 1);
|
||||
LOG_MSG("NSO \"%s\" module name length mismatch! (0x%02X != 0x%02X).", nso_ctx->nso_filename, module_name.name_length, (u8)nso_ctx->nso_header.module_name_size - 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -177,14 +194,14 @@ static bool nsoGetModuleName(NsoContext *nso_ctx)
|
|||
nso_ctx->module_name = calloc(nso_ctx->nso_header.module_name_size, sizeof(char));
|
||||
if (!nso_ctx->module_name)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for NSO \"%s\" module name!", nso_ctx->nso_filename);
|
||||
LOG_MSG("Failed to allocate memory for NSO \"%s\" module name!", nso_ctx->nso_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read module name string. */
|
||||
if (!pfsReadEntryData(nso_ctx->pfs_ctx, nso_ctx->pfs_entry, nso_ctx->module_name, module_name.name_length, nso_ctx->nso_header.module_name_offset + 1))
|
||||
{
|
||||
LOGFILE("Failed to read NSO \"%s\" module name string!", nso_ctx->nso_filename);
|
||||
LOG_MSG("Failed to read NSO \"%s\" module name string!", nso_ctx->nso_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -209,7 +226,7 @@ static u8 *nsoGetRodataSegment(NsoContext *nso_ctx)
|
|||
/* Allocate memory for the .rodata buffer. */
|
||||
if (!(rodata_buf = calloc(rodata_buf_size, sizeof(u8))))
|
||||
{
|
||||
LOGFILE("Failed to allocate 0x%lX bytes for the .rodata segment in NSO \"%s\"!", rodata_buf_size, nso_ctx->nso_filename);
|
||||
LOG_MSG("Failed to allocate 0x%lX bytes for the .rodata segment in NSO \"%s\"!", rodata_buf_size, nso_ctx->nso_filename);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -218,7 +235,7 @@ static u8 *nsoGetRodataSegment(NsoContext *nso_ctx)
|
|||
/* Read .rodata segment data. */
|
||||
if (!pfsReadEntryData(nso_ctx->pfs_ctx, nso_ctx->pfs_entry, rodata_read_ptr, rodata_read_size, nso_ctx->nso_header.rodata_segment_info.file_offset))
|
||||
{
|
||||
LOGFILE("Failed to read %s .rodata segment in NRO \"%s\"!", nso_ctx->nso_filename);
|
||||
LOG_MSG("Failed to read %s .rodata segment in NRO \"%s\"!", nso_ctx->nso_filename);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -228,7 +245,7 @@ static u8 *nsoGetRodataSegment(NsoContext *nso_ctx)
|
|||
if ((lz4_res = LZ4_decompress_safe((char*)rodata_read_ptr, (char*)rodata_buf, (int)nso_ctx->nso_header.rodata_file_size, (int)rodata_buf_size)) != \
|
||||
(int)nso_ctx->nso_header.rodata_segment_info.size)
|
||||
{
|
||||
LOGFILE("LZ4 decompression failed for NRO \"%s\"! (0x%08X).", nso_ctx->nso_filename, (u32)lz4_res);
|
||||
LOG_MSG("LZ4 decompression failed for NRO \"%s\"! (0x%08X).", nso_ctx->nso_filename, (u32)lz4_res);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
@ -239,7 +256,7 @@ static u8 *nsoGetRodataSegment(NsoContext *nso_ctx)
|
|||
sha256CalculateHash(rodata_hash, rodata_buf, nso_ctx->nso_header.rodata_segment_info.size);
|
||||
if (memcmp(rodata_hash, nso_ctx->nso_header.rodata_segment_hash, SHA256_HASH_SIZE) != 0)
|
||||
{
|
||||
LOGFILE(".rodata segment checksum mismatch for NRO \"%s\"!", nso_ctx->nso_filename);
|
||||
LOG_MSG(".rodata segment checksum mismatch for NRO \"%s\"!", nso_ctx->nso_filename);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
@ -265,7 +282,7 @@ static bool nsoGetModuleInfoName(NsoContext *nso_ctx, u8 *rodata_buf)
|
|||
nso_ctx->module_info_name = calloc(module_info->name_length + 1, sizeof(char));
|
||||
if (!nso_ctx->module_info_name)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for NSO \"%s\" module info name!", nso_ctx->nso_filename);
|
||||
LOG_MSG("Failed to allocate memory for NSO \"%s\" module info name!", nso_ctx->nso_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -282,7 +299,7 @@ static bool nsoGetSectionFromRodataSegment(NsoContext *nso_ctx, u8 *rodata_buf,
|
|||
/* Allocate memory for the desired .rodata section. */
|
||||
if (!(*section_ptr = malloc(section_size)))
|
||||
{
|
||||
LOGFILE("Failed to allocate 0x%lX bytes for section at .rodata offset 0x%lX in NSO \"%s\"!", section_size, section_offset, nso_ctx->nso_filename);
|
||||
LOG_MSG("Failed to allocate 0x%lX bytes for section at .rodata offset 0x%lX in NSO \"%s\"!", section_size, section_offset, nso_ctx->nso_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
95
source/pfs.c
95
source/pfs.c
|
@ -35,10 +35,12 @@ bool pfsInitializeContext(PartitionFileSystemContext *out, NcaFsSectionContext *
|
|||
u32 hash_region_count = 0;
|
||||
NcaRegion *hash_region = NULL;
|
||||
|
||||
bool success = false, dump_fs_header = false;
|
||||
|
||||
if (!out || !nca_fs_ctx || !nca_fs_ctx->enabled || nca_fs_ctx->section_type != NcaFsSectionType_PartitionFs || nca_fs_ctx->header.fs_type != NcaFsType_PartitionFs || \
|
||||
nca_fs_ctx->header.hash_type != NcaHashType_HierarchicalSha256 || !(nca_ctx = (NcaContext*)nca_fs_ctx->nca_ctx) || (nca_ctx->rights_id_available && !nca_ctx->titlekey_retrieved))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -50,8 +52,8 @@ bool pfsInitializeContext(PartitionFileSystemContext *out, NcaFsSectionContext *
|
|||
|
||||
if (!ncaValidateHierarchicalSha256Offsets(&(nca_fs_ctx->header.hash_data.hierarchical_sha256_data), nca_fs_ctx->section_size))
|
||||
{
|
||||
LOGFILE("Invalid HierarchicalSha256 block!");
|
||||
return false;
|
||||
LOG_MSG("Invalid HierarchicalSha256 block!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
hash_region_count = nca_fs_ctx->header.hash_data.hierarchical_sha256_data.hash_region_count;
|
||||
|
@ -63,21 +65,23 @@ bool pfsInitializeContext(PartitionFileSystemContext *out, NcaFsSectionContext *
|
|||
/* Read partial Partition FS header. */
|
||||
if (!ncaReadFsSection(nca_fs_ctx, &pfs_header, sizeof(PartitionFileSystemHeader), out->offset))
|
||||
{
|
||||
LOGFILE("Failed to read partial Partition FS header!");
|
||||
return false;
|
||||
LOG_MSG("Failed to read partial Partition FS header!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
magic = __builtin_bswap32(pfs_header.magic);
|
||||
if (magic != PFS0_MAGIC)
|
||||
{
|
||||
LOGFILE("Invalid Partition FS magic word! (0x%08X).", magic);
|
||||
return false;
|
||||
LOG_MSG("Invalid Partition FS magic word! (0x%08X).", magic);
|
||||
dump_fs_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!pfs_header.entry_count || !pfs_header.name_table_size)
|
||||
{
|
||||
LOGFILE("Invalid Partition FS entry count / name table size!");
|
||||
return false;
|
||||
LOG_MSG("Invalid Partition FS entry count / name table size!");
|
||||
dump_fs_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Calculate full Partition FS header size. */
|
||||
|
@ -87,37 +91,47 @@ bool pfsInitializeContext(PartitionFileSystemContext *out, NcaFsSectionContext *
|
|||
out->header = calloc(out->header_size, sizeof(u8));
|
||||
if (!out->header)
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes buffer for the full Partition FS header!", out->header_size);
|
||||
return false;
|
||||
LOG_MSG("Unable to allocate 0x%lX bytes buffer for the full Partition FS header!", out->header_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Read full Partition FS header. */
|
||||
if (!ncaReadFsSection(nca_fs_ctx, out->header, out->header_size, out->offset))
|
||||
{
|
||||
LOGFILE("Failed to read full Partition FS header!");
|
||||
pfsFreeContext(out);
|
||||
return false;
|
||||
LOG_MSG("Failed to read full Partition FS header!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Check if we're dealing with an ExeFS section. */
|
||||
if ((main_npdm_entry = pfsGetEntryByName(out, "main.npdm")) != NULL && pfsReadEntryData(out, main_npdm_entry, &magic, sizeof(u32), 0) && \
|
||||
__builtin_bswap32(magic) == NPDM_META_MAGIC) out->is_exefs = true;
|
||||
|
||||
return true;
|
||||
/* Update flag. */
|
||||
success = true;
|
||||
|
||||
end:
|
||||
if (!success)
|
||||
{
|
||||
if (dump_fs_header) LOG_DATA(&pfs_header, sizeof(PartitionFileSystemHeader), "Partition FS header dump:");
|
||||
|
||||
pfsFreeContext(out);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool pfsReadPartitionData(PartitionFileSystemContext *ctx, void *out, u64 read_size, u64 offset)
|
||||
{
|
||||
if (!ctx || !ctx->nca_fs_ctx || !ctx->size || !out || !read_size || (offset + read_size) > ctx->size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read partition data. */
|
||||
if (!ncaReadFsSection(ctx->nca_fs_ctx, out, read_size, ctx->offset + offset))
|
||||
{
|
||||
LOGFILE("Failed to read Partition FS data!");
|
||||
LOG_MSG("Failed to read Partition FS data!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -128,14 +142,14 @@ bool pfsReadEntryData(PartitionFileSystemContext *ctx, PartitionFileSystemEntry
|
|||
{
|
||||
if (!ctx || !fs_entry || !fs_entry->size || (fs_entry->offset + fs_entry->size) > ctx->size || !out || !read_size || (offset + read_size) > fs_entry->size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read entry data. */
|
||||
if (!pfsReadPartitionData(ctx, out, read_size, ctx->header_size + fs_entry->offset + offset))
|
||||
{
|
||||
LOGFILE("Failed to read Partition FS entry data!");
|
||||
LOG_MSG("Failed to read Partition FS entry data!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -144,26 +158,33 @@ bool pfsReadEntryData(PartitionFileSystemContext *ctx, PartitionFileSystemEntry
|
|||
|
||||
bool pfsGetEntryIndexByName(PartitionFileSystemContext *ctx, const char *name, u32 *out_idx)
|
||||
{
|
||||
size_t name_len = 0;
|
||||
PartitionFileSystemEntry *fs_entry = NULL;
|
||||
u32 entry_count = pfsGetEntryCount(ctx);
|
||||
u32 entry_count = pfsGetEntryCount(ctx), name_table_size = 0;
|
||||
char *name_table = pfsGetNameTable(ctx);
|
||||
|
||||
if (!entry_count || !name_table || !name || !(name_len = strlen(name)) || !out_idx)
|
||||
if (!entry_count || !name_table || !name || !*name || !out_idx)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
name_table_size = ((PartitionFileSystemHeader*)ctx->header)->name_table_size;
|
||||
|
||||
for(u32 i = 0; i < entry_count; i++)
|
||||
{
|
||||
if (!(fs_entry = pfsGetEntryByIndex(ctx, i)))
|
||||
{
|
||||
LOGFILE("Failed to retrieve Partition FS entry #%u!", i);
|
||||
LOG_MSG("Failed to retrieve Partition FS entry #%u!", i);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strlen(name_table + fs_entry->name_offset) == name_len && !strcmp(name_table + fs_entry->name_offset, name))
|
||||
if (fs_entry->name_offset >= name_table_size)
|
||||
{
|
||||
LOG_MSG("Name offset from Partition FS entry #%u exceeds name table size!", i);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!strcmp(name_table + fs_entry->name_offset, name))
|
||||
{
|
||||
*out_idx = i;
|
||||
return true;
|
||||
|
@ -171,7 +192,7 @@ bool pfsGetEntryIndexByName(PartitionFileSystemContext *ctx, const char *name, u
|
|||
}
|
||||
|
||||
/* Only log error if we're not dealing with a NPDM. */
|
||||
if (name_len != 9 || strcmp(name, "main.npdm") != 0) LOGFILE("Unable to find Partition FS entry \"%s\"!", name);
|
||||
if (strcmp(name, "main.npdm") != 0) LOG_MSG("Unable to find Partition FS entry \"%s\"!", name);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -184,7 +205,7 @@ bool pfsGetTotalDataSize(PartitionFileSystemContext *ctx, u64 *out_size)
|
|||
|
||||
if (!entry_count || !out_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -192,7 +213,7 @@ bool pfsGetTotalDataSize(PartitionFileSystemContext *ctx, u64 *out_size)
|
|||
{
|
||||
if (!(fs_entry = pfsGetEntryByIndex(ctx, i)))
|
||||
{
|
||||
LOGFILE("Failed to retrieve Partition FS entry #%u!", i);
|
||||
LOG_MSG("Failed to retrieve Partition FS entry #%u!", i);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -209,7 +230,7 @@ bool pfsGenerateEntryPatch(PartitionFileSystemContext *ctx, PartitionFileSystemE
|
|||
if (!ctx || !ctx->nca_fs_ctx || !ctx->header_size || !ctx->header || !fs_entry || !fs_entry->size || (fs_entry->offset + fs_entry->size) > ctx->size || !data || !data_size || \
|
||||
(data_offset + data_size) > fs_entry->size || !out)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -217,7 +238,7 @@ bool pfsGenerateEntryPatch(PartitionFileSystemContext *ctx, PartitionFileSystemE
|
|||
|
||||
if (!ncaGenerateHierarchicalSha256Patch(ctx->nca_fs_ctx, data, data_size, partition_offset, out))
|
||||
{
|
||||
LOGFILE("Failed to generate 0x%lX bytes HierarchicalSha256 patch at offset 0x%lX for Partition FS entry!", data_size, partition_offset);
|
||||
LOG_MSG("Failed to generate 0x%lX bytes HierarchicalSha256 patch at offset 0x%lX for Partition FS entry!", data_size, partition_offset);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -228,7 +249,7 @@ bool pfsAddEntryInformationToFileContext(PartitionFileSystemFileContext *ctx, co
|
|||
{
|
||||
if (!ctx || !entry_name || !*entry_name)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -243,7 +264,7 @@ bool pfsAddEntryInformationToFileContext(PartitionFileSystemFileContext *ctx, co
|
|||
/* Reallocate Partition FS entries. */
|
||||
if (!(tmp_pfs_entries = realloc(ctx->entries, tmp_pfs_entries_size)))
|
||||
{
|
||||
LOGFILE("Failed to reallocate Partition FS entries!");
|
||||
LOG_MSG("Failed to reallocate Partition FS entries!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -263,7 +284,7 @@ bool pfsAddEntryInformationToFileContext(PartitionFileSystemFileContext *ctx, co
|
|||
/* Reallocate Partition FS name table. */
|
||||
if (!(tmp_name_table = realloc(ctx->name_table, tmp_name_table_size)))
|
||||
{
|
||||
LOGFILE("Failed to reallocate Partition FS name table!");
|
||||
LOG_MSG("Failed to reallocate Partition FS name table!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -288,7 +309,7 @@ bool pfsUpdateEntryNameFromFileContext(PartitionFileSystemFileContext *ctx, u32
|
|||
{
|
||||
if (!ctx || !ctx->header.entry_count || !ctx->header.name_table_size || !ctx->entries || !ctx->name_table || entry_idx >= ctx->header.entry_count || !new_entry_name || !*new_entry_name)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -300,7 +321,7 @@ bool pfsUpdateEntryNameFromFileContext(PartitionFileSystemFileContext *ctx, u32
|
|||
|
||||
if (new_entry_name_len > cur_entry_name_len)
|
||||
{
|
||||
LOGFILE("New entry name length exceeds previous entry name length! (0x%lX > 0x%lX).", new_entry_name_len, cur_entry_name_len);
|
||||
LOG_MSG("New entry name length exceeds previous entry name length! (0x%lX > 0x%lX).", new_entry_name_len, cur_entry_name_len);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -313,7 +334,7 @@ bool pfsWriteFileContextHeaderToMemoryBuffer(PartitionFileSystemFileContext *ctx
|
|||
{
|
||||
if (!ctx || !ctx->header.entry_count || !ctx->header.name_table_size || !ctx->entries || !ctx->name_table || !buf || !out_header_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -332,7 +353,7 @@ bool pfsWriteFileContextHeaderToMemoryBuffer(PartitionFileSystemFileContext *ctx
|
|||
/* Check buffer size. */
|
||||
if (buf_size < full_header_size)
|
||||
{
|
||||
LOGFILE("Not enough space available in input buffer to write full Partition FS header! (got 0x%lX, need 0x%lX).", buf_size, full_header_size);
|
||||
LOG_MSG("Not enough space available in input buffer to write full Partition FS header! (got 0x%lX, need 0x%lX).", buf_size, full_header_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ bool programInfoInitializeContext(ProgramInfoContext *out, NcaContext *nca_ctx)
|
|||
(nca_ctx->storage_id != NcmStorageId_GameCard && !nca_ctx->ncm_storage) || (nca_ctx->storage_id == NcmStorageId_GameCard && !nca_ctx->gamecard_offset) || \
|
||||
nca_ctx->header.content_type != NcaContentType_Program || nca_ctx->content_type_ctx || !out)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -73,28 +73,28 @@ bool programInfoInitializeContext(ProgramInfoContext *out, NcaContext *nca_ctx)
|
|||
/* Initialize Partition FS context. */
|
||||
if (!pfsInitializeContext(&(out->pfs_ctx), &(nca_ctx->fs_ctx[0])))
|
||||
{
|
||||
LOGFILE("Failed to initialize Partition FS context!");
|
||||
LOG_MSG("Failed to initialize Partition FS context!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Check if we're indeed dealing with an ExeFS. */
|
||||
if (!out->pfs_ctx.is_exefs)
|
||||
{
|
||||
LOGFILE("Initialized Partition FS is not an ExeFS!");
|
||||
LOG_MSG("Initialized Partition FS is not an ExeFS!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Get ExeFS entry count. Edge case, we should never trigger this. */
|
||||
if (!(pfs_entry_count = pfsGetEntryCount(&(out->pfs_ctx))))
|
||||
{
|
||||
LOGFILE("ExeFS has no file entries!");
|
||||
LOG_MSG("ExeFS has no file entries!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize NPDM context. */
|
||||
if (!npdmInitializeContext(&(out->npdm_ctx), &(out->pfs_ctx)))
|
||||
{
|
||||
LOGFILE("Failed to initialize NPDM context!");
|
||||
LOG_MSG("Failed to initialize NPDM context!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -104,13 +104,13 @@ bool programInfoInitializeContext(ProgramInfoContext *out, NcaContext *nca_ctx)
|
|||
/* Skip the main.npdm entry, as well as any other entries without a NSO header. */
|
||||
PartitionFileSystemEntry *pfs_entry = pfsGetEntryByIndex(&(out->pfs_ctx), i);
|
||||
char *pfs_entry_name = pfsGetEntryName(&(out->pfs_ctx), pfs_entry);
|
||||
if (!pfs_entry || !pfs_entry_name || !strncmp(pfs_entry_name, "main.npdm", 9) || !pfsReadEntryData(&(out->pfs_ctx), pfs_entry, &magic, sizeof(u32), 0) || \
|
||||
if (!pfs_entry || !pfs_entry_name || !strcmp(pfs_entry_name, "main.npdm") || !pfsReadEntryData(&(out->pfs_ctx), pfs_entry, &magic, sizeof(u32), 0) || \
|
||||
__builtin_bswap32(magic) != NSO_HEADER_MAGIC) continue;
|
||||
|
||||
/* Reallocate NSO context buffer. */
|
||||
if (!(tmp_nso_ctx = realloc(out->nso_ctx, (out->nso_count + 1) * sizeof(NsoContext))))
|
||||
{
|
||||
LOGFILE("Failed to reallocate NSO context buffer for NSO \"%s\"! (entry #%u).", pfs_entry_name, i);
|
||||
LOG_MSG("Failed to reallocate NSO context buffer for NSO \"%s\"! (entry #%u).", pfs_entry_name, i);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,7 @@ bool programInfoInitializeContext(ProgramInfoContext *out, NcaContext *nca_ctx)
|
|||
/* Initialize NSO context. */
|
||||
if (!nsoInitializeContext(&(out->nso_ctx[out->nso_count]), &(out->pfs_ctx), pfs_entry))
|
||||
{
|
||||
LOGFILE("Failed to initialize context for NSO \"%s\"! (entry #%u).", pfs_entry_name, i);
|
||||
LOG_MSG("Failed to initialize context for NSO \"%s\"! (entry #%u).", pfs_entry_name, i);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ bool programInfoInitializeContext(ProgramInfoContext *out, NcaContext *nca_ctx)
|
|||
/* Safety check. */
|
||||
if (!out->nso_count)
|
||||
{
|
||||
LOGFILE("ExeFS has no NSOs!");
|
||||
LOG_MSG("ExeFS has no NSOs!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ bool programInfoGenerateAuthoringToolXml(ProgramInfoContext *program_info_ctx)
|
|||
{
|
||||
if (!programInfoIsValidContext(program_info_ctx))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -181,21 +181,21 @@ bool programInfoGenerateAuthoringToolXml(ProgramInfoContext *program_info_ctx)
|
|||
mbedtls_base64_encode(NULL, 0, &npdm_acid_b64_size, npdm_acid, npdm_acid_size);
|
||||
if (npdm_acid_b64_size <= npdm_acid_size)
|
||||
{
|
||||
LOGFILE("Invalid Base64 conversion length for the NPDM ACID section! (0x%lX, 0x%lX).", npdm_acid_b64_size, npdm_acid_size);
|
||||
LOG_MSG("Invalid Base64 conversion length for the NPDM ACID section! (0x%lX, 0x%lX).", npdm_acid_b64_size, npdm_acid_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Allocate memory for the NPDM ACID Base64 string. */
|
||||
if (!(npdm_acid_b64 = calloc(npdm_acid_b64_size + 1, sizeof(char))))
|
||||
{
|
||||
LOGFILE("Failed to allocate 0x%lX bytes for the NPDM ACID section Base64 string!", npdm_acid_b64_size);
|
||||
LOG_MSG("Failed to allocate 0x%lX bytes for the NPDM ACID section Base64 string!", npdm_acid_b64_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Convert NPDM ACID section to a Base64 string. */
|
||||
if (mbedtls_base64_encode((u8*)npdm_acid_b64, npdm_acid_b64_size + 1, &npdm_acid_b64_size, npdm_acid, npdm_acid_size) != 0)
|
||||
{
|
||||
LOGFILE("Base64 conversion failed for the NPDM ACID section!");
|
||||
LOG_MSG("Base64 conversion failed for the NPDM ACID section!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -266,7 +266,7 @@ end:
|
|||
if (!success)
|
||||
{
|
||||
if (xml_buf) free(xml_buf);
|
||||
LOGFILE("Failed to generate ProgramInfo AuthoringTool XML!");
|
||||
LOG_MSG("Failed to generate ProgramInfo AuthoringTool XML!");
|
||||
}
|
||||
|
||||
return success;
|
||||
|
@ -276,7 +276,7 @@ static bool programInfoGetSdkVersionAndBuildTypeFromSdkNso(ProgramInfoContext *p
|
|||
{
|
||||
if (!program_info_ctx || !program_info_ctx->nso_count || !program_info_ctx->nso_ctx || !sdk_version || !build_type)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -292,7 +292,7 @@ static bool programInfoGetSdkVersionAndBuildTypeFromSdkNso(ProgramInfoContext *p
|
|||
for(u32 i = 0; i < program_info_ctx->nso_count; i++)
|
||||
{
|
||||
nso_ctx = &(program_info_ctx->nso_ctx[i]);
|
||||
if (nso_ctx->nso_filename && strlen(nso_ctx->nso_filename) == 3 && !strcmp(nso_ctx->nso_filename, "sdk") && nso_ctx->rodata_api_info_section && nso_ctx->rodata_api_info_section_size) break;
|
||||
if (nso_ctx->nso_filename && !strcmp(nso_ctx->nso_filename, "sdk") && nso_ctx->rodata_api_info_section && nso_ctx->rodata_api_info_section_size) break;
|
||||
nso_ctx = NULL;
|
||||
}
|
||||
|
||||
|
@ -327,7 +327,7 @@ static bool programInfoGetSdkVersionAndBuildTypeFromSdkNso(ProgramInfoContext *p
|
|||
/* Duplicate strings. */
|
||||
if (!(*sdk_version = strndup(sdk_entry_version, sdk_entry_version_len)) || !(*build_type = strdup(sdk_entry_build_type)))
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for output strings!");
|
||||
LOG_MSG("Failed to allocate memory for output strings!");
|
||||
|
||||
if (*sdk_version)
|
||||
{
|
||||
|
@ -359,7 +359,7 @@ static bool programInfoAddNsoApiListToAuthoringToolXml(char **xml_buf, u64 *xml_
|
|||
if (!xml_buf || !xml_buf_size || !program_info_ctx || !program_info_ctx->nso_count || !program_info_ctx->nso_ctx || !api_list_tag || !*api_list_tag || !api_entry_prefix || \
|
||||
!*api_entry_prefix || !sdk_prefix || !(sdk_prefix_len = strlen(sdk_prefix)))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -453,7 +453,7 @@ static bool programInfoAddStringFieldToAuthoringToolXml(char **xml_buf, u64 *xml
|
|||
{
|
||||
if (!xml_buf || !xml_buf_size || !tag_name || !*tag_name)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -465,7 +465,7 @@ static bool programInfoAddNsoSymbolsToAuthoringToolXml(char **xml_buf, u64 *xml_
|
|||
{
|
||||
if (!xml_buf || !xml_buf_size || !program_info_ctx || !program_info_ctx->npdm_ctx.meta_header || !program_info_ctx->nso_count || !program_info_ctx->nso_ctx)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -479,8 +479,8 @@ static bool programInfoAddNsoSymbolsToAuthoringToolXml(char **xml_buf, u64 *xml_
|
|||
for(u32 i = 0; i < program_info_ctx->nso_count; i++)
|
||||
{
|
||||
nso_ctx = &(program_info_ctx->nso_ctx[i]);
|
||||
if (nso_ctx->nso_filename && strlen(nso_ctx->nso_filename) == 4 && !strcmp(nso_ctx->nso_filename, "main") && nso_ctx->rodata_dynstr_section && nso_ctx->rodata_dynstr_section_size && \
|
||||
nso_ctx->rodata_dynsym_section && nso_ctx->rodata_dynsym_section_size) break;
|
||||
if (nso_ctx->nso_filename && !strcmp(nso_ctx->nso_filename, "main") && nso_ctx->rodata_dynstr_section && nso_ctx->rodata_dynstr_section_size && nso_ctx->rodata_dynsym_section && \
|
||||
nso_ctx->rodata_dynsym_section_size) break;
|
||||
nso_ctx = NULL;
|
||||
}
|
||||
|
||||
|
@ -563,7 +563,7 @@ static bool programInfoAddFsAccessControlDataToAuthoringToolXml(char **xml_buf,
|
|||
|
||||
if (!xml_buf || !xml_buf_size || !program_info_ctx || !(aci_fac_data = program_info_ctx->npdm_ctx.aci_fac_data))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
117
source/romfs.c
117
source/romfs.c
|
@ -30,12 +30,13 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_
|
|||
{
|
||||
NcaContext *nca_ctx = NULL;
|
||||
u64 dir_table_offset = 0, file_table_offset = 0;
|
||||
bool success = false, dump_fs_header = false;
|
||||
|
||||
if (!out || !nca_fs_ctx || !nca_fs_ctx->enabled || !(nca_ctx = (NcaContext*)nca_fs_ctx->nca_ctx) || (nca_ctx->format_version == NcaVersion_Nca0 && \
|
||||
(nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs || nca_fs_ctx->header.hash_type != NcaHashType_HierarchicalSha256)) || (nca_ctx->format_version != NcaVersion_Nca0 && \
|
||||
(nca_fs_ctx->section_type != NcaFsSectionType_RomFs || nca_fs_ctx->header.hash_type != NcaHashType_HierarchicalIntegrity)) || (nca_ctx->rights_id_available && !nca_ctx->titlekey_retrieved))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -53,8 +54,8 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_
|
|||
{
|
||||
if (!ncaValidateHierarchicalSha256Offsets(&(nca_fs_ctx->header.hash_data.hierarchical_sha256_data), nca_fs_ctx->section_size))
|
||||
{
|
||||
LOGFILE("Invalid HierarchicalSha256 block!");
|
||||
return false;
|
||||
LOG_MSG("Invalid HierarchicalSha256 block!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
layer_count = nca_fs_ctx->header.hash_data.hierarchical_sha256_data.hash_region_count;
|
||||
|
@ -65,8 +66,8 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_
|
|||
} else {
|
||||
if (!ncaValidateHierarchicalIntegrityOffsets(&(nca_fs_ctx->header.hash_data.integrity_meta_info), nca_fs_ctx->section_size))
|
||||
{
|
||||
LOGFILE("Invalid HierarchicalIntegrity block!");
|
||||
return false;
|
||||
LOG_MSG("Invalid HierarchicalIntegrity block!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
layer_count = NCA_IVFC_LEVEL_COUNT;
|
||||
|
@ -79,39 +80,39 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_
|
|||
/* Read RomFS header. */
|
||||
if (!ncaReadFsSection(nca_fs_ctx, &(out->header), sizeof(RomFileSystemHeader), out->offset))
|
||||
{
|
||||
LOGFILE("Failed to read RomFS header!");
|
||||
return false;
|
||||
LOG_MSG("Failed to read RomFS header!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if ((nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs && out->header.old_format.header_size != ROMFS_OLD_HEADER_SIZE) || \
|
||||
(nca_fs_ctx->section_type == NcaFsSectionType_RomFs && out->header.cur_format.header_size != ROMFS_HEADER_SIZE))
|
||||
{
|
||||
LOGFILE("Invalid RomFS header size!");
|
||||
return false;
|
||||
LOG_MSG("Invalid RomFS header size!");
|
||||
dump_fs_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
|
||||
/* 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);
|
||||
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);
|
||||
|
||||
if (!out->dir_table_size || (dir_table_offset + out->dir_table_size) > out->size)
|
||||
{
|
||||
LOGFILE("Invalid RomFS directory entries table!");
|
||||
return false;
|
||||
LOG_MSG("Invalid RomFS directory entries table!");
|
||||
dump_fs_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
out->dir_table = malloc(out->dir_table_size);
|
||||
if (!out->dir_table)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for RomFS directory entries table!");
|
||||
return false;
|
||||
LOG_MSG("Unable to allocate memory for RomFS directory entries table!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!ncaReadFsSection(nca_fs_ctx, out->dir_table, out->dir_table_size, out->offset + dir_table_offset))
|
||||
{
|
||||
LOGFILE("Failed to read RomFS directory entries table!");
|
||||
LOG_MSG("Failed to read RomFS directory entries table!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -121,20 +122,21 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_
|
|||
|
||||
if (!out->file_table_size || (file_table_offset + out->file_table_size) > out->size)
|
||||
{
|
||||
LOGFILE("Invalid RomFS file entries table!");
|
||||
LOG_MSG("Invalid RomFS file entries table!");
|
||||
dump_fs_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
out->file_table = malloc(out->file_table_size);
|
||||
if (!out->file_table)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for RomFS file entries table!");
|
||||
LOG_MSG("Unable to allocate memory for RomFS file entries table!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!ncaReadFsSection(nca_fs_ctx, out->file_table, out->file_table_size, out->offset + file_table_offset))
|
||||
{
|
||||
LOGFILE("Failed to read RomFS file entries table!");
|
||||
LOG_MSG("Failed to read RomFS file entries table!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -142,14 +144,21 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *nca_
|
|||
out->body_offset = (nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? (u64)out->header.old_format.body_offset : out->header.cur_format.body_offset);
|
||||
if (out->body_offset >= out->size)
|
||||
{
|
||||
LOGFILE("Invalid RomFS file data body!");
|
||||
LOG_MSG("Invalid RomFS file data body!");
|
||||
dump_fs_header = true;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Update flag. */
|
||||
success = true;
|
||||
|
||||
end:
|
||||
if (!success) romfsFreeContext(out);
|
||||
if (!success)
|
||||
{
|
||||
if (dump_fs_header) LOG_DATA(&(out->header), sizeof(RomFileSystemHeader), "RomFS header dump:");
|
||||
|
||||
romfsFreeContext(out);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
@ -158,14 +167,14 @@ bool romfsReadFileSystemData(RomFileSystemContext *ctx, void *out, u64 read_size
|
|||
{
|
||||
if (!ctx || !ctx->nca_fs_ctx || !ctx->size || !out || !read_size || (offset + read_size) > ctx->size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read filesystem data. */
|
||||
if (!ncaReadFsSection(ctx->nca_fs_ctx, out, read_size, ctx->offset + offset))
|
||||
{
|
||||
LOGFILE("Failed to read RomFS data!");
|
||||
LOG_MSG("Failed to read RomFS data!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -176,14 +185,14 @@ bool romfsReadFileEntryData(RomFileSystemContext *ctx, RomFileSystemFileEntry *f
|
|||
{
|
||||
if (!ctx || !ctx->body_offset || !file_entry || !file_entry->size || (file_entry->offset + file_entry->size) > ctx->size || !out || !read_size || (offset + read_size) > file_entry->size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read entry data. */
|
||||
if (!romfsReadFileSystemData(ctx, out, read_size, ctx->body_offset + file_entry->offset + offset))
|
||||
{
|
||||
LOGFILE("Failed to read RomFS file entry data!");
|
||||
LOG_MSG("Failed to read RomFS file entry data!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -194,7 +203,7 @@ bool romfsGetTotalDataSize(RomFileSystemContext *ctx, u64 *out_size)
|
|||
{
|
||||
if (!ctx || !ctx->file_table_size || !ctx->file_table || !out_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -205,7 +214,7 @@ bool romfsGetTotalDataSize(RomFileSystemContext *ctx, u64 *out_size)
|
|||
{
|
||||
if (!(file_entry = romfsGetFileEntryByOffset(ctx, offset)))
|
||||
{
|
||||
LOGFILE("Failed to retrieve file entry!");
|
||||
LOG_MSG("Failed to retrieve file entry!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -223,7 +232,7 @@ bool romfsGetDirectoryDataSize(RomFileSystemContext *ctx, RomFileSystemDirectory
|
|||
if (!ctx || !ctx->dir_table_size || !ctx->dir_table || !ctx->file_table_size || !ctx->file_table || !dir_entry || (dir_entry->file_offset == ROMFS_VOID_ENTRY && \
|
||||
dir_entry->directory_offset == ROMFS_VOID_ENTRY) || !out_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -237,7 +246,7 @@ bool romfsGetDirectoryDataSize(RomFileSystemContext *ctx, RomFileSystemDirectory
|
|||
{
|
||||
if (!(cur_file_entry = romfsGetFileEntryByOffset(ctx, cur_file_offset)))
|
||||
{
|
||||
LOGFILE("Failed to retrieve file entry!");
|
||||
LOG_MSG("Failed to retrieve file entry!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -250,7 +259,7 @@ bool romfsGetDirectoryDataSize(RomFileSystemContext *ctx, RomFileSystemDirectory
|
|||
{
|
||||
if (!(cur_dir_entry = romfsGetDirectoryEntryByOffset(ctx, cur_dir_offset)) || !romfsGetDirectoryDataSize(ctx, cur_dir_entry, &child_dir_size))
|
||||
{
|
||||
LOGFILE("Failed to retrieve directory entry/size!");
|
||||
LOG_MSG("Failed to retrieve directory entry/size!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -271,7 +280,7 @@ RomFileSystemDirectoryEntry *romfsGetDirectoryEntryByPath(RomFileSystemContext *
|
|||
|
||||
if (!ctx || !ctx->dir_table || !ctx->dir_table_size || !path || *path != '/' || !(path_len = strlen(path)) || !(dir_entry = romfsGetDirectoryEntryByOffset(ctx, 0)))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -281,14 +290,14 @@ RomFileSystemDirectoryEntry *romfsGetDirectoryEntryByPath(RomFileSystemContext *
|
|||
/* Duplicate path to avoid problems with strtok(). */
|
||||
if (!(path_dup = strdup(path)))
|
||||
{
|
||||
LOGFILE("Unable to duplicate input path! (\"%s\").", path);
|
||||
LOG_MSG("Unable to duplicate input path! (\"%s\").", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pch = strtok(path_dup, "/");
|
||||
if (!pch)
|
||||
{
|
||||
LOGFILE("Failed to tokenize input path! (\"%s\").", path);
|
||||
LOG_MSG("Failed to tokenize input path! (\"%s\").", path);
|
||||
dir_entry = NULL;
|
||||
goto end;
|
||||
}
|
||||
|
@ -297,7 +306,7 @@ RomFileSystemDirectoryEntry *romfsGetDirectoryEntryByPath(RomFileSystemContext *
|
|||
{
|
||||
if (!(dir_entry = romfsGetChildDirectoryEntryByName(ctx, dir_entry, pch)))
|
||||
{
|
||||
LOGFILE("Failed to retrieve directory entry by name for \"%s\"! (\"%s\").", pch, path);
|
||||
LOG_MSG("Failed to retrieve directory entry by name for \"%s\"! (\"%s\").", pch, path);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -320,7 +329,7 @@ RomFileSystemFileEntry *romfsGetFileEntryByPath(RomFileSystemContext *ctx, const
|
|||
|
||||
if (!ctx || !ctx->file_table || !ctx->file_table_size || !ctx->nca_fs_ctx || !ctx->nca_fs_ctx->nca_ctx || !path || *path != '/' || (path_len = strlen(path)) <= 1)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -329,7 +338,7 @@ RomFileSystemFileEntry *romfsGetFileEntryByPath(RomFileSystemContext *ctx, const
|
|||
/* Duplicate path. */
|
||||
if (!(path_dup = strdup(path)))
|
||||
{
|
||||
LOGFILE("Unable to duplicate input path! (\"%s\").", path);
|
||||
LOG_MSG("Unable to duplicate input path! (\"%s\").", path);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -343,7 +352,7 @@ RomFileSystemFileEntry *romfsGetFileEntryByPath(RomFileSystemContext *ctx, const
|
|||
/* Safety check. */
|
||||
if (!path_len || !(filename = strrchr(path_dup, '/')))
|
||||
{
|
||||
LOGFILE("Invalid input path! (\"%s\").", path);
|
||||
LOG_MSG("Invalid input path! (\"%s\").", path);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -354,7 +363,7 @@ RomFileSystemFileEntry *romfsGetFileEntryByPath(RomFileSystemContext *ctx, const
|
|||
/* If the first character is NULL, then just retrieve the root directory entry. */
|
||||
if (!(dir_entry = (*path_dup ? romfsGetDirectoryEntryByPath(ctx, path_dup) : romfsGetDirectoryEntryByOffset(ctx, 0))))
|
||||
{
|
||||
LOGFILE("Failed to retrieve directory entry for \"%s\"! (\"%s\").", *path_dup ? path_dup : "/", path);
|
||||
LOG_MSG("Failed to retrieve directory entry for \"%s\"! (\"%s\").", *path_dup ? path_dup : "/", path);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -362,8 +371,8 @@ RomFileSystemFileEntry *romfsGetFileEntryByPath(RomFileSystemContext *ctx, const
|
|||
if (!(file_entry = romfsGetChildFileEntryByName(ctx, dir_entry, filename)))
|
||||
{
|
||||
/* Only log error if we're not dealing with NACP icons or a LegalInformation XML. */
|
||||
bool skip_log = ((!strncmp(path, "/icon_", 6) && content_type == NcmContentType_Control) || (!strncmp(path, "/legalinfo.xml", 14) && content_type == NcmContentType_LegalInformation));
|
||||
if (!skip_log) LOGFILE("Failed to retrieve file entry by name for \"%s\"! (\"%s\").", filename, path);
|
||||
bool skip_log = ((!strncmp(path, "/icon_", 6) && content_type == NcmContentType_Control) || (!strcmp(path, "/legalinfo.xml") && content_type == NcmContentType_LegalInformation));
|
||||
if (!skip_log) LOG_MSG("Failed to retrieve file entry by name for \"%s\"! (\"%s\").", filename, path);
|
||||
}
|
||||
|
||||
end:
|
||||
|
@ -382,7 +391,7 @@ bool romfsGeneratePathFromDirectoryEntry(RomFileSystemContext *ctx, RomFileSyste
|
|||
if (!ctx || !ctx->dir_table || !ctx->dir_table_size || !dir_entry || (!dir_entry->name_length && dir_entry->parent_offset) || !out_path || out_path_size < 2 || \
|
||||
illegal_char_replace_type > RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -397,7 +406,7 @@ bool romfsGeneratePathFromDirectoryEntry(RomFileSystemContext *ctx, RomFileSyste
|
|||
dir_entries = calloc(1, sizeof(RomFileSystemDirectoryEntry*));
|
||||
if (!dir_entries)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for directory entries!");
|
||||
LOG_MSG("Unable to allocate memory for directory entries!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -413,7 +422,7 @@ bool romfsGeneratePathFromDirectoryEntry(RomFileSystemContext *ctx, RomFileSyste
|
|||
/* Reallocate directory entries. */
|
||||
if (!(tmp_dir_entries = realloc(dir_entries, (dir_entries_count + 1) * sizeof(RomFileSystemDirectoryEntry*))))
|
||||
{
|
||||
LOGFILE("Unable to reallocate directory entries buffer!");
|
||||
LOG_MSG("Unable to reallocate directory entries buffer!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -423,7 +432,7 @@ bool romfsGeneratePathFromDirectoryEntry(RomFileSystemContext *ctx, RomFileSyste
|
|||
RomFileSystemDirectoryEntry **cur_dir_entry = &(dir_entries[dir_entries_count]);
|
||||
if (!(*cur_dir_entry = romfsGetDirectoryEntryByOffset(ctx, dir_offset)) || !(*cur_dir_entry)->name_length)
|
||||
{
|
||||
LOGFILE("Failed to retrieve directory entry!");
|
||||
LOG_MSG("Failed to retrieve directory entry!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -433,7 +442,7 @@ bool romfsGeneratePathFromDirectoryEntry(RomFileSystemContext *ctx, RomFileSyste
|
|||
|
||||
if (path_len >= out_path_size)
|
||||
{
|
||||
LOGFILE("Output path length exceeds output buffer size!");
|
||||
LOG_MSG("Output path length exceeds output buffer size!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -470,14 +479,14 @@ bool romfsGeneratePathFromFileEntry(RomFileSystemContext *ctx, RomFileSystemFile
|
|||
if (!ctx || !ctx->file_table || !ctx->file_table_size || !file_entry || !file_entry->name_length || !out_path || out_path_size < 2 || \
|
||||
!(dir_entry = romfsGetDirectoryEntryByOffset(ctx, file_entry->parent_offset)) || illegal_char_replace_type > RomFileSystemPathIllegalCharReplaceType_KeepAsciiCharsOnly)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Retrieve full RomFS path up to the file entry name. */
|
||||
if (!romfsGeneratePathFromDirectoryEntry(ctx, dir_entry, out_path, out_path_size, illegal_char_replace_type))
|
||||
{
|
||||
LOGFILE("Failed to retrieve RomFS directory path!");
|
||||
LOG_MSG("Failed to retrieve RomFS directory path!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -485,7 +494,7 @@ bool romfsGeneratePathFromFileEntry(RomFileSystemContext *ctx, RomFileSystemFile
|
|||
path_len = strlen(out_path);
|
||||
if ((1 + file_entry->name_length) >= (out_path_size - path_len))
|
||||
{
|
||||
LOGFILE("Output path length exceeds output buffer size!");
|
||||
LOG_MSG("Output path length exceeds output buffer size!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -508,7 +517,7 @@ bool romfsGenerateFileEntryPatch(RomFileSystemContext *ctx, RomFileSystemFileEnt
|
|||
if (!ctx || !ctx->nca_fs_ctx || !ctx->body_offset || (ctx->nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs && ctx->nca_fs_ctx->section_type != NcaFsSectionType_RomFs) || !file_entry || \
|
||||
!file_entry->size || (file_entry->offset + file_entry->size) > ctx->size || !data || !data_size || (data_offset + data_size) > file_entry->size || !out)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -526,7 +535,7 @@ bool romfsGenerateFileEntryPatch(RomFileSystemContext *ctx, RomFileSystemFileEnt
|
|||
|
||||
out->written = false;
|
||||
|
||||
if (!success) LOGFILE("Failed to generate 0x%lX bytes Hierarchical%s patch at offset 0x%lX for RomFS file entry!", data_size, \
|
||||
if (!success) LOG_MSG("Failed to generate 0x%lX bytes Hierarchical%s patch at offset 0x%lX for RomFS file entry!", data_size, \
|
||||
ctx->nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs ? "Sha256" : "Integrity", fs_offset);
|
||||
|
||||
return success;
|
||||
|
@ -542,8 +551,8 @@ static RomFileSystemDirectoryEntry *romfsGetChildDirectoryEntryByName(RomFileSys
|
|||
|
||||
while(dir_offset != ROMFS_VOID_ENTRY)
|
||||
{
|
||||
if (!(child_dir_entry = romfsGetDirectoryEntryByOffset(ctx, dir_offset)) || !child_dir_entry->name_length) return NULL;
|
||||
if (child_dir_entry->name_length == name_len && !strncmp(child_dir_entry->name, name, name_len)) return child_dir_entry;
|
||||
if (!(child_dir_entry = romfsGetDirectoryEntryByOffset(ctx, dir_offset))) return NULL;
|
||||
if (!strcmp(child_dir_entry->name, name)) return child_dir_entry;
|
||||
dir_offset = child_dir_entry->next_offset;
|
||||
}
|
||||
|
||||
|
@ -561,8 +570,8 @@ static RomFileSystemFileEntry *romfsGetChildFileEntryByName(RomFileSystemContext
|
|||
|
||||
while(file_offset != ROMFS_VOID_ENTRY)
|
||||
{
|
||||
if (!(child_file_entry = romfsGetFileEntryByOffset(ctx, file_offset)) || !child_file_entry->name_length) return NULL;
|
||||
if (child_file_entry->name_length == name_len && !strncmp(child_file_entry->name, name, name_len)) return child_file_entry;
|
||||
if (!(child_file_entry = romfsGetFileEntryByOffset(ctx, file_offset))) return NULL;
|
||||
if (!strcmp(child_file_entry->name, name)) return child_file_entry;
|
||||
file_offset = child_file_entry->next_offset;
|
||||
}
|
||||
|
||||
|
|
20
source/rsa.c
20
source/rsa.c
|
@ -89,7 +89,7 @@ bool rsa2048GenerateSha256BasedPssSignature(void *dst, const void *src, size_t s
|
|||
{
|
||||
if (!dst || !src || !size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ bool rsa2048GenerateSha256BasedPssSignature(void *dst, const void *src, size_t s
|
|||
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const u8*)pers, strlen(pers));
|
||||
if (ret != 0)
|
||||
{
|
||||
LOGFILE("mbedtls_ctr_drbg_seed failed! (%d).", ret);
|
||||
LOG_MSG("mbedtls_ctr_drbg_seed failed! (%d).", ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ bool rsa2048GenerateSha256BasedPssSignature(void *dst, const void *src, size_t s
|
|||
ret = mbedtls_pk_parse_key(&pk, (const u8*)g_rsa2048CustomPrivateKey, strlen(g_rsa2048CustomPrivateKey) + 1, NULL, 0);
|
||||
if (ret != 0)
|
||||
{
|
||||
LOGFILE("mbedtls_pk_parse_key failed! (%d).", ret);
|
||||
LOG_MSG("mbedtls_pk_parse_key failed! (%d).", ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -136,7 +136,7 @@ bool rsa2048GenerateSha256BasedPssSignature(void *dst, const void *src, size_t s
|
|||
ret = mbedtls_pk_sign(&pk, MBEDTLS_MD_SHA256, hash, 0, buf, &olen, mbedtls_ctr_drbg_random, &ctr_drbg);
|
||||
if (ret != 0)
|
||||
{
|
||||
LOGFILE("mbedtls_pk_sign failed! (%d).", ret);
|
||||
LOG_MSG("mbedtls_pk_sign failed! (%d).", ret);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -161,7 +161,7 @@ bool rsa2048OaepDecryptAndVerify(void *dst, size_t dst_size, const void *signatu
|
|||
{
|
||||
if (!dst || !dst_size || !signature || !modulus || !exponent || !exponent_size || !label_hash || !out_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -171,13 +171,13 @@ bool rsa2048OaepDecryptAndVerify(void *dst, size_t dst_size, const void *signatu
|
|||
rc = splUserExpMod(signature, modulus, exponent, exponent_size, m_buf);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("splUserExpMod failed! (0x%08X).", rc);
|
||||
LOG_MSG("splUserExpMod failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_buf[0] != 0)
|
||||
{
|
||||
LOGFILE("Invalid PSS!");
|
||||
LOG_MSG("Invalid PSS!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,7 @@ bool rsa2048OaepDecryptAndVerify(void *dst, size_t dst_size, const void *signatu
|
|||
const u8 *db = (const u8*)(m_buf + 0x21);
|
||||
if (memcmp(db, label_hash, SHA256_HASH_SIZE) != 0)
|
||||
{
|
||||
LOGFILE("Label hash validation failed! Wrong decryption keys?");
|
||||
LOG_MSG("Label hash validation failed! Wrong decryption keys?");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -207,7 +207,7 @@ bool rsa2048OaepDecryptAndVerify(void *dst, size_t dst_size, const void *signatu
|
|||
|
||||
if (!remaining || *data++ != 1)
|
||||
{
|
||||
LOGFILE("Message prefix validation failed! Wrong decryption keys?");
|
||||
LOG_MSG("Message prefix validation failed! Wrong decryption keys?");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -224,7 +224,7 @@ static void rsaCalculateMgf1AndXor(void *data, size_t data_size, const void *h_s
|
|||
{
|
||||
if (!data || !data_size || !h_src || !h_src_size || h_src_size > RSA2048_SIG_SIZE)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
256
source/save.c
256
source/save.c
File diff suppressed because it is too large
Load diff
|
@ -93,7 +93,7 @@ bool servicesInitialize(void)
|
|||
rc = service_info->init_func();
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("Failed to initialize %s service! (0x%08X).", service_info->name, rc);
|
||||
LOG_MSG("Failed to initialize %s service! (0x%08X).", service_info->name, rc);
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
@ -138,7 +138,7 @@ bool servicesCheckRunningServiceByName(const char *name)
|
|||
bool running = false;
|
||||
|
||||
rc = smRegisterService(&handle, service_name, false, 1);
|
||||
if (R_FAILED(rc)) LOGFILE("smRegisterService failed for \"%s\"! (0x%08X).", name, rc);
|
||||
if (R_FAILED(rc)) LOG_MSG("smRegisterService failed for \"%s\"! (0x%08X).", name, rc);
|
||||
running = R_FAILED(rc);
|
||||
|
||||
if (handle != INVALID_HANDLE) svcCloseHandle(handle);
|
||||
|
@ -155,13 +155,11 @@ bool servicesCheckInitializedServiceByName(const char *name)
|
|||
|
||||
if (!name || !*name) goto end;
|
||||
|
||||
size_t name_len = strlen(name);
|
||||
|
||||
for(u32 i = 0; i < g_serviceInfoCount; i++)
|
||||
{
|
||||
ServiceInfo *service_info = &(g_serviceInfo[i]);
|
||||
|
||||
if (strlen(service_info->name) == name_len && !strcmp(service_info->name, name))
|
||||
if (!strcmp(service_info->name, name))
|
||||
{
|
||||
ret = service_info->initialized;
|
||||
break;
|
||||
|
@ -194,7 +192,7 @@ Result servicesHasService(bool *out, const char *name)
|
|||
{
|
||||
if (!out || !name || !*name)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return MAKERESULT(Module_Libnx, LibnxError_IoError);
|
||||
}
|
||||
|
||||
|
@ -203,7 +201,7 @@ Result servicesHasService(bool *out, const char *name)
|
|||
SmServiceName service_name = smEncodeName(name);
|
||||
|
||||
rc = smAtmosphereHasService(out, service_name);
|
||||
if (R_FAILED(rc)) LOGFILE("smAtmosphereHasService failed for \"%s\"! (0x%08X).", name, rc);
|
||||
if (R_FAILED(rc)) LOG_MSG("smAtmosphereHasService failed for \"%s\"! (0x%08X).", name, rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -266,7 +264,7 @@ static bool servicesClkGetServiceType(void *arg)
|
|||
if (!arg) return false;
|
||||
|
||||
ServiceInfo *info = (ServiceInfo*)arg;
|
||||
if (strlen(info->name) != 3 || strcmp(info->name, "clk") != 0 || info->init_func != NULL || info->close_func != NULL) return false;
|
||||
if (strcmp(info->name, "clk") != 0 || info->init_func != NULL || info->close_func != NULL) return false;
|
||||
|
||||
/* Determine which service needs to be used to control hardware clock rates, depending on the system version. */
|
||||
/* This may either be pcv (sysver lower than 8.0.0) or clkrst (sysver equal to or greater than 8.0.0). */
|
||||
|
@ -285,7 +283,7 @@ static bool servicesSplCryptoCheckAvailability(void *arg)
|
|||
if (!arg) return false;
|
||||
|
||||
ServiceInfo *info = (ServiceInfo*)arg;
|
||||
if (strlen(info->name) != 7 || strcmp(info->name, "spl:mig") != 0 || info->init_func == NULL || info->close_func == NULL) return false;
|
||||
if (strcmp(info->name, "spl:mig") != 0 || info->init_func == NULL || info->close_func == NULL) return false;
|
||||
|
||||
/* Check if spl:mig is available (sysver equal to or greater than 4.0.0). */
|
||||
return !hosversionBefore(4, 0, 0);
|
||||
|
|
110
source/tik.c
110
source/tik.c
|
@ -125,7 +125,7 @@ bool tikRetrieveTicketByRightsId(Ticket *dst, const FsRightsId *id, bool use_gam
|
|||
{
|
||||
if (!dst || !id)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ bool tikRetrieveTicketByRightsId(Ticket *dst, const FsRightsId *id, bool use_gam
|
|||
bool tik_retrieved = (use_gamecard ? tikRetrieveTicketFromGameCardByRightsId(dst, id) : tikRetrieveTicketFromEsSaveDataByRightsId(dst, id));
|
||||
if (!tik_retrieved)
|
||||
{
|
||||
LOGFILE("Unable to retrieve ticket data!");
|
||||
LOG_MSG("Unable to retrieve ticket data!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -154,7 +154,7 @@ bool tikRetrieveTicketByRightsId(Ticket *dst, const FsRightsId *id, bool use_gam
|
|||
|
||||
if (!titlekey_retrieved)
|
||||
{
|
||||
LOGFILE("Unable to retrieve titlekey from ticket!");
|
||||
LOG_MSG("Unable to retrieve titlekey from ticket!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -162,7 +162,7 @@ bool tikRetrieveTicketByRightsId(Ticket *dst, const FsRightsId *id, bool use_gam
|
|||
/* Old custom tools used to wipe the key_generation field or save its value to a different offset. */
|
||||
if (!tikGetTitleKekDecryptedTitleKey(dst->dec_titlekey, dst->enc_titlekey, id->c[0xF]))
|
||||
{
|
||||
LOGFILE("Unable to perform titlekek decryption!");
|
||||
LOG_MSG("Unable to perform titlekek decryption!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,7 @@ bool tikConvertPersonalizedTicketToCommonTicket(Ticket *tik, u8 **out_raw_cert_c
|
|||
if (!tik || tik->type == TikType_None || tik->type > TikType_SigHmac160 || tik->size < SIGNED_TIK_MIN_SIZE || tik->size > SIGNED_TIK_MAX_SIZE || \
|
||||
!(tik_common_block = tikGetCommonBlock(tik->data)) || tik_common_block->titlekey_type != TikTitleKeyType_Personalized || !out_raw_cert_chain || !out_raw_cert_chain_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -207,7 +207,7 @@ bool tikConvertPersonalizedTicketToCommonTicket(Ticket *tik, u8 **out_raw_cert_c
|
|||
|
||||
if (!raw_cert_chain)
|
||||
{
|
||||
LOGFILE("Failed to generate raw certificate chain for common ticket signature issuer!");
|
||||
LOG_MSG("Failed to generate raw certificate chain for common ticket signature issuer!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -253,7 +253,7 @@ static bool tikRetrieveTicketFromGameCardByRightsId(Ticket *dst, const FsRightsI
|
|||
{
|
||||
if (!dst || !id)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -263,27 +263,27 @@ static bool tikRetrieveTicketFromGameCardByRightsId(Ticket *dst, const FsRightsI
|
|||
utilsGenerateHexStringFromData(tik_filename, sizeof(tik_filename), id->c, 0x10);
|
||||
strcat(tik_filename, ".tik");
|
||||
|
||||
if (!gamecardGetEntryInfoFromHashFileSystemPartitionByName(GameCardHashFileSystemPartitionType_Secure, tik_filename, &tik_offset, &tik_size))
|
||||
if (!gamecardGetHashFileSystemEntryInfoByName(GameCardHashFileSystemPartitionType_Secure, tik_filename, &tik_offset, &tik_size))
|
||||
{
|
||||
LOGFILE("Error retrieving offset and size for \"%s\" entry in secure hash FS partition!", tik_filename);
|
||||
LOG_MSG("Error retrieving offset and size for \"%s\" entry in secure hash FS partition!", tik_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tik_size < SIGNED_TIK_MIN_SIZE || tik_size > SIGNED_TIK_MAX_SIZE)
|
||||
{
|
||||
LOGFILE("Invalid size for \"%s\"! (0x%lX).", tik_filename, tik_size);
|
||||
LOG_MSG("Invalid size for \"%s\"! (0x%lX).", tik_filename, tik_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!gamecardReadStorage(dst->data, tik_size, tik_offset))
|
||||
{
|
||||
LOGFILE("Failed to read \"%s\" data from the inserted gamecard!", tik_filename);
|
||||
LOG_MSG("Failed to read \"%s\" data from the inserted gamecard!", tik_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!tikGetTicketTypeAndSize(dst->data, tik_size, &(dst->type), &(dst->size)))
|
||||
{
|
||||
LOGFILE("Unable to determine ticket type and size!");
|
||||
LOG_MSG("Unable to determine ticket type and size!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -294,7 +294,7 @@ static bool tikRetrieveTicketFromEsSaveDataByRightsId(Ticket *dst, const FsRight
|
|||
{
|
||||
if (!dst || !id)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -311,42 +311,42 @@ static bool tikRetrieveTicketFromEsSaveDataByRightsId(Ticket *dst, const FsRight
|
|||
/* Allocate memory to retrieve the ticket. */
|
||||
if (!(buf = malloc(buf_size)))
|
||||
{
|
||||
LOGFILE("Unable to allocate 0x%lX bytes block for temporary read buffer!", buf_size);
|
||||
LOG_MSG("Unable to allocate 0x%lX bytes block for temporary read buffer!", buf_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Get titlekey type. */
|
||||
if (!tikGetTitleKeyTypeFromRightsId(id, &titlekey_type))
|
||||
{
|
||||
LOGFILE("Unable to retrieve ticket titlekey type!");
|
||||
LOG_MSG("Unable to retrieve ticket titlekey type!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Open ES common/personalized system savefile. */
|
||||
if (!(save_ctx = save_open_savefile(titlekey_type == TikTitleKeyType_Common ? TIK_COMMON_SAVEFILE_PATH : TIK_PERSONALIZED_SAVEFILE_PATH, 0)))
|
||||
{
|
||||
LOGFILE("Failed to open ES %s ticket system savefile!", g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
LOG_MSG("Failed to open ES %s ticket system savefile!", g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Get ticket entry offset from ticket_list.bin. */
|
||||
if (!tikGetTicketEntryOffsetFromTicketList(save_ctx, buf, buf_size, id, &ticket_offset, titlekey_type))
|
||||
{
|
||||
LOGFILE("Unable to find an entry with a matching Rights ID in \"%s\" from ES %s ticket system save!", TIK_LIST_STORAGE_PATH, g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
LOG_MSG("Unable to find an entry with a matching Rights ID in \"%s\" from ES %s ticket system save!", TIK_LIST_STORAGE_PATH, g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Get ticket entry from ticket.bin. */
|
||||
if (!tikRetrieveTicketEntryFromTicketBin(save_ctx, buf, buf_size, id, ticket_offset, titlekey_type))
|
||||
{
|
||||
LOGFILE("Unable to find a matching %s ticket entry for the provided Rights ID!", g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
LOG_MSG("Unable to find a matching %s ticket entry for the provided Rights ID!", g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Get ticket type and size. */
|
||||
if (!tikGetTicketTypeAndSize(buf, SIGNED_TIK_MAX_SIZE, &(dst->type), &(dst->size)))
|
||||
{
|
||||
LOGFILE("Unable to determine ticket type and size!");
|
||||
LOG_MSG("Unable to determine ticket type and size!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -368,7 +368,7 @@ static bool tikGetTitleKekEncryptedTitleKeyFromTicket(Ticket *tik)
|
|||
|
||||
if (!tik || !(tik_common_block = tikGetCommonBlock(tik->data)))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -387,7 +387,7 @@ static bool tikGetTitleKekEncryptedTitleKeyFromTicket(Ticket *tik)
|
|||
/* Retrieve eTicket device key. */
|
||||
if (!tikRetrieveEticketDeviceKey())
|
||||
{
|
||||
LOGFILE("Unable to retrieve eTicket device key!");
|
||||
LOG_MSG("Unable to retrieve eTicket device key!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -397,7 +397,7 @@ static bool tikGetTitleKekEncryptedTitleKeyFromTicket(Ticket *tik)
|
|||
if (!rsa2048OaepDecryptAndVerify(out_keydata, 0x100, tik_common_block->titlekey_block, eticket_devkey->modulus, eticket_devkey->exponent, 0x100, g_nullHash, &out_keydata_size) || \
|
||||
out_keydata_size < 0x10)
|
||||
{
|
||||
LOGFILE("RSA-OAEP titlekey decryption failed!");
|
||||
LOG_MSG("RSA-OAEP titlekey decryption failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -406,7 +406,7 @@ static bool tikGetTitleKekEncryptedTitleKeyFromTicket(Ticket *tik)
|
|||
|
||||
break;
|
||||
default:
|
||||
LOGFILE("Invalid titlekey type value! (0x%02X).", tik_common_block->titlekey_type);
|
||||
LOG_MSG("Invalid titlekey type value! (0x%02X).", tik_common_block->titlekey_type);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -417,7 +417,7 @@ static bool tikGetTitleKekDecryptedTitleKey(void *dst, const void *src, u8 key_g
|
|||
{
|
||||
if (!dst || !src)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -427,7 +427,7 @@ static bool tikGetTitleKekDecryptedTitleKey(void *dst, const void *src, u8 key_g
|
|||
titlekek = keysGetTitlekek(key_generation);
|
||||
if (!titlekek)
|
||||
{
|
||||
LOGFILE("Unable to retrieve titlekek for key generation 0x%02X!", key_generation);
|
||||
LOG_MSG("Unable to retrieve titlekek for key generation 0x%02X!", key_generation);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -441,7 +441,7 @@ static bool tikGetTitleKeyTypeFromRightsId(const FsRightsId *id, u8 *out)
|
|||
{
|
||||
if (!id || !out)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -456,7 +456,7 @@ static bool tikGetTitleKeyTypeFromRightsId(const FsRightsId *id, u8 *out)
|
|||
|
||||
if (!tikRetrieveRightsIdsByTitleKeyType(&rights_ids, &count, i == 1))
|
||||
{
|
||||
LOGFILE("Unable to retrieve %s rights IDs!", g_tikTitleKeyTypeStrings[i]);
|
||||
LOG_MSG("Unable to retrieve %s rights IDs!", g_tikTitleKeyTypeStrings[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -484,7 +484,7 @@ static bool tikRetrieveRightsIdsByTitleKeyType(FsRightsId **out, u32 *out_count,
|
|||
{
|
||||
if (!out || !out_count)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -499,27 +499,27 @@ static bool tikRetrieveRightsIdsByTitleKeyType(FsRightsId **out, u32 *out_count,
|
|||
rc = (personalized ? esCountPersonalizedTicket((s32*)&count) : esCountCommonTicket((s32*)&count));
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("esCount%c%sTicket failed! (0x%08X).", toupper(g_tikTitleKeyTypeStrings[str_idx][0]), g_tikTitleKeyTypeStrings[str_idx] + 1);
|
||||
LOG_MSG("esCount%c%sTicket failed! (0x%08X).", toupper(g_tikTitleKeyTypeStrings[str_idx][0]), g_tikTitleKeyTypeStrings[str_idx] + 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
{
|
||||
LOGFILE("No %s tickets available!", g_tikTitleKeyTypeStrings[str_idx]);
|
||||
LOG_MSG("No %s tickets available!", g_tikTitleKeyTypeStrings[str_idx]);
|
||||
return true;
|
||||
}
|
||||
|
||||
rights_ids = calloc(count, sizeof(FsRightsId));
|
||||
if (!rights_ids)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for %s rights IDs!", g_tikTitleKeyTypeStrings[str_idx]);
|
||||
LOG_MSG("Unable to allocate memory for %s rights IDs!", g_tikTitleKeyTypeStrings[str_idx]);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = (personalized ? esListPersonalizedTicket((s32*)&ids_written, rights_ids, (s32)count) : esListCommonTicket((s32*)&ids_written, rights_ids, (s32)count));
|
||||
if (R_FAILED(rc) || !ids_written)
|
||||
{
|
||||
LOGFILE("esList%c%sTicket failed! (0x%08X). Wrote %u entries, expected %u entries.", toupper(g_tikTitleKeyTypeStrings[str_idx][0]), g_tikTitleKeyTypeStrings[str_idx] + 1, rc, ids_written, count);
|
||||
LOG_MSG("esList%c%sTicket failed! (0x%08X). Wrote %u entries, expected %u entries.", toupper(g_tikTitleKeyTypeStrings[str_idx][0]), g_tikTitleKeyTypeStrings[str_idx] + 1, rc, ids_written, count);
|
||||
free(rights_ids);
|
||||
return false;
|
||||
}
|
||||
|
@ -534,7 +534,7 @@ static bool tikGetTicketEntryOffsetFromTicketList(save_ctx_t *save_ctx, u8 *buf,
|
|||
{
|
||||
if (!save_ctx || !buf || !buf_size || (buf_size % sizeof(TikListEntry)) != 0 || !id || !out_offset)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -549,14 +549,14 @@ static bool tikGetTicketEntryOffsetFromTicketList(save_ctx_t *save_ctx, u8 *buf,
|
|||
/* Get FAT storage info for the ticket_list.bin stored within the opened system savefile. */
|
||||
if (!save_get_fat_storage_from_file_entry_by_path(save_ctx, TIK_LIST_STORAGE_PATH, &fat_storage, &ticket_list_bin_size))
|
||||
{
|
||||
LOGFILE("Failed to locate \"%s\" in ES %s ticket system save!", TIK_LIST_STORAGE_PATH, g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
LOG_MSG("Failed to locate \"%s\" in ES %s ticket system save!", TIK_LIST_STORAGE_PATH, g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check ticket_list.bin size. */
|
||||
if (ticket_list_bin_size < sizeof(TikListEntry) || (ticket_list_bin_size % sizeof(TikListEntry)) != 0)
|
||||
{
|
||||
LOGFILE("Invalid size for \"%s\" in ES %s ticket system save! (0x%lX).", TIK_LIST_STORAGE_PATH, g_tikTitleKeyTypeStrings[titlekey_type], ticket_list_bin_size);
|
||||
LOG_MSG("Invalid size for \"%s\" in ES %s ticket system save! (0x%lX).", TIK_LIST_STORAGE_PATH, g_tikTitleKeyTypeStrings[titlekey_type], ticket_list_bin_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -567,7 +567,7 @@ static bool tikGetTicketEntryOffsetFromTicketList(save_ctx_t *save_ctx, u8 *buf,
|
|||
|
||||
if ((br = save_allocation_table_storage_read(&fat_storage, buf, total_br, buf_size)) != buf_size)
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes chunk at offset 0x%lX from \"%s\" in ES %s ticket system save!", buf_size, total_br, TIK_LIST_STORAGE_PATH, g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
LOG_MSG("Failed to read 0x%lX bytes chunk at offset 0x%lX from \"%s\" in ES %s ticket system save!", buf_size, total_br, TIK_LIST_STORAGE_PATH, g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -607,7 +607,7 @@ static bool tikRetrieveTicketEntryFromTicketBin(save_ctx_t *save_ctx, u8 *buf, u
|
|||
{
|
||||
if (!save_ctx || !buf || buf_size < SIGNED_TIK_MAX_SIZE || !id || (ticket_offset % SIGNED_TIK_MAX_SIZE) != 0)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -624,27 +624,27 @@ static bool tikRetrieveTicketEntryFromTicketBin(save_ctx_t *save_ctx, u8 *buf, u
|
|||
/* Get FAT storage info for the ticket.bin stored within the opened system savefile. */
|
||||
if (!save_get_fat_storage_from_file_entry_by_path(save_ctx, TIK_DB_STORAGE_PATH, &fat_storage, &ticket_bin_size))
|
||||
{
|
||||
LOGFILE("Failed to locate \"%s\" in ES %s ticket system save!", TIK_DB_STORAGE_PATH, g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
LOG_MSG("Failed to locate \"%s\" in ES %s ticket system save!", TIK_DB_STORAGE_PATH, g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check ticket.bin size. */
|
||||
if (ticket_bin_size < SIGNED_TIK_MIN_SIZE || (ticket_bin_size % SIGNED_TIK_MAX_SIZE) != 0 || ticket_bin_size < (ticket_offset + SIGNED_TIK_MAX_SIZE))
|
||||
{
|
||||
LOGFILE("Invalid size for \"%s\" in ES %s ticket system save! (0x%lX).", TIK_DB_STORAGE_PATH, g_tikTitleKeyTypeStrings[titlekey_type], ticket_bin_size);
|
||||
LOG_MSG("Invalid size for \"%s\" in ES %s ticket system save! (0x%lX).", TIK_DB_STORAGE_PATH, g_tikTitleKeyTypeStrings[titlekey_type], ticket_bin_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Read ticket data. */
|
||||
if ((br = save_allocation_table_storage_read(&fat_storage, buf, ticket_offset, SIGNED_TIK_MAX_SIZE)) != SIGNED_TIK_MAX_SIZE)
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes long ticket at offset 0x%lX from \"%s\" in ES %s ticket system save!", SIGNED_TIK_MAX_SIZE, ticket_offset, TIK_DB_STORAGE_PATH, \
|
||||
LOG_MSG("Failed to read 0x%lX bytes long ticket at offset 0x%lX from \"%s\" in ES %s ticket system save!", SIGNED_TIK_MAX_SIZE, ticket_offset, TIK_DB_STORAGE_PATH, \
|
||||
g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check if we're dealing with a volatile (encrypted) ticket. */
|
||||
if (!(tik_common_block = tikGetCommonBlock(buf)) || strncmp(tik_common_block->issuer, "Root", 4) != 0)
|
||||
if (!(tik_common_block = tikGetCommonBlock(buf)) || strncmp(tik_common_block->issuer, "Root-", 5) != 0)
|
||||
{
|
||||
tik_common_block = NULL;
|
||||
is_volatile = true;
|
||||
|
@ -652,14 +652,14 @@ static bool tikRetrieveTicketEntryFromTicketBin(save_ctx_t *save_ctx, u8 *buf, u
|
|||
/* Don't proceed if HOS version isn't at least 9.0.0. */
|
||||
if (!hosversionAtLeast(9, 0, 0))
|
||||
{
|
||||
LOGFILE("Unable to retrieve ES key entry for volatile tickets under HOS versions below 9.0.0!");
|
||||
LOG_MSG("Unable to retrieve ES key entry for volatile tickets under HOS versions below 9.0.0!");
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Retrieve ES program memory. */
|
||||
if (!memRetrieveFullProgramMemory(&g_esMemoryLocation))
|
||||
{
|
||||
LOGFILE("Failed to retrieve ES program memory!");
|
||||
LOG_MSG("Failed to retrieve ES program memory!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -683,7 +683,7 @@ static bool tikRetrieveTicketEntryFromTicketBin(save_ctx_t *save_ctx, u8 *buf, u
|
|||
aes128CtrCrypt(&ctr_ctx, dec_tik, buf, SIGNED_TIK_MAX_SIZE);
|
||||
|
||||
/* Check if we successfully decrypted this ticket. */
|
||||
if ((tik_common_block = tikGetCommonBlock(dec_tik)) != NULL && !strncmp(tik_common_block->issuer, "Root", 4))
|
||||
if ((tik_common_block = tikGetCommonBlock(dec_tik)) != NULL && !strncmp(tik_common_block->issuer, "Root-", 5))
|
||||
{
|
||||
memcpy(buf, dec_tik, SIGNED_TIK_MAX_SIZE);
|
||||
tik_common_block = tikGetCommonBlock(buf);
|
||||
|
@ -696,13 +696,13 @@ static bool tikRetrieveTicketEntryFromTicketBin(save_ctx_t *save_ctx, u8 *buf, u
|
|||
/* Check if we were able to decrypt the ticket. */
|
||||
if (!tik_common_block)
|
||||
{
|
||||
LOGFILE("Unable to decrypt volatile ticket at offset 0x%lX in \"%s\" from ES %s ticket system save!", ticket_offset, TIK_DB_STORAGE_PATH, g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
LOG_MSG("Unable to decrypt volatile ticket at offset 0x%lX in \"%s\" from ES %s ticket system save!", ticket_offset, TIK_DB_STORAGE_PATH, g_tikTitleKeyTypeStrings[titlekey_type]);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if the rights ID from the ticket common block matches the one we're looking for. */
|
||||
if (!(success = (memcmp(tik_common_block->rights_id.c, id->c, 0x10) == 0))) LOGFILE("Retrieved ticket doesn't hold a matching Rights ID!");
|
||||
if (!(success = (memcmp(tik_common_block->rights_id.c, id->c, 0x10) == 0))) LOG_MSG("Retrieved ticket doesn't hold a matching Rights ID!");
|
||||
|
||||
end:
|
||||
if (is_volatile) memFreeMemoryLocation(&g_esMemoryLocation);
|
||||
|
@ -718,13 +718,13 @@ static bool tikGetTicketTypeAndSize(void *data, u64 data_size, u8 *out_type, u64
|
|||
|
||||
if (!data || data_size < SIGNED_TIK_MIN_SIZE || data_size > SIGNED_TIK_MAX_SIZE || !out_type || !out_size)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(signed_ticket_size = tikGetSignedTicketSize(data)) || signed_ticket_size > data_size)
|
||||
{
|
||||
LOGFILE("Input buffer doesn't hold a valid signed ticket!");
|
||||
LOG_MSG("Input buffer doesn't hold a valid signed ticket!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -769,7 +769,7 @@ static bool tikRetrieveEticketDeviceKey(void)
|
|||
rc = setcalGetEticketDeviceKey(&g_eTicketDeviceKey);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("setcalGetEticketDeviceKey failed! (0x%08X).", rc);
|
||||
LOG_MSG("setcalGetEticketDeviceKey failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -783,14 +783,14 @@ static bool tikRetrieveEticketDeviceKey(void)
|
|||
public_exponent = __builtin_bswap32(eticket_devkey->public_exponent);
|
||||
if (public_exponent != ETICKET_DEVKEY_PUBLIC_EXPONENT)
|
||||
{
|
||||
LOGFILE("Invalid public RSA exponent for eTicket device key! Wrong keys? (0x%08X).", public_exponent);
|
||||
LOG_MSG("Invalid public RSA exponent for eTicket device key! Wrong keys? (0x%08X).", public_exponent);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Test RSA key pair. */
|
||||
if (!tikTestKeyPairFromEticketDeviceKey(&(eticket_devkey->public_exponent), eticket_devkey->exponent, eticket_devkey->modulus))
|
||||
{
|
||||
LOGFILE("RSA key pair test failed! Wrong keys?");
|
||||
LOG_MSG("RSA key pair test failed! Wrong keys?");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -803,7 +803,7 @@ static bool tikTestKeyPairFromEticketDeviceKey(const void *e, const void *d, con
|
|||
{
|
||||
if (!e || !d || !n)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -819,20 +819,20 @@ static bool tikTestKeyPairFromEticketDeviceKey(const void *e, const void *d, con
|
|||
rc = splUserExpMod(x, n, d, 0x100, y);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("splUserExpMod failed! (#1) (0x%08X).", rc);
|
||||
LOG_MSG("splUserExpMod failed! (#1) (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = splUserExpMod(y, n, e, 4, z);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("splUserExpMod failed! (#2) (0x%08X).", rc);
|
||||
LOG_MSG("splUserExpMod failed! (#2) (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (memcmp(x, z, 0x100) != 0)
|
||||
{
|
||||
LOGFILE("Invalid RSA key pair!");
|
||||
LOG_MSG("Invalid RSA key pair!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
116
source/title.c
116
source/title.c
|
@ -428,14 +428,14 @@ bool titleInitialize(void)
|
|||
g_nsAppControlData = calloc(1, sizeof(NsApplicationControlData));
|
||||
if (!g_nsAppControlData)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for the ns application control data!");
|
||||
LOG_MSG("Failed to allocate memory for the ns application control data!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Generate application metadata entries from hardcoded system titles, since we can't retrieve their names via ns. */
|
||||
if (!titleGenerateMetadataEntriesFromSystemTitles())
|
||||
{
|
||||
LOGFILE("Failed to generate application metadata from hardcoded system titles!");
|
||||
LOG_MSG("Failed to generate application metadata from hardcoded system titles!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -444,28 +444,28 @@ bool titleInitialize(void)
|
|||
/* However, if any new gamecard is inserted while the application is running, we *will* have to retrieve the metadata from its application(s). */
|
||||
if (!titleGenerateMetadataEntriesFromNsRecords())
|
||||
{
|
||||
LOGFILE("Failed to generate application metadata from ns records!");
|
||||
LOG_MSG("Failed to generate application metadata from ns records!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Open eMMC System, eMMC User and SD card ncm databases. */
|
||||
if (!titleOpenNcmDatabases())
|
||||
{
|
||||
LOGFILE("Failed to open ncm databases!");
|
||||
LOG_MSG("Failed to open ncm databases!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Open eMMC System, eMMC User and SD card ncm storages. */
|
||||
if (!titleOpenNcmStorages())
|
||||
{
|
||||
LOGFILE("Failed to open ncm storages!");
|
||||
LOG_MSG("Failed to open ncm storages!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Load title info by retrieving content meta keys from available eMMC System, eMMC User and SD card titles. */
|
||||
if (!titleLoadPersistentStorageTitleInfo())
|
||||
{
|
||||
LOGFILE("Failed to load persistent storage title info!");
|
||||
LOG_MSG("Failed to load persistent storage title info!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -476,7 +476,7 @@ bool titleInitialize(void)
|
|||
g_titleGameCardStatusChangeUserEvent = gamecardGetStatusChangeUserEvent();
|
||||
if (!g_titleGameCardStatusChangeUserEvent)
|
||||
{
|
||||
LOGFILE("Failed to retrieve gamecard status change user event!");
|
||||
LOG_MSG("Failed to retrieve gamecard status change user event!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -590,7 +590,7 @@ TitleApplicationMetadata **titleGetApplicationMetadataEntries(bool is_system, u3
|
|||
|
||||
if (!g_titleInterfaceInit || !g_appMetadata || (is_system && g_appMetadataCount < g_systemTitlesCount) || (!is_system && g_appMetadataCount == g_systemTitlesCount) || !out_count)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -606,7 +606,7 @@ TitleApplicationMetadata **titleGetApplicationMetadataEntries(bool is_system, u3
|
|||
tmp_app_metadata = realloc(app_metadata, (app_count + 1) * sizeof(TitleApplicationMetadata*));
|
||||
if (!tmp_app_metadata)
|
||||
{
|
||||
LOGFILE("Failed to reallocate application metadata pointer buffer!");
|
||||
LOG_MSG("Failed to reallocate application metadata pointer buffer!");
|
||||
if (app_metadata) free(app_metadata);
|
||||
app_metadata = NULL;
|
||||
goto end;
|
||||
|
@ -622,7 +622,7 @@ TitleApplicationMetadata **titleGetApplicationMetadataEntries(bool is_system, u3
|
|||
/* Update output counter. */
|
||||
*out_count = app_count;
|
||||
|
||||
if (!app_metadata || !app_count) LOGFILE("No content data found for %s!", is_system ? "system titles" : "user applications");
|
||||
if (!app_metadata || !app_count) LOG_MSG("No content data found for %s!", is_system ? "system titles" : "user applications");
|
||||
|
||||
end:
|
||||
mutexUnlock(&g_titleMutex);
|
||||
|
@ -643,7 +643,7 @@ bool titleGetUserApplicationData(u64 app_id, TitleUserApplicationData *out)
|
|||
|
||||
if (!g_titleInterfaceInit || !out)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -671,7 +671,7 @@ bool titleGetUserApplicationData(u64 app_id, TitleUserApplicationData *out)
|
|||
success = (out->app_info || out->patch_info || out->aoc_info);
|
||||
if (!success)
|
||||
{
|
||||
LOGFILE("Failed to retrieve user application data for ID \"%016lX\"!", app_id);
|
||||
LOG_MSG("Failed to retrieve user application data for ID \"%016lX\"!", app_id);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -697,7 +697,7 @@ TitleInfo **titleGetInfoFromOrphanTitles(u32 *out_count)
|
|||
|
||||
if (!g_titleInterfaceInit || !g_titleInfo || !g_titleInfoCount || !g_titleInfoOrphanCount || !out_count)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -705,7 +705,7 @@ TitleInfo **titleGetInfoFromOrphanTitles(u32 *out_count)
|
|||
orphan_info = calloc(g_titleInfoOrphanCount, sizeof(TitleInfo*));
|
||||
if (!orphan_info)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for orphan title info buffer!");
|
||||
LOG_MSG("Failed to allocate memory for orphan title info buffer!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -761,7 +761,7 @@ char *titleGenerateFileName(const TitleInfo *title_info, u8 name_convention, u8
|
|||
if (!title_info || title_info->meta_key.type < NcmContentMetaType_Application || title_info->meta_key.type > NcmContentMetaType_Delta || name_convention > TitleFileNameConvention_IdAndVersionOnly || \
|
||||
(name_convention == TitleFileNameConvention_Full && illegal_char_replace_type > TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -785,7 +785,7 @@ char *titleGenerateFileName(const TitleInfo *title_info, u8 name_convention, u8
|
|||
|
||||
/* Duplicate generated filename. */
|
||||
filename = strdup(title_name);
|
||||
if (!filename) LOGFILE("Failed to duplicate generated filename!");
|
||||
if (!filename) LOG_MSG("Failed to duplicate generated filename!");
|
||||
|
||||
end:
|
||||
mutexUnlock(&g_titleMutex);
|
||||
|
@ -805,7 +805,7 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_
|
|||
g_titleInfoGameCardStartIndex != (g_titleInfoCount - g_titleInfoGameCardCount) || name_convention > TitleFileNameConvention_IdAndVersionOnly || \
|
||||
(name_convention == TitleFileNameConvention_Full && illegal_char_replace_type > TitleFileNameIllegalCharReplaceType_KeepAsciiCharsOnly))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -856,7 +856,7 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_
|
|||
tmp_filename = realloc(filename, (cur_filename_len + app_name_len + 1) * sizeof(char));
|
||||
if (!tmp_filename)
|
||||
{
|
||||
LOGFILE("Failed to reallocate filename buffer!");
|
||||
LOG_MSG("Failed to reallocate filename buffer!");
|
||||
if (filename) free(filename);
|
||||
filename = NULL;
|
||||
goto end;
|
||||
|
@ -871,7 +871,7 @@ char *titleGenerateGameCardFileName(u8 name_convention, u8 illegal_char_replace_
|
|||
cur_filename_len += app_name_len;
|
||||
}
|
||||
|
||||
if (!filename) LOGFILE("Error: the inserted gamecard doesn't hold any user applications!");
|
||||
if (!filename) LOG_MSG("Error: the inserted gamecard doesn't hold any user applications!");
|
||||
|
||||
end:
|
||||
mutexUnlock(&g_titleMutex);
|
||||
|
@ -947,7 +947,7 @@ static bool titleGenerateMetadataEntriesFromSystemTitles(void)
|
|||
tmp_app_metadata = realloc(g_appMetadata, (g_appMetadataCount + g_systemTitlesCount) * sizeof(TitleApplicationMetadata));
|
||||
if (!tmp_app_metadata)
|
||||
{
|
||||
LOGFILE("Failed to reallocate application metadata buffer! (%u %s).", g_appMetadataCount + g_systemTitlesCount, (g_appMetadataCount + g_systemTitlesCount) > 1 ? "entries" : "entry");
|
||||
LOG_MSG("Failed to reallocate application metadata buffer! (%u %s).", g_appMetadataCount + g_systemTitlesCount, (g_appMetadataCount + g_systemTitlesCount) > 1 ? "entries" : "entry");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -992,7 +992,7 @@ static bool titleGenerateMetadataEntriesFromNsRecords(void)
|
|||
app_records = calloc(NS_APPLICATION_RECORD_LIMIT, sizeof(NsApplicationRecord));
|
||||
if (!app_records)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for ns application records!");
|
||||
LOG_MSG("Failed to allocate memory for ns application records!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1000,7 +1000,7 @@ static bool titleGenerateMetadataEntriesFromNsRecords(void)
|
|||
rc = nsListApplicationRecord(app_records, NS_APPLICATION_RECORD_LIMIT, 0, (s32*)&app_records_count);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("nsListApplicationRecord failed! (0x%08X).", rc);
|
||||
LOG_MSG("nsListApplicationRecord failed! (0x%08X).", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1015,7 +1015,7 @@ static bool titleGenerateMetadataEntriesFromNsRecords(void)
|
|||
tmp_app_metadata = realloc(g_appMetadata, (g_appMetadataCount + app_records_count) * sizeof(TitleApplicationMetadata));
|
||||
if (!tmp_app_metadata)
|
||||
{
|
||||
LOGFILE("Failed to reallocate application metadata buffer! (%u %s).", g_appMetadataCount + app_records_count, (g_appMetadataCount + app_records_count) > 1 ? "entries" : "entry");
|
||||
LOG_MSG("Failed to reallocate application metadata buffer! (%u %s).", g_appMetadataCount + app_records_count, (g_appMetadataCount + app_records_count) > 1 ? "entries" : "entry");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1032,7 +1032,7 @@ static bool titleGenerateMetadataEntriesFromNsRecords(void)
|
|||
/* Check retrieved application metadata count. */
|
||||
if (!new_app_count)
|
||||
{
|
||||
LOGFILE("Unable to retrieve application metadata from ns application records! (%u %s).", app_records_count, app_records_count > 1 ? "entries" : "entry");
|
||||
LOG_MSG("Unable to retrieve application metadata from ns application records! (%u %s).", app_records_count, app_records_count > 1 ? "entries" : "entry");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1056,7 +1056,7 @@ end:
|
|||
g_appMetadata = tmp_app_metadata;
|
||||
tmp_app_metadata = NULL;
|
||||
} else {
|
||||
LOGFILE("Failed to reallocate application metadata buffer! (%u %s).", g_appMetadataCount, g_appMetadataCount > 1 ? "entries" : "entry");
|
||||
LOG_MSG("Failed to reallocate application metadata buffer! (%u %s).", g_appMetadataCount, g_appMetadataCount > 1 ? "entries" : "entry");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1070,7 +1070,7 @@ static bool titleRetrieveApplicationMetadataByTitleId(u64 title_id, TitleApplica
|
|||
{
|
||||
if (!g_nsAppControlData || !title_id || !out)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1085,13 +1085,13 @@ static bool titleRetrieveApplicationMetadataByTitleId(u64 title_id, TitleApplica
|
|||
rc = nsGetApplicationControlData(NsApplicationControlSource_Storage, title_id, g_nsAppControlData, sizeof(NsApplicationControlData), &write_size);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("nsGetApplicationControlData failed for title ID \"%016lX\"! (0x%08X).", rc, title_id);
|
||||
LOG_MSG("nsGetApplicationControlData failed for title ID \"%016lX\"! (0x%08X).", rc, title_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (write_size < sizeof(NacpStruct))
|
||||
{
|
||||
LOGFILE("Retrieved application control data buffer is too small! (0x%lX).", write_size);
|
||||
LOG_MSG("Retrieved application control data buffer is too small! (0x%lX).", write_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1099,7 +1099,7 @@ static bool titleRetrieveApplicationMetadataByTitleId(u64 title_id, TitleApplica
|
|||
rc = nacpGetLanguageEntry(&(g_nsAppControlData->nacp), &lang_entry);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("nacpGetLanguageEntry failed! (0x%08X).", rc);
|
||||
LOG_MSG("nacpGetLanguageEntry failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1110,7 +1110,7 @@ static bool titleRetrieveApplicationMetadataByTitleId(u64 title_id, TitleApplica
|
|||
icon = malloc(icon_size);
|
||||
if (!icon)
|
||||
{
|
||||
LOGFILE("Error allocating memory for the icon buffer! (0x%X).", icon_size);
|
||||
LOG_MSG("Error allocating memory for the icon buffer! (0x%X).", icon_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1141,7 +1141,7 @@ static bool titleOpenNcmDatabases(void)
|
|||
ncm_db = titleGetNcmDatabaseByStorageId(i);
|
||||
if (!ncm_db)
|
||||
{
|
||||
LOGFILE("Failed to retrieve ncm database pointer for storage ID %u!", i);
|
||||
LOG_MSG("Failed to retrieve ncm database pointer for storage ID %u!", i);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1154,7 +1154,7 @@ static bool titleOpenNcmDatabases(void)
|
|||
{
|
||||
/* If the SD card is mounted, but it isn't currently being used by HOS, 0x21005 will be returned, so we'll just filter this particular error and continue. */
|
||||
/* This can occur when using the "Nintendo" directory from a different console, or when the "sdmc:/Nintendo/Contents/private" file is corrupted. */
|
||||
LOGFILE("ncmOpenContentMetaDatabase failed for storage ID %u! (0x%08X).", i, rc);
|
||||
LOG_MSG("ncmOpenContentMetaDatabase failed for storage ID %u! (0x%08X).", i, rc);
|
||||
if (i == NcmStorageId_SdCard && rc == 0x21005) continue;
|
||||
return false;
|
||||
}
|
||||
|
@ -1189,7 +1189,7 @@ static bool titleOpenNcmStorages(void)
|
|||
ncm_storage = titleGetNcmStorageByStorageId(i);
|
||||
if (!ncm_storage)
|
||||
{
|
||||
LOGFILE("Failed to retrieve ncm storage pointer for storage ID %u!", i);
|
||||
LOG_MSG("Failed to retrieve ncm storage pointer for storage ID %u!", i);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1202,7 +1202,7 @@ static bool titleOpenNcmStorages(void)
|
|||
{
|
||||
/* If the SD card is mounted, but it isn't currently being used by HOS, 0x21005 will be returned, so we'll just filter this particular error and continue. */
|
||||
/* This can occur when using the "Nintendo" directory from a different console, or when the "sdmc:/Nintendo/Contents/private" file is corrupted. */
|
||||
LOGFILE("ncmOpenContentStorage failed for storage ID %u! (0x%08X).", i, rc);
|
||||
LOG_MSG("ncmOpenContentStorage failed for storage ID %u! (0x%08X).", i, rc);
|
||||
if (i == NcmStorageId_SdCard && rc == 0x21005) continue;
|
||||
return false;
|
||||
}
|
||||
|
@ -1236,7 +1236,7 @@ static bool titleOpenNcmDatabaseAndStorageFromGameCard(void)
|
|||
rc = ncmOpenContentMetaDatabase(ncm_db, NcmStorageId_GameCard);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("ncmOpenContentMetaDatabase failed! (0x%08X).", rc);
|
||||
LOG_MSG("ncmOpenContentMetaDatabase failed! (0x%08X).", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1244,7 +1244,7 @@ static bool titleOpenNcmDatabaseAndStorageFromGameCard(void)
|
|||
rc = ncmOpenContentStorage(ncm_storage, NcmStorageId_GameCard);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("ncmOpenContentStorage failed! (0x%08X).", rc);
|
||||
LOG_MSG("ncmOpenContentStorage failed! (0x%08X).", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1274,7 +1274,7 @@ static bool titleLoadPersistentStorageTitleInfo(void)
|
|||
/* Generate title info from the current storage. */
|
||||
if (!titleGenerateTitleInfoFromStorage(i))
|
||||
{
|
||||
LOGFILE("Failed to generate title info from storage ID %u!", i);
|
||||
LOG_MSG("Failed to generate title info from storage ID %u!", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1288,7 +1288,7 @@ static bool titleGenerateTitleInfoFromStorage(u8 storage_id)
|
|||
|
||||
if (!(ncm_db = titleGetNcmDatabaseByStorageId(storage_id)) || !serviceIsActive(&(ncm_db->s)))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1306,7 +1306,7 @@ static bool titleGenerateTitleInfoFromStorage(u8 storage_id)
|
|||
meta_keys = calloc(1, meta_keys_size);
|
||||
if (!meta_keys)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the ncm application meta keys!");
|
||||
LOG_MSG("Unable to allocate memory for the ncm application meta keys!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1315,7 +1315,7 @@ static bool titleGenerateTitleInfoFromStorage(u8 storage_id)
|
|||
rc = ncmContentMetaDatabaseList(ncm_db, (s32*)&total, (s32*)&written, meta_keys, 1, 0, 0, 0, UINT64_MAX, NcmContentInstallType_Full);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("ncmContentMetaDatabaseList failed! (0x%08X) (first entry).", rc);
|
||||
LOG_MSG("ncmContentMetaDatabaseList failed! (0x%08X) (first entry).", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1337,7 +1337,7 @@ static bool titleGenerateTitleInfoFromStorage(u8 storage_id)
|
|||
meta_keys_tmp = realloc(meta_keys, meta_keys_size);
|
||||
if (!meta_keys_tmp)
|
||||
{
|
||||
LOGFILE("Unable to reallocate application meta keys buffer! (%u entries).", total);
|
||||
LOG_MSG("Unable to reallocate application meta keys buffer! (%u entries).", total);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1348,14 +1348,14 @@ static bool titleGenerateTitleInfoFromStorage(u8 storage_id)
|
|||
rc = ncmContentMetaDatabaseList(ncm_db, (s32*)&total, (s32*)&written, meta_keys, (s32)total, 0, 0, 0, UINT64_MAX, NcmContentInstallType_Full);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("ncmContentMetaDatabaseList failed! (0x%08X) (%u %s).", rc, total, total > 1 ? "entries" : "entry");
|
||||
LOG_MSG("ncmContentMetaDatabaseList failed! (0x%08X) (%u %s).", rc, total, total > 1 ? "entries" : "entry");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Safety check. */
|
||||
if (written != total)
|
||||
{
|
||||
LOGFILE("Application meta key count mismatch! (%u != %u).", written, total);
|
||||
LOG_MSG("Application meta key count mismatch! (%u != %u).", written, total);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
@ -1365,7 +1365,7 @@ static bool titleGenerateTitleInfoFromStorage(u8 storage_id)
|
|||
tmp_title_info = realloc(g_titleInfo, (g_titleInfoCount + total) * sizeof(TitleInfo));
|
||||
if (!tmp_title_info)
|
||||
{
|
||||
LOGFILE("Unable to reallocate title info buffer! (%u %s).", g_titleInfoCount + total, (g_titleInfoCount + total) > 1 ? "entries" : "entry");
|
||||
LOG_MSG("Unable to reallocate title info buffer! (%u %s).", g_titleInfoCount + total, (g_titleInfoCount + total) > 1 ? "entries" : "entry");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1431,7 +1431,7 @@ static bool titleGetContentInfosFromTitle(u8 storage_id, const NcmContentMetaKey
|
|||
|
||||
if (!(ncm_db = titleGetNcmDatabaseByStorageId(storage_id)) || !serviceIsActive(&(ncm_db->s)) || !meta_key || !out_content_infos || !out_content_count)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1449,13 +1449,13 @@ static bool titleGetContentInfosFromTitle(u8 storage_id, const NcmContentMetaKey
|
|||
rc = ncmContentMetaDatabaseGet(ncm_db, meta_key, &content_meta_header_read_size, &content_meta_header, sizeof(NcmContentMetaHeader));
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("ncmContentMetaDatabaseGet failed! (0x%08X).", rc);
|
||||
LOG_MSG("ncmContentMetaDatabaseGet failed! (0x%08X).", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (content_meta_header_read_size != sizeof(NcmContentMetaHeader))
|
||||
{
|
||||
LOGFILE("Content meta header size mismatch! (0x%lX != 0x%lX).", rc, content_meta_header_read_size, sizeof(NcmContentMetaHeader));
|
||||
LOG_MSG("Content meta header size mismatch! (0x%lX != 0x%lX).", rc, content_meta_header_read_size, sizeof(NcmContentMetaHeader));
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1463,7 +1463,7 @@ static bool titleGetContentInfosFromTitle(u8 storage_id, const NcmContentMetaKey
|
|||
content_count = (u32)content_meta_header.content_count;
|
||||
if (!content_count)
|
||||
{
|
||||
LOGFILE("Content count is zero!");
|
||||
LOG_MSG("Content count is zero!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1471,7 +1471,7 @@ static bool titleGetContentInfosFromTitle(u8 storage_id, const NcmContentMetaKey
|
|||
content_infos = calloc(content_count, sizeof(NcmContentInfo));
|
||||
if (!content_infos)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for the content infos buffer! (%u content[s]).", content_count);
|
||||
LOG_MSG("Unable to allocate memory for the content infos buffer! (%u content[s]).", content_count);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1479,13 +1479,13 @@ static bool titleGetContentInfosFromTitle(u8 storage_id, const NcmContentMetaKey
|
|||
rc = ncmContentMetaDatabaseListContentInfo(ncm_db, (s32*)&written, content_infos, (s32)content_count, meta_key, 0);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("ncmContentMetaDatabaseListContentInfo failed! (0x%08X).", rc);
|
||||
LOG_MSG("ncmContentMetaDatabaseListContentInfo failed! (0x%08X).", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (written != content_count)
|
||||
{
|
||||
LOGFILE("Content count mismatch! (%u != %u).", written, content_count);
|
||||
LOG_MSG("Content count mismatch! (%u != %u).", written, content_count);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1571,7 +1571,7 @@ static bool titleCreateGameCardInfoThread(void)
|
|||
{
|
||||
if (!utilsCreateThread(&g_titleGameCardInfoThread, titleGameCardInfoThreadFunc, NULL, 1))
|
||||
{
|
||||
LOGFILE("Failed to create gamecard title info thread!");
|
||||
LOG_MSG("Failed to create gamecard title info thread!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1667,7 +1667,7 @@ static bool titleRefreshGameCardTitleInfo(void)
|
|||
/* Open gamecard ncm database and storage handles. */
|
||||
if (!titleOpenNcmDatabaseAndStorageFromGameCard())
|
||||
{
|
||||
LOGFILE("Failed to open gamecard ncm database and storage handles.");
|
||||
LOG_MSG("Failed to open gamecard ncm database and storage handles.");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1677,7 +1677,7 @@ static bool titleRefreshGameCardTitleInfo(void)
|
|||
/* Generate gamecard title info. */
|
||||
if (!titleGenerateTitleInfoFromStorage(NcmStorageId_GameCard))
|
||||
{
|
||||
LOGFILE("Failed to generate gamecard title info!");
|
||||
LOG_MSG("Failed to generate gamecard title info!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1685,7 +1685,7 @@ static bool titleRefreshGameCardTitleInfo(void)
|
|||
g_titleInfoGameCardCount = (g_titleInfoCount - g_titleInfoGameCardStartIndex);
|
||||
if (!g_titleInfoGameCardCount)
|
||||
{
|
||||
LOGFILE("Empty content meta key count from gamecard!");
|
||||
LOG_MSG("Empty content meta key count from gamecard!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1708,7 +1708,7 @@ static bool titleRefreshGameCardTitleInfo(void)
|
|||
tmp_app_metadata = realloc(g_appMetadata, (g_appMetadataCount + 1) * sizeof(TitleApplicationMetadata));
|
||||
if (!tmp_app_metadata)
|
||||
{
|
||||
LOGFILE("Failed to reallocate application metadata buffer! (additional entry).");
|
||||
LOG_MSG("Failed to reallocate application metadata buffer! (additional entry).");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1840,7 +1840,7 @@ static TitleInfo *_titleGetInfoFromStorageByTitleId(u8 storage_id, u64 title_id,
|
|||
if (!g_titleInterfaceInit || !g_titleInfo || !g_titleInfoCount || storage_id < NcmStorageId_GameCard || storage_id > NcmStorageId_Any || (storage_id == NcmStorageId_GameCard && \
|
||||
(!g_titleInfoGameCardCount || g_titleInfoGameCardCount > g_titleInfoCount || g_titleInfoGameCardStartIndex != (g_titleInfoCount - g_titleInfoGameCardCount))) || !title_id)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -1859,7 +1859,7 @@ static TitleInfo *_titleGetInfoFromStorageByTitleId(u8 storage_id, u64 title_id,
|
|||
}
|
||||
}
|
||||
|
||||
if (!info && lock) LOGFILE("Unable to find TitleInfo entry with ID \"%016lX\"! (storage ID %u).", title_id, storage_id);
|
||||
if (!info && lock) LOG_MSG("Unable to find TitleInfo entry with ID \"%016lX\"! (storage ID %u).", title_id, storage_id);
|
||||
|
||||
end:
|
||||
if (lock) mutexUnlock(&g_titleMutex);
|
||||
|
|
16
source/ums.c
16
source/ums.c
|
@ -53,7 +53,7 @@ bool umsInitialize(void)
|
|||
rc = usbHsFsInitialize(0);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbHsFsInitialize failed! (0x%08X).", rc);
|
||||
LOG_MSG("usbHsFsInitialize failed! (0x%08X).", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ UsbHsFsDevice *umsGetDevices(u32 *out_count)
|
|||
|
||||
if (!g_umsInterfaceInit || !out_count)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ UsbHsFsDevice *umsGetDevices(u32 *out_count)
|
|||
devices = calloc(g_umsDeviceCount, sizeof(UsbHsFsDevice));
|
||||
if (!devices)
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for %u devices!", g_umsDeviceCount);
|
||||
LOG_MSG("Failed to allocate memory for %u devices!", g_umsDeviceCount);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -152,7 +152,7 @@ static bool umsCreateDetectionThread(void)
|
|||
{
|
||||
if (!utilsCreateThread(&g_umsDetectionThread, umsDetectionThreadFunc, NULL, 1))
|
||||
{
|
||||
LOGFILE("Failed to create USB Mass Storage detection thread!");
|
||||
LOG_MSG("Failed to create USB Mass Storage detection thread!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ static void umsDetectionThreadFunc(void *arg)
|
|||
|
||||
/* Get mounted device count. */
|
||||
g_umsDeviceCount = usbHsFsGetMountedDeviceCount();
|
||||
LOGFILE("USB Mass Storage status change event triggered! Mounted USB Mass Storage device count: %u.", g_umsDeviceCount);
|
||||
LOG_MSG("USB Mass Storage status change event triggered! Mounted USB Mass Storage device count: %u.", g_umsDeviceCount);
|
||||
|
||||
if (g_umsDeviceCount)
|
||||
{
|
||||
|
@ -215,15 +215,15 @@ static void umsDetectionThreadFunc(void *arg)
|
|||
/* Update USB Mass Storage device info updated flag. */
|
||||
g_umsDeviceInfoUpdated = true;
|
||||
} else {
|
||||
LOGFILE("USB Mass Storage device count mismatch! (%u != %u).", listed_device_count, g_umsDeviceCount);
|
||||
LOG_MSG("USB Mass Storage device count mismatch! (%u != %u).", listed_device_count, g_umsDeviceCount);
|
||||
fail = true;
|
||||
}
|
||||
} else {
|
||||
LOGFILE("Failed to list mounted USB Mass Storage devices!");
|
||||
LOG_MSG("Failed to list mounted USB Mass Storage devices!");
|
||||
fail = true;
|
||||
}
|
||||
} else {
|
||||
LOGFILE("Failed to allocate memory for mounted USB Mass Storage devices buffer!");
|
||||
LOG_MSG("Failed to allocate memory for mounted USB Mass Storage devices buffer!");
|
||||
fail = true;
|
||||
}
|
||||
|
||||
|
|
128
source/usb.c
128
source/usb.c
|
@ -227,14 +227,14 @@ bool usbInitialize(void)
|
|||
/* Allocate USB transfer buffer. */
|
||||
if (!usbAllocateTransferBuffer())
|
||||
{
|
||||
LOGFILE("Failed to allocate memory for the USB transfer buffer!");
|
||||
LOG_MSG("Failed to allocate memory for the USB transfer buffer!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize USB device interface. */
|
||||
if (!usbInitializeComms())
|
||||
{
|
||||
LOGFILE("Failed to initialize USB device interface!");
|
||||
LOG_MSG("Failed to initialize USB device interface!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -242,7 +242,7 @@ bool usbInitialize(void)
|
|||
g_usbStateChangeEvent = usbDsGetStateChangeEvent();
|
||||
if (!g_usbStateChangeEvent)
|
||||
{
|
||||
LOGFILE("Failed to retrieve USB state change kernel event!");
|
||||
LOG_MSG("Failed to retrieve USB state change kernel event!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -317,7 +317,7 @@ bool usbSendFileProperties(u64 file_size, const char *filename, u32 nsp_header_s
|
|||
!(filename_length = strlen(filename)) || filename_length >= FS_MAX_PATH || (!g_nspTransferMode && ((file_size && nsp_header_size >= file_size) || g_usbTransferRemainingSize)) || \
|
||||
(g_nspTransferMode && nsp_header_size))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -362,7 +362,7 @@ bool usbSendFileData(void *data, u64 data_size)
|
|||
if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInit || !g_usbDeviceInterface.initialized || !g_usbHostAvailable || !g_usbSessionStarted || !g_usbTransferRemainingSize || !data || \
|
||||
!data_size || data_size > USB_TRANSFER_BUFFER_SIZE || data_size > g_usbTransferRemainingSize)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -385,21 +385,21 @@ bool usbSendFileData(void *data, u64 data_size)
|
|||
{
|
||||
zlt_required = true;
|
||||
usbSetZltPacket(true);
|
||||
//LOGFILE("ZLT enabled. Last chunk size: 0x%lX bytes.", data_size);
|
||||
//LOG_MSG("ZLT enabled. Last chunk size: 0x%lX bytes.", data_size);
|
||||
}
|
||||
} else {
|
||||
/* Disable ZLT if this is the first of multiple data chunks. */
|
||||
if (!g_usbTransferWrittenSize)
|
||||
{
|
||||
usbSetZltPacket(false);
|
||||
//LOGFILE("ZLT disabled (first chunk).");
|
||||
//LOG_MSG("ZLT disabled (first chunk).");
|
||||
}
|
||||
}
|
||||
|
||||
/* Send data chunk. */
|
||||
if (!usbWrite(buf, data_size))
|
||||
{
|
||||
LOGFILE("Failed to write 0x%lX bytes long file data chunk from offset 0x%lX! (total size: 0x%lX).", data_size, g_usbTransferWrittenSize, g_usbTransferRemainingSize + g_usbTransferWrittenSize);
|
||||
LOG_MSG("Failed to write 0x%lX bytes long file data chunk from offset 0x%lX! (total size: 0x%lX).", data_size, g_usbTransferWrittenSize, g_usbTransferRemainingSize + g_usbTransferWrittenSize);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -413,7 +413,7 @@ bool usbSendFileData(void *data, u64 data_size)
|
|||
/* Check response from host device. */
|
||||
if (!usbRead(g_usbTransferBuffer, sizeof(UsbStatus)))
|
||||
{
|
||||
LOGFILE("Failed to read 0x%lX bytes long status block!", sizeof(UsbStatus));
|
||||
LOG_MSG("Failed to read 0x%lX bytes long status block!", sizeof(UsbStatus));
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
@ -422,7 +422,7 @@ bool usbSendFileData(void *data, u64 data_size)
|
|||
|
||||
if (cmd_status->magic != __builtin_bswap32(USB_CMD_HEADER_MAGIC))
|
||||
{
|
||||
LOGFILE("Invalid status block magic word!");
|
||||
LOG_MSG("Invalid status block magic word!");
|
||||
ret = false;
|
||||
goto end;
|
||||
}
|
||||
|
@ -481,7 +481,7 @@ bool usbSendNspHeader(void *nsp_header, u32 nsp_header_size)
|
|||
if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInit || !g_usbDeviceInterface.initialized || !g_usbHostAvailable || !g_usbSessionStarted || g_usbTransferRemainingSize || \
|
||||
!g_nspTransferMode || !nsp_header || !nsp_header_size || nsp_header_size > (USB_TRANSFER_BUFFER_SIZE - sizeof(UsbCommandHeader)))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -506,7 +506,7 @@ static bool usbCreateDetectionThread(void)
|
|||
{
|
||||
if (!utilsCreateThread(&g_usbDetectionThread, usbDetectionThreadFunc, NULL, 1))
|
||||
{
|
||||
LOGFILE("Failed to create USB detection thread!");
|
||||
LOG_MSG("Failed to create USB detection thread!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -563,7 +563,7 @@ static void usbDetectionThreadFunc(void *arg)
|
|||
g_usbSessionStarted = usbStartSession();
|
||||
if (g_usbSessionStarted)
|
||||
{
|
||||
LOGFILE("USB session successfully established. Endpoint max packet size: 0x%04X.", g_usbEndpointMaxPacketSize);
|
||||
LOG_MSG("USB session successfully established. Endpoint max packet size: 0x%04X.", g_usbEndpointMaxPacketSize);
|
||||
} else {
|
||||
/* Check if the exit event was triggered while waiting for a session to be established. */
|
||||
if (g_usbDetectionThreadExitFlag) break;
|
||||
|
@ -593,7 +593,7 @@ static bool usbStartSession(void)
|
|||
|
||||
if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInit || !g_usbDeviceInterface.initialized)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -617,7 +617,7 @@ static bool usbStartSession(void)
|
|||
g_usbEndpointMaxPacketSize = cmd_status->max_packet_size;
|
||||
if (g_usbEndpointMaxPacketSize != USB_FS_EP_MAX_PACKET_SIZE && g_usbEndpointMaxPacketSize != USB_HS_EP_MAX_PACKET_SIZE && g_usbEndpointMaxPacketSize != USB_SS_EP_MAX_PACKET_SIZE)
|
||||
{
|
||||
LOGFILE("Invalid endpoint max packet size value received from USB host: 0x%04X.", g_usbEndpointMaxPacketSize);
|
||||
LOG_MSG("Invalid endpoint max packet size value received from USB host: 0x%04X.", g_usbEndpointMaxPacketSize);
|
||||
|
||||
/* Reset flags. */
|
||||
ret = false;
|
||||
|
@ -633,7 +633,7 @@ static void usbEndSession(void)
|
|||
{
|
||||
if (!g_usbTransferBuffer || !g_usbDeviceInterfaceInit || !g_usbDeviceInterface.initialized || !g_usbHostAvailable || !g_usbSessionStarted)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -667,7 +667,7 @@ static bool usbSendCommand(void)
|
|||
|
||||
if ((sizeof(UsbCommandHeader) + cmd_block_size) > USB_TRANSFER_BUFFER_SIZE)
|
||||
{
|
||||
LOGFILE("Invalid command size!");
|
||||
LOG_MSG("Invalid command size!");
|
||||
status = UsbStatusType_InvalidCommandSize;
|
||||
goto end;
|
||||
}
|
||||
|
@ -675,7 +675,7 @@ static bool usbSendCommand(void)
|
|||
/* Write command header first. */
|
||||
if (!usbWrite(cmd_header, sizeof(UsbCommandHeader)))
|
||||
{
|
||||
if (log_rw_errors) LOGFILE("Failed to write header for type 0x%X command!", cmd);
|
||||
if (log_rw_errors) LOG_MSG("Failed to write header for type 0x%X command!", cmd);
|
||||
status = UsbStatusType_WriteCommandFailed;
|
||||
goto end;
|
||||
}
|
||||
|
@ -694,7 +694,7 @@ static bool usbSendCommand(void)
|
|||
cmd_block_written = usbWrite(g_usbTransferBuffer, cmd_block_size);
|
||||
if (!cmd_block_written)
|
||||
{
|
||||
if (log_rw_errors) LOGFILE("Failed to write command block for type 0x%X command!", cmd);
|
||||
if (log_rw_errors) LOG_MSG("Failed to write command block for type 0x%X command!", cmd);
|
||||
status = UsbStatusType_WriteCommandFailed;
|
||||
}
|
||||
|
||||
|
@ -708,7 +708,7 @@ static bool usbSendCommand(void)
|
|||
/* Read status block. */
|
||||
if (!usbRead(cmd_status, sizeof(UsbStatus)))
|
||||
{
|
||||
if (log_rw_errors) LOGFILE("Failed to read 0x%lX bytes long status block for type 0x%X command!", sizeof(UsbStatus), cmd);
|
||||
if (log_rw_errors) LOG_MSG("Failed to read 0x%lX bytes long status block for type 0x%X command!", sizeof(UsbStatus), cmd);
|
||||
status = UsbStatusType_ReadStatusFailed;
|
||||
goto end;
|
||||
}
|
||||
|
@ -739,22 +739,22 @@ static void usbLogStatusDetail(u32 status)
|
|||
case UsbStatusType_ReadStatusFailed:
|
||||
break;
|
||||
case UsbStatusType_InvalidMagicWord:
|
||||
LOGFILE("Host replied with Invalid Magic Word status code.");
|
||||
LOG_MSG("Host replied with Invalid Magic Word status code.");
|
||||
break;
|
||||
case UsbStatusType_UnsupportedCommand:
|
||||
LOGFILE("Host replied with Unsupported Command status code.");
|
||||
LOG_MSG("Host replied with Unsupported Command status code.");
|
||||
break;
|
||||
case UsbStatusType_UnsupportedAbiVersion:
|
||||
LOGFILE("Host replied with Unsupported ABI Version status code.");
|
||||
LOG_MSG("Host replied with Unsupported ABI Version status code.");
|
||||
break;
|
||||
case UsbStatusType_MalformedCommand:
|
||||
LOGFILE("Host replied with Malformed Command status code.");
|
||||
LOG_MSG("Host replied with Malformed Command status code.");
|
||||
break;
|
||||
case UsbStatusType_HostIoError:
|
||||
LOGFILE("Host replied with I/O Error status code.");
|
||||
LOG_MSG("Host replied with I/O Error status code.");
|
||||
break;
|
||||
default:
|
||||
LOGFILE("Unknown status code: 0x%X.", status);
|
||||
LOG_MSG("Unknown status code: 0x%X.", status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -839,7 +839,7 @@ static bool usbInitializeComms(void)
|
|||
rc = usbDsInitialize();
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInitialize failed! (0x%08X).", rc);
|
||||
LOG_MSG("usbDsInitialize failed! (0x%08X).", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -847,27 +847,27 @@ static bool usbInitializeComms(void)
|
|||
{
|
||||
/* Set language string descriptor. */
|
||||
rc = usbDsAddUsbLanguageStringDescriptor(NULL, supported_langs, num_supported_langs);
|
||||
if (R_FAILED(rc)) LOGFILE("usbDsAddUsbLanguageStringDescriptor failed! (0x%08X).", rc);
|
||||
if (R_FAILED(rc)) LOG_MSG("usbDsAddUsbLanguageStringDescriptor failed! (0x%08X).", rc);
|
||||
|
||||
/* Set manufacturer string descriptor. */
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
rc = usbDsAddUsbStringDescriptor(&(device_descriptor.iManufacturer), APP_AUTHOR);
|
||||
if (R_FAILED(rc)) LOGFILE("usbDsAddUsbStringDescriptor failed! (0x%08X) (manufacturer).", rc);
|
||||
if (R_FAILED(rc)) LOG_MSG("usbDsAddUsbStringDescriptor failed! (0x%08X) (manufacturer).", rc);
|
||||
}
|
||||
|
||||
/* Set product string descriptor. */
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
rc = usbDsAddUsbStringDescriptor(&(device_descriptor.iProduct), APP_TITLE);
|
||||
if (R_FAILED(rc)) LOGFILE("usbDsAddUsbStringDescriptor failed! (0x%08X) (product).", rc);
|
||||
if (R_FAILED(rc)) LOG_MSG("usbDsAddUsbStringDescriptor failed! (0x%08X) (product).", rc);
|
||||
}
|
||||
|
||||
/* Set serial number string descriptor. */
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
rc = usbDsAddUsbStringDescriptor(&(device_descriptor.iSerialNumber), APP_VERSION);
|
||||
if (R_FAILED(rc)) LOGFILE("usbDsAddUsbStringDescriptor failed! (0x%08X) (serial number).", rc);
|
||||
if (R_FAILED(rc)) LOG_MSG("usbDsAddUsbStringDescriptor failed! (0x%08X) (serial number).", rc);
|
||||
}
|
||||
|
||||
/* Set device descriptors. */
|
||||
|
@ -875,7 +875,7 @@ static bool usbInitializeComms(void)
|
|||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_Full, &device_descriptor); /* Full Speed is USB 1.1. */
|
||||
if (R_FAILED(rc)) LOGFILE("usbDsSetUsbDeviceDescriptor failed! (0x%08X) (USB 1.1).", rc);
|
||||
if (R_FAILED(rc)) LOG_MSG("usbDsSetUsbDeviceDescriptor failed! (0x%08X) (USB 1.1).", rc);
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
|
@ -884,7 +884,7 @@ static bool usbInitializeComms(void)
|
|||
device_descriptor.bcdUSB = USB_HS_BCD_REVISION;
|
||||
|
||||
rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_High, &device_descriptor); /* High Speed is USB 2.0. */
|
||||
if (R_FAILED(rc)) LOGFILE("usbDsSetUsbDeviceDescriptor failed! (0x%08X) (USB 2.0).", rc);
|
||||
if (R_FAILED(rc)) LOG_MSG("usbDsSetUsbDeviceDescriptor failed! (0x%08X) (USB 2.0).", rc);
|
||||
}
|
||||
|
||||
if (R_SUCCEEDED(rc))
|
||||
|
@ -894,19 +894,19 @@ static bool usbInitializeComms(void)
|
|||
device_descriptor.bMaxPacketSize0 = USB_SS_EP0_MAX_PACKET_SIZE;
|
||||
|
||||
rc = usbDsSetUsbDeviceDescriptor(UsbDeviceSpeed_Super, &device_descriptor); /* Super Speed is USB 3.0. */
|
||||
if (R_FAILED(rc)) LOGFILE("usbDsSetUsbDeviceDescriptor failed! (0x%08X) (USB 3.0).", rc);
|
||||
if (R_FAILED(rc)) LOG_MSG("usbDsSetUsbDeviceDescriptor failed! (0x%08X) (USB 3.0).", rc);
|
||||
}
|
||||
|
||||
/* Set Binary Object Store. */
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
rc = usbDsSetBinaryObjectStore(bos, USB_BOS_SIZE);
|
||||
if (R_FAILED(rc)) LOGFILE("usbDsSetBinaryObjectStore failed! (0x%08X).", rc);
|
||||
if (R_FAILED(rc)) LOG_MSG("usbDsSetBinaryObjectStore failed! (0x%08X).", rc);
|
||||
}
|
||||
} else {
|
||||
/* Set VID, PID and BCD. */
|
||||
rc = usbDsSetVidPidBcd(&device_info);
|
||||
if (R_FAILED(rc)) LOGFILE("usbDsSetVidPidBcd failed! (0x%08X).", rc);
|
||||
if (R_FAILED(rc)) LOG_MSG("usbDsSetVidPidBcd failed! (0x%08X).", rc);
|
||||
}
|
||||
|
||||
if (R_FAILED(rc)) goto end;
|
||||
|
@ -924,7 +924,7 @@ static bool usbInitializeComms(void)
|
|||
|
||||
if (!dev_iface_init)
|
||||
{
|
||||
LOGFILE("Failed to initialize USB device interface!");
|
||||
LOG_MSG("Failed to initialize USB device interface!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -933,7 +933,7 @@ static bool usbInitializeComms(void)
|
|||
rc = usbDsEnable();
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsEnable failed! (0x%08X).", rc);
|
||||
LOG_MSG("usbDsEnable failed! (0x%08X).", rc);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
@ -1031,7 +1031,7 @@ static bool usbInitializeDeviceInterface5x(void)
|
|||
rc = usbDsRegisterInterface(&(g_usbDeviceInterface.interface));
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsRegisterInterface failed! (0x%08X).", rc);
|
||||
LOG_MSG("usbDsRegisterInterface failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1043,21 +1043,21 @@ static bool usbInitializeDeviceInterface5x(void)
|
|||
rc = usbDsInterface_AppendConfigurationData(g_usbDeviceInterface.interface, UsbDeviceSpeed_Full, &interface_descriptor, USB_DT_INTERFACE_SIZE);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 1.1) (interface).", rc);
|
||||
LOG_MSG("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 1.1) (interface).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = usbDsInterface_AppendConfigurationData(g_usbDeviceInterface.interface, UsbDeviceSpeed_Full, &endpoint_descriptor_in, USB_DT_ENDPOINT_SIZE);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 1.1) (in endpoint).", rc);
|
||||
LOG_MSG("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 1.1) (in endpoint).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = usbDsInterface_AppendConfigurationData(g_usbDeviceInterface.interface, UsbDeviceSpeed_Full, &endpoint_descriptor_out, USB_DT_ENDPOINT_SIZE);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 1.1) (out endpoint).", rc);
|
||||
LOG_MSG("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 1.1) (out endpoint).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1068,21 +1068,21 @@ static bool usbInitializeDeviceInterface5x(void)
|
|||
rc = usbDsInterface_AppendConfigurationData(g_usbDeviceInterface.interface, UsbDeviceSpeed_High, &interface_descriptor, USB_DT_INTERFACE_SIZE);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 2.0) (interface).", rc);
|
||||
LOG_MSG("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 2.0) (interface).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = usbDsInterface_AppendConfigurationData(g_usbDeviceInterface.interface, UsbDeviceSpeed_High, &endpoint_descriptor_in, USB_DT_ENDPOINT_SIZE);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 2.0) (in endpoint).", rc);
|
||||
LOG_MSG("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 2.0) (in endpoint).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = usbDsInterface_AppendConfigurationData(g_usbDeviceInterface.interface, UsbDeviceSpeed_High, &endpoint_descriptor_out, USB_DT_ENDPOINT_SIZE);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 2.0) (out endpoint).", rc);
|
||||
LOG_MSG("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 2.0) (out endpoint).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1093,35 +1093,35 @@ static bool usbInitializeDeviceInterface5x(void)
|
|||
rc = usbDsInterface_AppendConfigurationData(g_usbDeviceInterface.interface, UsbDeviceSpeed_Super, &interface_descriptor, USB_DT_INTERFACE_SIZE);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 3.0) (interface).", rc);
|
||||
LOG_MSG("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 3.0) (interface).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = usbDsInterface_AppendConfigurationData(g_usbDeviceInterface.interface, UsbDeviceSpeed_Super, &endpoint_descriptor_in, USB_DT_ENDPOINT_SIZE);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 3.0) (in endpoint).", rc);
|
||||
LOG_MSG("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 3.0) (in endpoint).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = usbDsInterface_AppendConfigurationData(g_usbDeviceInterface.interface, UsbDeviceSpeed_Super, &endpoint_companion, USB_DT_SS_ENDPOINT_COMPANION_SIZE);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 3.0) (in endpoint companion).", rc);
|
||||
LOG_MSG("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 3.0) (in endpoint companion).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = usbDsInterface_AppendConfigurationData(g_usbDeviceInterface.interface, UsbDeviceSpeed_Super, &endpoint_descriptor_out, USB_DT_ENDPOINT_SIZE);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 3.0) (out endpoint).", rc);
|
||||
LOG_MSG("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 3.0) (out endpoint).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = usbDsInterface_AppendConfigurationData(g_usbDeviceInterface.interface, UsbDeviceSpeed_Super, &endpoint_companion, USB_DT_SS_ENDPOINT_COMPANION_SIZE);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 3.0) (out endpoint companion).", rc);
|
||||
LOG_MSG("usbDsInterface_AppendConfigurationData failed! (0x%08X) (USB 3.0) (out endpoint companion).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1129,21 +1129,21 @@ static bool usbInitializeDeviceInterface5x(void)
|
|||
rc = usbDsInterface_RegisterEndpoint(g_usbDeviceInterface.interface, &(g_usbDeviceInterface.endpoint_in), endpoint_descriptor_in.bEndpointAddress);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_RegisterEndpoint failed! (0x%08X) (in endpoint).", rc);
|
||||
LOG_MSG("usbDsInterface_RegisterEndpoint failed! (0x%08X) (in endpoint).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = usbDsInterface_RegisterEndpoint(g_usbDeviceInterface.interface, &(g_usbDeviceInterface.endpoint_out), endpoint_descriptor_out.bEndpointAddress);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_RegisterEndpoint failed! (0x%08X) (out endpoint).", rc);
|
||||
LOG_MSG("usbDsInterface_RegisterEndpoint failed! (0x%08X) (out endpoint).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = usbDsInterface_EnableInterface(g_usbDeviceInterface.interface);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_EnableInterface failed! (0x%08X).", rc);
|
||||
LOG_MSG("usbDsInterface_EnableInterface failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1190,7 +1190,7 @@ static bool usbInitializeDeviceInterface1x(void)
|
|||
rc = usbDsGetDsInterface(&(g_usbDeviceInterface.interface), &interface_descriptor, "usb");
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsGetDsInterface failed! (0x%08X).", rc);
|
||||
LOG_MSG("usbDsGetDsInterface failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1198,21 +1198,21 @@ static bool usbInitializeDeviceInterface1x(void)
|
|||
rc = usbDsInterface_GetDsEndpoint(g_usbDeviceInterface.interface, &(g_usbDeviceInterface.endpoint_in), &endpoint_descriptor_in);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_GetDsEndpoint failed! (0x%08X) (in endpoint).", rc);
|
||||
LOG_MSG("usbDsInterface_GetDsEndpoint failed! (0x%08X) (in endpoint).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = usbDsInterface_GetDsEndpoint(g_usbDeviceInterface.interface, &(g_usbDeviceInterface.endpoint_out), &endpoint_descriptor_out);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_GetDsEndpoint failed! (0x%08X) (out endpoint).", rc);
|
||||
LOG_MSG("usbDsInterface_GetDsEndpoint failed! (0x%08X) (out endpoint).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = usbDsInterface_EnableInterface(g_usbDeviceInterface.interface);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsInterface_EnableInterface failed! (0x%08X).", rc);
|
||||
LOG_MSG("usbDsInterface_EnableInterface failed! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1253,13 +1253,13 @@ static bool usbTransferData(void *buf, u64 size, UsbDsEndpoint *endpoint)
|
|||
{
|
||||
if (!buf || !IS_ALIGNED((u64)buf, USB_TRANSFER_ALIGNMENT) || !size || !endpoint)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!usbIsHostAvailable())
|
||||
{
|
||||
LOGFILE("USB host unavailable!");
|
||||
LOG_MSG("USB host unavailable!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1272,7 +1272,7 @@ static bool usbTransferData(void *buf, u64 size, UsbDsEndpoint *endpoint)
|
|||
rc = usbDsEndpoint_PostBufferAsync(endpoint, buf, size, &urb_id);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsEndpoint_PostBufferAsync failed! (0x%08X) (URB ID %u).", rc, urb_id);
|
||||
LOG_MSG("usbDsEndpoint_PostBufferAsync failed! (0x%08X) (URB ID %u).", rc, urb_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1312,27 +1312,27 @@ static bool usbTransferData(void *buf, u64 size, UsbDsEndpoint *endpoint)
|
|||
/* This will "reset" the USB connection by making the background thread wait until a new session is established. */
|
||||
if (g_usbSessionStarted) ueventSignal(&g_usbTimeoutEvent);
|
||||
|
||||
if (!thread_exit) LOGFILE("eventWait failed! (0x%08X) (URB ID %u).", rc, urb_id);
|
||||
if (!thread_exit) LOG_MSG("eventWait failed! (0x%08X) (URB ID %u).", rc, urb_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = usbDsEndpoint_GetReportData(endpoint, &report_data);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsEndpoint_GetReportData failed! (0x%08X) (URB ID %u).", rc, urb_id);
|
||||
LOG_MSG("usbDsEndpoint_GetReportData failed! (0x%08X) (URB ID %u).", rc, urb_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = usbDsParseReportData(&report_data, urb_id, NULL, &transferred_size);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("usbDsParseReportData failed! (0x%08X) (URB ID %u).", rc, urb_id);
|
||||
LOG_MSG("usbDsParseReportData failed! (0x%08X) (URB ID %u).", rc, urb_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (transferred_size != size)
|
||||
{
|
||||
LOGFILE("USB transfer failed! Expected 0x%lX bytes, got 0x%X bytes (URB ID %u).", size, transferred_size, urb_id);
|
||||
LOG_MSG("USB transfer failed! Expected 0x%lX bytes, got 0x%X bytes (URB ID %u).", size, transferred_size, urb_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
233
source/utils.c
233
source/utils.c
|
@ -33,8 +33,6 @@
|
|||
#include "bfttf.h"
|
||||
#include "fatfs/ff.h"
|
||||
|
||||
#define LOGFILE_PATH "./" APP_TITLE ".log"
|
||||
|
||||
/* Global variables. */
|
||||
|
||||
static bool g_resourcesInit = false, g_isDevUnit = false;
|
||||
|
@ -55,10 +53,6 @@ static u8 g_customFirmwareType = UtilsCustomFirmwareType_Unknown;
|
|||
|
||||
static AppletHookCookie g_systemOverclockCookie = {0};
|
||||
|
||||
static Mutex g_logfileMutex = 0;
|
||||
static const char *g_logfileTimestampFormat = "%d-%02d-%02d %02d:%02d:%02d -> %s: ";
|
||||
static const char *g_logfileLineBreak = "\r\n";
|
||||
|
||||
static const char *g_sizeSuffixes[] = { "B", "KiB", "MiB", "GiB" };
|
||||
static const u32 g_sizeSuffixesCount = MAX_ELEMENTS(g_sizeSuffixes);
|
||||
|
||||
|
@ -89,32 +83,32 @@ bool utilsInitializeResources(void)
|
|||
padInitializeWithMask(&g_padState, 0x1000000FFUL);
|
||||
|
||||
/* Create logfile. */
|
||||
utilsWriteLogBufferToLogFile("________________________________________________________________\r\n");
|
||||
LOGFILE(APP_TITLE " v%u.%u.%u starting. Built on " __DATE__ " - " __TIME__ ".", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO);
|
||||
logWriteStringToLogFile("________________________________________________________________\r\n");
|
||||
LOG_MSG(APP_TITLE " v%u.%u.%u starting. Built on " __DATE__ " - " __TIME__ ".", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO);
|
||||
|
||||
/* Log Horizon OS version. */
|
||||
u32 hos_version = hosversionGet();
|
||||
LOGFILE("Horizon OS version: %u.%u.%u.", HOSVER_MAJOR(hos_version), HOSVER_MINOR(hos_version), HOSVER_MICRO(hos_version));
|
||||
LOG_MSG("Horizon OS version: %u.%u.%u.", HOSVER_MAJOR(hos_version), HOSVER_MINOR(hos_version), HOSVER_MICRO(hos_version));
|
||||
|
||||
/* Retrieve custom firmware type. */
|
||||
_utilsGetCustomFirmwareType();
|
||||
LOGFILE("Detected %s CFW.", (g_customFirmwareType == UtilsCustomFirmwareType_Atmosphere ? "Atmosphère" : (g_customFirmwareType == UtilsCustomFirmwareType_SXOS ? "SX OS" : "ReiNX")));
|
||||
LOG_MSG("Detected %s CFW.", (g_customFirmwareType == UtilsCustomFirmwareType_Atmosphere ? "Atmosphère" : (g_customFirmwareType == UtilsCustomFirmwareType_SXOS ? "SX OS" : "ReiNX")));
|
||||
|
||||
/* Initialize needed services. */
|
||||
if (!servicesInitialize())
|
||||
{
|
||||
LOGFILE("Failed to initialize needed services!");
|
||||
LOG_MSG("Failed to initialize needed services!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Check if we're not running under a development unit. */
|
||||
if (!_utilsIsDevelopmentUnit()) goto end;
|
||||
LOGFILE("Running under %s unit.", g_isDevUnit ? "development" : "retail");
|
||||
LOG_MSG("Running under %s unit.", g_isDevUnit ? "development" : "retail");
|
||||
|
||||
/* Initialize USB interface. */
|
||||
if (!usbInitialize())
|
||||
{
|
||||
LOGFILE("Failed to initialize USB interface!");
|
||||
LOG_MSG("Failed to initialize USB interface!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -124,42 +118,42 @@ bool utilsInitializeResources(void)
|
|||
/* Load NCA keyset. */
|
||||
if (!keysLoadNcaKeyset())
|
||||
{
|
||||
LOGFILE("Failed to load NCA keyset!");
|
||||
LOG_MSG("Failed to load NCA keyset!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Allocate NCA crypto buffer. */
|
||||
if (!ncaAllocateCryptoBuffer())
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for NCA crypto buffer!");
|
||||
LOG_MSG("Unable to allocate memory for NCA crypto buffer!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize gamecard interface. */
|
||||
if (!gamecardInitialize())
|
||||
{
|
||||
LOGFILE("Failed to initialize gamecard interface!");
|
||||
LOG_MSG("Failed to initialize gamecard interface!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize title interface. */
|
||||
if (!titleInitialize())
|
||||
{
|
||||
LOGFILE("Failed to initialize the title interface!");
|
||||
LOG_MSG("Failed to initialize the title interface!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Initialize BFTTF interface. */
|
||||
if (!bfttfInitialize())
|
||||
{
|
||||
LOGFILE("Failed to initialize BFTTF interface!");
|
||||
LOG_MSG("Failed to initialize BFTTF interface!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Retrieve pointer to the SD card FsFileSystem element. */
|
||||
if (!(g_sdCardFileSystem = fsdevGetDeviceFileSystem("sdmc:")))
|
||||
{
|
||||
LOGFILE("Failed to retrieve FsFileSystem from SD card!");
|
||||
LOG_MSG("Failed to retrieve FsFileSystem from SD card!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -168,7 +162,7 @@ bool utilsInitializeResources(void)
|
|||
|
||||
/* Get applet type. */
|
||||
g_programAppletType = appletGetAppletType();
|
||||
LOGFILE("Running under %s mode.", utilsAppletModeCheck() ? "applet" : "title override");
|
||||
LOG_MSG("Running under %s mode.", utilsAppletModeCheck() ? "applet" : "title override");
|
||||
|
||||
/* Disable screen dimming and auto sleep. */
|
||||
appletSetMediaPlaybackState(true);
|
||||
|
@ -239,6 +233,9 @@ void utilsCloseResources(void)
|
|||
/* Close initialized services. */
|
||||
servicesClose();
|
||||
|
||||
/* Close logfile. */
|
||||
logCloseLogFile();
|
||||
|
||||
g_resourcesInit = false;
|
||||
|
||||
mutexUnlock(&g_resourcesMutex);
|
||||
|
@ -250,7 +247,7 @@ bool utilsCreateThread(Thread *out_thread, ThreadFunc func, void *arg, int cpu_i
|
|||
/* -2 can be provided to use the default process core. */
|
||||
if (!out_thread || !func || (cpu_id < 0 && cpu_id != -2) || cpu_id > 2)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -265,7 +262,7 @@ bool utilsCreateThread(Thread *out_thread, ThreadFunc func, void *arg, int cpu_i
|
|||
rc = svcGetInfo(&core_mask, InfoType_CoreMask, CUR_PROCESS_HANDLE, 0);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("svcGetInfo failed! (0x%08X).", rc);
|
||||
LOG_MSG("svcGetInfo failed! (0x%08X).", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -274,7 +271,7 @@ bool utilsCreateThread(Thread *out_thread, ThreadFunc func, void *arg, int cpu_i
|
|||
rc = threadCreate(out_thread, func, arg, NULL, stack_size, 0x3B, cpu_id);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("threadCreate failed! (0x%08X).", rc);
|
||||
LOG_MSG("threadCreate failed! (0x%08X).", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -282,7 +279,7 @@ bool utilsCreateThread(Thread *out_thread, ThreadFunc func, void *arg, int cpu_i
|
|||
rc = svcSetThreadCoreMask(out_thread->handle, cpu_id == -2 ? -1 : cpu_id, core_mask);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("svcSetThreadCoreMask failed! (0x%08X).", rc);
|
||||
LOG_MSG("svcSetThreadCoreMask failed! (0x%08X).", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -290,7 +287,7 @@ bool utilsCreateThread(Thread *out_thread, ThreadFunc func, void *arg, int cpu_i
|
|||
rc = threadStart(out_thread);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("threadStart failed! (0x%08X).", rc);
|
||||
LOG_MSG("threadStart failed! (0x%08X).", rc);
|
||||
goto end;
|
||||
}
|
||||
|
||||
|
@ -306,14 +303,14 @@ void utilsJoinThread(Thread *thread)
|
|||
{
|
||||
if (!thread || thread->handle == INVALID_HANDLE)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return;
|
||||
}
|
||||
|
||||
Result rc = threadWaitForExit(thread);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("threadWaitForExit failed! (0x%08X).", rc);
|
||||
LOG_MSG("threadWaitForExit failed! (0x%08X).", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -360,53 +357,65 @@ void utilsWaitForButtonPress(u64 flag)
|
|||
|
||||
bool utilsAppendFormattedStringToBuffer(char **dst, size_t *dst_size, const char *fmt, ...)
|
||||
{
|
||||
if (!dst || !dst_size || !fmt || !*fmt)
|
||||
if (!dst || !dst_size || (!*dst && *dst_size) || (*dst && !*dst_size) || !fmt || !*fmt)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
int formatted_str_len = 0;
|
||||
size_t required_dst_size = 0, dst_str_len = (*dst ? strlen(*dst) : 0);
|
||||
char *realloc_dst = NULL;
|
||||
size_t formatted_str_len = 0;
|
||||
|
||||
char *dst_ptr = *dst, *tmp_str = NULL;
|
||||
size_t dst_cur_size = *dst_size, dst_str_len = (dst_ptr ? strlen(dst_ptr) : 0);
|
||||
|
||||
bool success = false;
|
||||
|
||||
if (dst_str_len > *dst_size)
|
||||
if (dst_str_len >= dst_cur_size)
|
||||
{
|
||||
**dst = '\0';
|
||||
dst_str_len = 0;
|
||||
LOG_MSG("String length is equal to or greater than the provided buffer size! (0x%lX >= 0x%lX).", dst_str_len, dst_cur_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
/* Get formatted string length. */
|
||||
formatted_str_len = vsnprintf(NULL, 0, fmt, args);
|
||||
if (formatted_str_len <= 0)
|
||||
if ((int)formatted_str_len <= 0)
|
||||
{
|
||||
LOGFILE("Failed to retrieve formatted string length!");
|
||||
LOG_MSG("Failed to retrieve formatted string length!");
|
||||
goto end;
|
||||
}
|
||||
|
||||
required_dst_size = (dst_str_len + (size_t)formatted_str_len + 1);
|
||||
if (required_dst_size > *dst_size)
|
||||
formatted_str_len++;
|
||||
|
||||
if (!dst_cur_size || formatted_str_len > (dst_cur_size - dst_str_len))
|
||||
{
|
||||
realloc_dst = realloc(*dst, required_dst_size);
|
||||
if (!realloc_dst)
|
||||
/* Update buffer size. */
|
||||
dst_cur_size = (dst_str_len + formatted_str_len);
|
||||
|
||||
/* Reallocate buffer. */
|
||||
tmp_str = realloc(dst_ptr, dst_cur_size);
|
||||
if (!tmp_str)
|
||||
{
|
||||
LOGFILE("Failed to reallocate destination buffer!");
|
||||
LOG_MSG("Failed to resize buffer to 0x%lX byte(s).", dst_cur_size);
|
||||
goto end;
|
||||
}
|
||||
|
||||
*dst = realloc_dst;
|
||||
realloc_dst = NULL;
|
||||
dst_ptr = tmp_str;
|
||||
tmp_str = NULL;
|
||||
|
||||
memset(*dst + dst_str_len, 0, (size_t)formatted_str_len + 1);
|
||||
/* Clear allocated area. */
|
||||
memset(dst_ptr + dst_str_len, 0, formatted_str_len);
|
||||
|
||||
*dst_size = required_dst_size;
|
||||
/* Update pointers. */
|
||||
*dst = dst_ptr;
|
||||
*dst_size = dst_cur_size;
|
||||
}
|
||||
|
||||
vsprintf(*dst + dst_str_len, fmt, args);
|
||||
/* Generate formatted string. */
|
||||
vsprintf(dst_ptr + dst_str_len, fmt, args);
|
||||
success = true;
|
||||
|
||||
end:
|
||||
|
@ -415,109 +424,6 @@ end:
|
|||
return success;
|
||||
}
|
||||
|
||||
void utilsWriteMessageToLogFile(const char *func_name, const char *fmt, ...)
|
||||
{
|
||||
if (!func_name || !*func_name || !fmt || !*fmt) return;
|
||||
|
||||
mutexLock(&g_logfileMutex);
|
||||
|
||||
va_list args;
|
||||
|
||||
FILE *logfile = fopen(LOGFILE_PATH, "a+");
|
||||
if (!logfile) goto end;
|
||||
|
||||
time_t now = time(NULL);
|
||||
struct tm *ts = localtime(&now);
|
||||
|
||||
fprintf(logfile, g_logfileTimestampFormat, ts->tm_year + 1900, ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec, func_name);
|
||||
|
||||
va_start(args, fmt);
|
||||
vfprintf(logfile, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
fprintf(logfile, g_logfileLineBreak);
|
||||
fclose(logfile);
|
||||
utilsCommitSdCardFileSystemChanges();
|
||||
|
||||
end:
|
||||
mutexUnlock(&g_logfileMutex);
|
||||
}
|
||||
|
||||
void utilsWriteMessageToLogBuffer(char **dst, size_t *dst_size, const char *func_name, const char *fmt, ...)
|
||||
{
|
||||
if (!dst || !dst_size || !func_name || !*func_name || !fmt || !*fmt) return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
time_t now = time(NULL);
|
||||
struct tm *ts = localtime(&now);
|
||||
|
||||
int timestamp_len = 0, formatted_str_len = 0;
|
||||
size_t required_dst_size = 0, dst_str_len = (*dst ? strlen(*dst) : 0);
|
||||
char *realloc_dst = NULL;
|
||||
|
||||
if (dst_str_len > *dst_size)
|
||||
{
|
||||
**dst = '\0';
|
||||
dst_str_len = 0;
|
||||
}
|
||||
|
||||
timestamp_len = snprintf(NULL, 0, g_logfileTimestampFormat, ts->tm_year + 1900, ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec, func_name);
|
||||
if (timestamp_len <= 0) goto end;
|
||||
|
||||
formatted_str_len = vsnprintf(NULL, 0, fmt, args);
|
||||
if (formatted_str_len <= 0) goto end;
|
||||
|
||||
required_dst_size = (dst_str_len + (size_t)timestamp_len + (size_t)formatted_str_len + 3);
|
||||
if (required_dst_size > *dst_size)
|
||||
{
|
||||
realloc_dst = realloc(*dst, required_dst_size);
|
||||
if (!realloc_dst) goto end;
|
||||
|
||||
*dst = realloc_dst;
|
||||
realloc_dst = NULL;
|
||||
|
||||
memset(*dst + dst_str_len, 0, (size_t)timestamp_len + (size_t)formatted_str_len + 3);
|
||||
|
||||
*dst_size = required_dst_size;
|
||||
}
|
||||
|
||||
sprintf(*dst + dst_str_len, g_logfileTimestampFormat, ts->tm_year + 1900, ts->tm_mon + 1, ts->tm_mday, ts->tm_hour, ts->tm_min, ts->tm_sec, func_name);
|
||||
vsprintf(*dst + dst_str_len + (size_t)timestamp_len, fmt, args);
|
||||
sprintf(*dst + dst_str_len + (size_t)timestamp_len + (size_t)formatted_str_len, g_logfileLineBreak);
|
||||
|
||||
end:
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void utilsWriteLogBufferToLogFile(const char *src)
|
||||
{
|
||||
if (!src || !*src) return;
|
||||
|
||||
mutexLock(&g_logfileMutex);
|
||||
|
||||
FILE *logfile = fopen(LOGFILE_PATH, "a+");
|
||||
if (!logfile) goto end;
|
||||
|
||||
fprintf(logfile, "%s", src);
|
||||
fclose(logfile);
|
||||
utilsCommitSdCardFileSystemChanges();
|
||||
|
||||
end:
|
||||
mutexUnlock(&g_logfileMutex);
|
||||
}
|
||||
|
||||
void utilsLogFileMutexControl(bool lock)
|
||||
{
|
||||
if (lock)
|
||||
{
|
||||
mutexLock(&g_logfileMutex);
|
||||
} else {
|
||||
mutexUnlock(&g_logfileMutex);
|
||||
}
|
||||
}
|
||||
|
||||
void utilsReplaceIllegalCharacters(char *str, bool ascii_only)
|
||||
{
|
||||
size_t strsize = 0;
|
||||
|
@ -595,7 +501,7 @@ bool utilsGetFileSystemStatsByPath(const char *path, u64 *out_total, u64 *out_fr
|
|||
|
||||
if (!path || !*path || !(name_end = strchr(path, ':')) || *(name_end + 1) != '/' || (!out_total && !out_free))
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -604,7 +510,7 @@ bool utilsGetFileSystemStatsByPath(const char *path, u64 *out_total, u64 *out_fr
|
|||
|
||||
if ((ret = statvfs(stat_path, &info)) != 0)
|
||||
{
|
||||
LOGFILE("statvfs failed! (%d) (errno: %d).", ret, errno);
|
||||
LOG_MSG("statvfs failed! (%d) (errno: %d).", ret, errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -614,6 +520,11 @@ bool utilsGetFileSystemStatsByPath(const char *path, u64 *out_total, u64 *out_fr
|
|||
return true;
|
||||
}
|
||||
|
||||
FsFileSystem *utilsGetSdCardFileSystemObject(void)
|
||||
{
|
||||
return g_sdCardFileSystem;
|
||||
}
|
||||
|
||||
bool utilsCommitSdCardFileSystemChanges(void)
|
||||
{
|
||||
if (!g_sdCardFileSystem) return false;
|
||||
|
@ -646,7 +557,7 @@ bool utilsCreateConcatenationFile(const char *path)
|
|||
{
|
||||
if (!path || !*path)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -656,7 +567,7 @@ bool utilsCreateConcatenationFile(const char *path)
|
|||
/* Create ConcatenationFile */
|
||||
/* If the call succeeds, the caller function will be able to operate on this file using stdio calls. */
|
||||
Result rc = fsdevCreateFile(path, 0, FsCreateOption_BigFile);
|
||||
if (R_FAILED(rc)) LOGFILE("fsdevCreateFile failed for \"%s\"! (0x%08X).", path, rc);
|
||||
if (R_FAILED(rc)) LOG_MSG("fsdevCreateFile failed for \"%s\"! (0x%08X).", path, rc);
|
||||
|
||||
return R_SUCCEEDED(rc);
|
||||
}
|
||||
|
@ -688,7 +599,7 @@ char *utilsGeneratePath(const char *prefix, const char *filename, const char *ex
|
|||
{
|
||||
if (!filename || !*filename || !extension || !*extension)
|
||||
{
|
||||
LOGFILE("Invalid parameters!");
|
||||
LOG_MSG("Invalid parameters!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -698,7 +609,7 @@ char *utilsGeneratePath(const char *prefix, const char *filename, const char *ex
|
|||
|
||||
if (!(path = calloc(path_len, sizeof(char))))
|
||||
{
|
||||
LOGFILE("Failed to allocate 0x%lX bytes for output path!", path_len);
|
||||
LOG_MSG("Failed to allocate 0x%lX bytes for output path!", path_len);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -771,7 +682,7 @@ static bool _utilsIsDevelopmentUnit(void)
|
|||
{
|
||||
g_isDevUnit = tmp;
|
||||
} else {
|
||||
LOGFILE("splIsDevelopment failed! (0x%08X).", rc);
|
||||
LOG_MSG("splIsDevelopment failed! (0x%08X).", rc);
|
||||
}
|
||||
|
||||
return R_SUCCEEDED(rc);
|
||||
|
@ -785,21 +696,21 @@ static bool utilsMountEmmcBisSystemPartitionStorage(void)
|
|||
rc = fsOpenBisStorage(&g_emmcBisSystemPartitionStorage, FsBisPartitionId_System);
|
||||
if (R_FAILED(rc))
|
||||
{
|
||||
LOGFILE("Failed to open eMMC BIS System partition storage! (0x%08X).", rc);
|
||||
LOG_MSG("Failed to open eMMC BIS System partition storage! (0x%08X).", rc);
|
||||
return false;
|
||||
}
|
||||
|
||||
g_emmcBisSystemPartitionFatFsObj = calloc(1, sizeof(FATFS));
|
||||
if (!g_emmcBisSystemPartitionFatFsObj)
|
||||
{
|
||||
LOGFILE("Unable to allocate memory for FatFs element!");
|
||||
LOG_MSG("Unable to allocate memory for FatFs element!");
|
||||
return false;
|
||||
}
|
||||
|
||||
fr = f_mount(g_emmcBisSystemPartitionFatFsObj, BIS_SYSTEM_PARTITION_MOUNT_NAME, 1);
|
||||
if (fr != FR_OK)
|
||||
{
|
||||
LOGFILE("Failed to mount eMMC BIS System partition! (%u).", fr);
|
||||
LOG_MSG("Failed to mount eMMC BIS System partition! (%u).", fr);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,24 +23,7 @@
|
|||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <malloc.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdatomic.h>
|
||||
#include <assert.h>
|
||||
#include <switch.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "ums.h"
|
||||
|
||||
#define APP_BASE_PATH "sdmc:/switch/" APP_TITLE "/"
|
||||
|
||||
|
@ -48,9 +31,6 @@
|
|||
|
||||
#define MAX_ELEMENTS(x) ((sizeof((x))) / (sizeof((x)[0])))
|
||||
|
||||
#define LOGFILE(fmt, ...) utilsWriteMessageToLogFile(__func__, fmt, ##__VA_ARGS__)
|
||||
#define LOGBUF(dst, dst_size, fmt, ...) utilsWriteMessageToLogBuffer(dst, dst_size, __func__, fmt, ##__VA_ARGS__)
|
||||
|
||||
#define BIT_LONG(n) (1UL << (n))
|
||||
|
||||
#define ALIGN_UP(x, y) (((x) + ((y) - 1)) & ~((y) - 1))
|
||||
|
@ -61,11 +41,6 @@
|
|||
|
||||
#define BIS_SYSTEM_PARTITION_MOUNT_NAME "sys:"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// Used to determine which CFW is the application running under.
|
||||
typedef enum {
|
||||
UtilsCustomFirmwareType_Unknown = 0,
|
||||
|
@ -75,7 +50,7 @@ typedef enum {
|
|||
} UtilsCustomFirmwareType;
|
||||
|
||||
/// Resource (de)initialization.
|
||||
/// Called at program startup.
|
||||
/// Called at program startup and exit.
|
||||
bool utilsInitializeResources(void);
|
||||
void utilsCloseResources(void);
|
||||
|
||||
|
@ -100,12 +75,6 @@ void utilsWaitForButtonPress(u64 flag);
|
|||
/// If the buffer isn't big enough to hold both its current contents and the new formatted string, it will be resized.
|
||||
bool utilsAppendFormattedStringToBuffer(char **dst, size_t *dst_size, const char *fmt, ...);
|
||||
|
||||
/// Logfile management functions.
|
||||
void utilsWriteMessageToLogFile(const char *func_name, const char *fmt, ...);
|
||||
void utilsWriteMessageToLogBuffer(char **dst, size_t *dst_size, const char *func_name, const char *fmt, ...);
|
||||
void utilsWriteLogBufferToLogFile(const char *src);
|
||||
void utilsLogFileMutexControl(bool lock);
|
||||
|
||||
/// Replaces illegal FAT characters in the provided string with underscores.
|
||||
/// If 'ascii_only' is set to true, all characters outside the (0x20,0x7E] range will also be replaced with underscores.
|
||||
void utilsReplaceIllegalCharacters(char *str, bool ascii_only);
|
||||
|
@ -116,14 +85,17 @@ void utilsTrimString(char *str);
|
|||
/// Generates a lowercase hex string representation of the binary data stored in 'src' and stores it in 'dst'.
|
||||
void utilsGenerateHexStringFromData(char *dst, size_t dst_size, const void *src, size_t src_size);
|
||||
|
||||
/// Formats the provided 'size' value to a human readable size string and stores it in 'dst'.
|
||||
/// Formats the provided 'size' value to a human-readable size string and stores it in 'dst'.
|
||||
void utilsGenerateFormattedSizeString(u64 size, char *dst, size_t dst_size);
|
||||
|
||||
/// Saves the total size and free space available from the filesystem pointed to by the input path (e.g. "sdmc:/") to 'out_total' and 'out_free', respectively.
|
||||
/// Either 'out_total' or 'out_free' can be set to NULL, but at least one of them must be set to a valid pointer.
|
||||
/// Either 'out_total' or 'out_free' can be NULL, but at least one of them must be a valid pointer.
|
||||
/// Returns false if there's an error.
|
||||
bool utilsGetFileSystemStatsByPath(const char *path, u64 *out_total, u64 *out_free);
|
||||
|
||||
/// Returns a pointer to the FsFileSystem object for the SD card.
|
||||
FsFileSystem *utilsGetSdCardFileSystemObject(void);
|
||||
|
||||
/// Commits SD card filesystem changes.
|
||||
/// Must be used after closing a file handle from the SD card.
|
||||
bool utilsCommitSdCardFileSystemChanges(void);
|
||||
|
|
Loading…
Add table
Reference in a new issue