summaryrefslogtreecommitdiffstats
path: root/src/core/loader
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/loader')
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp10
-rw-r--r--src/core/loader/deconstructed_rom_directory.h4
-rw-r--r--src/core/loader/kip.cpp5
-rw-r--r--src/core/loader/loader.cpp8
-rw-r--r--src/core/loader/loader.h22
-rw-r--r--src/core/loader/nax.cpp4
-rw-r--r--src/core/loader/nax.h1
-rw-r--r--src/core/loader/nca.cpp104
-rw-r--r--src/core/loader/nca.h3
-rw-r--r--src/core/loader/nro.cpp5
-rw-r--r--src/core/loader/nso.cpp7
-rw-r--r--src/core/loader/nsp.cpp43
-rw-r--r--src/core/loader/nsp.h3
-rw-r--r--src/core/loader/xci.cpp38
-rw-r--r--src/core/loader/xci.h3
15 files changed, 205 insertions, 55 deletions
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index e04ad19db..5a42dea48 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -18,7 +18,7 @@ namespace Loader {
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_,
bool override_update_)
- : AppLoader(std::move(file_)), override_update(override_update_) {
+ : AppLoader(std::move(file_)), override_update(override_update_), is_hbl(false) {
const auto file_dir = file->GetContainingDirectory();
// Title ID
@@ -69,9 +69,9 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
}
AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
- FileSys::VirtualDir directory, bool override_update_)
+ FileSys::VirtualDir directory, bool override_update_, bool is_hbl_)
: AppLoader(directory->GetFile("main")), dir(std::move(directory)),
- override_update(override_update_) {}
+ override_update(override_update_), is_hbl(is_hbl_) {}
FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& dir_file) {
if (FileSys::IsDirectoryExeFS(dir_file->GetContainingDirectory())) {
@@ -147,13 +147,13 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
}
// Setup the process code layout
- if (process.LoadFromMetadata(metadata, code_size).IsError()) {
+ if (process.LoadFromMetadata(metadata, code_size, is_hbl).IsError()) {
return {ResultStatus::ErrorUnableToParseKernelMetadata, {}};
}
// Load NSO modules
modules.clear();
- const VAddr base_address{GetInteger(process.GetPageTable().GetCodeRegionStart())};
+ const VAddr base_address{GetInteger(process.GetEntryPoint())};
VAddr next_load_addr{base_address};
const FileSys::PatchManager pm{metadata.GetTitleID(), system.GetFileSystemController(),
system.GetContentProvider()};
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index f7702225e..1e9f765c9 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -27,7 +27,8 @@ public:
// Overload to accept exefs directory. Must contain 'main' and 'main.npdm'
explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory,
- bool override_update_ = false);
+ bool override_update_ = false,
+ bool is_hbl_ = false);
/**
* Identifies whether or not the given file is a deconstructed ROM directory.
@@ -62,6 +63,7 @@ private:
std::string name;
u64 title_id{};
bool override_update;
+ bool is_hbl;
Modules modules;
};
diff --git a/src/core/loader/kip.cpp b/src/core/loader/kip.cpp
index ffe976b94..bf56a08b4 100644
--- a/src/core/loader/kip.cpp
+++ b/src/core/loader/kip.cpp
@@ -90,13 +90,14 @@ AppLoader::LoadResult AppLoader_KIP::Load(Kernel::KProcess& process,
codeset.DataSegment().size += kip->GetBSSSize();
// Setup the process code layout
- if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size())
+ if (process
+ .LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size(), false)
.IsError()) {
return {ResultStatus::ErrorNotInitialized, {}};
}
codeset.memory = std::move(program_image);
- const VAddr base_address = GetInteger(process.GetPageTable().GetCodeRegionStart());
+ const VAddr base_address = GetInteger(process.GetEntryPoint());
process.LoadModule(std::move(codeset), base_address);
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", kip->GetName(), base_address);
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index f24474ed8..b6e355622 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -108,7 +108,7 @@ std::string GetFileTypeString(FileType type) {
return "unknown";
}
-constexpr std::array<const char*, 66> RESULT_MESSAGES{
+constexpr std::array<const char*, 68> RESULT_MESSAGES{
"The operation completed successfully.",
"The loader requested to load is already loaded.",
"The operation is not implemented.",
@@ -135,7 +135,7 @@ constexpr std::array<const char*, 66> RESULT_MESSAGES{
"The titlekey and/or titlekek is incorrect or the section header is invalid.",
"The XCI file is missing a Program-type NCA.",
"The NCA file is not an application.",
- "The ExeFS partition could not be found.",
+ "The Program-type NCA contains no executable. An update may be required.",
"The XCI file has a bad header.",
"The XCI file is missing a partition.",
"The file could not be found or does not exist.",
@@ -169,12 +169,14 @@ constexpr std::array<const char*, 66> RESULT_MESSAGES{
"The BKTR-type NCA has a bad Subsection block.",
"The BKTR-type NCA has a bad Relocation bucket.",
"The BKTR-type NCA has a bad Subsection bucket.",
- "The BKTR-type NCA is missing the base RomFS.",
+ "Game updates cannot be loaded directly. Load the base game instead.",
"The NSP or XCI does not contain an update in addition to the base game.",
"The KIP file has a bad header.",
"The KIP BLZ decompression of the section failed unexpectedly.",
"The INI file has a bad header.",
"The INI file contains more than the maximum allowable number of KIP files.",
+ "Integrity verification could not be performed for this file.",
+ "Integrity verification failed.",
};
std::string GetResultStatusString(ResultStatus status) {
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 7a2a52fd4..b4828f7cd 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -3,6 +3,7 @@
#pragma once
+#include <functional>
#include <iosfwd>
#include <memory>
#include <optional>
@@ -79,8 +80,6 @@ enum class ResultStatus : u16 {
ErrorBadPFSHeader,
ErrorIncorrectPFSFileSize,
ErrorBadNCAHeader,
- ErrorCompressedNCA,
- ErrorSparseNCA,
ErrorMissingProductionKeyFile,
ErrorMissingHeaderKey,
ErrorIncorrectHeaderKey,
@@ -134,6 +133,8 @@ enum class ResultStatus : u16 {
ErrorBLZDecompressionFailed,
ErrorBadINIHeader,
ErrorINITooManyKIPs,
+ ErrorIntegrityVerificationNotImplemented,
+ ErrorIntegrityVerificationFailed,
};
std::string GetResultStatusString(ResultStatus status);
@@ -172,6 +173,13 @@ public:
virtual LoadResult Load(Kernel::KProcess& process, Core::System& system) = 0;
/**
+ * Try to verify the integrity of the file.
+ */
+ virtual ResultStatus VerifyIntegrity(std::function<bool(size_t, size_t)> progress_callback) {
+ return ResultStatus::ErrorIntegrityVerificationNotImplemented;
+ }
+
+ /**
* Get the code (typically .code section) of the application
*
* @param[out] buffer Reference to buffer to store data
@@ -276,16 +284,6 @@ public:
}
/**
- * Gets the difference between the start of the IVFC header and the start of level 6 (RomFS)
- * data. Needed for BKTR patching.
- *
- * @return IVFC offset for RomFS.
- */
- virtual u64 ReadRomFSIVFCOffset() const {
- return 0;
- }
-
- /**
* Get the title of the application
*
* @param[out] title Reference to store the application title into
diff --git a/src/core/loader/nax.cpp b/src/core/loader/nax.cpp
index cf35b1249..3b7b005ff 100644
--- a/src/core/loader/nax.cpp
+++ b/src/core/loader/nax.cpp
@@ -76,10 +76,6 @@ ResultStatus AppLoader_NAX::ReadRomFS(FileSys::VirtualFile& dir) {
return nca_loader->ReadRomFS(dir);
}
-u64 AppLoader_NAX::ReadRomFSIVFCOffset() const {
- return nca_loader->ReadRomFSIVFCOffset();
-}
-
ResultStatus AppLoader_NAX::ReadProgramId(u64& out_program_id) {
return nca_loader->ReadProgramId(out_program_id);
}
diff --git a/src/core/loader/nax.h b/src/core/loader/nax.h
index d7f70db43..81df2bbcd 100644
--- a/src/core/loader/nax.h
+++ b/src/core/loader/nax.h
@@ -39,7 +39,6 @@ public:
LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
- u64 ReadRomFSIVFCOffset() const override;
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadBanner(std::vector<u8>& buffer) override;
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index 513af194d..4feb6968a 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -3,13 +3,18 @@
#include <utility>
+#include "common/hex_util.h"
+#include "common/scope_exit.h"
#include "core/core.h"
#include "core/file_sys/content_archive.h"
+#include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs_factory.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/deconstructed_rom_directory.h"
#include "core/loader/nca.h"
+#include "mbedtls/sha256.h"
namespace Loader {
@@ -43,9 +48,23 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::KProcess& process, Core::S
return {ResultStatus::ErrorNCANotProgram, {}};
}
- const auto exefs = nca->GetExeFS();
+ auto exefs = nca->GetExeFS();
if (exefs == nullptr) {
- return {ResultStatus::ErrorNoExeFS, {}};
+ LOG_INFO(Loader, "No ExeFS found in NCA, looking for ExeFS from update");
+
+ // This NCA may be a sparse base of an installed title.
+ // Try to fetch the ExeFS from the installed update.
+ const auto& installed = system.GetContentProvider();
+ const auto update_nca = installed.GetEntry(FileSys::GetUpdateTitleID(nca->GetTitleId()),
+ FileSys::ContentRecordType::Program);
+
+ if (update_nca) {
+ exefs = update_nca->GetExeFS();
+ }
+
+ if (exefs == nullptr) {
+ return {ResultStatus::ErrorNoExeFS, {}};
+ }
}
directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs, true);
@@ -64,6 +83,79 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::KProcess& process, Core::S
return load_result;
}
+ResultStatus AppLoader_NCA::VerifyIntegrity(std::function<bool(size_t, size_t)> progress_callback) {
+ using namespace Common::Literals;
+
+ constexpr size_t NcaFileNameWithHashLength = 36;
+ constexpr size_t NcaFileNameHashLength = 32;
+ constexpr size_t NcaSha256HashLength = 32;
+ constexpr size_t NcaSha256HalfHashLength = NcaSha256HashLength / 2;
+
+ // Get the file name.
+ const auto name = file->GetName();
+
+ // We won't try to verify meta NCAs.
+ if (name.ends_with(".cnmt.nca")) {
+ return ResultStatus::Success;
+ }
+
+ // Check if we can verify this file. NCAs should be named after their hashes.
+ if (!name.ends_with(".nca") || name.size() != NcaFileNameWithHashLength) {
+ LOG_WARNING(Loader, "Unable to validate NCA with name {}", name);
+ return ResultStatus::ErrorIntegrityVerificationNotImplemented;
+ }
+
+ // Get the expected truncated hash of the NCA.
+ const auto input_hash =
+ Common::HexStringToVector(file->GetName().substr(0, NcaFileNameHashLength), false);
+
+ // Declare buffer to read into.
+ std::vector<u8> buffer(4_MiB);
+
+ // Initialize sha256 verification context.
+ mbedtls_sha256_context ctx;
+ mbedtls_sha256_init(&ctx);
+ mbedtls_sha256_starts_ret(&ctx, 0);
+
+ // Ensure we maintain a clean state on exit.
+ SCOPE_EXIT({ mbedtls_sha256_free(&ctx); });
+
+ // Declare counters.
+ const size_t total_size = file->GetSize();
+ size_t processed_size = 0;
+
+ // Begin iterating the file.
+ while (processed_size < total_size) {
+ // Refill the buffer.
+ const size_t intended_read_size = std::min(buffer.size(), total_size - processed_size);
+ const size_t read_size = file->Read(buffer.data(), intended_read_size, processed_size);
+
+ // Update the hash function with the buffer contents.
+ mbedtls_sha256_update_ret(&ctx, buffer.data(), read_size);
+
+ // Update counters.
+ processed_size += read_size;
+
+ // Call the progress function.
+ if (!progress_callback(processed_size, total_size)) {
+ return ResultStatus::ErrorIntegrityVerificationFailed;
+ }
+ }
+
+ // Finalize context and compute the output hash.
+ std::array<u8, NcaSha256HashLength> output_hash;
+ mbedtls_sha256_finish_ret(&ctx, output_hash.data());
+
+ // Compare to expected.
+ if (std::memcmp(input_hash.data(), output_hash.data(), NcaSha256HalfHashLength) != 0) {
+ LOG_ERROR(Loader, "NCA hash mismatch detected for file {}", name);
+ return ResultStatus::ErrorIntegrityVerificationFailed;
+ }
+
+ // File verified.
+ return ResultStatus::Success;
+}
+
ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {
if (nca == nullptr) {
return ResultStatus::ErrorNotInitialized;
@@ -77,14 +169,6 @@ ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) {
return ResultStatus::Success;
}
-u64 AppLoader_NCA::ReadRomFSIVFCOffset() const {
- if (nca == nullptr) {
- return 0;
- }
-
- return nca->GetBaseIVFCOffset();
-}
-
ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) {
if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) {
return ResultStatus::ErrorNotInitialized;
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h
index d22d9146e..96779e27f 100644
--- a/src/core/loader/nca.h
+++ b/src/core/loader/nca.h
@@ -39,8 +39,9 @@ public:
LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
+ ResultStatus VerifyIntegrity(std::function<bool(size_t, size_t)> progress_callback) override;
+
ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override;
- u64 ReadRomFSIVFCOffset() const override;
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadBanner(std::vector<u8>& buffer) override;
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 506808b5d..69f1a54ed 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -196,14 +196,15 @@ static bool LoadNroImpl(Kernel::KProcess& process, const std::vector<u8>& data)
program_image.resize(static_cast<u32>(program_image.size()) + bss_size);
// Setup the process code layout
- if (process.LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size())
+ if (process
+ .LoadFromMetadata(FileSys::ProgramMetadata::GetDefault(), program_image.size(), false)
.IsError()) {
return false;
}
// Load codeset for current process
codeset.memory = std::move(program_image);
- process.LoadModule(std::move(codeset), process.GetPageTable().GetCodeRegionStart());
+ process.LoadModule(std::move(codeset), process.GetEntryPoint());
return true;
}
diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp
index 74cc9579f..1350da8dc 100644
--- a/src/core/loader/nso.cpp
+++ b/src/core/loader/nso.cpp
@@ -127,13 +127,14 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
}
// Apply patches if necessary
- if (pm && (pm->HasNSOPatch(nso_header.build_id) || Settings::values.dump_nso)) {
+ const auto name = nso_file.GetName();
+ if (pm && (pm->HasNSOPatch(nso_header.build_id, name) || Settings::values.dump_nso)) {
std::vector<u8> pi_header(sizeof(NSOHeader) + program_image.size());
std::memcpy(pi_header.data(), &nso_header, sizeof(NSOHeader));
std::memcpy(pi_header.data() + sizeof(NSOHeader), program_image.data(),
program_image.size());
- pi_header = pm->PatchNSO(pi_header, nso_file.GetName());
+ pi_header = pm->PatchNSO(pi_header, name);
std::copy(pi_header.begin() + sizeof(NSOHeader), pi_header.end(), program_image.data());
}
@@ -167,7 +168,7 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::S
modules.clear();
// Load module
- const VAddr base_address = GetInteger(process.GetPageTable().GetCodeRegionStart());
+ const VAddr base_address = GetInteger(process.GetEntryPoint());
if (!LoadModule(process, system, *file, base_address, true, true)) {
return {ResultStatus::ErrorLoadingNSO, {}};
}
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index 80663e0e0..f4ab75b77 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -30,7 +30,8 @@ AppLoader_NSP::AppLoader_NSP(FileSys::VirtualFile file_,
}
if (nsp->IsExtractedType()) {
- secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(nsp->GetExeFS());
+ secondary_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(
+ nsp->GetExeFS(), false, file->GetName() == "hbl.nsp");
} else {
const auto control_nca =
nsp->GetNCA(nsp->GetProgramTitleID(), FileSys::ContentRecordType::Control);
@@ -117,12 +118,44 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::KProcess& process, Core::S
return result;
}
-ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& out_file) {
- return secondary_loader->ReadRomFS(out_file);
+ResultStatus AppLoader_NSP::VerifyIntegrity(std::function<bool(size_t, size_t)> progress_callback) {
+ // Extracted-type NSPs can't be verified.
+ if (nsp->IsExtractedType()) {
+ return ResultStatus::ErrorIntegrityVerificationNotImplemented;
+ }
+
+ // Get list of all NCAs.
+ const auto ncas = nsp->GetNCAsCollapsed();
+
+ size_t total_size = 0;
+ size_t processed_size = 0;
+
+ // Loop over NCAs, collecting the total size to verify.
+ for (const auto& nca : ncas) {
+ total_size += nca->GetBaseFile()->GetSize();
+ }
+
+ // Loop over NCAs again, verifying each.
+ for (const auto& nca : ncas) {
+ AppLoader_NCA loader_nca(nca->GetBaseFile());
+
+ const auto NcaProgressCallback = [&](size_t nca_processed_size, size_t nca_total_size) {
+ return progress_callback(processed_size + nca_processed_size, total_size);
+ };
+
+ const auto verification_result = loader_nca.VerifyIntegrity(NcaProgressCallback);
+ if (verification_result != ResultStatus::Success) {
+ return verification_result;
+ }
+
+ processed_size += nca->GetBaseFile()->GetSize();
+ }
+
+ return ResultStatus::Success;
}
-u64 AppLoader_NSP::ReadRomFSIVFCOffset() const {
- return secondary_loader->ReadRomFSIVFCOffset();
+ResultStatus AppLoader_NSP::ReadRomFS(FileSys::VirtualFile& out_file) {
+ return secondary_loader->ReadRomFS(out_file);
}
ResultStatus AppLoader_NSP::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
diff --git a/src/core/loader/nsp.h b/src/core/loader/nsp.h
index 003cc345c..7ce436c67 100644
--- a/src/core/loader/nsp.h
+++ b/src/core/loader/nsp.h
@@ -45,8 +45,9 @@ public:
LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
+ ResultStatus VerifyIntegrity(std::function<bool(size_t, size_t)> progress_callback) override;
+
ResultStatus ReadRomFS(FileSys::VirtualFile& out_file) override;
- u64 ReadRomFSIVFCOffset() const override;
ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) override;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index c7b1b3815..12d72c380 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -85,12 +85,42 @@ AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::KProcess& process, Core::S
return result;
}
-ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& out_file) {
- return nca_loader->ReadRomFS(out_file);
+ResultStatus AppLoader_XCI::VerifyIntegrity(std::function<bool(size_t, size_t)> progress_callback) {
+ // Verify secure partition, as it is the only thing we can process.
+ auto secure_partition = xci->GetSecurePartitionNSP();
+
+ // Get list of all NCAs.
+ const auto ncas = secure_partition->GetNCAsCollapsed();
+
+ size_t total_size = 0;
+ size_t processed_size = 0;
+
+ // Loop over NCAs, collecting the total size to verify.
+ for (const auto& nca : ncas) {
+ total_size += nca->GetBaseFile()->GetSize();
+ }
+
+ // Loop over NCAs again, verifying each.
+ for (const auto& nca : ncas) {
+ AppLoader_NCA loader_nca(nca->GetBaseFile());
+
+ const auto NcaProgressCallback = [&](size_t nca_processed_size, size_t nca_total_size) {
+ return progress_callback(processed_size + nca_processed_size, total_size);
+ };
+
+ const auto verification_result = loader_nca.VerifyIntegrity(NcaProgressCallback);
+ if (verification_result != ResultStatus::Success) {
+ return verification_result;
+ }
+
+ processed_size += nca->GetBaseFile()->GetSize();
+ }
+
+ return ResultStatus::Success;
}
-u64 AppLoader_XCI::ReadRomFSIVFCOffset() const {
- return nca_loader->ReadRomFSIVFCOffset();
+ResultStatus AppLoader_XCI::ReadRomFS(FileSys::VirtualFile& out_file) {
+ return nca_loader->ReadRomFS(out_file);
}
ResultStatus AppLoader_XCI::ReadUpdateRaw(FileSys::VirtualFile& out_file) {
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h
index 2affb6c6e..b02e136d3 100644
--- a/src/core/loader/xci.h
+++ b/src/core/loader/xci.h
@@ -45,8 +45,9 @@ public:
LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
+ ResultStatus VerifyIntegrity(std::function<bool(size_t, size_t)> progress_callback) override;
+
ResultStatus ReadRomFS(FileSys::VirtualFile& out_file) override;
- u64 ReadRomFSIVFCOffset() const override;
ResultStatus ReadUpdateRaw(FileSys::VirtualFile& out_file) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadProgramIds(std::vector<u64>& out_program_ids) override;