diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/file_sys/registered_cache.cpp | 98 | ||||
| -rw-r--r-- | src/core/file_sys/registered_cache.h | 4 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 4 |
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 | ||
| 550 | bool 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 | |||
| 550 | InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists, | 600 | InstallResult 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 | ||
| 35 | enum class InstallResult { | 35 | enum 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; |