From 97bf83bc56860be244077e9213468466f894c73d Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Sat, 25 Aug 2018 19:04:48 -0400
Subject: [PATCH] patch_manager: Add usages of patches to ExeFS

---
 src/core/file_sys/romfs_factory.cpp           | 11 ++++++-
 src/core/file_sys/romfs_factory.h             |  1 +
 .../loader/deconstructed_rom_directory.cpp    | 29 +++++++++++++++----
 src/core/loader/deconstructed_rom_directory.h |  7 +++--
 src/core/loader/nca.cpp                       |  2 +-
 5 files changed, 41 insertions(+), 9 deletions(-)

diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index 66f9786e01..fc9cf1eca7 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -6,7 +6,10 @@
 #include "common/assert.h"
 #include "common/common_types.h"
 #include "common/logging/log.h"
+#include "core/core.h"
 #include "core/file_sys/content_archive.h"
+#include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/patch_manager.h"
 #include "core/file_sys/registered_cache.h"
 #include "core/file_sys/romfs_factory.h"
 #include "core/hle/service/filesystem/filesystem.h"
@@ -19,10 +22,16 @@ RomFSFactory::RomFSFactory(Loader::AppLoader& app_loader) {
     if (app_loader.ReadRomFS(file) != Loader::ResultStatus::Success) {
         LOG_ERROR(Service_FS, "Unable to read RomFS!");
     }
+
+    updatable = app_loader.IsRomFSUpdatable();
 }
 
 ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
-    return MakeResult<VirtualFile>(file);
+    if (!updatable)
+        return MakeResult<VirtualFile>(file);
+
+    const PatchManager patch_manager(Core::CurrentProcess()->process_id);
+    return MakeResult<VirtualFile>(patch_manager.PatchRomFS(file));
 }
 
 ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) {
diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h
index f38ddc4f7c..168db1c465 100644
--- a/src/core/file_sys/romfs_factory.h
+++ b/src/core/file_sys/romfs_factory.h
@@ -36,6 +36,7 @@ public:
 
 private:
     VirtualFile file;
+    bool updatable;
 };
 
 } // namespace FileSys
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 1ae4bb656f..04ef55da1a 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -9,6 +9,7 @@
 #include "core/core.h"
 #include "core/file_sys/content_archive.h"
 #include "core/file_sys/control_metadata.h"
+#include "core/file_sys/patch_manager.h"
 #include "core/file_sys/romfs_factory.h"
 #include "core/gdbstub/gdbstub.h"
 #include "core/hle/kernel/kernel.h"
@@ -21,8 +22,9 @@
 
 namespace Loader {
 
-AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_)
-    : AppLoader(std::move(file_)) {
+AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_,
+                                                                         bool override_update)
+    : AppLoader(std::move(file_)), override_update(override_update) {
     const auto dir = file->GetContainingDirectory();
 
     // Icon
@@ -66,8 +68,9 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys
 }
 
 AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
-    FileSys::VirtualDir directory)
-    : AppLoader(directory->GetFile("main")), dir(std::move(directory)) {}
+    FileSys::VirtualDir directory, bool override_update)
+    : AppLoader(directory->GetFile("main")), dir(std::move(directory)),
+      override_update(override_update) {}
 
 FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& file) {
     if (FileSys::IsDirectoryExeFS(file->GetContainingDirectory())) {
@@ -89,7 +92,8 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
         dir = file->GetContainingDirectory();
     }
 
-    const FileSys::VirtualFile npdm = dir->GetFile("main.npdm");
+    // Read meta to determine title ID
+    FileSys::VirtualFile npdm = dir->GetFile("main.npdm");
     if (npdm == nullptr)
         return ResultStatus::ErrorMissingNPDM;
 
@@ -97,6 +101,21 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load(
     if (result != ResultStatus::Success) {
         return result;
     }
+
+    if (override_update) {
+        const FileSys::PatchManager patch_manager(metadata.GetTitleID());
+        dir = patch_manager.PatchExeFS(dir);
+    }
+
+    // Reread in case PatchExeFS affected the main.npdm
+    npdm = dir->GetFile("main.npdm");
+    if (npdm == nullptr)
+        return ResultStatus::ErrorMissingNPDM;
+
+    ResultStatus result2 = metadata.Load(npdm);
+    if (result2 != ResultStatus::Success) {
+        return result2;
+    }
     metadata.Print();
 
     const FileSys::ProgramAddressSpaceType arch_bits{metadata.GetAddressSpaceType()};
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index b20804f75d..cb50f8bff9 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -20,10 +20,12 @@ namespace Loader {
  */
 class AppLoader_DeconstructedRomDirectory final : public AppLoader {
 public:
-    explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file);
+    explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile main_file,
+                                                 bool override_update = false);
 
     // Overload to accept exefs directory. Must contain 'main' and 'main.npdm'
-    explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory);
+    explicit AppLoader_DeconstructedRomDirectory(FileSys::VirtualDir directory,
+                                                 bool override_update = false);
 
     /**
      * Returns the type of the file
@@ -51,6 +53,7 @@ private:
     std::vector<u8> icon_data;
     std::string name;
     u64 title_id{};
+    bool override_update;
 };
 
 } // namespace Loader
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index c036a8a1cd..6b1c27b47f 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -48,7 +48,7 @@ ResultStatus AppLoader_NCA::Load(Kernel::SharedPtr<Kernel::Process>& process) {
     if (exefs == nullptr)
         return ResultStatus::ErrorNoExeFS;
 
-    directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs);
+    directory_loader = std::make_unique<AppLoader_DeconstructedRomDirectory>(exefs, true);
 
     const auto load_result = directory_loader->Load(process);
     if (load_result != ResultStatus::Success)