hac2l: add basenca, basexci, basepfs/basensp, baseappfs support

This commit is contained in:
Michael Scire 2022-06-11 21:16:04 -07:00
parent 161c292397
commit f2166ab374
5 changed files with 123 additions and 1 deletions

View File

@ -163,6 +163,11 @@ namespace ams::hactool {
MakeOptionHandler("normaldir", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.normal_partition_out_dir), arg); }),
MakeOptionHandler("updatedir", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.update_partition_out_dir), arg); }),
MakeOptionHandler("logodir", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.logo_partition_out_dir), arg); }),
MakeOptionHandler("basenca", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.base_nca_path), arg); }),
MakeOptionHandler("basexci", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.base_xci_path), arg); }),
MakeOptionHandler("basepfs", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.base_pfs_path), arg); }),
MakeOptionHandler("basensp", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.base_pfs_path), arg); }),
MakeOptionHandler("baseappfs", [] (Options &options, const char *arg) { return CreateFilePath(std::addressof(options.base_appfs_path), arg); }),
MakeOptionHandler("listromfs", [] (Options &options) { options.list_romfs = true; }),
MakeOptionHandler("listupdate", [] (Options &options) { options.list_update = true; }),
MakeOptionHandler("appindex", [] (Options &options, const char *arg) { return ParseIntegerArgument(std::addressof(options.preferred_app_index), arg); }),

View File

