diff options
55 files changed, 1885 insertions, 265 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 | ||
| 590 | Service::FileSystem::FileSystemController& System::GetFileSystemController() { | ||
| 591 | return impl->fs_controller; | ||
| 592 | } | ||
| 593 | |||
| 594 | const Service::FileSystem::FileSystemController& System::GetFileSystemController() const { | ||
| 595 | return impl->fs_controller; | ||
| 596 | } | ||
| 597 | |||
| 574 | void System::RegisterContentProvider(FileSys::ContentProviderUnionSlot slot, | 598 | void 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 { | |||
| 47 | class Controller; | 47 | class Controller; |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | namespace FileSystem { | ||
| 51 | class FileSystemController; | ||
| 52 | } // namespace FileSystem | ||
| 53 | |||
| 50 | namespace Glue { | 54 | namespace Glue { |
| 51 | class ARPManager; | 55 | class 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 | ||
| 483 | FileSys::VirtualFile PartitionDataManager::GetDecryptedProdInfo() const { | ||
| 484 | return prodinfo_decrypted; | ||
| 485 | } | ||
| 486 | |||
| 483 | std::array<u8, 576> PartitionDataManager::GetETicketExtendedKek() const { | 487 | std::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 | ||
| 89 | private: | 90 | 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 @@ | |||
| 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 | ||
| 9 | namespace FileSys { | 13 | namespace 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 | ||
| 19 | BISFactory::~BISFactory() = default; | 27 | BISFactory::~BISFactory() = default; |
| 20 | 28 | ||
| 29 | VirtualDir BISFactory::GetSystemNANDContentDirectory() const { | ||
| 30 | return GetOrCreateDirectoryRelative(nand_root, "/system/Contents"); | ||
| 31 | } | ||
| 32 | |||
| 33 | VirtualDir BISFactory::GetUserNANDContentDirectory() const { | ||
| 34 | return GetOrCreateDirectoryRelative(nand_root, "/user/Contents"); | ||
| 35 | } | ||
| 36 | |||
| 21 | RegisteredCache* BISFactory::GetSystemNANDContents() const { | 37 | RegisteredCache* 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 | ||
| 45 | PlaceholderCache* BISFactory::GetSystemNANDPlaceholder() const { | ||
| 46 | return sysnand_placeholder.get(); | ||
| 47 | } | ||
| 48 | |||
| 49 | PlaceholderCache* BISFactory::GetUserNANDPlaceholder() const { | ||
| 50 | return usrnand_placeholder.get(); | ||
| 51 | } | ||
| 52 | |||
| 29 | VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const { | 53 | VirtualDir 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 | ||
| 66 | VirtualDir 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 | |||
| 81 | VirtualFile 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 | |||
| 107 | VirtualDir BISFactory::GetImageDirectory() const { | ||
| 108 | return GetOrCreateDirectoryRelative(nand_root, "/user/Album"); | ||
| 109 | } | ||
| 110 | |||
| 111 | u64 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 | |||
| 119 | u64 BISFactory::GetSystemNANDTotalSpace() const { | ||
| 120 | return static_cast<u64>(Settings::values.nand_system_size); | ||
| 121 | } | ||
| 122 | |||
| 123 | u64 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 | |||
| 131 | u64 BISFactory::GetUserNANDTotalSpace() const { | ||
| 132 | return static_cast<u64>(Settings::values.nand_user_size); | ||
| 133 | } | ||
| 134 | |||
| 135 | u64 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 | ||
| 11 | namespace FileSys { | 11 | namespace FileSys { |
| 12 | 12 | ||
| 13 | enum 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 | |||
| 13 | class RegisteredCache; | 30 | class RegisteredCache; |
| 31 | class 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 | |||
| 29 | private: | 64 | private: |
| 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 | ||
| 19 | namespace FileSys { | 22 | namespace FileSys { |
| 20 | 23 | ||
| 24 | constexpr u64 GAMECARD_CERTIFICATE_OFFSET = 0x7000; | ||
| 21 | constexpr std::array partition_names{ | 25 | constexpr 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 | ||
| 182 | VirtualDir 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 | |||
| 196 | std::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 | |||
| 178 | Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) { | 202 | Loader::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 | |||
| 109 | private: | 116 | private: |
| 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 | ||
| 531 | std::array<u8, 16> NCA::GetRightsId() const { | ||
| 532 | return header.rights_id; | ||
| 533 | } | ||
| 534 | |||
| 535 | u32 NCA::GetSDKVersion() const { | ||
| 536 | return header.sdk_version; | ||
| 537 | } | ||
| 538 | |||
| 531 | bool NCA::IsUpdate() const { | 539 | bool 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 | ||
| 259 | std::vector<CheatList> PatchManager::CreateCheatList(const Core::System& system, | 274 | std::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 | ||
| 286 | static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { | 307 | static 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 | ||
| 394 | std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames( | 416 | std::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) { | |||
| 48 | static bool FollowsNcaIdFormat(std::string_view name) { | 49 | static 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 | ||
| 54 | static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bool second_hex_upper, | 58 | static 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 | ||
| 134 | PlaceholderCache::PlaceholderCache(VirtualDir dir_) : dir(std::move(dir_)) {} | ||
| 135 | |||
| 136 | bool 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 | |||
| 160 | bool 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 | |||
| 178 | bool PlaceholderCache::Exists(const NcaID& id) const { | ||
| 179 | const auto path = GetRelativePathFromNcaID(id, false, true, false); | ||
| 180 | |||
| 181 | return dir->GetFileRelative(path) != nullptr; | ||
| 182 | } | ||
| 183 | |||
| 184 | bool 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 | |||
| 194 | bool 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 | |||
| 210 | bool PlaceholderCache::CleanAll() const { | ||
| 211 | return dir->GetParentDirectory()->CleanSubdirectoryRecursive(dir->GetName()); | ||
| 212 | } | ||
| 213 | |||
| 214 | std::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 | |||
| 235 | u64 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 | |||
| 245 | bool 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 | |||
| 255 | std::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 | |||
| 269 | NcaID 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 | |||
| 130 | VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, | 284 | VirtualFile 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 | ||
| 170 | VirtualFile RegisteredCache::GetFileAtID(NcaID id) const { | 324 | VirtualFile 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; | |||
| 25 | enum class TitleType : u8; | 25 | enum class TitleType : u8; |
| 26 | 26 | ||
| 27 | struct ContentRecord; | 27 | struct ContentRecord; |
| 28 | struct MetaRecord; | ||
| 29 | class RegisteredCache; | ||
| 28 | 30 | ||
| 29 | using NcaID = std::array<u8, 0x10>; | 31 | using NcaID = std::array<u8, 0x10>; |
| 30 | using ContentProviderParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>; | 32 | using 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 | ||
| 94 | class PlaceholderCache { | ||
| 95 | public: | ||
| 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 | |||
| 111 | private: | ||
| 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 | */ |
| 105 | class RegisteredCache : public ContentProvider { | 128 | class RegisteredCache : public ContentProvider { |
| 129 | friend class PlaceholderCache; | ||
| 130 | |||
| 106 | public: | 131 | public: |
| 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 | ||
| 37 | ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() { | 38 | ResultVal<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 | ||
| 46 | ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) { | 47 | ResultVal<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 | ||
| 39 | private: | 39 | private: |
| 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 | ||
| 16 | constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size"; | 16 | constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size"; |
| 17 | 17 | ||
| 18 | std::string SaveDataDescriptor::DebugInfo() const { | 18 | namespace { |
| 19 | return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, " | 19 | void 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 | |||
| 25 | SaveDataFactory::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 | |||
| 31 | SaveDataFactory::~SaveDataFactory() = default; | ||
| 32 | |||
| 33 | ResultVal<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 = | 57 | std::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. | 65 | SaveDataFactory::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); | 71 | SaveDataFactory::~SaveDataFactory() = default; |
| 72 | |||
| 73 | ResultVal<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 | |||
| 91 | ResultVal<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 | ||
| 154 | void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, | 168 | void 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 | ||
| 78 | private: | 80 | private: |
| 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 | ||
| 10 | namespace FileSys { | 11 | namespace 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 | ||
| 19 | SDMCFactory::~SDMCFactory() = default; | 22 | SDMCFactory::~SDMCFactory() = default; |
| 20 | 23 | ||
| 21 | ResultVal<VirtualDir> SDMCFactory::Open() { | 24 | ResultVal<VirtualDir> SDMCFactory::Open() const { |
| 22 | return MakeResult<VirtualDir>(dir); | 25 | return MakeResult<VirtualDir>(dir); |
| 23 | } | 26 | } |
| 24 | 27 | ||
| 28 | VirtualDir SDMCFactory::GetSDMCContentDirectory() const { | ||
| 29 | return GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents"); | ||
| 30 | } | ||
| 31 | |||
| 25 | RegisteredCache* SDMCFactory::GetSDMCContents() const { | 32 | RegisteredCache* SDMCFactory::GetSDMCContents() const { |
| 26 | return contents.get(); | 33 | return contents.get(); |
| 27 | } | 34 | } |
| 28 | 35 | ||
| 36 | PlaceholderCache* SDMCFactory::GetSDMCPlaceholder() const { | ||
| 37 | return placeholder.get(); | ||
| 38 | } | ||
| 39 | |||
| 40 | VirtualDir SDMCFactory::GetImageDirectory() const { | ||
| 41 | return GetOrCreateDirectoryRelative(dir, "/Nintendo/Album"); | ||
| 42 | } | ||
| 43 | |||
| 44 | u64 SDMCFactory::GetSDMCFreeSpace() const { | ||
| 45 | return GetSDMCTotalSpace() - dir->GetSize(); | ||
| 46 | } | ||
| 47 | |||
| 48 | u64 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 @@ | |||
| 11 | namespace FileSys { | 11 | namespace FileSys { |
| 12 | 12 | ||
| 13 | class RegisteredCache; | 13 | class RegisteredCache; |
| 14 | class PlaceholderCache; | ||
| 14 | 15 | ||
| 15 | /// File system interface to the SDCard archive | 16 | /// File system interface to the SDCard archive |
| 16 | class SDMCFactory { | 17 | class 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 | ||
| 24 | private: | 34 | private: |
| 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 | ||
| 249 | void NSP::ReadNCAs(const std::vector<VirtualFile>& files) { | 249 | void 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 | ||
| 1144 | void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { | 1144 | void 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 | ||
| 1154 | void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) { | 1162 | void 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 | ||
| 11 | namespace Service { | 11 | namespace Service { |
| 12 | namespace FileSystem { | ||
| 13 | class FileSystemController; | ||
| 14 | } | ||
| 15 | |||
| 12 | namespace NVFlinger { | 16 | namespace NVFlinger { |
| 13 | class NVFlinger; | 17 | class 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 | ||
| 11 | namespace Service { | 11 | namespace Service { |
| 12 | namespace FileSystem { | ||
| 13 | class FileSystemController; | ||
| 14 | } | ||
| 15 | |||
| 12 | namespace NVFlinger { | 16 | namespace NVFlinger { |
| 13 | class NVFlinger; | 17 | class 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 | ||
| 29 | namespace Service::FileSystem { | 31 | namespace 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. | ||
| 34 | constexpr 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) |
| 38 | constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000; | 35 | constexpr 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 | ||
| 229 | u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const { | ||
| 230 | if (backing->IsWritable()) | ||
| 231 | return EMULATED_SD_REPORTED_SIZE; | ||
| 232 | |||
| 233 | return 0; | ||
| 234 | } | ||
| 235 | |||
| 236 | ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType( | 226 | ResultVal<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 | /** | 244 | FileSystemController::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. | 246 | FileSystemController::~FileSystemController() = default; |
| 257 | */ | ||
| 258 | static std::unique_ptr<FileSys::RomFSFactory> romfs_factory; | ||
| 259 | static std::unique_ptr<FileSys::SaveDataFactory> save_data_factory; | ||
| 260 | static std::unique_ptr<FileSys::SDMCFactory> sdmc_factory; | ||
| 261 | static std::unique_ptr<FileSys::BISFactory> bis_factory; | ||
| 262 | 247 | ||
| 263 | ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) { | 248 | ResultCode 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 | ||
| 270 | ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory) { | 254 | ResultCode 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 | ||
| 277 | ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) { | 262 | ResultCode 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 | ||
| 284 | ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) { | 269 | ResultCode 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 | ||
| 291 | void SetPackedUpdate(FileSys::VirtualFile update_raw) { | 276 | void 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 | ||
| 300 | ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() { | 285 | ResultVal<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 | ||
| 311 | ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id, | 296 | ResultVal<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 | ||
| 324 | ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, | 309 | ResultVal<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 | |||
| 321 | ResultVal<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 | ||
| 336 | ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) { | 333 | ResultVal<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 | ||
| 346 | ResultVal<FileSys::VirtualDir> OpenSDMC() { | 344 | ResultVal<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 | ||
| 356 | FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id) { | 354 | ResultVal<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 | |||
| 370 | ResultVal<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 | |||
| 386 | u64 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 | |||
| 412 | u64 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 | |||
| 438 | FileSys::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 | ||
| 388 | void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, | 471 | void 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 | ||
| 394 | FileSys::RegisteredCache* GetSystemNANDContents() { | 477 | void 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 | |||
| 484 | FileSys::XCI* FileSystemController::GetGameCard() const { | ||
| 485 | return gamecard.get(); | ||
| 486 | } | ||
| 487 | |||
| 488 | FileSys::RegisteredCache* FileSystemController::GetGameCardContents() const { | ||
| 489 | return gamecard_registered.get(); | ||
| 490 | } | ||
| 491 | |||
| 492 | FileSys::PlaceholderCache* FileSystemController::GetGameCardPlaceholder() const { | ||
| 493 | return gamecard_placeholder.get(); | ||
| 494 | } | ||
| 495 | |||
| 496 | FileSys::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 | ||
| 403 | FileSys::RegisteredCache* GetUserNANDContents() { | 505 | FileSys::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 | ||
| 412 | FileSys::RegisteredCache* GetSDMCContents() { | 514 | FileSys::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 | ||
| 421 | FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) { | 523 | FileSys::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 | |||
| 532 | FileSys::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 | |||
| 541 | FileSys::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 | |||
| 550 | FileSys::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 | |||
| 570 | FileSys::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 | |||
| 590 | FileSys::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 | |||
| 599 | FileSys::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 | |||
| 608 | FileSys::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 | |||
| 617 | FileSys::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 | |||
| 626 | FileSys::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 | |||
| 635 | FileSys::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 | |||
| 648 | FileSys::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 | |||
| 659 | FileSys::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 | ||
| 430 | FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) { | 668 | FileSys::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 | ||
| 439 | void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { | 677 | void 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 | ||
| 475 | void InstallInterfaces(Core::System& system) { | 713 | void 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 { | |||
| 14 | class BISFactory; | 14 | class BISFactory; |
| 15 | class RegisteredCache; | 15 | class RegisteredCache; |
| 16 | class RegisteredCacheUnion; | 16 | class RegisteredCacheUnion; |
| 17 | class PlaceholderCache; | ||
| 17 | class RomFSFactory; | 18 | class RomFSFactory; |
| 18 | class SaveDataFactory; | 19 | class SaveDataFactory; |
| 19 | class SDMCFactory; | 20 | class SDMCFactory; |
| 21 | class XCI; | ||
| 20 | 22 | ||
| 23 | enum class BisPartitionId : u32; | ||
| 21 | enum class ContentRecordType : u8; | 24 | enum class ContentRecordType : u8; |
| 22 | enum class Mode : u32; | 25 | enum class Mode : u32; |
| 23 | enum class SaveDataSpaceId : u8; | 26 | enum class SaveDataSpaceId : u8; |
| @@ -36,34 +39,91 @@ class ServiceManager; | |||
| 36 | 39 | ||
| 37 | namespace FileSystem { | 40 | namespace FileSystem { |
| 38 | 41 | ||
| 39 | ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory); | 42 | enum class ContentStorageId : u32 { |
| 40 | ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory); | 43 | System, |
| 41 | ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory); | 44 | User, |
| 42 | ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory); | 45 | SdCard, |
| 43 | 46 | }; | |
| 44 | void SetPackedUpdate(FileSys::VirtualFile update_raw); | ||
| 45 | ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess(); | ||
| 46 | ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id, | ||
| 47 | FileSys::ContentRecordType type); | ||
| 48 | ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, | ||
| 49 | const FileSys::SaveDataDescriptor& descriptor); | ||
| 50 | ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space); | ||
| 51 | ResultVal<FileSys::VirtualDir> OpenSDMC(); | ||
| 52 | |||
| 53 | FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id); | ||
| 54 | void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id, | ||
| 55 | FileSys::SaveDataSize new_value); | ||
| 56 | 47 | ||
| 57 | FileSys::RegisteredCache* GetSystemNANDContents(); | 48 | enum class ImageDirectoryId : u32 { |
| 58 | FileSys::RegisteredCache* GetUserNANDContents(); | 49 | NAND, |
| 59 | FileSys::RegisteredCache* GetSDMCContents(); | 50 | SdCard, |
| 51 | }; | ||
| 60 | 52 | ||
| 61 | FileSys::VirtualDir GetModificationLoadRoot(u64 title_id); | 53 | class FileSystemController { |
| 62 | FileSys::VirtualDir GetModificationDumpRoot(u64 title_id); | 54 | public: |
| 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 | 117 | private: |
| 65 | // above is called. | 118 | std::unique_ptr<FileSys::RomFSFactory> romfs_factory; |
| 66 | void 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 | ||
| 68 | void InstallInterfaces(Core::System& system); | 128 | void 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 | ||
| 31 | namespace Service::FileSystem { | 32 | namespace Service::FileSystem { |
| 32 | 33 | ||
| 34 | struct 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 | |||
| 33 | enum class FileSystemType : u8 { | 46 | enum class FileSystemType : u8 { |
| 34 | Invalid0 = 0, | 47 | Invalid0 = 0, |
| 35 | Invalid1 = 1, | 48 | Invalid1 = 1, |
| @@ -289,8 +302,8 @@ private: | |||
| 289 | 302 | ||
| 290 | class IFileSystem final : public ServiceFramework<IFileSystem> { | 303 | class IFileSystem final : public ServiceFramework<IFileSystem> { |
| 291 | public: | 304 | public: |
| 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 | |||
| 470 | private: | 499 | private: |
| 471 | VfsDirectoryServiceWrapper backend; | 500 | VfsDirectoryServiceWrapper backend; |
| 501 | SizeGetter size; | ||
| 472 | }; | 502 | }; |
| 473 | 503 | ||
| 474 | class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { | 504 | class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { |
| 475 | public: | 505 | public: |
| 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 | ||
| 617 | FSP_SRV::FSP_SRV(const Core::Reporter& reporter) : ServiceFramework("fsp-srv"), reporter(reporter) { | 653 | FSP_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) { | |||
| 754 | void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) { | 791 | void 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 | ||
| 818 | void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { | 868 | void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { |
| @@ -836,7 +886,7 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { | |||
| 836 | void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { | 886 | void 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 | ||
| 33 | class FSP_SRV final : public ServiceFramework<FSP_SRV> { | 33 | class FSP_SRV final : public ServiceFramework<FSP_SRV> { |
| 34 | public: | 34 | public: |
| 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 | ||
| 38 | private: | 38 | private: |
| @@ -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 | ||
| 620 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 620 | void 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 | ||
| 9 | namespace Service::NS { | 9 | namespace Service { |
| 10 | |||
| 11 | namespace FileSystem { | ||
| 12 | class FileSystemController; | ||
| 13 | } // namespace FileSystem | ||
| 14 | |||
| 15 | namespace NS { | ||
| 10 | 16 | ||
| 11 | class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> { | 17 | class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> { |
| 12 | public: | 18 | public: |
| @@ -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. |
| 94 | void InstallInterfaces(SM::ServiceManager& service_manager); | 100 | void 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 | ||
| 153 | PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} { | 153 | PL_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 | ||
| 10 | namespace Service::NS { | 10 | namespace Service { |
| 11 | |||
| 12 | namespace FileSystem { | ||
| 13 | class FileSystemController; | ||
| 14 | } // namespace FileSystem | ||
| 15 | |||
| 16 | namespace NS { | ||
| 11 | 17 | ||
| 12 | class PL_U final : public ServiceFramework<PL_U> { | 18 | class PL_U final : public ServiceFramework<PL_U> { |
| 13 | public: | 19 | public: |
| 14 | PL_U(); | 20 | PL_U(FileSystem::FileSystemController& fsc); |
| 15 | ~PL_U() override; | 21 | ~PL_U() override; |
| 16 | 22 | ||
| 17 | private: | 23 | private: |
| @@ -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 { | |||
| 18 | class System; | 18 | class System; |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | namespace FileSys { | ||
| 22 | class VfsFilesystem; | ||
| 23 | } | ||
| 24 | |||
| 25 | namespace Kernel { | 21 | namespace Kernel { |
| 26 | class ClientPort; | 22 | class ClientPort; |
| 27 | class ServerPort; | 23 | class ServerPort; |
| @@ -31,6 +27,10 @@ class HLERequestContext; | |||
| 31 | 27 | ||
| 32 | namespace Service { | 28 | namespace Service { |
| 33 | 29 | ||
| 30 | namespace FileSystem { | ||
| 31 | class FileSystemController; | ||
| 32 | } // namespace FileSystem | ||
| 33 | |||
| 34 | namespace SM { | 34 | namespace SM { |
| 35 | class ServiceManager; | 35 | class 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 | ||
| 349 | enum class NANDTotalSize : u64 { | ||
| 350 | S29_1GB = 0x747C00000ULL, | ||
| 351 | }; | ||
| 352 | |||
| 353 | enum class NANDUserSize : u64 { | ||
| 354 | S26GB = 0x680000000ULL, | ||
| 355 | }; | ||
| 356 | |||
| 357 | enum class NANDSystemSize : u64 { | ||
| 358 | S2_5GB = 0xA0000000, | ||
| 359 | }; | ||
| 360 | |||
| 361 | enum 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 | |||
| 349 | struct Values { | 374 | struct 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; |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index f051e17b4..dc6fa07fc 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -33,6 +33,9 @@ add_executable(yuzu | |||
| 33 | configuration/configure_debug.ui | 33 | configuration/configure_debug.ui |
| 34 | configuration/configure_dialog.cpp | 34 | configuration/configure_dialog.cpp |
| 35 | configuration/configure_dialog.h | 35 | configuration/configure_dialog.h |
| 36 | configuration/configure_filesystem.cpp | ||
| 37 | configuration/configure_filesystem.h | ||
| 38 | configuration/configure_filesystem.ui | ||
| 36 | configuration/configure_gamelist.cpp | 39 | configuration/configure_gamelist.cpp |
| 37 | configuration/configure_gamelist.h | 40 | configuration/configure_gamelist.h |
| 38 | configuration/configure_gamelist.ui | 41 | configuration/configure_gamelist.ui |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 3f54f54fb..92d9fb161 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -459,6 +459,49 @@ void Config::ReadDataStorageValues() { | |||
| 459 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir))) | 459 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir))) |
| 460 | .toString() | 460 | .toString() |
| 461 | .toStdString()); | 461 | .toStdString()); |
| 462 | FileUtil::GetUserPath( | ||
| 463 | FileUtil::UserPath::LoadDir, | ||
| 464 | qt_config | ||
| 465 | ->value(QStringLiteral("load_directory"), | ||
| 466 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir))) | ||
| 467 | .toString() | ||
| 468 | .toStdString()); | ||
| 469 | FileUtil::GetUserPath( | ||
| 470 | FileUtil::UserPath::DumpDir, | ||
| 471 | qt_config | ||
| 472 | ->value(QStringLiteral("dump_directory"), | ||
| 473 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir))) | ||
| 474 | .toString() | ||
| 475 | .toStdString()); | ||
| 476 | FileUtil::GetUserPath( | ||
| 477 | FileUtil::UserPath::CacheDir, | ||
| 478 | qt_config | ||
| 479 | ->value(QStringLiteral("cache_directory"), | ||
| 480 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir))) | ||
| 481 | .toString() | ||
| 482 | .toStdString()); | ||
| 483 | Settings::values.gamecard_inserted = | ||
| 484 | ReadSetting(QStringLiteral("gamecard_inserted"), false).toBool(); | ||
| 485 | Settings::values.gamecard_current_game = | ||
| 486 | ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool(); | ||
| 487 | Settings::values.gamecard_path = | ||
| 488 | ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString(); | ||
| 489 | Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>( | ||
| 490 | ReadSetting(QStringLiteral("nand_total_size"), | ||
| 491 | QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB))) | ||
| 492 | .toULongLong()); | ||
| 493 | Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>( | ||
| 494 | ReadSetting(QStringLiteral("nand_user_size"), | ||
| 495 | QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB))) | ||
| 496 | .toULongLong()); | ||
| 497 | Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>( | ||
| 498 | ReadSetting(QStringLiteral("nand_system_size"), | ||
| 499 | QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB))) | ||
| 500 | .toULongLong()); | ||
| 501 | Settings::values.sdmc_size = static_cast<Settings::SDMCSize>( | ||
| 502 | ReadSetting(QStringLiteral("sdmc_size"), | ||
| 503 | QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB))) | ||
| 504 | .toULongLong()); | ||
| 462 | 505 | ||
| 463 | qt_config->endGroup(); | 506 | qt_config->endGroup(); |
| 464 | } | 507 | } |
| @@ -875,7 +918,32 @@ void Config::SaveDataStorageValues() { | |||
| 875 | WriteSetting(QStringLiteral("sdmc_directory"), | 918 | WriteSetting(QStringLiteral("sdmc_directory"), |
| 876 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)), | 919 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)), |
| 877 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir))); | 920 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir))); |
| 878 | 921 | WriteSetting(QStringLiteral("load_directory"), | |
| 922 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir)), | ||
| 923 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir))); | ||
| 924 | WriteSetting(QStringLiteral("dump_directory"), | ||
| 925 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir)), | ||
| 926 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir))); | ||
| 927 | WriteSetting(QStringLiteral("cache_directory"), | ||
| 928 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir)), | ||
| 929 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir))); | ||
| 930 | WriteSetting(QStringLiteral("gamecard_inserted"), Settings::values.gamecard_inserted, false); | ||
| 931 | WriteSetting(QStringLiteral("gamecard_current_game"), Settings::values.gamecard_current_game, | ||
| 932 | false); | ||
| 933 | WriteSetting(QStringLiteral("gamecard_path"), | ||
| 934 | QString::fromStdString(Settings::values.gamecard_path), QStringLiteral("")); | ||
| 935 | WriteSetting(QStringLiteral("nand_total_size"), | ||
| 936 | QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_total_size)), | ||
| 937 | QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB))); | ||
| 938 | WriteSetting(QStringLiteral("nand_user_size"), | ||
| 939 | QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_user_size)), | ||
| 940 | QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB))); | ||
| 941 | WriteSetting(QStringLiteral("nand_system_size"), | ||
| 942 | QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_system_size)), | ||
| 943 | QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB))); | ||
| 944 | WriteSetting(QStringLiteral("sdmc_size"), | ||
| 945 | QVariant::fromValue<u64>(static_cast<u64>(Settings::values.sdmc_size)), | ||
| 946 | QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB))); | ||
| 879 | qt_config->endGroup(); | 947 | qt_config->endGroup(); |
| 880 | } | 948 | } |
| 881 | 949 | ||
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index 267717bc9..49fadd0ef 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui | |||
| @@ -63,6 +63,11 @@ | |||
| 63 | <string>Profiles</string> | 63 | <string>Profiles</string> |
| 64 | </attribute> | 64 | </attribute> |
| 65 | </widget> | 65 | </widget> |
| 66 | <widget class="ConfigureFilesystem" name="filesystemTab"> | ||
| 67 | <attribute name="title"> | ||
| 68 | <string>Filesystem</string> | ||
| 69 | </attribute> | ||
| 70 | </widget> | ||
| 66 | <widget class="ConfigureInputSimple" name="inputTab"> | 71 | <widget class="ConfigureInputSimple" name="inputTab"> |
| 67 | <attribute name="title"> | 72 | <attribute name="title"> |
| 68 | <string>Input</string> | 73 | <string>Input</string> |
| @@ -126,6 +131,12 @@ | |||
| 126 | <container>1</container> | 131 | <container>1</container> |
| 127 | </customwidget> | 132 | </customwidget> |
| 128 | <customwidget> | 133 | <customwidget> |
| 134 | <class>ConfigureFilesystem</class> | ||
| 135 | <extends>QWidget</extends> | ||
| 136 | <header>configuration/configure_filesystem.h</header> | ||
| 137 | <container>1</container> | ||
| 138 | </customwidget> | ||
| 139 | <customwidget> | ||
| 129 | <class>ConfigureAudio</class> | 140 | <class>ConfigureAudio</class> |
| 130 | <extends>QWidget</extends> | 141 | <extends>QWidget</extends> |
| 131 | <header>configuration/configure_audio.h</header> | 142 | <header>configuration/configure_audio.h</header> |
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index 5b7e03056..90c1f9459 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp | |||
| @@ -34,8 +34,6 @@ void ConfigureDebug::SetConfiguration() { | |||
| 34 | ui->toggle_console->setChecked(UISettings::values.show_console); | 34 | ui->toggle_console->setChecked(UISettings::values.show_console); |
| 35 | ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter)); | 35 | ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter)); |
| 36 | ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); | 36 | ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); |
| 37 | ui->dump_exefs->setChecked(Settings::values.dump_exefs); | ||
| 38 | ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso); | ||
| 39 | ui->reporting_services->setChecked(Settings::values.reporting_services); | 37 | ui->reporting_services->setChecked(Settings::values.reporting_services); |
| 40 | ui->quest_flag->setChecked(Settings::values.quest_flag); | 38 | ui->quest_flag->setChecked(Settings::values.quest_flag); |
| 41 | } | 39 | } |
| @@ -46,8 +44,6 @@ void ConfigureDebug::ApplyConfiguration() { | |||
| 46 | UISettings::values.show_console = ui->toggle_console->isChecked(); | 44 | UISettings::values.show_console = ui->toggle_console->isChecked(); |
| 47 | Settings::values.log_filter = ui->log_filter_edit->text().toStdString(); | 45 | Settings::values.log_filter = ui->log_filter_edit->text().toStdString(); |
| 48 | Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); | 46 | Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); |
| 49 | Settings::values.dump_exefs = ui->dump_exefs->isChecked(); | ||
| 50 | Settings::values.dump_nso = ui->dump_decompressed_nso->isChecked(); | ||
| 51 | Settings::values.reporting_services = ui->reporting_services->isChecked(); | 47 | Settings::values.reporting_services = ui->reporting_services->isChecked(); |
| 52 | Settings::values.quest_flag = ui->quest_flag->isChecked(); | 48 | Settings::values.quest_flag = ui->quest_flag->isChecked(); |
| 53 | Debugger::ToggleConsole(); | 49 | Debugger::ToggleConsole(); |
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index 7e109cef0..ce49569bb 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui | |||
| @@ -103,58 +103,6 @@ | |||
| 103 | </item> | 103 | </item> |
| 104 | </layout> | 104 | </layout> |
| 105 | </item> | 105 | </item> |
| 106 | </layout> | ||
| 107 | </widget> | ||
| 108 | </item> | ||
| 109 | <item> | ||
| 110 | <widget class="QGroupBox" name="groupBox_3"> | ||
| 111 | <property name="title"> | ||
| 112 | <string>Homebrew</string> | ||
| 113 | </property> | ||
| 114 | <layout class="QVBoxLayout" name="verticalLayout_5"> | ||
| 115 | <item> | ||
| 116 | <layout class="QHBoxLayout" name="horizontalLayout_4"> | ||
| 117 | <item> | ||
| 118 | <widget class="QLabel" name="label_3"> | ||
| 119 | <property name="text"> | ||
| 120 | <string>Arguments String</string> | ||
| 121 | </property> | ||
| 122 | </widget> | ||
| 123 | </item> | ||
| 124 | <item> | ||
| 125 | <widget class="QLineEdit" name="homebrew_args_edit"/> | ||
| 126 | </item> | ||
| 127 | </layout> | ||
| 128 | </item> | ||
| 129 | </layout> | ||
| 130 | </widget> | ||
| 131 | </item> | ||
| 132 | <item> | ||
| 133 | <widget class="QGroupBox" name="groupBox_4"> | ||
| 134 | <property name="title"> | ||
| 135 | <string>Dump</string> | ||
| 136 | </property> | ||
| 137 | <layout class="QVBoxLayout" name="verticalLayout_6"> | ||
| 138 | <item> | ||
| 139 | <widget class="QCheckBox" name="dump_decompressed_nso"> | ||
| 140 | <property name="whatsThis"> | ||
| 141 | <string>When checked, any NSO yuzu tries to load or patch will be copied decompressed to the yuzu/dump directory.</string> | ||
| 142 | </property> | ||
| 143 | <property name="text"> | ||
| 144 | <string>Dump Decompressed NSOs</string> | ||
| 145 | </property> | ||
| 146 | </widget> | ||
| 147 | </item> | ||
| 148 | <item> | ||
| 149 | <widget class="QCheckBox" name="dump_exefs"> | ||
| 150 | <property name="whatsThis"> | ||
| 151 | <string>When checked, any game that yuzu loads will have its ExeFS dumped to the yuzu/dump directory.</string> | ||
| 152 | </property> | ||
| 153 | <property name="text"> | ||
| 154 | <string>Dump ExeFS</string> | ||
| 155 | </property> | ||
| 156 | </widget> | ||
| 157 | </item> | ||
| 158 | <item> | 106 | <item> |
| 159 | <widget class="QCheckBox" name="reporting_services"> | 107 | <widget class="QCheckBox" name="reporting_services"> |
| 160 | <property name="text"> | 108 | <property name="text"> |
| @@ -163,7 +111,7 @@ | |||
| 163 | </widget> | 111 | </widget> |
| 164 | </item> | 112 | </item> |
| 165 | <item> | 113 | <item> |
| 166 | <widget class="QLabel" name="label_3"> | 114 | <widget class="QLabel" name="label"> |
| 167 | <property name="font"> | 115 | <property name="font"> |
| 168 | <font> | 116 | <font> |
| 169 | <italic>true</italic> | 117 | <italic>true</italic> |
| @@ -197,10 +145,36 @@ | |||
| 197 | </widget> | 145 | </widget> |
| 198 | </item> | 146 | </item> |
| 199 | <item> | 147 | <item> |
| 148 | <widget class="QGroupBox" name="groupBox_3"> | ||
| 149 | <property name="title"> | ||
| 150 | <string>Homebrew</string> | ||
| 151 | </property> | ||
| 152 | <layout class="QVBoxLayout" name="verticalLayout_5"> | ||
| 153 | <item> | ||
| 154 | <layout class="QHBoxLayout" name="horizontalLayout_4"> | ||
| 155 | <item> | ||
| 156 | <widget class="QLabel" name="label_3"> | ||
| 157 | <property name="text"> | ||
| 158 | <string>Arguments String</string> | ||
| 159 | </property> | ||
| 160 | </widget> | ||
| 161 | </item> | ||
| 162 | <item> | ||
| 163 | <widget class="QLineEdit" name="homebrew_args_edit"/> | ||
| 164 | </item> | ||
| 165 | </layout> | ||
| 166 | </item> | ||
| 167 | </layout> | ||
| 168 | </widget> | ||
| 169 | </item> | ||
| 170 | <item> | ||
| 200 | <spacer name="verticalSpacer"> | 171 | <spacer name="verticalSpacer"> |
| 201 | <property name="orientation"> | 172 | <property name="orientation"> |
| 202 | <enum>Qt::Vertical</enum> | 173 | <enum>Qt::Vertical</enum> |
| 203 | </property> | 174 | </property> |
| 175 | <property name="sizeType"> | ||
| 176 | <enum>QSizePolicy::Expanding</enum> | ||
| 177 | </property> | ||
| 204 | <property name="sizeHint" stdset="0"> | 178 | <property name="sizeHint" stdset="0"> |
| 205 | <size> | 179 | <size> |
| 206 | <width>20</width> | 180 | <width>20</width> |
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 775e3f2ea..7c875ae87 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp | |||
| @@ -37,6 +37,7 @@ void ConfigureDialog::ApplyConfiguration() { | |||
| 37 | ui->gameListTab->ApplyConfiguration(); | 37 | ui->gameListTab->ApplyConfiguration(); |
| 38 | ui->systemTab->ApplyConfiguration(); | 38 | ui->systemTab->ApplyConfiguration(); |
| 39 | ui->profileManagerTab->ApplyConfiguration(); | 39 | ui->profileManagerTab->ApplyConfiguration(); |
| 40 | ui->filesystemTab->applyConfiguration(); | ||
| 40 | ui->inputTab->ApplyConfiguration(); | 41 | ui->inputTab->ApplyConfiguration(); |
| 41 | ui->hotkeysTab->ApplyConfiguration(registry); | 42 | ui->hotkeysTab->ApplyConfiguration(registry); |
| 42 | ui->graphicsTab->ApplyConfiguration(); | 43 | ui->graphicsTab->ApplyConfiguration(); |
| @@ -73,7 +74,7 @@ Q_DECLARE_METATYPE(QList<QWidget*>); | |||
| 73 | void ConfigureDialog::PopulateSelectionList() { | 74 | void ConfigureDialog::PopulateSelectionList() { |
| 74 | const std::array<std::pair<QString, QList<QWidget*>>, 4> items{ | 75 | const std::array<std::pair<QString, QList<QWidget*>>, 4> items{ |
| 75 | {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->gameListTab}}, | 76 | {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->gameListTab}}, |
| 76 | {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->audioTab}}, | 77 | {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->filesystemTab, ui->audioTab}}, |
| 77 | {tr("Graphics"), {ui->graphicsTab}}, | 78 | {tr("Graphics"), {ui->graphicsTab}}, |
| 78 | {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}, | 79 | {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}, |
| 79 | }; | 80 | }; |
| @@ -106,6 +107,7 @@ void ConfigureDialog::UpdateVisibleTabs() { | |||
| 106 | {ui->debugTab, tr("Debug")}, | 107 | {ui->debugTab, tr("Debug")}, |
| 107 | {ui->webTab, tr("Web")}, | 108 | {ui->webTab, tr("Web")}, |
| 108 | {ui->gameListTab, tr("Game List")}, | 109 | {ui->gameListTab, tr("Game List")}, |
| 110 | {ui->filesystemTab, tr("Filesystem")}, | ||
| 109 | }; | 111 | }; |
| 110 | 112 | ||
| 111 | [[maybe_unused]] const QSignalBlocker blocker(ui->tabWidget); | 113 | [[maybe_unused]] const QSignalBlocker blocker(ui->tabWidget); |
diff --git a/src/yuzu/configuration/configure_filesystem.cpp b/src/yuzu/configuration/configure_filesystem.cpp new file mode 100644 index 000000000..29f540eb7 --- /dev/null +++ b/src/yuzu/configuration/configure_filesystem.cpp | |||
| @@ -0,0 +1,177 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <QFileDialog> | ||
| 6 | #include <QMessageBox> | ||
| 7 | #include "common/common_paths.h" | ||
| 8 | #include "common/file_util.h" | ||
| 9 | #include "core/settings.h" | ||
| 10 | #include "ui_configure_filesystem.h" | ||
| 11 | #include "yuzu/configuration/configure_filesystem.h" | ||
| 12 | #include "yuzu/uisettings.h" | ||
| 13 | |||
| 14 | namespace { | ||
| 15 | |||
| 16 | template <typename T> | ||
| 17 | void SetComboBoxFromData(QComboBox* combo_box, T data) { | ||
| 18 | const auto index = combo_box->findData(QVariant::fromValue(static_cast<u64>(data))); | ||
| 19 | if (index >= combo_box->count() || index < 0) | ||
| 20 | return; | ||
| 21 | |||
| 22 | combo_box->setCurrentIndex(index); | ||
| 23 | } | ||
| 24 | |||
| 25 | } // Anonymous namespace | ||
| 26 | |||
| 27 | ConfigureFilesystem::ConfigureFilesystem(QWidget* parent) | ||
| 28 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureFilesystem>()) { | ||
| 29 | ui->setupUi(this); | ||
| 30 | this->setConfiguration(); | ||
| 31 | |||
| 32 | connect(ui->nand_directory_button, &QToolButton::pressed, this, | ||
| 33 | [this] { SetDirectory(DirectoryTarget::NAND, ui->nand_directory_edit); }); | ||
| 34 | connect(ui->sdmc_directory_button, &QToolButton::pressed, this, | ||
| 35 | [this] { SetDirectory(DirectoryTarget::SD, ui->sdmc_directory_edit); }); | ||
| 36 | connect(ui->gamecard_path_button, &QToolButton::pressed, this, | ||
| 37 | [this] { SetDirectory(DirectoryTarget::Gamecard, ui->gamecard_path_edit); }); | ||
| 38 | connect(ui->dump_path_button, &QToolButton::pressed, this, | ||
| 39 | [this] { SetDirectory(DirectoryTarget::Dump, ui->dump_path_edit); }); | ||
| 40 | connect(ui->load_path_button, &QToolButton::pressed, this, | ||
| 41 | [this] { SetDirectory(DirectoryTarget::Load, ui->load_path_edit); }); | ||
| 42 | connect(ui->cache_directory_button, &QToolButton::pressed, this, | ||
| 43 | [this] { SetDirectory(DirectoryTarget::Cache, ui->cache_directory_edit); }); | ||
| 44 | |||
| 45 | connect(ui->reset_game_list_cache, &QPushButton::pressed, this, | ||
| 46 | &ConfigureFilesystem::ResetMetadata); | ||
| 47 | |||
| 48 | connect(ui->gamecard_inserted, &QCheckBox::stateChanged, this, | ||
| 49 | &ConfigureFilesystem::UpdateEnabledControls); | ||
| 50 | connect(ui->gamecard_current_game, &QCheckBox::stateChanged, this, | ||
| 51 | &ConfigureFilesystem::UpdateEnabledControls); | ||
| 52 | } | ||
| 53 | |||
| 54 | ConfigureFilesystem::~ConfigureFilesystem() = default; | ||
| 55 | |||
| 56 | void ConfigureFilesystem::setConfiguration() { | ||
| 57 | ui->nand_directory_edit->setText( | ||
| 58 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir))); | ||
| 59 | ui->sdmc_directory_edit->setText( | ||
| 60 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir))); | ||
| 61 | ui->gamecard_path_edit->setText(QString::fromStdString(Settings::values.gamecard_path)); | ||
| 62 | ui->dump_path_edit->setText( | ||
| 63 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir))); | ||
| 64 | ui->load_path_edit->setText( | ||
| 65 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir))); | ||
| 66 | ui->cache_directory_edit->setText( | ||
| 67 | QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir))); | ||
| 68 | |||
| 69 | ui->gamecard_inserted->setChecked(Settings::values.gamecard_inserted); | ||
| 70 | ui->gamecard_current_game->setChecked(Settings::values.gamecard_current_game); | ||
| 71 | ui->dump_exefs->setChecked(Settings::values.dump_exefs); | ||
| 72 | ui->dump_nso->setChecked(Settings::values.dump_nso); | ||
| 73 | |||
| 74 | ui->cache_game_list->setChecked(UISettings::values.cache_game_list); | ||
| 75 | |||
| 76 | SetComboBoxFromData(ui->nand_size, Settings::values.nand_total_size); | ||
| 77 | SetComboBoxFromData(ui->usrnand_size, Settings::values.nand_user_size); | ||
| 78 | SetComboBoxFromData(ui->sysnand_size, Settings::values.nand_system_size); | ||
| 79 | SetComboBoxFromData(ui->sdmc_size, Settings::values.sdmc_size); | ||
| 80 | |||
| 81 | UpdateEnabledControls(); | ||
| 82 | } | ||
| 83 | |||
| 84 | void ConfigureFilesystem::applyConfiguration() { | ||
| 85 | FileUtil::GetUserPath(FileUtil::UserPath::NANDDir, | ||
| 86 | ui->nand_directory_edit->text().toStdString()); | ||
| 87 | FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir, | ||
| 88 | ui->sdmc_directory_edit->text().toStdString()); | ||
| 89 | FileUtil::GetUserPath(FileUtil::UserPath::DumpDir, ui->dump_path_edit->text().toStdString()); | ||
| 90 | FileUtil::GetUserPath(FileUtil::UserPath::LoadDir, ui->load_path_edit->text().toStdString()); | ||
| 91 | FileUtil::GetUserPath(FileUtil::UserPath::CacheDir, | ||
| 92 | ui->cache_directory_edit->text().toStdString()); | ||
| 93 | Settings::values.gamecard_path = ui->gamecard_path_edit->text().toStdString(); | ||
| 94 | |||
| 95 | Settings::values.gamecard_inserted = ui->gamecard_inserted->isChecked(); | ||
| 96 | Settings::values.gamecard_current_game = ui->gamecard_current_game->isChecked(); | ||
| 97 | Settings::values.dump_exefs = ui->dump_exefs->isChecked(); | ||
| 98 | Settings::values.dump_nso = ui->dump_nso->isChecked(); | ||
| 99 | |||
| 100 | UISettings::values.cache_game_list = ui->cache_game_list->isChecked(); | ||
| 101 | |||
| 102 | Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>( | ||
| 103 | ui->nand_size->itemData(ui->nand_size->currentIndex()).toULongLong()); | ||
| 104 | Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>( | ||
| 105 | ui->nand_size->itemData(ui->sysnand_size->currentIndex()).toULongLong()); | ||
| 106 | Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>( | ||
| 107 | ui->nand_size->itemData(ui->usrnand_size->currentIndex()).toULongLong()); | ||
| 108 | Settings::values.sdmc_size = static_cast<Settings::SDMCSize>( | ||
| 109 | ui->nand_size->itemData(ui->sdmc_size->currentIndex()).toULongLong()); | ||
| 110 | } | ||
| 111 | |||
| 112 | void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) { | ||
| 113 | QString caption; | ||
| 114 | |||
| 115 | switch (target) { | ||
| 116 | case DirectoryTarget::NAND: | ||
| 117 | caption = tr("Select Emulated NAND Directory..."); | ||
| 118 | break; | ||
| 119 | case DirectoryTarget::SD: | ||
| 120 | caption = tr("Select Emulated SD Directory..."); | ||
| 121 | break; | ||
| 122 | case DirectoryTarget::Gamecard: | ||
| 123 | caption = tr("Select Gamecard Path..."); | ||
| 124 | break; | ||
| 125 | case DirectoryTarget::Dump: | ||
| 126 | caption = tr("Select Dump Directory..."); | ||
| 127 | break; | ||
| 128 | case DirectoryTarget::Load: | ||
| 129 | caption = tr("Select Mod Load Directory..."); | ||
| 130 | break; | ||
| 131 | case DirectoryTarget::Cache: | ||
| 132 | caption = tr("Select Cache Directory..."); | ||
| 133 | break; | ||
| 134 | } | ||
| 135 | |||
| 136 | QString str; | ||
| 137 | if (target == DirectoryTarget::Gamecard) { | ||
| 138 | str = QFileDialog::getOpenFileName(this, caption, QFileInfo(edit->text()).dir().path(), | ||
| 139 | QStringLiteral("NX Gamecard;*.xci")); | ||
| 140 | } else { | ||
| 141 | str = QFileDialog::getExistingDirectory(this, caption, edit->text()); | ||
| 142 | } | ||
| 143 | |||
| 144 | if (str.isEmpty()) | ||
| 145 | return; | ||
| 146 | |||
| 147 | edit->setText(str); | ||
| 148 | } | ||
| 149 | |||
| 150 | void ConfigureFilesystem::ResetMetadata() { | ||
| 151 | if (!FileUtil::Exists(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP + | ||
| 152 | "game_list")) { | ||
| 153 | QMessageBox::information(this, tr("Reset Metadata Cache"), | ||
| 154 | tr("The metadata cache is already empty.")); | ||
| 155 | } else if (FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + | ||
| 156 | DIR_SEP + "game_list")) { | ||
| 157 | QMessageBox::information(this, tr("Reset Metadata Cache"), | ||
| 158 | tr("The operation completed successfully.")); | ||
| 159 | UISettings::values.is_game_list_reload_pending.exchange(true); | ||
| 160 | } else { | ||
| 161 | QMessageBox::warning( | ||
| 162 | this, tr("Reset Metadata Cache"), | ||
| 163 | tr("The metadata cache couldn't be deleted. It might be in use or non-existent.")); | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | void ConfigureFilesystem::UpdateEnabledControls() { | ||
| 168 | ui->gamecard_current_game->setEnabled(ui->gamecard_inserted->isChecked()); | ||
| 169 | ui->gamecard_path_edit->setEnabled(ui->gamecard_inserted->isChecked() && | ||
| 170 | !ui->gamecard_current_game->isChecked()); | ||
| 171 | ui->gamecard_path_button->setEnabled(ui->gamecard_inserted->isChecked() && | ||
| 172 | !ui->gamecard_current_game->isChecked()); | ||
| 173 | } | ||
| 174 | |||
| 175 | void ConfigureFilesystem::retranslateUi() { | ||
| 176 | ui->retranslateUi(this); | ||
| 177 | } | ||
diff --git a/src/yuzu/configuration/configure_filesystem.h b/src/yuzu/configuration/configure_filesystem.h new file mode 100644 index 000000000..a79303760 --- /dev/null +++ b/src/yuzu/configuration/configure_filesystem.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | // Copyright 2019 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <QWidget> | ||
| 9 | |||
| 10 | class QLineEdit; | ||
| 11 | |||
| 12 | namespace Ui { | ||
| 13 | class ConfigureFilesystem; | ||
| 14 | } | ||
| 15 | |||
| 16 | class ConfigureFilesystem : public QWidget { | ||
| 17 | Q_OBJECT | ||
| 18 | |||
| 19 | public: | ||
| 20 | explicit ConfigureFilesystem(QWidget* parent = nullptr); | ||
| 21 | ~ConfigureFilesystem() override; | ||
| 22 | |||
| 23 | void applyConfiguration(); | ||
| 24 | void retranslateUi(); | ||
| 25 | |||
| 26 | private: | ||
| 27 | void setConfiguration(); | ||
| 28 | |||
| 29 | enum class DirectoryTarget { | ||
| 30 | NAND, | ||
| 31 | SD, | ||
| 32 | Gamecard, | ||
| 33 | Dump, | ||
| 34 | Load, | ||
| 35 | Cache, | ||
| 36 | }; | ||
| 37 | |||
| 38 | void SetDirectory(DirectoryTarget target, QLineEdit* edit); | ||
| 39 | void ResetMetadata(); | ||
| 40 | void UpdateEnabledControls(); | ||
| 41 | |||
| 42 | std::unique_ptr<Ui::ConfigureFilesystem> ui; | ||
| 43 | }; | ||
diff --git a/src/yuzu/configuration/configure_filesystem.ui b/src/yuzu/configuration/configure_filesystem.ui new file mode 100644 index 000000000..58cd07f52 --- /dev/null +++ b/src/yuzu/configuration/configure_filesystem.ui | |||
| @@ -0,0 +1,395 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>ConfigureFilesystem</class> | ||
| 4 | <widget class="QWidget" name="ConfigureFilesystem"> | ||
| 5 | <property name="geometry"> | ||
| 6 | <rect> | ||
| 7 | <x>0</x> | ||
| 8 | <y>0</y> | ||
| 9 | <width>453</width> | ||
| 10 | <height>561</height> | ||
| 11 | </rect> | ||
| 12 | </property> | ||
| 13 | <property name="windowTitle"> | ||
| 14 | <string>Form</string> | ||
| 15 | </property> | ||
| 16 | <layout class="QVBoxLayout" name="verticalLayout"> | ||
| 17 | <item> | ||
| 18 | <layout class="QVBoxLayout" name="verticalLayout_3"> | ||
| 19 | <item> | ||
| 20 | <widget class="QGroupBox" name="groupBox"> | ||
| 21 | <property name="title"> | ||
| 22 | <string>Storage Directories</string> | ||
| 23 | </property> | ||
| 24 | <layout class="QGridLayout" name="gridLayout"> | ||
| 25 | <item row="0" column="0"> | ||
| 26 | <widget class="QLabel" name="label"> | ||
| 27 | <property name="text"> | ||
| 28 | <string>NAND</string> | ||
| 29 | </property> | ||
| 30 | </widget> | ||
| 31 | </item> | ||
| 32 | <item row="0" column="3"> | ||
| 33 | <widget class="QToolButton" name="nand_directory_button"> | ||
| 34 | <property name="text"> | ||
| 35 | <string>...</string> | ||
| 36 | </property> | ||
| 37 | </widget> | ||
| 38 | </item> | ||
| 39 | <item row="0" column="2"> | ||
| 40 | <widget class="QLineEdit" name="nand_directory_edit"/> | ||
| 41 | </item> | ||
| 42 | <item row="1" column="2"> | ||
| 43 | <widget class="QLineEdit" name="sdmc_directory_edit"/> | ||
| 44 | </item> | ||
| 45 | <item row="1" column="0"> | ||
| 46 | <widget class="QLabel" name="label_2"> | ||
| 47 | <property name="text"> | ||
| 48 | <string>SD Card</string> | ||
| 49 | </property> | ||
| 50 | </widget> | ||
| 51 | </item> | ||
| 52 | <item row="1" column="3"> | ||
| 53 | <widget class="QToolButton" name="sdmc_directory_button"> | ||
| 54 | <property name="text"> | ||
| 55 | <string>...</string> | ||
| 56 | </property> | ||
| 57 | </widget> | ||
| 58 | </item> | ||
| 59 | <item row="0" column="1"> | ||
| 60 | <spacer name="horizontalSpacer"> | ||
| 61 | <property name="orientation"> | ||
| 62 | <enum>Qt::Horizontal</enum> | ||
| 63 | </property> | ||
| 64 | <property name="sizeType"> | ||
| 65 | <enum>QSizePolicy::Maximum</enum> | ||
| 66 | </property> | ||
| 67 | <property name="sizeHint" stdset="0"> | ||
| 68 | <size> | ||
| 69 | <width>60</width> | ||
| 70 | <height>20</height> | ||
| 71 | </size> | ||
| 72 | </property> | ||
| 73 | </spacer> | ||
| 74 | </item> | ||
| 75 | </layout> | ||
| 76 | </widget> | ||
| 77 | </item> | ||
| 78 | <item> | ||
| 79 | <widget class="QGroupBox" name="groupBox_2"> | ||
| 80 | <property name="title"> | ||
| 81 | <string>Gamecard</string> | ||
| 82 | </property> | ||
| 83 | <layout class="QGridLayout" name="gridLayout_2"> | ||
| 84 | <item row="2" column="1"> | ||
| 85 | <widget class="QLabel" name="label_3"> | ||
| 86 | <property name="text"> | ||
| 87 | <string>Path</string> | ||
| 88 | </property> | ||
| 89 | </widget> | ||
| 90 | </item> | ||
| 91 | <item row="2" column="2"> | ||
| 92 | <widget class="QLineEdit" name="gamecard_path_edit"/> | ||
| 93 | </item> | ||
| 94 | <item row="0" column="1"> | ||
| 95 | <widget class="QCheckBox" name="gamecard_inserted"> | ||
| 96 | <property name="text"> | ||
| 97 | <string>Inserted</string> | ||
| 98 | </property> | ||
| 99 | </widget> | ||
| 100 | </item> | ||
| 101 | <item row="1" column="1"> | ||
| 102 | <widget class="QCheckBox" name="gamecard_current_game"> | ||
| 103 | <property name="text"> | ||
| 104 | <string>Current Game</string> | ||
| 105 | </property> | ||
| 106 | </widget> | ||
| 107 | </item> | ||
| 108 | <item row="2" column="3"> | ||
| 109 | <widget class="QToolButton" name="gamecard_path_button"> | ||
| 110 | <property name="text"> | ||
| 111 | <string>...</string> | ||
| 112 | </property> | ||
| 113 | </widget> | ||
| 114 | </item> | ||
| 115 | </layout> | ||
| 116 | </widget> | ||
| 117 | </item> | ||
| 118 | <item> | ||
| 119 | <widget class="QGroupBox" name="groupBox_3"> | ||
| 120 | <property name="title"> | ||
| 121 | <string>Storage Sizes</string> | ||
| 122 | </property> | ||
| 123 | <layout class="QGridLayout" name="gridLayout_3"> | ||
| 124 | <item row="3" column="0"> | ||
| 125 | <widget class="QLabel" name="label_5"> | ||
| 126 | <property name="text"> | ||
| 127 | <string>SD Card</string> | ||
| 128 | </property> | ||
| 129 | </widget> | ||
| 130 | </item> | ||
| 131 | <item row="1" column="0"> | ||
| 132 | <widget class="QLabel" name="label_4"> | ||
| 133 | <property name="text"> | ||
| 134 | <string>System NAND</string> | ||
| 135 | </property> | ||
| 136 | </widget> | ||
| 137 | </item> | ||
| 138 | <item row="1" column="1"> | ||
| 139 | <widget class="QComboBox" name="sysnand_size"> | ||
| 140 | <item> | ||
| 141 | <property name="text"> | ||
| 142 | <string>2.5 GB</string> | ||
| 143 | </property> | ||
| 144 | </item> | ||
| 145 | </widget> | ||
| 146 | </item> | ||
| 147 | <item row="3" column="1"> | ||
| 148 | <widget class="QComboBox" name="sdmc_size"> | ||
| 149 | <property name="currentText"> | ||
| 150 | <string>32 GB</string> | ||
| 151 | </property> | ||
| 152 | <item> | ||
| 153 | <property name="text"> | ||
| 154 | <string>1 GB</string> | ||
| 155 | </property> | ||
| 156 | </item> | ||
| 157 | <item> | ||
| 158 | <property name="text"> | ||
| 159 | <string>2 GB</string> | ||
| 160 | </property> | ||
| 161 | </item> | ||
| 162 | <item> | ||
| 163 | <property name="text"> | ||
| 164 | <string>4 GB</string> | ||
| 165 | </property> | ||
| 166 | </item> | ||
| 167 | <item> | ||
| 168 | <property name="text"> | ||
| 169 | <string>8 GB</string> | ||
| 170 | </property> | ||
| 171 | </item> | ||
| 172 | <item> | ||
| 173 | <property name="text"> | ||
| 174 | <string>16 GB</string> | ||
| 175 | </property> | ||
| 176 | </item> | ||
| 177 | <item> | ||
| 178 | <property name="text"> | ||
| 179 | <string>32 GB</string> | ||
| 180 | </property> | ||
| 181 | </item> | ||
| 182 | <item> | ||
| 183 | <property name="text"> | ||
| 184 | <string>64 GB</string> | ||
| 185 | </property> | ||
| 186 | </item> | ||
| 187 | <item> | ||
| 188 | <property name="text"> | ||
| 189 | <string>128 GB</string> | ||
| 190 | </property> | ||
| 191 | </item> | ||
| 192 | <item> | ||
| 193 | <property name="text"> | ||
| 194 | <string>256 GB</string> | ||
| 195 | </property> | ||
| 196 | </item> | ||
| 197 | <item> | ||
| 198 | <property name="text"> | ||
| 199 | <string>1 TB</string> | ||
| 200 | </property> | ||
| 201 | </item> | ||
| 202 | </widget> | ||
| 203 | </item> | ||
| 204 | <item row="2" column="1"> | ||
| 205 | <widget class="QComboBox" name="usrnand_size"> | ||
| 206 | <item> | ||
| 207 | <property name="text"> | ||
| 208 | <string>26 GB</string> | ||
| 209 | </property> | ||
| 210 | </item> | ||
| 211 | </widget> | ||
| 212 | </item> | ||
| 213 | <item row="2" column="0"> | ||
| 214 | <widget class="QLabel" name="label_6"> | ||
| 215 | <property name="text"> | ||
| 216 | <string>User NAND</string> | ||
| 217 | </property> | ||
| 218 | </widget> | ||
| 219 | </item> | ||
| 220 | <item row="0" column="0"> | ||
| 221 | <widget class="QLabel" name="label_7"> | ||
| 222 | <property name="text"> | ||
| 223 | <string>NAND</string> | ||
| 224 | </property> | ||
| 225 | </widget> | ||
| 226 | </item> | ||
| 227 | <item row="0" column="1"> | ||
| 228 | <widget class="QComboBox" name="nand_size"> | ||
| 229 | <item> | ||
| 230 | <property name="text"> | ||
| 231 | <string>29.1 GB</string> | ||
| 232 | </property> | ||
| 233 | </item> | ||
| 234 | </widget> | ||
| 235 | </item> | ||
| 236 | </layout> | ||
| 237 | </widget> | ||
| 238 | </item> | ||
| 239 | <item> | ||
| 240 | <widget class="QGroupBox" name="groupBox_4"> | ||
| 241 | <property name="title"> | ||
| 242 | <string>Patch Manager</string> | ||
| 243 | </property> | ||
| 244 | <layout class="QGridLayout" name="gridLayout_4"> | ||
| 245 | <item row="1" column="2"> | ||
| 246 | <widget class="QLineEdit" name="load_path_edit"/> | ||
| 247 | </item> | ||
| 248 | <item row="0" column="2"> | ||
| 249 | <widget class="QLineEdit" name="dump_path_edit"/> | ||
| 250 | </item> | ||
| 251 | <item row="0" column="3"> | ||
| 252 | <widget class="QToolButton" name="dump_path_button"> | ||
| 253 | <property name="text"> | ||
| 254 | <string>...</string> | ||
| 255 | </property> | ||
| 256 | </widget> | ||
| 257 | </item> | ||
| 258 | <item row="1" column="3"> | ||
| 259 | <widget class="QToolButton" name="load_path_button"> | ||
| 260 | <property name="text"> | ||
| 261 | <string>...</string> | ||
| 262 | </property> | ||
| 263 | </widget> | ||
| 264 | </item> | ||
| 265 | <item row="2" column="0" colspan="4"> | ||
| 266 | <layout class="QHBoxLayout" name="horizontalLayout"> | ||
| 267 | <item> | ||
| 268 | <widget class="QCheckBox" name="dump_nso"> | ||
| 269 | <property name="text"> | ||
| 270 | <string>Dump Decompressed NSOs</string> | ||
| 271 | </property> | ||
| 272 | </widget> | ||
| 273 | </item> | ||
| 274 | <item> | ||
| 275 | <widget class="QCheckBox" name="dump_exefs"> | ||
| 276 | <property name="text"> | ||
| 277 | <string>Dump ExeFS</string> | ||
| 278 | </property> | ||
| 279 | </widget> | ||
| 280 | </item> | ||
| 281 | </layout> | ||
| 282 | </item> | ||
| 283 | <item row="1" column="0"> | ||
| 284 | <widget class="QLabel" name="label_9"> | ||
| 285 | <property name="text"> | ||
| 286 | <string>Mod Load Root</string> | ||
| 287 | </property> | ||
| 288 | </widget> | ||
| 289 | </item> | ||
| 290 | <item row="0" column="0"> | ||
| 291 | <widget class="QLabel" name="label_8"> | ||
| 292 | <property name="text"> | ||
| 293 | <string>Dump Root</string> | ||
| 294 | </property> | ||
| 295 | </widget> | ||
| 296 | </item> | ||
| 297 | <item row="0" column="1"> | ||
| 298 | <spacer name="horizontalSpacer_2"> | ||
| 299 | <property name="orientation"> | ||
| 300 | <enum>Qt::Horizontal</enum> | ||
| 301 | </property> | ||
| 302 | <property name="sizeType"> | ||
| 303 | <enum>QSizePolicy::Fixed</enum> | ||
| 304 | </property> | ||
| 305 | <property name="sizeHint" stdset="0"> | ||
| 306 | <size> | ||
| 307 | <width>40</width> | ||
| 308 | <height>20</height> | ||
| 309 | </size> | ||
| 310 | </property> | ||
| 311 | </spacer> | ||
| 312 | </item> | ||
| 313 | </layout> | ||
| 314 | </widget> | ||
| 315 | </item> | ||
| 316 | <item> | ||
| 317 | <widget class="QGroupBox" name="groupBox_5"> | ||
| 318 | <property name="title"> | ||
| 319 | <string>Caching</string> | ||
| 320 | </property> | ||
| 321 | <layout class="QGridLayout" name="gridLayout_5"> | ||
| 322 | <item row="0" column="0"> | ||
| 323 | <widget class="QLabel" name="label_10"> | ||
| 324 | <property name="text"> | ||
| 325 | <string>Cache Directory</string> | ||
| 326 | </property> | ||
| 327 | </widget> | ||
| 328 | </item> | ||
| 329 | <item row="0" column="1"> | ||
| 330 | <spacer name="horizontalSpacer_3"> | ||
| 331 | <property name="orientation"> | ||
| 332 | <enum>Qt::Horizontal</enum> | ||
| 333 | </property> | ||
| 334 | <property name="sizeType"> | ||
| 335 | <enum>QSizePolicy::Fixed</enum> | ||
| 336 | </property> | ||
| 337 | <property name="sizeHint" stdset="0"> | ||
| 338 | <size> | ||
| 339 | <width>40</width> | ||
| 340 | <height>20</height> | ||
| 341 | </size> | ||
| 342 | </property> | ||
| 343 | </spacer> | ||
| 344 | </item> | ||
| 345 | <item row="0" column="2"> | ||
| 346 | <widget class="QLineEdit" name="cache_directory_edit"/> | ||
| 347 | </item> | ||
| 348 | <item row="0" column="3"> | ||
| 349 | <widget class="QToolButton" name="cache_directory_button"> | ||
| 350 | <property name="text"> | ||
| 351 | <string>...</string> | ||
| 352 | </property> | ||
| 353 | </widget> | ||
| 354 | </item> | ||
| 355 | <item row="1" column="0" colspan="4"> | ||
| 356 | <layout class="QHBoxLayout" name="horizontalLayout_2"> | ||
| 357 | <item> | ||
| 358 | <widget class="QCheckBox" name="cache_game_list"> | ||
| 359 | <property name="text"> | ||
| 360 | <string>Cache Game List Metadata</string> | ||
| 361 | </property> | ||
| 362 | </widget> | ||
| 363 | </item> | ||
| 364 | <item> | ||
| 365 | <widget class="QPushButton" name="reset_game_list_cache"> | ||
| 366 | <property name="text"> | ||
| 367 | <string>Reset Metadata Cache</string> | ||
| 368 | </property> | ||
| 369 | </widget> | ||
| 370 | </item> | ||
| 371 | </layout> | ||
| 372 | </item> | ||
| 373 | </layout> | ||
| 374 | </widget> | ||
| 375 | </item> | ||
| 376 | </layout> | ||
| 377 | </item> | ||
| 378 | <item> | ||
| 379 | <spacer name="verticalSpacer"> | ||
| 380 | <property name="orientation"> | ||
| 381 | <enum>Qt::Vertical</enum> | ||
| 382 | </property> | ||
| 383 | <property name="sizeHint" stdset="0"> | ||
| 384 | <size> | ||
| 385 | <width>20</width> | ||
| 386 | <height>40</height> | ||
| 387 | </size> | ||
| 388 | </property> | ||
| 389 | </spacer> | ||
| 390 | </item> | ||
| 391 | </layout> | ||
| 392 | </widget> | ||
| 393 | <resources/> | ||
| 394 | <connections/> | ||
| 395 | </ui> | ||
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 10bcd650e..b49446be9 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.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 <QSpinBox> | ||
| 5 | #include "core/core.h" | 6 | #include "core/core.h" |
| 6 | #include "core/settings.h" | 7 | #include "core/settings.h" |
| 7 | #include "ui_configure_general.h" | 8 | #include "ui_configure_general.h" |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 0865385e3..f147044d9 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -221,7 +221,7 @@ GMainWindow::GMainWindow() | |||
| 221 | std::make_unique<FileSys::ContentProviderUnion>()); | 221 | std::make_unique<FileSys::ContentProviderUnion>()); |
| 222 | Core::System::GetInstance().RegisterContentProvider( | 222 | Core::System::GetInstance().RegisterContentProvider( |
| 223 | FileSys::ContentProviderUnionSlot::FrontendManual, provider.get()); | 223 | FileSys::ContentProviderUnionSlot::FrontendManual, provider.get()); |
| 224 | Service::FileSystem::CreateFactories(*vfs); | 224 | Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs); |
| 225 | 225 | ||
| 226 | // Gen keys if necessary | 226 | // Gen keys if necessary |
| 227 | OnReinitializeKeys(ReinitializeKeyBehavior::NoWarning); | 227 | OnReinitializeKeys(ReinitializeKeyBehavior::NoWarning); |
| @@ -1507,15 +1507,19 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 1507 | failed(); | 1507 | failed(); |
| 1508 | return; | 1508 | return; |
| 1509 | } | 1509 | } |
| 1510 | const auto res = | 1510 | const auto res = Core::System::GetInstance() |
| 1511 | Service::FileSystem::GetUserNANDContents()->InstallEntry(*nsp, false, qt_raw_copy); | 1511 | .GetFileSystemController() |
| 1512 | .GetUserNANDContents() | ||
| 1513 | ->InstallEntry(*nsp, false, qt_raw_copy); | ||
| 1512 | if (res == FileSys::InstallResult::Success) { | 1514 | if (res == FileSys::InstallResult::Success) { |
| 1513 | success(); | 1515 | success(); |
| 1514 | } else { | 1516 | } else { |
| 1515 | if (res == FileSys::InstallResult::ErrorAlreadyExists) { | 1517 | if (res == FileSys::InstallResult::ErrorAlreadyExists) { |
| 1516 | if (overwrite()) { | 1518 | if (overwrite()) { |
| 1517 | const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( | 1519 | const auto res2 = Core::System::GetInstance() |
| 1518 | *nsp, true, qt_raw_copy); | 1520 | .GetFileSystemController() |
| 1521 | .GetUserNANDContents() | ||
| 1522 | ->InstallEntry(*nsp, true, qt_raw_copy); | ||
| 1519 | if (res2 == FileSys::InstallResult::Success) { | 1523 | if (res2 == FileSys::InstallResult::Success) { |
| 1520 | success(); | 1524 | success(); |
| 1521 | } else { | 1525 | } else { |
| @@ -1569,19 +1573,28 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 1569 | 1573 | ||
| 1570 | FileSys::InstallResult res; | 1574 | FileSys::InstallResult res; |
| 1571 | if (index >= static_cast<size_t>(FileSys::TitleType::Application)) { | 1575 | if (index >= static_cast<size_t>(FileSys::TitleType::Application)) { |
| 1572 | res = Service::FileSystem::GetUserNANDContents()->InstallEntry( | 1576 | res = Core::System::GetInstance() |
| 1573 | *nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); | 1577 | .GetFileSystemController() |
| 1578 | .GetUserNANDContents() | ||
| 1579 | ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false, | ||
| 1580 | qt_raw_copy); | ||
| 1574 | } else { | 1581 | } else { |
| 1575 | res = Service::FileSystem::GetSystemNANDContents()->InstallEntry( | 1582 | res = Core::System::GetInstance() |
| 1576 | *nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); | 1583 | .GetFileSystemController() |
| 1584 | .GetSystemNANDContents() | ||
| 1585 | ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false, | ||
| 1586 | qt_raw_copy); | ||
| 1577 | } | 1587 | } |
| 1578 | 1588 | ||
| 1579 | if (res == FileSys::InstallResult::Success) { | 1589 | if (res == FileSys::InstallResult::Success) { |
| 1580 | success(); | 1590 | success(); |
| 1581 | } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { | 1591 | } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { |
| 1582 | if (overwrite()) { | 1592 | if (overwrite()) { |
| 1583 | const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( | 1593 | const auto res2 = Core::System::GetInstance() |
| 1584 | *nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy); | 1594 | .GetFileSystemController() |
| 1595 | .GetUserNANDContents() | ||
| 1596 | ->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), | ||
| 1597 | true, qt_raw_copy); | ||
| 1585 | if (res2 == FileSys::InstallResult::Success) { | 1598 | if (res2 == FileSys::InstallResult::Success) { |
| 1586 | success(); | 1599 | success(); |
| 1587 | } else { | 1600 | } else { |
| @@ -1611,7 +1624,7 @@ void GMainWindow::OnMenuSelectEmulatedDirectory(EmulatedDirectoryTarget target) | |||
| 1611 | FileUtil::GetUserPath(target == EmulatedDirectoryTarget::SDMC ? FileUtil::UserPath::SDMCDir | 1624 | FileUtil::GetUserPath(target == EmulatedDirectoryTarget::SDMC ? FileUtil::UserPath::SDMCDir |
| 1612 | : FileUtil::UserPath::NANDDir, | 1625 | : FileUtil::UserPath::NANDDir, |
| 1613 | dir_path.toStdString()); | 1626 | dir_path.toStdString()); |
| 1614 | Service::FileSystem::CreateFactories(*vfs); | 1627 | Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs); |
| 1615 | game_list->PopulateAsync(UISettings::values.game_dirs); | 1628 | game_list->PopulateAsync(UISettings::values.game_dirs); |
| 1616 | } | 1629 | } |
| 1617 | } | 1630 | } |
| @@ -1996,7 +2009,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { | |||
| 1996 | 2009 | ||
| 1997 | const auto function = [this, &keys, &pdm] { | 2010 | const auto function = [this, &keys, &pdm] { |
| 1998 | keys.PopulateFromPartitionData(pdm); | 2011 | keys.PopulateFromPartitionData(pdm); |
| 1999 | Service::FileSystem::CreateFactories(*vfs); | 2012 | Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs); |
| 2000 | keys.DeriveETicket(pdm); | 2013 | keys.DeriveETicket(pdm); |
| 2001 | }; | 2014 | }; |
| 2002 | 2015 | ||
| @@ -2041,7 +2054,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { | |||
| 2041 | prog.close(); | 2054 | prog.close(); |
| 2042 | } | 2055 | } |
| 2043 | 2056 | ||
| 2044 | Service::FileSystem::CreateFactories(*vfs); | 2057 | Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs); |
| 2045 | 2058 | ||
| 2046 | if (behavior == ReinitializeKeyBehavior::Warning) { | 2059 | if (behavior == ReinitializeKeyBehavior::Warning) { |
| 2047 | game_list->PopulateAsync(UISettings::values.game_dirs); | 2060 | game_list->PopulateAsync(UISettings::values.game_dirs); |
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 5cadfd191..d82438502 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp | |||
| @@ -316,6 +316,29 @@ void Config::ReadValues() { | |||
| 316 | FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir, | 316 | FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir, |
| 317 | sdl2_config->Get("Data Storage", "sdmc_directory", | 317 | sdl2_config->Get("Data Storage", "sdmc_directory", |
| 318 | FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir))); | 318 | FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir))); |
| 319 | FileUtil::GetUserPath(FileUtil::UserPath::LoadDir, | ||
| 320 | sdl2_config->Get("Data Storage", "load_directory", | ||
| 321 | FileUtil::GetUserPath(FileUtil::UserPath::LoadDir))); | ||
| 322 | FileUtil::GetUserPath(FileUtil::UserPath::DumpDir, | ||
| 323 | sdl2_config->Get("Data Storage", "dump_directory", | ||
| 324 | FileUtil::GetUserPath(FileUtil::UserPath::DumpDir))); | ||
| 325 | FileUtil::GetUserPath(FileUtil::UserPath::CacheDir, | ||
| 326 | sdl2_config->Get("Data Storage", "cache_directory", | ||
| 327 | FileUtil::GetUserPath(FileUtil::UserPath::CacheDir))); | ||
| 328 | Settings::values.gamecard_inserted = | ||
| 329 | sdl2_config->GetBoolean("Data Storage", "gamecard_inserted", false); | ||
| 330 | Settings::values.gamecard_current_game = | ||
| 331 | sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false); | ||
| 332 | Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", ""); | ||
| 333 | Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(sdl2_config->GetInteger( | ||
| 334 | "Data Storage", "nand_total_size", static_cast<long>(Settings::NANDTotalSize::S29_1GB))); | ||
| 335 | Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(sdl2_config->GetInteger( | ||
| 336 | "Data Storage", "nand_user_size", static_cast<long>(Settings::NANDUserSize::S26GB))); | ||
| 337 | Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>( | ||
| 338 | sdl2_config->GetInteger("Data Storage", "nand_system_size", | ||
| 339 | static_cast<long>(Settings::NANDSystemSize::S2_5GB))); | ||
| 340 | Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(sdl2_config->GetInteger( | ||
| 341 | "Data Storage", "sdmc_size", static_cast<long>(Settings::SDMCSize::S16GB))); | ||
| 319 | 342 | ||
| 320 | // System | 343 | // System |
| 321 | Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false); | 344 | Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false); |
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index f9f244522..a6171c3ed 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h | |||
| @@ -173,6 +173,20 @@ volume = | |||
| 173 | # 1 (default): Yes, 0: No | 173 | # 1 (default): Yes, 0: No |
| 174 | use_virtual_sd = | 174 | use_virtual_sd = |
| 175 | 175 | ||
| 176 | # Whether or not to enable gamecard emulation | ||
| 177 | # 1: Yes, 0 (default): No | ||
| 178 | gamecard_inserted = | ||
| 179 | |||
| 180 | # Whether or not the gamecard should be emulated as the current game | ||
| 181 | # If 'gamecard_inserted' is 0 this setting is irrelevant | ||
| 182 | # 1: Yes, 0 (default): No | ||
| 183 | gamecard_current_game = | ||
| 184 | |||
| 185 | # Path to an XCI file to use as the gamecard | ||
| 186 | # If 'gamecard_inserted' is 0 this setting is irrelevant | ||
| 187 | # If 'gamecard_current_game' is 1 this setting is irrelevant | ||
| 188 | gamecard_path = | ||
| 189 | |||
| 176 | [System] | 190 | [System] |
| 177 | # Whether the system is docked | 191 | # Whether the system is docked |
| 178 | # 1: Yes, 0 (default): No | 192 | # 1: Yes, 0 (default): No |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 129d8ca73..bac05b959 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -184,7 +184,7 @@ int main(int argc, char** argv) { | |||
| 184 | Core::System& system{Core::System::GetInstance()}; | 184 | Core::System& system{Core::System::GetInstance()}; |
| 185 | system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); | 185 | system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); |
| 186 | system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>()); | 186 | system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>()); |
| 187 | Service::FileSystem::CreateFactories(*system.GetFilesystem()); | 187 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem()); |
| 188 | 188 | ||
| 189 | SCOPE_EXIT({ system.Shutdown(); }); | 189 | SCOPE_EXIT({ system.Shutdown(); }); |
| 190 | 190 | ||
diff --git a/src/yuzu_tester/yuzu.cpp b/src/yuzu_tester/yuzu.cpp index 0ee97aa54..94ad50cb3 100644 --- a/src/yuzu_tester/yuzu.cpp +++ b/src/yuzu_tester/yuzu.cpp | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | #include "common/telemetry.h" | 22 | #include "common/telemetry.h" |
| 23 | #include "core/core.h" | 23 | #include "core/core.h" |
| 24 | #include "core/crypto/key_manager.h" | 24 | #include "core/crypto/key_manager.h" |
| 25 | #include "core/file_sys/registered_cache.h" | ||
| 25 | #include "core/file_sys/vfs_real.h" | 26 | #include "core/file_sys/vfs_real.h" |
| 26 | #include "core/hle/service/filesystem/filesystem.h" | 27 | #include "core/hle/service/filesystem/filesystem.h" |
| 27 | #include "core/loader/loader.h" | 28 | #include "core/loader/loader.h" |
| @@ -216,8 +217,9 @@ int main(int argc, char** argv) { | |||
| 216 | }; | 217 | }; |
| 217 | 218 | ||
| 218 | Core::System& system{Core::System::GetInstance()}; | 219 | Core::System& system{Core::System::GetInstance()}; |
| 220 | system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); | ||
| 219 | system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>()); | 221 | system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>()); |
| 220 | Service::FileSystem::CreateFactories(*system.GetFilesystem()); | 222 | system.GetFileSystemController().CreateFactories(*system.GetFilesystem()); |
| 221 | 223 | ||
| 222 | SCOPE_EXIT({ system.Shutdown(); }); | 224 | SCOPE_EXIT({ system.Shutdown(); }); |
| 223 | 225 | ||