From 2ec852dd9f38ab6376f78ade15b8c62d86ab518a Mon Sep 17 00:00:00 2001
From: Morph <39850852+Morph1984@users.noreply.github.com>
Date: Mon, 20 Jul 2020 10:28:44 -0400
Subject: [PATCH] registered_cache: Add support for removing folder ncas

---
 src/core/file_sys/registered_cache.cpp | 101 +++++++++++++------------
 src/core/file_sys/registered_cache.h   |   6 +-
 2 files changed, 54 insertions(+), 53 deletions(-)

diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 37351c5610..e94eed3b66 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -547,56 +547,6 @@ InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_ex
     return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy);
 }
 
-bool RegisteredCache::RemoveExistingEntry(u64 title_id) {
-    const auto delete_nca = [this](const NcaID& id) {
-        const auto path = GetRelativePathFromNcaID(id, false, true, false);
-
-        if (dir->GetFileRelative(path) == nullptr) {
-            return false;
-        }
-
-        Core::Crypto::SHA256Hash hash{};
-        mbedtls_sha256_ret(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::HexToString(id, false)));
-
-        return res;
-    };
-
-    // If an entry exists in the registered cache, remove it
-    if (HasEntry(title_id, ContentRecordType::Meta)) {
-        LOG_INFO(Loader,
-                 "Previously installed entry (v{}) for title_id={:016X} detected! "
-                 "Attempting to remove...",
-                 GetEntryVersion(title_id).value_or(0), title_id);
-        // Get all the ncas associated with the current CNMT and delete them
-        const auto meta_old_id =
-            GetNcaIDFromMetadata(title_id, ContentRecordType::Meta).value_or(NcaID{});
-        const auto program_id =
-            GetNcaIDFromMetadata(title_id, ContentRecordType::Program).value_or(NcaID{});
-        const auto data_id =
-            GetNcaIDFromMetadata(title_id, ContentRecordType::Data).value_or(NcaID{});
-        const auto control_id =
-            GetNcaIDFromMetadata(title_id, ContentRecordType::Control).value_or(NcaID{});
-        const auto html_id =
-            GetNcaIDFromMetadata(title_id, ContentRecordType::HtmlDocument).value_or(NcaID{});
-        const auto legal_id =
-            GetNcaIDFromMetadata(title_id, ContentRecordType::LegalInformation).value_or(NcaID{});
-
-        delete_nca(meta_old_id);
-        delete_nca(program_id);
-        delete_nca(data_id);
-        delete_nca(control_id);
-        delete_nca(html_id);
-        delete_nca(legal_id);
-        return true;
-    }
-    return false;
-}
-
 InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists,
                                             const VfsCopyFunction& copy) {
     const auto ncas = nsp.GetNCAsCollapsed();
@@ -692,6 +642,57 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
     return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id);
 }
 
+bool RegisteredCache::RemoveExistingEntry(u64 title_id) const {
+    const auto delete_nca = [this](const NcaID& id) {
+        const auto path = GetRelativePathFromNcaID(id, false, true, false);
+
+        const bool isFile = dir->GetFileRelative(path) != nullptr;
+        const bool isDir = dir->GetDirectoryRelative(path) != nullptr;
+
+        if (isFile) {
+            return dir->DeleteFile(path);
+        } else if (isDir) {
+            return dir->DeleteSubdirectoryRecursive(path);
+        }
+
+        return false;
+    };
+
+    // If an entry exists in the registered cache, remove it
+    if (HasEntry(title_id, ContentRecordType::Meta)) {
+        LOG_INFO(Loader,
+                 "Previously installed entry (v{}) for title_id={:016X} detected! "
+                 "Attempting to remove...",
+                 GetEntryVersion(title_id).value_or(0), title_id);
+
+        // Get all the ncas associated with the current CNMT and delete them
+        const auto meta_old_id =
+            GetNcaIDFromMetadata(title_id, ContentRecordType::Meta).value_or(NcaID{});
+        const auto program_id =
+            GetNcaIDFromMetadata(title_id, ContentRecordType::Program).value_or(NcaID{});
+        const auto data_id =
+            GetNcaIDFromMetadata(title_id, ContentRecordType::Data).value_or(NcaID{});
+        const auto control_id =
+            GetNcaIDFromMetadata(title_id, ContentRecordType::Control).value_or(NcaID{});
+        const auto html_id =
+            GetNcaIDFromMetadata(title_id, ContentRecordType::HtmlDocument).value_or(NcaID{});
+        const auto legal_id =
+            GetNcaIDFromMetadata(title_id, ContentRecordType::LegalInformation).value_or(NcaID{});
+
+        const auto deleted_meta = delete_nca(meta_old_id);
+        const auto deleted_program = delete_nca(program_id);
+        const auto deleted_data = delete_nca(data_id);
+        const auto deleted_control = delete_nca(control_id);
+        const auto deleted_html = delete_nca(html_id);
+        const auto deleted_legal = delete_nca(legal_id);
+
+        return deleted_meta && (deleted_meta || deleted_program || deleted_data ||
+                                deleted_control || deleted_html || deleted_legal);
+    }
+
+    return false;
+}
+
 InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy,
                                              bool overwrite_if_exists,
                                              std::optional<NcaID> override_id) {
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index 29cf0d40c7..ec1d54f27c 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -155,9 +155,6 @@ public:
         std::optional<TitleType> title_type = {}, std::optional<ContentRecordType> record_type = {},
         std::optional<u64> title_id = {}) const override;
 
-    // Removes an existing entry based on title id
-    bool RemoveExistingEntry(u64 title_id);
-
     // 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,
@@ -172,6 +169,9 @@ public:
     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,