@ -36,6 +36,10 @@ namespace ams::hactool {
struct Options {
const char *in_file_path = nullptr;
FileType file_type = FileType::Nca;
const char *base_nca_path = nullptr;
const char *base_xci_path = nullptr;
const char *base_pfs_path = nullptr;
const char *base_appfs_path = nullptr;
bool valid = false;
bool raw = false;
bool verify = false;

View File

@ -140,6 +140,15 @@ namespace ams::hactool {
fssrv::impl::ExternalKeyManager m_external_nca_key_manager;
std::shared_ptr<fs::fsa::IFileSystem> m_local_fs;
bool m_has_base_nca;
bool m_has_base_xci;
bool m_has_base_pfs;
bool m_has_base_appfs;
ProcessAsNcaContext m_base_nca_ctx;
ProcessAsXciContext m_base_xci_ctx;
ProcessAsPfsContext m_base_pfs_ctx;
ProcessAsApplicationFileSystemContext m_base_appfs_ctx;
os::SdkMutex m_print_lock;
char m_indent_buffer[1_KB];
public:

View File

@ -19,7 +19,13 @@
namespace ams::hactool {
Processor::Processor(const Options &options) : m_options(options) {
Processor::Processor(const Options &options) : m_options(options), m_base_nca_ctx{}, m_base_xci_ctx{}, m_base_pfs_ctx{}, m_base_appfs_ctx{} {
/* Default to no bases. */
m_has_base_nca = false;
m_has_base_xci = false;
m_has_base_pfs = false;
m_has_base_appfs = false;
/* Create local file system for host root. */
fssrv::fscreator::LocalFileSystemCreator local_fs_creator(true);
fs::Path normalized_path;
@ -33,6 +39,61 @@ namespace ams::hactool {
/* Setup our internal keys. */
this->PresetInternalKeys();
/* Open any bases we've been provided. */
{
if (m_options.base_nca_path != nullptr) {
std::shared_ptr<fs::IStorage> storage = nullptr;
if (const auto open_res = OpenFileStorage(std::addressof(storage), m_local_fs, m_options.base_nca_path); R_SUCCEEDED(open_res)) {
if (const auto proc_res = this->ProcessAsNca(std::move(storage), std::addressof(m_base_nca_ctx)); R_SUCCEEDED(proc_res)) {
m_has_base_nca = true;
} else {
fprintf(stderr, "Failed to process base nca (%s): 2%03d-%04d\n", m_options.base_nca_path, proc_res.GetModule(), proc_res.GetDescription());
}
} else {
fprintf(stderr, "Failed to open base nca (%s): 2%03d-%04d\n", m_options.base_nca_path, open_res.GetModule(), open_res.GetDescription());
}
}
if (m_options.base_xci_path != nullptr) {
std::shared_ptr<fs::IStorage> storage = nullptr;
if (const auto open_res = OpenFileStorage(std::addressof(storage), m_local_fs, m_options.base_xci_path); R_SUCCEEDED(open_res)) {
if (const auto proc_res = this->ProcessAsXci(std::move(storage), std::addressof(m_base_xci_ctx)); R_SUCCEEDED(proc_res)) {
m_has_base_xci = true;
} else {
fprintf(stderr, "Failed to process base xci (%s): 2%03d-%04d\n", m_options.base_xci_path, proc_res.GetModule(), proc_res.GetDescription());
}
} else {
fprintf(stderr, "Failed to open base xci (%s): 2%03d-%04d\n", m_options.base_xci_path, open_res.GetModule(), open_res.GetDescription());
}
}
if (m_options.base_pfs_path != nullptr) {
std::shared_ptr<fs::IStorage> storage = nullptr;
if (const auto open_res = OpenFileStorage(std::addressof(storage), m_local_fs, m_options.base_pfs_path); R_SUCCEEDED(open_res)) {
if (const auto proc_res = this->ProcessAsPfs(std::move(storage), std::addressof(m_base_pfs_ctx)); R_SUCCEEDED(proc_res)) {
m_has_base_pfs = true;
} else {
fprintf(stderr, "Failed to process base pfs (%s): 2%03d-%04d\n", m_options.base_pfs_path, proc_res.GetModule(), proc_res.GetDescription());
}
} else {
fprintf(stderr, "Failed to open base pfs (%s): 2%03d-%04d\n", m_options.base_pfs_path, open_res.GetModule(), open_res.GetDescription());
}
}
if (m_options.base_appfs_path != nullptr) {
std::shared_ptr<fs::fsa::IFileSystem> fs = nullptr;
if (const auto open_res = OpenSubDirectoryFileSystem(std::addressof(fs), m_local_fs, m_options.base_appfs_path); R_SUCCEEDED(open_res)) {
if (const auto proc_res = this->ProcessAsApplicationFileSystem(std::move(fs), std::addressof(m_base_appfs_ctx)); R_SUCCEEDED(proc_res)) {
m_has_base_appfs = true;
} else {
fprintf(stderr, "Failed to process base app fs (%s): 2%03d-%04d\n", m_options.base_appfs_path, proc_res.GetModule(), proc_res.GetDescription());
}
} else {
fprintf(stderr, "Failed to open base app fs (%s): 2%03d-%04d\n", m_options.base_appfs_path, open_res.GetModule(), open_res.GetDescription());
}
}
}
if (m_options.file_type == FileType::AppFs) {
/* Open the filesystem. */
std::shared_ptr<fs::fsa::IFileSystem> input = nullptr;

View File

@ -127,6 +127,47 @@ namespace ams::hactool {
/* Create an NCA reader for the input file. */
R_TRY(ParseNca(std::addressof(ctx->reader), ctx->storage, m_external_nca_key_manager));
/* Decide on a base, if one isn't already set. */
{
/* First see if we explicitly have a viable base nca. */
if (ctx->base_reader == nullptr && m_has_base_nca && m_base_nca_ctx.reader != nullptr && m_base_nca_ctx.reader->GetProgramId() == ctx->reader->GetProgramId()) {
ctx->base_reader = m_base_nca_ctx.reader;
}
/* Next, we'll try looking for a match in the appfs of a base xci, pfs, or appfs. */
auto GetBaseFromAppFs = [&](ProcessAsApplicationFileSystemContext &app_ctx, const char *src) {
if (ctx->base_reader == nullptr) {
if (auto app_prog = app_ctx.apps.Find(ncm::ApplicationId{ctx->reader->GetProgramId() & ~static_cast<u64>(0xFF)}, 0, ctx->reader->GetProgramId() & 0xFF, ncm::ContentType::Program, ncm::ContentMetaType::Application); app_prog != app_ctx.apps.end()) {
ProcessAsNcaContext tmp_ctx{};
if (const auto process_res = this->ProcessAsNca(app_prog->GetData().storage, std::addressof(tmp_ctx)); R_SUCCEEDED(process_res)) {
if (ctx->reader->GetProgramId() )
ctx->base_reader = tmp_ctx.reader;
} else {
fprintf(stderr, "[Warning]: Failed to process base program nca from %s: 2%03d-%04d\n", src, process_res.GetModule(), process_res.GetDescription());
}
}
}
};
if (m_has_base_xci && m_base_xci_ctx.secure_partition.fs != nullptr) {
m_has_base_xci = false;
GetBaseFromAppFs(m_base_xci_ctx.app_ctx, "basexci");
m_has_base_xci = true;
}
if (m_has_base_pfs && !m_base_pfs_ctx.is_exefs) {
m_has_base_xci = false;
GetBaseFromAppFs(m_base_pfs_ctx.app_ctx, "basepfs");
m_has_base_pfs = true;
}
if (m_has_base_appfs) {
m_has_base_appfs = false;
GetBaseFromAppFs(m_base_appfs_ctx, "baseappfs");
m_has_base_appfs = true;
}
}
/* Open storages for each section. */
std::shared_ptr<fs::IStorage> npdm_storage;
@ -279,6 +320,8 @@ namespace ams::hactool {
addon.v32 = util::ConvertToBigEndian<u32>(ctx.reader->GetSdkAddonVersion());
this->PrintFormat("SDK Version", "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8, addon.v8[0], addon.v8[1], addon.v8[2], addon.v8[3]);
this->PrintId64("Program Id", ctx.reader->GetProgramId());
this->PrintString("Distribution Type", fs::impl::IdString().ToString(ctx.reader->GetDistributionType()));
this->PrintString("Content Type", fs::impl::IdString().ToString(ctx.reader->GetContentType()));