romfs: reintroduce support for missing base RomFS.

Also added a free space check and concatenation file creation to sd_romfs_dumper.
This commit is contained in:
Pablo Curiel 2022-07-05 06:01:07 +02:00
parent 942a407247
commit c910fe6c0a
4 changed files with 64 additions and 19 deletions

View File

@ -126,6 +126,7 @@ static void read_thread_func(void *arg)
{
fclose(shared_data->fd);
shared_data->fd = NULL;
utilsCommitSdCardFileSystemChanges();
}
/* Retrieve RomFS file entry information. */
@ -141,6 +142,13 @@ static void read_thread_func(void *arg)
utilsCreateDirectoryTree(path, false);
/* Create file. */
if (file_entry->size > FAT32_FILESIZE_LIMIT && !utilsCreateConcatenationFile(path))
{
shared_data->read_error = true;
condvarWakeAll(&g_writeCondvar);
break;
}
shared_data->read_error = ((shared_data->fd = fopen(path, "wb")) == NULL);
if (shared_data->read_error)
{
@ -201,10 +209,10 @@ static void read_thread_func(void *arg)
{
fclose(shared_data->fd);
shared_data->fd = NULL;
if (shared_data->read_error || shared_data->write_error || shared_data->transfer_cancelled) utilsRemoveConcatenationFile(path);
utilsCommitSdCardFileSystemChanges();
}
if ((shared_data->read_error || shared_data->write_error || shared_data->transfer_cancelled) && *path) remove(path);
free(buf);
end:
@ -579,6 +587,12 @@ int main(int argc, char *argv[])
TitleInfo *latest_patch = NULL;
if (user_app_data.patch_info) latest_patch = get_latest_patch_info(user_app_data.patch_info);
if (!latest_patch && (!base_nca_ctx->fs_ctx[1].enabled || (base_nca_ctx->fs_ctx[1].section_type != NcaFsSectionType_RomFs && base_nca_ctx->fs_ctx[1].section_type != NcaFsSectionType_Nca0RomFs)))
{
consolePrint("base app has no valid romfs and no updates could be found\n");
goto out2;
}
if (base_nca_ctx->fs_ctx[1].has_sparse_layer && (!latest_patch || latest_patch->version.value < user_app_data.app_info->version.value))
{
consolePrint("base app is a sparse title and no v%u or greater update could be found\n", user_app_data.app_info->version.value);
@ -616,6 +630,20 @@ int main(int argc, char *argv[])
consolePrint("romfs initialize ctx succeeded\n");
// check free space
u64 free_space = 0;
if (!utilsGetFileSystemStatsByPath("sdmc:/", NULL, &free_space))
{
consolePrint("failed to retrieve free sd card space\n");
goto out2;
}
if (free_space <= shared_data.total_size)
{
consolePrint("extracted romfs size (0x%lX) exceeds free sd card space (0x%lX)\n", shared_data.total_size, free_space);
goto out2;
}
shared_data.fd = NULL;
shared_data.data = buf;
shared_data.data_size = 0;

View File

@ -552,6 +552,12 @@ int main(int argc, char *argv[])
TitleInfo *latest_patch = NULL;
if (user_app_data.patch_info) latest_patch = get_latest_patch_info(user_app_data.patch_info);
if (!latest_patch && (!base_nca_ctx->fs_ctx[1].enabled || (base_nca_ctx->fs_ctx[1].section_type != NcaFsSectionType_RomFs && base_nca_ctx->fs_ctx[1].section_type != NcaFsSectionType_Nca0RomFs)))
{
consolePrint("base app has no valid romfs and no updates could be found\n");
goto out2;
}
if (base_nca_ctx->fs_ctx[1].has_sparse_layer && (!latest_patch || latest_patch->version.value < user_app_data.app_info->version.value))
{
consolePrint("base app is a sparse title and no v%u or greater update could be found\n", user_app_data.app_info->version.value);

View File

@ -363,11 +363,12 @@ static bool bktrReadIndirectStorage(BucketTreeVisitor *visitor, void *out, u64 r
{
BucketTreeContext *ctx = visitor->bktr_ctx;
bool is_sparse = (ctx->storage_type == BucketTreeStorageType_Sparse);
bool missing_original_storage = !bktrIsValidSubstorage(&(ctx->substorages[0]));
if (!out || !bktrIsValidSubstorage(&(ctx->substorages[0])) || (!is_sparse && !bktrIsValidSubstorage(&(ctx->substorages[1]))) || \
(!is_sparse && ((ctx->substorages[0].type != BucketTreeSubStorageType_Regular && ctx->substorages[0].type != BucketTreeStorageType_Compressed && \
ctx->substorages[0].type != BucketTreeSubStorageType_Sparse) || ctx->substorages[1].type != BucketTreeSubStorageType_AesCtrEx)) || \
(is_sparse && ctx->substorages[0].type != BucketTreeSubStorageType_Regular))
if (!out || (is_sparse && (missing_original_storage || ctx->substorages[0].type != BucketTreeSubStorageType_Regular)) || \
(!is_sparse && (!bktrIsValidSubstorage(&(ctx->substorages[1])) || ctx->substorages[1].type != BucketTreeSubStorageType_AesCtrEx || \
(!missing_original_storage && ((ctx->substorages[0].type != BucketTreeSubStorageType_Regular && \
ctx->substorages[0].type != BucketTreeStorageType_Compressed && ctx->substorages[0].type != BucketTreeSubStorageType_Sparse))))))
{
LOG_MSG("Invalid parameters!");
return false;
@ -438,10 +439,15 @@ static bool bktrReadIndirectStorage(BucketTreeVisitor *visitor, void *out, u64 r
if (cur_entry.storage_index == BucketTreeIndirectStorageIndex_Original)
{
/* Retrieve data from the original data storage. */
/* This may either be a Regular/Sparse/Compressed storage from the base NCA (Indirect) or a Regular storage from this very same NCA (Sparse). */
success = bktrReadSubStorage(&(ctx->substorages[0]), &params);
if (!success) LOG_MSG("Failed to read 0x%lX-byte long chunk from offset 0x%lX in original data storage!", read_size, data_offset);
if (!missing_original_storage)
{
/* Retrieve data from the original data storage. */
/* This may either be a Regular/Sparse/Compressed storage from the base NCA (Indirect) or a Regular storage from this very same NCA (Sparse). */
success = bktrReadSubStorage(&(ctx->substorages[0]), &params);
if (!success) LOG_MSG("Failed to read 0x%lX-byte long chunk from offset 0x%lX in original data storage!", read_size, data_offset);
} else {
LOG_MSG("Error: attempting to read 0x%lX-byte long chunk from missing original data storage at offset 0x%lX!", read_size, data_offset);
}
} else {
if (!is_sparse)
{

View File

@ -33,12 +33,17 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base
NcaContext *base_nca_ctx = NULL, *patch_nca_ctx = NULL;
bool dump_fs_header = false, success = false;
if (!out || !base_nca_fs_ctx || !base_nca_fs_ctx->enabled || (base_nca_fs_ctx->has_sparse_layer && !patch_nca_fs_ctx) || !(base_nca_ctx = (NcaContext*)base_nca_fs_ctx->nca_ctx) || \
(base_nca_ctx->format_version == NcaVersion_Nca0 && (base_nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs || \
base_nca_fs_ctx->hash_type != NcaHashType_HierarchicalSha256)) || (base_nca_ctx->format_version != NcaVersion_Nca0 && \
(base_nca_fs_ctx->section_type != NcaFsSectionType_RomFs || (base_nca_fs_ctx->hash_type != NcaHashType_HierarchicalIntegrity && \
base_nca_fs_ctx->hash_type != NcaHashType_HierarchicalIntegritySha3))) || (base_nca_ctx->rights_id_available && !base_nca_ctx->titlekey_retrieved) || \
(patch_nca_fs_ctx && (!patch_nca_fs_ctx->enabled || !(patch_nca_ctx = (NcaContext*)patch_nca_fs_ctx->nca_ctx) || patch_nca_ctx->format_version != base_nca_ctx->format_version || \
/* Check if the base RomFS is missing (e.g. Fortnite, World of Tanks Blitz, etc.). */
bool missing_base_romfs = (base_nca_fs_ctx && (!base_nca_fs_ctx->enabled || (base_nca_fs_ctx->section_type != NcaFsSectionType_RomFs && \
base_nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs)));
if (!out || !base_nca_fs_ctx || (!patch_nca_fs_ctx && (missing_base_romfs || base_nca_fs_ctx->has_sparse_layer)) || \
(!missing_base_romfs && (!(base_nca_ctx = (NcaContext*)base_nca_fs_ctx->nca_ctx) || (base_nca_ctx->format_version == NcaVersion_Nca0 && \
(base_nca_fs_ctx->section_type != NcaFsSectionType_Nca0RomFs || base_nca_fs_ctx->hash_type != NcaHashType_HierarchicalSha256)) || \
(base_nca_ctx->format_version != NcaVersion_Nca0 && (base_nca_fs_ctx->section_type != NcaFsSectionType_RomFs || \
(base_nca_fs_ctx->hash_type != NcaHashType_HierarchicalIntegrity && base_nca_fs_ctx->hash_type != NcaHashType_HierarchicalIntegritySha3))) || \
(base_nca_ctx->rights_id_available && !base_nca_ctx->titlekey_retrieved))) || (patch_nca_fs_ctx && (!patch_nca_fs_ctx->enabled || \
!(patch_nca_ctx = (NcaContext*)patch_nca_fs_ctx->nca_ctx) || (!missing_base_romfs && patch_nca_ctx->format_version != base_nca_ctx->format_version) || \
patch_nca_fs_ctx->section_type != NcaFsSectionType_PatchRomFs || (patch_nca_ctx->rights_id_available && !patch_nca_ctx->titlekey_retrieved))))
{
LOG_MSG("Invalid parameters!");
@ -52,7 +57,7 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base
bool is_nca0_romfs = (base_nca_fs_ctx->section_type == NcaFsSectionType_Nca0RomFs);
/* Initialize base NCA storage context. */
if (!ncaStorageInitializeContext(base_storage_ctx, base_nca_fs_ctx))
if (!missing_base_romfs && !ncaStorageInitializeContext(base_storage_ctx, base_nca_fs_ctx))
{
LOG_MSG("Failed to initialize base NCA storage context!");
goto end;
@ -67,8 +72,8 @@ bool romfsInitializeContext(RomFileSystemContext *out, NcaFsSectionContext *base
goto end;
}
/* Set patch NCA storage original substorage. */
if (!ncaStorageSetPatchOriginalSubStorage(patch_storage_ctx, base_storage_ctx))
/* Set patch NCA storage original substorage, if available. */
if (!missing_base_romfs && !ncaStorageSetPatchOriginalSubStorage(patch_storage_ctx, base_storage_ctx))
{
LOG_MSG("Failed to set patch NCA storage context's original substorage!");
goto end;