summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/file_sys/nca_metadata.cpp4
-rw-r--r--src/core/file_sys/nca_metadata.h1
-rw-r--r--src/core/file_sys/registered_cache.cpp28
-rw-r--r--src/core/file_sys/registered_cache.h5
-rw-r--r--src/yuzu/main.cpp104
-rw-r--r--src/yuzu/main.h1
-rw-r--r--src/yuzu/main.ui6
7 files changed, 148 insertions, 1 deletions
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp
index 52c78020c..f4a774675 100644
--- a/src/core/file_sys/nca_metadata.cpp
+++ b/src/core/file_sys/nca_metadata.cpp
@@ -45,6 +45,10 @@ CNMT::CNMT(CNMTHeader header_, OptionalHeader opt_header_,
45 45
46CNMT::~CNMT() = default; 46CNMT::~CNMT() = default;
47 47
48const CNMTHeader& CNMT::GetHeader() const {
49 return header;
50}
51
48u64 CNMT::GetTitleID() const { 52u64 CNMT::GetTitleID() const {
49 return header.title_id; 53 return header.title_id;
50} 54}
diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h
index c59ece010..68e463b5f 100644
--- a/src/core/file_sys/nca_metadata.h
+++ b/src/core/file_sys/nca_metadata.h
@@ -89,6 +89,7 @@ public:
89 std::vector<ContentRecord> content_records_, std::vector<MetaRecord> meta_records_); 89 std::vector<ContentRecord> content_records_, std::vector<MetaRecord> meta_records_);
90 ~CNMT(); 90 ~CNMT();
91 91
92 const CNMTHeader& GetHeader() const;
92 u64 GetTitleID() const; 93 u64 GetTitleID() const;
93 u32 GetTitleVersion() const; 94 u32 GetTitleVersion() const;
94 TitleType GetType() const; 95 TitleType GetType() const;
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index f70adab82..e33b00d89 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -9,6 +9,7 @@
9#include "common/fs/path_util.h" 9#include "common/fs/path_util.h"
10#include "common/hex_util.h" 10#include "common/hex_util.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/scope_exit.h"
12#include "core/crypto/key_manager.h" 13#include "core/crypto/key_manager.h"
13#include "core/file_sys/card_image.h" 14#include "core/file_sys/card_image.h"
14#include "core/file_sys/common_funcs.h" 15#include "core/file_sys/common_funcs.h"
@@ -625,7 +626,7 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
625 nca->GetTitleId() != title_id) { 626 nca->GetTitleId() != title_id) {
626 // Create fake cnmt for patch to multiprogram application 627 // Create fake cnmt for patch to multiprogram application
627 const auto sub_nca_result = 628 const auto sub_nca_result =
628 InstallEntry(*nca, TitleType::Update, overwrite_if_exists, copy); 629 InstallEntry(*nca, cnmt.GetHeader(), record, overwrite_if_exists, copy);
629 if (sub_nca_result != InstallResult::Success) { 630 if (sub_nca_result != InstallResult::Success) {
630 return sub_nca_result; 631 return sub_nca_result;
631 } 632 }
@@ -672,6 +673,31 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
672 return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); 673 return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id);
673} 674}
674 675
676InstallResult RegisteredCache::InstallEntry(const NCA& nca, const CNMTHeader& base_header,
677 const ContentRecord& base_record,
678 bool overwrite_if_exists, const VfsCopyFunction& copy) {
679 const CNMTHeader header{
680 .title_id = nca.GetTitleId(),
681 .title_version = base_header.title_version,
682 .type = base_header.type,
683 .reserved = {},
684 .table_offset = 0x10,
685 .number_content_entries = 1,
686 .number_meta_entries = 0,
687 .attributes = 0,
688 .reserved2 = {},
689 .is_committed = 0,
690 .required_download_system_version = 0,
691 .reserved3 = {},
692 };
693 const OptionalHeader opt_header{0, 0};
694 const CNMT new_cnmt(header, opt_header, {base_record}, {});
695 if (!RawInstallYuzuMeta(new_cnmt)) {
696 return InstallResult::ErrorMetaFailed;
697 }
698 return RawInstallNCA(nca, copy, overwrite_if_exists, base_record.nca_id);
699}
700
675bool RegisteredCache::RemoveExistingEntry(u64 title_id) const { 701bool RegisteredCache::RemoveExistingEntry(u64 title_id) const {
676 bool removed_data = false; 702 bool removed_data = false;
677 703
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index bd7f53eaf..64815a845 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -24,6 +24,7 @@ enum class NCAContentType : u8;
24enum class TitleType : u8; 24enum class TitleType : u8;
25 25
26struct ContentRecord; 26struct ContentRecord;
27struct CNMTHeader;
27struct MetaRecord; 28struct MetaRecord;
28class RegisteredCache; 29class RegisteredCache;
29 30
@@ -169,6 +170,10 @@ public:
169 InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false, 170 InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false,
170 const VfsCopyFunction& copy = &VfsRawCopy); 171 const VfsCopyFunction& copy = &VfsRawCopy);
171 172
173 InstallResult InstallEntry(const NCA& nca, const CNMTHeader& base_header,
174 const ContentRecord& base_record, bool overwrite_if_exists = false,
175 const VfsCopyFunction& copy = &VfsRawCopy);
176
172 // Removes an existing entry based on title id 177 // Removes an existing entry based on title id
173 bool RemoveExistingEntry(u64 title_id) const; 178 bool RemoveExistingEntry(u64 title_id) const;
174 179
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 9cea60c32..fc2055a7b 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -8,6 +8,7 @@
8#include <iostream> 8#include <iostream>
9#include <memory> 9#include <memory>
10#include <thread> 10#include <thread>
11#include "core/loader/nca.h"
11#ifdef __APPLE__ 12#ifdef __APPLE__
12#include <unistd.h> // for chdir 13#include <unistd.h> // for chdir
13#endif 14#endif
@@ -1554,6 +1555,7 @@ void GMainWindow::ConnectMenuEvents() {
1554 1555
1555 // Help 1556 // Help
1556 connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder); 1557 connect_menu(ui->action_Open_yuzu_Folder, &GMainWindow::OnOpenYuzuFolder);
1558 connect_menu(ui->action_Verify_installed_contents, &GMainWindow::OnVerifyInstalledContents);
1557 connect_menu(ui->action_About, &GMainWindow::OnAbout); 1559 connect_menu(ui->action_About, &GMainWindow::OnAbout);
1558} 1560}
1559 1561
@@ -4000,6 +4002,108 @@ void GMainWindow::OnOpenYuzuFolder() {
4000 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::YuzuDir)))); 4002 QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::YuzuDir))));
4001} 4003}
4002 4004
4005void GMainWindow::OnVerifyInstalledContents() {
4006 // Declare sizes.
4007 size_t total_size = 0;
4008 size_t processed_size = 0;
4009
4010 // Initialize a progress dialog.
4011 QProgressDialog progress(tr("Verifying integrity..."), tr("Cancel"), 0, 100, this);
4012 progress.setWindowModality(Qt::WindowModal);
4013 progress.setMinimumDuration(100);
4014 progress.setAutoClose(false);
4015 progress.setAutoReset(false);
4016
4017 // Declare a list of file names which failed to verify.
4018 std::vector<std::string> failed;
4019
4020 // Declare progress callback.
4021 auto QtProgressCallback = [&](size_t nca_processed, size_t nca_total) {
4022 if (progress.wasCanceled()) {
4023 return false;
4024 }
4025 progress.setValue(static_cast<int>(((processed_size + nca_processed) * 100) / total_size));
4026 return true;
4027 };
4028
4029 // Get content registries.
4030 auto bis_contents = system->GetFileSystemController().GetSystemNANDContents();
4031 auto user_contents = system->GetFileSystemController().GetUserNANDContents();
4032
4033 std::vector<FileSys::RegisteredCache*> content_providers;
4034 if (bis_contents) {
4035 content_providers.push_back(bis_contents);
4036 }
4037 if (user_contents) {
4038 content_providers.push_back(user_contents);
4039 }
4040
4041 // Get associated NCA files.
4042 std::vector<FileSys::VirtualFile> nca_files;
4043
4044 // Get all installed IDs.
4045 for (auto nca_provider : content_providers) {
4046 const auto entries = nca_provider->ListEntriesFilter();
4047
4048 for (const auto& entry : entries) {
4049 auto nca_file = nca_provider->GetEntryRaw(entry.title_id, entry.type);
4050 if (!nca_file) {
4051 continue;
4052 }
4053
4054 total_size += nca_file->GetSize();
4055 nca_files.push_back(std::move(nca_file));
4056 }
4057 }
4058
4059 // Using the NCA loader, determine if all NCAs are valid.
4060 for (auto& nca_file : nca_files) {
4061 Loader::AppLoader_NCA nca_loader(nca_file);
4062
4063 auto status = nca_loader.VerifyIntegrity(QtProgressCallback);
4064 if (progress.wasCanceled()) {
4065 break;
4066 }
4067 if (status != Loader::ResultStatus::Success) {
4068 FileSys::NCA nca(nca_file);
4069 const auto title_id = nca.GetTitleId();
4070 std::string title_name = "unknown";
4071
4072 const auto control = provider->GetEntry(FileSys::GetBaseTitleID(title_id),
4073 FileSys::ContentRecordType::Control);
4074 if (control && control->GetStatus() == Loader::ResultStatus::Success) {
4075 const FileSys::PatchManager pm{title_id, system->GetFileSystemController(),
4076 *provider};
4077 const auto [nacp, logo] = pm.ParseControlNCA(*control);
4078 if (nacp) {
4079 title_name = nacp->GetApplicationName();
4080 }
4081 }
4082
4083 if (title_id > 0) {
4084 failed.push_back(
4085 fmt::format("{} ({:016X}) ({})", nca_file->GetName(), title_id, title_name));
4086 } else {
4087 failed.push_back(fmt::format("{} (unknown)", nca_file->GetName()));
4088 }
4089 }
4090
4091 processed_size += nca_file->GetSize();
4092 }
4093
4094 progress.close();
4095
4096 if (failed.size() > 0) {
4097 auto failed_names = QString::fromStdString(fmt::format("{}", fmt::join(failed, "\n")));
4098 QMessageBox::critical(
4099 this, tr("Integrity verification failed!"),
4100 tr("Verification failed for the following files:\n\n%1").arg(failed_names));
4101 } else {
4102 QMessageBox::information(this, tr("Integrity verification succeeded!"),
4103 tr("The operation completed successfully."));
4104 }
4105}
4106
4003void GMainWindow::OnAbout() { 4107void GMainWindow::OnAbout() {
4004 AboutDialog aboutDialog(this); 4108 AboutDialog aboutDialog(this);
4005 aboutDialog.exec(); 4109 aboutDialog.exec();
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 1e4f6e477..7b4820ecd 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -343,6 +343,7 @@ private slots:
343 void OnConfigurePerGame(); 343 void OnConfigurePerGame();
344 void OnLoadAmiibo(); 344 void OnLoadAmiibo();
345 void OnOpenYuzuFolder(); 345 void OnOpenYuzuFolder();
346 void OnVerifyInstalledContents();
346 void OnAbout(); 347 void OnAbout();
347 void OnToggleFilterBar(); 348 void OnToggleFilterBar();
348 void OnToggleStatusBar(); 349 void OnToggleStatusBar();
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 013ba0ceb..e54d7d75d 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -148,6 +148,7 @@
148 <addaction name="action_Configure_Tas"/> 148 <addaction name="action_Configure_Tas"/>
149 </widget> 149 </widget>
150 <addaction name="action_Rederive"/> 150 <addaction name="action_Rederive"/>
151 <addaction name="action_Verify_installed_contents"/>
151 <addaction name="separator"/> 152 <addaction name="separator"/>
152 <addaction name="action_Capture_Screenshot"/> 153 <addaction name="action_Capture_Screenshot"/>
153 <addaction name="menuTAS"/> 154 <addaction name="menuTAS"/>
@@ -214,6 +215,11 @@
214 <string>&amp;Reinitialize keys...</string> 215 <string>&amp;Reinitialize keys...</string>
215 </property> 216 </property>
216 </action> 217 </action>
218 <action name="action_Verify_installed_contents">
219 <property name="text">
220 <string>Verify installed contents</string>
221 </property>
222 </action>
217 <action name="action_About"> 223 <action name="action_About">
218 <property name="text"> 224 <property name="text">
219 <string>&amp;About yuzu</string> 225 <string>&amp;About yuzu</string>