| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
- // SPDX-License-Identifier: GPL-2.0-or-later
- #pragma once
- #include <array>
- #include <functional>
- #include <memory>
- #include <string>
- #include <vector>
- #include <boost/container/flat_map.hpp>
- #include "common/common_types.h"
- #include "core/crypto/key_manager.h"
- #include "core/file_sys/vfs.h"
- namespace FileSys {
- class CNMT;
- class NCA;
- class NSP;
- class XCI;
- enum class ContentRecordType : u8;
- enum class NCAContentType : u8;
- enum class TitleType : u8;
- struct ContentRecord;
- struct MetaRecord;
- class RegisteredCache;
- using NcaID = std::array<u8, 0x10>;
- using ContentProviderParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>;
- using VfsCopyFunction = std::function<bool(const VirtualFile&, const VirtualFile&, size_t)>;
- enum class InstallResult {
- Success,
- OverwriteExisting,
- ErrorAlreadyExists,
- ErrorCopyFailed,
- ErrorMetaFailed,
- ErrorBaseInstall,
- };
- struct ContentProviderEntry {
- u64 title_id;
- ContentRecordType type;
- std::string DebugInfo() const;
- };
- constexpr u64 GetUpdateTitleID(u64 base_title_id) {
- return base_title_id | 0x800;
- }
- ContentRecordType GetCRTypeFromNCAType(NCAContentType type);
- // boost flat_map requires operator< for O(log(n)) lookups.
- bool operator<(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs);
- // std unique requires operator== to identify duplicates.
- bool operator==(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs);
- bool operator!=(const ContentProviderEntry& lhs, const ContentProviderEntry& rhs);
- class ContentProvider {
- public:
- virtual ~ContentProvider();
- virtual void Refresh() = 0;
- virtual bool HasEntry(u64 title_id, ContentRecordType type) const = 0;
- bool HasEntry(ContentProviderEntry entry) const;
- virtual std::optional<u32> GetEntryVersion(u64 title_id) const = 0;
- virtual VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const = 0;
- VirtualFile GetEntryUnparsed(ContentProviderEntry entry) const;
- virtual VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const = 0;
- VirtualFile GetEntryRaw(ContentProviderEntry entry) const;
- virtual std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const = 0;
- std::unique_ptr<NCA> GetEntry(ContentProviderEntry entry) const;
- virtual std::vector<ContentProviderEntry> ListEntries() const;
- // If a parameter is not std::nullopt, it will be filtered for from all entries.
- virtual std::vector<ContentProviderEntry> ListEntriesFilter(
- std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
- std::optional<u64> title_id = {}) const = 0;
- protected:
- // A single instance of KeyManager to be used by GetEntry()
- Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance();
- };
- class PlaceholderCache {
- public:
- explicit PlaceholderCache(VirtualDir dir);
- bool Create(const NcaID& id, u64 size) const;
- bool Delete(const NcaID& id) const;
- bool Exists(const NcaID& id) const;
- bool Write(const NcaID& id, u64 offset, const std::vector<u8>& data) const;
- bool Register(RegisteredCache* cache, const NcaID& placeholder, const NcaID& install) const;
- bool CleanAll() const;
- std::optional<std::array<u8, 0x10>> GetRightsID(const NcaID& id) const;
- u64 Size(const NcaID& id) const;
- bool SetSize(const NcaID& id, u64 new_size) const;
- std::vector<NcaID> List() const;
- static NcaID Generate();
- private:
- VirtualDir dir;
- };
- /*
- * A class that catalogues NCAs in the registered directory structure.
- * Nintendo's registered format follows this structure:
- *
- * Root
- * | 000000XX <- XX is the ____ two digits of the NcaID
- * | <hash>.nca <- hash is the NcaID (first half of SHA256 over entire file) (folder)
- * | 00
- * | 01 <- Actual content split along 4GB boundaries. (optional)
- *
- * (This impl also supports substituting the nca dir for an nca file, as that's more convenient
- * when 4GB splitting can be ignored.)
- */
- class RegisteredCache : public ContentProvider {
- friend class PlaceholderCache;
- public:
- // Parsing function defines the conversion from raw file to NCA. If there are other steps
- // besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom
- // parsing function.
- explicit RegisteredCache(
- VirtualDir dir, ContentProviderParsingFunction parsing_function =
- [](const VirtualFile& file, const NcaID& id) { return file; });
- ~RegisteredCache() override;
- void Refresh() override;
- bool HasEntry(u64 title_id, ContentRecordType type) const override;
- std::optional<u32> GetEntryVersion(u64 title_id) const override;
- VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const override;
- VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const override;
- std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const override;
- // If a parameter is not std::nullopt, it will be filtered for from all entries.
- std::vector<ContentProviderEntry> ListEntriesFilter(
- std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
- std::optional<u64> title_id = {}) const override;
- // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure
- // there is a meta NCA and all of them are accessible.
- InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false,
- const VfsCopyFunction& copy = &VfsRawCopy);
- InstallResult InstallEntry(const NSP& nsp, bool overwrite_if_exists = false,
- const VfsCopyFunction& copy = &VfsRawCopy);
- // Due to the fact that we must use Meta-type NCAs to determine the existence of files, this
- // 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.
- // TODO(DarkLordZach): Author real meta-type NCAs and install those.
- InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false,
- const VfsCopyFunction& copy = &VfsRawCopy);
- // Removes an existing entry based on title id
- bool RemoveExistingEntry(u64 title_id) const;
- private:
- template <typename T>
- void IterateAllMetadata(std::vector<T>& out,
- std::function<T(const CNMT&, const ContentRecord&)> proc,
- std::function<bool(const CNMT&, const ContentRecord&)> filter) const;
- std::vector<NcaID> AccumulateFiles() const;
- void ProcessFiles(const std::vector<NcaID>& ids);
- void AccumulateYuzuMeta();
- std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const;
- VirtualFile GetFileAtID(NcaID id) const;
- VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& open_dir, std::string_view path) const;
- InstallResult RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
- bool overwrite_if_exists, std::optional<NcaID> override_id = {});
- bool RawInstallYuzuMeta(const CNMT& cnmt);
- VirtualDir dir;
- ContentProviderParsingFunction parser;
- // maps tid -> NcaID of meta
- std::map<u64, NcaID> meta_id;
- // maps tid -> meta
- std::map<u64, CNMT> meta;
- // maps tid -> meta for CNMT in yuzu_meta
- std::map<u64, CNMT> yuzu_meta;
- };
- enum class ContentProviderUnionSlot {
- SysNAND, ///< System NAND
- UserNAND, ///< User NAND
- SDMC, ///< SD Card
- FrontendManual, ///< Frontend-defined game list or similar
- };
- // Combines multiple ContentProvider(s) (i.e. SysNAND, UserNAND, SDMC) into one interface.
- class ContentProviderUnion : public ContentProvider {
- public:
- ~ContentProviderUnion() override;
- void SetSlot(ContentProviderUnionSlot slot, ContentProvider* provider);
- void ClearSlot(ContentProviderUnionSlot slot);
- void Refresh() override;
- bool HasEntry(u64 title_id, ContentRecordType type) const override;
- std::optional<u32> GetEntryVersion(u64 title_id) const override;
- VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const override;
- VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const override;
- std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const override;
- std::vector<ContentProviderEntry> ListEntriesFilter(
- std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
- std::optional<u64> title_id) const override;
- std::vector<std::pair<ContentProviderUnionSlot, ContentProviderEntry>> ListEntriesFilterOrigin(
- std::optional<ContentProviderUnionSlot> origin = {},
- std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
- std::optional<u64> title_id = {}) const;
- std::optional<ContentProviderUnionSlot> GetSlotForEntry(u64 title_id,
- ContentRecordType type) const;
- private:
- std::map<ContentProviderUnionSlot, ContentProvider*> providers;
- };
- class ManualContentProvider : public ContentProvider {
- public:
- ~ManualContentProvider() override;
- void AddEntry(TitleType title_type, ContentRecordType content_type, u64 title_id,
- VirtualFile file);
- void ClearAllEntries();
- void Refresh() override;
- bool HasEntry(u64 title_id, ContentRecordType type) const override;
- std::optional<u32> GetEntryVersion(u64 title_id) const override;
- VirtualFile GetEntryUnparsed(u64 title_id, ContentRecordType type) const override;
- VirtualFile GetEntryRaw(u64 title_id, ContentRecordType type) const override;
- std::unique_ptr<NCA> GetEntry(u64 title_id, ContentRecordType type) const override;
- std::vector<ContentProviderEntry> ListEntriesFilter(
- std::optional<TitleType> title_type, std::optional<ContentRecordType> record_type,
- std::optional<u64> title_id) const override;
- private:
- std::map<std::tuple<TitleType, ContentRecordType, u64>, VirtualFile> entries;
- };
- } // namespace FileSys
|