summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_32.cpp13
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp13
-rw-r--r--src/core/core.cpp14
-rw-r--r--src/core/core_timing.cpp12
-rw-r--r--src/core/core_timing_util.cpp1
-rw-r--r--src/core/core_timing_util.h1
-rw-r--r--src/core/cpu_manager.cpp29
-rw-r--r--src/core/crypto/aes_util.cpp2
-rw-r--r--src/core/crypto/key_manager.cpp439
-rw-r--r--src/core/crypto/key_manager.h8
-rw-r--r--src/core/crypto/partition_data_manager.cpp4
-rw-r--r--src/core/file_sys/bis_factory.cpp2
-rw-r--r--src/core/file_sys/registered_cache.cpp2
-rw-r--r--src/core/file_sys/vfs.cpp56
-rw-r--r--src/core/file_sys/vfs_libzip.cpp2
-rw-r--r--src/core/file_sys/vfs_real.cpp241
-rw-r--r--src/core/file_sys/vfs_real.h8
-rw-r--r--src/core/file_sys/xts_archive.cpp2
-rw-r--r--src/core/hle/service/acc/acc.cpp8
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp22
-rw-r--r--src/core/hle/service/am/applets/web_browser.cpp16
-rw-r--r--src/core/hle/service/bcat/backend/boxcat.cpp20
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp80
-rw-r--r--src/core/loader/loader.cpp2
-rw-r--r--src/core/perf_stats.cpp4
-rw-r--r--src/core/reporter.cpp9
-rw-r--r--src/core/settings.cpp4
-rw-r--r--src/core/settings.h6
-rw-r--r--src/core/telemetry_session.cpp14
-rw-r--r--src/core/telemetry_session.h5
30 files changed, 582 insertions, 457 deletions
diff --git a/src/core/arm/dynarmic/arm_dynarmic_32.cpp b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
index 443ca72eb..b5f28a86e 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_32.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_32.cpp
@@ -143,7 +143,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
143 config.wall_clock_cntpct = uses_wall_clock; 143 config.wall_clock_cntpct = uses_wall_clock;
144 144
145 // Safe optimizations 145 // Safe optimizations
146 if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) { 146 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
147 if (!Settings::values.cpuopt_page_tables) { 147 if (!Settings::values.cpuopt_page_tables) {
148 config.page_table = nullptr; 148 config.page_table = nullptr;
149 } 149 }
@@ -170,6 +170,17 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable&
170 } 170 }
171 } 171 }
172 172
173 // Unsafe optimizations
174 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) {
175 config.unsafe_optimizations = true;
176 if (Settings::values.cpuopt_unsafe_unfuse_fma) {
177 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
178 }
179 if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
180 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
181 }
182 }
183
173 return std::make_unique<Dynarmic::A32::Jit>(config); 184 return std::make_unique<Dynarmic::A32::Jit>(config);
174} 185}
175 186
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index a63a04a25..ce9968724 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -195,7 +195,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
195 config.wall_clock_cntpct = uses_wall_clock; 195 config.wall_clock_cntpct = uses_wall_clock;
196 196
197 // Safe optimizations 197 // Safe optimizations
198 if (Settings::values.cpu_accuracy != Settings::CPUAccuracy::Accurate) { 198 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::DebugMode) {
199 if (!Settings::values.cpuopt_page_tables) { 199 if (!Settings::values.cpuopt_page_tables) {
200 config.page_table = nullptr; 200 config.page_table = nullptr;
201 } 201 }
@@ -222,6 +222,17 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable&
222 } 222 }
223 } 223 }
224 224
225 // Unsafe optimizations
226 if (Settings::values.cpu_accuracy == Settings::CPUAccuracy::Unsafe) {
227 config.unsafe_optimizations = true;
228 if (Settings::values.cpuopt_unsafe_unfuse_fma) {
229 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA;
230 }
231 if (Settings::values.cpuopt_unsafe_reduce_fp_error) {
232 config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_ReducedErrorFP;
233 }
234 }
235
225 return std::make_shared<Dynarmic::A64::Jit>(config); 236 return std::make_shared<Dynarmic::A64::Jit>(config);
226} 237}
227 238
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 42277e2cd..c2c0eec0b 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -113,7 +113,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
113 return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName()); 113 return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName());
114 } 114 }
115 115
116 if (FileUtil::IsDirectory(path)) 116 if (Common::FS::IsDirectory(path))
117 return vfs->OpenFile(path + "/" + "main", FileSys::Mode::Read); 117 return vfs->OpenFile(path + "/" + "main", FileSys::Mode::Read);
118 118
119 return vfs->OpenFile(path, FileSys::Mode::Read); 119 return vfs->OpenFile(path, FileSys::Mode::Read);
@@ -269,14 +269,14 @@ struct System::Impl {
269 // Log last frame performance stats if game was loded 269 // Log last frame performance stats if game was loded
270 if (perf_stats) { 270 if (perf_stats) {
271 const auto perf_results = GetAndResetPerfStats(); 271 const auto perf_results = GetAndResetPerfStats();
272 telemetry_session->AddField(Telemetry::FieldType::Performance, 272 constexpr auto performance = Common::Telemetry::FieldType::Performance;
273 "Shutdown_EmulationSpeed", 273
274 telemetry_session->AddField(performance, "Shutdown_EmulationSpeed",
274 perf_results.emulation_speed * 100.0); 275 perf_results.emulation_speed * 100.0);
275 telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Framerate", 276 telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps);
276 perf_results.game_fps); 277 telemetry_session->AddField(performance, "Shutdown_Frametime",
277 telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime",
278 perf_results.frametime * 1000.0); 278 perf_results.frametime * 1000.0);
279 telemetry_session->AddField(Telemetry::FieldType::Performance, "Mean_Frametime_MS", 279 telemetry_session->AddField(performance, "Mean_Frametime_MS",
280 perf_stats->GetMeanFrametime()); 280 perf_stats->GetMeanFrametime());
281 } 281 }
282 282
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index 71af26ec5..e6c8461a5 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -7,14 +7,14 @@
7#include <string> 7#include <string>
8#include <tuple> 8#include <tuple>
9 9
10#include "common/assert.h"
11#include "common/microprofile.h" 10#include "common/microprofile.h"
12#include "core/core_timing.h" 11#include "core/core_timing.h"
13#include "core/core_timing_util.h" 12#include "core/core_timing_util.h"
13#include "core/hardware_properties.h"
14 14
15namespace Core::Timing { 15namespace Core::Timing {
16 16
17constexpr u64 MAX_SLICE_LENGTH = 4000; 17constexpr s64 MAX_SLICE_LENGTH = 4000;
18 18
19std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) { 19std::shared_ptr<EventType> CreateEvent(std::string name, TimedCallback&& callback) {
20 return std::make_shared<EventType>(std::move(callback), std::move(name)); 20 return std::make_shared<EventType>(std::move(callback), std::move(name));
@@ -37,10 +37,8 @@ struct CoreTiming::Event {
37 } 37 }
38}; 38};
39 39
40CoreTiming::CoreTiming() { 40CoreTiming::CoreTiming()
41 clock = 41 : clock{Common::CreateBestMatchingClock(Hardware::BASE_CLOCK_RATE, Hardware::CNTFREQ)} {}
42 Common::CreateBestMatchingClock(Core::Hardware::BASE_CLOCK_RATE, Core::Hardware::CNTFREQ);
43}
44 42
45CoreTiming::~CoreTiming() = default; 43CoreTiming::~CoreTiming() = default;
46 44
@@ -136,7 +134,7 @@ void CoreTiming::UnscheduleEvent(const std::shared_ptr<EventType>& event_type,
136 134
137void CoreTiming::AddTicks(u64 ticks) { 135void CoreTiming::AddTicks(u64 ticks) {
138 this->ticks += ticks; 136 this->ticks += ticks;
139 downcount -= ticks; 137 downcount -= static_cast<s64>(ticks);
140} 138}
141 139
142void CoreTiming::Idle() { 140void CoreTiming::Idle() {
diff --git a/src/core/core_timing_util.cpp b/src/core/core_timing_util.cpp
index aefc63663..8ce8e602e 100644
--- a/src/core/core_timing_util.cpp
+++ b/src/core/core_timing_util.cpp
@@ -8,6 +8,7 @@
8#include <limits> 8#include <limits>
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/uint128.h" 10#include "common/uint128.h"
11#include "core/hardware_properties.h"
11 12
12namespace Core::Timing { 13namespace Core::Timing {
13 14
diff --git a/src/core/core_timing_util.h b/src/core/core_timing_util.h
index 2ed979e14..e4a046bf9 100644
--- a/src/core/core_timing_util.h
+++ b/src/core/core_timing_util.h
@@ -6,7 +6,6 @@
6 6
7#include <chrono> 7#include <chrono>
8#include "common/common_types.h" 8#include "common/common_types.h"
9#include "core/hardware_properties.h"
10 9
11namespace Core::Timing { 10namespace Core::Timing {
12 11
diff --git a/src/core/cpu_manager.cpp b/src/core/cpu_manager.cpp
index 358943429..ef0bae556 100644
--- a/src/core/cpu_manager.cpp
+++ b/src/core/cpu_manager.cpp
@@ -41,9 +41,9 @@ void CpuManager::Shutdown() {
41 running_mode = false; 41 running_mode = false;
42 Pause(false); 42 Pause(false);
43 if (is_multicore) { 43 if (is_multicore) {
44 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { 44 for (auto& data : core_data) {
45 core_data[core].host_thread->join(); 45 data.host_thread->join();
46 core_data[core].host_thread.reset(); 46 data.host_thread.reset();
47 } 47 }
48 } else { 48 } else {
49 core_data[0].host_thread->join(); 49 core_data[0].host_thread->join();
@@ -166,25 +166,23 @@ void CpuManager::MultiCorePause(bool paused) {
166 bool all_not_barrier = false; 166 bool all_not_barrier = false;
167 while (!all_not_barrier) { 167 while (!all_not_barrier) {
168 all_not_barrier = true; 168 all_not_barrier = true;
169 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { 169 for (const auto& data : core_data) {
170 all_not_barrier &= 170 all_not_barrier &= !data.is_running.load() && data.initialized.load();
171 !core_data[core].is_running.load() && core_data[core].initialized.load();
172 } 171 }
173 } 172 }
174 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { 173 for (auto& data : core_data) {
175 core_data[core].enter_barrier->Set(); 174 data.enter_barrier->Set();
176 } 175 }
177 if (paused_state.load()) { 176 if (paused_state.load()) {
178 bool all_barrier = false; 177 bool all_barrier = false;
179 while (!all_barrier) { 178 while (!all_barrier) {
180 all_barrier = true; 179 all_barrier = true;
181 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { 180 for (const auto& data : core_data) {
182 all_barrier &= 181 all_barrier &= data.is_paused.load() && data.initialized.load();
183 core_data[core].is_paused.load() && core_data[core].initialized.load();
184 } 182 }
185 } 183 }
186 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { 184 for (auto& data : core_data) {
187 core_data[core].exit_barrier->Set(); 185 data.exit_barrier->Set();
188 } 186 }
189 } 187 }
190 } else { 188 } else {
@@ -192,9 +190,8 @@ void CpuManager::MultiCorePause(bool paused) {
192 bool all_barrier = false; 190 bool all_barrier = false;
193 while (!all_barrier) { 191 while (!all_barrier) {
194 all_barrier = true; 192 all_barrier = true;
195 for (std::size_t core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) { 193 for (const auto& data : core_data) {
196 all_barrier &= 194 all_barrier &= data.is_paused.load() && data.initialized.load();
197 core_data[core].is_paused.load() && core_data[core].initialized.load();
198 } 195 }
199 } 196 }
200 /// Don't release the barrier 197 /// Don't release the barrier
diff --git a/src/core/crypto/aes_util.cpp b/src/core/crypto/aes_util.cpp
index 330996b24..6a9734812 100644
--- a/src/core/crypto/aes_util.cpp
+++ b/src/core/crypto/aes_util.cpp
@@ -116,7 +116,7 @@ void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, std::size_t size, u8*
116 116
117 for (std::size_t i = 0; i < size; i += sector_size) { 117 for (std::size_t i = 0; i < size; i += sector_size) {
118 SetIV(CalculateNintendoTweak(sector_id++)); 118 SetIV(CalculateNintendoTweak(sector_id++));
119 Transcode<u8, u8>(src + i, sector_size, dest + i, op); 119 Transcode(src + i, sector_size, dest + i, op);
120 } 120 }
121} 121}
122 122
diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp
index c09f7ad41..dc591c730 100644
--- a/src/core/crypto/key_manager.cpp
+++ b/src/core/crypto/key_manager.cpp
@@ -36,6 +36,7 @@
36#include "core/settings.h" 36#include "core/settings.h"
37 37
38namespace Core::Crypto { 38namespace Core::Crypto {
39namespace {
39 40
40constexpr u64 CURRENT_CRYPTO_REVISION = 0x5; 41constexpr u64 CURRENT_CRYPTO_REVISION = 0x5;
41constexpr u64 FULL_TICKET_SIZE = 0x400; 42constexpr u64 FULL_TICKET_SIZE = 0x400;
@@ -49,7 +50,72 @@ constexpr std::array eticket_source_hashes{
49}; 50};
50// clang-format on 51// clang-format on
51 52
52const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{ 53constexpr std::array<std::pair<std::string_view, KeyIndex<S128KeyType>>, 30> s128_file_id{{
54 {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
55 {"eticket_rsa_kek_source",
56 {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKek), 0}},
57 {"eticket_rsa_kekek_source",
58 {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKekek), 0}},
59 {"rsa_kek_mask_0", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Mask0), 0}},
60 {"rsa_kek_seed_3", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Seed3), 0}},
61 {"rsa_oaep_kek_generation_source",
62 {S128KeyType::Source, static_cast<u64>(SourceKeyType::RSAOaepKekGeneration), 0}},
63 {"sd_card_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek), 0}},
64 {"aes_kek_generation_source",
65 {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration), 0}},
66 {"aes_key_generation_source",
67 {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration), 0}},
68 {"package2_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Package2), 0}},
69 {"master_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Master), 0}},
70 {"header_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek), 0}},
71 {"key_area_key_application_source",
72 {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
73 static_cast<u64>(KeyAreaKeyType::Application)}},
74 {"key_area_key_ocean_source",
75 {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
76 static_cast<u64>(KeyAreaKeyType::Ocean)}},
77 {"key_area_key_system_source",
78 {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
79 static_cast<u64>(KeyAreaKeyType::System)}},
80 {"titlekek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Titlekek), 0}},
81 {"keyblob_mac_key_source",
82 {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC), 0}},
83 {"tsec_key", {S128KeyType::TSEC, 0, 0}},
84 {"secure_boot_key", {S128KeyType::SecureBoot, 0, 0}},
85 {"sd_seed", {S128KeyType::SDSeed, 0, 0}},
86 {"bis_key_0_crypt", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Crypto)}},
87 {"bis_key_0_tweak", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Tweak)}},
88 {"bis_key_1_crypt", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Crypto)}},
89 {"bis_key_1_tweak", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Tweak)}},
90 {"bis_key_2_crypt", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Crypto)}},
91 {"bis_key_2_tweak", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Tweak)}},
92 {"bis_key_3_crypt", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Crypto)}},
93 {"bis_key_3_tweak", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Tweak)}},
94 {"header_kek", {S128KeyType::HeaderKek, 0, 0}},
95 {"sd_card_kek", {S128KeyType::SDKek, 0, 0}},
96}};
97
98auto Find128ByName(std::string_view name) {
99 return std::find_if(s128_file_id.begin(), s128_file_id.end(),
100 [&name](const auto& pair) { return pair.first == name; });
101}
102
103constexpr std::array<std::pair<std::string_view, KeyIndex<S256KeyType>>, 6> s256_file_id{{
104 {"header_key", {S256KeyType::Header, 0, 0}},
105 {"sd_card_save_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save), 0}},
106 {"sd_card_nca_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA), 0}},
107 {"header_key_source", {S256KeyType::HeaderSource, 0, 0}},
108 {"sd_card_save_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::Save), 0}},
109 {"sd_card_nca_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::NCA), 0}},
110}};
111
112auto Find256ByName(std::string_view name) {
113 return std::find_if(s256_file_id.begin(), s256_file_id.end(),
114 [&name](const auto& pair) { return pair.first == name; });
115}
116
117using KeyArray = std::array<std::pair<std::pair<S128KeyType, u64>, std::string_view>, 7>;
118constexpr KeyArray KEYS_VARIABLE_LENGTH{{
53 {{S128KeyType::Master, 0}, "master_key_"}, 119 {{S128KeyType::Master, 0}, "master_key_"},
54 {{S128KeyType::Package1, 0}, "package1_key_"}, 120 {{S128KeyType::Package1, 0}, "package1_key_"},
55 {{S128KeyType::Package2, 0}, "package2_key_"}, 121 {{S128KeyType::Package2, 0}, "package2_key_"},
@@ -57,14 +123,13 @@ const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{
57 {{S128KeyType::Source, static_cast<u64>(SourceKeyType::Keyblob)}, "keyblob_key_source_"}, 123 {{S128KeyType::Source, static_cast<u64>(SourceKeyType::Keyblob)}, "keyblob_key_source_"},
58 {{S128KeyType::Keyblob, 0}, "keyblob_key_"}, 124 {{S128KeyType::Keyblob, 0}, "keyblob_key_"},
59 {{S128KeyType::KeyblobMAC, 0}, "keyblob_mac_key_"}, 125 {{S128KeyType::KeyblobMAC, 0}, "keyblob_mac_key_"},
60}; 126}};
61 127
62namespace {
63template <std::size_t Size> 128template <std::size_t Size>
64bool IsAllZeroArray(const std::array<u8, Size>& array) { 129bool IsAllZeroArray(const std::array<u8, Size>& array) {
65 return std::all_of(array.begin(), array.end(), [](const auto& elem) { return elem == 0; }); 130 return std::all_of(array.begin(), array.end(), [](const auto& elem) { return elem == 0; });
66} 131}
67} // namespace 132} // Anonymous namespace
68 133
69u64 GetSignatureTypeDataSize(SignatureType type) { 134u64 GetSignatureTypeDataSize(SignatureType type) {
70 switch (type) { 135 switch (type) {
@@ -96,13 +161,13 @@ u64 GetSignatureTypePaddingSize(SignatureType type) {
96} 161}
97 162
98SignatureType Ticket::GetSignatureType() const { 163SignatureType Ticket::GetSignatureType() const {
99 if (auto ticket = std::get_if<RSA4096Ticket>(&data)) { 164 if (const auto* ticket = std::get_if<RSA4096Ticket>(&data)) {
100 return ticket->sig_type; 165 return ticket->sig_type;
101 } 166 }
102 if (auto ticket = std::get_if<RSA2048Ticket>(&data)) { 167 if (const auto* ticket = std::get_if<RSA2048Ticket>(&data)) {
103 return ticket->sig_type; 168 return ticket->sig_type;
104 } 169 }
105 if (auto ticket = std::get_if<ECDSATicket>(&data)) { 170 if (const auto* ticket = std::get_if<ECDSATicket>(&data)) {
106 return ticket->sig_type; 171 return ticket->sig_type;
107 } 172 }
108 173
@@ -110,13 +175,13 @@ SignatureType Ticket::GetSignatureType() const {
110} 175}
111 176
112TicketData& Ticket::GetData() { 177TicketData& Ticket::GetData() {
113 if (auto ticket = std::get_if<RSA4096Ticket>(&data)) { 178 if (auto* ticket = std::get_if<RSA4096Ticket>(&data)) {
114 return ticket->data; 179 return ticket->data;
115 } 180 }
116 if (auto ticket = std::get_if<RSA2048Ticket>(&data)) { 181 if (auto* ticket = std::get_if<RSA2048Ticket>(&data)) {
117 return ticket->data; 182 return ticket->data;
118 } 183 }
119 if (auto ticket = std::get_if<ECDSATicket>(&data)) { 184 if (auto* ticket = std::get_if<ECDSATicket>(&data)) {
120 return ticket->data; 185 return ticket->data;
121 } 186 }
122 187
@@ -124,13 +189,13 @@ TicketData& Ticket::GetData() {
124} 189}
125 190
126const TicketData& Ticket::GetData() const { 191const TicketData& Ticket::GetData() const {
127 if (auto ticket = std::get_if<RSA4096Ticket>(&data)) { 192 if (const auto* ticket = std::get_if<RSA4096Ticket>(&data)) {
128 return ticket->data; 193 return ticket->data;
129 } 194 }
130 if (auto ticket = std::get_if<RSA2048Ticket>(&data)) { 195 if (const auto* ticket = std::get_if<RSA2048Ticket>(&data)) {
131 return ticket->data; 196 return ticket->data;
132 } 197 }
133 if (auto ticket = std::get_if<ECDSATicket>(&data)) { 198 if (const auto* ticket = std::get_if<ECDSATicket>(&data)) {
134 return ticket->data; 199 return ticket->data;
135 } 200 }
136 201
@@ -233,8 +298,9 @@ void KeyManager::DeriveGeneralPurposeKeys(std::size_t crypto_revision) {
233} 298}
234 299
235RSAKeyPair<2048> KeyManager::GetETicketRSAKey() const { 300RSAKeyPair<2048> KeyManager::GetETicketRSAKey() const {
236 if (IsAllZeroArray(eticket_extended_kek) || !HasKey(S128KeyType::ETicketRSAKek)) 301 if (IsAllZeroArray(eticket_extended_kek) || !HasKey(S128KeyType::ETicketRSAKek)) {
237 return {}; 302 return {};
303 }
238 304
239 const auto eticket_final = GetKey(S128KeyType::ETicketRSAKek); 305 const auto eticket_final = GetKey(S128KeyType::ETicketRSAKek);
240 306
@@ -261,27 +327,30 @@ Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source)
261} 327}
262 328
263std::optional<Key128> DeriveSDSeed() { 329std::optional<Key128> DeriveSDSeed() {
264 const FileUtil::IOFile save_43(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + 330 const Common::FS::IOFile save_43(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
265 "/system/save/8000000000000043", 331 "/system/save/8000000000000043",
266 "rb+"); 332 "rb+");
267 if (!save_43.IsOpen()) 333 if (!save_43.IsOpen()) {
268 return {}; 334 return std::nullopt;
335 }
269 336
270 const FileUtil::IOFile sd_private( 337 const Common::FS::IOFile sd_private(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir) +
271 FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir) + "/Nintendo/Contents/private", "rb+"); 338 "/Nintendo/Contents/private",
272 if (!sd_private.IsOpen()) 339 "rb+");
273 return {}; 340 if (!sd_private.IsOpen()) {
341 return std::nullopt;
342 }
274 343
275 std::array<u8, 0x10> private_seed{}; 344 std::array<u8, 0x10> private_seed{};
276 if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != private_seed.size()) { 345 if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != private_seed.size()) {
277 return {}; 346 return std::nullopt;
278 } 347 }
279 348
280 std::array<u8, 0x10> buffer{}; 349 std::array<u8, 0x10> buffer{};
281 std::size_t offset = 0; 350 std::size_t offset = 0;
282 for (; offset + 0x10 < save_43.GetSize(); ++offset) { 351 for (; offset + 0x10 < save_43.GetSize(); ++offset) {
283 if (!save_43.Seek(offset, SEEK_SET)) { 352 if (!save_43.Seek(offset, SEEK_SET)) {
284 return {}; 353 return std::nullopt;
285 } 354 }
286 355
287 save_43.ReadBytes(buffer.data(), buffer.size()); 356 save_43.ReadBytes(buffer.data(), buffer.size());
@@ -291,23 +360,26 @@ std::optional<Key128> DeriveSDSeed() {
291 } 360 }
292 361
293 if (!save_43.Seek(offset + 0x10, SEEK_SET)) { 362 if (!save_43.Seek(offset + 0x10, SEEK_SET)) {
294 return {}; 363 return std::nullopt;
295 } 364 }
296 365
297 Key128 seed{}; 366 Key128 seed{};
298 if (save_43.ReadBytes(seed.data(), seed.size()) != seed.size()) { 367 if (save_43.ReadBytes(seed.data(), seed.size()) != seed.size()) {
299 return {}; 368 return std::nullopt;
300 } 369 }
301 return seed; 370 return seed;
302} 371}
303 372
304Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys) { 373Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys) {
305 if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek))) 374 if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek))) {
306 return Loader::ResultStatus::ErrorMissingSDKEKSource; 375 return Loader::ResultStatus::ErrorMissingSDKEKSource;
307 if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration))) 376 }
377 if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration))) {
308 return Loader::ResultStatus::ErrorMissingAESKEKGenerationSource; 378 return Loader::ResultStatus::ErrorMissingAESKEKGenerationSource;
309 if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration))) 379 }
380 if (!keys.HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration))) {
310 return Loader::ResultStatus::ErrorMissingAESKeyGenerationSource; 381 return Loader::ResultStatus::ErrorMissingAESKeyGenerationSource;
382 }
311 383
312 const auto sd_kek_source = 384 const auto sd_kek_source =
313 keys.GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek)); 385 keys.GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek));
@@ -320,14 +392,17 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke
320 GenerateKeyEncryptionKey(sd_kek_source, master_00, aes_kek_gen, aes_key_gen); 392 GenerateKeyEncryptionKey(sd_kek_source, master_00, aes_kek_gen, aes_key_gen);
321 keys.SetKey(S128KeyType::SDKek, sd_kek); 393 keys.SetKey(S128KeyType::SDKek, sd_kek);
322 394
323 if (!keys.HasKey(S128KeyType::SDSeed)) 395 if (!keys.HasKey(S128KeyType::SDSeed)) {
324 return Loader::ResultStatus::ErrorMissingSDSeed; 396 return Loader::ResultStatus::ErrorMissingSDSeed;
397 }
325 const auto sd_seed = keys.GetKey(S128KeyType::SDSeed); 398 const auto sd_seed = keys.GetKey(S128KeyType::SDSeed);
326 399
327 if (!keys.HasKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save))) 400 if (!keys.HasKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save))) {
328 return Loader::ResultStatus::ErrorMissingSDSaveKeySource; 401 return Loader::ResultStatus::ErrorMissingSDSaveKeySource;
329 if (!keys.HasKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA))) 402 }
403 if (!keys.HasKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA))) {
330 return Loader::ResultStatus::ErrorMissingSDNCAKeySource; 404 return Loader::ResultStatus::ErrorMissingSDNCAKeySource;
405 }
331 406
332 std::array<Key256, 2> sd_key_sources{ 407 std::array<Key256, 2> sd_key_sources{
333 keys.GetKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save)), 408 keys.GetKey(S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save)),
@@ -336,8 +411,9 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke
336 411
337 // Combine sources and seed 412 // Combine sources and seed
338 for (auto& source : sd_key_sources) { 413 for (auto& source : sd_key_sources) {
339 for (std::size_t i = 0; i < source.size(); ++i) 414 for (std::size_t i = 0; i < source.size(); ++i) {
340 source[i] ^= sd_seed[i & 0xF]; 415 source[i] ^= sd_seed[i & 0xF];
416 }
341 } 417 }
342 418
343 AESCipher<Key128> cipher(sd_kek, Mode::ECB); 419 AESCipher<Key128> cipher(sd_kek, Mode::ECB);
@@ -355,9 +431,10 @@ Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& ke
355 return Loader::ResultStatus::Success; 431 return Loader::ResultStatus::Success;
356} 432}
357 433
358std::vector<Ticket> GetTicketblob(const FileUtil::IOFile& ticket_save) { 434std::vector<Ticket> GetTicketblob(const Common::FS::IOFile& ticket_save) {
359 if (!ticket_save.IsOpen()) 435 if (!ticket_save.IsOpen()) {
360 return {}; 436 return {};
437 }
361 438
362 std::vector<u8> buffer(ticket_save.GetSize()); 439 std::vector<u8> buffer(ticket_save.GetSize());
363 if (ticket_save.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) { 440 if (ticket_save.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) {
@@ -417,7 +494,7 @@ static std::optional<u64> FindTicketOffset(const std::array<u8, size>& data) {
417 offset = i + 1; 494 offset = i + 1;
418 break; 495 break;
419 } else if (data[i] != 0x0) { 496 } else if (data[i] != 0x0) {
420 return {}; 497 return std::nullopt;
421 } 498 }
422 } 499 }
423 500
@@ -427,16 +504,18 @@ static std::optional<u64> FindTicketOffset(const std::array<u8, size>& data) {
427std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket, 504std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket,
428 const RSAKeyPair<2048>& key) { 505 const RSAKeyPair<2048>& key) {
429 const auto issuer = ticket.GetData().issuer; 506 const auto issuer = ticket.GetData().issuer;
430 if (IsAllZeroArray(issuer)) 507 if (IsAllZeroArray(issuer)) {
431 return {}; 508 return std::nullopt;
509 }
432 if (issuer[0] != 'R' || issuer[1] != 'o' || issuer[2] != 'o' || issuer[3] != 't') { 510 if (issuer[0] != 'R' || issuer[1] != 'o' || issuer[2] != 'o' || issuer[3] != 't') {
433 LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority."); 511 LOG_INFO(Crypto, "Attempting to parse ticket with non-standard certificate authority.");
434 } 512 }
435 513
436 Key128 rights_id = ticket.GetData().rights_id; 514 Key128 rights_id = ticket.GetData().rights_id;
437 515
438 if (rights_id == Key128{}) 516 if (rights_id == Key128{}) {
439 return {}; 517 return std::nullopt;
518 }
440 519
441 if (!std::any_of(ticket.GetData().title_key_common_pad.begin(), 520 if (!std::any_of(ticket.GetData().title_key_common_pad.begin(),
442 ticket.GetData().title_key_common_pad.end(), [](u8 b) { return b != 0; })) { 521 ticket.GetData().title_key_common_pad.end(), [](u8 b) { return b != 0; })) {
@@ -468,15 +547,17 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket,
468 std::array<u8, 0xDF> m_2; 547 std::array<u8, 0xDF> m_2;
469 std::memcpy(m_2.data(), rsa_step.data() + 0x21, m_2.size()); 548 std::memcpy(m_2.data(), rsa_step.data() + 0x21, m_2.size());
470 549
471 if (m_0 != 0) 550 if (m_0 != 0) {
472 return {}; 551 return std::nullopt;
552 }
473 553
474 m_1 = m_1 ^ MGF1<0x20>(m_2); 554 m_1 = m_1 ^ MGF1<0x20>(m_2);
475 m_2 = m_2 ^ MGF1<0xDF>(m_1); 555 m_2 = m_2 ^ MGF1<0xDF>(m_1);
476 556
477 const auto offset = FindTicketOffset(m_2); 557 const auto offset = FindTicketOffset(m_2);
478 if (!offset) 558 if (!offset) {
479 return {}; 559 return std::nullopt;
560 }
480 ASSERT(*offset > 0); 561 ASSERT(*offset > 0);
481 562
482 Key128 key_temp{}; 563 Key128 key_temp{};
@@ -487,8 +568,8 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket,
487 568
488KeyManager::KeyManager() { 569KeyManager::KeyManager() {
489 // Initialize keys 570 // Initialize keys
490 const std::string hactool_keys_dir = FileUtil::GetHactoolConfigurationPath(); 571 const std::string hactool_keys_dir = Common::FS::GetHactoolConfigurationPath();
491 const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir); 572 const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir);
492 if (Settings::values.use_dev_keys) { 573 if (Settings::values.use_dev_keys) {
493 dev_mode = true; 574 dev_mode = true;
494 AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "dev.keys", false); 575 AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "dev.keys", false);
@@ -506,34 +587,39 @@ KeyManager::KeyManager() {
506} 587}
507 588
508static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_t length) { 589static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_t length) {
509 if (base.size() < begin + length) 590 if (base.size() < begin + length) {
510 return false; 591 return false;
592 }
511 return std::all_of(base.begin() + begin, base.begin() + begin + length, 593 return std::all_of(base.begin() + begin, base.begin() + begin + length,
512 [](u8 c) { return std::isxdigit(c); }); 594 [](u8 c) { return std::isxdigit(c); });
513} 595}
514 596
515void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { 597void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
516 std::ifstream file; 598 std::ifstream file;
517 OpenFStream(file, filename, std::ios_base::in); 599 Common::FS::OpenFStream(file, filename, std::ios_base::in);
518 if (!file.is_open()) 600 if (!file.is_open()) {
519 return; 601 return;
602 }
520 603
521 std::string line; 604 std::string line;
522 while (std::getline(file, line)) { 605 while (std::getline(file, line)) {
523 std::vector<std::string> out; 606 std::vector<std::string> out;
524 std::stringstream stream(line); 607 std::stringstream stream(line);
525 std::string item; 608 std::string item;
526 while (std::getline(stream, item, '=')) 609 while (std::getline(stream, item, '=')) {
527 out.push_back(std::move(item)); 610 out.push_back(std::move(item));
611 }
528 612
529 if (out.size() != 2) 613 if (out.size() != 2) {
530 continue; 614 continue;
615 }
531 616
532 out[0].erase(std::remove(out[0].begin(), out[0].end(), ' '), out[0].end()); 617 out[0].erase(std::remove(out[0].begin(), out[0].end(), ' '), out[0].end());
533 out[1].erase(std::remove(out[1].begin(), out[1].end(), ' '), out[1].end()); 618 out[1].erase(std::remove(out[1].begin(), out[1].end(), ' '), out[1].end());
534 619
535 if (out[0].compare(0, 1, "#") == 0) 620 if (out[0].compare(0, 1, "#") == 0) {
536 continue; 621 continue;
622 }
537 623
538 if (is_title_keys) { 624 if (is_title_keys) {
539 auto rights_id_raw = Common::HexStringToArray<16>(out[0]); 625 auto rights_id_raw = Common::HexStringToArray<16>(out[0]);
@@ -543,24 +629,26 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
543 s128_keys[{S128KeyType::Titlekey, rights_id[1], rights_id[0]}] = key; 629 s128_keys[{S128KeyType::Titlekey, rights_id[1], rights_id[0]}] = key;
544 } else { 630 } else {
545 out[0] = Common::ToLower(out[0]); 631 out[0] = Common::ToLower(out[0]);
546 if (s128_file_id.find(out[0]) != s128_file_id.end()) { 632 if (const auto iter128 = Find128ByName(out[0]); iter128 != s128_file_id.end()) {
547 const auto index = s128_file_id.at(out[0]); 633 const auto& index = iter128->second;
548 Key128 key = Common::HexStringToArray<16>(out[1]); 634 const Key128 key = Common::HexStringToArray<16>(out[1]);
549 s128_keys[{index.type, index.field1, index.field2}] = key; 635 s128_keys[{index.type, index.field1, index.field2}] = key;
550 } else if (s256_file_id.find(out[0]) != s256_file_id.end()) { 636 } else if (const auto iter256 = Find256ByName(out[0]); iter256 != s256_file_id.end()) {
551 const auto index = s256_file_id.at(out[0]); 637 const auto& index = iter256->second;
552 Key256 key = Common::HexStringToArray<32>(out[1]); 638 const Key256 key = Common::HexStringToArray<32>(out[1]);
553 s256_keys[{index.type, index.field1, index.field2}] = key; 639 s256_keys[{index.type, index.field1, index.field2}] = key;
554 } else if (out[0].compare(0, 8, "keyblob_") == 0 && 640 } else if (out[0].compare(0, 8, "keyblob_") == 0 &&
555 out[0].compare(0, 9, "keyblob_k") != 0) { 641 out[0].compare(0, 9, "keyblob_k") != 0) {
556 if (!ValidCryptoRevisionString(out[0], 8, 2)) 642 if (!ValidCryptoRevisionString(out[0], 8, 2)) {
557 continue; 643 continue;
644 }
558 645
559 const auto index = std::stoul(out[0].substr(8, 2), nullptr, 16); 646 const auto index = std::stoul(out[0].substr(8, 2), nullptr, 16);
560 keyblobs[index] = Common::HexStringToArray<0x90>(out[1]); 647 keyblobs[index] = Common::HexStringToArray<0x90>(out[1]);
561 } else if (out[0].compare(0, 18, "encrypted_keyblob_") == 0) { 648 } else if (out[0].compare(0, 18, "encrypted_keyblob_") == 0) {
562 if (!ValidCryptoRevisionString(out[0], 18, 2)) 649 if (!ValidCryptoRevisionString(out[0], 18, 2)) {
563 continue; 650 continue;
651 }
564 652
565 const auto index = std::stoul(out[0].substr(18, 2), nullptr, 16); 653 const auto index = std::stoul(out[0].substr(18, 2), nullptr, 16);
566 encrypted_keyblobs[index] = Common::HexStringToArray<0xB0>(out[1]); 654 encrypted_keyblobs[index] = Common::HexStringToArray<0xB0>(out[1]);
@@ -568,8 +656,9 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
568 eticket_extended_kek = Common::HexStringToArray<576>(out[1]); 656 eticket_extended_kek = Common::HexStringToArray<576>(out[1]);
569 } else { 657 } else {
570 for (const auto& kv : KEYS_VARIABLE_LENGTH) { 658 for (const auto& kv : KEYS_VARIABLE_LENGTH) {
571 if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2)) 659 if (!ValidCryptoRevisionString(out[0], kv.second.size(), 2)) {
572 continue; 660 continue;
661 }
573 if (out[0].compare(0, kv.second.size(), kv.second) == 0) { 662 if (out[0].compare(0, kv.second.size(), kv.second) == 0) {
574 const auto index = 663 const auto index =
575 std::stoul(out[0].substr(kv.second.size(), 2), nullptr, 16); 664 std::stoul(out[0].substr(kv.second.size(), 2), nullptr, 16);
@@ -604,10 +693,11 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) {
604 693
605void KeyManager::AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2, 694void KeyManager::AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2,
606 const std::string& filename, bool title) { 695 const std::string& filename, bool title) {
607 if (FileUtil::Exists(dir1 + DIR_SEP + filename)) 696 if (Common::FS::Exists(dir1 + DIR_SEP + filename)) {
608 LoadFromFile(dir1 + DIR_SEP + filename, title); 697 LoadFromFile(dir1 + DIR_SEP + filename, title);
609 else if (FileUtil::Exists(dir2 + DIR_SEP + filename)) 698 } else if (Common::FS::Exists(dir2 + DIR_SEP + filename)) {
610 LoadFromFile(dir2 + DIR_SEP + filename, title); 699 LoadFromFile(dir2 + DIR_SEP + filename, title);
700 }
611} 701}
612 702
613bool KeyManager::BaseDeriveNecessary() const { 703bool KeyManager::BaseDeriveNecessary() const {
@@ -615,8 +705,9 @@ bool KeyManager::BaseDeriveNecessary() const {
615 return !HasKey(key_type, index1, index2); 705 return !HasKey(key_type, index1, index2);
616 }; 706 };
617 707
618 if (check_key_existence(S256KeyType::Header)) 708 if (check_key_existence(S256KeyType::Header)) {
619 return true; 709 return true;
710 }
620 711
621 for (size_t i = 0; i < CURRENT_CRYPTO_REVISION; ++i) { 712 for (size_t i = 0; i < CURRENT_CRYPTO_REVISION; ++i) {
622 if (check_key_existence(S128KeyType::Master, i) || 713 if (check_key_existence(S128KeyType::Master, i) ||
@@ -641,14 +732,16 @@ bool KeyManager::HasKey(S256KeyType id, u64 field1, u64 field2) const {
641} 732}
642 733
643Key128 KeyManager::GetKey(S128KeyType id, u64 field1, u64 field2) const { 734Key128 KeyManager::GetKey(S128KeyType id, u64 field1, u64 field2) const {
644 if (!HasKey(id, field1, field2)) 735 if (!HasKey(id, field1, field2)) {
645 return {}; 736 return {};
737 }
646 return s128_keys.at({id, field1, field2}); 738 return s128_keys.at({id, field1, field2});
647} 739}
648 740
649Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) const { 741Key256 KeyManager::GetKey(S256KeyType id, u64 field1, u64 field2) const {
650 if (!HasKey(id, field1, field2)) 742 if (!HasKey(id, field1, field2)) {
651 return {}; 743 return {};
744 }
652 return s256_keys.at({id, field1, field2}); 745 return s256_keys.at({id, field1, field2});
653} 746}
654 747
@@ -670,7 +763,7 @@ Key256 KeyManager::GetBISKey(u8 partition_id) const {
670template <size_t Size> 763template <size_t Size>
671void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname, 764void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname,
672 const std::array<u8, Size>& key) { 765 const std::array<u8, Size>& key) {
673 const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir); 766 const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir);
674 std::string filename = "title.keys_autogenerated"; 767 std::string filename = "title.keys_autogenerated";
675 if (category == KeyCategory::Standard) { 768 if (category == KeyCategory::Standard) {
676 filename = dev_mode ? "dev.keys_autogenerated" : "prod.keys_autogenerated"; 769 filename = dev_mode ? "dev.keys_autogenerated" : "prod.keys_autogenerated";
@@ -679,9 +772,9 @@ void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname,
679 } 772 }
680 773
681 const auto path = yuzu_keys_dir + DIR_SEP + filename; 774 const auto path = yuzu_keys_dir + DIR_SEP + filename;
682 const auto add_info_text = !FileUtil::Exists(path); 775 const auto add_info_text = !Common::FS::Exists(path);
683 FileUtil::CreateFullPath(path); 776 Common::FS::CreateFullPath(path);
684 FileUtil::IOFile file{path, "a"}; 777 Common::FS::IOFile file{path, "a"};
685 if (!file.IsOpen()) { 778 if (!file.IsOpen()) {
686 return; 779 return;
687 } 780 }
@@ -714,8 +807,7 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
714 } 807 }
715 808
716 const auto iter2 = std::find_if( 809 const auto iter2 = std::find_if(
717 s128_file_id.begin(), s128_file_id.end(), 810 s128_file_id.begin(), s128_file_id.end(), [&id, &field1, &field2](const auto& elem) {
718 [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S128KeyType>> elem) {
719 return std::tie(elem.second.type, elem.second.field1, elem.second.field2) == 811 return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==
720 std::tie(id, field1, field2); 812 std::tie(id, field1, field2);
721 }); 813 });
@@ -725,9 +817,11 @@ void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) {
725 817
726 // Variable cases 818 // Variable cases
727 if (id == S128KeyType::KeyArea) { 819 if (id == S128KeyType::KeyArea) {
728 static constexpr std::array<const char*, 3> kak_names = {"key_area_key_application_{:02X}", 820 static constexpr std::array<const char*, 3> kak_names = {
729 "key_area_key_ocean_{:02X}", 821 "key_area_key_application_{:02X}",
730 "key_area_key_system_{:02X}"}; 822 "key_area_key_ocean_{:02X}",
823 "key_area_key_system_{:02X}",
824 };
731 WriteKeyToFile(category, fmt::format(kak_names.at(field2), field1), key); 825 WriteKeyToFile(category, fmt::format(kak_names.at(field2), field1), key);
732 } else if (id == S128KeyType::Master) { 826 } else if (id == S128KeyType::Master) {
733 WriteKeyToFile(category, fmt::format("master_key_{:02X}", field1), key); 827 WriteKeyToFile(category, fmt::format("master_key_{:02X}", field1), key);
@@ -753,8 +847,7 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
753 return; 847 return;
754 } 848 }
755 const auto iter = std::find_if( 849 const auto iter = std::find_if(
756 s256_file_id.begin(), s256_file_id.end(), 850 s256_file_id.begin(), s256_file_id.end(), [&id, &field1, &field2](const auto& elem) {
757 [&id, &field1, &field2](const std::pair<std::string, KeyIndex<S256KeyType>> elem) {
758 return std::tie(elem.second.type, elem.second.field1, elem.second.field2) == 851 return std::tie(elem.second.type, elem.second.field1, elem.second.field2) ==
759 std::tie(id, field1, field2); 852 std::tie(id, field1, field2);
760 }); 853 });
@@ -765,29 +858,31 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) {
765} 858}
766 859
767bool KeyManager::KeyFileExists(bool title) { 860bool KeyManager::KeyFileExists(bool title) {
768 const std::string hactool_keys_dir = FileUtil::GetHactoolConfigurationPath(); 861 const std::string hactool_keys_dir = Common::FS::GetHactoolConfigurationPath();
769 const std::string yuzu_keys_dir = FileUtil::GetUserPath(FileUtil::UserPath::KeysDir); 862 const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir);
770 if (title) { 863 if (title) {
771 return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "title.keys") || 864 return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "title.keys") ||
772 FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "title.keys"); 865 Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "title.keys");
773 } 866 }
774 867
775 if (Settings::values.use_dev_keys) { 868 if (Settings::values.use_dev_keys) {
776 return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "dev.keys") || 869 return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "dev.keys") ||
777 FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "dev.keys"); 870 Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "dev.keys");
778 } 871 }
779 872
780 return FileUtil::Exists(hactool_keys_dir + DIR_SEP + "prod.keys") || 873 return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "prod.keys") ||
781 FileUtil::Exists(yuzu_keys_dir + DIR_SEP + "prod.keys"); 874 Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "prod.keys");
782} 875}
783 876
784void KeyManager::DeriveSDSeedLazy() { 877void KeyManager::DeriveSDSeedLazy() {
785 if (HasKey(S128KeyType::SDSeed)) 878 if (HasKey(S128KeyType::SDSeed)) {
786 return; 879 return;
880 }
787 881
788 const auto res = DeriveSDSeed(); 882 const auto res = DeriveSDSeed();
789 if (res) 883 if (res) {
790 SetKey(S128KeyType::SDSeed, *res); 884 SetKey(S128KeyType::SDSeed, *res);
885 }
791} 886}
792 887
793static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) { 888static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) {
@@ -799,11 +894,13 @@ static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) {
799} 894}
800 895
801void KeyManager::DeriveBase() { 896void KeyManager::DeriveBase() {
802 if (!BaseDeriveNecessary()) 897 if (!BaseDeriveNecessary()) {
803 return; 898 return;
899 }
804 900
805 if (!HasKey(S128KeyType::SecureBoot) || !HasKey(S128KeyType::TSEC)) 901 if (!HasKey(S128KeyType::SecureBoot) || !HasKey(S128KeyType::TSEC)) {
806 return; 902 return;
903 }
807 904
808 const auto has_bis = [this](u64 id) { 905 const auto has_bis = [this](u64 id) {
809 return HasKey(S128KeyType::BIS, id, static_cast<u64>(BISKeyType::Crypto)) && 906 return HasKey(S128KeyType::BIS, id, static_cast<u64>(BISKeyType::Crypto)) &&
@@ -820,10 +917,11 @@ void KeyManager::DeriveBase() {
820 static_cast<u64>(BISKeyType::Tweak)); 917 static_cast<u64>(BISKeyType::Tweak));
821 }; 918 };
822 919
823 if (has_bis(2) && !has_bis(3)) 920 if (has_bis(2) && !has_bis(3)) {
824 copy_bis(2, 3); 921 copy_bis(2, 3);
825 else if (has_bis(3) && !has_bis(2)) 922 } else if (has_bis(3) && !has_bis(2)) {
826 copy_bis(3, 2); 923 copy_bis(3, 2);
924 }
827 925
828 std::bitset<32> revisions(0xFFFFFFFF); 926 std::bitset<32> revisions(0xFFFFFFFF);
829 for (size_t i = 0; i < revisions.size(); ++i) { 927 for (size_t i = 0; i < revisions.size(); ++i) {
@@ -833,15 +931,17 @@ void KeyManager::DeriveBase() {
833 } 931 }
834 } 932 }
835 933
836 if (!revisions.any()) 934 if (!revisions.any()) {
837 return; 935 return;
936 }
838 937
839 const auto sbk = GetKey(S128KeyType::SecureBoot); 938 const auto sbk = GetKey(S128KeyType::SecureBoot);
840 const auto tsec = GetKey(S128KeyType::TSEC); 939 const auto tsec = GetKey(S128KeyType::TSEC);
841 940
842 for (size_t i = 0; i < revisions.size(); ++i) { 941 for (size_t i = 0; i < revisions.size(); ++i) {
843 if (!revisions[i]) 942 if (!revisions[i]) {
844 continue; 943 continue;
944 }
845 945
846 // Derive keyblob key 946 // Derive keyblob key
847 const auto key = DeriveKeyblobKey( 947 const auto key = DeriveKeyblobKey(
@@ -850,16 +950,18 @@ void KeyManager::DeriveBase() {
850 SetKey(S128KeyType::Keyblob, key, i); 950 SetKey(S128KeyType::Keyblob, key, i);
851 951
852 // Derive keyblob MAC key 952 // Derive keyblob MAC key
853 if (!HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC))) 953 if (!HasKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC))) {
854 continue; 954 continue;
955 }
855 956
856 const auto mac_key = DeriveKeyblobMACKey( 957 const auto mac_key = DeriveKeyblobMACKey(
857 key, GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC))); 958 key, GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC)));
858 SetKey(S128KeyType::KeyblobMAC, mac_key, i); 959 SetKey(S128KeyType::KeyblobMAC, mac_key, i);
859 960
860 Key128 cmac = CalculateCMAC(encrypted_keyblobs[i].data() + 0x10, 0xA0, mac_key); 961 Key128 cmac = CalculateCMAC(encrypted_keyblobs[i].data() + 0x10, 0xA0, mac_key);
861 if (std::memcmp(cmac.data(), encrypted_keyblobs[i].data(), cmac.size()) != 0) 962 if (std::memcmp(cmac.data(), encrypted_keyblobs[i].data(), cmac.size()) != 0) {
862 continue; 963 continue;
964 }
863 965
864 // Decrypt keyblob 966 // Decrypt keyblob
865 if (keyblobs[i] == std::array<u8, 0x90>{}) { 967 if (keyblobs[i] == std::array<u8, 0x90>{}) {
@@ -883,16 +985,19 @@ void KeyManager::DeriveBase() {
883 985
884 revisions.set(); 986 revisions.set();
885 for (size_t i = 0; i < revisions.size(); ++i) { 987 for (size_t i = 0; i < revisions.size(); ++i) {
886 if (!HasKey(S128KeyType::Master, i)) 988 if (!HasKey(S128KeyType::Master, i)) {
887 revisions.reset(i); 989 revisions.reset(i);
990 }
888 } 991 }
889 992
890 if (!revisions.any()) 993 if (!revisions.any()) {
891 return; 994 return;
995 }
892 996
893 for (size_t i = 0; i < revisions.size(); ++i) { 997 for (size_t i = 0; i < revisions.size(); ++i) {
894 if (!revisions[i]) 998 if (!revisions[i]) {
895 continue; 999 continue;
1000 }
896 1001
897 // Derive general purpose keys 1002 // Derive general purpose keys
898 DeriveGeneralPurposeKeys(i); 1003 DeriveGeneralPurposeKeys(i);
@@ -922,16 +1027,19 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
922 const auto es = Core::System::GetInstance().GetContentProvider().GetEntry( 1027 const auto es = Core::System::GetInstance().GetContentProvider().GetEntry(
923 0x0100000000000033, FileSys::ContentRecordType::Program); 1028 0x0100000000000033, FileSys::ContentRecordType::Program);
924 1029
925 if (es == nullptr) 1030 if (es == nullptr) {
926 return; 1031 return;
1032 }
927 1033
928 const auto exefs = es->GetExeFS(); 1034 const auto exefs = es->GetExeFS();
929 if (exefs == nullptr) 1035 if (exefs == nullptr) {
930 return; 1036 return;
1037 }
931 1038
932 const auto main = exefs->GetFile("main"); 1039 const auto main = exefs->GetFile("main");
933 if (main == nullptr) 1040 if (main == nullptr) {
934 return; 1041 return;
1042 }
935 1043
936 const auto bytes = main->ReadAllBytes(); 1044 const auto bytes = main->ReadAllBytes();
937 1045
@@ -941,16 +1049,19 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
941 const auto seed3 = data.GetRSAKekSeed3(); 1049 const auto seed3 = data.GetRSAKekSeed3();
942 const auto mask0 = data.GetRSAKekMask0(); 1050 const auto mask0 = data.GetRSAKekMask0();
943 1051
944 if (eticket_kek != Key128{}) 1052 if (eticket_kek != Key128{}) {
945 SetKey(S128KeyType::Source, eticket_kek, static_cast<size_t>(SourceKeyType::ETicketKek)); 1053 SetKey(S128KeyType::Source, eticket_kek, static_cast<size_t>(SourceKeyType::ETicketKek));
1054 }
946 if (eticket_kekek != Key128{}) { 1055 if (eticket_kekek != Key128{}) {
947 SetKey(S128KeyType::Source, eticket_kekek, 1056 SetKey(S128KeyType::Source, eticket_kekek,
948 static_cast<size_t>(SourceKeyType::ETicketKekek)); 1057 static_cast<size_t>(SourceKeyType::ETicketKekek));
949 } 1058 }
950 if (seed3 != Key128{}) 1059 if (seed3 != Key128{}) {
951 SetKey(S128KeyType::RSAKek, seed3, static_cast<size_t>(RSAKekType::Seed3)); 1060 SetKey(S128KeyType::RSAKek, seed3, static_cast<size_t>(RSAKekType::Seed3));
952 if (mask0 != Key128{}) 1061 }
1062 if (mask0 != Key128{}) {
953 SetKey(S128KeyType::RSAKek, mask0, static_cast<size_t>(RSAKekType::Mask0)); 1063 SetKey(S128KeyType::RSAKek, mask0, static_cast<size_t>(RSAKekType::Mask0));
1064 }
954 if (eticket_kek == Key128{} || eticket_kekek == Key128{} || seed3 == Key128{} || 1065 if (eticket_kek == Key128{} || eticket_kekek == Key128{} || seed3 == Key128{} ||
955 mask0 == Key128{}) { 1066 mask0 == Key128{}) {
956 return; 1067 return;
@@ -976,8 +1087,9 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
976 AESCipher<Key128> es_kek(temp_kekek, Mode::ECB); 1087 AESCipher<Key128> es_kek(temp_kekek, Mode::ECB);
977 es_kek.Transcode(eticket_kek.data(), eticket_kek.size(), eticket_final.data(), Op::Decrypt); 1088 es_kek.Transcode(eticket_kek.data(), eticket_kek.size(), eticket_final.data(), Op::Decrypt);
978 1089
979 if (eticket_final == Key128{}) 1090 if (eticket_final == Key128{}) {
980 return; 1091 return;
1092 }
981 1093
982 SetKey(S128KeyType::ETicketRSAKek, eticket_final); 1094 SetKey(S128KeyType::ETicketRSAKek, eticket_final);
983 1095
@@ -992,18 +1104,20 @@ void KeyManager::DeriveETicket(PartitionDataManager& data) {
992void KeyManager::PopulateTickets() { 1104void KeyManager::PopulateTickets() {
993 const auto rsa_key = GetETicketRSAKey(); 1105 const auto rsa_key = GetETicketRSAKey();
994 1106
995 if (rsa_key == RSAKeyPair<2048>{}) 1107 if (rsa_key == RSAKeyPair<2048>{}) {
996 return; 1108 return;
1109 }
997 1110
998 if (!common_tickets.empty() && !personal_tickets.empty()) 1111 if (!common_tickets.empty() && !personal_tickets.empty()) {
999 return; 1112 return;
1113 }
1000 1114
1001 const FileUtil::IOFile save1(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + 1115 const Common::FS::IOFile save1(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
1002 "/system/save/80000000000000e1", 1116 "/system/save/80000000000000e1",
1003 "rb+"); 1117 "rb+");
1004 const FileUtil::IOFile save2(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + 1118 const Common::FS::IOFile save2(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
1005 "/system/save/80000000000000e2", 1119 "/system/save/80000000000000e2",
1006 "rb+"); 1120 "rb+");
1007 1121
1008 const auto blob2 = GetTicketblob(save2); 1122 const auto blob2 = GetTicketblob(save2);
1009 auto res = GetTicketblob(save1); 1123 auto res = GetTicketblob(save1);
@@ -1013,8 +1127,10 @@ void KeyManager::PopulateTickets() {
1013 for (std::size_t i = 0; i < res.size(); ++i) { 1127 for (std::size_t i = 0; i < res.size(); ++i) {
1014 const auto common = i < idx; 1128 const auto common = i < idx;
1015 const auto pair = ParseTicket(res[i], rsa_key); 1129 const auto pair = ParseTicket(res[i], rsa_key);
1016 if (!pair) 1130 if (!pair) {
1017 continue; 1131 continue;
1132 }
1133
1018 const auto& [rid, key] = *pair; 1134 const auto& [rid, key] = *pair;
1019 u128 rights_id; 1135 u128 rights_id;
1020 std::memcpy(rights_id.data(), rid.data(), rid.size()); 1136 std::memcpy(rights_id.data(), rid.data(), rid.size());
@@ -1043,27 +1159,33 @@ void KeyManager::SynthesizeTickets() {
1043} 1159}
1044 1160
1045void KeyManager::SetKeyWrapped(S128KeyType id, Key128 key, u64 field1, u64 field2) { 1161void KeyManager::SetKeyWrapped(S128KeyType id, Key128 key, u64 field1, u64 field2) {
1046 if (key == Key128{}) 1162 if (key == Key128{}) {
1047 return; 1163 return;
1164 }
1048 SetKey(id, key, field1, field2); 1165 SetKey(id, key, field1, field2);
1049} 1166}
1050 1167
1051void KeyManager::SetKeyWrapped(S256KeyType id, Key256 key, u64 field1, u64 field2) { 1168void KeyManager::SetKeyWrapped(S256KeyType id, Key256 key, u64 field1, u64 field2) {
1052 if (key == Key256{}) 1169 if (key == Key256{}) {
1053 return; 1170 return;
1171 }
1172
1054 SetKey(id, key, field1, field2); 1173 SetKey(id, key, field1, field2);
1055} 1174}
1056 1175
1057void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) { 1176void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
1058 if (!BaseDeriveNecessary()) 1177 if (!BaseDeriveNecessary()) {
1059 return; 1178 return;
1179 }
1060 1180
1061 if (!data.HasBoot0()) 1181 if (!data.HasBoot0()) {
1062 return; 1182 return;
1183 }
1063 1184
1064 for (size_t i = 0; i < encrypted_keyblobs.size(); ++i) { 1185 for (size_t i = 0; i < encrypted_keyblobs.size(); ++i) {
1065 if (encrypted_keyblobs[i] != std::array<u8, 0xB0>{}) 1186 if (encrypted_keyblobs[i] != std::array<u8, 0xB0>{}) {
1066 continue; 1187 continue;
1188 }
1067 encrypted_keyblobs[i] = data.GetEncryptedKeyblob(i); 1189 encrypted_keyblobs[i] = data.GetEncryptedKeyblob(i);
1068 WriteKeyToFile<0xB0>(KeyCategory::Console, fmt::format("encrypted_keyblob_{:02X}", i), 1190 WriteKeyToFile<0xB0>(KeyCategory::Console, fmt::format("encrypted_keyblob_{:02X}", i),
1069 encrypted_keyblobs[i]); 1191 encrypted_keyblobs[i]);
@@ -1085,8 +1207,9 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
1085 static_cast<u64>(SourceKeyType::Keyblob), i); 1207 static_cast<u64>(SourceKeyType::Keyblob), i);
1086 } 1208 }
1087 1209
1088 if (data.HasFuses()) 1210 if (data.HasFuses()) {
1089 SetKeyWrapped(S128KeyType::SecureBoot, data.GetSecureBootKey()); 1211 SetKeyWrapped(S128KeyType::SecureBoot, data.GetSecureBootKey());
1212 }
1090 1213
1091 DeriveBase(); 1214 DeriveBase();
1092 1215
@@ -1100,8 +1223,9 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
1100 1223
1101 const auto masters = data.GetTZMasterKeys(latest_master); 1224 const auto masters = data.GetTZMasterKeys(latest_master);
1102 for (size_t i = 0; i < masters.size(); ++i) { 1225 for (size_t i = 0; i < masters.size(); ++i) {
1103 if (masters[i] != Key128{} && !HasKey(S128KeyType::Master, i)) 1226 if (masters[i] != Key128{} && !HasKey(S128KeyType::Master, i)) {
1104 SetKey(S128KeyType::Master, masters[i], i); 1227 SetKey(S128KeyType::Master, masters[i], i);
1228 }
1105 } 1229 }
1106 1230
1107 DeriveBase(); 1231 DeriveBase();
@@ -1111,8 +1235,9 @@ void KeyManager::PopulateFromPartitionData(PartitionDataManager& data) {
1111 1235
1112 std::array<Key128, 0x20> package2_keys{}; 1236 std::array<Key128, 0x20> package2_keys{};
1113 for (size_t i = 0; i < package2_keys.size(); ++i) { 1237 for (size_t i = 0; i < package2_keys.size(); ++i) {
1114 if (HasKey(S128KeyType::Package2, i)) 1238 if (HasKey(S128KeyType::Package2, i)) {
1115 package2_keys[i] = GetKey(S128KeyType::Package2, i); 1239 package2_keys[i] = GetKey(S128KeyType::Package2, i);
1240 }
1116 } 1241 }
1117 data.DecryptPackage2(package2_keys, Package2Type::NormalMain); 1242 data.DecryptPackage2(package2_keys, Package2Type::NormalMain);
1118 1243
@@ -1150,12 +1275,15 @@ const std::map<u128, Ticket>& KeyManager::GetPersonalizedTickets() const {
1150 1275
1151bool KeyManager::AddTicketCommon(Ticket raw) { 1276bool KeyManager::AddTicketCommon(Ticket raw) {
1152 const auto rsa_key = GetETicketRSAKey(); 1277 const auto rsa_key = GetETicketRSAKey();
1153 if (rsa_key == RSAKeyPair<2048>{}) 1278 if (rsa_key == RSAKeyPair<2048>{}) {
1154 return false; 1279 return false;
1280 }
1155 1281
1156 const auto pair = ParseTicket(raw, rsa_key); 1282 const auto pair = ParseTicket(raw, rsa_key);
1157 if (!pair) 1283 if (!pair) {
1158 return false; 1284 return false;
1285 }
1286
1159 const auto& [rid, key] = *pair; 1287 const auto& [rid, key] = *pair;
1160 u128 rights_id; 1288 u128 rights_id;
1161 std::memcpy(rights_id.data(), rid.data(), rid.size()); 1289 std::memcpy(rights_id.data(), rid.data(), rid.size());
@@ -1166,12 +1294,15 @@ bool KeyManager::AddTicketCommon(Ticket raw) {
1166 1294
1167bool KeyManager::AddTicketPersonalized(Ticket raw) { 1295bool KeyManager::AddTicketPersonalized(Ticket raw) {
1168 const auto rsa_key = GetETicketRSAKey(); 1296 const auto rsa_key = GetETicketRSAKey();
1169 if (rsa_key == RSAKeyPair<2048>{}) 1297 if (rsa_key == RSAKeyPair<2048>{}) {
1170 return false; 1298 return false;
1299 }
1171 1300
1172 const auto pair = ParseTicket(raw, rsa_key); 1301 const auto pair = ParseTicket(raw, rsa_key);
1173 if (!pair) 1302 if (!pair) {
1174 return false; 1303 return false;
1304 }
1305
1175 const auto& [rid, key] = *pair; 1306 const auto& [rid, key] = *pair;
1176 u128 rights_id; 1307 u128 rights_id;
1177 std::memcpy(rights_id.data(), rid.data(), rid.size()); 1308 std::memcpy(rights_id.data(), rid.data(), rid.size());
@@ -1179,58 +1310,4 @@ bool KeyManager::AddTicketPersonalized(Ticket raw) {
1179 SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]); 1310 SetKey(S128KeyType::Titlekey, key, rights_id[1], rights_id[0]);
1180 return true; 1311 return true;
1181} 1312}
1182
1183const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> KeyManager::s128_file_id = {
1184 {"eticket_rsa_kek", {S128KeyType::ETicketRSAKek, 0, 0}},
1185 {"eticket_rsa_kek_source",
1186 {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKek), 0}},
1187 {"eticket_rsa_kekek_source",
1188 {S128KeyType::Source, static_cast<u64>(SourceKeyType::ETicketKekek), 0}},
1189 {"rsa_kek_mask_0", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Mask0), 0}},
1190 {"rsa_kek_seed_3", {S128KeyType::RSAKek, static_cast<u64>(RSAKekType::Seed3), 0}},
1191 {"rsa_oaep_kek_generation_source",
1192 {S128KeyType::Source, static_cast<u64>(SourceKeyType::RSAOaepKekGeneration), 0}},
1193 {"sd_card_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::SDKek), 0}},
1194 {"aes_kek_generation_source",
1195 {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKekGeneration), 0}},
1196 {"aes_key_generation_source",
1197 {S128KeyType::Source, static_cast<u64>(SourceKeyType::AESKeyGeneration), 0}},
1198 {"package2_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Package2), 0}},
1199 {"master_key_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Master), 0}},
1200 {"header_kek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::HeaderKek), 0}},
1201 {"key_area_key_application_source",
1202 {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
1203 static_cast<u64>(KeyAreaKeyType::Application)}},
1204 {"key_area_key_ocean_source",
1205 {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
1206 static_cast<u64>(KeyAreaKeyType::Ocean)}},
1207 {"key_area_key_system_source",
1208 {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyAreaKey),
1209 static_cast<u64>(KeyAreaKeyType::System)}},
1210 {"titlekek_source", {S128KeyType::Source, static_cast<u64>(SourceKeyType::Titlekek), 0}},
1211 {"keyblob_mac_key_source",
1212 {S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC), 0}},
1213 {"tsec_key", {S128KeyType::TSEC, 0, 0}},
1214 {"secure_boot_key", {S128KeyType::SecureBoot, 0, 0}},
1215 {"sd_seed", {S128KeyType::SDSeed, 0, 0}},
1216 {"bis_key_0_crypt", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Crypto)}},
1217 {"bis_key_0_tweak", {S128KeyType::BIS, 0, static_cast<u64>(BISKeyType::Tweak)}},
1218 {"bis_key_1_crypt", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Crypto)}},
1219 {"bis_key_1_tweak", {S128KeyType::BIS, 1, static_cast<u64>(BISKeyType::Tweak)}},
1220 {"bis_key_2_crypt", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Crypto)}},
1221 {"bis_key_2_tweak", {S128KeyType::BIS, 2, static_cast<u64>(BISKeyType::Tweak)}},
1222 {"bis_key_3_crypt", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Crypto)}},
1223 {"bis_key_3_tweak", {S128KeyType::BIS, 3, static_cast<u64>(BISKeyType::Tweak)}},
1224 {"header_kek", {S128KeyType::HeaderKek, 0, 0}},
1225 {"sd_card_kek", {S128KeyType::SDKek, 0, 0}},
1226};
1227
1228const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> KeyManager::s256_file_id = {
1229 {"header_key", {S256KeyType::Header, 0, 0}},
1230 {"sd_card_save_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::Save), 0}},
1231 {"sd_card_nca_key_source", {S256KeyType::SDKeySource, static_cast<u64>(SDKeyType::NCA), 0}},
1232 {"header_key_source", {S256KeyType::HeaderSource, 0, 0}},
1233 {"sd_card_save_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::Save), 0}},
1234 {"sd_card_nca_key", {S256KeyType::SDKey, static_cast<u64>(SDKeyType::NCA), 0}},
1235};
1236} // namespace Core::Crypto 1313} // namespace Core::Crypto
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h
index 9269a73f2..321b75323 100644
--- a/src/core/crypto/key_manager.h
+++ b/src/core/crypto/key_manager.h
@@ -10,14 +10,13 @@
10#include <string> 10#include <string>
11 11
12#include <variant> 12#include <variant>
13#include <boost/container/flat_map.hpp>
14#include <fmt/format.h> 13#include <fmt/format.h>
15#include "common/common_funcs.h" 14#include "common/common_funcs.h"
16#include "common/common_types.h" 15#include "common/common_types.h"
17#include "core/crypto/partition_data_manager.h" 16#include "core/crypto/partition_data_manager.h"
18#include "core/file_sys/vfs_types.h" 17#include "core/file_sys/vfs_types.h"
19 18
20namespace FileUtil { 19namespace Common::FS {
21class IOFile; 20class IOFile;
22} 21}
23 22
@@ -293,9 +292,6 @@ private:
293 292
294 void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0); 293 void SetKeyWrapped(S128KeyType id, Key128 key, u64 field1 = 0, u64 field2 = 0);
295 void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0); 294 void SetKeyWrapped(S256KeyType id, Key256 key, u64 field1 = 0, u64 field2 = 0);
296
297 static const boost::container::flat_map<std::string, KeyIndex<S128KeyType>> s128_file_id;
298 static const boost::container::flat_map<std::string, KeyIndex<S256KeyType>> s256_file_id;
299}; 295};
300 296
301Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed); 297Key128 GenerateKeyEncryptionKey(Key128 source, Key128 master, Key128 kek_seed, Key128 key_seed);
@@ -308,7 +304,7 @@ std::array<u8, 0x90> DecryptKeyblob(const std::array<u8, 0xB0>& encrypted_keyblo
308std::optional<Key128> DeriveSDSeed(); 304std::optional<Key128> DeriveSDSeed();
309Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys); 305Loader::ResultStatus DeriveSDKeys(std::array<Key256, 2>& sd_keys, KeyManager& keys);
310 306
311std::vector<Ticket> GetTicketblob(const FileUtil::IOFile& ticket_save); 307std::vector<Ticket> GetTicketblob(const Common::FS::IOFile& ticket_save);
312 308
313// Returns a pair of {rights_id, titlekey}. Fails if the ticket has no certificate authority 309// Returns a pair of {rights_id, titlekey}. Fails if the ticket has no certificate authority
314// (offset 0x140-0x144 is zero) 310// (offset 0x140-0x144 is zero)
diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp
index 3e96f7516..46136d04a 100644
--- a/src/core/crypto/partition_data_manager.cpp
+++ b/src/core/crypto/partition_data_manager.cpp
@@ -367,8 +367,8 @@ static bool AttemptDecrypt(const std::array<u8, 16>& key, Package2Header& header
367 Package2Header temp = header; 367 Package2Header temp = header;
368 AESCipher<Key128> cipher(key, Mode::CTR); 368 AESCipher<Key128> cipher(key, Mode::CTR);
369 cipher.SetIV(header.header_ctr); 369 cipher.SetIV(header.header_ctr);
370 cipher.Transcode(&temp.header_ctr, sizeof(Package2Header) - 0x100, &temp.header_ctr, 370 cipher.Transcode(&temp.header_ctr, sizeof(Package2Header) - sizeof(Package2Header::signature),
371 Op::Decrypt); 371 &temp.header_ctr, Op::Decrypt);
372 if (temp.magic == Common::MakeMagic('P', 'K', '2', '1')) { 372 if (temp.magic == Common::MakeMagic('P', 'K', '2', '1')) {
373 header = temp; 373 header = temp;
374 return true; 374 return true;
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
index 285277ef8..9ffda2e14 100644
--- a/src/core/file_sys/bis_factory.cpp
+++ b/src/core/file_sys/bis_factory.cpp
@@ -86,7 +86,7 @@ VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id) const {
86 auto& keys = Core::Crypto::KeyManager::Instance(); 86 auto& keys = Core::Crypto::KeyManager::Instance();
87 Core::Crypto::PartitionDataManager pdm{ 87 Core::Crypto::PartitionDataManager pdm{
88 Core::System::GetInstance().GetFilesystem()->OpenDirectory( 88 Core::System::GetInstance().GetFilesystem()->OpenDirectory(
89 FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), Mode::Read)}; 89 Common::FS::GetUserPath(Common::FS::UserPath::SysDataDir), Mode::Read)};
90 keys.PopulateFromPartitionData(pdm); 90 keys.PopulateFromPartitionData(pdm);
91 91
92 switch (id) { 92 switch (id) {
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index f831487dd..e42b677f7 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -728,7 +728,7 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
728 LOG_WARNING(Loader, "Overwriting existing NCA..."); 728 LOG_WARNING(Loader, "Overwriting existing NCA...");
729 VirtualDir c_dir; 729 VirtualDir c_dir;
730 { c_dir = dir->GetFileRelative(path)->GetContainingDirectory(); } 730 { c_dir = dir->GetFileRelative(path)->GetContainingDirectory(); }
731 c_dir->DeleteFile(FileUtil::GetFilename(path)); 731 c_dir->DeleteFile(Common::FS::GetFilename(path));
732 } 732 }
733 733
734 auto out = dir->CreateFileRelative(path); 734 auto out = dir->CreateFileRelative(path);
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp
index e33327ef0..a4c3f67c4 100644
--- a/src/core/file_sys/vfs.cpp
+++ b/src/core/file_sys/vfs.cpp
@@ -30,7 +30,7 @@ bool VfsFilesystem::IsWritable() const {
30} 30}
31 31
32VfsEntryType VfsFilesystem::GetEntryType(std::string_view path_) const { 32VfsEntryType VfsFilesystem::GetEntryType(std::string_view path_) const {
33 const auto path = FileUtil::SanitizePath(path_); 33 const auto path = Common::FS::SanitizePath(path_);
34 if (root->GetFileRelative(path) != nullptr) 34 if (root->GetFileRelative(path) != nullptr)
35 return VfsEntryType::File; 35 return VfsEntryType::File;
36 if (root->GetDirectoryRelative(path) != nullptr) 36 if (root->GetDirectoryRelative(path) != nullptr)
@@ -40,22 +40,22 @@ VfsEntryType VfsFilesystem::GetEntryType(std::string_view path_) const {
40} 40}
41 41
42VirtualFile VfsFilesystem::OpenFile(std::string_view path_, Mode perms) { 42VirtualFile VfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
43 const auto path = FileUtil::SanitizePath(path_); 43 const auto path = Common::FS::SanitizePath(path_);
44 return root->GetFileRelative(path); 44 return root->GetFileRelative(path);
45} 45}
46 46
47VirtualFile VfsFilesystem::CreateFile(std::string_view path_, Mode perms) { 47VirtualFile VfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
48 const auto path = FileUtil::SanitizePath(path_); 48 const auto path = Common::FS::SanitizePath(path_);
49 return root->CreateFileRelative(path); 49 return root->CreateFileRelative(path);
50} 50}
51 51
52VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) { 52VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) {
53 const auto old_path = FileUtil::SanitizePath(old_path_); 53 const auto old_path = Common::FS::SanitizePath(old_path_);
54 const auto new_path = FileUtil::SanitizePath(new_path_); 54 const auto new_path = Common::FS::SanitizePath(new_path_);
55 55
56 // VfsDirectory impls are only required to implement copy across the current directory. 56 // VfsDirectory impls are only required to implement copy across the current directory.
57 if (FileUtil::GetParentPath(old_path) == FileUtil::GetParentPath(new_path)) { 57 if (Common::FS::GetParentPath(old_path) == Common::FS::GetParentPath(new_path)) {
58 if (!root->Copy(FileUtil::GetFilename(old_path), FileUtil::GetFilename(new_path))) 58 if (!root->Copy(Common::FS::GetFilename(old_path), Common::FS::GetFilename(new_path)))
59 return nullptr; 59 return nullptr;
60 return OpenFile(new_path, Mode::ReadWrite); 60 return OpenFile(new_path, Mode::ReadWrite);
61 } 61 }
@@ -76,8 +76,8 @@ VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view
76} 76}
77 77
78VirtualFile VfsFilesystem::MoveFile(std::string_view old_path, std::string_view new_path) { 78VirtualFile VfsFilesystem::MoveFile(std::string_view old_path, std::string_view new_path) {
79 const auto sanitized_old_path = FileUtil::SanitizePath(old_path); 79 const auto sanitized_old_path = Common::FS::SanitizePath(old_path);
80 const auto sanitized_new_path = FileUtil::SanitizePath(new_path); 80 const auto sanitized_new_path = Common::FS::SanitizePath(new_path);
81 81
82 // Again, non-default impls are highly encouraged to provide a more optimized version of this. 82 // Again, non-default impls are highly encouraged to provide a more optimized version of this.
83 auto out = CopyFile(sanitized_old_path, sanitized_new_path); 83 auto out = CopyFile(sanitized_old_path, sanitized_new_path);
@@ -89,26 +89,26 @@ VirtualFile VfsFilesystem::MoveFile(std::string_view old_path, std::string_view
89} 89}
90 90
91bool VfsFilesystem::DeleteFile(std::string_view path_) { 91bool VfsFilesystem::DeleteFile(std::string_view path_) {
92 const auto path = FileUtil::SanitizePath(path_); 92 const auto path = Common::FS::SanitizePath(path_);
93 auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write); 93 auto parent = OpenDirectory(Common::FS::GetParentPath(path), Mode::Write);
94 if (parent == nullptr) 94 if (parent == nullptr)
95 return false; 95 return false;
96 return parent->DeleteFile(FileUtil::GetFilename(path)); 96 return parent->DeleteFile(Common::FS::GetFilename(path));
97} 97}
98 98
99VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) { 99VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) {
100 const auto path = FileUtil::SanitizePath(path_); 100 const auto path = Common::FS::SanitizePath(path_);
101 return root->GetDirectoryRelative(path); 101 return root->GetDirectoryRelative(path);
102} 102}
103 103
104VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { 104VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) {
105 const auto path = FileUtil::SanitizePath(path_); 105 const auto path = Common::FS::SanitizePath(path_);
106 return root->CreateDirectoryRelative(path); 106 return root->CreateDirectoryRelative(path);
107} 107}
108 108
109VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_view new_path_) { 109VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_view new_path_) {
110 const auto old_path = FileUtil::SanitizePath(old_path_); 110 const auto old_path = Common::FS::SanitizePath(old_path_);
111 const auto new_path = FileUtil::SanitizePath(new_path_); 111 const auto new_path = Common::FS::SanitizePath(new_path_);
112 112
113 // Non-default impls are highly encouraged to provide a more optimized version of this. 113 // Non-default impls are highly encouraged to provide a more optimized version of this.
114 auto old_dir = OpenDirectory(old_path, Mode::Read); 114 auto old_dir = OpenDirectory(old_path, Mode::Read);
@@ -139,8 +139,8 @@ VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_
139} 139}
140 140
141VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path, std::string_view new_path) { 141VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path, std::string_view new_path) {
142 const auto sanitized_old_path = FileUtil::SanitizePath(old_path); 142 const auto sanitized_old_path = Common::FS::SanitizePath(old_path);
143 const auto sanitized_new_path = FileUtil::SanitizePath(new_path); 143 const auto sanitized_new_path = Common::FS::SanitizePath(new_path);
144 144
145 // Non-default impls are highly encouraged to provide a more optimized version of this. 145 // Non-default impls are highly encouraged to provide a more optimized version of this.
146 auto out = CopyDirectory(sanitized_old_path, sanitized_new_path); 146 auto out = CopyDirectory(sanitized_old_path, sanitized_new_path);
@@ -152,17 +152,17 @@ VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path, std::string_v
152} 152}
153 153
154bool VfsFilesystem::DeleteDirectory(std::string_view path_) { 154bool VfsFilesystem::DeleteDirectory(std::string_view path_) {
155 const auto path = FileUtil::SanitizePath(path_); 155 const auto path = Common::FS::SanitizePath(path_);
156 auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write); 156 auto parent = OpenDirectory(Common::FS::GetParentPath(path), Mode::Write);
157 if (parent == nullptr) 157 if (parent == nullptr)
158 return false; 158 return false;
159 return parent->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path)); 159 return parent->DeleteSubdirectoryRecursive(Common::FS::GetFilename(path));
160} 160}
161 161
162VfsFile::~VfsFile() = default; 162VfsFile::~VfsFile() = default;
163 163
164std::string VfsFile::GetExtension() const { 164std::string VfsFile::GetExtension() const {
165 return std::string(FileUtil::GetExtensionFromFilename(GetName())); 165 return std::string(Common::FS::GetExtensionFromFilename(GetName()));
166} 166}
167 167
168VfsDirectory::~VfsDirectory() = default; 168VfsDirectory::~VfsDirectory() = default;
@@ -203,7 +203,7 @@ std::string VfsFile::GetFullPath() const {
203} 203}
204 204
205std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) const { 205std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) const {
206 auto vec = FileUtil::SplitPathComponents(path); 206 auto vec = Common::FS::SplitPathComponents(path);
207 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), 207 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
208 vec.end()); 208 vec.end());
209 if (vec.empty()) { 209 if (vec.empty()) {
@@ -239,7 +239,7 @@ std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(std::string_view path) co
239} 239}
240 240
241std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(std::string_view path) const { 241std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(std::string_view path) const {
242 auto vec = FileUtil::SplitPathComponents(path); 242 auto vec = Common::FS::SplitPathComponents(path);
243 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), 243 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
244 vec.end()); 244 vec.end());
245 if (vec.empty()) { 245 if (vec.empty()) {
@@ -301,7 +301,7 @@ std::size_t VfsDirectory::GetSize() const {
301} 301}
302 302
303std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(std::string_view path) { 303std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(std::string_view path) {
304 auto vec = FileUtil::SplitPathComponents(path); 304 auto vec = Common::FS::SplitPathComponents(path);
305 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), 305 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
306 vec.end()); 306 vec.end());
307 if (vec.empty()) { 307 if (vec.empty()) {
@@ -320,7 +320,7 @@ std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(std::string_view path)
320 } 320 }
321 } 321 }
322 322
323 return dir->CreateFileRelative(FileUtil::GetPathWithoutTop(path)); 323 return dir->CreateFileRelative(Common::FS::GetPathWithoutTop(path));
324} 324}
325 325
326std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(std::string_view path) { 326std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(std::string_view path) {
@@ -332,7 +332,7 @@ std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(std::string_view path)
332} 332}
333 333
334std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(std::string_view path) { 334std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(std::string_view path) {
335 auto vec = FileUtil::SplitPathComponents(path); 335 auto vec = Common::FS::SplitPathComponents(path);
336 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }), 336 vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
337 vec.end()); 337 vec.end());
338 if (vec.empty()) { 338 if (vec.empty()) {
@@ -351,7 +351,7 @@ std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(std::string_
351 } 351 }
352 } 352 }
353 353
354 return dir->CreateDirectoryRelative(FileUtil::GetPathWithoutTop(path)); 354 return dir->CreateDirectoryRelative(Common::FS::GetPathWithoutTop(path));
355} 355}
356 356
357std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryAbsolute(std::string_view path) { 357std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
diff --git a/src/core/file_sys/vfs_libzip.cpp b/src/core/file_sys/vfs_libzip.cpp
index d69952940..429d7bc8b 100644
--- a/src/core/file_sys/vfs_libzip.cpp
+++ b/src/core/file_sys/vfs_libzip.cpp
@@ -49,7 +49,7 @@ VirtualDir ExtractZIP(VirtualFile file) {
49 if (zip_fread(file2.get(), buf.data(), buf.size()) != s64(buf.size())) 49 if (zip_fread(file2.get(), buf.data(), buf.size()) != s64(buf.size()))
50 return nullptr; 50 return nullptr;
51 51
52 const auto parts = FileUtil::SplitPathComponents(stat.name); 52 const auto parts = Common::FS::SplitPathComponents(stat.name);
53 const auto new_file = std::make_shared<VectorVfsFile>(buf, parts.back()); 53 const auto new_file = std::make_shared<VectorVfsFile>(buf, parts.back());
54 54
55 std::shared_ptr<VectorVfsDirectory> dtrv = out; 55 std::shared_ptr<VectorVfsDirectory> dtrv = out;
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp
index 0db0091f6..488687ba9 100644
--- a/src/core/file_sys/vfs_real.cpp
+++ b/src/core/file_sys/vfs_real.cpp
@@ -14,6 +14,8 @@
14 14
15namespace FileSys { 15namespace FileSys {
16 16
17namespace FS = Common::FS;
18
17static std::string ModeFlagsToString(Mode mode) { 19static std::string ModeFlagsToString(Mode mode) {
18 std::string mode_str; 20 std::string mode_str;
19 21
@@ -57,79 +59,82 @@ bool RealVfsFilesystem::IsWritable() const {
57} 59}
58 60
59VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const { 61VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const {
60 const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); 62 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
61 if (!FileUtil::Exists(path)) 63 if (!FS::Exists(path)) {
62 return VfsEntryType::None; 64 return VfsEntryType::None;
63 if (FileUtil::IsDirectory(path)) 65 }
66 if (FS::IsDirectory(path)) {
64 return VfsEntryType::Directory; 67 return VfsEntryType::Directory;
68 }
65 69
66 return VfsEntryType::File; 70 return VfsEntryType::File;
67} 71}
68 72
69VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { 73VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
70 const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); 74 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
71 if (cache.find(path) != cache.end()) { 75
72 auto weak = cache[path]; 76 if (const auto weak_iter = cache.find(path); weak_iter != cache.cend()) {
77 const auto& weak = weak_iter->second;
78
73 if (!weak.expired()) { 79 if (!weak.expired()) {
74 return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, weak.lock(), path, perms)); 80 return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, weak.lock(), path, perms));
75 } 81 }
76 } 82 }
77 83
78 if (!FileUtil::Exists(path) && True(perms & Mode::WriteAppend)) { 84 if (!FS::Exists(path) && True(perms & Mode::WriteAppend)) {
79 FileUtil::CreateEmptyFile(path); 85 FS::CreateEmptyFile(path);
80 } 86 }
81 87
82 auto backing = std::make_shared<FileUtil::IOFile>(path, ModeFlagsToString(perms).c_str()); 88 auto backing = std::make_shared<FS::IOFile>(path, ModeFlagsToString(perms).c_str());
83 cache[path] = backing; 89 cache.insert_or_assign(path, backing);
84 90
85 // Cannot use make_shared as RealVfsFile constructor is private 91 // Cannot use make_shared as RealVfsFile constructor is private
86 return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, backing, path, perms)); 92 return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, backing, path, perms));
87} 93}
88 94
89VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { 95VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
90 const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); 96 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
91 const auto path_fwd = FileUtil::SanitizePath(path, FileUtil::DirectorySeparator::ForwardSlash); 97 const auto path_fwd = FS::SanitizePath(path, FS::DirectorySeparator::ForwardSlash);
92 if (!FileUtil::Exists(path)) { 98 if (!FS::Exists(path)) {
93 FileUtil::CreateFullPath(path_fwd); 99 FS::CreateFullPath(path_fwd);
94 if (!FileUtil::CreateEmptyFile(path)) 100 if (!FS::CreateEmptyFile(path)) {
95 return nullptr; 101 return nullptr;
102 }
96 } 103 }
97 return OpenFile(path, perms); 104 return OpenFile(path, perms);
98} 105}
99 106
100VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) { 107VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) {
101 const auto old_path = 108 const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
102 FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); 109 const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
103 const auto new_path =
104 FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
105 110
106 if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || 111 if (!FS::Exists(old_path) || FS::Exists(new_path) || FS::IsDirectory(old_path) ||
107 FileUtil::IsDirectory(old_path) || !FileUtil::Copy(old_path, new_path)) 112 !FS::Copy(old_path, new_path)) {
108 return nullptr; 113 return nullptr;
114 }
109 return OpenFile(new_path, Mode::ReadWrite); 115 return OpenFile(new_path, Mode::ReadWrite);
110} 116}
111 117
112VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { 118VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) {
113 const auto old_path = 119 const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
114 FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); 120 const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
115 const auto new_path = 121 const auto cached_file_iter = cache.find(old_path);
116 FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
117 122
118 if (cache.find(old_path) != cache.end()) { 123 if (cached_file_iter != cache.cend()) {
119 auto file = cache[old_path].lock(); 124 auto file = cached_file_iter->second.lock();
120 125
121 if (!cache[old_path].expired()) { 126 if (!cached_file_iter->second.expired()) {
122 file->Close(); 127 file->Close();
123 } 128 }
124 129
125 if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || 130 if (!FS::Exists(old_path) || FS::Exists(new_path) || FS::IsDirectory(old_path) ||
126 FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) { 131 !FS::Rename(old_path, new_path)) {
127 return nullptr; 132 return nullptr;
128 } 133 }
129 134
130 cache.erase(old_path); 135 cache.erase(old_path);
131 file->Open(new_path, "r+b"); 136 file->Open(new_path, "r+b");
132 cache[new_path] = file; 137 cache.insert_or_assign(new_path, std::move(file));
133 } else { 138 } else {
134 UNREACHABLE(); 139 UNREACHABLE();
135 return nullptr; 140 return nullptr;
@@ -139,28 +144,33 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_
139} 144}
140 145
141bool RealVfsFilesystem::DeleteFile(std::string_view path_) { 146bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
142 const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); 147 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
143 if (cache.find(path) != cache.end()) { 148 const auto cached_iter = cache.find(path);
144 if (!cache[path].expired()) 149
145 cache[path].lock()->Close(); 150 if (cached_iter != cache.cend()) {
151 if (!cached_iter->second.expired()) {
152 cached_iter->second.lock()->Close();
153 }
146 cache.erase(path); 154 cache.erase(path);
147 } 155 }
148 return FileUtil::Delete(path); 156
157 return FS::Delete(path);
149} 158}
150 159
151VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) { 160VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) {
152 const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); 161 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
153 // Cannot use make_shared as RealVfsDirectory constructor is private 162 // Cannot use make_shared as RealVfsDirectory constructor is private
154 return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms)); 163 return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
155} 164}
156 165
157VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { 166VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) {
158 const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); 167 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
159 const auto path_fwd = FileUtil::SanitizePath(path, FileUtil::DirectorySeparator::ForwardSlash); 168 const auto path_fwd = FS::SanitizePath(path, FS::DirectorySeparator::ForwardSlash);
160 if (!FileUtil::Exists(path)) { 169 if (!FS::Exists(path)) {
161 FileUtil::CreateFullPath(path_fwd); 170 FS::CreateFullPath(path_fwd);
162 if (!FileUtil::CreateDir(path)) 171 if (!FS::CreateDir(path)) {
163 return nullptr; 172 return nullptr;
173 }
164 } 174 }
165 // Cannot use make_shared as RealVfsDirectory constructor is private 175 // Cannot use make_shared as RealVfsDirectory constructor is private
166 return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms)); 176 return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
@@ -168,67 +178,75 @@ VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms
168 178
169VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_, 179VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_,
170 std::string_view new_path_) { 180 std::string_view new_path_) {
171 const auto old_path = 181 const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
172 FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); 182 const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
173 const auto new_path = 183 if (!FS::Exists(old_path) || FS::Exists(new_path) || !FS::IsDirectory(old_path)) {
174 FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
175 if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
176 !FileUtil::IsDirectory(old_path))
177 return nullptr; 184 return nullptr;
178 FileUtil::CopyDir(old_path, new_path); 185 }
186 FS::CopyDir(old_path, new_path);
179 return OpenDirectory(new_path, Mode::ReadWrite); 187 return OpenDirectory(new_path, Mode::ReadWrite);
180} 188}
181 189
182VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, 190VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,
183 std::string_view new_path_) { 191 std::string_view new_path_) {
184 const auto old_path = 192 const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault);
185 FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); 193 const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault);
186 const auto new_path = 194
187 FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); 195 if (!FS::Exists(old_path) || FS::Exists(new_path) || FS::IsDirectory(old_path) ||
188 if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || 196 !FS::Rename(old_path, new_path)) {
189 FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path))
190 return nullptr; 197 return nullptr;
198 }
191 199
192 for (auto& kv : cache) { 200 for (auto& kv : cache) {
193 // Path in cache starts with old_path 201 // If the path in the cache doesn't start with old_path, then bail on this file.
194 if (kv.first.rfind(old_path, 0) == 0) { 202 if (kv.first.rfind(old_path, 0) != 0) {
195 const auto file_old_path = 203 continue;
196 FileUtil::SanitizePath(kv.first, FileUtil::DirectorySeparator::PlatformDefault); 204 }
197 const auto file_new_path = 205
198 FileUtil::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()), 206 const auto file_old_path =
199 FileUtil::DirectorySeparator::PlatformDefault); 207 FS::SanitizePath(kv.first, FS::DirectorySeparator::PlatformDefault);
200 auto cached = cache[file_old_path]; 208 auto file_new_path = FS::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()),
201 if (!cached.expired()) { 209 FS::DirectorySeparator::PlatformDefault);
202 auto file = cached.lock(); 210 const auto& cached = cache[file_old_path];
203 file->Open(file_new_path, "r+b"); 211
204 cache.erase(file_old_path); 212 if (cached.expired()) {
205 cache[file_new_path] = file; 213 continue;
206 }
207 } 214 }
215
216 auto file = cached.lock();
217 file->Open(file_new_path, "r+b");
218 cache.erase(file_old_path);
219 cache.insert_or_assign(std::move(file_new_path), std::move(file));
208 } 220 }
209 221
210 return OpenDirectory(new_path, Mode::ReadWrite); 222 return OpenDirectory(new_path, Mode::ReadWrite);
211} 223}
212 224
213bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) { 225bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {
214 const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); 226 const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
227
215 for (auto& kv : cache) { 228 for (auto& kv : cache) {
216 // Path in cache starts with old_path 229 // If the path in the cache doesn't start with path, then bail on this file.
217 if (kv.first.rfind(path, 0) == 0) { 230 if (kv.first.rfind(path, 0) != 0) {
218 if (!cache[kv.first].expired()) 231 continue;
219 cache[kv.first].lock()->Close(); 232 }
220 cache.erase(kv.first); 233
234 const auto& entry = cache[kv.first];
235 if (!entry.expired()) {
236 entry.lock()->Close();
221 } 237 }
238
239 cache.erase(kv.first);
222 } 240 }
223 return FileUtil::DeleteDirRecursively(path); 241
242 return FS::DeleteDirRecursively(path);
224} 243}
225 244
226RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::shared_ptr<FileUtil::IOFile> backing_, 245RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::shared_ptr<FS::IOFile> backing_,
227 const std::string& path_, Mode perms_) 246 const std::string& path_, Mode perms_)
228 : base(base_), backing(std::move(backing_)), path(path_), 247 : base(base_), backing(std::move(backing_)), path(path_), parent_path(FS::GetParentPath(path_)),
229 parent_path(FileUtil::GetParentPath(path_)), 248 path_components(FS::SplitPathComponents(path_)),
230 path_components(FileUtil::SplitPathComponents(path_)), 249 parent_components(FS::SliceVector(path_components, 0, path_components.size() - 1)),
231 parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
232 perms(perms_) {} 250 perms(perms_) {}
233 251
234RealVfsFile::~RealVfsFile() = default; 252RealVfsFile::~RealVfsFile() = default;
@@ -258,14 +276,16 @@ bool RealVfsFile::IsReadable() const {
258} 276}
259 277
260std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { 278std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
261 if (!backing->Seek(offset, SEEK_SET)) 279 if (!backing->Seek(static_cast<s64>(offset), SEEK_SET)) {
262 return 0; 280 return 0;
281 }
263 return backing->ReadBytes(data, length); 282 return backing->ReadBytes(data, length);
264} 283}
265 284
266std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { 285std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {
267 if (!backing->Seek(offset, SEEK_SET)) 286 if (!backing->Seek(static_cast<s64>(offset), SEEK_SET)) {
268 return 0; 287 return 0;
288 }
269 return backing->WriteBytes(data, length); 289 return backing->WriteBytes(data, length);
270} 290}
271 291
@@ -282,16 +302,18 @@ bool RealVfsFile::Close() {
282 302
283template <> 303template <>
284std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>() const { 304std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>() const {
285 if (perms == Mode::Append) 305 if (perms == Mode::Append) {
286 return {}; 306 return {};
307 }
287 308
288 std::vector<VirtualFile> out; 309 std::vector<VirtualFile> out;
289 FileUtil::ForeachDirectoryEntry( 310 FS::ForeachDirectoryEntry(
290 nullptr, path, 311 nullptr, path,
291 [&out, this](u64* entries_out, const std::string& directory, const std::string& filename) { 312 [&out, this](u64* entries_out, const std::string& directory, const std::string& filename) {
292 const std::string full_path = directory + DIR_SEP + filename; 313 const std::string full_path = directory + DIR_SEP + filename;
293 if (!FileUtil::IsDirectory(full_path)) 314 if (!FS::IsDirectory(full_path)) {
294 out.emplace_back(base.OpenFile(full_path, perms)); 315 out.emplace_back(base.OpenFile(full_path, perms));
316 }
295 return true; 317 return true;
296 }); 318 });
297 319
@@ -300,16 +322,18 @@ std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>(
300 322
301template <> 323template <>
302std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDirectory>() const { 324std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDirectory>() const {
303 if (perms == Mode::Append) 325 if (perms == Mode::Append) {
304 return {}; 326 return {};
327 }
305 328
306 std::vector<VirtualDir> out; 329 std::vector<VirtualDir> out;
307 FileUtil::ForeachDirectoryEntry( 330 FS::ForeachDirectoryEntry(
308 nullptr, path, 331 nullptr, path,
309 [&out, this](u64* entries_out, const std::string& directory, const std::string& filename) { 332 [&out, this](u64* entries_out, const std::string& directory, const std::string& filename) {
310 const std::string full_path = directory + DIR_SEP + filename; 333 const std::string full_path = directory + DIR_SEP + filename;
311 if (FileUtil::IsDirectory(full_path)) 334 if (FS::IsDirectory(full_path)) {
312 out.emplace_back(base.OpenDirectory(full_path, perms)); 335 out.emplace_back(base.OpenDirectory(full_path, perms));
336 }
313 return true; 337 return true;
314 }); 338 });
315 339
@@ -317,29 +341,30 @@ std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDi
317} 341}
318 342
319RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_) 343RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_)
320 : base(base_), path(FileUtil::RemoveTrailingSlash(path_)), 344 : base(base_), path(FS::RemoveTrailingSlash(path_)), parent_path(FS::GetParentPath(path)),
321 parent_path(FileUtil::GetParentPath(path)), 345 path_components(FS::SplitPathComponents(path)),
322 path_components(FileUtil::SplitPathComponents(path)), 346 parent_components(FS::SliceVector(path_components, 0, path_components.size() - 1)),
323 parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
324 perms(perms_) { 347 perms(perms_) {
325 if (!FileUtil::Exists(path) && True(perms & Mode::WriteAppend)) { 348 if (!FS::Exists(path) && True(perms & Mode::WriteAppend)) {
326 FileUtil::CreateDir(path); 349 FS::CreateDir(path);
327 } 350 }
328} 351}
329 352
330RealVfsDirectory::~RealVfsDirectory() = default; 353RealVfsDirectory::~RealVfsDirectory() = default;
331 354
332std::shared_ptr<VfsFile> RealVfsDirectory::GetFileRelative(std::string_view path) const { 355std::shared_ptr<VfsFile> RealVfsDirectory::GetFileRelative(std::string_view path) const {
333 const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path)); 356 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
334 if (!FileUtil::Exists(full_path) || FileUtil::IsDirectory(full_path)) 357 if (!FS::Exists(full_path) || FS::IsDirectory(full_path)) {
335 return nullptr; 358 return nullptr;
359 }
336 return base.OpenFile(full_path, perms); 360 return base.OpenFile(full_path, perms);
337} 361}
338 362
339std::shared_ptr<VfsDirectory> RealVfsDirectory::GetDirectoryRelative(std::string_view path) const { 363std::shared_ptr<VfsDirectory> RealVfsDirectory::GetDirectoryRelative(std::string_view path) const {
340 const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path)); 364 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
341 if (!FileUtil::Exists(full_path) || !FileUtil::IsDirectory(full_path)) 365 if (!FS::Exists(full_path) || !FS::IsDirectory(full_path)) {
342 return nullptr; 366 return nullptr;
367 }
343 return base.OpenDirectory(full_path, perms); 368 return base.OpenDirectory(full_path, perms);
344} 369}
345 370
@@ -352,17 +377,17 @@ std::shared_ptr<VfsDirectory> RealVfsDirectory::GetSubdirectory(std::string_view
352} 377}
353 378
354std::shared_ptr<VfsFile> RealVfsDirectory::CreateFileRelative(std::string_view path) { 379std::shared_ptr<VfsFile> RealVfsDirectory::CreateFileRelative(std::string_view path) {
355 const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path)); 380 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
356 return base.CreateFile(full_path, perms); 381 return base.CreateFile(full_path, perms);
357} 382}
358 383
359std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateDirectoryRelative(std::string_view path) { 384std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateDirectoryRelative(std::string_view path) {
360 const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path)); 385 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
361 return base.CreateDirectory(full_path, perms); 386 return base.CreateDirectory(full_path, perms);
362} 387}
363 388
364bool RealVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) { 389bool RealVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
365 auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(name)); 390 const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(name));
366 return base.DeleteDirectory(full_path); 391 return base.DeleteDirectory(full_path);
367} 392}
368 393
@@ -387,8 +412,9 @@ std::string RealVfsDirectory::GetName() const {
387} 412}
388 413
389std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const { 414std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const {
390 if (path_components.size() <= 1) 415 if (path_components.size() <= 1) {
391 return nullptr; 416 return nullptr;
417 }
392 418
393 return base.OpenDirectory(parent_path, perms); 419 return base.OpenDirectory(parent_path, perms);
394} 420}
@@ -425,16 +451,17 @@ std::string RealVfsDirectory::GetFullPath() const {
425} 451}
426 452
427std::map<std::string, VfsEntryType, std::less<>> RealVfsDirectory::GetEntries() const { 453std::map<std::string, VfsEntryType, std::less<>> RealVfsDirectory::GetEntries() const {
428 if (perms == Mode::Append) 454 if (perms == Mode::Append) {
429 return {}; 455 return {};
456 }
430 457
431 std::map<std::string, VfsEntryType, std::less<>> out; 458 std::map<std::string, VfsEntryType, std::less<>> out;
432 FileUtil::ForeachDirectoryEntry( 459 FS::ForeachDirectoryEntry(
433 nullptr, path, 460 nullptr, path,
434 [&out](u64* entries_out, const std::string& directory, const std::string& filename) { 461 [&out](u64* entries_out, const std::string& directory, const std::string& filename) {
435 const std::string full_path = directory + DIR_SEP + filename; 462 const std::string full_path = directory + DIR_SEP + filename;
436 out.emplace(filename, FileUtil::IsDirectory(full_path) ? VfsEntryType::Directory 463 out.emplace(filename,
437 : VfsEntryType::File); 464 FS::IsDirectory(full_path) ? VfsEntryType::Directory : VfsEntryType::File);
438 return true; 465 return true;
439 }); 466 });
440 467
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h
index a0a857a31..0b537b22c 100644
--- a/src/core/file_sys/vfs_real.h
+++ b/src/core/file_sys/vfs_real.h
@@ -9,7 +9,7 @@
9#include "core/file_sys/mode.h" 9#include "core/file_sys/mode.h"
10#include "core/file_sys/vfs.h" 10#include "core/file_sys/vfs.h"
11 11
12namespace FileUtil { 12namespace Common::FS {
13class IOFile; 13class IOFile;
14} 14}
15 15
@@ -36,7 +36,7 @@ public:
36 bool DeleteDirectory(std::string_view path) override; 36 bool DeleteDirectory(std::string_view path) override;
37 37
38private: 38private:
39 boost::container::flat_map<std::string, std::weak_ptr<FileUtil::IOFile>> cache; 39 boost::container::flat_map<std::string, std::weak_ptr<Common::FS::IOFile>> cache;
40}; 40};
41 41
42// An implmentation of VfsFile that represents a file on the user's computer. 42// An implmentation of VfsFile that represents a file on the user's computer.
@@ -58,13 +58,13 @@ public:
58 bool Rename(std::string_view name) override; 58 bool Rename(std::string_view name) override;
59 59
60private: 60private:
61 RealVfsFile(RealVfsFilesystem& base, std::shared_ptr<FileUtil::IOFile> backing, 61 RealVfsFile(RealVfsFilesystem& base, std::shared_ptr<Common::FS::IOFile> backing,
62 const std::string& path, Mode perms = Mode::Read); 62 const std::string& path, Mode perms = Mode::Read);
63 63
64 bool Close(); 64 bool Close();
65 65
66 RealVfsFilesystem& base; 66 RealVfsFilesystem& base;
67 std::shared_ptr<FileUtil::IOFile> backing; 67 std::shared_ptr<Common::FS::IOFile> backing;
68 std::string path; 68 std::string path;
69 std::string parent_path; 69 std::string parent_path;
70 std::vector<std::string> path_components; 70 std::vector<std::string> path_components;
diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp
index 81413c684..ccf5966d0 100644
--- a/src/core/file_sys/xts_archive.cpp
+++ b/src/core/file_sys/xts_archive.cpp
@@ -44,7 +44,7 @@ static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t
44} 44}
45 45
46NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::move(file_)) { 46NAX::NAX(VirtualFile file_) : header(std::make_unique<NAXHeader>()), file(std::move(file_)) {
47 std::string path = FileUtil::SanitizePath(file->GetFullPath()); 47 std::string path = Common::FS::SanitizePath(file->GetFullPath());
48 static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca", 48 static const std::regex nax_path_regex("/registered/(000000[0-9A-F]{2})/([0-9A-F]{32})\\.nca",
49 std::regex_constants::ECMAScript | 49 std::regex_constants::ECMAScript |
50 std::regex_constants::icase); 50 std::regex_constants::icase);
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp
index 63e4aeca0..eb54cb123 100644
--- a/src/core/hle/service/acc/acc.cpp
+++ b/src/core/hle/service/acc/acc.cpp
@@ -35,7 +35,7 @@ constexpr ResultCode ERR_INVALID_BUFFER_SIZE{ErrorModule::Account, 30};
35constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100}; 35constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100};
36 36
37static std::string GetImagePath(Common::UUID uuid) { 37static std::string GetImagePath(Common::UUID uuid) {
38 return FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + 38 return Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) +
39 "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; 39 "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg";
40} 40}
41 41
@@ -318,7 +318,7 @@ protected:
318 IPC::ResponseBuilder rb{ctx, 3}; 318 IPC::ResponseBuilder rb{ctx, 3};
319 rb.Push(RESULT_SUCCESS); 319 rb.Push(RESULT_SUCCESS);
320 320
321 const FileUtil::IOFile image(GetImagePath(user_id), "rb"); 321 const Common::FS::IOFile image(GetImagePath(user_id), "rb");
322 if (!image.IsOpen()) { 322 if (!image.IsOpen()) {
323 LOG_WARNING(Service_ACC, 323 LOG_WARNING(Service_ACC,
324 "Failed to load user provided image! Falling back to built-in backup..."); 324 "Failed to load user provided image! Falling back to built-in backup...");
@@ -340,7 +340,7 @@ protected:
340 IPC::ResponseBuilder rb{ctx, 3}; 340 IPC::ResponseBuilder rb{ctx, 3};
341 rb.Push(RESULT_SUCCESS); 341 rb.Push(RESULT_SUCCESS);
342 342
343 const FileUtil::IOFile image(GetImagePath(user_id), "rb"); 343 const Common::FS::IOFile image(GetImagePath(user_id), "rb");
344 344
345 if (!image.IsOpen()) { 345 if (!image.IsOpen()) {
346 LOG_WARNING(Service_ACC, 346 LOG_WARNING(Service_ACC,
@@ -405,7 +405,7 @@ protected:
405 ProfileData data; 405 ProfileData data;
406 std::memcpy(&data, user_data.data(), sizeof(ProfileData)); 406 std::memcpy(&data, user_data.data(), sizeof(ProfileData));
407 407
408 FileUtil::IOFile image(GetImagePath(user_id), "wb"); 408 Common::FS::IOFile image(GetImagePath(user_id), "wb");
409 409
410 if (!image.IsOpen() || !image.Resize(image_data.size()) || 410 if (!image.IsOpen() || !image.Resize(image_data.size()) ||
411 image.WriteBytes(image_data.data(), image_data.size()) != image_data.size() || 411 image.WriteBytes(image_data.data(), image_data.size()) != image_data.size() ||
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp
index a98d57b5c..9b829e957 100644
--- a/src/core/hle/service/acc/profile_manager.cpp
+++ b/src/core/hle/service/acc/profile_manager.cpp
@@ -13,6 +13,7 @@
13 13
14namespace Service::Account { 14namespace Service::Account {
15 15
16namespace FS = Common::FS;
16using Common::UUID; 17using Common::UUID;
17 18
18struct UserRaw { 19struct UserRaw {
@@ -318,9 +319,8 @@ bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase&
318} 319}
319 320
320void ProfileManager::ParseUserSaveFile() { 321void ProfileManager::ParseUserSaveFile() {
321 FileUtil::IOFile save(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + 322 const FS::IOFile save(
322 ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat", 323 FS::GetUserPath(FS::UserPath::NANDDir) + ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat", "rb");
323 "rb");
324 324
325 if (!save.IsOpen()) { 325 if (!save.IsOpen()) {
326 LOG_WARNING(Service_ACC, "Failed to load profile data from save data... Generating new " 326 LOG_WARNING(Service_ACC, "Failed to load profile data from save data... Generating new "
@@ -366,22 +366,22 @@ void ProfileManager::WriteUserSaveFile() {
366 }; 366 };
367 } 367 }
368 368
369 const auto raw_path = 369 const auto raw_path = FS::GetUserPath(FS::UserPath::NANDDir) + "/system/save/8000000000000010";
370 FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + "/system/save/8000000000000010"; 370 if (FS::Exists(raw_path) && !FS::IsDirectory(raw_path)) {
371 if (FileUtil::Exists(raw_path) && !FileUtil::IsDirectory(raw_path)) 371 FS::Delete(raw_path);
372 FileUtil::Delete(raw_path); 372 }
373 373
374 const auto path = FileUtil::GetUserPath(FileUtil::UserPath::NANDDir) + 374 const auto path =
375 ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat"; 375 FS::GetUserPath(FS::UserPath::NANDDir) + ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat";
376 376
377 if (!FileUtil::CreateFullPath(path)) { 377 if (!FS::CreateFullPath(path)) {
378 LOG_WARNING(Service_ACC, "Failed to create full path of profiles.dat. Create the directory " 378 LOG_WARNING(Service_ACC, "Failed to create full path of profiles.dat. Create the directory "
379 "nand/system/save/8000000000000010/su/avators to mitigate this " 379 "nand/system/save/8000000000000010/su/avators to mitigate this "
380 "issue."); 380 "issue.");
381 return; 381 return;
382 } 382 }
383 383
384 FileUtil::IOFile save(path, "wb"); 384 FS::IOFile save(path, "wb");
385 385
386 if (!save.IsOpen()) { 386 if (!save.IsOpen()) {
387 LOG_WARNING(Service_ACC, "Failed to write save data to file... No changes to user data " 387 LOG_WARNING(Service_ACC, "Failed to write save data to file... No changes to user data "
diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp
index 4157fbf39..efe595c4f 100644
--- a/src/core/hle/service/am/applets/web_browser.cpp
+++ b/src/core/hle/service/am/applets/web_browser.cpp
@@ -293,8 +293,8 @@ void WebBrowser::Finalize() {
293 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(data))); 293 broker.PushNormalDataFromApplet(std::make_shared<IStorage>(std::move(data)));
294 broker.SignalStateChanged(); 294 broker.SignalStateChanged();
295 295
296 if (!temporary_dir.empty() && FileUtil::IsDirectory(temporary_dir)) { 296 if (!temporary_dir.empty() && Common::FS::IsDirectory(temporary_dir)) {
297 FileUtil::DeleteDirRecursively(temporary_dir); 297 Common::FS::DeleteDirRecursively(temporary_dir);
298 } 298 }
299} 299}
300 300
@@ -452,10 +452,10 @@ void WebBrowser::InitializeOffline() {
452 }; 452 };
453 453
454 temporary_dir = 454 temporary_dir =
455 FileUtil::SanitizePath(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + "web_applet_" + 455 Common::FS::SanitizePath(Common::FS::GetUserPath(Common::FS::UserPath::CacheDir) +
456 WEB_SOURCE_NAMES[static_cast<u32>(source) - 1], 456 "web_applet_" + WEB_SOURCE_NAMES[static_cast<u32>(source) - 1],
457 FileUtil::DirectorySeparator::PlatformDefault); 457 Common::FS::DirectorySeparator::PlatformDefault);
458 FileUtil::DeleteDirRecursively(temporary_dir); 458 Common::FS::DeleteDirRecursively(temporary_dir);
459 459
460 u64 title_id = 0; // 0 corresponds to current process 460 u64 title_id = 0; // 0 corresponds to current process
461 ASSERT(args[WebArgTLVType::ApplicationID].size() >= 0x8); 461 ASSERT(args[WebArgTLVType::ApplicationID].size() >= 0x8);
@@ -492,8 +492,8 @@ void WebBrowser::InitializeOffline() {
492 } 492 }
493 493
494 filename = 494 filename =
495 FileUtil::SanitizePath(temporary_dir + path_additional_directory + DIR_SEP + filename, 495 Common::FS::SanitizePath(temporary_dir + path_additional_directory + DIR_SEP + filename,
496 FileUtil::DirectorySeparator::PlatformDefault); 496 Common::FS::DirectorySeparator::PlatformDefault);
497} 497}
498 498
499void WebBrowser::ExecuteShop() { 499void WebBrowser::ExecuteShop() {
diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp
index 51c2ba964..ca021a99f 100644
--- a/src/core/hle/service/bcat/backend/boxcat.cpp
+++ b/src/core/hle/service/bcat/backend/boxcat.cpp
@@ -89,12 +89,12 @@ constexpr u32 TIMEOUT_SECONDS = 30;
89 89
90std::string GetBINFilePath(u64 title_id) { 90std::string GetBINFilePath(u64 title_id) {
91 return fmt::format("{}bcat/{:016X}/launchparam.bin", 91 return fmt::format("{}bcat/{:016X}/launchparam.bin",
92 FileUtil::GetUserPath(FileUtil::UserPath::CacheDir), title_id); 92 Common::FS::GetUserPath(Common::FS::UserPath::CacheDir), title_id);
93} 93}
94 94
95std::string GetZIPFilePath(u64 title_id) { 95std::string GetZIPFilePath(u64 title_id) {
96 return fmt::format("{}bcat/{:016X}/data.zip", 96 return fmt::format("{}bcat/{:016X}/data.zip",
97 FileUtil::GetUserPath(FileUtil::UserPath::CacheDir), title_id); 97 Common::FS::GetUserPath(Common::FS::UserPath::CacheDir), title_id);
98} 98}
99 99
100// If the error is something the user should know about (build ID mismatch, bad client version), 100// If the error is something the user should know about (build ID mismatch, bad client version),
@@ -205,8 +205,8 @@ private:
205 {std::string("Game-Build-Id"), fmt::format("{:016X}", build_id)}, 205 {std::string("Game-Build-Id"), fmt::format("{:016X}", build_id)},
206 }; 206 };
207 207
208 if (FileUtil::Exists(path)) { 208 if (Common::FS::Exists(path)) {
209 FileUtil::IOFile file{path, "rb"}; 209 Common::FS::IOFile file{path, "rb"};
210 if (file.IsOpen()) { 210 if (file.IsOpen()) {
211 std::vector<u8> bytes(file.GetSize()); 211 std::vector<u8> bytes(file.GetSize());
212 file.ReadBytes(bytes.data(), bytes.size()); 212 file.ReadBytes(bytes.data(), bytes.size());
@@ -236,8 +236,8 @@ private:
236 return DownloadResult::InvalidContentType; 236 return DownloadResult::InvalidContentType;
237 } 237 }
238 238
239 FileUtil::CreateFullPath(path); 239 Common::FS::CreateFullPath(path);
240 FileUtil::IOFile file{path, "wb"}; 240 Common::FS::IOFile file{path, "wb"};
241 if (!file.IsOpen()) 241 if (!file.IsOpen())
242 return DownloadResult::GeneralFSError; 242 return DownloadResult::GeneralFSError;
243 if (!file.Resize(response->body.size())) 243 if (!file.Resize(response->body.size()))
@@ -290,7 +290,7 @@ void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGe
290 LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); 290 LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res);
291 291
292 if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { 292 if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) {
293 FileUtil::Delete(zip_path); 293 Common::FS::Delete(zip_path);
294 } 294 }
295 295
296 HandleDownloadDisplayResult(applet_manager, res); 296 HandleDownloadDisplayResult(applet_manager, res);
@@ -300,7 +300,7 @@ void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGe
300 300
301 progress.StartProcessingDataList(); 301 progress.StartProcessingDataList();
302 302
303 FileUtil::IOFile zip{zip_path, "rb"}; 303 Common::FS::IOFile zip{zip_path, "rb"};
304 const auto size = zip.GetSize(); 304 const auto size = zip.GetSize();
305 std::vector<u8> bytes(size); 305 std::vector<u8> bytes(size);
306 if (!zip.IsOpen() || size == 0 || zip.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) { 306 if (!zip.IsOpen() || size == 0 || zip.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) {
@@ -420,7 +420,7 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title)
420 LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); 420 LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res);
421 421
422 if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { 422 if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) {
423 FileUtil::Delete(path); 423 Common::FS::Delete(path);
424 } 424 }
425 425
426 HandleDownloadDisplayResult(applet_manager, res); 426 HandleDownloadDisplayResult(applet_manager, res);
@@ -428,7 +428,7 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title)
428 } 428 }
429 } 429 }
430 430
431 FileUtil::IOFile bin{path, "rb"}; 431 Common::FS::IOFile bin{path, "rb"};
432 const auto size = bin.GetSize(); 432 const auto size = bin.GetSize();
433 std::vector<u8> bytes(size); 433 std::vector<u8> bytes(size);
434 if (!bin.IsOpen() || size == 0 || bin.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) { 434 if (!bin.IsOpen() || size == 0 || bin.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) {
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 4490f8e4c..2cee1193c 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -36,7 +36,7 @@ constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000;
36 36
37static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base, 37static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
38 std::string_view dir_name_) { 38 std::string_view dir_name_) {
39 std::string dir_name(FileUtil::SanitizePath(dir_name_)); 39 std::string dir_name(Common::FS::SanitizePath(dir_name_));
40 if (dir_name.empty() || dir_name == "." || dir_name == "/" || dir_name == "\\") 40 if (dir_name.empty() || dir_name == "." || dir_name == "/" || dir_name == "\\")
41 return base; 41 return base;
42 42
@@ -53,13 +53,13 @@ std::string VfsDirectoryServiceWrapper::GetName() const {
53} 53}
54 54
55ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size) const { 55ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size) const {
56 std::string path(FileUtil::SanitizePath(path_)); 56 std::string path(Common::FS::SanitizePath(path_));
57 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); 57 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
58 // dir can be nullptr if path contains subdirectories, create those prior to creating the file. 58 // dir can be nullptr if path contains subdirectories, create those prior to creating the file.
59 if (dir == nullptr) { 59 if (dir == nullptr) {
60 dir = backing->CreateSubdirectory(FileUtil::GetParentPath(path)); 60 dir = backing->CreateSubdirectory(Common::FS::GetParentPath(path));
61 } 61 }
62 auto file = dir->CreateFile(FileUtil::GetFilename(path)); 62 auto file = dir->CreateFile(Common::FS::GetFilename(path));
63 if (file == nullptr) { 63 if (file == nullptr) {
64 // TODO(DarkLordZach): Find a better error code for this 64 // TODO(DarkLordZach): Find a better error code for this
65 return RESULT_UNKNOWN; 65 return RESULT_UNKNOWN;
@@ -72,17 +72,17 @@ ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64
72} 72}
73 73
74ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const { 74ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const {
75 std::string path(FileUtil::SanitizePath(path_)); 75 std::string path(Common::FS::SanitizePath(path_));
76 if (path.empty()) { 76 if (path.empty()) {
77 // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but... 77 // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but...
78 return RESULT_SUCCESS; 78 return RESULT_SUCCESS;
79 } 79 }
80 80
81 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); 81 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
82 if (dir->GetFile(FileUtil::GetFilename(path)) == nullptr) { 82 if (dir->GetFile(Common::FS::GetFilename(path)) == nullptr) {
83 return FileSys::ERROR_PATH_NOT_FOUND; 83 return FileSys::ERROR_PATH_NOT_FOUND;
84 } 84 }
85 if (!dir->DeleteFile(FileUtil::GetFilename(path))) { 85 if (!dir->DeleteFile(Common::FS::GetFilename(path))) {
86 // TODO(DarkLordZach): Find a better error code for this 86 // TODO(DarkLordZach): Find a better error code for this
87 return RESULT_UNKNOWN; 87 return RESULT_UNKNOWN;
88 } 88 }
@@ -91,11 +91,11 @@ ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) cons
91} 91}
92 92
93ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const { 93ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const {
94 std::string path(FileUtil::SanitizePath(path_)); 94 std::string path(Common::FS::SanitizePath(path_));
95 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); 95 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
96 if (dir == nullptr && FileUtil::GetFilename(FileUtil::GetParentPath(path)).empty()) 96 if (dir == nullptr && Common::FS::GetFilename(Common::FS::GetParentPath(path)).empty())
97 dir = backing; 97 dir = backing;
98 auto new_dir = dir->CreateSubdirectory(FileUtil::GetFilename(path)); 98 auto new_dir = dir->CreateSubdirectory(Common::FS::GetFilename(path));
99 if (new_dir == nullptr) { 99 if (new_dir == nullptr) {
100 // TODO(DarkLordZach): Find a better error code for this 100 // TODO(DarkLordZach): Find a better error code for this
101 return RESULT_UNKNOWN; 101 return RESULT_UNKNOWN;
@@ -104,9 +104,9 @@ ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_)
104} 104}
105 105
106ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path_) const { 106ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path_) const {
107 std::string path(FileUtil::SanitizePath(path_)); 107 std::string path(Common::FS::SanitizePath(path_));
108 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); 108 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
109 if (!dir->DeleteSubdirectory(FileUtil::GetFilename(path))) { 109 if (!dir->DeleteSubdirectory(Common::FS::GetFilename(path))) {
110 // TODO(DarkLordZach): Find a better error code for this 110 // TODO(DarkLordZach): Find a better error code for this
111 return RESULT_UNKNOWN; 111 return RESULT_UNKNOWN;
112 } 112 }
@@ -114,9 +114,9 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path_)
114} 114}
115 115
116ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path_) const { 116ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path_) const {
117 std::string path(FileUtil::SanitizePath(path_)); 117 std::string path(Common::FS::SanitizePath(path_));
118 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); 118 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
119 if (!dir->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path))) { 119 if (!dir->DeleteSubdirectoryRecursive(Common::FS::GetFilename(path))) {
120 // TODO(DarkLordZach): Find a better error code for this 120 // TODO(DarkLordZach): Find a better error code for this
121 return RESULT_UNKNOWN; 121 return RESULT_UNKNOWN;
122 } 122 }
@@ -124,10 +124,10 @@ ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::str
124} 124}
125 125
126ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::string& path) const { 126ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::string& path) const {
127 const std::string sanitized_path(FileUtil::SanitizePath(path)); 127 const std::string sanitized_path(Common::FS::SanitizePath(path));
128 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(sanitized_path)); 128 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(sanitized_path));
129 129
130 if (!dir->CleanSubdirectoryRecursive(FileUtil::GetFilename(sanitized_path))) { 130 if (!dir->CleanSubdirectoryRecursive(Common::FS::GetFilename(sanitized_path))) {
131 // TODO(DarkLordZach): Find a better error code for this 131 // TODO(DarkLordZach): Find a better error code for this
132 return RESULT_UNKNOWN; 132 return RESULT_UNKNOWN;
133 } 133 }
@@ -137,14 +137,14 @@ ResultCode VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::stri
137 137
138ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_, 138ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
139 const std::string& dest_path_) const { 139 const std::string& dest_path_) const {
140 std::string src_path(FileUtil::SanitizePath(src_path_)); 140 std::string src_path(Common::FS::SanitizePath(src_path_));
141 std::string dest_path(FileUtil::SanitizePath(dest_path_)); 141 std::string dest_path(Common::FS::SanitizePath(dest_path_));
142 auto src = backing->GetFileRelative(src_path); 142 auto src = backing->GetFileRelative(src_path);
143 if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) { 143 if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
144 // Use more-optimized vfs implementation rename. 144 // Use more-optimized vfs implementation rename.
145 if (src == nullptr) 145 if (src == nullptr)
146 return FileSys::ERROR_PATH_NOT_FOUND; 146 return FileSys::ERROR_PATH_NOT_FOUND;
147 if (!src->Rename(FileUtil::GetFilename(dest_path))) { 147 if (!src->Rename(Common::FS::GetFilename(dest_path))) {
148 // TODO(DarkLordZach): Find a better error code for this 148 // TODO(DarkLordZach): Find a better error code for this
149 return RESULT_UNKNOWN; 149 return RESULT_UNKNOWN;
150 } 150 }
@@ -162,7 +162,7 @@ ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
162 ASSERT_MSG(dest->WriteBytes(src->ReadAllBytes()) == src->GetSize(), 162 ASSERT_MSG(dest->WriteBytes(src->ReadAllBytes()) == src->GetSize(),
163 "Could not write all of the bytes but everything else has succeded."); 163 "Could not write all of the bytes but everything else has succeded.");
164 164
165 if (!src->GetContainingDirectory()->DeleteFile(FileUtil::GetFilename(src_path))) { 165 if (!src->GetContainingDirectory()->DeleteFile(Common::FS::GetFilename(src_path))) {
166 // TODO(DarkLordZach): Find a better error code for this 166 // TODO(DarkLordZach): Find a better error code for this
167 return RESULT_UNKNOWN; 167 return RESULT_UNKNOWN;
168 } 168 }
@@ -172,14 +172,14 @@ ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
172 172
173ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_, 173ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_,
174 const std::string& dest_path_) const { 174 const std::string& dest_path_) const {
175 std::string src_path(FileUtil::SanitizePath(src_path_)); 175 std::string src_path(Common::FS::SanitizePath(src_path_));
176 std::string dest_path(FileUtil::SanitizePath(dest_path_)); 176 std::string dest_path(Common::FS::SanitizePath(dest_path_));
177 auto src = GetDirectoryRelativeWrapped(backing, src_path); 177 auto src = GetDirectoryRelativeWrapped(backing, src_path);
178 if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) { 178 if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
179 // Use more-optimized vfs implementation rename. 179 // Use more-optimized vfs implementation rename.
180 if (src == nullptr) 180 if (src == nullptr)
181 return FileSys::ERROR_PATH_NOT_FOUND; 181 return FileSys::ERROR_PATH_NOT_FOUND;
182 if (!src->Rename(FileUtil::GetFilename(dest_path))) { 182 if (!src->Rename(Common::FS::GetFilename(dest_path))) {
183 // TODO(DarkLordZach): Find a better error code for this 183 // TODO(DarkLordZach): Find a better error code for this
184 return RESULT_UNKNOWN; 184 return RESULT_UNKNOWN;
185 } 185 }
@@ -198,7 +198,7 @@ ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_pa
198 198
199ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path_, 199ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path_,
200 FileSys::Mode mode) const { 200 FileSys::Mode mode) const {
201 const std::string path(FileUtil::SanitizePath(path_)); 201 const std::string path(Common::FS::SanitizePath(path_));
202 std::string_view npath = path; 202 std::string_view npath = path;
203 while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) { 203 while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) {
204 npath.remove_prefix(1); 204 npath.remove_prefix(1);
@@ -218,7 +218,7 @@ ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::
218} 218}
219 219
220ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path_) { 220ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path_) {
221 std::string path(FileUtil::SanitizePath(path_)); 221 std::string path(Common::FS::SanitizePath(path_));
222 auto dir = GetDirectoryRelativeWrapped(backing, path); 222 auto dir = GetDirectoryRelativeWrapped(backing, path);
223 if (dir == nullptr) { 223 if (dir == nullptr) {
224 // TODO(DarkLordZach): Find a better error code for this 224 // TODO(DarkLordZach): Find a better error code for this
@@ -229,11 +229,11 @@ ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const s
229 229
230ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType( 230ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
231 const std::string& path_) const { 231 const std::string& path_) const {
232 std::string path(FileUtil::SanitizePath(path_)); 232 std::string path(Common::FS::SanitizePath(path_));
233 auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); 233 auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
234 if (dir == nullptr) 234 if (dir == nullptr)
235 return FileSys::ERROR_PATH_NOT_FOUND; 235 return FileSys::ERROR_PATH_NOT_FOUND;
236 auto filename = FileUtil::GetFilename(path); 236 auto filename = Common::FS::GetFilename(path);
237 // TODO(Subv): Some games use the '/' path, find out what this means. 237 // TODO(Subv): Some games use the '/' path, find out what this means.
238 if (filename.empty()) 238 if (filename.empty())
239 return MakeResult(FileSys::EntryType::Directory); 239 return MakeResult(FileSys::EntryType::Directory);
@@ -695,13 +695,13 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove
695 sdmc_factory = nullptr; 695 sdmc_factory = nullptr;
696 } 696 }
697 697
698 auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), 698 auto nand_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir),
699 FileSys::Mode::ReadWrite); 699 FileSys::Mode::ReadWrite);
700 auto sd_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), 700 auto sd_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir),
701 FileSys::Mode::ReadWrite); 701 FileSys::Mode::ReadWrite);
702 auto load_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), 702 auto load_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::LoadDir),
703 FileSys::Mode::ReadWrite); 703 FileSys::Mode::ReadWrite);
704 auto dump_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), 704 auto dump_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::DumpDir),
705 FileSys::Mode::ReadWrite); 705 FileSys::Mode::ReadWrite);
706 706
707 if (bis_factory == nullptr) { 707 if (bis_factory == nullptr) {
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 7c48e55e1..9bc3a8840 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -67,7 +67,7 @@ FileType GuessFromFilename(const std::string& name) {
67 return FileType::NCA; 67 return FileType::NCA;
68 68
69 const std::string extension = 69 const std::string extension =
70 Common::ToLower(std::string(FileUtil::GetExtensionFromFilename(name))); 70 Common::ToLower(std::string(Common::FS::GetExtensionFromFilename(name)));
71 71
72 if (extension == "elf") 72 if (extension == "elf")
73 return FileType::ELF; 73 return FileType::ELF;
diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp
index b899ac884..b93396a80 100644
--- a/src/core/perf_stats.cpp
+++ b/src/core/perf_stats.cpp
@@ -38,11 +38,11 @@ PerfStats::~PerfStats() {
38 std::ostringstream stream; 38 std::ostringstream stream;
39 std::copy(perf_history.begin() + IgnoreFrames, perf_history.begin() + current_index, 39 std::copy(perf_history.begin() + IgnoreFrames, perf_history.begin() + current_index,
40 std::ostream_iterator<double>(stream, "\n")); 40 std::ostream_iterator<double>(stream, "\n"));
41 const std::string& path = FileUtil::GetUserPath(FileUtil::UserPath::LogDir); 41 const std::string& path = Common::FS::GetUserPath(Common::FS::UserPath::LogDir);
42 // %F Date format expanded is "%Y-%m-%d" 42 // %F Date format expanded is "%Y-%m-%d"
43 const std::string filename = 43 const std::string filename =
44 fmt::format("{}/{:%F-%H-%M}_{:016X}.csv", path, *std::localtime(&t), title_id); 44 fmt::format("{}/{:%F-%H-%M}_{:016X}.csv", path, *std::localtime(&t), title_id);
45 FileUtil::IOFile file(filename, "w"); 45 Common::FS::IOFile file(filename, "w");
46 file.WriteString(stream.str()); 46 file.WriteString(stream.str());
47} 47}
48 48
diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp
index 76cfa5a17..0becdf642 100644
--- a/src/core/reporter.cpp
+++ b/src/core/reporter.cpp
@@ -28,8 +28,9 @@
28namespace { 28namespace {
29 29
30std::string GetPath(std::string_view type, u64 title_id, std::string_view timestamp) { 30std::string GetPath(std::string_view type, u64 title_id, std::string_view timestamp) {
31 return fmt::format("{}{}/{:016X}_{}.json", FileUtil::GetUserPath(FileUtil::UserPath::LogDir), 31 return fmt::format("{}{}/{:016X}_{}.json",
32 type, title_id, timestamp); 32 Common::FS::GetUserPath(Common::FS::UserPath::LogDir), type, title_id,
33 timestamp);
33} 34}
34 35
35std::string GetTimestamp() { 36std::string GetTimestamp() {
@@ -40,13 +41,13 @@ std::string GetTimestamp() {
40using namespace nlohmann; 41using namespace nlohmann;
41 42
42void SaveToFile(json json, const std::string& filename) { 43void SaveToFile(json json, const std::string& filename) {
43 if (!FileUtil::CreateFullPath(filename)) { 44 if (!Common::FS::CreateFullPath(filename)) {
44 LOG_ERROR(Core, "Failed to create path for '{}' to save report!", filename); 45 LOG_ERROR(Core, "Failed to create path for '{}' to save report!", filename);
45 return; 46 return;
46 } 47 }
47 48
48 std::ofstream file( 49 std::ofstream file(
49 FileUtil::SanitizePath(filename, FileUtil::DirectorySeparator::PlatformDefault)); 50 Common::FS::SanitizePath(filename, Common::FS::DirectorySeparator::PlatformDefault));
50 file << std::setw(4) << json << std::endl; 51 file << std::setw(4) << json << std::endl;
51} 52}
52 53
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 416b2d866..d328fb8b7 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -121,8 +121,8 @@ void LogSettings() {
121 log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue()); 121 log_setting("Audio_EnableAudioStretching", values.enable_audio_stretching.GetValue());
122 log_setting("Audio_OutputDevice", values.audio_device_id); 122 log_setting("Audio_OutputDevice", values.audio_device_id);
123 log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd); 123 log_setting("DataStorage_UseVirtualSd", values.use_virtual_sd);
124 log_setting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)); 124 log_setting("DataStorage_NandDir", Common::FS::GetUserPath(Common::FS::UserPath::NANDDir));
125 log_setting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)); 125 log_setting("DataStorage_SdmcDir", Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir));
126 log_setting("Debugging_UseGdbstub", values.use_gdbstub); 126 log_setting("Debugging_UseGdbstub", values.use_gdbstub);
127 log_setting("Debugging_GdbstubPort", values.gdbstub_port); 127 log_setting("Debugging_GdbstubPort", values.gdbstub_port);
128 log_setting("Debugging_ProgramArgs", values.program_args); 128 log_setting("Debugging_ProgramArgs", values.program_args);
diff --git a/src/core/settings.h b/src/core/settings.h
index bb145f193..3681b5e9d 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -359,7 +359,8 @@ enum class GPUAccuracy : u32 {
359 359
360enum class CPUAccuracy { 360enum class CPUAccuracy {
361 Accurate = 0, 361 Accurate = 0,
362 DebugMode = 1, 362 Unsafe = 1,
363 DebugMode = 2,
363}; 364};
364 365
365extern bool configuring_global; 366extern bool configuring_global;
@@ -419,6 +420,9 @@ struct Values {
419 bool cpuopt_misc_ir; 420 bool cpuopt_misc_ir;
420 bool cpuopt_reduce_misalign_checks; 421 bool cpuopt_reduce_misalign_checks;
421 422
423 bool cpuopt_unsafe_unfuse_fma;
424 bool cpuopt_unsafe_reduce_fp_error;
425
422 // Renderer 426 // Renderer
423 Setting<RendererBackend> renderer_backend; 427 Setting<RendererBackend> renderer_backend;
424 bool renderer_debug; 428 bool renderer_debug;
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index 5a30c75da..da09c0dbc 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -25,6 +25,8 @@
25 25
26namespace Core { 26namespace Core {
27 27
28namespace Telemetry = Common::Telemetry;
29
28static u64 GenerateTelemetryId() { 30static u64 GenerateTelemetryId() {
29 u64 telemetry_id{}; 31 u64 telemetry_id{};
30 32
@@ -70,12 +72,12 @@ static const char* TranslateGPUAccuracyLevel(Settings::GPUAccuracy backend) {
70 72
71u64 GetTelemetryId() { 73u64 GetTelemetryId() {
72 u64 telemetry_id{}; 74 u64 telemetry_id{};
73 const std::string filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + 75 const std::string filename{Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir) +
74 "telemetry_id"}; 76 "telemetry_id"};
75 77
76 bool generate_new_id = !FileUtil::Exists(filename); 78 bool generate_new_id = !Common::FS::Exists(filename);
77 if (!generate_new_id) { 79 if (!generate_new_id) {
78 FileUtil::IOFile file(filename, "rb"); 80 Common::FS::IOFile file(filename, "rb");
79 if (!file.IsOpen()) { 81 if (!file.IsOpen()) {
80 LOG_ERROR(Core, "failed to open telemetry_id: {}", filename); 82 LOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
81 return {}; 83 return {};
@@ -88,7 +90,7 @@ u64 GetTelemetryId() {
88 } 90 }
89 91
90 if (generate_new_id) { 92 if (generate_new_id) {
91 FileUtil::IOFile file(filename, "wb"); 93 Common::FS::IOFile file(filename, "wb");
92 if (!file.IsOpen()) { 94 if (!file.IsOpen()) {
93 LOG_ERROR(Core, "failed to open telemetry_id: {}", filename); 95 LOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
94 return {}; 96 return {};
@@ -102,10 +104,10 @@ u64 GetTelemetryId() {
102 104
103u64 RegenerateTelemetryId() { 105u64 RegenerateTelemetryId() {
104 const u64 new_telemetry_id{GenerateTelemetryId()}; 106 const u64 new_telemetry_id{GenerateTelemetryId()};
105 const std::string filename{FileUtil::GetUserPath(FileUtil::UserPath::ConfigDir) + 107 const std::string filename{Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir) +
106 "telemetry_id"}; 108 "telemetry_id"};
107 109
108 FileUtil::IOFile file(filename, "wb"); 110 Common::FS::IOFile file(filename, "wb");
109 if (!file.IsOpen()) { 111 if (!file.IsOpen()) {
110 LOG_ERROR(Core, "failed to open telemetry_id: {}", filename); 112 LOG_ERROR(Core, "failed to open telemetry_id: {}", filename);
111 return {}; 113 return {};
diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h
index 17ac22377..66789d4bd 100644
--- a/src/core/telemetry_session.h
+++ b/src/core/telemetry_session.h
@@ -52,7 +52,7 @@ public:
52 * @param value Value for the field to add. 52 * @param value Value for the field to add.
53 */ 53 */
54 template <typename T> 54 template <typename T>
55 void AddField(Telemetry::FieldType type, const char* name, T value) { 55 void AddField(Common::Telemetry::FieldType type, const char* name, T value) {
56 field_collection.AddField(type, name, std::move(value)); 56 field_collection.AddField(type, name, std::move(value));
57 } 57 }
58 58
@@ -63,7 +63,8 @@ public:
63 bool SubmitTestcase(); 63 bool SubmitTestcase();
64 64
65private: 65private:
66 Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session 66 /// Tracks all added fields for the session
67 Common::Telemetry::FieldCollection field_collection;
67}; 68};
68 69
69/** 70/**