summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/file_sys/patch_manager.cpp94
-rw-r--r--src/core/file_sys/patch_manager.h8
3 files changed, 104 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 23fd6e920..a98dbb9ab 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -34,6 +34,8 @@ add_library(core STATIC
34 file_sys/errors.h 34 file_sys/errors.h
35 file_sys/fsmitm_romfsbuild.cpp 35 file_sys/fsmitm_romfsbuild.cpp
36 file_sys/fsmitm_romfsbuild.h 36 file_sys/fsmitm_romfsbuild.h
37 file_sys/ips_layer.cpp
38 file_sys/ips_layer.h
37 file_sys/mode.h 39 file_sys/mode.h
38 file_sys/nca_metadata.cpp 40 file_sys/nca_metadata.cpp
39 file_sys/nca_metadata.h 41 file_sys/nca_metadata.h
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index 10b4acc92..044e01ae9 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -6,13 +6,16 @@
6#include <array> 6#include <array>
7#include <cstddef> 7#include <cstddef>
8 8
9#include "common/hex_util.h"
9#include "common/logging/log.h" 10#include "common/logging/log.h"
10#include "core/file_sys/content_archive.h" 11#include "core/file_sys/content_archive.h"
11#include "core/file_sys/control_metadata.h" 12#include "core/file_sys/control_metadata.h"
13#include "core/file_sys/ips_layer.h"
12#include "core/file_sys/patch_manager.h" 14#include "core/file_sys/patch_manager.h"
13#include "core/file_sys/registered_cache.h" 15#include "core/file_sys/registered_cache.h"
14#include "core/file_sys/romfs.h" 16#include "core/file_sys/romfs.h"
15#include "core/file_sys/vfs_layered.h" 17#include "core/file_sys/vfs_layered.h"
18#include "core/file_sys/vfs_vector.h"
16#include "core/hle/service/filesystem/filesystem.h" 19#include "core/hle/service/filesystem/filesystem.h"
17#include "core/loader/loader.h" 20#include "core/loader/loader.h"
18 21
@@ -21,6 +24,14 @@ namespace FileSys {
21constexpr u64 SINGLE_BYTE_MODULUS = 0x100; 24constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
22constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; 25constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
23 26
27struct NSOBuildHeader {
28 u32_le magic;
29 INSERT_PADDING_BYTES(0x3C);
30 std::array<u8, 0x20> build_id;
31 INSERT_PADDING_BYTES(0xA0);
32};
33static_assert(sizeof(NSOBuildHeader) == 0x100, "NSOBuildHeader has incorrect size.");
34
24std::string FormatTitleVersion(u32 version, TitleVersionFormat format) { 35std::string FormatTitleVersion(u32 version, TitleVersionFormat format) {
25 std::array<u8, sizeof(u32)> bytes{}; 36 std::array<u8, sizeof(u32)> bytes{};
26 bytes[0] = version % SINGLE_BYTE_MODULUS; 37 bytes[0] = version % SINGLE_BYTE_MODULUS;
@@ -61,6 +72,89 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
61 return exefs; 72 return exefs;
62} 73}
63 74
75std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso) const {
76 if (nso.size() < 0x100)
77 return nso;
78
79 NSOBuildHeader header{};
80 std::memcpy(&header, nso.data(), sizeof(NSOBuildHeader));
81
82 if (header.magic != Common::MakeMagic('N', 'S', 'O', '0'))
83 return nso;
84
85 const auto build_id_raw = Common::HexArrayToString(header.build_id);
86 const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1);
87
88 LOG_INFO(Loader, "Patching NSO for build_id={}", build_id);
89
90 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
91 auto patch_dirs = load_dir->GetSubdirectories();
92 std::sort(patch_dirs.begin(), patch_dirs.end(),
93 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
94
95 std::vector<VirtualFile> ips;
96 ips.reserve(patch_dirs.size() - 1);
97 for (const auto& subdir : patch_dirs) {
98 auto exefs_dir = subdir->GetSubdirectory("exefs");
99 if (exefs_dir != nullptr) {
100 for (const auto& file : exefs_dir->GetFiles()) {
101 if (file->GetExtension() != "ips")
102 continue;
103 auto name = file->GetName();
104 const auto p1 = name.substr(0, name.find_first_of('.'));
105 const auto this_build_id = p1.substr(0, p1.find_last_not_of('0') + 1);
106
107 if (build_id == this_build_id)
108 ips.push_back(file);
109 }
110 }
111 }
112
113 auto out = nso;
114 for (const auto& ips_file : ips) {
115 LOG_INFO(Loader, " - Appling IPS patch from mod \"{}\"",
116 ips_file->GetContainingDirectory()->GetParentDirectory()->GetName());
117 const auto patched = PatchIPS(std::make_shared<VectorVfsFile>(out), ips_file);
118 if (patched != nullptr)
119 out = patched->ReadAllBytes();
120 }
121
122 if (out.size() < 0x100)
123 return nso;
124 std::memcpy(out.data(), &header, sizeof(NSOBuildHeader));
125 return out;
126}
127
128bool PatchManager::HasNSOPatch(const std::array<u8, 32>& build_id_) const {
129 const auto build_id_raw = Common::HexArrayToString(build_id_);
130 const auto build_id = build_id_raw.substr(0, build_id_raw.find_last_not_of('0') + 1);
131
132 LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id);
133
134 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
135 auto patch_dirs = load_dir->GetSubdirectories();
136 std::sort(patch_dirs.begin(), patch_dirs.end(),
137 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
138
139 for (const auto& subdir : patch_dirs) {
140 auto exefs_dir = subdir->GetSubdirectory("exefs");
141 if (exefs_dir != nullptr) {
142 for (const auto& file : exefs_dir->GetFiles()) {
143 if (file->GetExtension() != "ips")
144 continue;
145 auto name = file->GetName();
146 const auto p1 = name.substr(0, name.find_first_of('.'));
147 const auto this_build_id = p1.substr(0, p1.find_last_not_of('0') + 1);
148
149 if (build_id == this_build_id)
150 return true;
151 }
152 }
153 }
154
155 return false;
156}
157
64static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { 158static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) {
65 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); 159 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
66 if (type != ContentRecordType::Program || load_dir == nullptr || load_dir->GetSize() <= 0) { 160 if (type != ContentRecordType::Program || load_dir == nullptr || load_dir->GetSize() <= 0) {
diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h
index 7807515f9..254f7bfc9 100644
--- a/src/core/file_sys/patch_manager.h
+++ b/src/core/file_sys/patch_manager.h
@@ -34,6 +34,14 @@ public:
34 // - Game Updates 34 // - Game Updates
35 VirtualDir PatchExeFS(VirtualDir exefs) const; 35 VirtualDir PatchExeFS(VirtualDir exefs) const;
36 36
37 // Currently tracked NSO patches:
38 // - IPS
39 std::vector<u8> PatchNSO(const std::vector<u8>& nso) const;
40
41 // Checks to see if PatchNSO() will have any effect given the NSO's build ID.
42 // Used to prevent expensive copies in NSO loader.
43 bool HasNSOPatch(const std::array<u8, 0x20>& build_id) const;
44
37 // Currently tracked RomFS patches: 45 // Currently tracked RomFS patches:
38 // - Game Updates 46 // - Game Updates
39 // - LayeredFS 47 // - LayeredFS