summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/file_sys/registered_cache.cpp98
-rw-r--r--src/core/file_sys/registered_cache.h4
-rw-r--r--src/yuzu/main.cpp4
3 files changed, 94 insertions, 12 deletions
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 27c1b0233..37351c561 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -547,6 +547,56 @@ InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_ex
547 return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy); 547 return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy);
548} 548}
549 549
550bool RegisteredCache::RemoveExistingEntry(u64 title_id) {
551 const auto delete_nca = [this](const NcaID& id) {
552 const auto path = GetRelativePathFromNcaID(id, false, true, false);
553
554 if (dir->GetFileRelative(path) == nullptr) {
555 return false;
556 }
557
558 Core::Crypto::SHA256Hash hash{};
559 mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0);
560 const auto dirname = fmt::format("000000{:02X}", hash[0]);
561
562 const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
563
564 const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexToString(id, false)));
565
566 return res;
567 };
568
569 // If an entry exists in the registered cache, remove it
570 if (HasEntry(title_id, ContentRecordType::Meta)) {
571 LOG_INFO(Loader,
572 "Previously installed entry (v{}) for title_id={:016X} detected! "
573 "Attempting to remove...",
574 GetEntryVersion(title_id).value_or(0), title_id);
575 // Get all the ncas associated with the current CNMT and delete them
576 const auto meta_old_id =
577 GetNcaIDFromMetadata(title_id, ContentRecordType::Meta).value_or(NcaID{});
578 const auto program_id =
579 GetNcaIDFromMetadata(title_id, ContentRecordType::Program).value_or(NcaID{});
580 const auto data_id =
581 GetNcaIDFromMetadata(title_id, ContentRecordType::Data).value_or(NcaID{});
582 const auto control_id =
583 GetNcaIDFromMetadata(title_id, ContentRecordType::Control).value_or(NcaID{});
584 const auto html_id =
585 GetNcaIDFromMetadata(title_id, ContentRecordType::HtmlDocument).value_or(NcaID{});
586 const auto legal_id =
587 GetNcaIDFromMetadata(title_id, ContentRecordType::LegalInformation).value_or(NcaID{});
588
589 delete_nca(meta_old_id);
590 delete_nca(program_id);
591 delete_nca(data_id);
592 delete_nca(control_id);
593 delete_nca(html_id);
594 delete_nca(legal_id);
595 return true;
596 }
597 return false;
598}
599
550InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists, 600InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists,
551 const VfsCopyFunction& copy) { 601 const VfsCopyFunction& copy) {
552 const auto ncas = nsp.GetNCAsCollapsed(); 602 const auto ncas = nsp.GetNCAsCollapsed();
@@ -560,31 +610,57 @@ InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_ex
560 return InstallResult::ErrorMetaFailed; 610 return InstallResult::ErrorMetaFailed;
561 } 611 }
562 612
563 // Install Metadata File
564 const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); 613 const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32);
565 const auto meta_id = Common::HexStringToArray<16>(meta_id_raw); 614 const auto meta_id = Common::HexStringToArray<16>(meta_id_raw);
566 615
567 const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id); 616 if ((*meta_iter)->GetSubdirectories().empty()) {
568 if (res != InstallResult::Success) 617 LOG_ERROR(Loader,
569 return res; 618 "The file you are attempting to install does not contain a section0 within the "
619 "metadata NCA and is therefore malformed. Verify that the file is valid.");
620 return InstallResult::ErrorMetaFailed;
621 }
570 622
571 // Install all the other NCAs
572 const auto section0 = (*meta_iter)->GetSubdirectories()[0]; 623 const auto section0 = (*meta_iter)->GetSubdirectories()[0];
624
625 if (section0->GetFiles().empty()) {
626 LOG_ERROR(Loader,
627 "The file you are attempting to install does not contain a CNMT within the "
628 "metadata NCA and is therefore malformed. Verify that the file is valid.");
629 return InstallResult::ErrorMetaFailed;
630 }
631
573 const auto cnmt_file = section0->GetFiles()[0]; 632 const auto cnmt_file = section0->GetFiles()[0];
574 const CNMT cnmt(cnmt_file); 633 const CNMT cnmt(cnmt_file);
634
635 const auto title_id = cnmt.GetTitleID();
636 const auto result = RemoveExistingEntry(title_id);
637
638 // Install Metadata File
639 const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id);
640 if (res != InstallResult::Success) {
641 return res;
642 }
643
644 // Install all the other NCAs
575 for (const auto& record : cnmt.GetContentRecords()) { 645 for (const auto& record : cnmt.GetContentRecords()) {
576 // Ignore DeltaFragments, they are not useful to us 646 // Ignore DeltaFragments, they are not useful to us
577 if (record.type == ContentRecordType::DeltaFragment) 647 if (record.type == ContentRecordType::DeltaFragment) {
578 continue; 648 continue;
649 }
579 const auto nca = GetNCAFromNSPForID(nsp, record.nca_id); 650 const auto nca = GetNCAFromNSPForID(nsp, record.nca_id);
580 if (nca == nullptr) 651 if (nca == nullptr) {
581 return InstallResult::ErrorCopyFailed; 652 return InstallResult::ErrorCopyFailed;
653 }
582 const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id); 654 const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id);
583 if (res2 != InstallResult::Success) 655 if (res2 != InstallResult::Success) {
584 return res2; 656 return res2;
657 }
585 } 658 }
586 659
587 Refresh(); 660 Refresh();
661 if (result) {
662 return InstallResult::OverwriteExisting;
663 }
588 return InstallResult::Success; 664 return InstallResult::Success;
589} 665}
590 666
@@ -610,8 +686,9 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
610 mbedtls_sha256_ret(data.data(), data.size(), c_rec.hash.data(), 0); 686 mbedtls_sha256_ret(data.data(), data.size(), c_rec.hash.data(), 0);
611 memcpy(&c_rec.nca_id, &c_rec.hash, 16); 687 memcpy(&c_rec.nca_id, &c_rec.hash, 16);
612 const CNMT new_cnmt(header, opt_header, {c_rec}, {}); 688 const CNMT new_cnmt(header, opt_header, {c_rec}, {});
613 if (!RawInstallYuzuMeta(new_cnmt)) 689 if (!RawInstallYuzuMeta(new_cnmt)) {
614 return InstallResult::ErrorMetaFailed; 690 return InstallResult::ErrorMetaFailed;
691 }
615 return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); 692 return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id);
616} 693}
617 694
@@ -649,8 +726,9 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
649 } 726 }
650 727
651 auto out = dir->CreateFileRelative(path); 728 auto out = dir->CreateFileRelative(path);
652 if (out == nullptr) 729 if (out == nullptr) {
653 return InstallResult::ErrorCopyFailed; 730 return InstallResult::ErrorCopyFailed;
731 }
654 return copy(in, out, VFS_RC_LARGE_COPY_BLOCK) ? InstallResult::Success 732 return copy(in, out, VFS_RC_LARGE_COPY_BLOCK) ? InstallResult::Success
655 : InstallResult::ErrorCopyFailed; 733 : InstallResult::ErrorCopyFailed;
656} 734}
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index f339cd17b..29cf0d40c 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -34,6 +34,7 @@ using VfsCopyFunction = std::function<bool(const VirtualFile&, const VirtualFile
34 34
35enum class InstallResult { 35enum class InstallResult {
36 Success, 36 Success,
37 OverwriteExisting,
37 ErrorAlreadyExists, 38 ErrorAlreadyExists,
38 ErrorCopyFailed, 39 ErrorCopyFailed,
39 ErrorMetaFailed, 40 ErrorMetaFailed,
@@ -154,6 +155,9 @@ public:
154 std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {}, 155 std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
155 std::optional<u64> title_id = {}) const override; 156 std::optional<u64> title_id = {}) const override;
156 157
158 // Removes an existing entry based on title id
159 bool RemoveExistingEntry(u64 title_id);
160
157 // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure 161 // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure
158 // there is a meta NCA and all of them are accessible. 162 // there is a meta NCA and all of them are accessible.
159 InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false, 163 InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false,
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index 432379705..d51cb2bcb 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -1755,7 +1755,7 @@ InstallResult GMainWindow::InstallNSPXCI(const QString& filename) {
1755 *nsp, true, qt_raw_copy); 1755 *nsp, true, qt_raw_copy);
1756 if (res == FileSys::InstallResult::Success) { 1756 if (res == FileSys::InstallResult::Success) {
1757 return InstallResult::Success; 1757 return InstallResult::Success;
1758 } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { 1758 } else if (res == FileSys::InstallResult::OverwriteExisting) {
1759 return InstallResult::Overwrite; 1759 return InstallResult::Overwrite;
1760 } else { 1760 } else {
1761 return InstallResult::Failure; 1761 return InstallResult::Failure;
@@ -1842,7 +1842,7 @@ InstallResult GMainWindow::InstallNCA(const QString& filename) {
1842 1842
1843 if (res == FileSys::InstallResult::Success) { 1843 if (res == FileSys::InstallResult::Success) {
1844 return InstallResult::Success; 1844 return InstallResult::Success;
1845 } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { 1845 } else if (res == FileSys::InstallResult::OverwriteExisting) {
1846 return InstallResult::Overwrite; 1846 return InstallResult::Overwrite;
1847 } else { 1847 } else {
1848 return InstallResult::Failure; 1848 return InstallResult::Failure;