aboutsummaryrefslogtreecommitdiff
path: root/src/core/file_sys/patch_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/file_sys/patch_manager.cpp')
-rw-r--r--src/core/file_sys/patch_manager.cpp153
1 files changed, 108 insertions, 45 deletions
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index e9c3bb75c2..627646ee84 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -123,6 +123,39 @@ bool IsVersionedExternalUpdateDisabled(const std::vector<std::string>& disabled,
return std::find(disabled.cbegin(), disabled.cend(), disabled_key) != disabled.cend() ||
std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend();
}
+
+std::string GetUpdateVersionStringFromSlot(const ContentProvider* provider, u64 update_tid) {
+ if (provider == nullptr) {
+ return {};
+ }
+
+ auto control_nca = provider->GetEntry(update_tid, ContentRecordType::Control);
+ if (control_nca == nullptr ||
+ control_nca->GetStatus() != Loader::ResultStatus::Success) {
+ return {};
+ }
+
+ const auto romfs = control_nca->GetRomFS();
+ if (romfs == nullptr) {
+ return {};
+ }
+
+ const auto extracted = ExtractRomFS(romfs);
+ if (extracted == nullptr) {
+ return {};
+ }
+
+ auto nacp_file = extracted->GetFile("control.nacp");
+ if (nacp_file == nullptr) {
+ nacp_file = extracted->GetFile("Control.nacp");
+ }
+ if (nacp_file == nullptr) {
+ return {};
+ }
+
+ NACP nacp{nacp_file};
+ return nacp.GetVersionString();
+}
} // Anonymous namespace
PatchManager::PatchManager(u64 title_id_,
@@ -771,6 +804,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
std::nullopt, std::nullopt, ContentRecordType::Program, update_tid);
for (const auto& [slot, entry] : all_updates) {
+ (void)entry;
if (slot == ContentProviderUnionSlot::External ||
slot == ContentProviderUnionSlot::FrontendManual) {
continue;
@@ -786,7 +820,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
source_suffix = " (NAND)";
break;
case ContentProviderUnionSlot::SDMC:
- source_type = PatchSource::NAND;
+ source_type = PatchSource::SDMC;
source_suffix = " (SDMC)";
break;
default:
@@ -795,19 +829,16 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
std::string version_str;
u32 numeric_ver = 0;
- PatchManager update{update_tid, fs_controller, content_provider};
- const auto metadata = update.GetControlMetadata();
- const auto& nacp = metadata.first;
-
- if (nacp != nullptr) {
- version_str = nacp->GetVersionString();
- }
-
- const auto meta_ver = content_provider.GetEntryVersion(update_tid);
- if (meta_ver.has_value()) {
- numeric_ver = *meta_ver;
- if (version_str.empty() && numeric_ver != 0) {
- version_str = FormatTitleVersion(numeric_ver);
+ const auto* slot_provider = content_union->GetSlotProvider(slot);
+ version_str = GetUpdateVersionStringFromSlot(slot_provider, update_tid);
+
+ if (slot_provider != nullptr) {
+ const auto slot_ver = slot_provider->GetEntryVersion(update_tid);
+ if (slot_ver.has_value()) {
+ numeric_ver = *slot_ver;
+ if (version_str.empty() && numeric_ver != 0) {
+ version_str = FormatTitleVersion(numeric_ver);
+ }
}
}
@@ -956,37 +987,60 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
}
// DLC
- 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](const ContentProviderEntry& entry) {
- const auto base_tid = GetBaseTitleID(entry.title_id);
- const bool matches_base = base_tid == title_id;
-
- if (!matches_base) {
- LOG_DEBUG(Loader, "DLC {:016X} base {:016X} doesn't match title {:016X}",
- entry.title_id, base_tid, title_id);
- return false;
- }
-
- auto nca = content_provider.GetEntry(entry);
- if (!nca) {
- LOG_DEBUG(Loader, "Failed to get NCA for DLC {:016X}", entry.title_id);
- return false;
- }
-
- const auto status = nca->GetStatus();
- if (status != Loader::ResultStatus::Success) {
- LOG_DEBUG(Loader, "DLC {:016X} NCA has status {}",
- entry.title_id, static_cast<int>(status));
- return false;
- }
-
- return true;
- });
+ bool has_external_dlc = false;
+ bool has_nand_dlc = false;
+ bool has_sdmc_dlc = false;
+ bool has_other_dlc = false;
+ const auto dlc_entries_with_origin =
+ content_union->ListEntriesFilterOrigin(std::nullopt, TitleType::AOC, ContentRecordType::Data);
+
+ dlc_match.reserve(dlc_entries_with_origin.size());
+ for (const auto& [slot, entry] : dlc_entries_with_origin) {
+ const auto base_tid = GetBaseTitleID(entry.title_id);
+ const bool matches_base = base_tid == title_id;
+ if (!matches_base) {
+ LOG_DEBUG(Loader, "DLC {:016X} base {:016X} doesn't match title {:016X}",
+ entry.title_id, base_tid, title_id);
+ continue;
+ }
+
+ const auto* slot_provider = content_union->GetSlotProvider(slot);
+ if (slot_provider == nullptr) {
+ continue;
+ }
+
+ auto nca = slot_provider->GetEntry(entry);
+ if (!nca) {
+ LOG_DEBUG(Loader, "Failed to get NCA for DLC {:016X}", entry.title_id);
+ continue;
+ }
+
+ const auto status = nca->GetStatus();
+ if (status != Loader::ResultStatus::Success) {
+ LOG_DEBUG(Loader, "DLC {:016X} NCA has status {}", entry.title_id,
+ static_cast<int>(status));
+ continue;
+ }
+
+ switch (slot) {
+ case ContentProviderUnionSlot::External:
+ case ContentProviderUnionSlot::FrontendManual:
+ has_external_dlc = true;
+ break;
+ case ContentProviderUnionSlot::UserNAND:
+ case ContentProviderUnionSlot::SysNAND:
+ has_nand_dlc = true;
+ break;
+ case ContentProviderUnionSlot::SDMC:
+ has_sdmc_dlc = true;
+ break;
+ default:
+ has_other_dlc = true;
+ break;
+ }
+ dlc_match.push_back(entry);
+ }
if (!dlc_match.empty()) {
// Ensure sorted so DLC IDs show in order.
@@ -1000,13 +1054,22 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
const auto dlc_disabled =
std::find(disabled.begin(), disabled.end(), "DLC") != disabled.end();
+ PatchSource dlc_source = PatchSource::Unknown;
+ if (has_external_dlc && !has_nand_dlc && !has_sdmc_dlc && !has_other_dlc) {
+ dlc_source = PatchSource::External;
+ } else if (has_nand_dlc && !has_external_dlc && !has_sdmc_dlc && !has_other_dlc) {
+ dlc_source = PatchSource::NAND;
+ } else if (has_sdmc_dlc && !has_external_dlc && !has_nand_dlc && !has_other_dlc) {
+ dlc_source = PatchSource::SDMC;
+ }
+
out.push_back({.enabled = !dlc_disabled,
.name = "DLC",
.version = std::move(list),
.type = PatchType::DLC,
.program_id = title_id,
.title_id = dlc_match.back().title_id,
- .source = PatchSource::Unknown});
+ .source = dlc_source});
}
return out;