registered_cache.h 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <array>
  6. #include <functional>
  7. #include <map>
  8. #include <memory>
  9. #include <string>
  10. #include <vector>
  11. #include <boost/container/flat_map.hpp>
  12. #include "common/common_types.h"
  13. #include "core/crypto/key_manager.h"
  14. #include "core/file_sys/vfs.h"
  15. namespace FileSys {
  16. class CNMT;
  17. class NCA;
  18. class NSP;
  19. class XCI;
  20. enum class ContentRecordType : u8;
  21. enum class TitleType : u8;
  22. struct ContentRecord;
  23. using NcaID = std::array<u8, 0x10>;
  24. using RegisteredCacheParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>;
  25. using VfsCopyFunction = std::function<bool(const VirtualFile&, const VirtualFile&, size_t)>;
  26. enum class InstallResult {
  27. Success,
  28. ErrorAlreadyExists,
  29. ErrorCopyFailed,
  30. ErrorMetaFailed,
  31. };
  32. struct RegisteredCacheEntry {
  33. u64 title_id;
  34. ContentRecordType type;
  35. std::string DebugInfo() const;
  36. };
  37. constexpr u64 GetUpdateTitleID(u64 base_title_id) {
  38. return base_title_id | 0x800;
  39. }
  40. // boost flat_map requires operator< for O(log(n)) lookups.
  41. bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
  42. // std unique requires operator== to identify duplicates.
  43. bool operator==(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
  44. bool operator!=(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs);
  45. /*
  46. * A class that catalogues NCAs in the registered directory structure.
  47. * Nintendo's registered format follows this structure:
  48. *
  49. * Root
  50. * | 000000XX <- XX is the ____ two digits of the NcaID
  51. * | <hash>.nca <- hash is the NcaID (first half of SHA256 over entire file) (folder)
  52. * | 00
  53. * | 01 <- Actual content split along 4GB boundaries. (optional)
  54. *
  55. * (This impl also supports substituting the nca dir for an nca file, as that's more convenient
  56. * when 4GB splitting can be ignored.)
  57. */
  58. class RegisteredCache {
  59. friend class RegisteredCacheUnion;
  60. public:
  61. // Parsing function defines the conversion from raw file to NCA. If there are other steps
  62. // besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom
  63. // parsing function.
  64. explicit RegisteredCache(VirtualDir dir,
  65. RegisteredCacheParsingFunction parsing_function =
  66. [](const VirtualFile& file, const NcaID& id) { return file; });
  67. ~RegisteredCache();
  68. void Refresh();
  69. bool HasEntry(u64 title_id, ContentRecordType type) const;
  70. bool HasEntry(RegisteredCacheEntry entry) const;
  71. std::optional<u32> GetEntryVersion(u64 title_id) const;
  72. VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const;
  73. VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const;
  74. VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const;
  75. VirtualFile GetEntryRaw(RegisteredCacheEntry entry) const;
  76. std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const;
  77. std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
  78. std::vector<RegisteredCacheEntry> ListEntries() const;
  79. // If a parameter is not std::nullopt, it will be filtered for from all entries.
  80. std::vector<RegisteredCacheEntry> ListEntriesFilter(
  81. std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
  82. std::optional<u64> title_id = {}) const;
  83. // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure
  84. // there is a meta NCA and all of them are accessible.
  85. InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false,
  86. const VfsCopyFunction& copy = &VfsRawCopy);
  87. InstallResult InstallEntry(const NSP& nsp, bool overwrite_if_exists = false,
  88. const VfsCopyFunction& copy = &VfsRawCopy);
  89. // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this
  90. // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a
  91. // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there.
  92. // TODO(DarkLordZach): Author real meta-type NCAs and install those.
  93. InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false,
  94. const VfsCopyFunction& copy = &VfsRawCopy);
  95. private:
  96. template <typename T>
  97. void IterateAllMetadata(std::vector<T>& out,
  98. std::function<T(const CNMT&, const ContentRecord&)> proc,
  99. std::function<bool(const CNMT&, const ContentRecord&)> filter) const;
  100. std::vector<NcaID> AccumulateFiles() const;
  101. void ProcessFiles(const std::vector<NcaID>& ids);
  102. void AccumulateYuzuMeta();
  103. std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const;
  104. VirtualFile GetFileAtID(NcaID id) const;
  105. VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const;
  106. InstallResult RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
  107. bool overwrite_if_exists, std::optional<NcaID> override_id = {});
  108. bool RawInstallYuzuMeta(const CNMT& cnmt);
  109. VirtualDir dir;
  110. RegisteredCacheParsingFunction parser;
  111. Core::Crypto::KeyManager keys;
  112. // maps tid -> NcaID of meta
  113. boost::container::flat_map<u64, NcaID> meta_id;
  114. // maps tid -> meta
  115. boost::container::flat_map<u64, CNMT> meta;
  116. // maps tid -> meta for CNMT in yuzu_meta
  117. boost::container::flat_map<u64, CNMT> yuzu_meta;
  118. };
  119. // Combines multiple RegisteredCaches (i.e. SysNAND, UserNAND, SDMC) into one interface.
  120. class RegisteredCacheUnion {
  121. public:
  122. explicit RegisteredCacheUnion(std::vector<RegisteredCache*> caches);
  123. void Refresh();
  124. bool HasEntry(u64 title_id, ContentRecordType type) const;
  125. bool HasEntry(RegisteredCacheEntry entry) const;
  126. std::optional<u32> GetEntryVersion(u64 title_id) const;
  127. VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const;
  128. VirtualFile GetEntryUnparsed(RegisteredCacheEntry entry) const;
  129. VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const;
  130. VirtualFile GetEntryRaw(RegisteredCacheEntry entry) const;
  131. std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const;
  132. std::unique_ptr<NCA> GetEntry(RegisteredCacheEntry entry) const;
  133. std::vector<RegisteredCacheEntry> ListEntries() const;
  134. // If a parameter is not std::nullopt, it will be filtered for from all entries.
  135. std::vector<RegisteredCacheEntry> ListEntriesFilter(
  136. std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
  137. std::optional<u64> title_id = {}) const;
  138. private:
  139. std::vector<RegisteredCache*> caches;
  140. };
  141. } // namespace FileSys