summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorGravatar David2019-09-22 11:42:34 +1000
committerGravatar GitHub2019-09-22 11:42:34 +1000
commitc9ccdfbeac21ddd74d3cc79e8ef2c8d82f3d4efd (patch)
treee260125fd1ef6e8a29b255b967a447eeb1aeb204 /src/core
parentMerge pull request #2883 from ogniK5377/log-game (diff)
parentconfigure_debug: Move reporting option to logging (diff)
downloadyuzu-c9ccdfbeac21ddd74d3cc79e8ef2c8d82f3d4efd.tar.gz
yuzu-c9ccdfbeac21ddd74d3cc79e8ef2c8d82f3d4efd.tar.xz
yuzu-c9ccdfbeac21ddd74d3cc79e8ef2c8d82f3d4efd.zip
Merge pull request #2430 from DarkLordZach/fs-controller
core: Implement FileSystemController to deglobalize FS services
Diffstat (limited to 'src/core')
-rw-r--r--src/core/core.cpp24
-rw-r--r--src/core/core.h8
-rw-r--r--src/core/crypto/partition_data_manager.cpp4
-rw-r--r--src/core/crypto/partition_data_manager.h1
-rw-r--r--src/core/file_sys/bis_factory.cpp101
-rw-r--r--src/core/file_sys/bis_factory.h38
-rw-r--r--src/core/file_sys/card_image.cpp24
-rw-r--r--src/core/file_sys/card_image.h9
-rw-r--r--src/core/file_sys/content_archive.cpp8
-rw-r--r--src/core/file_sys/content_archive.h2
-rw-r--r--src/core/file_sys/patch_manager.cpp41
-rw-r--r--src/core/file_sys/registered_cache.cpp188
-rw-r--r--src/core/file_sys/registered_cache.h25
-rw-r--r--src/core/file_sys/romfs_factory.cpp16
-rw-r--r--src/core/file_sys/romfs_factory.h4
-rw-r--r--src/core/file_sys/savedata_factory.cpp68
-rw-r--r--src/core/file_sys/savedata_factory.h6
-rw-r--r--src/core/file_sys/sdmc_factory.cpp27
-rw-r--r--src/core/file_sys/sdmc_factory.h13
-rw-r--r--src/core/file_sys/submission_package.cpp3
-rw-r--r--src/core/hle/service/am/am.cpp24
-rw-r--r--src/core/hle/service/am/applet_ae.h4
-rw-r--r--src/core/hle/service/am/applet_oe.h4
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp329
-rw-r--r--src/core/hle/service/filesystem/filesystem.h116
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp80
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h4
-rw-r--r--src/core/hle/service/ns/ns.cpp4
-rw-r--r--src/core/hle/service/ns/ns.h14
-rw-r--r--src/core/hle/service/ns/pl_u.cpp5
-rw-r--r--src/core/hle/service/ns/pl_u.h14
-rw-r--r--src/core/hle/service/service.cpp3
-rw-r--r--src/core/hle/service/service.h8
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp4
-rw-r--r--src/core/loader/nca.cpp4
-rw-r--r--src/core/loader/nro.cpp4
-rw-r--r--src/core/loader/nsp.cpp4
-rw-r--r--src/core/loader/xci.cpp4
-rw-r--r--src/core/settings.cpp5
-rw-r--r--src/core/settings.h34
40 files changed, 1088 insertions, 190 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 9ab174de2..f22244cf7 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -14,8 +14,13 @@
14#include "core/core_cpu.h" 14#include "core/core_cpu.h"
15#include "core/core_timing.h" 15#include "core/core_timing.h"
16#include "core/cpu_core_manager.h" 16#include "core/cpu_core_manager.h"
17#include "core/file_sys/bis_factory.h"
18#include "core/file_sys/card_image.h"
17#include "core/file_sys/mode.h" 19#include "core/file_sys/mode.h"
18#include "core/file_sys/registered_cache.h" 20#include "core/file_sys/registered_cache.h"
21#include "core/file_sys/romfs_factory.h"
22#include "core/file_sys/savedata_factory.h"
23#include "core/file_sys/sdmc_factory.h"
19#include "core/file_sys/vfs_concat.h" 24#include "core/file_sys/vfs_concat.h"
20#include "core/file_sys/vfs_real.h" 25#include "core/file_sys/vfs_real.h"
21#include "core/gdbstub/gdbstub.h" 26#include "core/gdbstub/gdbstub.h"
@@ -27,6 +32,7 @@
27#include "core/hle/kernel/thread.h" 32#include "core/hle/kernel/thread.h"
28#include "core/hle/service/am/applets/applets.h" 33#include "core/hle/service/am/applets/applets.h"
29#include "core/hle/service/apm/controller.h" 34#include "core/hle/service/apm/controller.h"
35#include "core/hle/service/filesystem/filesystem.h"
30#include "core/hle/service/glue/manager.h" 36#include "core/hle/service/glue/manager.h"
31#include "core/hle/service/service.h" 37#include "core/hle/service/service.h"
32#include "core/hle/service/sm/sm.h" 38#include "core/hle/service/sm/sm.h"
@@ -202,6 +208,15 @@ struct System::Impl {
202 main_process->Run(load_parameters->main_thread_priority, 208 main_process->Run(load_parameters->main_thread_priority,
203 load_parameters->main_thread_stack_size); 209 load_parameters->main_thread_stack_size);
204 210
211 if (Settings::values.gamecard_inserted) {
212 if (Settings::values.gamecard_current_game) {
213 fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, filepath));
214 } else if (!Settings::values.gamecard_path.empty()) {
215 fs_controller.SetGameCard(
216 GetGameFileFromPath(virtual_filesystem, Settings::values.gamecard_path));
217 }
218 }
219
205 u64 title_id{0}; 220 u64 title_id{0};
206 if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) { 221 if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
207 LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", 222 LOG_ERROR(Core, "Failed to find title id for ROM (Error {})",
@@ -304,6 +319,7 @@ struct System::Impl {
304 FileSys::VirtualFilesystem virtual_filesystem; 319 FileSys::VirtualFilesystem virtual_filesystem;
305 /// ContentProviderUnion instance 320 /// ContentProviderUnion instance
306 std::unique_ptr<FileSys::ContentProviderUnion> content_provider; 321 std::unique_ptr<FileSys::ContentProviderUnion> content_provider;
322 Service::FileSystem::FileSystemController fs_controller;
307 /// AppLoader used to load the current executing application 323 /// AppLoader used to load the current executing application
308 std::unique_ptr<Loader::AppLoader> app_loader; 324 std::unique_ptr<Loader::AppLoader> app_loader;
309 std::unique_ptr<VideoCore::RendererBase> renderer; 325 std::unique_ptr<VideoCore::RendererBase> renderer;
@@ -571,6 +587,14 @@ const FileSys::ContentProvider& System::GetContentProvider() const {
571 return *impl->content_provider; 587 return *impl->content_provider;
572} 588}
573 589
590Service::FileSystem::FileSystemController& System::GetFileSystemController() {
591 return impl->fs_controller;
592}
593
594const Service::FileSystem::FileSystemController& System::GetFileSystemController() const {
595 return impl->fs_controller;
596}
597
574void System::RegisterContentProvider(FileSys::ContentProviderUnionSlot slot, 598void System::RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
575 FileSys::ContentProvider* provider) { 599 FileSys::ContentProvider* provider) {
576 impl->content_provider->SetSlot(slot, provider); 600 impl->content_provider->SetSlot(slot, provider);
diff --git a/src/core/core.h b/src/core/core.h
index 0138d93b0..bb2962fdd 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -47,6 +47,10 @@ namespace APM {
47class Controller; 47class Controller;
48} 48}
49 49
50namespace FileSystem {
51class FileSystemController;
52} // namespace FileSystem
53
50namespace Glue { 54namespace Glue {
51class ARPManager; 55class ARPManager;
52} 56}
@@ -299,6 +303,10 @@ public:
299 303
300 const FileSys::ContentProvider& GetContentProvider() const; 304 const FileSys::ContentProvider& GetContentProvider() const;
301 305
306 Service::FileSystem::FileSystemController& GetFileSystemController();
307
308 const Service::FileSystem::FileSystemController& GetFileSystemController() const;
309
302 void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot, 310 void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
303 FileSys::ContentProvider* provider); 311 FileSys::ContentProvider* provider);
304 312
diff --git a/src/core/crypto/partition_data_manager.cpp b/src/core/crypto/partition_data_manager.cpp
index 01a969be9..594cd82c5 100644
--- a/src/core/crypto/partition_data_manager.cpp
+++ b/src/core/crypto/partition_data_manager.cpp
@@ -480,6 +480,10 @@ void PartitionDataManager::DecryptProdInfo(std::array<u8, 0x20> bis_key) {
480 prodinfo_decrypted = std::make_shared<XTSEncryptionLayer>(prodinfo, bis_key); 480 prodinfo_decrypted = std::make_shared<XTSEncryptionLayer>(prodinfo, bis_key);
481} 481}
482 482
483FileSys::VirtualFile PartitionDataManager::GetDecryptedProdInfo() const {
484 return prodinfo_decrypted;
485}
486
483std::array<u8, 576> PartitionDataManager::GetETicketExtendedKek() const { 487std::array<u8, 576> PartitionDataManager::GetETicketExtendedKek() const {
484 std::array<u8, 0x240> out{}; 488 std::array<u8, 0x240> out{};
485 if (prodinfo_decrypted != nullptr) 489 if (prodinfo_decrypted != nullptr)
diff --git a/src/core/crypto/partition_data_manager.h b/src/core/crypto/partition_data_manager.h
index 0ad007c72..7a7b5d038 100644
--- a/src/core/crypto/partition_data_manager.h
+++ b/src/core/crypto/partition_data_manager.h
@@ -84,6 +84,7 @@ public:
84 bool HasProdInfo() const; 84 bool HasProdInfo() const;
85 FileSys::VirtualFile GetProdInfoRaw() const; 85 FileSys::VirtualFile GetProdInfoRaw() const;
86 void DecryptProdInfo(std::array<u8, 0x20> bis_key); 86 void DecryptProdInfo(std::array<u8, 0x20> bis_key);
87 FileSys::VirtualFile GetDecryptedProdInfo() const;
87 std::array<u8, 0x240> GetETicketExtendedKek() const; 88 std::array<u8, 0x240> GetETicketExtendedKek() const;
88 89
89private: 90private:
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp
index e29f70b3a..8f758d6d9 100644
--- a/src/core/file_sys/bis_factory.cpp
+++ b/src/core/file_sys/bis_factory.cpp
@@ -3,8 +3,12 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <fmt/format.h> 5#include <fmt/format.h>
6#include "common/file_util.h"
7#include "core/core.h"
6#include "core/file_sys/bis_factory.h" 8#include "core/file_sys/bis_factory.h"
9#include "core/file_sys/mode.h"
7#include "core/file_sys/registered_cache.h" 10#include "core/file_sys/registered_cache.h"
11#include "core/settings.h"
8 12
9namespace FileSys { 13namespace FileSys {
10 14
@@ -14,10 +18,22 @@ BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir
14 sysnand_cache(std::make_unique<RegisteredCache>( 18 sysnand_cache(std::make_unique<RegisteredCache>(
15 GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))), 19 GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))),
16 usrnand_cache(std::make_unique<RegisteredCache>( 20 usrnand_cache(std::make_unique<RegisteredCache>(
17 GetOrCreateDirectoryRelative(nand_root, "/user/Contents/registered"))) {} 21 GetOrCreateDirectoryRelative(nand_root, "/user/Contents/registered"))),
22 sysnand_placeholder(std::make_unique<PlaceholderCache>(
23 GetOrCreateDirectoryRelative(nand_root, "/system/Contents/placehld"))),
24 usrnand_placeholder(std::make_unique<PlaceholderCache>(
25 GetOrCreateDirectoryRelative(nand_root, "/user/Contents/placehld"))) {}
18 26
19BISFactory::~BISFactory() = default; 27BISFactory::~BISFactory() = default;
20 28
29VirtualDir BISFactory::GetSystemNANDContentDirectory() const {
30 return GetOrCreateDirectoryRelative(nand_root, "/system/Contents");
31}
32
33VirtualDir BISFactory::GetUserNANDContentDirectory() const {
34 return GetOrCreateDirectoryRelative(nand_root, "/user/Contents");
35}
36
21RegisteredCache* BISFactory::GetSystemNANDContents() const { 37RegisteredCache* BISFactory::GetSystemNANDContents() const {
22 return sysnand_cache.get(); 38 return sysnand_cache.get();
23} 39}
@@ -26,9 +42,17 @@ RegisteredCache* BISFactory::GetUserNANDContents() const {
26 return usrnand_cache.get(); 42 return usrnand_cache.get();
27} 43}
28 44
45PlaceholderCache* BISFactory::GetSystemNANDPlaceholder() const {
46 return sysnand_placeholder.get();
47}
48
49PlaceholderCache* BISFactory::GetUserNANDPlaceholder() const {
50 return usrnand_placeholder.get();
51}
52
29VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const { 53VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const {
30 // LayeredFS doesn't work on updates and title id-less homebrew 54 // LayeredFS doesn't work on updates and title id-less homebrew
31 if (title_id == 0 || (title_id & 0x800) > 0) 55 if (title_id == 0 || (title_id & 0xFFF) == 0x800)
32 return nullptr; 56 return nullptr;
33 return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id)); 57 return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id));
34} 58}
@@ -39,4 +63,77 @@ VirtualDir BISFactory::GetModificationDumpRoot(u64 title_id) const {
39 return GetOrCreateDirectoryRelative(dump_root, fmt::format("/{:016X}", title_id)); 63 return GetOrCreateDirectoryRelative(dump_root, fmt::format("/{:016X}", title_id));
40} 64}
41 65
66VirtualDir BISFactory::OpenPartition(BisPartitionId id) const {
67 switch (id) {
68 case BisPartitionId::CalibrationFile:
69 return GetOrCreateDirectoryRelative(nand_root, "/prodinfof");
70 case BisPartitionId::SafeMode:
71 return GetOrCreateDirectoryRelative(nand_root, "/safe");
72 case BisPartitionId::System:
73 return GetOrCreateDirectoryRelative(nand_root, "/system");
74 case BisPartitionId::User:
75 return GetOrCreateDirectoryRelative(nand_root, "/user");
76 default:
77 return nullptr;
78 }
79}
80
81VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id) const {
82 Core::Crypto::KeyManager keys;
83 Core::Crypto::PartitionDataManager pdm{
84 Core::System::GetInstance().GetFilesystem()->OpenDirectory(
85 FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), Mode::Read)};
86 keys.PopulateFromPartitionData(pdm);
87
88 switch (id) {
89 case BisPartitionId::CalibrationBinary:
90 return pdm.GetDecryptedProdInfo();
91 case BisPartitionId::BootConfigAndPackage2Part1:
92 case BisPartitionId::BootConfigAndPackage2Part2:
93 case BisPartitionId::BootConfigAndPackage2Part3:
94 case BisPartitionId::BootConfigAndPackage2Part4:
95 case BisPartitionId::BootConfigAndPackage2Part5:
96 case BisPartitionId::BootConfigAndPackage2Part6: {
97 const auto new_id = static_cast<u8>(id) -
98 static_cast<u8>(BisPartitionId::BootConfigAndPackage2Part1) +
99 static_cast<u8>(Core::Crypto::Package2Type::NormalMain);
100 return pdm.GetPackage2Raw(static_cast<Core::Crypto::Package2Type>(new_id));
101 }
102 default:
103 return nullptr;
104 }
105}
106
107VirtualDir BISFactory::GetImageDirectory() const {
108 return GetOrCreateDirectoryRelative(nand_root, "/user/Album");
109}
110
111u64 BISFactory::GetSystemNANDFreeSpace() const {
112 const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system");
113 if (sys_dir == nullptr)
114 return 0;
115
116 return GetSystemNANDTotalSpace() - sys_dir->GetSize();
117}
118
119u64 BISFactory::GetSystemNANDTotalSpace() const {
120 return static_cast<u64>(Settings::values.nand_system_size);
121}
122
123u64 BISFactory::GetUserNANDFreeSpace() const {
124 const auto usr_dir = GetOrCreateDirectoryRelative(nand_root, "/user");
125 if (usr_dir == nullptr)
126 return 0;
127
128 return GetUserNANDTotalSpace() - usr_dir->GetSize();
129}
130
131u64 BISFactory::GetUserNANDTotalSpace() const {
132 return static_cast<u64>(Settings::values.nand_user_size);
133}
134
135u64 BISFactory::GetFullNANDTotalSpace() const {
136 return static_cast<u64>(Settings::values.nand_total_size);
137}
138
42} // namespace FileSys 139} // namespace FileSys
diff --git a/src/core/file_sys/bis_factory.h b/src/core/file_sys/bis_factory.h
index 453c11ad2..bdfe728c9 100644
--- a/src/core/file_sys/bis_factory.h
+++ b/src/core/file_sys/bis_factory.h
@@ -10,7 +10,25 @@
10 10
11namespace FileSys { 11namespace FileSys {
12 12
13enum class BisPartitionId : u32 {
14 UserDataRoot = 20,
15 CalibrationBinary = 27,
16 CalibrationFile = 28,
17 BootConfigAndPackage2Part1 = 21,
18 BootConfigAndPackage2Part2 = 22,
19 BootConfigAndPackage2Part3 = 23,
20 BootConfigAndPackage2Part4 = 24,
21 BootConfigAndPackage2Part5 = 25,
22 BootConfigAndPackage2Part6 = 26,
23 SafeMode = 29,
24 System = 31,
25 SystemProperEncryption = 32,
26 SystemProperPartition = 33,
27 User = 30,
28};
29
13class RegisteredCache; 30class RegisteredCache;
31class PlaceholderCache;
14 32
15/// File system interface to the Built-In Storage 33/// File system interface to the Built-In Storage
16/// This is currently missing accessors to BIS partitions, but seemed like a good place for the NAND 34/// This is currently missing accessors to BIS partitions, but seemed like a good place for the NAND
@@ -20,12 +38,29 @@ public:
20 explicit BISFactory(VirtualDir nand_root, VirtualDir load_root, VirtualDir dump_root); 38 explicit BISFactory(VirtualDir nand_root, VirtualDir load_root, VirtualDir dump_root);
21 ~BISFactory(); 39 ~BISFactory();
22 40
41 VirtualDir GetSystemNANDContentDirectory() const;
42 VirtualDir GetUserNANDContentDirectory() const;
43
23 RegisteredCache* GetSystemNANDContents() const; 44 RegisteredCache* GetSystemNANDContents() const;
24 RegisteredCache* GetUserNANDContents() const; 45 RegisteredCache* GetUserNANDContents() const;
25 46
47 PlaceholderCache* GetSystemNANDPlaceholder() const;
48 PlaceholderCache* GetUserNANDPlaceholder() const;
49
26 VirtualDir GetModificationLoadRoot(u64 title_id) const; 50 VirtualDir GetModificationLoadRoot(u64 title_id) const;
27 VirtualDir GetModificationDumpRoot(u64 title_id) const; 51 VirtualDir GetModificationDumpRoot(u64 title_id) const;
28 52
53 VirtualDir OpenPartition(BisPartitionId id) const;
54 VirtualFile OpenPartitionStorage(BisPartitionId id) const;
55
56 VirtualDir GetImageDirectory() const;
57
58 u64 GetSystemNANDFreeSpace() const;
59 u64 GetSystemNANDTotalSpace() const;
60 u64 GetUserNANDFreeSpace() const;
61 u64 GetUserNANDTotalSpace() const;
62 u64 GetFullNANDTotalSpace() const;
63
29private: 64private:
30 VirtualDir nand_root; 65 VirtualDir nand_root;
31 VirtualDir load_root; 66 VirtualDir load_root;
@@ -33,6 +68,9 @@ private:
33 68
34 std::unique_ptr<RegisteredCache> sysnand_cache; 69 std::unique_ptr<RegisteredCache> sysnand_cache;
35 std::unique_ptr<RegisteredCache> usrnand_cache; 70 std::unique_ptr<RegisteredCache> usrnand_cache;
71
72 std::unique_ptr<PlaceholderCache> sysnand_placeholder;
73 std::unique_ptr<PlaceholderCache> usrnand_placeholder;
36}; 74};
37 75
38} // namespace FileSys 76} // namespace FileSys
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp
index 626ed0042..db54113a0 100644
--- a/src/core/file_sys/card_image.cpp
+++ b/src/core/file_sys/card_image.cpp
@@ -12,12 +12,16 @@
12#include "core/file_sys/content_archive.h" 12#include "core/file_sys/content_archive.h"
13#include "core/file_sys/nca_metadata.h" 13#include "core/file_sys/nca_metadata.h"
14#include "core/file_sys/partition_filesystem.h" 14#include "core/file_sys/partition_filesystem.h"
15#include "core/file_sys/romfs.h"
15#include "core/file_sys/submission_package.h" 16#include "core/file_sys/submission_package.h"
17#include "core/file_sys/vfs_concat.h"
16#include "core/file_sys/vfs_offset.h" 18#include "core/file_sys/vfs_offset.h"
19#include "core/file_sys/vfs_vector.h"
17#include "core/loader/loader.h" 20#include "core/loader/loader.h"
18 21
19namespace FileSys { 22namespace FileSys {
20 23
24constexpr u64 GAMECARD_CERTIFICATE_OFFSET = 0x7000;
21constexpr std::array partition_names{ 25constexpr std::array partition_names{
22 "update", 26 "update",
23 "normal", 27 "normal",
@@ -175,6 +179,26 @@ VirtualDir XCI::GetParentDirectory() const {
175 return file->GetContainingDirectory(); 179 return file->GetContainingDirectory();
176} 180}
177 181
182VirtualDir XCI::ConcatenatedPseudoDirectory() {
183 const auto out = std::make_shared<VectorVfsDirectory>();
184 for (const auto& part_id : {XCIPartition::Normal, XCIPartition::Logo, XCIPartition::Secure}) {
185 const auto& part = GetPartition(part_id);
186 if (part == nullptr)
187 continue;
188
189 for (const auto& file : part->GetFiles())
190 out->AddFile(file);
191 }
192
193 return out;
194}
195
196std::array<u8, 0x200> XCI::GetCertificate() const {
197 std::array<u8, 0x200> out;
198 file->Read(out.data(), out.size(), GAMECARD_CERTIFICATE_OFFSET);
199 return out;
200}
201
178Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { 202Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
179 const auto partition_index = static_cast<std::size_t>(part); 203 const auto partition_index = static_cast<std::size_t>(part);
180 const auto& partition = partitions[partition_index]; 204 const auto& partition = partitions[partition_index];
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h
index a350496f7..3e6b92ff3 100644
--- a/src/core/file_sys/card_image.h
+++ b/src/core/file_sys/card_image.h
@@ -91,6 +91,8 @@ public:
91 VirtualDir GetLogoPartition() const; 91 VirtualDir GetLogoPartition() const;
92 92
93 u64 GetProgramTitleID() const; 93 u64 GetProgramTitleID() const;
94 u32 GetSystemUpdateVersion();
95 u64 GetSystemUpdateTitleID() const;
94 96
95 bool HasProgramNCA() const; 97 bool HasProgramNCA() const;
96 VirtualFile GetProgramNCAFile() const; 98 VirtualFile GetProgramNCAFile() const;
@@ -106,6 +108,11 @@ public:
106 108
107 VirtualDir GetParentDirectory() const override; 109 VirtualDir GetParentDirectory() const override;
108 110
111 // Creates a directory that contains all the NCAs in the gamecard
112 VirtualDir ConcatenatedPseudoDirectory();
113
114 std::array<u8, 0x200> GetCertificate() const;
115
109private: 116private:
110 Loader::ResultStatus AddNCAFromPartition(XCIPartition part); 117 Loader::ResultStatus AddNCAFromPartition(XCIPartition part);
111 118
@@ -120,6 +127,8 @@ private:
120 std::shared_ptr<NCA> program; 127 std::shared_ptr<NCA> program;
121 std::vector<std::shared_ptr<NCA>> ncas; 128 std::vector<std::shared_ptr<NCA>> ncas;
122 129
130 u64 update_normal_partition_end;
131
123 Core::Crypto::KeyManager keys; 132 Core::Crypto::KeyManager keys;
124}; 133};
125} // namespace FileSys 134} // namespace FileSys
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp
index ce5c69b41..ea5c92f61 100644
--- a/src/core/file_sys/content_archive.cpp
+++ b/src/core/file_sys/content_archive.cpp
@@ -528,6 +528,14 @@ u64 NCA::GetTitleId() const {
528 return header.title_id; 528 return header.title_id;
529} 529}
530 530
531std::array<u8, 16> NCA::GetRightsId() const {
532 return header.rights_id;
533}
534
535u32 NCA::GetSDKVersion() const {
536 return header.sdk_version;
537}
538
531bool NCA::IsUpdate() const { 539bool NCA::IsUpdate() const {
532 return is_update; 540 return is_update;
533} 541}
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h
index 15b9e6624..e249079b5 100644
--- a/src/core/file_sys/content_archive.h
+++ b/src/core/file_sys/content_archive.h
@@ -112,6 +112,8 @@ public:
112 112
113 NCAContentType GetType() const; 113 NCAContentType GetType() const;
114 u64 GetTitleId() const; 114 u64 GetTitleId() const;
115 std::array<u8, 0x10> GetRightsId() const;
116 u32 GetSDKVersion() const;
115 bool IsUpdate() const; 117 bool IsUpdate() const;
116 118
117 VirtualFile GetRomFS() const; 119 VirtualFile GetRomFS() const;
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp
index a8f80e2c6..c1dd0c6d7 100644
--- a/src/core/file_sys/patch_manager.cpp
+++ b/src/core/file_sys/patch_manager.cpp
@@ -63,7 +63,8 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
63 63
64 if (Settings::values.dump_exefs) { 64 if (Settings::values.dump_exefs) {
65 LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id); 65 LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
66 const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id); 66 const auto dump_dir =
67 Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id);
67 if (dump_dir != nullptr) { 68 if (dump_dir != nullptr) {
68 const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs"); 69 const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
69 VfsRawCopyD(exefs, exefs_dir); 70 VfsRawCopyD(exefs, exefs_dir);
@@ -88,7 +89,8 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
88 } 89 }
89 90
90 // LayeredExeFS 91 // LayeredExeFS
91 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); 92 const auto load_dir =
93 Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
92 if (load_dir != nullptr && load_dir->GetSize() > 0) { 94 if (load_dir != nullptr && load_dir->GetSize() > 0) {
93 auto patch_dirs = load_dir->GetSubdirectories(); 95 auto patch_dirs = load_dir->GetSubdirectories();
94 std::sort( 96 std::sort(
@@ -174,7 +176,8 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
174 if (Settings::values.dump_nso) { 176 if (Settings::values.dump_nso) {
175 LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id, 177 LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id,
176 title_id); 178 title_id);
177 const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id); 179 const auto dump_dir =
180 Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id);
178 if (dump_dir != nullptr) { 181 if (dump_dir != nullptr) {
179 const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso"); 182 const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso");
180 const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id)); 183 const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id));
@@ -186,7 +189,13 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
186 189
187 LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id); 190 LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
188 191
189 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); 192 const auto load_dir =
193 Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
194 if (load_dir == nullptr) {
195 LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
196 return nso;
197 }
198
190 auto patch_dirs = load_dir->GetSubdirectories(); 199 auto patch_dirs = load_dir->GetSubdirectories();
191 std::sort(patch_dirs.begin(), patch_dirs.end(), 200 std::sort(patch_dirs.begin(), patch_dirs.end(),
192 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); 201 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
@@ -224,7 +233,13 @@ bool PatchManager::HasNSOPatch(const std::array<u8, 32>& build_id_) const {
224 233
225 LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id); 234 LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id);
226 235
227 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); 236 const auto load_dir =
237 Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
238 if (load_dir == nullptr) {
239 LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
240 return false;
241 }
242
228 auto patch_dirs = load_dir->GetSubdirectories(); 243 auto patch_dirs = load_dir->GetSubdirectories();
229 std::sort(patch_dirs.begin(), patch_dirs.end(), 244 std::sort(patch_dirs.begin(), patch_dirs.end(),
230 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); 245 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
@@ -258,7 +273,13 @@ static std::optional<CheatList> ReadCheatFileFromFolder(const Core::System& syst
258 273
259std::vector<CheatList> PatchManager::CreateCheatList(const Core::System& system, 274std::vector<CheatList> PatchManager::CreateCheatList(const Core::System& system,
260 const std::array<u8, 32>& build_id_) const { 275 const std::array<u8, 32>& build_id_) const {
261 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); 276 const auto load_dir =
277 Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
278 if (load_dir == nullptr) {
279 LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
280 return {};
281 }
282
262 auto patch_dirs = load_dir->GetSubdirectories(); 283 auto patch_dirs = load_dir->GetSubdirectories();
263 std::sort(patch_dirs.begin(), patch_dirs.end(), 284 std::sort(patch_dirs.begin(), patch_dirs.end(),
264 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); 285 [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
@@ -284,7 +305,8 @@ std::vector<CheatList> PatchManager::CreateCheatList(const Core::System& system,
284} 305}
285 306
286static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { 307static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) {
287 const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); 308 const auto load_dir =
309 Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
288 if ((type != ContentRecordType::Program && type != ContentRecordType::Data) || 310 if ((type != ContentRecordType::Program && type != ContentRecordType::Data) ||
289 load_dir == nullptr || load_dir->GetSize() <= 0) { 311 load_dir == nullptr || load_dir->GetSize() <= 0) {
290 return; 312 return;
@@ -393,6 +415,8 @@ static bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
393 415
394std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames( 416std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames(
395 VirtualFile update_raw) const { 417 VirtualFile update_raw) const {
418 if (title_id == 0)
419 return {};
396 std::map<std::string, std::string, std::less<>> out; 420 std::map<std::string, std::string, std::less<>> out;
397 const auto& installed = Core::System::GetInstance().GetContentProvider(); 421 const auto& installed = Core::System::GetInstance().GetContentProvider();
398 const auto& disabled = Settings::values.disabled_addons[title_id]; 422 const auto& disabled = Settings::values.disabled_addons[title_id];
@@ -423,7 +447,8 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
423 } 447 }
424 448
425 // General Mods (LayeredFS and IPS) 449 // General Mods (LayeredFS and IPS)
426 const auto mod_dir = Service::FileSystem::GetModificationLoadRoot(title_id); 450 const auto mod_dir =
451 Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
427 if (mod_dir != nullptr && mod_dir->GetSize() > 0) { 452 if (mod_dir != nullptr && mod_dir->GetSize() > 0) {
428 for (const auto& mod : mod_dir->GetSubdirectories()) { 453 for (const auto& mod : mod_dir->GetSubdirectories()) {
429 std::string types; 454 std::string types;
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp
index 3725b10f7..ac3fbd849 100644
--- a/src/core/file_sys/registered_cache.cpp
+++ b/src/core/file_sys/registered_cache.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <random>
6#include <regex> 7#include <regex>
7#include <mbedtls/sha256.h> 8#include <mbedtls/sha256.h>
8#include "common/assert.h" 9#include "common/assert.h"
@@ -48,18 +49,21 @@ static bool FollowsTwoDigitDirFormat(std::string_view name) {
48static bool FollowsNcaIdFormat(std::string_view name) { 49static bool FollowsNcaIdFormat(std::string_view name) {
49 static const std::regex nca_id_regex("[0-9A-F]{32}\\.nca", std::regex_constants::ECMAScript | 50 static const std::regex nca_id_regex("[0-9A-F]{32}\\.nca", std::regex_constants::ECMAScript |
50 std::regex_constants::icase); 51 std::regex_constants::icase);
51 return name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex); 52 static const std::regex nca_id_cnmt_regex(
53 "[0-9A-F]{32}\\.cnmt.nca", std::regex_constants::ECMAScript | std::regex_constants::icase);
54 return (name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex)) ||
55 (name.size() == 41 && std::regex_match(name.begin(), name.end(), nca_id_cnmt_regex));
52} 56}
53 57
54static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bool second_hex_upper, 58static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bool second_hex_upper,
55 bool within_two_digit) { 59 bool within_two_digit, bool cnmt_suffix) {
56 if (!within_two_digit) { 60 if (!within_two_digit)
57 return fmt::format("/{}.nca", Common::HexToString(nca_id, second_hex_upper)); 61 return fmt::format(cnmt_suffix ? "{}.cnmt.nca" : "/{}.nca",
58 } 62 Common::HexToString(nca_id, second_hex_upper));
59 63
60 Core::Crypto::SHA256Hash hash{}; 64 Core::Crypto::SHA256Hash hash{};
61 mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0); 65 mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0);
62 return fmt::format("/000000{:02X}/{}.nca", hash[0], 66 return fmt::format(cnmt_suffix ? "/000000{:02X}/{}.cnmt.nca" : "/000000{:02X}/{}.nca", hash[0],
63 Common::HexToString(nca_id, second_hex_upper)); 67 Common::HexToString(nca_id, second_hex_upper));
64} 68}
65 69
@@ -127,6 +131,156 @@ std::vector<ContentProviderEntry> ContentProvider::ListEntries() const {
127 return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt); 131 return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt);
128} 132}
129 133
134PlaceholderCache::PlaceholderCache(VirtualDir dir_) : dir(std::move(dir_)) {}
135
136bool PlaceholderCache::Create(const NcaID& id, u64 size) const {
137 const auto path = GetRelativePathFromNcaID(id, false, true, false);
138
139 if (dir->GetFileRelative(path) != nullptr) {
140 return false;
141 }
142
143 Core::Crypto::SHA256Hash hash{};
144 mbedtls_sha256(id.data(), id.size(), hash.data(), 0);
145 const auto dirname = fmt::format("000000{:02X}", hash[0]);
146
147 const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
148
149 if (dir2 == nullptr)
150 return false;
151
152 const auto file = dir2->CreateFile(fmt::format("{}.nca", Common::HexToString(id, false)));
153
154 if (file == nullptr)
155 return false;
156
157 return file->Resize(size);
158}
159
160bool PlaceholderCache::Delete(const NcaID& id) const {
161 const auto path = GetRelativePathFromNcaID(id, false, true, false);
162
163 if (dir->GetFileRelative(path) == nullptr) {
164 return false;
165 }
166
167 Core::Crypto::SHA256Hash hash{};
168 mbedtls_sha256(id.data(), id.size(), hash.data(), 0);
169 const auto dirname = fmt::format("000000{:02X}", hash[0]);
170
171 const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
172
173 const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexToString(id, false)));
174
175 return res;
176}
177
178bool PlaceholderCache::Exists(const NcaID& id) const {
179 const auto path = GetRelativePathFromNcaID(id, false, true, false);
180
181 return dir->GetFileRelative(path) != nullptr;
182}
183
184bool PlaceholderCache::Write(const NcaID& id, u64 offset, const std::vector<u8>& data) const {
185 const auto path = GetRelativePathFromNcaID(id, false, true, false);
186 const auto file = dir->GetFileRelative(path);
187
188 if (file == nullptr)
189 return false;
190
191 return file->WriteBytes(data, offset) == data.size();
192}
193
194bool PlaceholderCache::Register(RegisteredCache* cache, const NcaID& placeholder,
195 const NcaID& install) const {
196 const auto path = GetRelativePathFromNcaID(placeholder, false, true, false);
197 const auto file = dir->GetFileRelative(path);
198
199 if (file == nullptr)
200 return false;
201
202 const auto res = cache->RawInstallNCA(NCA{file}, &VfsRawCopy, false, install);
203
204 if (res != InstallResult::Success)
205 return false;
206
207 return Delete(placeholder);
208}
209
210bool PlaceholderCache::CleanAll() const {
211 return dir->GetParentDirectory()->CleanSubdirectoryRecursive(dir->GetName());
212}
213
214std::optional<std::array<u8, 0x10>> PlaceholderCache::GetRightsID(const NcaID& id) const {
215 const auto path = GetRelativePathFromNcaID(id, false, true, false);
216 const auto file = dir->GetFileRelative(path);
217
218 if (file == nullptr)
219 return std::nullopt;
220
221 NCA nca{file};
222
223 if (nca.GetStatus() != Loader::ResultStatus::Success &&
224 nca.GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
225 return std::nullopt;
226 }
227
228 const auto rights_id = nca.GetRightsId();
229 if (rights_id == NcaID{})
230 return std::nullopt;
231
232 return rights_id;
233}
234
235u64 PlaceholderCache::Size(const NcaID& id) const {
236 const auto path = GetRelativePathFromNcaID(id, false, true, false);
237 const auto file = dir->GetFileRelative(path);
238
239 if (file == nullptr)
240 return 0;
241
242 return file->GetSize();
243}
244
245bool PlaceholderCache::SetSize(const NcaID& id, u64 new_size) const {
246 const auto path = GetRelativePathFromNcaID(id, false, true, false);
247 const auto file = dir->GetFileRelative(path);
248
249 if (file == nullptr)
250 return false;
251
252 return file->Resize(new_size);
253}
254
255std::vector<NcaID> PlaceholderCache::List() const {
256 std::vector<NcaID> out;
257 for (const auto& sdir : dir->GetSubdirectories()) {
258 for (const auto& file : sdir->GetFiles()) {
259 const auto name = file->GetName();
260 if (name.length() == 36 && name[32] == '.' && name[33] == 'n' && name[34] == 'c' &&
261 name[35] == 'a') {
262 out.push_back(Common::HexStringToArray<0x10>(name.substr(0, 32)));
263 }
264 }
265 }
266 return out;
267}
268
269NcaID PlaceholderCache::Generate() {
270 std::random_device device;
271 std::mt19937 gen(device());
272 std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
273
274 NcaID out{};
275
276 const auto v1 = distribution(gen);
277 const auto v2 = distribution(gen);
278 std::memcpy(out.data(), &v1, sizeof(u64));
279 std::memcpy(out.data() + sizeof(u64), &v2, sizeof(u64));
280
281 return out;
282}
283
130VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, 284VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
131 std::string_view path) const { 285 std::string_view path) const {
132 const auto file = dir->GetFileRelative(path); 286 const auto file = dir->GetFileRelative(path);
@@ -169,14 +323,18 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
169 323
170VirtualFile RegisteredCache::GetFileAtID(NcaID id) const { 324VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
171 VirtualFile file; 325 VirtualFile file;
172 // Try all four modes of file storage: 326 // Try all five relevant modes of file storage:
173 // (bit 1 = uppercase/lower, bit 0 = within a two-digit dir) 327 // (bit 2 = uppercase/lower, bit 1 = within a two-digit dir, bit 0 = .cnmt suffix)
174 // 00: /000000**/{:032X}.nca 328 // 000: /000000**/{:032X}.nca
175 // 01: /{:032X}.nca 329 // 010: /{:032X}.nca
176 // 10: /000000**/{:032x}.nca 330 // 100: /000000**/{:032x}.nca
177 // 11: /{:032x}.nca 331 // 110: /{:032x}.nca
178 for (u8 i = 0; i < 4; ++i) { 332 // 111: /{:032x}.cnmt.nca
179 const auto path = GetRelativePathFromNcaID(id, (i & 0b10) == 0, (i & 0b01) == 0); 333 for (u8 i = 0; i < 8; ++i) {
334 if ((i % 2) == 1 && i != 7)
335 continue;
336 const auto path =
337 GetRelativePathFromNcaID(id, (i & 0b100) == 0, (i & 0b010) == 0, (i & 0b001) == 0b001);
180 file = OpenFileOrDirectoryConcat(dir, path); 338 file = OpenFileOrDirectoryConcat(dir, path);
181 if (file != nullptr) 339 if (file != nullptr)
182 return file; 340 return file;
@@ -472,7 +630,7 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
472 memcpy(id.data(), hash.data(), 16); 630 memcpy(id.data(), hash.data(), 16);
473 } 631 }
474 632
475 std::string path = GetRelativePathFromNcaID(id, false, true); 633 std::string path = GetRelativePathFromNcaID(id, false, true, false);
476 634
477 if (GetFileAtID(id) != nullptr && !overwrite_if_exists) { 635 if (GetFileAtID(id) != nullptr && !overwrite_if_exists) {
478 LOG_WARNING(Loader, "Attempting to overwrite existing NCA. Skipping..."); 636 LOG_WARNING(Loader, "Attempting to overwrite existing NCA. Skipping...");
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h
index 4398d63e1..d1eec240e 100644
--- a/src/core/file_sys/registered_cache.h
+++ b/src/core/file_sys/registered_cache.h
@@ -25,6 +25,8 @@ enum class NCAContentType : u8;
25enum class TitleType : u8; 25enum class TitleType : u8;
26 26
27struct ContentRecord; 27struct ContentRecord;
28struct MetaRecord;
29class RegisteredCache;
28 30
29using NcaID = std::array<u8, 0x10>; 31using NcaID = std::array<u8, 0x10>;
30using ContentProviderParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>; 32using ContentProviderParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>;
@@ -89,6 +91,27 @@ protected:
89 Core::Crypto::KeyManager keys; 91 Core::Crypto::KeyManager keys;
90}; 92};
91 93
94class PlaceholderCache {
95public:
96 explicit PlaceholderCache(VirtualDir dir);
97
98 bool Create(const NcaID& id, u64 size) const;
99 bool Delete(const NcaID& id) const;
100 bool Exists(const NcaID& id) const;
101 bool Write(const NcaID& id, u64 offset, const std::vector<u8>& data) const;
102 bool Register(RegisteredCache* cache, const NcaID& placeholder, const NcaID& install) const;
103 bool CleanAll() const;
104 std::optional<std::array<u8, 0x10>> GetRightsID(const NcaID& id) const;
105 u64 Size(const NcaID& id) const;
106 bool SetSize(const NcaID& id, u64 new_size) const;
107 std::vector<NcaID> List() const;
108
109 static NcaID Generate();
110
111private:
112 VirtualDir dir;
113};
114
92/* 115/*
93 * A class that catalogues NCAs in the registered directory structure. 116 * A class that catalogues NCAs in the registered directory structure.
94 * Nintendo's registered format follows this structure: 117 * Nintendo's registered format follows this structure:
@@ -103,6 +126,8 @@ protected:
103 * when 4GB splitting can be ignored.) 126 * when 4GB splitting can be ignored.)
104 */ 127 */
105class RegisteredCache : public ContentProvider { 128class RegisteredCache : public ContentProvider {
129 friend class PlaceholderCache;
130
106public: 131public:
107 // Parsing function defines the conversion from raw file to NCA. If there are other steps 132 // Parsing function defines the conversion from raw file to NCA. If there are other steps
108 // besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom 133 // besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom
diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp
index b2ccb2926..84cd4684c 100644
--- a/src/core/file_sys/romfs_factory.cpp
+++ b/src/core/file_sys/romfs_factory.cpp
@@ -7,6 +7,7 @@
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/file_sys/card_image.h"
10#include "core/file_sys/content_archive.h" 11#include "core/file_sys/content_archive.h"
11#include "core/file_sys/nca_metadata.h" 12#include "core/file_sys/nca_metadata.h"
12#include "core/file_sys/patch_manager.h" 13#include "core/file_sys/patch_manager.h"
@@ -34,7 +35,7 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) {
34 this->update_raw = std::move(update_raw); 35 this->update_raw = std::move(update_raw);
35} 36}
36 37
37ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() { 38ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() const {
38 if (!updatable) 39 if (!updatable)
39 return MakeResult<VirtualFile>(file); 40 return MakeResult<VirtualFile>(file);
40 41
@@ -43,7 +44,8 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
43 patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw)); 44 patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw));
44} 45}
45 46
46ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) { 47ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage,
48 ContentRecordType type) const {
47 std::shared_ptr<NCA> res; 49 std::shared_ptr<NCA> res;
48 50
49 switch (storage) { 51 switch (storage) {
@@ -51,13 +53,17 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, Conte
51 res = Core::System::GetInstance().GetContentProvider().GetEntry(title_id, type); 53 res = Core::System::GetInstance().GetContentProvider().GetEntry(title_id, type);
52 break; 54 break;
53 case StorageId::NandSystem: 55 case StorageId::NandSystem:
54 res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type); 56 res =
57 Core::System::GetInstance().GetFileSystemController().GetSystemNANDContents()->GetEntry(
58 title_id, type);
55 break; 59 break;
56 case StorageId::NandUser: 60 case StorageId::NandUser:
57 res = Service::FileSystem::GetUserNANDContents()->GetEntry(title_id, type); 61 res = Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->GetEntry(
62 title_id, type);
58 break; 63 break;
59 case StorageId::SdCard: 64 case StorageId::SdCard:
60 res = Service::FileSystem::GetSDMCContents()->GetEntry(title_id, type); 65 res = Core::System::GetInstance().GetFileSystemController().GetSDMCContents()->GetEntry(
66 title_id, type);
61 break; 67 break;
62 default: 68 default:
63 UNIMPLEMENTED_MSG("Unimplemented storage_id={:02X}", static_cast<u8>(storage)); 69 UNIMPLEMENTED_MSG("Unimplemented storage_id={:02X}", static_cast<u8>(storage));
diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h
index 7724c0b23..da63a313a 100644
--- a/src/core/file_sys/romfs_factory.h
+++ b/src/core/file_sys/romfs_factory.h
@@ -33,8 +33,8 @@ public:
33 ~RomFSFactory(); 33 ~RomFSFactory();
34 34
35 void SetPackedUpdate(VirtualFile update_raw); 35 void SetPackedUpdate(VirtualFile update_raw);
36 ResultVal<VirtualFile> OpenCurrentProcess(); 36 ResultVal<VirtualFile> OpenCurrentProcess() const;
37 ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type); 37 ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type) const;
38 38
39private: 39private:
40 VirtualFile file; 40 VirtualFile file;
diff --git a/src/core/file_sys/savedata_factory.cpp b/src/core/file_sys/savedata_factory.cpp
index 7974b031d..f77cc02ac 100644
--- a/src/core/file_sys/savedata_factory.cpp
+++ b/src/core/file_sys/savedata_factory.cpp
@@ -15,22 +15,8 @@ namespace FileSys {
15 15
16constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size"; 16constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size";
17 17
18std::string SaveDataDescriptor::DebugInfo() const { 18namespace {
19 return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, " 19void PrintSaveDataDescriptorWarnings(SaveDataDescriptor meta) {
20 "rank={}, index={}]",
21 static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id,
22 static_cast<u8>(rank), index);
23}
24
25SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
26 // Delete all temporary storages
27 // On hardware, it is expected that temporary storage be empty at first use.
28 dir->DeleteSubdirectoryRecursive("temp");
29}
30
31SaveDataFactory::~SaveDataFactory() = default;
32
33ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataDescriptor& meta) {
34 if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) { 20 if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
35 if (meta.zero_1 != 0) { 21 if (meta.zero_1 != 0) {
36 LOG_WARNING(Service_FS, 22 LOG_WARNING(Service_FS,
@@ -65,23 +51,51 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, const SaveDat
65 "non-zero ({:016X}{:016X})", 51 "non-zero ({:016X}{:016X})",
66 meta.user_id[1], meta.user_id[0]); 52 meta.user_id[1], meta.user_id[0]);
67 } 53 }
54}
55} // Anonymous namespace
68 56
69 std::string save_directory = 57std::string SaveDataDescriptor::DebugInfo() const {
70 GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id); 58 return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, "
59 "save_id={:016X}, "
60 "rank={}, index={}]",
61 static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id,
62 static_cast<u8>(rank), index);
63}
71 64
72 // TODO(DarkLordZach): Try to not create when opening, there are dedicated create save methods. 65SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
73 // But, user_ids don't match so this works for now. 66 // Delete all temporary storages
67 // On hardware, it is expected that temporary storage be empty at first use.
68 dir->DeleteSubdirectoryRecursive("temp");
69}
74 70
75 auto out = dir->GetDirectoryRelative(save_directory); 71SaveDataFactory::~SaveDataFactory() = default;
72
73ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
74 const SaveDataDescriptor& meta) const {
75 PrintSaveDataDescriptorWarnings(meta);
76
77 const auto save_directory =
78 GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
79
80 auto out = dir->CreateDirectoryRelative(save_directory);
76 81
82 // Return an error if the save data doesn't actually exist.
77 if (out == nullptr) { 83 if (out == nullptr) {
78 // TODO(bunnei): This is a work-around to always create a save data directory if it does not 84 // TODO(DarkLordZach): Find out correct error code.
79 // already exist. This is a hack, as we do not understand yet how this works on hardware. 85 return ResultCode(-1);
80 // Without a save data directory, many games will assert on boot. This should not have any
81 // bad side-effects.
82 out = dir->CreateDirectoryRelative(save_directory);
83 } 86 }
84 87
88 return MakeResult<VirtualDir>(std::move(out));
89}
90
91ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
92 const SaveDataDescriptor& meta) const {
93
94 const auto save_directory =
95 GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
96
97 auto out = dir->GetDirectoryRelative(save_directory);
98
85 // Return an error if the save data doesn't actually exist. 99 // Return an error if the save data doesn't actually exist.
86 if (out == nullptr) { 100 if (out == nullptr) {
87 // TODO(Subv): Find out correct error code. 101 // TODO(Subv): Find out correct error code.
@@ -152,7 +166,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
152} 166}
153 167
154void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, 168void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
155 SaveDataSize new_value) { 169 SaveDataSize new_value) const {
156 const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0); 170 const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
157 const auto dir = GetOrCreateDirectoryRelative(this->dir, path); 171 const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
158 172
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h
index b73654571..991e57aa1 100644
--- a/src/core/file_sys/savedata_factory.h
+++ b/src/core/file_sys/savedata_factory.h
@@ -64,7 +64,8 @@ public:
64 explicit SaveDataFactory(VirtualDir dir); 64 explicit SaveDataFactory(VirtualDir dir);
65 ~SaveDataFactory(); 65 ~SaveDataFactory();
66 66
67 ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataDescriptor& meta); 67 ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataDescriptor& meta) const;
68 ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataDescriptor& meta) const;
68 69
69 VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const; 70 VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
70 71
@@ -73,7 +74,8 @@ public:
73 u128 user_id, u64 save_id); 74 u128 user_id, u64 save_id);
74 75
75 SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const; 76 SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const;
76 void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, SaveDataSize new_value); 77 void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
78 SaveDataSize new_value) const;
77 79
78private: 80private:
79 VirtualDir dir; 81 VirtualDir dir;
diff --git a/src/core/file_sys/sdmc_factory.cpp b/src/core/file_sys/sdmc_factory.cpp
index bd3a57058..5113a1ca6 100644
--- a/src/core/file_sys/sdmc_factory.cpp
+++ b/src/core/file_sys/sdmc_factory.cpp
@@ -6,6 +6,7 @@
6#include "core/file_sys/registered_cache.h" 6#include "core/file_sys/registered_cache.h"
7#include "core/file_sys/sdmc_factory.h" 7#include "core/file_sys/sdmc_factory.h"
8#include "core/file_sys/xts_archive.h" 8#include "core/file_sys/xts_archive.h"
9#include "core/settings.h"
9 10
10namespace FileSys { 11namespace FileSys {
11 12
@@ -14,16 +15,38 @@ SDMCFactory::SDMCFactory(VirtualDir dir_)
14 GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"), 15 GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"),
15 [](const VirtualFile& file, const NcaID& id) { 16 [](const VirtualFile& file, const NcaID& id) {
16 return NAX{file, id}.GetDecrypted(); 17 return NAX{file, id}.GetDecrypted();
17 })) {} 18 })),
19 placeholder(std::make_unique<PlaceholderCache>(
20 GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/placehld"))) {}
18 21
19SDMCFactory::~SDMCFactory() = default; 22SDMCFactory::~SDMCFactory() = default;
20 23
21ResultVal<VirtualDir> SDMCFactory::Open() { 24ResultVal<VirtualDir> SDMCFactory::Open() const {
22 return MakeResult<VirtualDir>(dir); 25 return MakeResult<VirtualDir>(dir);
23} 26}
24 27
28VirtualDir SDMCFactory::GetSDMCContentDirectory() const {
29 return GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents");
30}
31
25RegisteredCache* SDMCFactory::GetSDMCContents() const { 32RegisteredCache* SDMCFactory::GetSDMCContents() const {
26 return contents.get(); 33 return contents.get();
27} 34}
28 35
36PlaceholderCache* SDMCFactory::GetSDMCPlaceholder() const {
37 return placeholder.get();
38}
39
40VirtualDir SDMCFactory::GetImageDirectory() const {
41 return GetOrCreateDirectoryRelative(dir, "/Nintendo/Album");
42}
43
44u64 SDMCFactory::GetSDMCFreeSpace() const {
45 return GetSDMCTotalSpace() - dir->GetSize();
46}
47
48u64 SDMCFactory::GetSDMCTotalSpace() const {
49 return static_cast<u64>(Settings::values.sdmc_size);
50}
51
29} // namespace FileSys 52} // namespace FileSys
diff --git a/src/core/file_sys/sdmc_factory.h b/src/core/file_sys/sdmc_factory.h
index 42794ba5b..42dc4e08a 100644
--- a/src/core/file_sys/sdmc_factory.h
+++ b/src/core/file_sys/sdmc_factory.h
@@ -11,6 +11,7 @@
11namespace FileSys { 11namespace FileSys {
12 12
13class RegisteredCache; 13class RegisteredCache;
14class PlaceholderCache;
14 15
15/// File system interface to the SDCard archive 16/// File system interface to the SDCard archive
16class SDMCFactory { 17class SDMCFactory {
@@ -18,13 +19,23 @@ public:
18 explicit SDMCFactory(VirtualDir dir); 19 explicit SDMCFactory(VirtualDir dir);
19 ~SDMCFactory(); 20 ~SDMCFactory();
20 21
21 ResultVal<VirtualDir> Open(); 22 ResultVal<VirtualDir> Open() const;
23
24 VirtualDir GetSDMCContentDirectory() const;
25
22 RegisteredCache* GetSDMCContents() const; 26 RegisteredCache* GetSDMCContents() const;
27 PlaceholderCache* GetSDMCPlaceholder() const;
28
29 VirtualDir GetImageDirectory() const;
30
31 u64 GetSDMCFreeSpace() const;
32 u64 GetSDMCTotalSpace() const;
23 33
24private: 34private:
25 VirtualDir dir; 35 VirtualDir dir;
26 36
27 std::unique_ptr<RegisteredCache> contents; 37 std::unique_ptr<RegisteredCache> contents;
38 std::unique_ptr<PlaceholderCache> placeholder;
28}; 39};
29 40
30} // namespace FileSys 41} // namespace FileSys
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp
index 730221fd6..ef3084681 100644
--- a/src/core/file_sys/submission_package.cpp
+++ b/src/core/file_sys/submission_package.cpp
@@ -248,7 +248,8 @@ void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) {
248 248
249void NSP::ReadNCAs(const std::vector<VirtualFile>& files) { 249void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
250 for (const auto& outer_file : files) { 250 for (const auto& outer_file : files) {
251 if (outer_file->GetName().substr(outer_file->GetName().size() - 9) != ".cnmt.nca") { 251 if (outer_file->GetName().size() < 9 ||
252 outer_file->GetName().substr(outer_file->GetName().size() - 9) != ".cnmt.nca") {
252 continue; 253 continue;
253 } 254 }
254 255
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index aa2c83937..6c594dcaf 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -1143,13 +1143,21 @@ void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(
1143 1143
1144void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { 1144void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
1145 IPC::RequestParser rp{ctx}; 1145 IPC::RequestParser rp{ctx};
1146 u128 uid = rp.PopRaw<u128>(); // What does this do? 1146 u128 user_id = rp.PopRaw<u128>();
1147 LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]); 1147
1148 LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
1149
1150 FileSys::SaveDataDescriptor descriptor{};
1151 descriptor.title_id = Core::CurrentProcess()->GetTitleID();
1152 descriptor.user_id = user_id;
1153 descriptor.type = FileSys::SaveDataType::SaveData;
1154 const auto res = system.GetFileSystemController().CreateSaveData(
1155 FileSys::SaveDataSpaceId::NandUser, descriptor);
1148 1156
1149 IPC::ResponseBuilder rb{ctx, 4}; 1157 IPC::ResponseBuilder rb{ctx, 4};
1150 rb.Push(RESULT_SUCCESS); 1158 rb.Push(res.Code());
1151 rb.Push<u64>(0); 1159 rb.Push<u64>(0);
1152} // namespace Service::AM 1160}
1153 1161
1154void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) { 1162void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
1155 // Takes an input u32 Result, no output. 1163 // Takes an input u32 Result, no output.
@@ -1261,8 +1269,8 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
1261 "new_journal={:016X}", 1269 "new_journal={:016X}",
1262 static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size); 1270 static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
1263 1271
1264 const auto title_id = system.CurrentProcess()->GetTitleID(); 1272 system.GetFileSystemController().WriteSaveDataSize(
1265 FileSystem::WriteSaveDataSize(type, title_id, user_id, {new_normal_size, new_journal_size}); 1273 type, system.CurrentProcess()->GetTitleID(), user_id, {new_normal_size, new_journal_size});
1266 1274
1267 IPC::ResponseBuilder rb{ctx, 4}; 1275 IPC::ResponseBuilder rb{ctx, 4};
1268 rb.Push(RESULT_SUCCESS); 1276 rb.Push(RESULT_SUCCESS);
@@ -1281,8 +1289,8 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
1281 LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type), 1289 LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type),
1282 user_id[1], user_id[0]); 1290 user_id[1], user_id[0]);
1283 1291
1284 const auto title_id = system.CurrentProcess()->GetTitleID(); 1292 const auto size = system.GetFileSystemController().ReadSaveDataSize(
1285 const auto size = FileSystem::ReadSaveDataSize(type, title_id, user_id); 1293 type, system.CurrentProcess()->GetTitleID(), user_id);
1286 1294
1287 IPC::ResponseBuilder rb{ctx, 6}; 1295 IPC::ResponseBuilder rb{ctx, 6};
1288 rb.Push(RESULT_SUCCESS); 1296 rb.Push(RESULT_SUCCESS);
diff --git a/src/core/hle/service/am/applet_ae.h b/src/core/hle/service/am/applet_ae.h
index 9e006cd9d..0e0d10858 100644
--- a/src/core/hle/service/am/applet_ae.h
+++ b/src/core/hle/service/am/applet_ae.h
@@ -9,6 +9,10 @@
9#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
10 10
11namespace Service { 11namespace Service {
12namespace FileSystem {
13class FileSystemController;
14}
15
12namespace NVFlinger { 16namespace NVFlinger {
13class NVFlinger; 17class NVFlinger;
14} 18}
diff --git a/src/core/hle/service/am/applet_oe.h b/src/core/hle/service/am/applet_oe.h
index 22c05419d..99a65e7b5 100644
--- a/src/core/hle/service/am/applet_oe.h
+++ b/src/core/hle/service/am/applet_oe.h
@@ -9,6 +9,10 @@
9#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
10 10
11namespace Service { 11namespace Service {
12namespace FileSystem {
13class FileSystemController;
14}
15
12namespace NVFlinger { 16namespace NVFlinger {
13class NVFlinger; 17class NVFlinger;
14} 18}
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 8ce110dd1..14cd0e322 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -8,6 +8,7 @@
8#include "common/file_util.h" 8#include "common/file_util.h"
9#include "core/core.h" 9#include "core/core.h"
10#include "core/file_sys/bis_factory.h" 10#include "core/file_sys/bis_factory.h"
11#include "core/file_sys/card_image.h"
11#include "core/file_sys/control_metadata.h" 12#include "core/file_sys/control_metadata.h"
12#include "core/file_sys/errors.h" 13#include "core/file_sys/errors.h"
13#include "core/file_sys/mode.h" 14#include "core/file_sys/mode.h"
@@ -25,14 +26,10 @@
25#include "core/hle/service/filesystem/fsp_pr.h" 26#include "core/hle/service/filesystem/fsp_pr.h"
26#include "core/hle/service/filesystem/fsp_srv.h" 27#include "core/hle/service/filesystem/fsp_srv.h"
27#include "core/loader/loader.h" 28#include "core/loader/loader.h"
29#include "core/settings.h"
28 30
29namespace Service::FileSystem { 31namespace Service::FileSystem {
30 32
31// Size of emulated sd card free space, reported in bytes.
32// Just using 32GB because thats reasonable
33// TODO(DarkLordZach): Eventually make this configurable in settings.
34constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000;
35
36// A default size for normal/journal save data size if application control metadata cannot be found. 33// A default size for normal/journal save data size if application control metadata cannot be found.
37// This should be large enough to satisfy even the most extreme requirements (~4.2GB) 34// This should be large enough to satisfy even the most extreme requirements (~4.2GB)
38constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000; 35constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000;
@@ -226,13 +223,6 @@ ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const s
226 return MakeResult(dir); 223 return MakeResult(dir);
227} 224}
228 225
229u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const {
230 if (backing->IsWritable())
231 return EMULATED_SD_REPORTED_SIZE;
232
233 return 0;
234}
235
236ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType( 226ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
237 const std::string& path_) const { 227 const std::string& path_) const {
238 std::string path(FileUtil::SanitizePath(path_)); 228 std::string path(FileUtil::SanitizePath(path_));
@@ -251,44 +241,39 @@ ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
251 return FileSys::ERROR_PATH_NOT_FOUND; 241 return FileSys::ERROR_PATH_NOT_FOUND;
252} 242}
253 243
254/** 244FileSystemController::FileSystemController() = default;
255 * Map of registered file systems, identified by type. Once an file system is registered here, it 245
256 * is never removed until UnregisterFileSystems is called. 246FileSystemController::~FileSystemController() = default;
257 */
258static std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
259static std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
260static std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
261static std::unique_ptr<FileSys::BISFactory> bis_factory;
262 247
263ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) { 248ResultCode FileSystemController::RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
264 ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second RomFS");
265 romfs_factory = std::move(factory); 249 romfs_factory = std::move(factory);
266 LOG_DEBUG(Service_FS, "Registered RomFS"); 250 LOG_DEBUG(Service_FS, "Registered RomFS");
267 return RESULT_SUCCESS; 251 return RESULT_SUCCESS;
268} 252}
269 253
270ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory) { 254ResultCode FileSystemController::RegisterSaveData(
271 ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second save data"); 255 std::unique_ptr<FileSys::SaveDataFactory>&& factory) {
256 ASSERT_MSG(save_data_factory == nullptr, "Tried to register a second save data");
272 save_data_factory = std::move(factory); 257 save_data_factory = std::move(factory);
273 LOG_DEBUG(Service_FS, "Registered save data"); 258 LOG_DEBUG(Service_FS, "Registered save data");
274 return RESULT_SUCCESS; 259 return RESULT_SUCCESS;
275} 260}
276 261
277ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) { 262ResultCode FileSystemController::RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
278 ASSERT_MSG(sdmc_factory == nullptr, "Tried to register a second SDMC"); 263 ASSERT_MSG(sdmc_factory == nullptr, "Tried to register a second SDMC");
279 sdmc_factory = std::move(factory); 264 sdmc_factory = std::move(factory);
280 LOG_DEBUG(Service_FS, "Registered SDMC"); 265 LOG_DEBUG(Service_FS, "Registered SDMC");
281 return RESULT_SUCCESS; 266 return RESULT_SUCCESS;
282} 267}
283 268
284ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) { 269ResultCode FileSystemController::RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
285 ASSERT_MSG(bis_factory == nullptr, "Tried to register a second BIS"); 270 ASSERT_MSG(bis_factory == nullptr, "Tried to register a second BIS");
286 bis_factory = std::move(factory); 271 bis_factory = std::move(factory);
287 LOG_DEBUG(Service_FS, "Registered BIS"); 272 LOG_DEBUG(Service_FS, "Registered BIS");
288 return RESULT_SUCCESS; 273 return RESULT_SUCCESS;
289} 274}
290 275
291void SetPackedUpdate(FileSys::VirtualFile update_raw) { 276void FileSystemController::SetPackedUpdate(FileSys::VirtualFile update_raw) {
292 LOG_TRACE(Service_FS, "Setting packed update for romfs"); 277 LOG_TRACE(Service_FS, "Setting packed update for romfs");
293 278
294 if (romfs_factory == nullptr) 279 if (romfs_factory == nullptr)
@@ -297,7 +282,7 @@ void SetPackedUpdate(FileSys::VirtualFile update_raw) {
297 romfs_factory->SetPackedUpdate(std::move(update_raw)); 282 romfs_factory->SetPackedUpdate(std::move(update_raw));
298} 283}
299 284
300ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() { 285ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess() const {
301 LOG_TRACE(Service_FS, "Opening RomFS for current process"); 286 LOG_TRACE(Service_FS, "Opening RomFS for current process");
302 287
303 if (romfs_factory == nullptr) { 288 if (romfs_factory == nullptr) {
@@ -308,8 +293,8 @@ ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() {
308 return romfs_factory->OpenCurrentProcess(); 293 return romfs_factory->OpenCurrentProcess();
309} 294}
310 295
311ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id, 296ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS(
312 FileSys::ContentRecordType type) { 297 u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const {
313 LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}", 298 LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}",
314 title_id, static_cast<u8>(storage_id), static_cast<u8>(type)); 299 title_id, static_cast<u8>(storage_id), static_cast<u8>(type));
315 300
@@ -321,8 +306,20 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
321 return romfs_factory->Open(title_id, storage_id, type); 306 return romfs_factory->Open(title_id, storage_id, type);
322} 307}
323 308
324ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, 309ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
325 const FileSys::SaveDataDescriptor& descriptor) { 310 FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const {
311 LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}",
312 static_cast<u8>(space), save_struct.DebugInfo());
313
314 if (save_data_factory == nullptr) {
315 return FileSys::ERROR_ENTITY_NOT_FOUND;
316 }
317
318 return save_data_factory->Create(space, save_struct);
319}
320
321ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData(
322 FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& descriptor) const {
326 LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", 323 LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}",
327 static_cast<u8>(space), descriptor.DebugInfo()); 324 static_cast<u8>(space), descriptor.DebugInfo());
328 325
@@ -333,7 +330,8 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
333 return save_data_factory->Open(space, descriptor); 330 return save_data_factory->Open(space, descriptor);
334} 331}
335 332
336ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) { 333ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace(
334 FileSys::SaveDataSpaceId space) const {
337 LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space)); 335 LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space));
338 336
339 if (save_data_factory == nullptr) { 337 if (save_data_factory == nullptr) {
@@ -343,7 +341,7 @@ ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space)
343 return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space)); 341 return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space));
344} 342}
345 343
346ResultVal<FileSys::VirtualDir> OpenSDMC() { 344ResultVal<FileSys::VirtualDir> FileSystemController::OpenSDMC() const {
347 LOG_TRACE(Service_FS, "Opening SDMC"); 345 LOG_TRACE(Service_FS, "Opening SDMC");
348 346
349 if (sdmc_factory == nullptr) { 347 if (sdmc_factory == nullptr) {
@@ -353,7 +351,92 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
353 return sdmc_factory->Open(); 351 return sdmc_factory->Open();
354} 352}
355 353
356FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id) { 354ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition(
355 FileSys::BisPartitionId id) const {
356 LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", static_cast<u32>(id));
357
358 if (bis_factory == nullptr) {
359 return FileSys::ERROR_ENTITY_NOT_FOUND;
360 }
361
362 auto part = bis_factory->OpenPartition(id);
363 if (part == nullptr) {
364 return FileSys::ERROR_INVALID_ARGUMENT;
365 }
366
367 return MakeResult<FileSys::VirtualDir>(std::move(part));
368}
369
370ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
371 FileSys::BisPartitionId id) const {
372 LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", static_cast<u32>(id));
373
374 if (bis_factory == nullptr) {
375 return FileSys::ERROR_ENTITY_NOT_FOUND;
376 }
377
378 auto part = bis_factory->OpenPartitionStorage(id);
379 if (part == nullptr) {
380 return FileSys::ERROR_INVALID_ARGUMENT;
381 }
382
383 return MakeResult<FileSys::VirtualFile>(std::move(part));
384}
385
386u64 FileSystemController::GetFreeSpaceSize(FileSys::StorageId id) const {
387 switch (id) {
388 case FileSys::StorageId::None:
389 case FileSys::StorageId::GameCard:
390 return 0;
391 case FileSys::StorageId::SdCard:
392 if (sdmc_factory == nullptr)
393 return 0;
394 return sdmc_factory->GetSDMCFreeSpace();
395 case FileSys::StorageId::Host:
396 if (bis_factory == nullptr)
397 return 0;
398 return bis_factory->GetSystemNANDFreeSpace() + bis_factory->GetUserNANDFreeSpace();
399 case FileSys::StorageId::NandSystem:
400 if (bis_factory == nullptr)
401 return 0;
402 return bis_factory->GetSystemNANDFreeSpace();
403 case FileSys::StorageId::NandUser:
404 if (bis_factory == nullptr)
405 return 0;
406 return bis_factory->GetUserNANDFreeSpace();
407 }
408
409 return 0;
410}
411
412u64 FileSystemController::GetTotalSpaceSize(FileSys::StorageId id) const {
413 switch (id) {
414 case FileSys::StorageId::None:
415 case FileSys::StorageId::GameCard:
416 return 0;
417 case FileSys::StorageId::SdCard:
418 if (sdmc_factory == nullptr)
419 return 0;
420 return sdmc_factory->GetSDMCTotalSpace();
421 case FileSys::StorageId::Host:
422 if (bis_factory == nullptr)
423 return 0;
424 return bis_factory->GetFullNANDTotalSpace();
425 case FileSys::StorageId::NandSystem:
426 if (bis_factory == nullptr)
427 return 0;
428 return bis_factory->GetSystemNANDTotalSpace();
429 case FileSys::StorageId::NandUser:
430 if (bis_factory == nullptr)
431 return 0;
432 return bis_factory->GetUserNANDTotalSpace();
433 }
434
435 return 0;
436}
437
438FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataType type,
439 u64 title_id, u128 user_id) const {
357 if (save_data_factory == nullptr) { 440 if (save_data_factory == nullptr) {
358 return {0, 0}; 441 return {0, 0};
359 } 442 }
@@ -385,13 +468,32 @@ FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
385 return value; 468 return value;
386} 469}
387 470
388void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, 471void FileSystemController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
389 FileSys::SaveDataSize new_value) { 472 FileSys::SaveDataSize new_value) const {
390 if (save_data_factory != nullptr) 473 if (save_data_factory != nullptr)
391 save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value); 474 save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value);
392} 475}
393 476
394FileSys::RegisteredCache* GetSystemNANDContents() { 477void FileSystemController::SetGameCard(FileSys::VirtualFile file) {
478 gamecard = std::make_unique<FileSys::XCI>(file);
479 const auto dir = gamecard->ConcatenatedPseudoDirectory();
480 gamecard_registered = std::make_unique<FileSys::RegisteredCache>(dir);
481 gamecard_placeholder = std::make_unique<FileSys::PlaceholderCache>(dir);
482}
483
484FileSys::XCI* FileSystemController::GetGameCard() const {
485 return gamecard.get();
486}
487
488FileSys::RegisteredCache* FileSystemController::GetGameCardContents() const {
489 return gamecard_registered.get();
490}
491
492FileSys::PlaceholderCache* FileSystemController::GetGameCardPlaceholder() const {
493 return gamecard_placeholder.get();
494}
495
496FileSys::RegisteredCache* FileSystemController::GetSystemNANDContents() const {
395 LOG_TRACE(Service_FS, "Opening System NAND Contents"); 497 LOG_TRACE(Service_FS, "Opening System NAND Contents");
396 498
397 if (bis_factory == nullptr) 499 if (bis_factory == nullptr)
@@ -400,7 +502,7 @@ FileSys::RegisteredCache* GetSystemNANDContents() {
400 return bis_factory->GetSystemNANDContents(); 502 return bis_factory->GetSystemNANDContents();
401} 503}
402 504
403FileSys::RegisteredCache* GetUserNANDContents() { 505FileSys::RegisteredCache* FileSystemController::GetUserNANDContents() const {
404 LOG_TRACE(Service_FS, "Opening User NAND Contents"); 506 LOG_TRACE(Service_FS, "Opening User NAND Contents");
405 507
406 if (bis_factory == nullptr) 508 if (bis_factory == nullptr)
@@ -409,7 +511,7 @@ FileSys::RegisteredCache* GetUserNANDContents() {
409 return bis_factory->GetUserNANDContents(); 511 return bis_factory->GetUserNANDContents();
410} 512}
411 513
412FileSys::RegisteredCache* GetSDMCContents() { 514FileSys::RegisteredCache* FileSystemController::GetSDMCContents() const {
413 LOG_TRACE(Service_FS, "Opening SDMC Contents"); 515 LOG_TRACE(Service_FS, "Opening SDMC Contents");
414 516
415 if (sdmc_factory == nullptr) 517 if (sdmc_factory == nullptr)
@@ -418,7 +520,143 @@ FileSys::RegisteredCache* GetSDMCContents() {
418 return sdmc_factory->GetSDMCContents(); 520 return sdmc_factory->GetSDMCContents();
419} 521}
420 522
421FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) { 523FileSys::PlaceholderCache* FileSystemController::GetSystemNANDPlaceholder() const {
524 LOG_TRACE(Service_FS, "Opening System NAND Placeholder");
525
526 if (bis_factory == nullptr)
527 return nullptr;
528
529 return bis_factory->GetSystemNANDPlaceholder();
530}
531
532FileSys::PlaceholderCache* FileSystemController::GetUserNANDPlaceholder() const {
533 LOG_TRACE(Service_FS, "Opening User NAND Placeholder");
534
535 if (bis_factory == nullptr)
536 return nullptr;
537
538 return bis_factory->GetUserNANDPlaceholder();
539}
540
541FileSys::PlaceholderCache* FileSystemController::GetSDMCPlaceholder() const {
542 LOG_TRACE(Service_FS, "Opening SDMC Placeholder");
543
544 if (sdmc_factory == nullptr)
545 return nullptr;
546
547 return sdmc_factory->GetSDMCPlaceholder();
548}
549
550FileSys::RegisteredCache* FileSystemController::GetRegisteredCacheForStorage(
551 FileSys::StorageId id) const {
552 switch (id) {
553 case FileSys::StorageId::None:
554 case FileSys::StorageId::Host:
555 UNIMPLEMENTED();
556 return nullptr;
557 case FileSys::StorageId::GameCard:
558 return GetGameCardContents();
559 case FileSys::StorageId::NandSystem:
560 return GetSystemNANDContents();
561 case FileSys::StorageId::NandUser:
562 return GetUserNANDContents();
563 case FileSys::StorageId::SdCard:
564 return GetSDMCContents();
565 }
566
567 return nullptr;
568}
569
570FileSys::PlaceholderCache* FileSystemController::GetPlaceholderCacheForStorage(
571 FileSys::StorageId id) const {
572 switch (id) {
573 case FileSys::StorageId::None:
574 case FileSys::StorageId::Host:
575 UNIMPLEMENTED();
576 return nullptr;
577 case FileSys::StorageId::GameCard:
578 return GetGameCardPlaceholder();
579 case FileSys::StorageId::NandSystem:
580 return GetSystemNANDPlaceholder();
581 case FileSys::StorageId::NandUser:
582 return GetUserNANDPlaceholder();
583 case FileSys::StorageId::SdCard:
584 return GetSDMCPlaceholder();
585 }
586
587 return nullptr;
588}
589
590FileSys::VirtualDir FileSystemController::GetSystemNANDContentDirectory() const {
591 LOG_TRACE(Service_FS, "Opening system NAND content directory");
592
593 if (bis_factory == nullptr)
594 return nullptr;
595
596 return bis_factory->GetSystemNANDContentDirectory();
597}
598
599FileSys::VirtualDir FileSystemController::GetUserNANDContentDirectory() const {
600 LOG_TRACE(Service_FS, "Opening user NAND content directory");
601
602 if (bis_factory == nullptr)
603 return nullptr;
604
605 return bis_factory->GetUserNANDContentDirectory();
606}
607
608FileSys::VirtualDir FileSystemController::GetSDMCContentDirectory() const {
609 LOG_TRACE(Service_FS, "Opening SDMC content directory");
610
611 if (sdmc_factory == nullptr)
612 return nullptr;
613
614 return sdmc_factory->GetSDMCContentDirectory();
615}
616
617FileSys::VirtualDir FileSystemController::GetNANDImageDirectory() const {
618 LOG_TRACE(Service_FS, "Opening NAND image directory");
619
620 if (bis_factory == nullptr)
621 return nullptr;
622
623 return bis_factory->GetImageDirectory();
624}
625
626FileSys::VirtualDir FileSystemController::GetSDMCImageDirectory() const {
627 LOG_TRACE(Service_FS, "Opening SDMC image directory");
628
629 if (sdmc_factory == nullptr)
630 return nullptr;
631
632 return sdmc_factory->GetImageDirectory();
633}
634
635FileSys::VirtualDir FileSystemController::GetContentDirectory(ContentStorageId id) const {
636 switch (id) {
637 case ContentStorageId::System:
638 return GetSystemNANDContentDirectory();
639 case ContentStorageId::User:
640 return GetUserNANDContentDirectory();
641 case ContentStorageId::SdCard:
642 return GetSDMCContentDirectory();
643 }
644
645 return nullptr;
646}
647
648FileSys::VirtualDir FileSystemController::GetImageDirectory(ImageDirectoryId id) const {
649 switch (id) {
650 case ImageDirectoryId::NAND:
651 return GetNANDImageDirectory();
652 case ImageDirectoryId::SdCard:
653 return GetSDMCImageDirectory();
654 }
655
656 return nullptr;
657}
658
659FileSys::VirtualDir FileSystemController::GetModificationLoadRoot(u64 title_id) const {
422 LOG_TRACE(Service_FS, "Opening mod load root for tid={:016X}", title_id); 660 LOG_TRACE(Service_FS, "Opening mod load root for tid={:016X}", title_id);
423 661
424 if (bis_factory == nullptr) 662 if (bis_factory == nullptr)
@@ -427,7 +665,7 @@ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
427 return bis_factory->GetModificationLoadRoot(title_id); 665 return bis_factory->GetModificationLoadRoot(title_id);
428} 666}
429 667
430FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) { 668FileSys::VirtualDir FileSystemController::GetModificationDumpRoot(u64 title_id) const {
431 LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id); 669 LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id);
432 670
433 if (bis_factory == nullptr) 671 if (bis_factory == nullptr)
@@ -436,7 +674,7 @@ FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) {
436 return bis_factory->GetModificationDumpRoot(title_id); 674 return bis_factory->GetModificationDumpRoot(title_id);
437} 675}
438 676
439void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { 677void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
440 if (overwrite) { 678 if (overwrite) {
441 bis_factory = nullptr; 679 bis_factory = nullptr;
442 save_data_factory = nullptr; 680 save_data_factory = nullptr;
@@ -473,11 +711,10 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
473} 711}
474 712
475void InstallInterfaces(Core::System& system) { 713void InstallInterfaces(Core::System& system) {
476 romfs_factory = nullptr;
477 CreateFactories(*system.GetFilesystem(), false);
478 std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager()); 714 std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager());
479 std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager()); 715 std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager());
480 std::make_shared<FSP_SRV>(system.GetReporter())->InstallAsService(system.ServiceManager()); 716 std::make_shared<FSP_SRV>(system.GetFileSystemController(), system.GetReporter())
717 ->InstallAsService(system.ServiceManager());
481} 718}
482 719
483} // namespace Service::FileSystem 720} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 3849dd89e..3e0c03ec0 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -14,10 +14,13 @@ namespace FileSys {
14class BISFactory; 14class BISFactory;
15class RegisteredCache; 15class RegisteredCache;
16class RegisteredCacheUnion; 16class RegisteredCacheUnion;
17class PlaceholderCache;
17class RomFSFactory; 18class RomFSFactory;
18class SaveDataFactory; 19class SaveDataFactory;
19class SDMCFactory; 20class SDMCFactory;
21class XCI;
20 22
23enum class BisPartitionId : u32;
21enum class ContentRecordType : u8; 24enum class ContentRecordType : u8;
22enum class Mode : u32; 25enum class Mode : u32;
23enum class SaveDataSpaceId : u8; 26enum class SaveDataSpaceId : u8;
@@ -36,34 +39,91 @@ class ServiceManager;
36 39
37namespace FileSystem { 40namespace FileSystem {
38 41
39ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory); 42enum class ContentStorageId : u32 {
40ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory); 43 System,
41ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory); 44 User,
42ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory); 45 SdCard,
43 46};
44void SetPackedUpdate(FileSys::VirtualFile update_raw);
45ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess();
46ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
47 FileSys::ContentRecordType type);
48ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
49 const FileSys::SaveDataDescriptor& descriptor);
50ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
51ResultVal<FileSys::VirtualDir> OpenSDMC();
52
53FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id);
54void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
55 FileSys::SaveDataSize new_value);
56 47
57FileSys::RegisteredCache* GetSystemNANDContents(); 48enum class ImageDirectoryId : u32 {
58FileSys::RegisteredCache* GetUserNANDContents(); 49 NAND,
59FileSys::RegisteredCache* GetSDMCContents(); 50 SdCard,
51};
60 52
61FileSys::VirtualDir GetModificationLoadRoot(u64 title_id); 53class FileSystemController {
62FileSys::VirtualDir GetModificationDumpRoot(u64 title_id); 54public:
55 FileSystemController();
56 ~FileSystemController();
57
58 ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory);
59 ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory);
60 ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
61 ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
62
63 void SetPackedUpdate(FileSys::VirtualFile update_raw);
64 ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() const;
65 ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
66 FileSys::ContentRecordType type) const;
67 ResultVal<FileSys::VirtualDir> CreateSaveData(
68 FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const;
69 ResultVal<FileSys::VirtualDir> OpenSaveData(
70 FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const;
71 ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) const;
72 ResultVal<FileSys::VirtualDir> OpenSDMC() const;
73 ResultVal<FileSys::VirtualDir> OpenBISPartition(FileSys::BisPartitionId id) const;
74 ResultVal<FileSys::VirtualFile> OpenBISPartitionStorage(FileSys::BisPartitionId id) const;
75
76 u64 GetFreeSpaceSize(FileSys::StorageId id) const;
77 u64 GetTotalSpaceSize(FileSys::StorageId id) const;
78
79 FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
80 u128 user_id) const;
81 void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
82 FileSys::SaveDataSize new_value) const;
83
84 void SetGameCard(FileSys::VirtualFile file);
85 FileSys::XCI* GetGameCard() const;
86
87 FileSys::RegisteredCache* GetSystemNANDContents() const;
88 FileSys::RegisteredCache* GetUserNANDContents() const;
89 FileSys::RegisteredCache* GetSDMCContents() const;
90 FileSys::RegisteredCache* GetGameCardContents() const;
91
92 FileSys::PlaceholderCache* GetSystemNANDPlaceholder() const;
93 FileSys::PlaceholderCache* GetUserNANDPlaceholder() const;
94 FileSys::PlaceholderCache* GetSDMCPlaceholder() const;
95 FileSys::PlaceholderCache* GetGameCardPlaceholder() const;
96
97 FileSys::RegisteredCache* GetRegisteredCacheForStorage(FileSys::StorageId id) const;
98 FileSys::PlaceholderCache* GetPlaceholderCacheForStorage(FileSys::StorageId id) const;
99
100 FileSys::VirtualDir GetSystemNANDContentDirectory() const;
101 FileSys::VirtualDir GetUserNANDContentDirectory() const;
102 FileSys::VirtualDir GetSDMCContentDirectory() const;
103
104 FileSys::VirtualDir GetNANDImageDirectory() const;
105 FileSys::VirtualDir GetSDMCImageDirectory() const;
106
107 FileSys::VirtualDir GetContentDirectory(ContentStorageId id) const;
108 FileSys::VirtualDir GetImageDirectory(ImageDirectoryId id) const;
109
110 FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const;
111 FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const;
112
113 // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
114 // above is called.
115 void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
63 116
64// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function 117private:
65// above is called. 118 std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
66void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true); 119 std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
120 std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
121 std::unique_ptr<FileSys::BISFactory> bis_factory;
122
123 std::unique_ptr<FileSys::XCI> gamecard;
124 std::unique_ptr<FileSys::RegisteredCache> gamecard_registered;
125 std::unique_ptr<FileSys::PlaceholderCache> gamecard_placeholder;
126};
67 127
68void InstallInterfaces(Core::System& system); 128void InstallInterfaces(Core::System& system);
69 129
@@ -160,12 +220,6 @@ public:
160 ResultVal<FileSys::VirtualDir> OpenDirectory(const std::string& path); 220 ResultVal<FileSys::VirtualDir> OpenDirectory(const std::string& path);
161 221
162 /** 222 /**
163 * Get the free space
164 * @return The number of free bytes in the archive
165 */
166 u64 GetFreeSpaceSize() const;
167
168 /**
169 * Get the type of the specified path 223 * Get the type of the specified path
170 * @return The type of the specified path or error code 224 * @return The type of the specified path or error code
171 */ 225 */
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index d3cd46a9b..eb982ad49 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -19,6 +19,7 @@
19#include "core/file_sys/mode.h" 19#include "core/file_sys/mode.h"
20#include "core/file_sys/nca_metadata.h" 20#include "core/file_sys/nca_metadata.h"
21#include "core/file_sys/patch_manager.h" 21#include "core/file_sys/patch_manager.h"
22#include "core/file_sys/romfs_factory.h"
22#include "core/file_sys/savedata_factory.h" 23#include "core/file_sys/savedata_factory.h"
23#include "core/file_sys/system_archive/system_archive.h" 24#include "core/file_sys/system_archive/system_archive.h"
24#include "core/file_sys/vfs.h" 25#include "core/file_sys/vfs.h"
@@ -30,6 +31,18 @@
30 31
31namespace Service::FileSystem { 32namespace Service::FileSystem {
32 33
34struct SizeGetter {
35 std::function<u64()> get_free_size;
36 std::function<u64()> get_total_size;
37
38 static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) {
39 return {
40 [&fsc, id] { return fsc.GetFreeSpaceSize(id); },
41 [&fsc, id] { return fsc.GetTotalSpaceSize(id); },
42 };
43 }
44};
45
33enum class FileSystemType : u8 { 46enum class FileSystemType : u8 {
34 Invalid0 = 0, 47 Invalid0 = 0,
35 Invalid1 = 1, 48 Invalid1 = 1,
@@ -289,8 +302,8 @@ private:
289 302
290class IFileSystem final : public ServiceFramework<IFileSystem> { 303class IFileSystem final : public ServiceFramework<IFileSystem> {
291public: 304public:
292 explicit IFileSystem(FileSys::VirtualDir backend) 305 explicit IFileSystem(FileSys::VirtualDir backend, SizeGetter size)
293 : ServiceFramework("IFileSystem"), backend(std::move(backend)) { 306 : ServiceFramework("IFileSystem"), backend(std::move(backend)), size(std::move(size)) {
294 static const FunctionInfo functions[] = { 307 static const FunctionInfo functions[] = {
295 {0, &IFileSystem::CreateFile, "CreateFile"}, 308 {0, &IFileSystem::CreateFile, "CreateFile"},
296 {1, &IFileSystem::DeleteFile, "DeleteFile"}, 309 {1, &IFileSystem::DeleteFile, "DeleteFile"},
@@ -467,14 +480,31 @@ public:
467 rb.Push(RESULT_SUCCESS); 480 rb.Push(RESULT_SUCCESS);
468 } 481 }
469 482
483 void GetFreeSpaceSize(Kernel::HLERequestContext& ctx) {
484 LOG_DEBUG(Service_FS, "called");
485
486 IPC::ResponseBuilder rb{ctx, 4};
487 rb.Push(RESULT_SUCCESS);
488 rb.Push(size.get_free_size());
489 }
490
491 void GetTotalSpaceSize(Kernel::HLERequestContext& ctx) {
492 LOG_DEBUG(Service_FS, "called");
493
494 IPC::ResponseBuilder rb{ctx, 4};
495 rb.Push(RESULT_SUCCESS);
496 rb.Push(size.get_total_size());
497 }
498
470private: 499private:
471 VfsDirectoryServiceWrapper backend; 500 VfsDirectoryServiceWrapper backend;
501 SizeGetter size;
472}; 502};
473 503
474class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { 504class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
475public: 505public:
476 explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space) 506 explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space, FileSystemController& fsc)
477 : ServiceFramework("ISaveDataInfoReader") { 507 : ServiceFramework("ISaveDataInfoReader"), fsc(fsc) {
478 static const FunctionInfo functions[] = { 508 static const FunctionInfo functions[] = {
479 {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, 509 {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
480 }; 510 };
@@ -520,8 +550,13 @@ private:
520 } 550 }
521 551
522 void FindAllSaves(FileSys::SaveDataSpaceId space) { 552 void FindAllSaves(FileSys::SaveDataSpaceId space) {
523 const auto save_root = OpenSaveDataSpace(space); 553 const auto save_root = fsc.OpenSaveDataSpace(space);
524 ASSERT(save_root.Succeeded()); 554
555 if (save_root.Failed() || *save_root == nullptr) {
556 LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!",
557 static_cast<u8>(space));
558 return;
559 }
525 560
526 for (const auto& type : (*save_root)->GetSubdirectories()) { 561 for (const auto& type : (*save_root)->GetSubdirectories()) {
527 if (type->GetName() == "save") { 562 if (type->GetName() == "save") {
@@ -610,11 +645,13 @@ private:
610 }; 645 };
611 static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size."); 646 static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
612 647
648 FileSystemController& fsc;
613 std::vector<SaveDataInfo> info; 649 std::vector<SaveDataInfo> info;
614 u64 next_entry_index = 0; 650 u64 next_entry_index = 0;
615}; 651};
616 652
617FSP_SRV::FSP_SRV(const Core::Reporter& reporter) : ServiceFramework("fsp-srv"), reporter(reporter) { 653FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter)
654 : ServiceFramework("fsp-srv"), fsc(fsc), reporter(reporter) {
618 // clang-format off 655 // clang-format off
619 static const FunctionInfo functions[] = { 656 static const FunctionInfo functions[] = {
620 {0, nullptr, "OpenFileSystem"}, 657 {0, nullptr, "OpenFileSystem"},
@@ -754,7 +791,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
754void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) { 791void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
755 LOG_DEBUG(Service_FS, "called"); 792 LOG_DEBUG(Service_FS, "called");
756 793
757 IFileSystem filesystem(OpenSDMC().Unwrap()); 794 IFileSystem filesystem(fsc.OpenSDMC().Unwrap(),
795 SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
758 796
759 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 797 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
760 rb.Push(RESULT_SUCCESS); 798 rb.Push(RESULT_SUCCESS);
@@ -768,8 +806,10 @@ void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
768 auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>(); 806 auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
769 u128 uid = rp.PopRaw<u128>(); 807 u128 uid = rp.PopRaw<u128>();
770 808
771 LOG_WARNING(Service_FS, "(STUBBED) called save_struct = {}, uid = {:016X}{:016X}", 809 LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
772 save_struct.DebugInfo(), uid[1], uid[0]); 810 uid[1], uid[0]);
811
812 fsc.CreateSaveData(FileSys::SaveDataSpaceId::NandUser, save_struct);
773 813
774 IPC::ResponseBuilder rb{ctx, 2}; 814 IPC::ResponseBuilder rb{ctx, 2};
775 rb.Push(RESULT_SUCCESS); 815 rb.Push(RESULT_SUCCESS);
@@ -786,14 +826,24 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
786 IPC::RequestParser rp{ctx}; 826 IPC::RequestParser rp{ctx};
787 const auto parameters = rp.PopRaw<Parameters>(); 827 const auto parameters = rp.PopRaw<Parameters>();
788 828
789 auto dir = OpenSaveData(parameters.save_data_space_id, parameters.descriptor); 829 auto dir = fsc.OpenSaveData(parameters.save_data_space_id, parameters.descriptor);
790 if (dir.Failed()) { 830 if (dir.Failed()) {
791 IPC::ResponseBuilder rb{ctx, 2, 0, 0}; 831 IPC::ResponseBuilder rb{ctx, 2, 0, 0};
792 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); 832 rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
793 return; 833 return;
794 } 834 }
795 835
796 IFileSystem filesystem(std::move(dir.Unwrap())); 836 FileSys::StorageId id;
837 if (parameters.save_data_space_id == FileSys::SaveDataSpaceId::NandUser) {
838 id = FileSys::StorageId::NandUser;
839 } else if (parameters.save_data_space_id == FileSys::SaveDataSpaceId::SdCardSystem ||
840 parameters.save_data_space_id == FileSys::SaveDataSpaceId::SdCardUser) {
841 id = FileSys::StorageId::SdCard;
842 } else {
843 id = FileSys::StorageId::NandSystem;
844 }
845
846 IFileSystem filesystem(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id));
797 847
798 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 848 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
799 rb.Push(RESULT_SUCCESS); 849 rb.Push(RESULT_SUCCESS);
@@ -812,7 +862,7 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext&
812 862
813 IPC::ResponseBuilder rb{ctx, 2, 0, 1}; 863 IPC::ResponseBuilder rb{ctx, 2, 0, 1};
814 rb.Push(RESULT_SUCCESS); 864 rb.Push(RESULT_SUCCESS);
815 rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space)); 865 rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space, fsc));
816} 866}
817 867
818void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { 868void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
@@ -836,7 +886,7 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
836void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { 886void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
837 LOG_DEBUG(Service_FS, "called"); 887 LOG_DEBUG(Service_FS, "called");
838 888
839 auto romfs = OpenRomFSCurrentProcess(); 889 auto romfs = fsc.OpenRomFSCurrentProcess();
840 if (romfs.Failed()) { 890 if (romfs.Failed()) {
841 // TODO (bunnei): Find the right error code to use here 891 // TODO (bunnei): Find the right error code to use here
842 LOG_CRITICAL(Service_FS, "no file system interface available!"); 892 LOG_CRITICAL(Service_FS, "no file system interface available!");
@@ -861,7 +911,7 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
861 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}", 911 LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
862 static_cast<u8>(storage_id), unknown, title_id); 912 static_cast<u8>(storage_id), unknown, title_id);
863 913
864 auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data); 914 auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
865 915
866 if (data.Failed()) { 916 if (data.Failed()) {
867 const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id); 917 const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
index b5486a193..d52b55999 100644
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ b/src/core/hle/service/filesystem/fsp_srv.h
@@ -32,7 +32,7 @@ enum class LogMode : u32 {
32 32
33class FSP_SRV final : public ServiceFramework<FSP_SRV> { 33class FSP_SRV final : public ServiceFramework<FSP_SRV> {
34public: 34public:
35 explicit FSP_SRV(const Core::Reporter& reporter); 35 explicit FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter);
36 ~FSP_SRV() override; 36 ~FSP_SRV() override;
37 37
38private: 38private:
@@ -51,6 +51,8 @@ private:
51 void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx); 51 void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
52 void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx); 52 void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx);
53 53
54 FileSystemController& fsc;
55
54 FileSys::VirtualFile romfs; 56 FileSys::VirtualFile romfs;
55 u64 current_process_id = 0; 57 u64 current_process_id = 0;
56 u32 access_log_program_index = 0; 58 u32 access_log_program_index = 0;
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp
index ce88a2941..13121c4f1 100644
--- a/src/core/hle/service/ns/ns.cpp
+++ b/src/core/hle/service/ns/ns.cpp
@@ -617,7 +617,7 @@ public:
617 } 617 }
618}; 618};
619 619
620void InstallInterfaces(SM::ServiceManager& service_manager) { 620void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSystemController& fsc) {
621 std::make_shared<NS>("ns:am2")->InstallAsService(service_manager); 621 std::make_shared<NS>("ns:am2")->InstallAsService(service_manager);
622 std::make_shared<NS>("ns:ec")->InstallAsService(service_manager); 622 std::make_shared<NS>("ns:ec")->InstallAsService(service_manager);
623 std::make_shared<NS>("ns:rid")->InstallAsService(service_manager); 623 std::make_shared<NS>("ns:rid")->InstallAsService(service_manager);
@@ -628,7 +628,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
628 std::make_shared<NS_SU>()->InstallAsService(service_manager); 628 std::make_shared<NS_SU>()->InstallAsService(service_manager);
629 std::make_shared<NS_VM>()->InstallAsService(service_manager); 629 std::make_shared<NS_VM>()->InstallAsService(service_manager);
630 630
631 std::make_shared<PL_U>()->InstallAsService(service_manager); 631 std::make_shared<PL_U>(fsc)->InstallAsService(service_manager);
632} 632}
633 633
634} // namespace Service::NS 634} // namespace Service::NS
diff --git a/src/core/hle/service/ns/ns.h b/src/core/hle/service/ns/ns.h
index 0e8256cb4..d067e7a9a 100644
--- a/src/core/hle/service/ns/ns.h
+++ b/src/core/hle/service/ns/ns.h
@@ -6,7 +6,13 @@
6 6
7#include "core/hle/service/service.h" 7#include "core/hle/service/service.h"
8 8
9namespace Service::NS { 9namespace Service {
10
11namespace FileSystem {
12class FileSystemController;
13} // namespace FileSystem
14
15namespace NS {
10 16
11class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> { 17class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> {
12public: 18public:
@@ -91,6 +97,8 @@ private:
91}; 97};
92 98
93/// Registers all NS services with the specified service manager. 99/// Registers all NS services with the specified service manager.
94void InstallInterfaces(SM::ServiceManager& service_manager); 100void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSystemController& fsc);
101
102} // namespace NS
95 103
96} // namespace Service::NS 104} // namespace Service
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp
index 2a522136d..9d49f36e8 100644
--- a/src/core/hle/service/ns/pl_u.cpp
+++ b/src/core/hle/service/ns/pl_u.cpp
@@ -150,7 +150,8 @@ struct PL_U::Impl {
150 std::vector<FontRegion> shared_font_regions; 150 std::vector<FontRegion> shared_font_regions;
151}; 151};
152 152
153PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} { 153PL_U::PL_U(FileSystem::FileSystemController& fsc)
154 : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
154 static const FunctionInfo functions[] = { 155 static const FunctionInfo functions[] = {
155 {0, &PL_U::RequestLoad, "RequestLoad"}, 156 {0, &PL_U::RequestLoad, "RequestLoad"},
156 {1, &PL_U::GetLoadState, "GetLoadState"}, 157 {1, &PL_U::GetLoadState, "GetLoadState"},
@@ -161,7 +162,7 @@ PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
161 }; 162 };
162 RegisterHandlers(functions); 163 RegisterHandlers(functions);
163 // Attempt to load shared font data from disk 164 // Attempt to load shared font data from disk
164 const auto* nand = FileSystem::GetSystemNANDContents(); 165 const auto* nand = fsc.GetSystemNANDContents();
165 std::size_t offset = 0; 166 std::size_t offset = 0;
166 // Rebuild shared fonts from data ncas 167 // Rebuild shared fonts from data ncas
167 if (nand->HasEntry(static_cast<u64>(FontArchives::Standard), 168 if (nand->HasEntry(static_cast<u64>(FontArchives::Standard),
diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/pl_u.h
index 253f26a2a..35ca424d2 100644
--- a/src/core/hle/service/ns/pl_u.h
+++ b/src/core/hle/service/ns/pl_u.h
@@ -7,11 +7,17 @@
7#include <memory> 7#include <memory>
8#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
9 9
10namespace Service::NS { 10namespace Service {
11
12namespace FileSystem {
13class FileSystemController;
14} // namespace FileSystem
15
16namespace NS {
11 17
12class PL_U final : public ServiceFramework<PL_U> { 18class PL_U final : public ServiceFramework<PL_U> {
13public: 19public:
14 PL_U(); 20 PL_U(FileSystem::FileSystemController& fsc);
15 ~PL_U() override; 21 ~PL_U() override;
16 22
17private: 23private:
@@ -26,4 +32,6 @@ private:
26 std::unique_ptr<Impl> impl; 32 std::unique_ptr<Impl> impl;
27}; 33};
28 34
29} // namespace Service::NS 35} // namespace NS
36
37} // namespace Service
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 3a0f8c3f6..454387467 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -199,6 +199,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
199 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it 199 // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
200 // here and pass it into the respective InstallInterfaces functions. 200 // here and pass it into the respective InstallInterfaces functions.
201 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming()); 201 auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming());
202 system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
202 203
203 SM::ServiceManager::InstallInterfaces(sm); 204 SM::ServiceManager::InstallInterfaces(sm);
204 205
@@ -235,7 +236,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
235 NIFM::InstallInterfaces(*sm); 236 NIFM::InstallInterfaces(*sm);
236 NIM::InstallInterfaces(*sm); 237 NIM::InstallInterfaces(*sm);
237 NPNS::InstallInterfaces(*sm); 238 NPNS::InstallInterfaces(*sm);
238 NS::InstallInterfaces(*sm); 239 NS::InstallInterfaces(*sm, system.GetFileSystemController());
239 Nvidia::InstallInterfaces(*sm, *nv_flinger, system); 240 Nvidia::InstallInterfaces(*sm, *nv_flinger, system);
240 PCIe::InstallInterfaces(*sm); 241 PCIe::InstallInterfaces(*sm);
241 PCTL::InstallInterfaces(*sm); 242 PCTL::InstallInterfaces(*sm);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index c6c4bdae5..aef964861 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -18,10 +18,6 @@ namespace Core {
18class System; 18class System;
19} 19}
20 20
21namespace FileSys {
22class VfsFilesystem;
23}
24
25namespace Kernel { 21namespace Kernel {
26class ClientPort; 22class ClientPort;
27class ServerPort; 23class ServerPort;
@@ -31,6 +27,10 @@ class HLERequestContext;
31 27
32namespace Service { 28namespace Service {
33 29
30namespace FileSystem {
31class FileSystemController;
32} // namespace FileSystem
33
34namespace SM { 34namespace SM {
35class ServiceManager; 35class ServiceManager;
36} 36}
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index f9e88be2b..d19c3623c 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -7,6 +7,7 @@
7#include "common/common_funcs.h" 7#include "common/common_funcs.h"
8#include "common/file_util.h" 8#include "common/file_util.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "core/core.h"
10#include "core/file_sys/content_archive.h" 11#include "core/file_sys/content_archive.h"
11#include "core/file_sys/control_metadata.h" 12#include "core/file_sys/control_metadata.h"
12#include "core/file_sys/patch_manager.h" 13#include "core/file_sys/patch_manager.h"
@@ -176,7 +177,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
176 // Register the RomFS if a ".romfs" file was found 177 // Register the RomFS if a ".romfs" file was found
177 if (romfs_iter != files.end() && *romfs_iter != nullptr) { 178 if (romfs_iter != files.end() && *romfs_iter != nullptr) {
178 romfs = *romfs_iter; 179 romfs = *romfs_iter;
179 Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this)); 180 Core::System::GetInstance().GetFileSystemController().RegisterRomFS(
181 std::make_unique<FileSys::RomFSFactory>(*this));
180 } 182 }
181 183
182 is_loaded = true; 184 is_loaded = true;
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp
index 0f65fb637..5a0469978 100644
--- a/src/core/loader/nca.cpp
+++ b/src/core/loader/nca.cpp
@@ -6,6 +6,7 @@
6 6
7#include "common/file_util.h" 7#include "common/file_util.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9#include "core/core.h"
9#include "core/file_sys/content_archive.h" 10#include "core/file_sys/content_archive.h"
10#include "core/file_sys/romfs_factory.h" 11#include "core/file_sys/romfs_factory.h"
11#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/process.h"
@@ -57,7 +58,8 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process) {
57 } 58 }
58 59
59 if (nca->GetRomFS() != nullptr && nca->GetRomFS()->GetSize() > 0) { 60 if (nca->GetRomFS() != nullptr && nca->GetRomFS()->GetSize() > 0) {
60 Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this)); 61 Core::System::GetInstance().GetFileSystemController().RegisterRomFS(
62 std::make_unique<FileSys::RomFSFactory>(*this));
61 } 63 }
62 64
63 is_loaded = true; 65 is_loaded = true;
diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp
index 3a5361fdd..175898b91 100644
--- a/src/core/loader/nro.cpp
+++ b/src/core/loader/nro.cpp
@@ -10,6 +10,7 @@
10#include "common/file_util.h" 10#include "common/file_util.h"
11#include "common/logging/log.h" 11#include "common/logging/log.h"
12#include "common/swap.h" 12#include "common/swap.h"
13#include "core/core.h"
13#include "core/file_sys/control_metadata.h" 14#include "core/file_sys/control_metadata.h"
14#include "core/file_sys/romfs_factory.h" 15#include "core/file_sys/romfs_factory.h"
15#include "core/file_sys/vfs_offset.h" 16#include "core/file_sys/vfs_offset.h"
@@ -214,7 +215,8 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process) {
214 } 215 }
215 216
216 if (romfs != nullptr) { 217 if (romfs != nullptr) {
217 Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this)); 218 Core::System::GetInstance().GetFileSystemController().RegisterRomFS(
219 std::make_unique<FileSys::RomFSFactory>(*this));
218 } 220 }
219 221
220 is_loaded = true; 222 is_loaded = true;
diff --git a/src/core/loader/nsp.cpp b/src/core/loader/nsp.cpp
index 35c82c99d..13950fc08 100644
--- a/src/core/loader/nsp.cpp
+++ b/src/core/loader/nsp.cpp
@@ -5,6 +5,7 @@
5#include <vector> 5#include <vector>
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/core.h"
8#include "core/file_sys/card_image.h" 9#include "core/file_sys/card_image.h"
9#include "core/file_sys/content_archive.h" 10#include "core/file_sys/content_archive.h"
10#include "core/file_sys/control_metadata.h" 11#include "core/file_sys/control_metadata.h"
@@ -105,7 +106,8 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process) {
105 106
106 FileSys::VirtualFile update_raw; 107 FileSys::VirtualFile update_raw;
107 if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { 108 if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
108 Service::FileSystem::SetPackedUpdate(std::move(update_raw)); 109 Core::System::GetInstance().GetFileSystemController().SetPackedUpdate(
110 std::move(update_raw));
109 } 111 }
110 112
111 is_loaded = true; 113 is_loaded = true;
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp
index 5e8553db9..7186ad1ff 100644
--- a/src/core/loader/xci.cpp
+++ b/src/core/loader/xci.cpp
@@ -5,6 +5,7 @@
5#include <vector> 5#include <vector>
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "core/core.h"
8#include "core/file_sys/card_image.h" 9#include "core/file_sys/card_image.h"
9#include "core/file_sys/content_archive.h" 10#include "core/file_sys/content_archive.h"
10#include "core/file_sys/control_metadata.h" 11#include "core/file_sys/control_metadata.h"
@@ -72,7 +73,8 @@ AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process) {
72 73
73 FileSys::VirtualFile update_raw; 74 FileSys::VirtualFile update_raw;
74 if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) { 75 if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
75 Service::FileSystem::SetPackedUpdate(std::move(update_raw)); 76 Core::System::GetInstance().GetFileSystemController().SetPackedUpdate(
77 std::move(update_raw));
76 } 78 }
77 79
78 is_loaded = true; 80 is_loaded = true;
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 0dd1632ac..7de3fd1e5 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/file_util.h"
5#include "core/core.h" 6#include "core/core.h"
6#include "core/gdbstub/gdbstub.h" 7#include "core/gdbstub/gdbstub.h"
7#include "core/hle/service/hid/hid.h" 8#include "core/hle/service/hid/hid.h"
@@ -97,8 +98,8 @@ void LogSettings() {
97 LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching); 98 LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching);
98 LogSetting("Audio_OutputDevice", Settings::values.audio_device_id); 99 LogSetting("Audio_OutputDevice", Settings::values.audio_device_id);
99 LogSetting("DataStorage_UseVirtualSd", Settings::values.use_virtual_sd); 100 LogSetting("DataStorage_UseVirtualSd", Settings::values.use_virtual_sd);
100 LogSetting("DataStorage_NandDir", Settings::values.nand_dir); 101 LogSetting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
101 LogSetting("DataStorage_SdmcDir", Settings::values.sdmc_dir); 102 LogSetting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
102 LogSetting("Debugging_UseGdbstub", Settings::values.use_gdbstub); 103 LogSetting("Debugging_UseGdbstub", Settings::values.use_gdbstub);
103 LogSetting("Debugging_GdbstubPort", Settings::values.gdbstub_port); 104 LogSetting("Debugging_GdbstubPort", Settings::values.gdbstub_port);
104 LogSetting("Debugging_ProgramArgs", Settings::values.program_args); 105 LogSetting("Debugging_ProgramArgs", Settings::values.program_args);
diff --git a/src/core/settings.h b/src/core/settings.h
index d4b70ec4c..47bddfb30 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -346,6 +346,31 @@ struct TouchscreenInput {
346 u32 rotation_angle; 346 u32 rotation_angle;
347}; 347};
348 348
349enum class NANDTotalSize : u64 {
350 S29_1GB = 0x747C00000ULL,
351};
352
353enum class NANDUserSize : u64 {
354 S26GB = 0x680000000ULL,
355};
356
357enum class NANDSystemSize : u64 {
358 S2_5GB = 0xA0000000,
359};
360
361enum class SDMCSize : u64 {
362 S1GB = 0x40000000,
363 S2GB = 0x80000000,
364 S4GB = 0x100000000ULL,
365 S8GB = 0x200000000ULL,
366 S16GB = 0x400000000ULL,
367 S32GB = 0x800000000ULL,
368 S64GB = 0x1000000000ULL,
369 S128GB = 0x2000000000ULL,
370 S256GB = 0x4000000000ULL,
371 S1TB = 0x10000000000ULL,
372};
373
349struct Values { 374struct Values {
350 // System 375 // System
351 bool use_docked_mode; 376 bool use_docked_mode;
@@ -382,8 +407,13 @@ struct Values {
382 407
383 // Data Storage 408 // Data Storage
384 bool use_virtual_sd; 409 bool use_virtual_sd;
385 std::string nand_dir; 410 bool gamecard_inserted;
386 std::string sdmc_dir; 411 bool gamecard_current_game;
412 std::string gamecard_path;
413 NANDTotalSize nand_total_size;
414 NANDSystemSize nand_system_size;
415 NANDUserSize nand_user_size;
416 SDMCSize sdmc_size;
387 417
388 // Renderer 418 // Renderer
389 float resolution_factor; 419 float resolution_factor;