From 8500ca797f430226c86edf694db6a96ee14a8333 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 10 Apr 2019 12:21:51 -0400 Subject: registered_cache: Implement PlaceholderCache to manage placeholder and installing content --- src/core/file_sys/registered_cache.cpp | 150 +++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) (limited to 'src/core/file_sys/registered_cache.cpp') diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 3725b10f7..93a20ab94 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -127,6 +127,156 @@ std::vector ContentProvider::ListEntries() const { return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt); } +PlaceholderCache::PlaceholderCache(VirtualDir dir_) : dir(std::move(dir_)) {} + +bool PlaceholderCache::Create(const NcaID& id, u64 size) const { + const auto path = GetRelativePathFromNcaID(id, false, true, false); + + if (dir->GetFileRelative(path) != nullptr) { + return false; + } + + Core::Crypto::SHA256Hash hash{}; + mbedtls_sha256(id.data(), id.size(), hash.data(), 0); + const auto dirname = fmt::format("000000{:02X}", hash[0]); + + const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname); + + if (dir2 == nullptr) + return false; + + const auto file = dir2->CreateFile(fmt::format("{}.nca", Common::HexArrayToString(id, false))); + + if (file == nullptr) + return false; + + return file->Resize(size); +} + +bool PlaceholderCache::Delete(const NcaID& id) const { + const auto path = GetRelativePathFromNcaID(id, false, true, false); + + if (dir->GetFileRelative(path) == nullptr) { + return false; + } + + Core::Crypto::SHA256Hash hash{}; + mbedtls_sha256(id.data(), id.size(), hash.data(), 0); + const auto dirname = fmt::format("000000{:02X}", hash[0]); + + const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname); + + const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexArrayToString(id, false))); + + return res; +} + +bool PlaceholderCache::Exists(const NcaID& id) const { + const auto path = GetRelativePathFromNcaID(id, false, true, false); + + return dir->GetFileRelative(path) != nullptr; +} + +bool PlaceholderCache::Write(const NcaID& id, u64 offset, const std::vector& data) const { + const auto path = GetRelativePathFromNcaID(id, false, true, false); + const auto file = dir->GetFileRelative(path); + + if (file == nullptr) + return false; + + return file->WriteBytes(data, offset) == data.size(); +} + +bool PlaceholderCache::Register(RegisteredCache* cache, const NcaID& placeholder, + const NcaID& install) const { + const auto path = GetRelativePathFromNcaID(placeholder, false, true, false); + const auto file = dir->GetFileRelative(path); + + if (file == nullptr) + return false; + + const auto res = cache->RawInstallNCA(NCA{file}, &VfsRawCopy, false, install); + + if (res != InstallResult::Success) + return false; + + return Delete(placeholder); +} + +bool PlaceholderCache::CleanAll() const { + return dir->GetParentDirectory()->CleanSubdirectoryRecursive(dir->GetName()); +} + +std::optional> PlaceholderCache::GetRightsID(const NcaID& id) const { + const auto path = GetRelativePathFromNcaID(id, false, true, false); + const auto file = dir->GetFileRelative(path); + + if (file == nullptr) + return std::nullopt; + + NCA nca{file}; + + if (nca.GetStatus() != Loader::ResultStatus::Success && + nca.GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) { + return std::nullopt; + } + + const auto rights_id = nca.GetRightsId(); + if (rights_id == NcaID{}) + return std::nullopt; + + return rights_id; +} + +u64 PlaceholderCache::Size(const NcaID& id) const { + const auto path = GetRelativePathFromNcaID(id, false, true, false); + const auto file = dir->GetFileRelative(path); + + if (file == nullptr) + return 0; + + return file->GetSize(); +} + +bool PlaceholderCache::SetSize(const NcaID& id, u64 new_size) const { + const auto path = GetRelativePathFromNcaID(id, false, true, false); + const auto file = dir->GetFileRelative(path); + + if (file == nullptr) + return false; + + return file->Resize(new_size); +} + +std::vector PlaceholderCache::List() const { + std::vector out; + for (const auto& sdir : dir->GetSubdirectories()) { + for (const auto& file : sdir->GetFiles()) { + const auto name = file->GetName(); + if (name.length() == 36 && name[32] == '.' && name[33] == 'n' && name[34] == 'c' && + name[35] == 'a') { + out.push_back(Common::HexStringToArray<0x10>(name.substr(0, 32))); + } + } + } + return out; +} + +NcaID PlaceholderCache::Generate() { + std::random_device device; + std::mt19937 gen(device()); + std::uniform_int_distribution distribution(1, std::numeric_limits::max()); + + NcaID out{}; + + const auto v1 = distribution(gen); + const auto v2 = distribution(gen); + std::memcpy(out.data(), &v1, sizeof(u64)); + std::memcpy(out.data() + sizeof(u64), &v2, sizeof(u64)); + + return out; +} + VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const { const auto file = dir->GetFileRelative(path); -- cgit v1.2.3 From 9d9fc8a675ffa35998830a0a5670dd1ca288112f Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Wed, 10 Apr 2019 12:24:44 -0400 Subject: registered_cache: Process *.cnmt.nca files Needed to use the RegisteredCache/PlaceholderCache on gamecards. --- src/core/file_sys/registered_cache.cpp | 39 ++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 16 deletions(-) (limited to 'src/core/file_sys/registered_cache.cpp') diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 93a20ab94..afa87be9c 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -48,19 +48,22 @@ static bool FollowsTwoDigitDirFormat(std::string_view name) { static bool FollowsNcaIdFormat(std::string_view name) { static const std::regex nca_id_regex("[0-9A-F]{32}\\.nca", std::regex_constants::ECMAScript | std::regex_constants::icase); - return name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex); + static const std::regex nca_id_cnmt_regex( + "[0-9A-F]{32}\\.cnmt.nca", std::regex_constants::ECMAScript | std::regex_constants::icase); + return (name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex)) || + (name.size() == 41 && std::regex_match(name.begin(), name.end(), nca_id_cnmt_regex)); } static std::string GetRelativePathFromNcaID(const std::array& nca_id, bool second_hex_upper, - bool within_two_digit) { - if (!within_two_digit) { - return fmt::format("/{}.nca", Common::HexToString(nca_id, second_hex_upper)); - } + bool within_two_digit, bool cnmt_suffix) { + if (!within_two_digit) + return fmt::format(cnmt_suffix ? "{}.cnmt.nca" : "/{}.nca", + Common::HexArrayToString(nca_id, second_hex_upper)); Core::Crypto::SHA256Hash hash{}; mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0); - return fmt::format("/000000{:02X}/{}.nca", hash[0], - Common::HexToString(nca_id, second_hex_upper)); + return fmt::format(cnmt_suffix ? "/000000{:02X}/{}.cnmt.nca" : "/000000{:02X}/{}.nca", hash[0], + Common::HexArrayToString(nca_id, second_hex_upper)); } static std::string GetCNMTName(TitleType type, u64 title_id) { @@ -319,14 +322,18 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, VirtualFile RegisteredCache::GetFileAtID(NcaID id) const { VirtualFile file; - // Try all four modes of file storage: - // (bit 1 = uppercase/lower, bit 0 = within a two-digit dir) - // 00: /000000**/{:032X}.nca - // 01: /{:032X}.nca - // 10: /000000**/{:032x}.nca - // 11: /{:032x}.nca - for (u8 i = 0; i < 4; ++i) { - const auto path = GetRelativePathFromNcaID(id, (i & 0b10) == 0, (i & 0b01) == 0); + // Try all five relevant modes of file storage: + // (bit 2 = uppercase/lower, bit 1 = within a two-digit dir, bit 0 = .cnmt suffix) + // 000: /000000**/{:032X}.nca + // 010: /{:032X}.nca + // 100: /000000**/{:032x}.nca + // 110: /{:032x}.nca + // 111: /{:032x}.cnmt.nca + for (u8 i = 0; i < 8; ++i) { + if ((i % 2) == 1 && i != 7) + continue; + const auto path = + GetRelativePathFromNcaID(id, (i & 0b100) == 0, (i & 0b010) == 0, (i & 0b001) == 0b001); file = OpenFileOrDirectoryConcat(dir, path); if (file != nullptr) return file; @@ -622,7 +629,7 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti memcpy(id.data(), hash.data(), 16); } - std::string path = GetRelativePathFromNcaID(id, false, true); + std::string path = GetRelativePathFromNcaID(id, false, true, false); if (GetFileAtID(id) != nullptr && !overwrite_if_exists) { LOG_WARNING(Loader, "Attempting to overwrite existing NCA. Skipping..."); -- cgit v1.2.3 From c6ff4a6f4d05eb380616be57e4088003e7aedfcb Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Mon, 22 Apr 2019 17:56:56 -0400 Subject: yuzu: Port old usages of Filesystem namespace to FilesystemController --- src/core/file_sys/registered_cache.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/core/file_sys/registered_cache.cpp') diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index afa87be9c..d1ef1e72d 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include +#include #include #include #include "common/assert.h" -- cgit v1.2.3 From 038bcec11153cefd713ddb06eddcc42b0a936df2 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Sat, 21 Sep 2019 18:43:11 -0400 Subject: configure_debug: Move reporting option to logging --- src/core/file_sys/registered_cache.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/core/file_sys/registered_cache.cpp') diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index d1ef1e72d..ac3fbd849 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -59,12 +59,12 @@ static std::string GetRelativePathFromNcaID(const std::array& nca_id, bo bool within_two_digit, bool cnmt_suffix) { if (!within_two_digit) return fmt::format(cnmt_suffix ? "{}.cnmt.nca" : "/{}.nca", - Common::HexArrayToString(nca_id, second_hex_upper)); + Common::HexToString(nca_id, second_hex_upper)); Core::Crypto::SHA256Hash hash{}; mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0); return fmt::format(cnmt_suffix ? "/000000{:02X}/{}.cnmt.nca" : "/000000{:02X}/{}.nca", hash[0], - Common::HexArrayToString(nca_id, second_hex_upper)); + Common::HexToString(nca_id, second_hex_upper)); } static std::string GetCNMTName(TitleType type, u64 title_id) { @@ -149,7 +149,7 @@ bool PlaceholderCache::Create(const NcaID& id, u64 size) const { if (dir2 == nullptr) return false; - const auto file = dir2->CreateFile(fmt::format("{}.nca", Common::HexArrayToString(id, false))); + const auto file = dir2->CreateFile(fmt::format("{}.nca", Common::HexToString(id, false))); if (file == nullptr) return false; @@ -170,7 +170,7 @@ bool PlaceholderCache::Delete(const NcaID& id) const { const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname); - const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexArrayToString(id, false))); + const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexToString(id, false))); return res; } -- cgit v1.2.3