diff options
| author | 2018-08-11 23:01:38 -0400 | |
|---|---|---|
| committer | 2018-08-11 23:01:42 -0400 | |
| commit | 6b76b774007020befdaa8d7475a9a4edd6d0a0a4 (patch) | |
| tree | 2df8544c20f22914520ea397524d3a91159131a5 /src/core/file_sys | |
| parent | game_list: Split game list scans to multiple functions (diff) | |
| download | yuzu-6b76b774007020befdaa8d7475a9a4edd6d0a0a4.tar.gz yuzu-6b76b774007020befdaa8d7475a9a4edd6d0a0a4.tar.xz yuzu-6b76b774007020befdaa8d7475a9a4edd6d0a0a4.zip | |
registration: Add support for force overwrite of installed
Diffstat (limited to 'src/core/file_sys')
| -rw-r--r-- | src/core/file_sys/registered_cache.cpp | 50 | ||||
| -rw-r--r-- | src/core/file_sys/registered_cache.h | 20 |
2 files changed, 48 insertions, 22 deletions
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 20fec2391..e916d5610 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp | |||
| @@ -60,7 +60,7 @@ static std::string GetCNMTName(TitleType type, u64 title_id) { | |||
| 60 | auto index = static_cast<size_t>(type); | 60 | auto index = static_cast<size_t>(type); |
| 61 | // If the index is after the jump in TitleType, subtract it out. | 61 | // If the index is after the jump in TitleType, subtract it out. |
| 62 | if (index >= static_cast<size_t>(TitleType::Application)) | 62 | if (index >= static_cast<size_t>(TitleType::Application)) |
| 63 | index -= static_cast<size_t>(TitleType::Application); | 63 | index -= 0x7B; |
| 64 | return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id); | 64 | return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id); |
| 65 | } | 65 | } |
| 66 | 66 | ||
| @@ -343,7 +343,8 @@ static std::shared_ptr<NCA> GetNCAFromXCIForID(std::shared_ptr<XCI> xci, const N | |||
| 343 | return iter == xci->GetNCAs().end() ? nullptr : *iter; | 343 | return iter == xci->GetNCAs().end() ? nullptr : *iter; |
| 344 | } | 344 | } |
| 345 | 345 | ||
| 346 | bool RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, const VfsCopyFunction& copy) { | 346 | InstallResult RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists, |
| 347 | const VfsCopyFunction& copy) { | ||
| 347 | const auto& ncas = xci->GetNCAs(); | 348 | const auto& ncas = xci->GetNCAs(); |
| 348 | const auto& meta_iter = std::find_if(ncas.begin(), ncas.end(), [](std::shared_ptr<NCA> nca) { | 349 | const auto& meta_iter = std::find_if(ncas.begin(), ncas.end(), [](std::shared_ptr<NCA> nca) { |
| 349 | return nca->GetType() == NCAContentType::Meta; | 350 | return nca->GetType() == NCAContentType::Meta; |
| @@ -352,14 +353,16 @@ bool RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, const VfsCopyFuncti | |||
| 352 | if (meta_iter == ncas.end()) { | 353 | if (meta_iter == ncas.end()) { |
| 353 | LOG_ERROR(Loader, "The XCI you are attempting to install does not have a metadata NCA and " | 354 | LOG_ERROR(Loader, "The XCI you are attempting to install does not have a metadata NCA and " |
| 354 | "is therefore malformed. Double check your encryption keys."); | 355 | "is therefore malformed. Double check your encryption keys."); |
| 355 | return false; | 356 | return InstallResult::ErrorMetaFailed; |
| 356 | } | 357 | } |
| 357 | 358 | ||
| 358 | // Install Metadata File | 359 | // Install Metadata File |
| 359 | const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); | 360 | const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); |
| 360 | const auto meta_id = HexStringToArray<16>(meta_id_raw); | 361 | const auto meta_id = HexStringToArray<16>(meta_id_raw); |
| 361 | if (!RawInstallNCA(*meta_iter, copy, meta_id)) | 362 | |
| 362 | return false; | 363 | const auto res = RawInstallNCA(*meta_iter, copy, overwrite_if_exists, meta_id); |
| 364 | if (res != InstallResult::Success) | ||
| 365 | return res; | ||
| 363 | 366 | ||
| 364 | // Install all the other NCAs | 367 | // Install all the other NCAs |
| 365 | const auto section0 = (*meta_iter)->GetSubdirectories()[0]; | 368 | const auto section0 = (*meta_iter)->GetSubdirectories()[0]; |
| @@ -367,16 +370,19 @@ bool RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, const VfsCopyFuncti | |||
| 367 | const CNMT cnmt(cnmt_file); | 370 | const CNMT cnmt(cnmt_file); |
| 368 | for (const auto& record : cnmt.GetContentRecords()) { | 371 | for (const auto& record : cnmt.GetContentRecords()) { |
| 369 | const auto nca = GetNCAFromXCIForID(xci, record.nca_id); | 372 | const auto nca = GetNCAFromXCIForID(xci, record.nca_id); |
| 370 | if (nca == nullptr || !RawInstallNCA(nca, copy, record.nca_id)) | 373 | if (nca == nullptr) |
| 371 | return false; | 374 | return InstallResult::ErrorCopyFailed; |
| 375 | const auto res2 = RawInstallNCA(nca, copy, overwrite_if_exists, record.nca_id); | ||
| 376 | if (res2 != InstallResult::Success) | ||
| 377 | return res2; | ||
| 372 | } | 378 | } |
| 373 | 379 | ||
| 374 | Refresh(); | 380 | Refresh(); |
| 375 | return true; | 381 | return InstallResult::Success; |
| 376 | } | 382 | } |
| 377 | 383 | ||
| 378 | bool RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type, | 384 | InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type, |
| 379 | const VfsCopyFunction& copy) { | 385 | bool overwrite_if_exists, const VfsCopyFunction& copy) { |
| 380 | CNMTHeader header{ | 386 | CNMTHeader header{ |
| 381 | nca->GetTitleId(), ///< Title ID | 387 | nca->GetTitleId(), ///< Title ID |
| 382 | 0, ///< Ignore/Default title version | 388 | 0, ///< Ignore/Default title version |
| @@ -393,11 +399,14 @@ bool RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type, | |||
| 393 | mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0); | 399 | mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0); |
| 394 | memcpy(&c_rec.nca_id, &c_rec.hash, 16); | 400 | memcpy(&c_rec.nca_id, &c_rec.hash, 16); |
| 395 | const CNMT new_cnmt(header, opt_header, {c_rec}, {}); | 401 | const CNMT new_cnmt(header, opt_header, {c_rec}, {}); |
| 396 | return RawInstallYuzuMeta(new_cnmt) && RawInstallNCA(nca, copy, c_rec.nca_id); | 402 | if (!RawInstallYuzuMeta(new_cnmt)) |
| 403 | return InstallResult::ErrorMetaFailed; | ||
| 404 | return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); | ||
| 397 | } | 405 | } |
| 398 | 406 | ||
| 399 | bool RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, | 407 | InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, |
| 400 | boost::optional<NcaID> override_id) { | 408 | bool overwrite_if_exists, |
| 409 | boost::optional<NcaID> override_id) { | ||
| 401 | const auto in = nca->GetBaseFile(); | 410 | const auto in = nca->GetBaseFile(); |
| 402 | Core::Crypto::SHA256Hash hash{}; | 411 | Core::Crypto::SHA256Hash hash{}; |
| 403 | 412 | ||
| @@ -416,15 +425,22 @@ bool RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunct | |||
| 416 | 425 | ||
| 417 | std::string path = GetRelativePathFromNcaID(id, false, true); | 426 | std::string path = GetRelativePathFromNcaID(id, false, true); |
| 418 | 427 | ||
| 419 | if (GetFileAtID(id) != nullptr) { | 428 | if (GetFileAtID(id) != nullptr && !overwrite_if_exists) { |
| 420 | LOG_WARNING(Loader, "Attempting to overwrite existing NCA. Skipping..."); | 429 | LOG_WARNING(Loader, "Attempting to overwrite existing NCA. Skipping..."); |
| 421 | return false; | 430 | return InstallResult::ErrorAlreadyExists; |
| 431 | } | ||
| 432 | |||
| 433 | if (GetFileAtID(id) != nullptr) { | ||
| 434 | LOG_WARNING(Loader, "Overwriting existing NCA..."); | ||
| 435 | VirtualDir c_dir; | ||
| 436 | { c_dir = dir->GetFileRelative(path)->GetContainingDirectory(); } | ||
| 437 | c_dir->DeleteFile(FileUtil::GetFilename(path)); | ||
| 422 | } | 438 | } |
| 423 | 439 | ||
| 424 | auto out = dir->CreateFileRelative(path); | 440 | auto out = dir->CreateFileRelative(path); |
| 425 | if (out == nullptr) | 441 | if (out == nullptr) |
| 426 | return false; | 442 | return InstallResult::ErrorCopyFailed; |
| 427 | return copy(in, out); | 443 | return copy(in, out) ? InstallResult::Success : InstallResult::ErrorCopyFailed; |
| 428 | } | 444 | } |
| 429 | 445 | ||
| 430 | bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) { | 446 | bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) { |
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index f2b07eec8..a7c51a59c 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h | |||
| @@ -25,6 +25,13 @@ using NcaID = std::array<u8, 0x10>; | |||
| 25 | using RegisteredCacheParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>; | 25 | using RegisteredCacheParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>; |
| 26 | using VfsCopyFunction = std::function<bool(VirtualFile, VirtualFile)>; | 26 | using VfsCopyFunction = std::function<bool(VirtualFile, VirtualFile)>; |
| 27 | 27 | ||
| 28 | enum class InstallResult { | ||
| 29 | Success, | ||
| 30 | ErrorAlreadyExists, | ||
| 31 | ErrorCopyFailed, | ||
| 32 | ErrorMetaFailed, | ||
| 33 | }; | ||
| 34 | |||
| 28 | struct RegisteredCacheEntry { | 35 | struct RegisteredCacheEntry { |
| 29 | u64 title_id; | 36 | u64 title_id; |
| 30 | ContentRecordType type; | 37 | ContentRecordType type; |
| @@ -77,14 +84,16 @@ public: | |||
| 77 | 84 | ||
| 78 | // Raw copies all the ncas from the xci to the csache. Does some quick checks to make sure there | 85 | // Raw copies all the ncas from the xci to the csache. Does some quick checks to make sure there |
| 79 | // is a meta NCA and all of them are accessible. | 86 | // is a meta NCA and all of them are accessible. |
| 80 | bool InstallEntry(std::shared_ptr<XCI> xci, const VfsCopyFunction& copy = &VfsRawCopy); | 87 | InstallResult InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists = false, |
| 88 | const VfsCopyFunction& copy = &VfsRawCopy); | ||
| 81 | 89 | ||
| 82 | // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this | 90 | // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this |
| 83 | // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a | 91 | // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a |
| 84 | // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there. | 92 | // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there. |
| 85 | // TODO(DarkLordZach): Author real meta-type NCAs and install those. | 93 | // TODO(DarkLordZach): Author real meta-type NCAs and install those. |
| 86 | bool InstallEntry(std::shared_ptr<NCA> nca, TitleType type, | 94 | InstallResult InstallEntry(std::shared_ptr<NCA> nca, TitleType type, |
| 87 | const VfsCopyFunction& copy = &VfsRawCopy); | 95 | bool overwrite_if_exists = false, |
| 96 | const VfsCopyFunction& copy = &VfsRawCopy); | ||
| 88 | 97 | ||
| 89 | private: | 98 | private: |
| 90 | template <typename T> | 99 | template <typename T> |
| @@ -97,8 +106,9 @@ private: | |||
| 97 | boost::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; | 106 | boost::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; |
| 98 | VirtualFile GetFileAtID(NcaID id) const; | 107 | VirtualFile GetFileAtID(NcaID id) const; |
| 99 | VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; | 108 | VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; |
| 100 | bool RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, | 109 | InstallResult RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, |
| 101 | boost::optional<NcaID> override_id = boost::none); | 110 | bool overwrite_if_exists, |
| 111 | boost::optional<NcaID> override_id = boost::none); | ||
| 102 | bool RawInstallYuzuMeta(const CNMT& cnmt); | 112 | bool RawInstallYuzuMeta(const CNMT& cnmt); |
| 103 | 113 | ||
| 104 | VirtualDir dir; | 114 | VirtualDir dir; |