aboutsummaryrefslogtreecommitdiff
path: root/src/core/file_sys
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/file_sys')
-rw-r--r--src/core/file_sys/bis_factory.cpp11
-rw-r--r--src/core/file_sys/bis_factory.h5
-rw-r--r--src/core/file_sys/card_image.cpp5
-rw-r--r--src/core/file_sys/card_image.h7
-rw-r--r--src/core/file_sys/content_archive.cpp15
-rw-r--r--src/core/file_sys/content_archive.h2
-rw-r--r--src/core/file_sys/control_metadata.cpp1
-rw-r--r--src/core/file_sys/control_metadata.h4
-rw-r--r--src/core/file_sys/fsmitm_romfsbuild.cpp10
-rw-r--r--src/core/file_sys/ips_layer.cpp8
-rw-r--r--src/core/file_sys/kernel_executable.cpp3
-rw-r--r--src/core/file_sys/kernel_executable.h9
-rw-r--r--src/core/file_sys/nca_metadata.cpp3
-rw-r--r--src/core/file_sys/nca_metadata.h2
-rw-r--r--src/core/file_sys/nca_patch.cpp83
-rw-r--r--src/core/file_sys/nca_patch.h4
-rw-r--r--src/core/file_sys/partition_filesystem.cpp8
-rw-r--r--src/core/file_sys/partition_filesystem.h8
-rw-r--r--src/core/file_sys/patch_manager.cpp222
-rw-r--r--src/core/file_sys/patch_manager.h63
-rw-r--r--src/core/file_sys/program_metadata.cpp1
-rw-r--r--src/core/file_sys/program_metadata.h2
-rw-r--r--src/core/file_sys/registered_cache.cpp33
-rw-r--r--src/core/file_sys/romfs.h1
-rw-r--r--src/core/file_sys/romfs_factory.cpp56
-rw-r--r--src/core/file_sys/romfs_factory.h21
-rw-r--r--src/core/file_sys/sdmc_factory.cpp2
-rw-r--r--src/core/file_sys/sdmc_factory.h2
-rw-r--r--src/core/file_sys/submission_package.cpp96
-rw-r--r--src/core/file_sys/submission_package.h7
-rw-r--r--src/core/file_sys/vfs.cpp7
-rw-r--r--src/core/file_sys/vfs_offset.cpp7
-rw-r--r--src/core/file_sys/vfs_static.h8
-rw-r--r--src/core/file_sys/xts_archive.cpp10
-rw-r--r--src/core/file_sys/xts_archive.h10
35 files changed, 405 insertions, 331 deletions
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
index 9ffda2e14..7c6304ff0 100644
--- a/src/core/file_sys/bis_factory.cpp
+++ b/src/core/file_sys/bis_factory.cpp
@@ -4,11 +4,10 @@
#include <fmt/format.h>
#include "common/file_util.h"
-#include "core/core.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/mode.h"
#include "core/file_sys/registered_cache.h"
-#include "core/settings.h"
+#include "core/file_sys/vfs.h"
namespace FileSys {
@@ -82,11 +81,11 @@ VirtualDir BISFactory::OpenPartition(BisPartitionId id) const {
}
}
-VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id) const {
+VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id,
+ VirtualFilesystem file_system) const {
auto& keys = Core::Crypto::KeyManager::Instance();
- Core::Crypto::PartitionDataManager pdm{
- Core::System::GetInstance().GetFilesystem()->OpenDirectory(
- Common::FS::GetUserPath(Common::FS::UserPath::SysDataDir), Mode::Read)};
+ Core::Crypto::PartitionDataManager pdm{file_system->OpenDirectory(
+ Common::FS::GetUserPath(Common::FS::UserPath::SysDataDir), Mode::Read)};
keys.PopulateFromPartitionData(pdm);
switch (id) {
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h
index 8f0451c98..136485881 100644
--- a/src/core/file_sys/bis_factory.h
+++ b/src/core/file_sys/bis_factory.h
@@ -6,7 +6,8 @@
#include <memory>
-#include "core/file_sys/vfs.h"
+#include "common/common_types.h"
+#include "core/file_sys/vfs_types.h"
namespace FileSys {
@@ -51,7 +52,7 @@ public:
VirtualDir GetModificationDumpRoot(u64 title_id) const;
VirtualDir OpenPartition(BisPartitionId id) const;
- VirtualFile OpenPartitionStorage(BisPartitionId id) const;
+ VirtualFile OpenPartitionStorage(BisPartitionId id, VirtualFilesystem file_system) const;
VirtualDir GetImageDirectory() const;
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index 664a47e7f..956da68f7 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -8,11 +8,11 @@
#include <fmt/ostream.h>
#include "common/logging/log.h"
+#include "core/crypto/key_manager.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/partition_filesystem.h"
-#include "core/file_sys/romfs.h"
#include "core/file_sys/submission_package.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_offset.h"
@@ -31,7 +31,8 @@ constexpr std::array partition_names{
XCI::XCI(VirtualFile file_)
: file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA},
- partitions(partition_names.size()), partitions_raw(partition_names.size()) {
+ partitions(partition_names.size()),
+ partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} {
if (file->ReadObject(&header) != sizeof(GamecardHeader)) {
status = Loader::ResultStatus::ErrorBadXCIHeader;
return;
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h
index e1b136426..2d0a0f285 100644
--- a/src/core/file_sys/card_image.h
+++ b/src/core/file_sys/card_image.h
@@ -9,9 +9,12 @@
#include <vector>
#include "common/common_types.h"
#include "common/swap.h"
-#include "core/crypto/key_manager.h"
#include "core/file_sys/vfs.h"
+namespace Core::Crypto {
+class KeyManager;
+}
+
namespace Loader {
enum class ResultStatus : u16;
}
@@ -140,6 +143,6 @@ private:
u64 update_normal_partition_end;
- Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
+ Core::Crypto::KeyManager& keys;
};
} // namespace FileSys
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index 5039341c7..76af47ff9 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -10,10 +10,10 @@
#include "common/logging/log.h"
#include "core/crypto/aes_util.h"
#include "core/crypto/ctr_encryption_layer.h"
+#include "core/crypto/key_manager.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_patch.h"
#include "core/file_sys/partition_filesystem.h"
-#include "core/file_sys/romfs.h"
#include "core/file_sys/vfs_offset.h"
#include "core/loader/loader.h"
@@ -119,7 +119,8 @@ static bool IsValidNCA(const NCAHeader& header) {
}
NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset)
- : file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)) {
+ : file(std::move(file_)),
+ bktr_base_romfs(std::move(bktr_base_romfs_)), keys{Core::Crypto::KeyManager::Instance()} {
if (file == nullptr) {
status = Loader::ResultStatus::ErrorNullFile;
return;
@@ -322,7 +323,7 @@ bool NCA::ReadRomFSSection(const NCASectionHeader& section, const NCASectionTabl
subsection_buckets.back().entries.push_back({section.bktr.relocation.offset, {0}, ctr_low});
subsection_buckets.back().entries.push_back({size, {0}, 0});
- std::optional<Core::Crypto::Key128> key = {};
+ std::optional<Core::Crypto::Key128> key;
if (encrypted) {
if (has_rights_id) {
status = Loader::ResultStatus::Success;
@@ -441,18 +442,18 @@ std::optional<Core::Crypto::Key128> NCA::GetTitlekey() {
memcpy(rights_id.data(), header.rights_id.data(), 16);
if (rights_id == u128{}) {
status = Loader::ResultStatus::ErrorInvalidRightsID;
- return {};
+ return std::nullopt;
}
auto titlekey = keys.GetKey(Core::Crypto::S128KeyType::Titlekey, rights_id[1], rights_id[0]);
if (titlekey == Core::Crypto::Key128{}) {
status = Loader::ResultStatus::ErrorMissingTitlekey;
- return {};
+ return std::nullopt;
}
if (!keys.HasKey(Core::Crypto::S128KeyType::Titlekek, master_key_id)) {
status = Loader::ResultStatus::ErrorMissingTitlekek;
- return {};
+ return std::nullopt;
}
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
@@ -476,7 +477,7 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s
case NCASectionCryptoType::BKTR:
LOG_TRACE(Crypto, "called with mode=CTR, starting_offset={:016X}", starting_offset);
{
- std::optional<Core::Crypto::Key128> key = {};
+ std::optional<Core::Crypto::Key128> key;
if (has_rights_id) {
status = Loader::ResultStatus::Success;
key = GetTitlekey();
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index d25cbcf91..69292232a 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -158,7 +158,7 @@ private:
bool encrypted = false;
bool is_update = false;
- Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
+ Core::Crypto::KeyManager& keys;
};
} // namespace FileSys
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp
index 63cd2eead..b0a130345 100644
--- a/src/core/file_sys/control_metadata.cpp
+++ b/src/core/file_sys/control_metadata.cpp
@@ -5,6 +5,7 @@
#include "common/string_util.h"
#include "common/swap.h"
#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/vfs.h"
namespace FileSys {
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h
index e37b2fadf..403c4219a 100644
--- a/src/core/file_sys/control_metadata.h
+++ b/src/core/file_sys/control_metadata.h
@@ -10,7 +10,7 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
-#include "core/file_sys/vfs.h"
+#include "core/file_sys/vfs_types.h"
namespace FileSys {
@@ -83,7 +83,7 @@ enum class Language : u8 {
Italian = 7,
Dutch = 8,
CanadianFrench = 9,
- Portugese = 10,
+ Portuguese = 10,
Russian = 11,
Korean = 12,
Taiwanese = 13,
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp
index 2aff2708a..c52fafb6f 100644
--- a/src/core/file_sys/fsmitm_romfsbuild.cpp
+++ b/src/core/file_sys/fsmitm_romfsbuild.cpp
@@ -266,8 +266,9 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
cur_file->offset = file_partition_size;
file_partition_size += cur_file->size;
cur_file->entry_offset = entry_offset;
- entry_offset += sizeof(RomFSFileEntry) +
- Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4);
+ entry_offset +=
+ static_cast<u32>(sizeof(RomFSFileEntry) +
+ Common::AlignUp(cur_file->path_len - cur_file->cur_path_ofs, 4));
prev_file = cur_file;
}
// Assign deferred parent/sibling ownership.
@@ -284,8 +285,9 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() {
for (const auto& it : directories) {
cur_dir = it.second;
cur_dir->entry_offset = entry_offset;
- entry_offset += sizeof(RomFSDirectoryEntry) +
- Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4);
+ entry_offset +=
+ static_cast<u32>(sizeof(RomFSDirectoryEntry) +
+ Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4));
}
// Assign deferred parent/sibling ownership.
for (auto it = directories.rbegin(); it->second != root; ++it) {
diff --git a/src/core/file_sys/ips_layer.cpp b/src/core/file_sys/ips_layer.cpp
index a08a70efd..a6101f1c0 100644
--- a/src/core/file_sys/ips_layer.cpp
+++ b/src/core/file_sys/ips_layer.cpp
@@ -245,9 +245,11 @@ void IPSwitchCompiler::Parse() {
// Read rest of patch
while (true) {
- if (i + 1 >= lines.size())
+ if (i + 1 >= lines.size()) {
break;
- const auto patch_line = lines[++i];
+ }
+
+ const auto& patch_line = lines[++i];
// Start of new patch
if (StartsWith(patch_line, "@enabled") || StartsWith(patch_line, "@disabled")) {
@@ -297,7 +299,7 @@ void IPSwitchCompiler::Parse() {
patch_text->GetName(), offset, Common::HexToString(replace));
}
- patch.records.insert_or_assign(offset, std::move(replace));
+ patch.records.insert_or_assign(static_cast<u32>(offset), std::move(replace));
}
patches.push_back(std::move(patch));
diff --git a/src/core/file_sys/kernel_executable.cpp b/src/core/file_sys/kernel_executable.cpp
index 76313679d..ef93ef3ed 100644
--- a/src/core/file_sys/kernel_executable.cpp
+++ b/src/core/file_sys/kernel_executable.cpp
@@ -2,9 +2,12 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include <cstring>
+
#include "common/string_util.h"
#include "core/file_sys/kernel_executable.h"
#include "core/file_sys/vfs_offset.h"
+#include "core/loader/loader.h"
namespace FileSys {
diff --git a/src/core/file_sys/kernel_executable.h b/src/core/file_sys/kernel_executable.h
index 324a57384..044c554d3 100644
--- a/src/core/file_sys/kernel_executable.h
+++ b/src/core/file_sys/kernel_executable.h
@@ -4,10 +4,17 @@
#pragma once
+#include <array>
+#include <vector>
+
#include "common/common_funcs.h"
+#include "common/common_types.h"
#include "common/swap.h"
#include "core/file_sys/vfs_types.h"
-#include "core/loader/loader.h"
+
+namespace Loader {
+enum class ResultStatus : u16;
+}
namespace FileSys {
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp
index 93d0df6b9..3596541b2 100644
--- a/src/core/file_sys/nca_metadata.cpp
+++ b/src/core/file_sys/nca_metadata.cpp
@@ -7,6 +7,7 @@
#include "common/logging/log.h"
#include "common/swap.h"
#include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/vfs.h"
namespace FileSys {
@@ -107,7 +108,7 @@ std::vector<u8> CNMT::Serialize() const {
memcpy(out.data() + sizeof(CNMTHeader), &opt_header, sizeof(OptionalHeader));
}
- auto offset = header.table_offset;
+ u64_le offset = header.table_offset;
for (const auto& rec : content_records) {
memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(ContentRecord));
diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h
index 1f82fff0a..53535e5f5 100644
--- a/src/core/file_sys/nca_metadata.h
+++ b/src/core/file_sys/nca_metadata.h
@@ -10,7 +10,7 @@
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/swap.h"
-#include "core/file_sys/vfs.h"
+#include "core/file_sys/vfs_types.h"
namespace FileSys {
class CNMT;
diff --git a/src/core/file_sys/nca_patch.cpp b/src/core/file_sys/nca_patch.cpp
index fe7375e84..5990a2fd5 100644
--- a/src/core/file_sys/nca_patch.cpp
+++ b/src/core/file_sys/nca_patch.cpp
@@ -12,6 +12,49 @@
#include "core/file_sys/nca_patch.h"
namespace FileSys {
+namespace {
+template <bool Subsection, typename BlockType, typename BucketType>
+std::pair<std::size_t, std::size_t> SearchBucketEntry(u64 offset, const BlockType& block,
+ const BucketType& buckets) {
+ if constexpr (Subsection) {
+ const auto& last_bucket = buckets[block.number_buckets - 1];
+ if (offset >= last_bucket.entries[last_bucket.number_entries].address_patch) {
+ return {block.number_buckets - 1, last_bucket.number_entries};
+ }
+ } else {
+ ASSERT_MSG(offset <= block.size, "Offset is out of bounds in BKTR relocation block.");
+ }
+
+ std::size_t bucket_id = std::count_if(
+ block.base_offsets.begin() + 1, block.base_offsets.begin() + block.number_buckets,
+ [&offset](u64 base_offset) { return base_offset <= offset; });
+
+ const auto& bucket = buckets[bucket_id];
+
+ if (bucket.number_entries == 1) {
+ return {bucket_id, 0};
+ }
+
+ std::size_t low = 0;
+ std::size_t mid = 0;
+ std::size_t high = bucket.number_entries - 1;
+ while (low <= high) {
+ mid = (low + high) / 2;
+ if (bucket.entries[mid].address_patch > offset) {
+ high = mid - 1;
+ } else {
+ if (mid == bucket.number_entries - 1 ||
+ bucket.entries[mid + 1].address_patch > offset) {
+ return {bucket_id, mid};
+ }
+
+ low = mid + 1;
+ }
+ }
+
+ UNREACHABLE_MSG("Offset could not be found in BKTR block.");
+}
+} // Anonymous namespace
BKTR::BKTR(VirtualFile base_romfs_, VirtualFile bktr_romfs_, RelocationBlock relocation_,
std::vector<RelocationBucket> relocation_buckets_, SubsectionBlock subsection_,
@@ -110,46 +153,6 @@ std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
return raw_read;
}
-template <bool Subsection, typename BlockType, typename BucketType>
-std::pair<std::size_t, std::size_t> BKTR::SearchBucketEntry(u64 offset, BlockType block,
- BucketType buckets) const {
- if constexpr (Subsection) {
- const auto last_bucket = buckets[block.number_buckets - 1];
- if (offset >= last_bucket.entries[last_bucket.number_entries].address_patch)
- return {block.number_buckets - 1, last_bucket.number_entries};
- } else {
- ASSERT_MSG(offset <= block.size, "Offset is out of bounds in BKTR relocation block.");
- }
-
- std::size_t bucket_id = std::count_if(
- block.base_offsets.begin() + 1, block.base_offsets.begin() + block.number_buckets,
- [&offset](u64 base_offset) { return base_offset <= offset; });
-
- const auto bucket = buckets[bucket_id];
-
- if (bucket.number_entries == 1)
- return {bucket_id, 0};
-
- std::size_t low = 0;
- std::size_t mid = 0;
- std::size_t high = bucket.number_entries - 1;
- while (low <= high) {
- mid = (low + high) / 2;
- if (bucket.entries[mid].address_patch > offset) {
- high = mid - 1;
- } else {
- if (mid == bucket.number_entries - 1 ||
- bucket.entries[mid + 1].address_patch > offset) {
- return {bucket_id, mid};
- }
-
- low = mid + 1;
- }
- }
-
- UNREACHABLE_MSG("Offset could not be found in BKTR block.");
-}
-
RelocationEntry BKTR::GetRelocationEntry(u64 offset) const {
const auto res = SearchBucketEntry<false>(offset, relocation, relocation_buckets);
return relocation_buckets[res.first].entries[res.second];
diff --git a/src/core/file_sys/nca_patch.h b/src/core/file_sys/nca_patch.h
index 8e64e8378..60c544f8e 100644
--- a/src/core/file_sys/nca_patch.h
+++ b/src/core/file_sys/nca_patch.h
@@ -117,10 +117,6 @@ public:
bool Rename(std::string_view name) override;
private:
- template <bool Subsection, typename BlockType, typename BucketType>
- std::pair<std::size_t, std::size_t> SearchBucketEntry(u64 offset, BlockType block,
- BucketType buckets) const;
-
RelocationEntry GetRelocationEntry(u64 offset) const;
RelocationEntry GetNextRelocationEntry(u64 offset) const;
diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp
index 846986736..48a2ed4d4 100644
--- a/src/core/file_sys/partition_filesystem.cpp
+++ b/src/core/file_sys/partition_filesystem.cpp
@@ -21,7 +21,7 @@ bool PartitionFilesystem::Header::HasValidMagicValue() const {
magic == Common::MakeMagic('P', 'F', 'S', '0');
}
-PartitionFilesystem::PartitionFilesystem(std::shared_ptr<VfsFile> file) {
+PartitionFilesystem::PartitionFilesystem(VirtualFile file) {
// At least be as large as the header
if (file->GetSize() < sizeof(Header)) {
status = Loader::ResultStatus::ErrorBadPFSHeader;
@@ -89,11 +89,11 @@ std::map<std::string, u64> PartitionFilesystem::GetFileSizes() const {
return sizes;
}
-std::vector<std::shared_ptr<VfsFile>> PartitionFilesystem::GetFiles() const {
+std::vector<VirtualFile> PartitionFilesystem::GetFiles() const {
return pfs_files;
}
-std::vector<std::shared_ptr<VfsDirectory>> PartitionFilesystem::GetSubdirectories() const {
+std::vector<VirtualDir> PartitionFilesystem::GetSubdirectories() const {
return {};
}
@@ -101,7 +101,7 @@ std::string PartitionFilesystem::GetName() const {
return is_hfs ? "HFS0" : "PFS0";
}
-std::shared_ptr<VfsDirectory> PartitionFilesystem::GetParentDirectory() const {
+VirtualDir PartitionFilesystem::GetParentDirectory() const {
// TODO(DarkLordZach): Add support for nested containers.
return nullptr;
}
diff --git a/src/core/file_sys/partition_filesystem.h b/src/core/file_sys/partition_filesystem.h
index 279193b19..0f831148e 100644
--- a/src/core/file_sys/partition_filesystem.h
+++ b/src/core/file_sys/partition_filesystem.h
@@ -24,7 +24,7 @@ namespace FileSys {
*/
class PartitionFilesystem : public ReadOnlyVfsDirectory {
public:
- explicit PartitionFilesystem(std::shared_ptr<VfsFile> file);
+ explicit PartitionFilesystem(VirtualFile file);
~PartitionFilesystem() override;
Loader::ResultStatus GetStatus() const;
@@ -32,10 +32,10 @@ public:
std::map<std::string, u64> GetFileOffsets() const;
std::map<std::string, u64> GetFileSizes() const;
- std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
- std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
+ std::vector<VirtualFile> GetFiles() const override;
+ std::vector<VirtualDir> GetSubdirectories() const override;
std::string GetName() const override;
- std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
+ VirtualDir GetParentDirectory() const override;
void PrintDebugInfo() const;
private:
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 729dbb5f4..e9d1607d0 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -27,8 +27,9 @@
#include "core/settings.h"
namespace FileSys {
+namespace {
-constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
+constexpr u32 SINGLE_BYTE_MODULUS = 0x100;
constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
@@ -36,21 +37,29 @@ constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
"subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9",
};
-std::string FormatTitleVersion(u32 version, TitleVersionFormat format) {
+enum class TitleVersionFormat : u8 {
+ ThreeElements, ///< vX.Y.Z
+ FourElements, ///< vX.Y.Z.W
+};
+
+std::string FormatTitleVersion(u32 version,
+ TitleVersionFormat format = TitleVersionFormat::ThreeElements) {
std::array<u8, sizeof(u32)> bytes{};
- bytes[0] = version % SINGLE_BYTE_MODULUS;
+ bytes[0] = static_cast<u8>(version % SINGLE_BYTE_MODULUS);
for (std::size_t i = 1; i < bytes.size(); ++i) {
version /= SINGLE_BYTE_MODULUS;
- bytes[i] = version % SINGLE_BYTE_MODULUS;
+ bytes[i] = static_cast<u8>(version % SINGLE_BYTE_MODULUS);
}
- if (format == TitleVersionFormat::FourElements)
+ if (format == TitleVersionFormat::FourElements) {
return fmt::format("v{}.{}.{}.{}", bytes[3], bytes[2], bytes[1], bytes[0]);
+ }
return fmt::format("v{}.{}.{}", bytes[3], bytes[2], bytes[1]);
}
-std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<VfsDirectory> dir,
- std::string_view name) {
+// Returns a directory with name matching name case-insensitive. Returns nullptr if directory
+// doesn't have a directory with name.
+VirtualDir FindSubdirectoryCaseless(const VirtualDir dir, std::string_view name) {
#ifdef _WIN32
return dir->GetSubdirectory(name);
#else
@@ -66,7 +75,47 @@ std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<Vfs
#endif
}
-PatchManager::PatchManager(u64 title_id) : title_id(title_id) {}
+std::optional<std::vector<Core::Memory::CheatEntry>> ReadCheatFileFromFolder(
+ u64 title_id, const PatchManager::BuildID& build_id_, const VirtualDir& base_path, bool upper) {
+ const auto build_id_raw = Common::HexToString(build_id_, upper);
+ const auto build_id = build_id_raw.substr(0, sizeof(u64) * 2);
+ const auto file = base_path->GetFile(fmt::format("{}.txt", build_id));
+
+ if (file == nullptr) {
+ LOG_INFO(Common_Filesystem, "No cheats file found for title_id={:016X}, build_id={}",
+ title_id, build_id);
+ return std::nullopt;
+ }
+
+ std::vector<u8> data(file->GetSize());
+ if (file->Read(data.data(), data.size()) != data.size()) {
+ LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}, build_id={}",
+ title_id, build_id);
+ return std::nullopt;
+ }
+
+ const Core::Memory::TextCheatParser parser;
+ return parser.Parse(std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
+}
+
+void AppendCommaIfNotEmpty(std::string& to, std::string_view with) {
+ if (to.empty()) {
+ to += with;
+ } else {
+ to += ", ";
+ to += with;
+ }
+}
+
+bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
+ return dir != nullptr && (!dir->GetFiles().empty() || !dir->GetSubdirectories().empty());
+}
+} // Anonymous namespace
+
+PatchManager::PatchManager(u64 title_id_,
+ const Service::FileSystem::FileSystemController& fs_controller_,
+ const ContentProvider& content_provider_)
+ : title_id{title_id_}, fs_controller{fs_controller_}, content_provider{content_provider_} {}
PatchManager::~PatchManager() = default;
@@ -82,34 +131,30 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
if (Settings::values.dump_exefs) {
LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
- const auto dump_dir =
- Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id);
+ const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id);
if (dump_dir != nullptr) {
const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
VfsRawCopyD(exefs, exefs_dir);
}
}
- const auto& installed = Core::System::GetInstance().GetContentProvider();
-
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto update_disabled =
std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend();
// Game Updates
const auto update_tid = GetUpdateTitleID(title_id);
- const auto update = installed.GetEntry(update_tid, ContentRecordType::Program);
+ const auto update = content_provider.GetEntry(update_tid, ContentRecordType::Program);
if (!update_disabled && update != nullptr && update->GetExeFS() != nullptr &&
update->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
LOG_INFO(Loader, " ExeFS: Update ({}) applied successfully",
- FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
+ FormatTitleVersion(content_provider.GetEntryVersion(update_tid).value_or(0)));
exefs = update->GetExeFS();
}
// LayeredExeFS
- const auto load_dir =
- Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
+ const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if (load_dir != nullptr && load_dir->GetSize() > 0) {
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(
@@ -195,8 +240,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
if (Settings::values.dump_nso) {
LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id,
title_id);
- const auto dump_dir =
- Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id);
+ const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id);
if (dump_dir != nullptr) {
const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso");
const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id));
@@ -208,8 +252,7 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
- const auto load_dir =
- Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
+ const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return nso;
@@ -246,14 +289,13 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
return out;
}
-bool PatchManager::HasNSOPatch(const std::array<u8, 32>& build_id_) const {
+bool PatchManager::HasNSOPatch(const BuildID& build_id_) const {
const auto build_id_raw = Common::HexToString(build_id_);
const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1);
LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id);
- const auto load_dir =
- Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
+ const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return false;
@@ -266,37 +308,9 @@ bool PatchManager::HasNSOPatch(const std::array<u8, 32>& build_id_) const {
return !CollectPatches(patch_dirs, build_id).empty();
}
-namespace {
-std::optional<std::vector<Core::Memory::CheatEntry>> ReadCheatFileFromFolder(
- const Core::System& system, u64 title_id, const std::array<u8, 0x20>& build_id_,
- const VirtualDir& base_path, bool upper) {
- const auto build_id_raw = Common::HexToString(build_id_, upper);
- const auto build_id = build_id_raw.substr(0, sizeof(u64) * 2);
- const auto file = base_path->GetFile(fmt::format("{}.txt", build_id));
-
- if (file == nullptr) {
- LOG_INFO(Common_Filesystem, "No cheats file found for title_id={:016X}, build_id={}",
- title_id, build_id);
- return std::nullopt;
- }
-
- std::vector<u8> data(file->GetSize());
- if (file->Read(data.data(), data.size()) != data.size()) {
- LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}, build_id={}",
- title_id, build_id);
- return std::nullopt;
- }
-
- Core::Memory::TextCheatParser parser;
- return parser.Parse(system,
- std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
-}
-
-} // Anonymous namespace
-
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(
- const Core::System& system, const std::array<u8, 32>& build_id_) const {
- const auto load_dir = system.GetFileSystemController().GetModificationLoadRoot(title_id);
+ const BuildID& build_id_) const {
+ const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if (load_dir == nullptr) {
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
return {};
@@ -315,14 +329,12 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(
auto cheats_dir = FindSubdirectoryCaseless(subdir, "cheats");
if (cheats_dir != nullptr) {
- auto res = ReadCheatFileFromFolder(system, title_id, build_id_, cheats_dir, true);
- if (res.has_value()) {
+ if (const auto res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true)) {
std::copy(res->begin(), res->end(), std::back_inserter(out));
continue;
}
- res = ReadCheatFileFromFolder(system, title_id, build_id_, cheats_dir, false);
- if (res.has_value()) {
+ if (const auto res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false)) {
std::copy(res->begin(), res->end(), std::back_inserter(out));
}
}
@@ -331,9 +343,9 @@ std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(
return out;
}
-static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) {
- const auto load_dir =
- Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
+static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type,
+ const Service::FileSystem::FileSystemController& fs_controller) {
+ const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
if ((type != ContentRecordType::Program && type != ContentRecordType::Data) ||
load_dir == nullptr || load_dir->GetSize() <= 0) {
return;
@@ -395,19 +407,19 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
const auto log_string = fmt::format("Patching RomFS for title_id={:016X}, type={:02X}",
title_id, static_cast<u8>(type));
- if (type == ContentRecordType::Program || type == ContentRecordType::Data)
+ if (type == ContentRecordType::Program || type == ContentRecordType::Data) {
LOG_INFO(Loader, "{}", log_string);
- else
+ } else {
LOG_DEBUG(Loader, "{}", log_string);
+ }
- if (romfs == nullptr)
+ if (romfs == nullptr) {
return romfs;
-
- const auto& installed = Core::System::GetInstance().GetContentProvider();
+ }
// Game Updates
const auto update_tid = GetUpdateTitleID(title_id);
- const auto update = installed.GetEntryRaw(update_tid, type);
+ const auto update = content_provider.GetEntryRaw(update_tid, type);
const auto& disabled = Settings::values.disabled_addons[title_id];
const auto update_disabled =
@@ -418,7 +430,7 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
new_nca->GetRomFS() != nullptr) {
LOG_INFO(Loader, " RomFS: Update ({}) applied successfully",
- FormatTitleVersion(installed.GetEntryVersion(update_tid).value_or(0)));
+ FormatTitleVersion(content_provider.GetEntryVersion(update_tid).value_or(0)));
romfs = new_nca->GetRomFS();
}
} else if (!update_disabled && update_raw != nullptr) {
@@ -431,33 +443,22 @@ VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, Content
}
// LayeredFS
- ApplyLayeredFS(romfs, title_id, type);
+ ApplyLayeredFS(romfs, title_id, type, fs_controller);
return romfs;
}
-static void AppendCommaIfNotEmpty(std::string& to, const std::string& with) {
- if (to.empty())
- to += with;
- else
- to += ", " + with;
-}
-
-static bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
- return dir != nullptr && (!dir->GetFiles().empty() || !dir->GetSubdirectories().empty());
-}
-
-std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames(
- VirtualFile update_raw) const {
- if (title_id == 0)
+PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile update_raw) const {
+ if (title_id == 0) {
return {};
+ }
+
std::map<std::string, std::string, std::less<>> out;
- const auto& installed = Core::System::GetInstance().GetContentProvider();
const auto& disabled = Settings::values.disabled_addons[title_id];
// Game Updates
const auto update_tid = GetUpdateTitleID(title_id);
- PatchManager update{update_tid};
+ PatchManager update{update_tid, fs_controller, content_provider};
const auto metadata = update.GetControlMetadata();
const auto& nacp = metadata.first;
@@ -468,13 +469,12 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
if (nacp != nullptr) {
out.insert_or_assign(update_label, nacp->GetVersionString());
} else {
- if (installed.HasEntry(update_tid, ContentRecordType::Program)) {
- const auto meta_ver = installed.GetEntryVersion(update_tid);
+ if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) {
+ const auto meta_ver = content_provider.GetEntryVersion(update_tid);
if (meta_ver.value_or(0) == 0) {
out.insert_or_assign(update_label, "");
} else {
- out.insert_or_assign(
- update_label, FormatTitleVersion(*meta_ver, TitleVersionFormat::ThreeElements));
+ out.insert_or_assign(update_label, FormatTitleVersion(*meta_ver));
}
} else if (update_raw != nullptr) {
out.insert_or_assign(update_label, "PACKED");
@@ -482,8 +482,7 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
}
// General Mods (LayeredFS and IPS)
- const auto mod_dir =
- Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
+ const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id);
if (mod_dir != nullptr && mod_dir->GetSize() > 0) {
for (const auto& mod : mod_dir->GetSubdirectories()) {
std::string types;
@@ -527,13 +526,15 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
}
// DLC
- const auto dlc_entries = installed.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
+ const auto dlc_entries =
+ content_provider.ListEntriesFilter(TitleType::AOC, ContentRecordType::Data);
std::vector<ContentProviderEntry> dlc_match;
dlc_match.reserve(dlc_entries.size());
std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
- [this, &installed](const ContentProviderEntry& entry) {
+ [this](const ContentProviderEntry& entry) {
return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id &&
- installed.GetEntry(entry)->GetStatus() == Loader::ResultStatus::Success;
+ content_provider.GetEntry(entry)->GetStatus() ==
+ Loader::ResultStatus::Success;
});
if (!dlc_match.empty()) {
// Ensure sorted so DLC IDs show in order.
@@ -554,49 +555,52 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
}
std::optional<u32> PatchManager::GetGameVersion() const {
- const auto& installed = Core::System::GetInstance().GetContentProvider();
const auto update_tid = GetUpdateTitleID(title_id);
- if (installed.HasEntry(update_tid, ContentRecordType::Program)) {
- return installed.GetEntryVersion(update_tid);
+ if (content_provider.HasEntry(update_tid, ContentRecordType::Program)) {
+ return content_provider.GetEntryVersion(update_tid);
}
- return installed.GetEntryVersion(title_id);
+ return content_provider.GetEntryVersion(title_id);
}
-std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::GetControlMetadata() const {
- const auto& installed = Core::System::GetInstance().GetContentProvider();
-
- const auto base_control_nca = installed.GetEntry(title_id, ContentRecordType::Control);
- if (base_control_nca == nullptr)
+PatchManager::Metadata PatchManager::GetControlMetadata() const {
+ const auto base_control_nca = content_provider.GetEntry(title_id, ContentRecordType::Control);
+ if (base_control_nca == nullptr) {
return {};
+ }
return ParseControlNCA(*base_control_nca);
}
-std::pair<std::unique_ptr<NACP>, VirtualFile> PatchManager::ParseControlNCA(const NCA& nca) const {
+PatchManager::Metadata PatchManager::ParseControlNCA(const NCA& nca) const {
const auto base_romfs = nca.GetRomFS();
- if (base_romfs == nullptr)
+ if (base_romfs == nullptr) {
return {};
+ }
const auto romfs = PatchRomFS(base_romfs, nca.GetBaseIVFCOffset(), ContentRecordType::Control);
- if (romfs == nullptr)
+ if (romfs == nullptr) {
return {};
+ }
const auto extracted = ExtractRomFS(romfs);
- if (extracted == nullptr)
+ if (extracted == nullptr) {
return {};
+ }
auto nacp_file = extracted->GetFile("control.nacp");
- if (nacp_file == nullptr)
+ if (nacp_file == nullptr) {
nacp_file = extracted->GetFile("Control.nacp");
+ }
auto nacp = nacp_file == nullptr ? nullptr : std::make_unique<NACP>(nacp_file);
VirtualFile icon_file;
for (const auto& language : FileSys::LANGUAGE_NAMES) {
- icon_file = extracted->GetFile("icon_" + std::string(language) + ".dat");
- if (icon_file != nullptr)
+ icon_file = extracted->GetFile(std::string("icon_").append(language).append(".dat"));
+ if (icon_file != nullptr) {
break;
+ }
}
return {std::move(nacp), icon_file};
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index f4cb918dd..fb1853035 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -6,88 +6,89 @@
#include <map>
#include <memory>
+#include <optional>
#include <string>
#include "common/common_types.h"
#include "core/file_sys/nca_metadata.h"
-#include "core/file_sys/vfs.h"
+#include "core/file_sys/vfs_types.h"
#include "core/memory/dmnt_cheat_types.h"
namespace Core {
class System;
}
+namespace Service::FileSystem {
+class FileSystemController;
+}
+
namespace FileSys {
+class ContentProvider;
class NCA;
class NACP;
-enum class TitleVersionFormat : u8 {
- ThreeElements, ///< vX.Y.Z
- FourElements, ///< vX.Y.Z.W
-};
-
-std::string FormatTitleVersion(u32 version,
- TitleVersionFormat format = TitleVersionFormat::ThreeElements);
-
-// Returns a directory with name matching name case-insensitive. Returns nullptr if directory
-// doesn't have a directory with name.
-std::shared_ptr<VfsDirectory> FindSubdirectoryCaseless(const std::shared_ptr<VfsDirectory> dir,
- std::string_view name);
-
// A centralized class to manage patches to games.
class PatchManager {
public:
- explicit PatchManager(u64 title_id);
+ using BuildID = std::array<u8, 0x20>;
+ using Metadata = std::pair<std::unique_ptr<NACP>, VirtualFile>;
+ using PatchVersionNames = std::map<std::string, std::string, std::less<>>;
+
+ explicit PatchManager(u64 title_id_,
+ const Service::FileSystem::FileSystemController& fs_controller_,
+ const ContentProvider& content_provider_);
~PatchManager();
- u64 GetTitleID() const;
+ [[nodiscard]] u64 GetTitleID() const;
// Currently tracked ExeFS patches:
// - Game Updates
- VirtualDir PatchExeFS(VirtualDir exefs) const;
+ [[nodiscard]] VirtualDir PatchExeFS(VirtualDir exefs) const;
// Currently tracked NSO patches:
// - IPS
// - IPSwitch
- std::vector<u8> PatchNSO(const std::vector<u8>& nso, const std::string& name) const;
+ [[nodiscard]] std::vector<u8> PatchNSO(const std::vector<u8>& nso,
+ const std::string& name) const;
// Checks to see if PatchNSO() will have any effect given the NSO's build ID.
// Used to prevent expensive copies in NSO loader.
- bool HasNSOPatch(const std::array<u8, 0x20>& build_id) const;
+ [[nodiscard]] bool HasNSOPatch(const BuildID& build_id) const;
// Creates a CheatList object with all
- std::vector<Core::Memory::CheatEntry> CreateCheatList(
- const Core::System& system, const std::array<u8, 0x20>& build_id) const;
+ [[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList(
+ const BuildID& build_id) const;
// Currently tracked RomFS patches:
// - Game Updates
// - LayeredFS
- VirtualFile PatchRomFS(VirtualFile base, u64 ivfc_offset,
- ContentRecordType type = ContentRecordType::Program,
- VirtualFile update_raw = nullptr) const;
+ [[nodiscard]] VirtualFile PatchRomFS(VirtualFile base, u64 ivfc_offset,
+ ContentRecordType type = ContentRecordType::Program,
+ VirtualFile update_raw = nullptr) const;
// Returns a vector of pairs between patch names and patch versions.
// i.e. Update 3.2.2 will return {"Update", "3.2.2"}
- std::map<std::string, std::string, std::less<>> GetPatchVersionNames(
- VirtualFile update_raw = nullptr) const;
+ [[nodiscard]] PatchVersionNames GetPatchVersionNames(VirtualFile update_raw = nullptr) const;
// If the game update exists, returns the u32 version field in its Meta-type NCA. If that fails,
// it will fallback to the Meta-type NCA of the base game. If that fails, the result will be
// std::nullopt
- std::optional<u32> GetGameVersion() const;
+ [[nodiscard]] std::optional<u32> GetGameVersion() const;
// Given title_id of the program, attempts to get the control data of the update and parse
// it, falling back to the base control data.
- std::pair<std::unique_ptr<NACP>, VirtualFile> GetControlMetadata() const;
+ [[nodiscard]] Metadata GetControlMetadata() const;
// Version of GetControlMetadata that takes an arbitrary NCA
- std::pair<std::unique_ptr<NACP>, VirtualFile> ParseControlNCA(const NCA& nca) const;
+ [[nodiscard]] Metadata ParseControlNCA(const NCA& nca) const;
private:
- std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
- const std::string& build_id) const;
+ [[nodiscard]] std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
+ const std::string& build_id) const;
u64 title_id;
+ const Service::FileSystem::FileSystemController& fs_controller;
+ const ContentProvider& content_provider;
};
} // namespace FileSys
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index 43169bf9f..9cf49bf44 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -7,6 +7,7 @@
#include "common/logging/log.h"
#include "core/file_sys/program_metadata.h"
+#include "core/file_sys/vfs.h"
#include "core/loader/loader.h"
namespace FileSys {
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index 35069972b..455532567 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -9,7 +9,7 @@
#include "common/bit_field.h"
#include "common/common_types.h"
#include "common/swap.h"
-#include "core/file_sys/vfs.h"
+#include "core/file_sys/vfs_types.h"
namespace Loader {
enum class ResultStatus : u16;
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index e42b677f7..da01002d5 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -257,8 +257,7 @@ std::vector<NcaID> PlaceholderCache::List() const {
for (const auto& sdir : dir->GetSubdirectories()) {
for (const auto& file : sdir->GetFiles()) {
const auto name = file->GetName();
- if (name.length() == 36 && name[32] == '.' && name[33] == 'n' && name[34] == 'c' &&
- name[35] == 'a') {
+ if (name.length() == 36 && name.ends_with(".nca")) {
out.push_back(Common::HexStringToArray<0x10>(name.substr(0, 32)));
}
}
@@ -621,25 +620,25 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
bool overwrite_if_exists, const VfsCopyFunction& copy) {
- CNMTHeader header{
- nca.GetTitleId(), // Title ID
- 0, // Ignore/Default title version
- type, // Type
- {}, // Padding
- 0x10, // Default table offset
- 1, // 1 Content Entry
- 0, // No Meta Entries
- {}, // Padding
- {}, // Reserved 1
- 0, // Is committed
- 0, // Required download system version
- {}, // Reserved 2
+ const CNMTHeader header{
+ .title_id = nca.GetTitleId(),
+ .title_version = 0,
+ .type = type,
+ .reserved = {},
+ .table_offset = 0x10,
+ .number_content_entries = 1,
+ .number_meta_entries = 0,
+ .attributes = 0,
+ .reserved2 = {},
+ .is_committed = 0,
+ .required_download_system_version = 0,
+ .reserved3 = {},
};
- OptionalHeader opt_header{0, 0};
+ const OptionalHeader opt_header{0, 0};
ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}};
const auto& data = nca.GetBaseFile()->ReadBytes(0x100000);
mbedtls_sha256_ret(data.data(), data.size(), c_rec.hash.data(), 0);
- memcpy(&c_rec.nca_id, &c_rec.hash, 16);
+ std::memcpy(&c_rec.nca_id, &c_rec.hash, 16);
const CNMT new_cnmt(header, opt_header, {c_rec}, {});
if (!RawInstallYuzuMeta(new_cnmt)) {
return InstallResult::ErrorMetaFailed;
diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h
index 2fd07ed04..82e683782 100644
--- a/src/core/file_sys/romfs.h
+++ b/src/core/file_sys/romfs.h
@@ -4,7 +4,6 @@
#pragma once
-#include <array>
#include "core/file_sys/vfs.h"
namespace FileSys {
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index 418a39a7e..987199747 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -6,7 +6,6 @@
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
-#include "core/core.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
@@ -19,7 +18,9 @@
namespace FileSys {
-RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) {
+RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader, ContentProvider& provider,
+ Service::FileSystem::FileSystemController& controller)
+ : content_provider{provider}, filesystem_controller{controller} {
// Load the RomFS from the app
if (app_loader.ReadRomFS(file) != Loader::ResultStatus::Success) {
LOG_ERROR(Service_FS, "Unable to read RomFS!");
@@ -36,49 +37,50 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) {
}
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_title_id) const {
- if (!updatable)
+ if (!updatable) {
return MakeResult<VirtualFile>(file);
+ }
- const PatchManager patch_manager(current_process_title_id);
+ const PatchManager patch_manager{current_process_title_id, filesystem_controller,
+ content_provider};
return MakeResult<VirtualFile>(
patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw));
}
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage,
ContentRecordType type) const {
- std::shared_ptr<NCA> res;
-
- switch (storage) {
- case StorageId::None:
- res = Core::System::GetInstance().GetContentProvider().GetEntry(title_id, type);
- break;
- case StorageId::NandSystem:
- res =
- Core::System::GetInstance().GetFileSystemController().GetSystemNANDContents()->GetEntry(
- title_id, type);
- break;
- case StorageId::NandUser:
- res = Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->GetEntry(
- title_id, type);
- break;
- case StorageId::SdCard:
- res = Core::System::GetInstance().GetFileSystemController().GetSDMCContents()->GetEntry(
- title_id, type);
- break;
- default:
- UNIMPLEMENTED_MSG("Unimplemented storage_id={:02X}", static_cast<u8>(storage));
- }
-
+ const std::shared_ptr<NCA> res = GetEntry(title_id, storage, type);
if (res == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return RESULT_UNKNOWN;
}
+
const auto romfs = res->GetRomFS();
if (romfs == nullptr) {
// TODO(DarkLordZach): Find the right error code to use here
return RESULT_UNKNOWN;
}
+
return MakeResult<VirtualFile>(romfs);
}
+std::shared_ptr<NCA> RomFSFactory::GetEntry(u64 title_id, StorageId storage,
+ ContentRecordType type) const {
+ switch (storage) {
+ case StorageId::None:
+ return content_provider.GetEntry(title_id, type);
+ case StorageId::NandSystem:
+ return filesystem_controller.GetSystemNANDContents()->GetEntry(title_id, type);
+ case StorageId::NandUser:
+ return filesystem_controller.GetUserNANDContents()->GetEntry(title_id, type);
+ case StorageId::SdCard:
+ return filesystem_controller.GetSDMCContents()->GetEntry(title_id, type);
+ case StorageId::Host:
+ case StorageId::GameCard:
+ default:
+ UNIMPLEMENTED_MSG("Unimplemented storage_id={:02X}", static_cast<u8>(storage));
+ return nullptr;
+ }
+}
+
} // namespace FileSys
diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h
index c5d40285c..ec704dfa8 100644
--- a/src/core/file_sys/romfs_factory.h
+++ b/src/core/file_sys/romfs_factory.h
@@ -13,8 +13,15 @@ namespace Loader {
class AppLoader;
} // namespace Loader
+namespace Service::FileSystem {
+class FileSystemController;
+}
+
namespace FileSys {
+class ContentProvider;
+class NCA;
+
enum class ContentRecordType : u8;
enum class StorageId : u8 {
@@ -29,18 +36,26 @@ enum class StorageId : u8 {
/// File system interface to the RomFS archive
class RomFSFactory {
public:
- explicit RomFSFactory(Loader::AppLoader& app_loader);
+ explicit RomFSFactory(Loader::AppLoader& app_loader, ContentProvider& provider,
+ Service::FileSystem::FileSystemController& controller);
~RomFSFactory();
void SetPackedUpdate(VirtualFile update_raw);
- ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const;
- ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type) const;
+ [[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const;
+ [[nodiscard]] ResultVal<VirtualFile> Open(u64 title_id, StorageId storage,
+ ContentRecordType type) const;
private:
+ [[nodiscard]] std::shared_ptr<NCA> GetEntry(u64 title_id, StorageId storage,
+ ContentRecordType type) const;
+
VirtualFile file;
VirtualFile update_raw;
bool updatable;
u64 ivfc_offset;
+
+ ContentProvider& content_provider;
+ Service::FileSystem::FileSystemController& filesystem_controller;
};
} // namespace FileSys
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp
index 6f732e4d8..cb56d8f2d 100644
--- a/src/core/file_sys/sdmc_factory.cpp
+++ b/src/core/file_sys/sdmc_factory.cpp
@@ -5,8 +5,8 @@
#include <memory>
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/sdmc_factory.h"
+#include "core/file_sys/vfs.h"
#include "core/file_sys/xts_archive.h"
-#include "core/settings.h"
namespace FileSys {
diff --git a/src/core/file_sys/sdmc_factory.h b/src/core/file_sys/sdmc_factory.h
index 42dc4e08a..2bb92ba93 100644
--- a/src/core/file_sys/sdmc_factory.h
+++ b/src/core/file_sys/sdmc_factory.h
@@ -5,7 +5,7 @@
#pragma once
#include <memory>
-#include "core/file_sys/vfs.h"
+#include "core/file_sys/vfs_types.h"
#include "core/hle/result.h"
namespace FileSys {
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index 175a8266a..90641d23b 100644
--- a/src/core/file_sys/submission_package.cpp
+++ b/src/core/file_sys/submission_package.cpp
@@ -19,42 +19,10 @@
#include "core/loader/loader.h"
namespace FileSys {
-namespace {
-void SetTicketKeys(const std::vector<VirtualFile>& files) {
- auto& keys = Core::Crypto::KeyManager::Instance();
-
- for (const auto& ticket_file : files) {
- if (ticket_file == nullptr) {
- continue;
- }
-
- if (ticket_file->GetExtension() != "tik") {
- continue;
- }
-
- if (ticket_file->GetSize() <
- Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) {
- continue;
- }
-
- Core::Crypto::Key128 key{};
- ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET);
-
- // We get the name without the extension in order to create the rights ID.
- std::string name_only(ticket_file->GetName());
- name_only.erase(name_only.size() - 4);
-
- const auto rights_id_raw = Common::HexStringToArray<16>(name_only);
- u128 rights_id;
- std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128));
- keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
- }
-}
-} // Anonymous namespace
NSP::NSP(VirtualFile file_)
: file(std::move(file_)), status{Loader::ResultStatus::Success},
- pfs(std::make_shared<PartitionFilesystem>(file)) {
+ pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} {
if (pfs->GetStatus() != Loader::ResultStatus::Success) {
status = pfs->GetStatus();
return;
@@ -232,6 +200,35 @@ VirtualDir NSP::GetParentDirectory() const {
return file->GetContainingDirectory();
}
+void NSP::SetTicketKeys(const std::vector<VirtualFile>& files) {
+ for (const auto& ticket_file : files) {
+ if (ticket_file == nullptr) {
+ continue;
+ }
+
+ if (ticket_file->GetExtension() != "tik") {
+ continue;
+ }
+
+ if (ticket_file->GetSize() <
+ Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET + sizeof(Core::Crypto::Key128)) {
+ continue;
+ }
+
+ Core::Crypto::Key128 key{};
+ ticket_file->Read(key.data(), key.size(), Core::Crypto::TICKET_FILE_TITLEKEY_OFFSET);
+
+ // We get the name without the extension in order to create the rights ID.
+ std::string name_only(ticket_file->GetName());
+ name_only.erase(name_only.size() - 4);
+
+ const auto rights_id_raw = Common::HexStringToArray<16>(name_only);
+ u128 rights_id;
+ std::memcpy(rights_id.data(), rights_id_raw.data(), sizeof(u128));
+ keys.SetKey(Core::Crypto::S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
+ }
+}
+
void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) {
exefs = pfs;
@@ -267,9 +264,9 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
}
const CNMT cnmt(inner_file);
- auto& ncas_title = ncas[cnmt.GetTitleID()];
- ncas_title[{cnmt.GetType(), ContentRecordType::Meta}] = nca;
+ ncas[cnmt.GetTitleID()][{cnmt.GetType(), ContentRecordType::Meta}] = nca;
+
for (const auto& rec : cnmt.GetContentRecords()) {
const auto id_string = Common::HexToString(rec.nca_id, false);
auto next_file = pfs->GetFile(fmt::format("{}.nca", id_string));
@@ -286,13 +283,32 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
}
auto next_nca = std::make_shared<NCA>(std::move(next_file), nullptr, 0);
+
if (next_nca->GetType() == NCAContentType::Program) {
- program_status[cnmt.GetTitleID()] = next_nca->GetStatus();
+ program_status[next_nca->GetTitleId()] = next_nca->GetStatus();
}
- if (next_nca->GetStatus() == Loader::ResultStatus::Success ||
- (next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS &&
- (cnmt.GetTitleID() & 0x800) != 0)) {
- ncas_title[{cnmt.GetType(), rec.type}] = std::move(next_nca);
+
+ if (next_nca->GetStatus() != Loader::ResultStatus::Success &&
+ next_nca->GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
+ continue;
+ }
+
+ // If the last 3 hexadecimal digits of the CNMT TitleID is 0x800 or is missing the
+ // BKTRBaseRomFS, this is an update NCA. Otherwise, this is a base NCA.
+ if ((cnmt.GetTitleID() & 0x800) != 0 ||
+ next_nca->GetStatus() == Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
+ // If the last 3 hexadecimal digits of the NCA's TitleID is between 0x1 and
+ // 0x7FF, this is a multi-program update NCA. Otherwise, this is a regular
+ // update NCA.
+ if ((next_nca->GetTitleId() & 0x7FF) != 0 &&
+ (next_nca->GetTitleId() & 0x800) == 0) {
+ ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] =
+ std::move(next_nca);
+ } else {
+ ncas[cnmt.GetTitleID()][{cnmt.GetType(), rec.type}] = std::move(next_nca);
+ }
+ } else {
+ ncas[next_nca->GetTitleId()][{cnmt.GetType(), rec.type}] = std::move(next_nca);
}
}
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h
index cf89de6a9..c70a11b5b 100644
--- a/src/core/file_sys/submission_package.h
+++ b/src/core/file_sys/submission_package.h
@@ -10,6 +10,10 @@
#include "common/common_types.h"
#include "core/file_sys/vfs.h"
+namespace Core::Crypto {
+class KeyManager;
+}
+
namespace Loader {
enum class ResultStatus : u16;
}
@@ -59,6 +63,7 @@ public:
VirtualDir GetParentDirectory() const override;
private:
+ void SetTicketKeys(const std::vector<VirtualFile>& files);
void InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files);
void ReadNCAs(const std::vector<VirtualFile>& files);
@@ -73,7 +78,7 @@ private:
std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas;
std::vector<VirtualFile> ticket_files;
- Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
+ Core::Crypto::KeyManager& keys;
VirtualFile romfs;
VirtualDir exefs;
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index a4c3f67c4..b2f026b6d 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -169,11 +169,12 @@ VfsDirectory::~VfsDirectory() = default;
std::optional<u8> VfsFile::ReadByte(std::size_t offset) const {
u8 out{};
- std::size_t size = Read(&out, 1, offset);
- if (size == 1)
+ const std::size_t size = Read(&out, sizeof(u8), offset);
+ if (size == 1) {
return out;
+ }
- return {};
+ return std::nullopt;
}
std::vector<u8> VfsFile::ReadBytes(std::size_t size, std::size_t offset) const {
diff --git a/src/core/file_sys/vfs_offset.cpp b/src/core/file_sys/vfs_offset.cpp
index c96f88488..7714d3de5 100644
--- a/src/core/file_sys/vfs_offset.cpp
+++ b/src/core/file_sys/vfs_offset.cpp
@@ -58,10 +58,11 @@ std::size_t OffsetVfsFile::Write(const u8* data, std::size_t length, std::size_t
}
std::optional<u8> OffsetVfsFile::ReadByte(std::size_t r_offset) const {
- if (r_offset < size)
- return file->ReadByte(offset + r_offset);
+ if (r_offset >= size) {
+ return std::nullopt;
+ }
- return {};
+ return file->ReadByte(offset + r_offset);
}
std::vector<u8> OffsetVfsFile::ReadBytes(std::size_t r_size, std::size_t r_offset) const {
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h
index 9f5a90b1b..8b27c30fa 100644
--- a/src/core/file_sys/vfs_static.h
+++ b/src/core/file_sys/vfs_static.h
@@ -54,9 +54,11 @@ public:
}
std::optional<u8> ReadByte(std::size_t offset) const override {
- if (offset < size)
- return value;
- return {};
+ if (offset >= size) {
+ return std::nullopt;
+ }
+
+ return value;
}
std::vector<u8> ReadBytes(std::size_t length, std::size_t offset) const override {
diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp
index ccf5966d0..24c58e7ae 100644
--- a/src/core/file_sys/xts_archive.cpp
+++ b/src/core/file_sys/xts_archive.cpp
@@ -15,8 +15,9 @@
#include "common/hex_util.h"
#include "common/string_util.h"
#include "core/crypto/aes_util.h"
+#include "core/crypto/key_manager.h"
#include "core/crypto/xts_encryption_layer.h"
-#include "core/file_sys/partition_filesystem.h"
+#include "core/file_sys/content_archive.h"
#include "core/file_sys/vfs_offset.h"
#include "core/file_sys/xts_archive.h"
#include "core/loader/loader.h"
@@ -43,7 +44,9 @@ static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t
return true;
}
-NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::move(file_)) {
+NAX::NAX(VirtualFile file_)
+ : header(std::make_unique<NAXHeader>()),
+ file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
std::string path = Common::FS::SanitizePath(file->GetFullPath());
static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca",
std::regex_constants::ECMAScript |
@@ -60,7 +63,8 @@ NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::m
}
NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
- : header(std::make_unique<NAXHeader>()), file(std::move(file_)) {
+ : header(std::make_unique<NAXHeader>()),
+ file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
Core::Crypto::SHA256Hash hash{};
mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0);
status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0],
diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h
index 563531bb6..c472e226e 100644
--- a/src/core/file_sys/xts_archive.h
+++ b/src/core/file_sys/xts_archive.h
@@ -9,12 +9,16 @@
#include "common/common_types.h"
#include "common/swap.h"
#include "core/crypto/key_manager.h"
-#include "core/file_sys/content_archive.h"
#include "core/file_sys/vfs.h"
-#include "core/loader/loader.h"
+
+namespace Loader {
+enum class ResultStatus : u16;
+}
namespace FileSys {
+class NCA;
+
struct NAXHeader {
std::array<u8, 0x20> hmac;
u64_le magic;
@@ -62,6 +66,6 @@ private:
VirtualFile dec_file;
- Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
+ Core::Crypto::KeyManager& keys;
};
} // namespace FileSys