summaryrefslogtreecommitdiffstats
path: root/src/core
diff options
context:
space:
mode:
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 @@
#include "core/core_cpu.h"
#include "core/core_timing.h"
#include "core/cpu_core_manager.h"
+#include "core/file_sys/bis_factory.h"
+#include "core/file_sys/card_image.h"
#include "core/file_sys/mode.h"
#include "core/file_sys/registered_cache.h"
+#include "core/file_sys/romfs_factory.h"
+#include "core/file_sys/savedata_factory.h"
+#include "core/file_sys/sdmc_factory.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h"
#include "core/gdbstub/gdbstub.h"
@@ -27,6 +32,7 @@
#include "core/hle/kernel/thread.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/apm/controller.h"
+#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
@@ -202,6 +208,15 @@ struct System::Impl {
main_process->Run(load_parameters->main_thread_priority,
load_parameters->main_thread_stack_size);
+ if (Settings::values.gamecard_inserted) {
+ if (Settings::values.gamecard_current_game) {
+ fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, filepath));
+ } else if (!Settings::values.gamecard_path.empty()) {
+ fs_controller.SetGameCard(
+ GetGameFileFromPath(virtual_filesystem, Settings::values.gamecard_path));
+ }
+ }
+
u64 title_id{0};
if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})",
@@ -304,6 +319,7 @@ struct System::Impl {
FileSys::VirtualFilesystem virtual_filesystem;
/// ContentProviderUnion instance
std::unique_ptr<FileSys::ContentProviderUnion> content_provider;
+ Service::FileSystem::FileSystemController fs_controller;
/// AppLoader used to load the current executing application
std::unique_ptr<Loader::AppLoader> app_loader;
std::unique_ptr<VideoCore::RendererBase> renderer;
@@ -571,6 +587,14 @@ const FileSys::ContentProvider& System::GetContentProvider() const {
return *impl->content_provider;
}
+Service::FileSystem::FileSystemController& System::GetFileSystemController() {
+ return impl->fs_controller;
+}
+
+const Service::FileSystem::FileSystemController& System::GetFileSystemController() const {
+ return impl->fs_controller;
+}
+
void System::RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
FileSys::ContentProvider* provider) {
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 {
class Controller;
}
+namespace FileSystem {
+class FileSystemController;
+} // namespace FileSystem
+
namespace Glue {
class ARPManager;
}
@@ -299,6 +303,10 @@ public:
const FileSys::ContentProvider& GetContentProvider() const;
+ Service::FileSystem::FileSystemController& GetFileSystemController();
+
+ const Service::FileSystem::FileSystemController& GetFileSystemController() const;
+
void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
FileSys::ContentProvider* provider);
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) {
prodinfo_decrypted = std::make_shared<XTSEncryptionLayer>(prodinfo, bis_key);
}
+FileSys::VirtualFile PartitionDataManager::GetDecryptedProdInfo() const {
+ return prodinfo_decrypted;
+}
+
std::array<u8, 576> PartitionDataManager::GetETicketExtendedKek() const {
std::array<u8, 0x240> out{};
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:
bool HasProdInfo() const;
FileSys::VirtualFile GetProdInfoRaw() const;
void DecryptProdInfo(std::array<u8, 0x20> bis_key);
+ FileSys::VirtualFile GetDecryptedProdInfo() const;
std::array<u8, 0x240> GetETicketExtendedKek() const;
private:
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 @@
// Refer to the license.txt file included.
#include <fmt/format.h>
+#include "common/file_util.h"
+#include "core/core.h"
#include "core/file_sys/bis_factory.h"
+#include "core/file_sys/mode.h"
#include "core/file_sys/registered_cache.h"
+#include "core/settings.h"
namespace FileSys {
@@ -14,10 +18,22 @@ BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir
sysnand_cache(std::make_unique<RegisteredCache>(
GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))),
usrnand_cache(std::make_unique<RegisteredCache>(
- GetOrCreateDirectoryRelative(nand_root, "/user/Contents/registered"))) {}
+ GetOrCreateDirectoryRelative(nand_root, "/user/Contents/registered"))),
+ sysnand_placeholder(std::make_unique<PlaceholderCache>(
+ GetOrCreateDirectoryRelative(nand_root, "/system/Contents/placehld"))),
+ usrnand_placeholder(std::make_unique<PlaceholderCache>(
+ GetOrCreateDirectoryRelative(nand_root, "/user/Contents/placehld"))) {}
BISFactory::~BISFactory() = default;
+VirtualDir BISFactory::GetSystemNANDContentDirectory() const {
+ return GetOrCreateDirectoryRelative(nand_root, "/system/Contents");
+}
+
+VirtualDir BISFactory::GetUserNANDContentDirectory() const {
+ return GetOrCreateDirectoryRelative(nand_root, "/user/Contents");
+}
+
RegisteredCache* BISFactory::GetSystemNANDContents() const {
return sysnand_cache.get();
}
@@ -26,9 +42,17 @@ RegisteredCache* BISFactory::GetUserNANDContents() const {
return usrnand_cache.get();
}
+PlaceholderCache* BISFactory::GetSystemNANDPlaceholder() const {
+ return sysnand_placeholder.get();
+}
+
+PlaceholderCache* BISFactory::GetUserNANDPlaceholder() const {
+ return usrnand_placeholder.get();
+}
+
VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const {
// LayeredFS doesn't work on updates and title id-less homebrew
- if (title_id == 0 || (title_id & 0x800) > 0)
+ if (title_id == 0 || (title_id & 0xFFF) == 0x800)
return nullptr;
return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id));
}
@@ -39,4 +63,77 @@ VirtualDir BISFactory::GetModificationDumpRoot(u64 title_id) const {
return GetOrCreateDirectoryRelative(dump_root, fmt::format("/{:016X}", title_id));
}
+VirtualDir BISFactory::OpenPartition(BisPartitionId id) const {
+ switch (id) {
+ case BisPartitionId::CalibrationFile:
+ return GetOrCreateDirectoryRelative(nand_root, "/prodinfof");
+ case BisPartitionId::SafeMode:
+ return GetOrCreateDirectoryRelative(nand_root, "/safe");
+ case BisPartitionId::System:
+ return GetOrCreateDirectoryRelative(nand_root, "/system");
+ case BisPartitionId::User:
+ return GetOrCreateDirectoryRelative(nand_root, "/user");
+ default:
+ return nullptr;
+ }
+}
+
+VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id) const {
+ Core::Crypto::KeyManager keys;
+ Core::Crypto::PartitionDataManager pdm{
+ Core::System::GetInstance().GetFilesystem()->OpenDirectory(
+ FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), Mode::Read)};
+ keys.PopulateFromPartitionData(pdm);
+
+ switch (id) {
+ case BisPartitionId::CalibrationBinary:
+ return pdm.GetDecryptedProdInfo();
+ case BisPartitionId::BootConfigAndPackage2Part1:
+ case BisPartitionId::BootConfigAndPackage2Part2:
+ case BisPartitionId::BootConfigAndPackage2Part3:
+ case BisPartitionId::BootConfigAndPackage2Part4:
+ case BisPartitionId::BootConfigAndPackage2Part5:
+ case BisPartitionId::BootConfigAndPackage2Part6: {
+ const auto new_id = static_cast<u8>(id) -
+ static_cast<u8>(BisPartitionId::BootConfigAndPackage2Part1) +
+ static_cast<u8>(Core::Crypto::Package2Type::NormalMain);
+ return pdm.GetPackage2Raw(static_cast<Core::Crypto::Package2Type>(new_id));
+ }
+ default:
+ return nullptr;
+ }
+}
+
+VirtualDir BISFactory::GetImageDirectory() const {
+ return GetOrCreateDirectoryRelative(nand_root, "/user/Album");
+}
+
+u64 BISFactory::GetSystemNANDFreeSpace() const {
+ const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system");
+ if (sys_dir == nullptr)
+ return 0;
+
+ return GetSystemNANDTotalSpace() - sys_dir->GetSize();
+}
+
+u64 BISFactory::GetSystemNANDTotalSpace() const {
+ return static_cast<u64>(Settings::values.nand_system_size);
+}
+
+u64 BISFactory::GetUserNANDFreeSpace() const {
+ const auto usr_dir = GetOrCreateDirectoryRelative(nand_root, "/user");
+ if (usr_dir == nullptr)
+ return 0;
+
+ return GetUserNANDTotalSpace() - usr_dir->GetSize();
+}
+
+u64 BISFactory::GetUserNANDTotalSpace() const {
+ return static_cast<u64>(Settings::values.nand_user_size);
+}
+
+u64 BISFactory::GetFullNANDTotalSpace() const {
+ return static_cast<u64>(Settings::values.nand_total_size);
+}
+
} // 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 @@
namespace FileSys {
+enum class BisPartitionId : u32 {
+ UserDataRoot = 20,
+ CalibrationBinary = 27,
+ CalibrationFile = 28,
+ BootConfigAndPackage2Part1 = 21,
+ BootConfigAndPackage2Part2 = 22,
+ BootConfigAndPackage2Part3 = 23,
+ BootConfigAndPackage2Part4 = 24,
+ BootConfigAndPackage2Part5 = 25,
+ BootConfigAndPackage2Part6 = 26,
+ SafeMode = 29,
+ System = 31,
+ SystemProperEncryption = 32,
+ SystemProperPartition = 33,
+ User = 30,
+};
+
class RegisteredCache;
+class PlaceholderCache;
/// File system interface to the Built-In Storage
/// This is currently missing accessors to BIS partitions, but seemed like a good place for the NAND
@@ -20,12 +38,29 @@ public:
explicit BISFactory(VirtualDir nand_root, VirtualDir load_root, VirtualDir dump_root);
~BISFactory();
+ VirtualDir GetSystemNANDContentDirectory() const;
+ VirtualDir GetUserNANDContentDirectory() const;
+
RegisteredCache* GetSystemNANDContents() const;
RegisteredCache* GetUserNANDContents() const;
+ PlaceholderCache* GetSystemNANDPlaceholder() const;
+ PlaceholderCache* GetUserNANDPlaceholder() const;
+
VirtualDir GetModificationLoadRoot(u64 title_id) const;
VirtualDir GetModificationDumpRoot(u64 title_id) const;
+ VirtualDir OpenPartition(BisPartitionId id) const;
+ VirtualFile OpenPartitionStorage(BisPartitionId id) const;
+
+ VirtualDir GetImageDirectory() const;
+
+ u64 GetSystemNANDFreeSpace() const;
+ u64 GetSystemNANDTotalSpace() const;
+ u64 GetUserNANDFreeSpace() const;
+ u64 GetUserNANDTotalSpace() const;
+ u64 GetFullNANDTotalSpace() const;
+
private:
VirtualDir nand_root;
VirtualDir load_root;
@@ -33,6 +68,9 @@ private:
std::unique_ptr<RegisteredCache> sysnand_cache;
std::unique_ptr<RegisteredCache> usrnand_cache;
+
+ std::unique_ptr<PlaceholderCache> sysnand_placeholder;
+ std::unique_ptr<PlaceholderCache> usrnand_placeholder;
};
} // 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 @@
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/partition_filesystem.h"
+#include "core/file_sys/romfs.h"
#include "core/file_sys/submission_package.h"
+#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_offset.h"
+#include "core/file_sys/vfs_vector.h"
#include "core/loader/loader.h"
namespace FileSys {
+constexpr u64 GAMECARD_CERTIFICATE_OFFSET = 0x7000;
constexpr std::array partition_names{
"update",
"normal",
@@ -175,6 +179,26 @@ VirtualDir XCI::GetParentDirectory() const {
return file->GetContainingDirectory();
}
+VirtualDir XCI::ConcatenatedPseudoDirectory() {
+ const auto out = std::make_shared<VectorVfsDirectory>();
+ for (const auto& part_id : {XCIPartition::Normal, XCIPartition::Logo, XCIPartition::Secure}) {
+ const auto& part = GetPartition(part_id);
+ if (part == nullptr)
+ continue;
+
+ for (const auto& file : part->GetFiles())
+ out->AddFile(file);
+ }
+
+ return out;
+}
+
+std::array<u8, 0x200> XCI::GetCertificate() const {
+ std::array<u8, 0x200> out;
+ file->Read(out.data(), out.size(), GAMECARD_CERTIFICATE_OFFSET);
+ return out;
+}
+
Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
const auto partition_index = static_cast<std::size_t>(part);
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:
VirtualDir GetLogoPartition() const;
u64 GetProgramTitleID() const;
+ u32 GetSystemUpdateVersion();
+ u64 GetSystemUpdateTitleID() const;
bool HasProgramNCA() const;
VirtualFile GetProgramNCAFile() const;
@@ -106,6 +108,11 @@ public:
VirtualDir GetParentDirectory() const override;
+ // Creates a directory that contains all the NCAs in the gamecard
+ VirtualDir ConcatenatedPseudoDirectory();
+
+ std::array<u8, 0x200> GetCertificate() const;
+
private:
Loader::ResultStatus AddNCAFromPartition(XCIPartition part);
@@ -120,6 +127,8 @@ private:
std::shared_ptr<NCA> program;
std::vector<std::shared_ptr<NCA>> ncas;
+ u64 update_normal_partition_end;
+
Core::Crypto::KeyManager keys;
};
} // 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 {
return header.title_id;
}
+std::array<u8, 16> NCA::GetRightsId() const {
+ return header.rights_id;
+}
+
+u32 NCA::GetSDKVersion() const {
+ return header.sdk_version;
+}
+
bool NCA::IsUpdate() const {
return is_update;
}
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:
NCAContentType GetType() const;
u64 GetTitleId() const;
+ std::array<u8, 0x10> GetRightsId() const;
+ u32 GetSDKVersion() const;
bool IsUpdate() const;
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 {
if (Settings::values.dump_exefs) {
LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
- const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
+ const auto dump_dir =
+ Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id);
if (dump_dir != nullptr) {
const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
VfsRawCopyD(exefs, exefs_dir);
@@ -88,7 +89,8 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
}
// LayeredExeFS
- const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
+ const auto load_dir =
+ Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
if (load_dir != nullptr && load_dir->GetSize() > 0) {
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(
@@ -174,7 +176,8 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
if (Settings::values.dump_nso) {
LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id,
title_id);
- const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
+ const auto dump_dir =
+ Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id);
if (dump_dir != nullptr) {
const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso");
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
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
- const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
+ const auto load_dir =
+ Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
+ if (load_dir == nullptr) {
+ LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
+ return nso;
+ }
+
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](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 {
LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id);
- const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
+ const auto load_dir =
+ Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
+ if (load_dir == nullptr) {
+ LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
+ return false;
+ }
+
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
@@ -258,7 +273,13 @@ static std::optional<CheatList> ReadCheatFileFromFolder(const Core::System& syst
std::vector<CheatList> PatchManager::CreateCheatList(const Core::System& system,
const std::array<u8, 32>& build_id_) const {
- const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
+ const auto load_dir =
+ Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
+ if (load_dir == nullptr) {
+ LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
+ return {};
+ }
+
auto patch_dirs = load_dir->GetSubdirectories();
std::sort(patch_dirs.begin(), patch_dirs.end(),
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
@@ -284,7 +305,8 @@ std::vector<CheatList> PatchManager::CreateCheatList(const Core::System& system,
}
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) {
- const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
+ const auto load_dir =
+ Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
if ((type != ContentRecordType::Program && type != ContentRecordType::Data) ||
load_dir == nullptr || load_dir->GetSize() <= 0) {
return;
@@ -393,6 +415,8 @@ static bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames(
VirtualFile update_raw) const {
+ if (title_id == 0)
+ return {};
std::map<std::string, std::string, std::less<>> out;
const auto& installed = Core::System::GetInstance().GetContentProvider();
const auto& disabled = Settings::values.disabled_addons[title_id];
@@ -423,7 +447,8 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
}
// General Mods (LayeredFS and IPS)
- const auto mod_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
+ const auto mod_dir =
+ Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
if (mod_dir != nullptr && mod_dir->GetSize() > 0) {
for (const auto& mod : mod_dir->GetSubdirectories()) {
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 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <random>
#include <regex>
#include <mbedtls/sha256.h>
#include "common/assert.h"
@@ -48,18 +49,21 @@ static bool FollowsTwoDigitDirFormat(std::string_view name) {
static bool FollowsNcaIdFormat(std::string_view name) {
static const std::regex nca_id_regex("[0-9A-F]{32}\\.nca", std::regex_constants::ECMAScript |
std::regex_constants::icase);
- return name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex);
+ static const std::regex nca_id_cnmt_regex(
+ "[0-9A-F]{32}\\.cnmt.nca", std::regex_constants::ECMAScript | std::regex_constants::icase);
+ return (name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex)) ||
+ (name.size() == 41 && std::regex_match(name.begin(), name.end(), nca_id_cnmt_regex));
}
static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bool second_hex_upper,
- bool within_two_digit) {
- if (!within_two_digit) {
- return fmt::format("/{}.nca", Common::HexToString(nca_id, second_hex_upper));
- }
+ bool within_two_digit, bool cnmt_suffix) {
+ if (!within_two_digit)
+ return fmt::format(cnmt_suffix ? "{}.cnmt.nca" : "/{}.nca",
+ Common::HexToString(nca_id, second_hex_upper));
Core::Crypto::SHA256Hash hash{};
mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0);
- return fmt::format("/000000{:02X}/{}.nca", hash[0],
+ return fmt::format(cnmt_suffix ? "/000000{:02X}/{}.cnmt.nca" : "/000000{:02X}/{}.nca", hash[0],
Common::HexToString(nca_id, second_hex_upper));
}
@@ -127,6 +131,156 @@ std::vector<ContentProviderEntry> ContentProvider::ListEntries() const {
return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt);
}
+PlaceholderCache::PlaceholderCache(VirtualDir dir_) : dir(std::move(dir_)) {}
+
+bool PlaceholderCache::Create(const NcaID& id, u64 size) const {
+ const auto path = GetRelativePathFromNcaID(id, false, true, false);
+
+ if (dir->GetFileRelative(path) != nullptr) {
+ return false;
+ }
+
+ Core::Crypto::SHA256Hash hash{};
+ mbedtls_sha256(id.data(), id.size(), hash.data(), 0);
+ const auto dirname = fmt::format("000000{:02X}", hash[0]);
+
+ const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
+
+ if (dir2 == nullptr)
+ return false;
+
+ const auto file = dir2->CreateFile(fmt::format("{}.nca", Common::HexToString(id, false)));
+
+ if (file == nullptr)
+ return false;
+
+ return file->Resize(size);
+}
+
+bool PlaceholderCache::Delete(const NcaID& id) const {
+ const auto path = GetRelativePathFromNcaID(id, false, true, false);
+
+ if (dir->GetFileRelative(path) == nullptr) {
+ return false;
+ }
+
+ Core::Crypto::SHA256Hash hash{};
+ mbedtls_sha256(id.data(), id.size(), hash.data(), 0);
+ const auto dirname = fmt::format("000000{:02X}", hash[0]);
+
+ const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
+
+ const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexToString(id, false)));
+
+ return res;
+}
+
+bool PlaceholderCache::Exists(const NcaID& id) const {
+ const auto path = GetRelativePathFromNcaID(id, false, true, false);
+
+ return dir->GetFileRelative(path) != nullptr;
+}
+
+bool PlaceholderCache::Write(const NcaID& id, u64 offset, const std::vector<u8>& data) const {
+ const auto path = GetRelativePathFromNcaID(id, false, true, false);
+ const auto file = dir->GetFileRelative(path);
+
+ if (file == nullptr)
+ return false;
+
+ return file->WriteBytes(data, offset) == data.size();
+}
+
+bool PlaceholderCache::Register(RegisteredCache* cache, const NcaID& placeholder,
+ const NcaID& install) const {
+ const auto path = GetRelativePathFromNcaID(placeholder, false, true, false);
+ const auto file = dir->GetFileRelative(path);
+
+ if (file == nullptr)
+ return false;
+
+ const auto res = cache->RawInstallNCA(NCA{file}, &VfsRawCopy, false, install);
+
+ if (res != InstallResult::Success)
+ return false;
+
+ return Delete(placeholder);
+}
+
+bool PlaceholderCache::CleanAll() const {
+ return dir->GetParentDirectory()->CleanSubdirectoryRecursive(dir->GetName());
+}
+
+std::optional<std::array<u8, 0x10>> PlaceholderCache::GetRightsID(const NcaID& id) const {
+ const auto path = GetRelativePathFromNcaID(id, false, true, false);
+ const auto file = dir->GetFileRelative(path);
+
+ if (file == nullptr)
+ return std::nullopt;
+
+ NCA nca{file};
+
+ if (nca.GetStatus() != Loader::ResultStatus::Success &&
+ nca.GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
+ return std::nullopt;
+ }
+
+ const auto rights_id = nca.GetRightsId();
+ if (rights_id == NcaID{})
+ return std::nullopt;
+
+ return rights_id;
+}
+
+u64 PlaceholderCache::Size(const NcaID& id) const {
+ const auto path = GetRelativePathFromNcaID(id, false, true, false);
+ const auto file = dir->GetFileRelative(path);
+
+ if (file == nullptr)
+ return 0;
+
+ return file->GetSize();
+}
+
+bool PlaceholderCache::SetSize(const NcaID& id, u64 new_size) const {
+ const auto path = GetRelativePathFromNcaID(id, false, true, false);
+ const auto file = dir->GetFileRelative(path);
+
+ if (file == nullptr)
+ return false;
+
+ return file->Resize(new_size);
+}
+
+std::vector<NcaID> PlaceholderCache::List() const {
+ std::vector<NcaID> out;
+ for (const auto& sdir : dir->GetSubdirectories()) {
+ for (const auto& file : sdir->GetFiles()) {
+ const auto name = file->GetName();
+ if (name.length() == 36 && name[32] == '.' && name[33] == 'n' && name[34] == 'c' &&
+ name[35] == 'a') {
+ out.push_back(Common::HexStringToArray<0x10>(name.substr(0, 32)));
+ }
+ }
+ }
+ return out;
+}
+
+NcaID PlaceholderCache::Generate() {
+ std::random_device device;
+ std::mt19937 gen(device());
+ std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
+
+ NcaID out{};
+
+ const auto v1 = distribution(gen);
+ const auto v2 = distribution(gen);
+ std::memcpy(out.data(), &v1, sizeof(u64));
+ std::memcpy(out.data() + sizeof(u64), &v2, sizeof(u64));
+
+ return out;
+}
+
VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
std::string_view path) const {
const auto file = dir->GetFileRelative(path);
@@ -169,14 +323,18 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
VirtualFile file;
- // Try all four modes of file storage:
- // (bit 1 = uppercase/lower, bit 0 = within a two-digit dir)
- // 00: /000000**/{:032X}.nca
- // 01: /{:032X}.nca
- // 10: /000000**/{:032x}.nca
- // 11: /{:032x}.nca
- for (u8 i = 0; i < 4; ++i) {
- const auto path = GetRelativePathFromNcaID(id, (i & 0b10) == 0, (i & 0b01) == 0);
+ // Try all five relevant modes of file storage:
+ // (bit 2 = uppercase/lower, bit 1 = within a two-digit dir, bit 0 = .cnmt suffix)
+ // 000: /000000**/{:032X}.nca
+ // 010: /{:032X}.nca
+ // 100: /000000**/{:032x}.nca
+ // 110: /{:032x}.nca
+ // 111: /{:032x}.cnmt.nca
+ for (u8 i = 0; i < 8; ++i) {
+ if ((i % 2) == 1 && i != 7)
+ continue;
+ const auto path =
+ GetRelativePathFromNcaID(id, (i & 0b100) == 0, (i & 0b010) == 0, (i & 0b001) == 0b001);
file = OpenFileOrDirectoryConcat(dir, path);
if (file != nullptr)
return file;
@@ -472,7 +630,7 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
memcpy(id.data(), hash.data(), 16);
}
- std::string path = GetRelativePathFromNcaID(id, false, true);
+ std::string path = GetRelativePathFromNcaID(id, false, true, false);
if (GetFileAtID(id) != nullptr && !overwrite_if_exists) {
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;
enum class TitleType : u8;
struct ContentRecord;
+struct MetaRecord;
+class RegisteredCache;
using NcaID = std::array<u8, 0x10>;
using ContentProviderParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>;
@@ -89,6 +91,27 @@ protected:
Core::Crypto::KeyManager keys;
};
+class PlaceholderCache {
+public:
+ explicit PlaceholderCache(VirtualDir dir);
+
+ bool Create(const NcaID& id, u64 size) const;
+ bool Delete(const NcaID& id) const;
+ bool Exists(const NcaID& id) const;
+ bool Write(const NcaID& id, u64 offset, const std::vector<u8>& data) const;
+ bool Register(RegisteredCache* cache, const NcaID& placeholder, const NcaID& install) const;
+ bool CleanAll() const;
+ std::optional<std::array<u8, 0x10>> GetRightsID(const NcaID& id) const;
+ u64 Size(const NcaID& id) const;
+ bool SetSize(const NcaID& id, u64 new_size) const;
+ std::vector<NcaID> List() const;
+
+ static NcaID Generate();
+
+private:
+ VirtualDir dir;
+};
+
/*
* A class that catalogues NCAs in the registered directory structure.
* Nintendo's registered format follows this structure:
@@ -103,6 +126,8 @@ protected:
* when 4GB splitting can be ignored.)
*/
class RegisteredCache : public ContentProvider {
+ friend class PlaceholderCache;
+
public:
// Parsing function defines the conversion from raw file to NCA. If there are other steps
// 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 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/core.h"
+#include "core/file_sys/card_image.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
@@ -34,7 +35,7 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) {
this->update_raw = std::move(update_raw);
}
-ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
+ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() const {
if (!updatable)
return MakeResult<VirtualFile>(file);
@@ -43,7 +44,8 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw));
}
-ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) {
+ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage,
+ ContentRecordType type) const {
std::shared_ptr<NCA> res;
switch (storage) {
@@ -51,13 +53,17 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, Conte
res = Core::System::GetInstance().GetContentProvider().GetEntry(title_id, type);
break;
case StorageId::NandSystem:
- res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type);
+ res =
+ Core::System::GetInstance().GetFileSystemController().GetSystemNANDContents()->GetEntry(
+ title_id, type);
break;
case StorageId::NandUser:
- res = Service::FileSystem::GetUserNANDContents()->GetEntry(title_id, type);
+ res = Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->GetEntry(
+ title_id, type);
break;
case StorageId::SdCard:
- res = Service::FileSystem::GetSDMCContents()->GetEntry(title_id, type);
+ res = Core::System::GetInstance().GetFileSystemController().GetSDMCContents()->GetEntry(
+ title_id, type);
break;
default:
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:
~RomFSFactory();
void SetPackedUpdate(VirtualFile update_raw);
- ResultVal<VirtualFile> OpenCurrentProcess();
- ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type);
+ ResultVal<VirtualFile> OpenCurrentProcess() const;
+ ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type) const;
private:
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 {
constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size";
-std::string SaveDataDescriptor::DebugInfo() const {
- return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, "
- "rank={}, index={}]",
- static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id,
- static_cast<u8>(rank), index);
-}
-
-SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
- // Delete all temporary storages
- // On hardware, it is expected that temporary storage be empty at first use.
- dir->DeleteSubdirectoryRecursive("temp");
-}
-
-SaveDataFactory::~SaveDataFactory() = default;
-
-ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataDescriptor& meta) {
+namespace {
+void PrintSaveDataDescriptorWarnings(SaveDataDescriptor meta) {
if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
if (meta.zero_1 != 0) {
LOG_WARNING(Service_FS,
@@ -65,23 +51,51 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, const SaveDat
"non-zero ({:016X}{:016X})",
meta.user_id[1], meta.user_id[0]);
}
+}
+} // Anonymous namespace
- std::string save_directory =
- GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
+std::string SaveDataDescriptor::DebugInfo() const {
+ return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, "
+ "save_id={:016X}, "
+ "rank={}, index={}]",
+ static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id,
+ static_cast<u8>(rank), index);
+}
- // TODO(DarkLordZach): Try to not create when opening, there are dedicated create save methods.
- // But, user_ids don't match so this works for now.
+SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
+ // Delete all temporary storages
+ // On hardware, it is expected that temporary storage be empty at first use.
+ dir->DeleteSubdirectoryRecursive("temp");
+}
- auto out = dir->GetDirectoryRelative(save_directory);
+SaveDataFactory::~SaveDataFactory() = default;
+
+ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
+ const SaveDataDescriptor& meta) const {
+ PrintSaveDataDescriptorWarnings(meta);
+
+ const auto save_directory =
+ GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
+
+ auto out = dir->CreateDirectoryRelative(save_directory);
+ // Return an error if the save data doesn't actually exist.
if (out == nullptr) {
- // TODO(bunnei): This is a work-around to always create a save data directory if it does not
- // already exist. This is a hack, as we do not understand yet how this works on hardware.
- // Without a save data directory, many games will assert on boot. This should not have any
- // bad side-effects.
- out = dir->CreateDirectoryRelative(save_directory);
+ // TODO(DarkLordZach): Find out correct error code.
+ return ResultCode(-1);
}
+ return MakeResult<VirtualDir>(std::move(out));
+}
+
+ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
+ const SaveDataDescriptor& meta) const {
+
+ const auto save_directory =
+ GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
+
+ auto out = dir->GetDirectoryRelative(save_directory);
+
// Return an error if the save data doesn't actually exist.
if (out == nullptr) {
// TODO(Subv): Find out correct error code.
@@ -152,7 +166,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
}
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
- SaveDataSize new_value) {
+ SaveDataSize new_value) const {
const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
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:
explicit SaveDataFactory(VirtualDir dir);
~SaveDataFactory();
- ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataDescriptor& meta);
+ ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataDescriptor& meta) const;
+ ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataDescriptor& meta) const;
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
@@ -73,7 +74,8 @@ public:
u128 user_id, u64 save_id);
SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const;
- void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, SaveDataSize new_value);
+ void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
+ SaveDataSize new_value) const;
private:
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 @@
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/sdmc_factory.h"
#include "core/file_sys/xts_archive.h"
+#include "core/settings.h"
namespace FileSys {
@@ -14,16 +15,38 @@ SDMCFactory::SDMCFactory(VirtualDir dir_)
GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"),
[](const VirtualFile& file, const NcaID& id) {
return NAX{file, id}.GetDecrypted();
- })) {}
+ })),
+ placeholder(std::make_unique<PlaceholderCache>(
+ GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/placehld"))) {}
SDMCFactory::~SDMCFactory() = default;
-ResultVal<VirtualDir> SDMCFactory::Open() {
+ResultVal<VirtualDir> SDMCFactory::Open() const {
return MakeResult<VirtualDir>(dir);
}
+VirtualDir SDMCFactory::GetSDMCContentDirectory() const {
+ return GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents");
+}
+
RegisteredCache* SDMCFactory::GetSDMCContents() const {
return contents.get();
}
+PlaceholderCache* SDMCFactory::GetSDMCPlaceholder() const {
+ return placeholder.get();
+}
+
+VirtualDir SDMCFactory::GetImageDirectory() const {
+ return GetOrCreateDirectoryRelative(dir, "/Nintendo/Album");
+}
+
+u64 SDMCFactory::GetSDMCFreeSpace() const {
+ return GetSDMCTotalSpace() - dir->GetSize();
+}
+
+u64 SDMCFactory::GetSDMCTotalSpace() const {
+ return static_cast<u64>(Settings::values.sdmc_size);
+}
+
} // 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 @@
namespace FileSys {
class RegisteredCache;
+class PlaceholderCache;
/// File system interface to the SDCard archive
class SDMCFactory {
@@ -18,13 +19,23 @@ public:
explicit SDMCFactory(VirtualDir dir);
~SDMCFactory();
- ResultVal<VirtualDir> Open();
+ ResultVal<VirtualDir> Open() const;
+
+ VirtualDir GetSDMCContentDirectory() const;
+
RegisteredCache* GetSDMCContents() const;
+ PlaceholderCache* GetSDMCPlaceholder() const;
+
+ VirtualDir GetImageDirectory() const;
+
+ u64 GetSDMCFreeSpace() const;
+ u64 GetSDMCTotalSpace() const;
private:
VirtualDir dir;
std::unique_ptr<RegisteredCache> contents;
+ std::unique_ptr<PlaceholderCache> placeholder;
};
} // 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) {
void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
for (const auto& outer_file : files) {
- if (outer_file->GetName().substr(outer_file->GetName().size() - 9) != ".cnmt.nca") {
+ if (outer_file->GetName().size() < 9 ||
+ outer_file->GetName().substr(outer_file->GetName().size() - 9) != ".cnmt.nca") {
continue;
}
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(
void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
- u128 uid = rp.PopRaw<u128>(); // What does this do?
- LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]);
+ u128 user_id = rp.PopRaw<u128>();
+
+ LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
+
+ FileSys::SaveDataDescriptor descriptor{};
+ descriptor.title_id = Core::CurrentProcess()->GetTitleID();
+ descriptor.user_id = user_id;
+ descriptor.type = FileSys::SaveDataType::SaveData;
+ const auto res = system.GetFileSystemController().CreateSaveData(
+ FileSys::SaveDataSpaceId::NandUser, descriptor);
IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(RESULT_SUCCESS);
+ rb.Push(res.Code());
rb.Push<u64>(0);
-} // namespace Service::AM
+}
void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
// Takes an input u32 Result, no output.
@@ -1261,8 +1269,8 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
"new_journal={:016X}",
static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
- const auto title_id = system.CurrentProcess()->GetTitleID();
- FileSystem::WriteSaveDataSize(type, title_id, user_id, {new_normal_size, new_journal_size});
+ system.GetFileSystemController().WriteSaveDataSize(
+ type, system.CurrentProcess()->GetTitleID(), user_id, {new_normal_size, new_journal_size});
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(RESULT_SUCCESS);
@@ -1281,8 +1289,8 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type),
user_id[1], user_id[0]);
- const auto title_id = system.CurrentProcess()->GetTitleID();
- const auto size = FileSystem::ReadSaveDataSize(type, title_id, user_id);
+ const auto size = system.GetFileSystemController().ReadSaveDataSize(
+ type, system.CurrentProcess()->GetTitleID(), user_id);
IPC::ResponseBuilder rb{ctx, 6};
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 @@
#include "core/hle/service/service.h"
namespace Service {
+namespace FileSystem {
+class FileSystemController;
+}
+
namespace NVFlinger {
class NVFlinger;
}
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 @@
#include "core/hle/service/service.h"
namespace Service {
+namespace FileSystem {
+class FileSystemController;
+}
+
namespace NVFlinger {
class NVFlinger;
}
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 @@
#include "common/file_util.h"
#include "core/core.h"
#include "core/file_sys/bis_factory.h"
+#include "core/file_sys/card_image.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/errors.h"
#include "core/file_sys/mode.h"
@@ -25,14 +26,10 @@
#include "core/hle/service/filesystem/fsp_pr.h"
#include "core/hle/service/filesystem/fsp_srv.h"
#include "core/loader/loader.h"
+#include "core/settings.h"
namespace Service::FileSystem {
-// Size of emulated sd card free space, reported in bytes.
-// Just using 32GB because thats reasonable
-// TODO(DarkLordZach): Eventually make this configurable in settings.
-constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000;
-
// A default size for normal/journal save data size if application control metadata cannot be found.
// This should be large enough to satisfy even the most extreme requirements (~4.2GB)
constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000;
@@ -226,13 +223,6 @@ ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const s
return MakeResult(dir);
}
-u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const {
- if (backing->IsWritable())
- return EMULATED_SD_REPORTED_SIZE;
-
- return 0;
-}
-
ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
const std::string& path_) const {
std::string path(FileUtil::SanitizePath(path_));
@@ -251,44 +241,39 @@ ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
return FileSys::ERROR_PATH_NOT_FOUND;
}
-/**
- * Map of registered file systems, identified by type. Once an file system is registered here, it
- * is never removed until UnregisterFileSystems is called.
- */
-static std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
-static std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
-static std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
-static std::unique_ptr<FileSys::BISFactory> bis_factory;
+FileSystemController::FileSystemController() = default;
+
+FileSystemController::~FileSystemController() = default;
-ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
- ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second RomFS");
+ResultCode FileSystemController::RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
romfs_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered RomFS");
return RESULT_SUCCESS;
}
-ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory) {
- ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second save data");
+ResultCode FileSystemController::RegisterSaveData(
+ std::unique_ptr<FileSys::SaveDataFactory>&& factory) {
+ ASSERT_MSG(save_data_factory == nullptr, "Tried to register a second save data");
save_data_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered save data");
return RESULT_SUCCESS;
}
-ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
+ResultCode FileSystemController::RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
ASSERT_MSG(sdmc_factory == nullptr, "Tried to register a second SDMC");
sdmc_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered SDMC");
return RESULT_SUCCESS;
}
-ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
+ResultCode FileSystemController::RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
ASSERT_MSG(bis_factory == nullptr, "Tried to register a second BIS");
bis_factory = std::move(factory);
LOG_DEBUG(Service_FS, "Registered BIS");
return RESULT_SUCCESS;
}
-void SetPackedUpdate(FileSys::VirtualFile update_raw) {
+void FileSystemController::SetPackedUpdate(FileSys::VirtualFile update_raw) {
LOG_TRACE(Service_FS, "Setting packed update for romfs");
if (romfs_factory == nullptr)
@@ -297,7 +282,7 @@ void SetPackedUpdate(FileSys::VirtualFile update_raw) {
romfs_factory->SetPackedUpdate(std::move(update_raw));
}
-ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() {
+ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess() const {
LOG_TRACE(Service_FS, "Opening RomFS for current process");
if (romfs_factory == nullptr) {
@@ -308,8 +293,8 @@ ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() {
return romfs_factory->OpenCurrentProcess();
}
-ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
- FileSys::ContentRecordType type) {
+ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS(
+ u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const {
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}",
title_id, static_cast<u8>(storage_id), static_cast<u8>(type));
@@ -321,8 +306,20 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
return romfs_factory->Open(title_id, storage_id, type);
}
-ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
- const FileSys::SaveDataDescriptor& descriptor) {
+ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
+ FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const {
+ LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}",
+ static_cast<u8>(space), save_struct.DebugInfo());
+
+ if (save_data_factory == nullptr) {
+ return FileSys::ERROR_ENTITY_NOT_FOUND;
+ }
+
+ return save_data_factory->Create(space, save_struct);
+}
+
+ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData(
+ FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& descriptor) const {
LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}",
static_cast<u8>(space), descriptor.DebugInfo());
@@ -333,7 +330,8 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
return save_data_factory->Open(space, descriptor);
}
-ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) {
+ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace(
+ FileSys::SaveDataSpaceId space) const {
LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space));
if (save_data_factory == nullptr) {
@@ -343,7 +341,7 @@ ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space)
return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space));
}
-ResultVal<FileSys::VirtualDir> OpenSDMC() {
+ResultVal<FileSys::VirtualDir> FileSystemController::OpenSDMC() const {
LOG_TRACE(Service_FS, "Opening SDMC");
if (sdmc_factory == nullptr) {
@@ -353,7 +351,92 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
return sdmc_factory->Open();
}
-FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id) {
+ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition(
+ FileSys::BisPartitionId id) const {
+ LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", static_cast<u32>(id));
+
+ if (bis_factory == nullptr) {
+ return FileSys::ERROR_ENTITY_NOT_FOUND;
+ }
+
+ auto part = bis_factory->OpenPartition(id);
+ if (part == nullptr) {
+ return FileSys::ERROR_INVALID_ARGUMENT;
+ }
+
+ return MakeResult<FileSys::VirtualDir>(std::move(part));
+}
+
+ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
+ FileSys::BisPartitionId id) const {
+ LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", static_cast<u32>(id));
+
+ if (bis_factory == nullptr) {
+ return FileSys::ERROR_ENTITY_NOT_FOUND;
+ }
+
+ auto part = bis_factory->OpenPartitionStorage(id);
+ if (part == nullptr) {
+ return FileSys::ERROR_INVALID_ARGUMENT;
+ }
+
+ return MakeResult<FileSys::VirtualFile>(std::move(part));
+}
+
+u64 FileSystemController::GetFreeSpaceSize(FileSys::StorageId id) const {
+ switch (id) {
+ case FileSys::StorageId::None:
+ case FileSys::StorageId::GameCard:
+ return 0;
+ case FileSys::StorageId::SdCard:
+ if (sdmc_factory == nullptr)
+ return 0;
+ return sdmc_factory->GetSDMCFreeSpace();
+ case FileSys::StorageId::Host:
+ if (bis_factory == nullptr)
+ return 0;
+ return bis_factory->GetSystemNANDFreeSpace() + bis_factory->GetUserNANDFreeSpace();
+ case FileSys::StorageId::NandSystem:
+ if (bis_factory == nullptr)
+ return 0;
+ return bis_factory->GetSystemNANDFreeSpace();
+ case FileSys::StorageId::NandUser:
+ if (bis_factory == nullptr)
+ return 0;
+ return bis_factory->GetUserNANDFreeSpace();
+ }
+
+ return 0;
+}
+
+u64 FileSystemController::GetTotalSpaceSize(FileSys::StorageId id) const {
+ switch (id) {
+ case FileSys::StorageId::None:
+ case FileSys::StorageId::GameCard:
+ return 0;
+ case FileSys::StorageId::SdCard:
+ if (sdmc_factory == nullptr)
+ return 0;
+ return sdmc_factory->GetSDMCTotalSpace();
+ case FileSys::StorageId::Host:
+ if (bis_factory == nullptr)
+ return 0;
+ return bis_factory->GetFullNANDTotalSpace();
+ case FileSys::StorageId::NandSystem:
+ if (bis_factory == nullptr)
+ return 0;
+ return bis_factory->GetSystemNANDTotalSpace();
+ case FileSys::StorageId::NandUser:
+ if (bis_factory == nullptr)
+ return 0;
+ return bis_factory->GetUserNANDTotalSpace();
+ }
+
+ return 0;
+}
+
+FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataType type,
+ u64 title_id, u128 user_id) const {
if (save_data_factory == nullptr) {
return {0, 0};
}
@@ -385,13 +468,32 @@ FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
return value;
}
-void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
- FileSys::SaveDataSize new_value) {
+void FileSystemController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
+ FileSys::SaveDataSize new_value) const {
if (save_data_factory != nullptr)
save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value);
}
-FileSys::RegisteredCache* GetSystemNANDContents() {
+void FileSystemController::SetGameCard(FileSys::VirtualFile file) {
+ gamecard = std::make_unique<FileSys::XCI>(file);
+ const auto dir = gamecard->ConcatenatedPseudoDirectory();
+ gamecard_registered = std::make_unique<FileSys::RegisteredCache>(dir);
+ gamecard_placeholder = std::make_unique<FileSys::PlaceholderCache>(dir);
+}
+
+FileSys::XCI* FileSystemController::GetGameCard() const {
+ return gamecard.get();
+}
+
+FileSys::RegisteredCache* FileSystemController::GetGameCardContents() const {
+ return gamecard_registered.get();
+}
+
+FileSys::PlaceholderCache* FileSystemController::GetGameCardPlaceholder() const {
+ return gamecard_placeholder.get();
+}
+
+FileSys::RegisteredCache* FileSystemController::GetSystemNANDContents() const {
LOG_TRACE(Service_FS, "Opening System NAND Contents");
if (bis_factory == nullptr)
@@ -400,7 +502,7 @@ FileSys::RegisteredCache* GetSystemNANDContents() {
return bis_factory->GetSystemNANDContents();
}
-FileSys::RegisteredCache* GetUserNANDContents() {
+FileSys::RegisteredCache* FileSystemController::GetUserNANDContents() const {
LOG_TRACE(Service_FS, "Opening User NAND Contents");
if (bis_factory == nullptr)
@@ -409,7 +511,7 @@ FileSys::RegisteredCache* GetUserNANDContents() {
return bis_factory->GetUserNANDContents();
}
-FileSys::RegisteredCache* GetSDMCContents() {
+FileSys::RegisteredCache* FileSystemController::GetSDMCContents() const {
LOG_TRACE(Service_FS, "Opening SDMC Contents");
if (sdmc_factory == nullptr)
@@ -418,7 +520,143 @@ FileSys::RegisteredCache* GetSDMCContents() {
return sdmc_factory->GetSDMCContents();
}
-FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
+FileSys::PlaceholderCache* FileSystemController::GetSystemNANDPlaceholder() const {
+ LOG_TRACE(Service_FS, "Opening System NAND Placeholder");
+
+ if (bis_factory == nullptr)
+ return nullptr;
+
+ return bis_factory->GetSystemNANDPlaceholder();
+}
+
+FileSys::PlaceholderCache* FileSystemController::GetUserNANDPlaceholder() const {
+ LOG_TRACE(Service_FS, "Opening User NAND Placeholder");
+
+ if (bis_factory == nullptr)
+ return nullptr;
+
+ return bis_factory->GetUserNANDPlaceholder();
+}
+
+FileSys::PlaceholderCache* FileSystemController::GetSDMCPlaceholder() const {
+ LOG_TRACE(Service_FS, "Opening SDMC Placeholder");
+
+ if (sdmc_factory == nullptr)
+ return nullptr;
+
+ return sdmc_factory->GetSDMCPlaceholder();
+}
+
+FileSys::RegisteredCache* FileSystemController::GetRegisteredCacheForStorage(
+ FileSys::StorageId id) const {
+ switch (id) {
+ case FileSys::StorageId::None:
+ case FileSys::StorageId::Host:
+ UNIMPLEMENTED();
+ return nullptr;
+ case FileSys::StorageId::GameCard:
+ return GetGameCardContents();
+ case FileSys::StorageId::NandSystem:
+ return GetSystemNANDContents();
+ case FileSys::StorageId::NandUser:
+ return GetUserNANDContents();
+ case FileSys::StorageId::SdCard:
+ return GetSDMCContents();
+ }
+
+ return nullptr;
+}
+
+FileSys::PlaceholderCache* FileSystemController::GetPlaceholderCacheForStorage(
+ FileSys::StorageId id) const {
+ switch (id) {
+ case FileSys::StorageId::None:
+ case FileSys::StorageId::Host:
+ UNIMPLEMENTED();
+ return nullptr;
+ case FileSys::StorageId::GameCard:
+ return GetGameCardPlaceholder();
+ case FileSys::StorageId::NandSystem:
+ return GetSystemNANDPlaceholder();
+ case FileSys::StorageId::NandUser:
+ return GetUserNANDPlaceholder();
+ case FileSys::StorageId::SdCard:
+ return GetSDMCPlaceholder();
+ }
+
+ return nullptr;
+}
+
+FileSys::VirtualDir FileSystemController::GetSystemNANDContentDirectory() const {
+ LOG_TRACE(Service_FS, "Opening system NAND content directory");
+
+ if (bis_factory == nullptr)
+ return nullptr;
+
+ return bis_factory->GetSystemNANDContentDirectory();
+}
+
+FileSys::VirtualDir FileSystemController::GetUserNANDContentDirectory() const {
+ LOG_TRACE(Service_FS, "Opening user NAND content directory");
+
+ if (bis_factory == nullptr)
+ return nullptr;
+
+ return bis_factory->GetUserNANDContentDirectory();
+}
+
+FileSys::VirtualDir FileSystemController::GetSDMCContentDirectory() const {
+ LOG_TRACE(Service_FS, "Opening SDMC content directory");
+
+ if (sdmc_factory == nullptr)
+ return nullptr;
+
+ return sdmc_factory->GetSDMCContentDirectory();
+}
+
+FileSys::VirtualDir FileSystemController::GetNANDImageDirectory() const {
+ LOG_TRACE(Service_FS, "Opening NAND image directory");
+
+ if (bis_factory == nullptr)
+ return nullptr;
+
+ return bis_factory->GetImageDirectory();
+}
+
+FileSys::VirtualDir FileSystemController::GetSDMCImageDirectory() const {
+ LOG_TRACE(Service_FS, "Opening SDMC image directory");
+
+ if (sdmc_factory == nullptr)
+ return nullptr;
+
+ return sdmc_factory->GetImageDirectory();
+}
+
+FileSys::VirtualDir FileSystemController::GetContentDirectory(ContentStorageId id) const {
+ switch (id) {
+ case ContentStorageId::System:
+ return GetSystemNANDContentDirectory();
+ case ContentStorageId::User:
+ return GetUserNANDContentDirectory();
+ case ContentStorageId::SdCard:
+ return GetSDMCContentDirectory();
+ }
+
+ return nullptr;
+}
+
+FileSys::VirtualDir FileSystemController::GetImageDirectory(ImageDirectoryId id) const {
+ switch (id) {
+ case ImageDirectoryId::NAND:
+ return GetNANDImageDirectory();
+ case ImageDirectoryId::SdCard:
+ return GetSDMCImageDirectory();
+ }
+
+ return nullptr;
+}
+
+FileSys::VirtualDir FileSystemController::GetModificationLoadRoot(u64 title_id) const {
LOG_TRACE(Service_FS, "Opening mod load root for tid={:016X}", title_id);
if (bis_factory == nullptr)
@@ -427,7 +665,7 @@ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
return bis_factory->GetModificationLoadRoot(title_id);
}
-FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) {
+FileSys::VirtualDir FileSystemController::GetModificationDumpRoot(u64 title_id) const {
LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id);
if (bis_factory == nullptr)
@@ -436,7 +674,7 @@ FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) {
return bis_factory->GetModificationDumpRoot(title_id);
}
-void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
+void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
if (overwrite) {
bis_factory = nullptr;
save_data_factory = nullptr;
@@ -473,11 +711,10 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
}
void InstallInterfaces(Core::System& system) {
- romfs_factory = nullptr;
- CreateFactories(*system.GetFilesystem(), false);
std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager());
std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager());
- std::make_shared<FSP_SRV>(system.GetReporter())->InstallAsService(system.ServiceManager());
+ std::make_shared<FSP_SRV>(system.GetFileSystemController(), system.GetReporter())
+ ->InstallAsService(system.ServiceManager());
}
} // 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 {
class BISFactory;
class RegisteredCache;
class RegisteredCacheUnion;
+class PlaceholderCache;
class RomFSFactory;
class SaveDataFactory;
class SDMCFactory;
+class XCI;
+enum class BisPartitionId : u32;
enum class ContentRecordType : u8;
enum class Mode : u32;
enum class SaveDataSpaceId : u8;
@@ -36,34 +39,91 @@ class ServiceManager;
namespace FileSystem {
-ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory);
-ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory);
-ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
-ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
-
-void SetPackedUpdate(FileSys::VirtualFile update_raw);
-ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess();
-ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
- FileSys::ContentRecordType type);
-ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
- const FileSys::SaveDataDescriptor& descriptor);
-ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
-ResultVal<FileSys::VirtualDir> OpenSDMC();
-
-FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id);
-void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
- FileSys::SaveDataSize new_value);
+enum class ContentStorageId : u32 {
+ System,
+ User,
+ SdCard,
+};
-FileSys::RegisteredCache* GetSystemNANDContents();
-FileSys::RegisteredCache* GetUserNANDContents();
-FileSys::RegisteredCache* GetSDMCContents();
+enum class ImageDirectoryId : u32 {
+ NAND,
+ SdCard,
+};
-FileSys::VirtualDir GetModificationLoadRoot(u64 title_id);
-FileSys::VirtualDir GetModificationDumpRoot(u64 title_id);
+class FileSystemController {
+public:
+ FileSystemController();
+ ~FileSystemController();
+
+ ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory);
+ ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory);
+ ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
+ ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
+
+ void SetPackedUpdate(FileSys::VirtualFile update_raw);
+ ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() const;
+ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
+ FileSys::ContentRecordType type) const;
+ ResultVal<FileSys::VirtualDir> CreateSaveData(
+ FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const;
+ ResultVal<FileSys::VirtualDir> OpenSaveData(
+ FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const;
+ ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) const;
+ ResultVal<FileSys::VirtualDir> OpenSDMC() const;
+ ResultVal<FileSys::VirtualDir> OpenBISPartition(FileSys::BisPartitionId id) const;
+ ResultVal<FileSys::VirtualFile> OpenBISPartitionStorage(FileSys::BisPartitionId id) const;
+
+ u64 GetFreeSpaceSize(FileSys::StorageId id) const;
+ u64 GetTotalSpaceSize(FileSys::StorageId id) const;
+
+ FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
+ u128 user_id) const;
+ void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
+ FileSys::SaveDataSize new_value) const;
+
+ void SetGameCard(FileSys::VirtualFile file);
+ FileSys::XCI* GetGameCard() const;
+
+ FileSys::RegisteredCache* GetSystemNANDContents() const;
+ FileSys::RegisteredCache* GetUserNANDContents() const;
+ FileSys::RegisteredCache* GetSDMCContents() const;
+ FileSys::RegisteredCache* GetGameCardContents() const;
+
+ FileSys::PlaceholderCache* GetSystemNANDPlaceholder() const;
+ FileSys::PlaceholderCache* GetUserNANDPlaceholder() const;
+ FileSys::PlaceholderCache* GetSDMCPlaceholder() const;
+ FileSys::PlaceholderCache* GetGameCardPlaceholder() const;
+
+ FileSys::RegisteredCache* GetRegisteredCacheForStorage(FileSys::StorageId id) const;
+ FileSys::PlaceholderCache* GetPlaceholderCacheForStorage(FileSys::StorageId id) const;
+
+ FileSys::VirtualDir GetSystemNANDContentDirectory() const;
+ FileSys::VirtualDir GetUserNANDContentDirectory() const;
+ FileSys::VirtualDir GetSDMCContentDirectory() const;
+
+ FileSys::VirtualDir GetNANDImageDirectory() const;
+ FileSys::VirtualDir GetSDMCImageDirectory() const;
+
+ FileSys::VirtualDir GetContentDirectory(ContentStorageId id) const;
+ FileSys::VirtualDir GetImageDirectory(ImageDirectoryId id) const;
+
+ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const;
+ FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const;
+
+ // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
+ // above is called.
+ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
-// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
-// above is called.
-void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
+private:
+ std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
+ std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
+ std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
+ std::unique_ptr<FileSys::BISFactory> bis_factory;
+
+ std::unique_ptr<FileSys::XCI> gamecard;
+ std::unique_ptr<FileSys::RegisteredCache> gamecard_registered;
+ std::unique_ptr<FileSys::PlaceholderCache> gamecard_placeholder;
+};
void InstallInterfaces(Core::System& system);
@@ -160,12 +220,6 @@ public:
ResultVal<FileSys::VirtualDir> OpenDirectory(const std::string& path);
/**
- * Get the free space
- * @return The number of free bytes in the archive
- */
- u64 GetFreeSpaceSize() const;
-
- /**
* Get the type of the specified path
* @return The type of the specified path or error code
*/
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 @@
#include "core/file_sys/mode.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
+#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/savedata_factory.h"
#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/vfs.h"
@@ -30,6 +31,18 @@
namespace Service::FileSystem {
+struct SizeGetter {
+ std::function<u64()> get_free_size;
+ std::function<u64()> get_total_size;
+
+ static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) {
+ return {
+ [&fsc, id] { return fsc.GetFreeSpaceSize(id); },
+ [&fsc, id] { return fsc.GetTotalSpaceSize(id); },
+ };
+ }
+};
+
enum class FileSystemType : u8 {
Invalid0 = 0,
Invalid1 = 1,
@@ -289,8 +302,8 @@ private:
class IFileSystem final : public ServiceFramework<IFileSystem> {
public:
- explicit IFileSystem(FileSys::VirtualDir backend)
- : ServiceFramework("IFileSystem"), backend(std::move(backend)) {
+ explicit IFileSystem(FileSys::VirtualDir backend, SizeGetter size)
+ : ServiceFramework("IFileSystem"), backend(std::move(backend)), size(std::move(size)) {
static const FunctionInfo functions[] = {
{0, &IFileSystem::CreateFile, "CreateFile"},
{1, &IFileSystem::DeleteFile, "DeleteFile"},
@@ -467,14 +480,31 @@ public:
rb.Push(RESULT_SUCCESS);
}
+ void GetFreeSpaceSize(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(size.get_free_size());
+ }
+
+ void GetTotalSpaceSize(Kernel::HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(RESULT_SUCCESS);
+ rb.Push(size.get_total_size());
+ }
+
private:
VfsDirectoryServiceWrapper backend;
+ SizeGetter size;
};
class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
public:
- explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space)
- : ServiceFramework("ISaveDataInfoReader") {
+ explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space, FileSystemController& fsc)
+ : ServiceFramework("ISaveDataInfoReader"), fsc(fsc) {
static const FunctionInfo functions[] = {
{0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
};
@@ -520,8 +550,13 @@ private:
}
void FindAllSaves(FileSys::SaveDataSpaceId space) {
- const auto save_root = OpenSaveDataSpace(space);
- ASSERT(save_root.Succeeded());
+ const auto save_root = fsc.OpenSaveDataSpace(space);
+
+ if (save_root.Failed() || *save_root == nullptr) {
+ LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!",
+ static_cast<u8>(space));
+ return;
+ }
for (const auto& type : (*save_root)->GetSubdirectories()) {
if (type->GetName() == "save") {
@@ -610,11 +645,13 @@ private:
};
static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
+ FileSystemController& fsc;
std::vector<SaveDataInfo> info;
u64 next_entry_index = 0;
};
-FSP_SRV::FSP_SRV(const Core::Reporter& reporter) : ServiceFramework("fsp-srv"), reporter(reporter) {
+FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter)
+ : ServiceFramework("fsp-srv"), fsc(fsc), reporter(reporter) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "OpenFileSystem"},
@@ -754,7 +791,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
- IFileSystem filesystem(OpenSDMC().Unwrap());
+ IFileSystem filesystem(fsc.OpenSDMC().Unwrap(),
+ SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -768,8 +806,10 @@ void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
u128 uid = rp.PopRaw<u128>();
- LOG_WARNING(Service_FS, "(STUBBED) called save_struct = {}, uid = {:016X}{:016X}",
- save_struct.DebugInfo(), uid[1], uid[0]);
+ LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
+ uid[1], uid[0]);
+
+ fsc.CreateSaveData(FileSys::SaveDataSpaceId::NandUser, save_struct);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
@@ -786,14 +826,24 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto parameters = rp.PopRaw<Parameters>();
- auto dir = OpenSaveData(parameters.save_data_space_id, parameters.descriptor);
+ auto dir = fsc.OpenSaveData(parameters.save_data_space_id, parameters.descriptor);
if (dir.Failed()) {
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
return;
}
- IFileSystem filesystem(std::move(dir.Unwrap()));
+ FileSys::StorageId id;
+ if (parameters.save_data_space_id == FileSys::SaveDataSpaceId::NandUser) {
+ id = FileSys::StorageId::NandUser;
+ } else if (parameters.save_data_space_id == FileSys::SaveDataSpaceId::SdCardSystem ||
+ parameters.save_data_space_id == FileSys::SaveDataSpaceId::SdCardUser) {
+ id = FileSys::StorageId::SdCard;
+ } else {
+ id = FileSys::StorageId::NandSystem;
+ }
+
+ IFileSystem filesystem(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id));
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
@@ -812,7 +862,7 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext&
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
- rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space));
+ rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space, fsc));
}
void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
@@ -836,7 +886,7 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called");
- auto romfs = OpenRomFSCurrentProcess();
+ auto romfs = fsc.OpenRomFSCurrentProcess();
if (romfs.Failed()) {
// TODO (bunnei): Find the right error code to use here
LOG_CRITICAL(Service_FS, "no file system interface available!");
@@ -861,7 +911,7 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
static_cast<u8>(storage_id), unknown, title_id);
- auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
+ auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
if (data.Failed()) {
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 {
class FSP_SRV final : public ServiceFramework<FSP_SRV> {
public:
- explicit FSP_SRV(const Core::Reporter& reporter);
+ explicit FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter);
~FSP_SRV() override;
private:
@@ -51,6 +51,8 @@ private:
void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx);
+ FileSystemController& fsc;
+
FileSys::VirtualFile romfs;
u64 current_process_id = 0;
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:
}
};
-void InstallInterfaces(SM::ServiceManager& service_manager) {
+void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSystemController& fsc) {
std::make_shared<NS>("ns:am2")->InstallAsService(service_manager);
std::make_shared<NS>("ns:ec")->InstallAsService(service_manager);
std::make_shared<NS>("ns:rid")->InstallAsService(service_manager);
@@ -628,7 +628,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
std::make_shared<NS_SU>()->InstallAsService(service_manager);
std::make_shared<NS_VM>()->InstallAsService(service_manager);
- std::make_shared<PL_U>()->InstallAsService(service_manager);
+ std::make_shared<PL_U>(fsc)->InstallAsService(service_manager);
}
} // 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 @@
#include "core/hle/service/service.h"
-namespace Service::NS {
+namespace Service {
+
+namespace FileSystem {
+class FileSystemController;
+} // namespace FileSystem
+
+namespace NS {
class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> {
public:
@@ -91,6 +97,8 @@ private:
};
/// Registers all NS services with the specified service manager.
-void InstallInterfaces(SM::ServiceManager& service_manager);
+void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSystemController& fsc);
+
+} // namespace NS
-} // namespace Service::NS
+} // 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 {
std::vector<FontRegion> shared_font_regions;
};
-PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
+PL_U::PL_U(FileSystem::FileSystemController& fsc)
+ : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
static const FunctionInfo functions[] = {
{0, &PL_U::RequestLoad, "RequestLoad"},
{1, &PL_U::GetLoadState, "GetLoadState"},
@@ -161,7 +162,7 @@ PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
};
RegisterHandlers(functions);
// Attempt to load shared font data from disk
- const auto* nand = FileSystem::GetSystemNANDContents();
+ const auto* nand = fsc.GetSystemNANDContents();
std::size_t offset = 0;
// Rebuild shared fonts from data ncas
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 @@
#include <memory>
#include "core/hle/service/service.h"
-namespace Service::NS {
+namespace Service {
+
+namespace FileSystem {
+class FileSystemController;
+} // namespace FileSystem
+
+namespace NS {
class PL_U final : public ServiceFramework<PL_U> {
public:
- PL_U();
+ PL_U(FileSystem::FileSystemController& fsc);
~PL_U() override;
private:
@@ -26,4 +32,6 @@ private:
std::unique_ptr<Impl> impl;
};
-} // namespace Service::NS
+} // namespace NS
+
+} // namespace Service
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 59cdcf165..906fdc415 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) {
// NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
// here and pass it into the respective InstallInterfaces functions.
auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming());
+ system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
SM::ServiceManager::InstallInterfaces(sm);
@@ -235,7 +236,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
NIFM::InstallInterfaces(*sm);
NIM::InstallInterfaces(*sm);
NPNS::InstallInterfaces(*sm);
- NS::InstallInterfaces(*sm);
+ NS::InstallInterfaces(*sm, system.GetFileSystemController());
Nvidia::InstallInterfaces(*sm, *nv_flinger, system);
PCIe::InstallInterfaces(*sm);
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 {
class System;
}
-namespace FileSys {
-class VfsFilesystem;
-}
-
namespace Kernel {
class ClientPort;
class ServerPort;
@@ -31,6 +27,10 @@ class HLERequestContext;
namespace Service {
+namespace FileSystem {
+class FileSystemController;
+} // namespace FileSystem
+
namespace SM {
class ServiceManager;
}
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 @@
#include "common/common_funcs.h"
#include "common/file_util.h"
#include "common/logging/log.h"
+#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
@@ -176,7 +177,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
// Register the RomFS if a ".romfs" file was found
if (romfs_iter != files.end() && *romfs_iter != nullptr) {
romfs = *romfs_iter;
- Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
+ Core::System::GetInstance().GetFileSystemController().RegisterRomFS(
+ std::make_unique<FileSys::RomFSFactory>(*this));
}
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 @@
#include "common/file_util.h"
#include "common/logging/log.h"
+#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/romfs_factory.h"
#include "core/hle/kernel/process.h"
@@ -57,7 +58,8 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process) {
}
if (nca->GetRomFS() != nullptr && nca->GetRomFS()->GetSize() > 0) {
- Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
+ Core::System::GetInstance().GetFileSystemController().RegisterRomFS(
+ std::make_unique<FileSys::RomFSFactory>(*this));
}
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 @@
#include "common/file_util.h"
#include "common/logging/log.h"
#include "common/swap.h"
+#include "core/core.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/vfs_offset.h"
@@ -214,7 +215,8 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process) {
}
if (romfs != nullptr) {
- Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
+ Core::System::GetInstance().GetFileSystemController().RegisterRomFS(
+ std::make_unique<FileSys::RomFSFactory>(*this));
}
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 @@
#include <vector>
#include "common/common_types.h"
+#include "core/core.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
@@ -105,7 +106,8 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process) {
FileSys::VirtualFile update_raw;
if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
- Service::FileSystem::SetPackedUpdate(std::move(update_raw));
+ Core::System::GetInstance().GetFileSystemController().SetPackedUpdate(
+ std::move(update_raw));
}
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 @@
#include <vector>
#include "common/common_types.h"
+#include "core/core.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
@@ -72,7 +73,8 @@ AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process) {
FileSys::VirtualFile update_raw;
if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
- Service::FileSystem::SetPackedUpdate(std::move(update_raw));
+ Core::System::GetInstance().GetFileSystemController().SetPackedUpdate(
+ std::move(update_raw));
}
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 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include "common/file_util.h"
#include "core/core.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/service/hid/hid.h"
@@ -97,8 +98,8 @@ void LogSettings() {
LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching);
LogSetting("Audio_OutputDevice", Settings::values.audio_device_id);
LogSetting("DataStorage_UseVirtualSd", Settings::values.use_virtual_sd);
- LogSetting("DataStorage_NandDir", Settings::values.nand_dir);
- LogSetting("DataStorage_SdmcDir", Settings::values.sdmc_dir);
+ LogSetting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
+ LogSetting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
LogSetting("Debugging_UseGdbstub", Settings::values.use_gdbstub);
LogSetting("Debugging_GdbstubPort", Settings::values.gdbstub_port);
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 {
u32 rotation_angle;
};
+enum class NANDTotalSize : u64 {
+ S29_1GB = 0x747C00000ULL,
+};
+
+enum class NANDUserSize : u64 {
+ S26GB = 0x680000000ULL,
+};
+
+enum class NANDSystemSize : u64 {
+ S2_5GB = 0xA0000000,
+};
+
+enum class SDMCSize : u64 {
+ S1GB = 0x40000000,
+ S2GB = 0x80000000,
+ S4GB = 0x100000000ULL,
+ S8GB = 0x200000000ULL,
+ S16GB = 0x400000000ULL,
+ S32GB = 0x800000000ULL,
+ S64GB = 0x1000000000ULL,
+ S128GB = 0x2000000000ULL,
+ S256GB = 0x4000000000ULL,
+ S1TB = 0x10000000000ULL,
+};
+
struct Values {
// System
bool use_docked_mode;
@@ -382,8 +407,13 @@ struct Values {
// Data Storage
bool use_virtual_sd;
- std::string nand_dir;
- std::string sdmc_dir;
+ bool gamecard_inserted;
+ bool gamecard_current_game;
+ std::string gamecard_path;
+ NANDTotalSize nand_total_size;
+ NANDSystemSize nand_system_size;
+ NANDUserSize nand_user_size;
+ SDMCSize sdmc_size;
// Renderer
float resolution_factor;