mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu.git
				synced 2025-05-12 00:45:25 +00:00 
			
		
		
		
	registration: Add support for force overwrite of installed
This commit is contained in:
		
							parent
							
								
									fdf27bf390
								
							
						
					
					
						commit
						6b76b77400
					
				| @ -60,7 +60,7 @@ static std::string GetCNMTName(TitleType type, u64 title_id) { | |||||||
|     auto index = static_cast<size_t>(type); |     auto index = static_cast<size_t>(type); | ||||||
|     // If the index is after the jump in TitleType, subtract it out.
 |     // If the index is after the jump in TitleType, subtract it out.
 | ||||||
|     if (index >= static_cast<size_t>(TitleType::Application)) |     if (index >= static_cast<size_t>(TitleType::Application)) | ||||||
|         index -= static_cast<size_t>(TitleType::Application); |         index -= 0x7B; | ||||||
|     return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id); |     return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -343,7 +343,8 @@ static std::shared_ptr<NCA> GetNCAFromXCIForID(std::shared_ptr<XCI> xci, const N | |||||||
|     return iter == xci->GetNCAs().end() ? nullptr : *iter; |     return iter == xci->GetNCAs().end() ? nullptr : *iter; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, const VfsCopyFunction& copy) { | InstallResult RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists, | ||||||
|  |                                             const VfsCopyFunction& copy) { | ||||||
|     const auto& ncas = xci->GetNCAs(); |     const auto& ncas = xci->GetNCAs(); | ||||||
|     const auto& meta_iter = std::find_if(ncas.begin(), ncas.end(), [](std::shared_ptr<NCA> nca) { |     const auto& meta_iter = std::find_if(ncas.begin(), ncas.end(), [](std::shared_ptr<NCA> nca) { | ||||||
|         return nca->GetType() == NCAContentType::Meta; |         return nca->GetType() == NCAContentType::Meta; | ||||||
| @ -352,14 +353,16 @@ bool RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, const VfsCopyFuncti | |||||||
|     if (meta_iter == ncas.end()) { |     if (meta_iter == ncas.end()) { | ||||||
|         LOG_ERROR(Loader, "The XCI you are attempting to install does not have a metadata NCA and " |         LOG_ERROR(Loader, "The XCI you are attempting to install does not have a metadata NCA and " | ||||||
|                           "is therefore malformed. Double check your encryption keys."); |                           "is therefore malformed. Double check your encryption keys."); | ||||||
|         return false; |         return InstallResult::ErrorMetaFailed; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Install Metadata File
 |     // Install Metadata File
 | ||||||
|     const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); |     const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); | ||||||
|     const auto meta_id = HexStringToArray<16>(meta_id_raw); |     const auto meta_id = HexStringToArray<16>(meta_id_raw); | ||||||
|     if (!RawInstallNCA(*meta_iter, copy, meta_id)) | 
 | ||||||
|         return false; |     const auto res = RawInstallNCA(*meta_iter, copy, overwrite_if_exists, meta_id); | ||||||
|  |     if (res != InstallResult::Success) | ||||||
|  |         return res; | ||||||
| 
 | 
 | ||||||
|     // Install all the other NCAs
 |     // Install all the other NCAs
 | ||||||
|     const auto section0 = (*meta_iter)->GetSubdirectories()[0]; |     const auto section0 = (*meta_iter)->GetSubdirectories()[0]; | ||||||
| @ -367,16 +370,19 @@ bool RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, const VfsCopyFuncti | |||||||
|     const CNMT cnmt(cnmt_file); |     const CNMT cnmt(cnmt_file); | ||||||
|     for (const auto& record : cnmt.GetContentRecords()) { |     for (const auto& record : cnmt.GetContentRecords()) { | ||||||
|         const auto nca = GetNCAFromXCIForID(xci, record.nca_id); |         const auto nca = GetNCAFromXCIForID(xci, record.nca_id); | ||||||
|         if (nca == nullptr || !RawInstallNCA(nca, copy, record.nca_id)) |         if (nca == nullptr) | ||||||
|             return false; |             return InstallResult::ErrorCopyFailed; | ||||||
|  |         const auto res2 = RawInstallNCA(nca, copy, overwrite_if_exists, record.nca_id); | ||||||
|  |         if (res2 != InstallResult::Success) | ||||||
|  |             return res2; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     Refresh(); |     Refresh(); | ||||||
|     return true; |     return InstallResult::Success; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type, | InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type, | ||||||
|                                    const VfsCopyFunction& copy) { |                                             bool overwrite_if_exists, const VfsCopyFunction& copy) { | ||||||
|     CNMTHeader header{ |     CNMTHeader header{ | ||||||
|         nca->GetTitleId(), ///< Title ID
 |         nca->GetTitleId(), ///< Title ID
 | ||||||
|         0,                 ///< Ignore/Default title version
 |         0,                 ///< Ignore/Default title version
 | ||||||
| @ -393,10 +399,13 @@ bool RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type, | |||||||
|     mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0); |     mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0); | ||||||
|     memcpy(&c_rec.nca_id, &c_rec.hash, 16); |     memcpy(&c_rec.nca_id, &c_rec.hash, 16); | ||||||
|     const CNMT new_cnmt(header, opt_header, {c_rec}, {}); |     const CNMT new_cnmt(header, opt_header, {c_rec}, {}); | ||||||
|     return RawInstallYuzuMeta(new_cnmt) && RawInstallNCA(nca, copy, c_rec.nca_id); |     if (!RawInstallYuzuMeta(new_cnmt)) | ||||||
|  |         return InstallResult::ErrorMetaFailed; | ||||||
|  |     return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, | InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, | ||||||
|  |                                              bool overwrite_if_exists, | ||||||
|                                              boost::optional<NcaID> override_id) { |                                              boost::optional<NcaID> override_id) { | ||||||
|     const auto in = nca->GetBaseFile(); |     const auto in = nca->GetBaseFile(); | ||||||
|     Core::Crypto::SHA256Hash hash{}; |     Core::Crypto::SHA256Hash hash{}; | ||||||
| @ -416,15 +425,22 @@ bool RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunct | |||||||
| 
 | 
 | ||||||
|     std::string path = GetRelativePathFromNcaID(id, false, true); |     std::string path = GetRelativePathFromNcaID(id, false, true); | ||||||
| 
 | 
 | ||||||
|     if (GetFileAtID(id) != nullptr) { |     if (GetFileAtID(id) != nullptr && !overwrite_if_exists) { | ||||||
|         LOG_WARNING(Loader, "Attempting to overwrite existing NCA. Skipping..."); |         LOG_WARNING(Loader, "Attempting to overwrite existing NCA. Skipping..."); | ||||||
|         return false; |         return InstallResult::ErrorAlreadyExists; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if (GetFileAtID(id) != nullptr) { | ||||||
|  |         LOG_WARNING(Loader, "Overwriting existing NCA..."); | ||||||
|  |         VirtualDir c_dir; | ||||||
|  |         { c_dir = dir->GetFileRelative(path)->GetContainingDirectory(); } | ||||||
|  |         c_dir->DeleteFile(FileUtil::GetFilename(path)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto out = dir->CreateFileRelative(path); |     auto out = dir->CreateFileRelative(path); | ||||||
|     if (out == nullptr) |     if (out == nullptr) | ||||||
|         return false; |         return InstallResult::ErrorCopyFailed; | ||||||
|     return copy(in, out); |     return copy(in, out) ? InstallResult::Success : InstallResult::ErrorCopyFailed; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) { | bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) { | ||||||
|  | |||||||
| @ -25,6 +25,13 @@ using NcaID = std::array<u8, 0x10>; | |||||||
| using RegisteredCacheParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>; | using RegisteredCacheParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>; | ||||||
| using VfsCopyFunction = std::function<bool(VirtualFile, VirtualFile)>; | using VfsCopyFunction = std::function<bool(VirtualFile, VirtualFile)>; | ||||||
| 
 | 
 | ||||||
|  | enum class InstallResult { | ||||||
|  |     Success, | ||||||
|  |     ErrorAlreadyExists, | ||||||
|  |     ErrorCopyFailed, | ||||||
|  |     ErrorMetaFailed, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| struct RegisteredCacheEntry { | struct RegisteredCacheEntry { | ||||||
|     u64 title_id; |     u64 title_id; | ||||||
|     ContentRecordType type; |     ContentRecordType type; | ||||||
| @ -77,13 +84,15 @@ public: | |||||||
| 
 | 
 | ||||||
|     // Raw copies all the ncas from the xci to the csache. Does some quick checks to make sure there
 |     // Raw copies all the ncas from the xci to the csache. Does some quick checks to make sure there
 | ||||||
|     // is a meta NCA and all of them are accessible.
 |     // is a meta NCA and all of them are accessible.
 | ||||||
|     bool InstallEntry(std::shared_ptr<XCI> xci, const VfsCopyFunction& copy = &VfsRawCopy); |     InstallResult InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists = false, | ||||||
|  |                                const VfsCopyFunction& copy = &VfsRawCopy); | ||||||
| 
 | 
 | ||||||
|     // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this
 |     // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this
 | ||||||
|     // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a
 |     // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a
 | ||||||
|     // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there.
 |     // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there.
 | ||||||
|     // TODO(DarkLordZach): Author real meta-type NCAs and install those.
 |     // TODO(DarkLordZach): Author real meta-type NCAs and install those.
 | ||||||
|     bool InstallEntry(std::shared_ptr<NCA> nca, TitleType type, |     InstallResult InstallEntry(std::shared_ptr<NCA> nca, TitleType type, | ||||||
|  |                                bool overwrite_if_exists = false, | ||||||
|                                const VfsCopyFunction& copy = &VfsRawCopy); |                                const VfsCopyFunction& copy = &VfsRawCopy); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
| @ -97,7 +106,8 @@ private: | |||||||
|     boost::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; |     boost::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; | ||||||
|     VirtualFile GetFileAtID(NcaID id) const; |     VirtualFile GetFileAtID(NcaID id) const; | ||||||
|     VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; |     VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; | ||||||
|     bool RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, |     InstallResult RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, | ||||||
|  |                                 bool overwrite_if_exists, | ||||||
|                                 boost::optional<NcaID> override_id = boost::none); |                                 boost::optional<NcaID> override_id = boost::none); | ||||||
|     bool RawInstallYuzuMeta(const CNMT& cnmt); |     bool RawInstallYuzuMeta(const CNMT& cnmt); | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -405,7 +405,6 @@ void GameList::RefreshGameDirectory() { | |||||||
| 
 | 
 | ||||||
| static void GetMetadataFromControlNCA(const std::shared_ptr<FileSys::NCA>& nca, | static void GetMetadataFromControlNCA(const std::shared_ptr<FileSys::NCA>& nca, | ||||||
|                                       std::vector<u8>& icon, std::string& name) { |                                       std::vector<u8>& icon, std::string& name) { | ||||||
| 
 |  | ||||||
|     const auto control_dir = FileSys::ExtractRomFS(nca->GetRomFS()); |     const auto control_dir = FileSys::ExtractRomFS(nca->GetRomFS()); | ||||||
|     if (control_dir == nullptr) |     if (control_dir == nullptr) | ||||||
|         return; |         return; | ||||||
|  | |||||||
| @ -650,37 +650,59 @@ void GMainWindow::OnMenuInstallToNAND() { | |||||||
|         return true; |         return true; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     const auto success = [this]() { | ||||||
|  |         QMessageBox::information(this, tr("Successfully Installed"), | ||||||
|  |                                  tr("The file was successfully installed.")); | ||||||
|  |         game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const auto failed = [this]() { | ||||||
|  |         QMessageBox::warning( | ||||||
|  |             this, tr("Failed to Install"), | ||||||
|  |             tr("There was an error while attempting to install the provided file. It " | ||||||
|  |                "could have an incorrect format or be missing metadata. Please " | ||||||
|  |                "double-check your file and try again.")); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     const auto overwrite = [this]() { | ||||||
|  |         return QMessageBox::question(this, "Failed to Install", | ||||||
|  |                                      "The file you are attempting to install already exists " | ||||||
|  |                                      "in the cache. Would you like to overwrite it?") == | ||||||
|  |                QMessageBox::Yes; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|     if (!filename.isEmpty()) { |     if (!filename.isEmpty()) { | ||||||
|         if (filename.endsWith("xci", Qt::CaseInsensitive)) { |         if (filename.endsWith("xci", Qt::CaseInsensitive)) { | ||||||
|             const auto xci = std::make_shared<FileSys::XCI>( |             const auto xci = std::make_shared<FileSys::XCI>( | ||||||
|                 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); |                 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); | ||||||
|             if (xci->GetStatus() != Loader::ResultStatus::Success) { |             if (xci->GetStatus() != Loader::ResultStatus::Success) { | ||||||
|                 QMessageBox::warning( |                 failed(); | ||||||
|                     this, tr("Failed to Install XCI"), |  | ||||||
|                     tr("The XCI file you provided is invalid. Please double-check your encryption " |  | ||||||
|                        "keys and the file and try again.")); |  | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|             if (Service::FileSystem::GetUserNANDContents()->InstallEntry(xci, qt_raw_copy)) { |             const auto res = | ||||||
|                 QMessageBox::information(this, tr("Successfully Installed XCI"), |                 Service::FileSystem::GetUserNANDContents()->InstallEntry(xci, false, qt_raw_copy); | ||||||
|                                          tr("The file was successfully installed.")); |             if (res == FileSys::InstallResult::Success) { | ||||||
|                 game_list->PopulateAsync(UISettings::values.gamedir, |                 success(); | ||||||
|                                          UISettings::values.gamedir_deepscan); |  | ||||||
|             } else { |             } else { | ||||||
|                 QMessageBox::warning( |                 if (res == FileSys::InstallResult::ErrorAlreadyExists) { | ||||||
|                     this, tr("Failed to Install XCI"), |                     if (overwrite()) { | ||||||
|                     tr("There was an error while attempting to install the provided XCI file. It " |                         const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( | ||||||
|                        "could have an incorrect format or be missing a metadata entry. Please " |                             xci, true, qt_raw_copy); | ||||||
|                        "double-check your file and try again.")); |                         if (res2 == FileSys::InstallResult::Success) { | ||||||
|  |                             success(); | ||||||
|  |                         } else { | ||||||
|  |                             failed(); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     failed(); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } else { |         } else { | ||||||
|             const auto nca = std::make_shared<FileSys::NCA>( |             const auto nca = std::make_shared<FileSys::NCA>( | ||||||
|                 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); |                 vfs->OpenFile(filename.toStdString(), FileSys::Mode::Read)); | ||||||
|             if (nca->GetStatus() != Loader::ResultStatus::Success) { |             if (nca->GetStatus() != Loader::ResultStatus::Success) { | ||||||
|                 QMessageBox::warning( |                 failed(); | ||||||
|                     this, tr("Failed to Install NCA"), |  | ||||||
|                     tr("The NCA file you provided is invalid. Please double-check your encryption " |  | ||||||
|                        "keys and the file and try again.")); |  | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| @ -702,7 +724,7 @@ void GMainWindow::OnMenuInstallToNAND() { | |||||||
| 
 | 
 | ||||||
|             auto index = tt_options.indexOf(item); |             auto index = tt_options.indexOf(item); | ||||||
|             if (!ok || index == -1) { |             if (!ok || index == -1) { | ||||||
|                 QMessageBox::warning(this, tr("Failed to Install NCA"), |                 QMessageBox::warning(this, tr("Failed to Install"), | ||||||
|                                      tr("The title type you selected for the NCA is invalid.")); |                                      tr("The title type you selected for the NCA is invalid.")); | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
| @ -710,18 +732,24 @@ void GMainWindow::OnMenuInstallToNAND() { | |||||||
|             if (index >= 5) |             if (index >= 5) | ||||||
|                 index += 0x7B; |                 index += 0x7B; | ||||||
| 
 | 
 | ||||||
|             if (Service::FileSystem::GetUserNANDContents()->InstallEntry( |             const auto res = Service::FileSystem::GetUserNANDContents()->InstallEntry( | ||||||
|                     nca, static_cast<FileSys::TitleType>(index), qt_raw_copy)) { |                 nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); | ||||||
|                 QMessageBox::information(this, tr("Successfully Installed NCA"), |             if (res == FileSys::InstallResult::Success) { | ||||||
|                                          tr("The file was successfully installed.")); |                 success(); | ||||||
|                 game_list->PopulateAsync(UISettings::values.gamedir, |  | ||||||
|                                          UISettings::values.gamedir_deepscan); |  | ||||||
|             } else { |             } else { | ||||||
|                 QMessageBox::warning(this, tr("Failed to Install NCA"), |                 if (res == FileSys::InstallResult::ErrorAlreadyExists) { | ||||||
|                                      tr("There was an error while attempting to install the " |                     if (overwrite()) { | ||||||
|                                         "provided NCA file. An error might have occured creating " |                         const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( | ||||||
|                                         "the metadata file or parsing the NCA. Please " |                             nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy); | ||||||
|                                         "double-check your file and try again.")); |                         if (res2 == FileSys::InstallResult::Success) { | ||||||
|  |                             success(); | ||||||
|  |                         } else { | ||||||
|  |                             failed(); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     failed(); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Zach Hilman
						Zach Hilman