mirror of
https://github.com/yuzu-emu/yuzu.git
synced 2024-11-27 06:04:15 +01:00
Merge pull request #2430 from DarkLordZach/fs-controller
core: Implement FileSystemController to deglobalize FS services
This commit is contained in:
commit
c9ccdfbeac
@ -14,8 +14,13 @@
|
||||
#include "core/core_cpu.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/cpu_core_manager.h"
|
||||
#include "core/file_sys/bis_factory.h"
|
||||
#include "core/file_sys/card_image.h"
|
||||
#include "core/file_sys/mode.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/romfs_factory.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/file_sys/sdmc_factory.h"
|
||||
#include "core/file_sys/vfs_concat.h"
|
||||
#include "core/file_sys/vfs_real.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
@ -27,6 +32,7 @@
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/service/am/applets/applets.h"
|
||||
#include "core/hle/service/apm/controller.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/glue/manager.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
@ -202,6 +208,15 @@ struct System::Impl {
|
||||
main_process->Run(load_parameters->main_thread_priority,
|
||||
load_parameters->main_thread_stack_size);
|
||||
|
||||
if (Settings::values.gamecard_inserted) {
|
||||
if (Settings::values.gamecard_current_game) {
|
||||
fs_controller.SetGameCard(GetGameFileFromPath(virtual_filesystem, filepath));
|
||||
} else if (!Settings::values.gamecard_path.empty()) {
|
||||
fs_controller.SetGameCard(
|
||||
GetGameFileFromPath(virtual_filesystem, Settings::values.gamecard_path));
|
||||
}
|
||||
}
|
||||
|
||||
u64 title_id{0};
|
||||
if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
|
||||
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})",
|
||||
@ -304,6 +319,7 @@ struct System::Impl {
|
||||
FileSys::VirtualFilesystem virtual_filesystem;
|
||||
/// ContentProviderUnion instance
|
||||
std::unique_ptr<FileSys::ContentProviderUnion> content_provider;
|
||||
Service::FileSystem::FileSystemController fs_controller;
|
||||
/// AppLoader used to load the current executing application
|
||||
std::unique_ptr<Loader::AppLoader> app_loader;
|
||||
std::unique_ptr<VideoCore::RendererBase> renderer;
|
||||
@ -571,6 +587,14 @@ const FileSys::ContentProvider& System::GetContentProvider() const {
|
||||
return *impl->content_provider;
|
||||
}
|
||||
|
||||
Service::FileSystem::FileSystemController& System::GetFileSystemController() {
|
||||
return impl->fs_controller;
|
||||
}
|
||||
|
||||
const Service::FileSystem::FileSystemController& System::GetFileSystemController() const {
|
||||
return impl->fs_controller;
|
||||
}
|
||||
|
||||
void System::RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
|
||||
FileSys::ContentProvider* provider) {
|
||||
impl->content_provider->SetSlot(slot, provider);
|
||||
|
@ -47,6 +47,10 @@ namespace APM {
|
||||
class Controller;
|
||||
}
|
||||
|
||||
namespace FileSystem {
|
||||
class FileSystemController;
|
||||
} // namespace FileSystem
|
||||
|
||||
namespace Glue {
|
||||
class ARPManager;
|
||||
}
|
||||
@ -299,6 +303,10 @@ public:
|
||||
|
||||
const FileSys::ContentProvider& GetContentProvider() const;
|
||||
|
||||
Service::FileSystem::FileSystemController& GetFileSystemController();
|
||||
|
||||
const Service::FileSystem::FileSystemController& GetFileSystemController() const;
|
||||
|
||||
void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
|
||||
FileSys::ContentProvider* provider);
|
||||
|
||||
|
@ -480,6 +480,10 @@ void PartitionDataManager::DecryptProdInfo(std::array<u8, 0x20> bis_key) {
|
||||
prodinfo_decrypted = std::make_shared<XTSEncryptionLayer>(prodinfo, bis_key);
|
||||
}
|
||||
|
||||
FileSys::VirtualFile PartitionDataManager::GetDecryptedProdInfo() const {
|
||||
return prodinfo_decrypted;
|
||||
}
|
||||
|
||||
std::array<u8, 576> PartitionDataManager::GetETicketExtendedKek() const {
|
||||
std::array<u8, 0x240> out{};
|
||||
if (prodinfo_decrypted != nullptr)
|
||||
|
@ -84,6 +84,7 @@ public:
|
||||
bool HasProdInfo() const;
|
||||
FileSys::VirtualFile GetProdInfoRaw() const;
|
||||
void DecryptProdInfo(std::array<u8, 0x20> bis_key);
|
||||
FileSys::VirtualFile GetDecryptedProdInfo() const;
|
||||
std::array<u8, 0x240> GetETicketExtendedKek() const;
|
||||
|
||||
private:
|
||||
|
@ -3,8 +3,12 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include "common/file_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/bis_factory.h"
|
||||
#include "core/file_sys/mode.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
@ -14,10 +18,22 @@ BISFactory::BISFactory(VirtualDir nand_root_, VirtualDir load_root_, VirtualDir
|
||||
sysnand_cache(std::make_unique<RegisteredCache>(
|
||||
GetOrCreateDirectoryRelative(nand_root, "/system/Contents/registered"))),
|
||||
usrnand_cache(std::make_unique<RegisteredCache>(
|
||||
GetOrCreateDirectoryRelative(nand_root, "/user/Contents/registered"))) {}
|
||||
GetOrCreateDirectoryRelative(nand_root, "/user/Contents/registered"))),
|
||||
sysnand_placeholder(std::make_unique<PlaceholderCache>(
|
||||
GetOrCreateDirectoryRelative(nand_root, "/system/Contents/placehld"))),
|
||||
usrnand_placeholder(std::make_unique<PlaceholderCache>(
|
||||
GetOrCreateDirectoryRelative(nand_root, "/user/Contents/placehld"))) {}
|
||||
|
||||
BISFactory::~BISFactory() = default;
|
||||
|
||||
VirtualDir BISFactory::GetSystemNANDContentDirectory() const {
|
||||
return GetOrCreateDirectoryRelative(nand_root, "/system/Contents");
|
||||
}
|
||||
|
||||
VirtualDir BISFactory::GetUserNANDContentDirectory() const {
|
||||
return GetOrCreateDirectoryRelative(nand_root, "/user/Contents");
|
||||
}
|
||||
|
||||
RegisteredCache* BISFactory::GetSystemNANDContents() const {
|
||||
return sysnand_cache.get();
|
||||
}
|
||||
@ -26,9 +42,17 @@ RegisteredCache* BISFactory::GetUserNANDContents() const {
|
||||
return usrnand_cache.get();
|
||||
}
|
||||
|
||||
PlaceholderCache* BISFactory::GetSystemNANDPlaceholder() const {
|
||||
return sysnand_placeholder.get();
|
||||
}
|
||||
|
||||
PlaceholderCache* BISFactory::GetUserNANDPlaceholder() const {
|
||||
return usrnand_placeholder.get();
|
||||
}
|
||||
|
||||
VirtualDir BISFactory::GetModificationLoadRoot(u64 title_id) const {
|
||||
// LayeredFS doesn't work on updates and title id-less homebrew
|
||||
if (title_id == 0 || (title_id & 0x800) > 0)
|
||||
if (title_id == 0 || (title_id & 0xFFF) == 0x800)
|
||||
return nullptr;
|
||||
return GetOrCreateDirectoryRelative(load_root, fmt::format("/{:016X}", title_id));
|
||||
}
|
||||
@ -39,4 +63,77 @@ VirtualDir BISFactory::GetModificationDumpRoot(u64 title_id) const {
|
||||
return GetOrCreateDirectoryRelative(dump_root, fmt::format("/{:016X}", title_id));
|
||||
}
|
||||
|
||||
VirtualDir BISFactory::OpenPartition(BisPartitionId id) const {
|
||||
switch (id) {
|
||||
case BisPartitionId::CalibrationFile:
|
||||
return GetOrCreateDirectoryRelative(nand_root, "/prodinfof");
|
||||
case BisPartitionId::SafeMode:
|
||||
return GetOrCreateDirectoryRelative(nand_root, "/safe");
|
||||
case BisPartitionId::System:
|
||||
return GetOrCreateDirectoryRelative(nand_root, "/system");
|
||||
case BisPartitionId::User:
|
||||
return GetOrCreateDirectoryRelative(nand_root, "/user");
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id) const {
|
||||
Core::Crypto::KeyManager keys;
|
||||
Core::Crypto::PartitionDataManager pdm{
|
||||
Core::System::GetInstance().GetFilesystem()->OpenDirectory(
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), Mode::Read)};
|
||||
keys.PopulateFromPartitionData(pdm);
|
||||
|
||||
switch (id) {
|
||||
case BisPartitionId::CalibrationBinary:
|
||||
return pdm.GetDecryptedProdInfo();
|
||||
case BisPartitionId::BootConfigAndPackage2Part1:
|
||||
case BisPartitionId::BootConfigAndPackage2Part2:
|
||||
case BisPartitionId::BootConfigAndPackage2Part3:
|
||||
case BisPartitionId::BootConfigAndPackage2Part4:
|
||||
case BisPartitionId::BootConfigAndPackage2Part5:
|
||||
case BisPartitionId::BootConfigAndPackage2Part6: {
|
||||
const auto new_id = static_cast<u8>(id) -
|
||||
static_cast<u8>(BisPartitionId::BootConfigAndPackage2Part1) +
|
||||
static_cast<u8>(Core::Crypto::Package2Type::NormalMain);
|
||||
return pdm.GetPackage2Raw(static_cast<Core::Crypto::Package2Type>(new_id));
|
||||
}
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
VirtualDir BISFactory::GetImageDirectory() const {
|
||||
return GetOrCreateDirectoryRelative(nand_root, "/user/Album");
|
||||
}
|
||||
|
||||
u64 BISFactory::GetSystemNANDFreeSpace() const {
|
||||
const auto sys_dir = GetOrCreateDirectoryRelative(nand_root, "/system");
|
||||
if (sys_dir == nullptr)
|
||||
return 0;
|
||||
|
||||
return GetSystemNANDTotalSpace() - sys_dir->GetSize();
|
||||
}
|
||||
|
||||
u64 BISFactory::GetSystemNANDTotalSpace() const {
|
||||
return static_cast<u64>(Settings::values.nand_system_size);
|
||||
}
|
||||
|
||||
u64 BISFactory::GetUserNANDFreeSpace() const {
|
||||
const auto usr_dir = GetOrCreateDirectoryRelative(nand_root, "/user");
|
||||
if (usr_dir == nullptr)
|
||||
return 0;
|
||||
|
||||
return GetUserNANDTotalSpace() - usr_dir->GetSize();
|
||||
}
|
||||
|
||||
u64 BISFactory::GetUserNANDTotalSpace() const {
|
||||
return static_cast<u64>(Settings::values.nand_user_size);
|
||||
}
|
||||
|
||||
u64 BISFactory::GetFullNANDTotalSpace() const {
|
||||
return static_cast<u64>(Settings::values.nand_total_size);
|
||||
}
|
||||
|
||||
} // namespace FileSys
|
||||
|
@ -10,7 +10,25 @@
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
enum class BisPartitionId : u32 {
|
||||
UserDataRoot = 20,
|
||||
CalibrationBinary = 27,
|
||||
CalibrationFile = 28,
|
||||
BootConfigAndPackage2Part1 = 21,
|
||||
BootConfigAndPackage2Part2 = 22,
|
||||
BootConfigAndPackage2Part3 = 23,
|
||||
BootConfigAndPackage2Part4 = 24,
|
||||
BootConfigAndPackage2Part5 = 25,
|
||||
BootConfigAndPackage2Part6 = 26,
|
||||
SafeMode = 29,
|
||||
System = 31,
|
||||
SystemProperEncryption = 32,
|
||||
SystemProperPartition = 33,
|
||||
User = 30,
|
||||
};
|
||||
|
||||
class RegisteredCache;
|
||||
class PlaceholderCache;
|
||||
|
||||
/// File system interface to the Built-In Storage
|
||||
/// This is currently missing accessors to BIS partitions, but seemed like a good place for the NAND
|
||||
@ -20,12 +38,29 @@ public:
|
||||
explicit BISFactory(VirtualDir nand_root, VirtualDir load_root, VirtualDir dump_root);
|
||||
~BISFactory();
|
||||
|
||||
VirtualDir GetSystemNANDContentDirectory() const;
|
||||
VirtualDir GetUserNANDContentDirectory() const;
|
||||
|
||||
RegisteredCache* GetSystemNANDContents() const;
|
||||
RegisteredCache* GetUserNANDContents() const;
|
||||
|
||||
PlaceholderCache* GetSystemNANDPlaceholder() const;
|
||||
PlaceholderCache* GetUserNANDPlaceholder() const;
|
||||
|
||||
VirtualDir GetModificationLoadRoot(u64 title_id) const;
|
||||
VirtualDir GetModificationDumpRoot(u64 title_id) const;
|
||||
|
||||
VirtualDir OpenPartition(BisPartitionId id) const;
|
||||
VirtualFile OpenPartitionStorage(BisPartitionId id) const;
|
||||
|
||||
VirtualDir GetImageDirectory() const;
|
||||
|
||||
u64 GetSystemNANDFreeSpace() const;
|
||||
u64 GetSystemNANDTotalSpace() const;
|
||||
u64 GetUserNANDFreeSpace() const;
|
||||
u64 GetUserNANDTotalSpace() const;
|
||||
u64 GetFullNANDTotalSpace() const;
|
||||
|
||||
private:
|
||||
VirtualDir nand_root;
|
||||
VirtualDir load_root;
|
||||
@ -33,6 +68,9 @@ private:
|
||||
|
||||
std::unique_ptr<RegisteredCache> sysnand_cache;
|
||||
std::unique_ptr<RegisteredCache> usrnand_cache;
|
||||
|
||||
std::unique_ptr<PlaceholderCache> sysnand_placeholder;
|
||||
std::unique_ptr<PlaceholderCache> usrnand_placeholder;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
@ -12,12 +12,16 @@
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
#include "core/file_sys/partition_filesystem.h"
|
||||
#include "core/file_sys/romfs.h"
|
||||
#include "core/file_sys/submission_package.h"
|
||||
#include "core/file_sys/vfs_concat.h"
|
||||
#include "core/file_sys/vfs_offset.h"
|
||||
#include "core/file_sys/vfs_vector.h"
|
||||
#include "core/loader/loader.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
constexpr u64 GAMECARD_CERTIFICATE_OFFSET = 0x7000;
|
||||
constexpr std::array partition_names{
|
||||
"update",
|
||||
"normal",
|
||||
@ -175,6 +179,26 @@ VirtualDir XCI::GetParentDirectory() const {
|
||||
return file->GetContainingDirectory();
|
||||
}
|
||||
|
||||
VirtualDir XCI::ConcatenatedPseudoDirectory() {
|
||||
const auto out = std::make_shared<VectorVfsDirectory>();
|
||||
for (const auto& part_id : {XCIPartition::Normal, XCIPartition::Logo, XCIPartition::Secure}) {
|
||||
const auto& part = GetPartition(part_id);
|
||||
if (part == nullptr)
|
||||
continue;
|
||||
|
||||
for (const auto& file : part->GetFiles())
|
||||
out->AddFile(file);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::array<u8, 0x200> XCI::GetCertificate() const {
|
||||
std::array<u8, 0x200> out;
|
||||
file->Read(out.data(), out.size(), GAMECARD_CERTIFICATE_OFFSET);
|
||||
return out;
|
||||
}
|
||||
|
||||
Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
|
||||
const auto partition_index = static_cast<std::size_t>(part);
|
||||
const auto& partition = partitions[partition_index];
|
||||
|
@ -91,6 +91,8 @@ public:
|
||||
VirtualDir GetLogoPartition() const;
|
||||
|
||||
u64 GetProgramTitleID() const;
|
||||
u32 GetSystemUpdateVersion();
|
||||
u64 GetSystemUpdateTitleID() const;
|
||||
|
||||
bool HasProgramNCA() const;
|
||||
VirtualFile GetProgramNCAFile() const;
|
||||
@ -106,6 +108,11 @@ public:
|
||||
|
||||
VirtualDir GetParentDirectory() const override;
|
||||
|
||||
// Creates a directory that contains all the NCAs in the gamecard
|
||||
VirtualDir ConcatenatedPseudoDirectory();
|
||||
|
||||
std::array<u8, 0x200> GetCertificate() const;
|
||||
|
||||
private:
|
||||
Loader::ResultStatus AddNCAFromPartition(XCIPartition part);
|
||||
|
||||
@ -120,6 +127,8 @@ private:
|
||||
std::shared_ptr<NCA> program;
|
||||
std::vector<std::shared_ptr<NCA>> ncas;
|
||||
|
||||
u64 update_normal_partition_end;
|
||||
|
||||
Core::Crypto::KeyManager keys;
|
||||
};
|
||||
} // namespace FileSys
|
||||
|
@ -528,6 +528,14 @@ u64 NCA::GetTitleId() const {
|
||||
return header.title_id;
|
||||
}
|
||||
|
||||
std::array<u8, 16> NCA::GetRightsId() const {
|
||||
return header.rights_id;
|
||||
}
|
||||
|
||||
u32 NCA::GetSDKVersion() const {
|
||||
return header.sdk_version;
|
||||
}
|
||||
|
||||
bool NCA::IsUpdate() const {
|
||||
return is_update;
|
||||
}
|
||||
|
@ -112,6 +112,8 @@ public:
|
||||
|
||||
NCAContentType GetType() const;
|
||||
u64 GetTitleId() const;
|
||||
std::array<u8, 0x10> GetRightsId() const;
|
||||
u32 GetSDKVersion() const;
|
||||
bool IsUpdate() const;
|
||||
|
||||
VirtualFile GetRomFS() const;
|
||||
|
@ -63,7 +63,8 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
||||
|
||||
if (Settings::values.dump_exefs) {
|
||||
LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id);
|
||||
const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
|
||||
const auto dump_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id);
|
||||
if (dump_dir != nullptr) {
|
||||
const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs");
|
||||
VfsRawCopyD(exefs, exefs_dir);
|
||||
@ -88,7 +89,8 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const {
|
||||
}
|
||||
|
||||
// LayeredExeFS
|
||||
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
|
||||
const auto load_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
|
||||
if (load_dir != nullptr && load_dir->GetSize() > 0) {
|
||||
auto patch_dirs = load_dir->GetSubdirectories();
|
||||
std::sort(
|
||||
@ -174,7 +176,8 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
|
||||
if (Settings::values.dump_nso) {
|
||||
LOG_INFO(Loader, "Dumping NSO for name={}, build_id={}, title_id={:016X}", name, build_id,
|
||||
title_id);
|
||||
const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id);
|
||||
const auto dump_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationDumpRoot(title_id);
|
||||
if (dump_dir != nullptr) {
|
||||
const auto nso_dir = GetOrCreateDirectoryRelative(dump_dir, "/nso");
|
||||
const auto file = nso_dir->CreateFile(fmt::format("{}-{}.nso", name, build_id));
|
||||
@ -186,7 +189,13 @@ std::vector<u8> PatchManager::PatchNSO(const std::vector<u8>& nso, const std::st
|
||||
|
||||
LOG_INFO(Loader, "Patching NSO for name={}, build_id={}", name, build_id);
|
||||
|
||||
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
|
||||
const auto load_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
|
||||
if (load_dir == nullptr) {
|
||||
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
||||
return nso;
|
||||
}
|
||||
|
||||
auto patch_dirs = load_dir->GetSubdirectories();
|
||||
std::sort(patch_dirs.begin(), patch_dirs.end(),
|
||||
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
|
||||
@ -224,7 +233,13 @@ bool PatchManager::HasNSOPatch(const std::array<u8, 32>& build_id_) const {
|
||||
|
||||
LOG_INFO(Loader, "Querying NSO patch existence for build_id={}", build_id);
|
||||
|
||||
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
|
||||
const auto load_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
|
||||
if (load_dir == nullptr) {
|
||||
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
||||
return false;
|
||||
}
|
||||
|
||||
auto patch_dirs = load_dir->GetSubdirectories();
|
||||
std::sort(patch_dirs.begin(), patch_dirs.end(),
|
||||
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
|
||||
@ -258,7 +273,13 @@ static std::optional<CheatList> ReadCheatFileFromFolder(const Core::System& syst
|
||||
|
||||
std::vector<CheatList> PatchManager::CreateCheatList(const Core::System& system,
|
||||
const std::array<u8, 32>& build_id_) const {
|
||||
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
|
||||
const auto load_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
|
||||
if (load_dir == nullptr) {
|
||||
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
||||
return {};
|
||||
}
|
||||
|
||||
auto patch_dirs = load_dir->GetSubdirectories();
|
||||
std::sort(patch_dirs.begin(), patch_dirs.end(),
|
||||
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
|
||||
@ -284,7 +305,8 @@ std::vector<CheatList> PatchManager::CreateCheatList(const Core::System& system,
|
||||
}
|
||||
|
||||
static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) {
|
||||
const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
|
||||
const auto load_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
|
||||
if ((type != ContentRecordType::Program && type != ContentRecordType::Data) ||
|
||||
load_dir == nullptr || load_dir->GetSize() <= 0) {
|
||||
return;
|
||||
@ -393,6 +415,8 @@ static bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
|
||||
|
||||
std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNames(
|
||||
VirtualFile update_raw) const {
|
||||
if (title_id == 0)
|
||||
return {};
|
||||
std::map<std::string, std::string, std::less<>> out;
|
||||
const auto& installed = Core::System::GetInstance().GetContentProvider();
|
||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||
@ -423,7 +447,8 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam
|
||||
}
|
||||
|
||||
// General Mods (LayeredFS and IPS)
|
||||
const auto mod_dir = Service::FileSystem::GetModificationLoadRoot(title_id);
|
||||
const auto mod_dir =
|
||||
Core::System::GetInstance().GetFileSystemController().GetModificationLoadRoot(title_id);
|
||||
if (mod_dir != nullptr && mod_dir->GetSize() > 0) {
|
||||
for (const auto& mod : mod_dir->GetSubdirectories()) {
|
||||
std::string types;
|
||||
|
@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <regex>
|
||||
#include <mbedtls/sha256.h>
|
||||
#include "common/assert.h"
|
||||
@ -48,18 +49,21 @@ static bool FollowsTwoDigitDirFormat(std::string_view name) {
|
||||
static bool FollowsNcaIdFormat(std::string_view name) {
|
||||
static const std::regex nca_id_regex("[0-9A-F]{32}\\.nca", std::regex_constants::ECMAScript |
|
||||
std::regex_constants::icase);
|
||||
return name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex);
|
||||
static const std::regex nca_id_cnmt_regex(
|
||||
"[0-9A-F]{32}\\.cnmt.nca", std::regex_constants::ECMAScript | std::regex_constants::icase);
|
||||
return (name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex)) ||
|
||||
(name.size() == 41 && std::regex_match(name.begin(), name.end(), nca_id_cnmt_regex));
|
||||
}
|
||||
|
||||
static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bool second_hex_upper,
|
||||
bool within_two_digit) {
|
||||
if (!within_two_digit) {
|
||||
return fmt::format("/{}.nca", Common::HexToString(nca_id, second_hex_upper));
|
||||
}
|
||||
bool within_two_digit, bool cnmt_suffix) {
|
||||
if (!within_two_digit)
|
||||
return fmt::format(cnmt_suffix ? "{}.cnmt.nca" : "/{}.nca",
|
||||
Common::HexToString(nca_id, second_hex_upper));
|
||||
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
mbedtls_sha256(nca_id.data(), nca_id.size(), hash.data(), 0);
|
||||
return fmt::format("/000000{:02X}/{}.nca", hash[0],
|
||||
return fmt::format(cnmt_suffix ? "/000000{:02X}/{}.cnmt.nca" : "/000000{:02X}/{}.nca", hash[0],
|
||||
Common::HexToString(nca_id, second_hex_upper));
|
||||
}
|
||||
|
||||
@ -127,6 +131,156 @@ std::vector<ContentProviderEntry> ContentProvider::ListEntries() const {
|
||||
return ListEntriesFilter(std::nullopt, std::nullopt, std::nullopt);
|
||||
}
|
||||
|
||||
PlaceholderCache::PlaceholderCache(VirtualDir dir_) : dir(std::move(dir_)) {}
|
||||
|
||||
bool PlaceholderCache::Create(const NcaID& id, u64 size) const {
|
||||
const auto path = GetRelativePathFromNcaID(id, false, true, false);
|
||||
|
||||
if (dir->GetFileRelative(path) != nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
mbedtls_sha256(id.data(), id.size(), hash.data(), 0);
|
||||
const auto dirname = fmt::format("000000{:02X}", hash[0]);
|
||||
|
||||
const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
|
||||
|
||||
if (dir2 == nullptr)
|
||||
return false;
|
||||
|
||||
const auto file = dir2->CreateFile(fmt::format("{}.nca", Common::HexToString(id, false)));
|
||||
|
||||
if (file == nullptr)
|
||||
return false;
|
||||
|
||||
return file->Resize(size);
|
||||
}
|
||||
|
||||
bool PlaceholderCache::Delete(const NcaID& id) const {
|
||||
const auto path = GetRelativePathFromNcaID(id, false, true, false);
|
||||
|
||||
if (dir->GetFileRelative(path) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
mbedtls_sha256(id.data(), id.size(), hash.data(), 0);
|
||||
const auto dirname = fmt::format("000000{:02X}", hash[0]);
|
||||
|
||||
const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
|
||||
|
||||
const auto res = dir2->DeleteFile(fmt::format("{}.nca", Common::HexToString(id, false)));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool PlaceholderCache::Exists(const NcaID& id) const {
|
||||
const auto path = GetRelativePathFromNcaID(id, false, true, false);
|
||||
|
||||
return dir->GetFileRelative(path) != nullptr;
|
||||
}
|
||||
|
||||
bool PlaceholderCache::Write(const NcaID& id, u64 offset, const std::vector<u8>& data) const {
|
||||
const auto path = GetRelativePathFromNcaID(id, false, true, false);
|
||||
const auto file = dir->GetFileRelative(path);
|
||||
|
||||
if (file == nullptr)
|
||||
return false;
|
||||
|
||||
return file->WriteBytes(data, offset) == data.size();
|
||||
}
|
||||
|
||||
bool PlaceholderCache::Register(RegisteredCache* cache, const NcaID& placeholder,
|
||||
const NcaID& install) const {
|
||||
const auto path = GetRelativePathFromNcaID(placeholder, false, true, false);
|
||||
const auto file = dir->GetFileRelative(path);
|
||||
|
||||
if (file == nullptr)
|
||||
return false;
|
||||
|
||||
const auto res = cache->RawInstallNCA(NCA{file}, &VfsRawCopy, false, install);
|
||||
|
||||
if (res != InstallResult::Success)
|
||||
return false;
|
||||
|
||||
return Delete(placeholder);
|
||||
}
|
||||
|
||||
bool PlaceholderCache::CleanAll() const {
|
||||
return dir->GetParentDirectory()->CleanSubdirectoryRecursive(dir->GetName());
|
||||
}
|
||||
|
||||
std::optional<std::array<u8, 0x10>> PlaceholderCache::GetRightsID(const NcaID& id) const {
|
||||
const auto path = GetRelativePathFromNcaID(id, false, true, false);
|
||||
const auto file = dir->GetFileRelative(path);
|
||||
|
||||
if (file == nullptr)
|
||||
return std::nullopt;
|
||||
|
||||
NCA nca{file};
|
||||
|
||||
if (nca.GetStatus() != Loader::ResultStatus::Success &&
|
||||
nca.GetStatus() != Loader::ResultStatus::ErrorMissingBKTRBaseRomFS) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const auto rights_id = nca.GetRightsId();
|
||||
if (rights_id == NcaID{})
|
||||
return std::nullopt;
|
||||
|
||||
return rights_id;
|
||||
}
|
||||
|
||||
u64 PlaceholderCache::Size(const NcaID& id) const {
|
||||
const auto path = GetRelativePathFromNcaID(id, false, true, false);
|
||||
const auto file = dir->GetFileRelative(path);
|
||||
|
||||
if (file == nullptr)
|
||||
return 0;
|
||||
|
||||
return file->GetSize();
|
||||
}
|
||||
|
||||
bool PlaceholderCache::SetSize(const NcaID& id, u64 new_size) const {
|
||||
const auto path = GetRelativePathFromNcaID(id, false, true, false);
|
||||
const auto file = dir->GetFileRelative(path);
|
||||
|
||||
if (file == nullptr)
|
||||
return false;
|
||||
|
||||
return file->Resize(new_size);
|
||||
}
|
||||
|
||||
std::vector<NcaID> PlaceholderCache::List() const {
|
||||
std::vector<NcaID> out;
|
||||
for (const auto& sdir : dir->GetSubdirectories()) {
|
||||
for (const auto& file : sdir->GetFiles()) {
|
||||
const auto name = file->GetName();
|
||||
if (name.length() == 36 && name[32] == '.' && name[33] == 'n' && name[34] == 'c' &&
|
||||
name[35] == 'a') {
|
||||
out.push_back(Common::HexStringToArray<0x10>(name.substr(0, 32)));
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
NcaID PlaceholderCache::Generate() {
|
||||
std::random_device device;
|
||||
std::mt19937 gen(device());
|
||||
std::uniform_int_distribution<u64> distribution(1, std::numeric_limits<u64>::max());
|
||||
|
||||
NcaID out{};
|
||||
|
||||
const auto v1 = distribution(gen);
|
||||
const auto v2 = distribution(gen);
|
||||
std::memcpy(out.data(), &v1, sizeof(u64));
|
||||
std::memcpy(out.data() + sizeof(u64), &v2, sizeof(u64));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
|
||||
std::string_view path) const {
|
||||
const auto file = dir->GetFileRelative(path);
|
||||
@ -169,14 +323,18 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
|
||||
|
||||
VirtualFile RegisteredCache::GetFileAtID(NcaID id) const {
|
||||
VirtualFile file;
|
||||
// Try all four modes of file storage:
|
||||
// (bit 1 = uppercase/lower, bit 0 = within a two-digit dir)
|
||||
// 00: /000000**/{:032X}.nca
|
||||
// 01: /{:032X}.nca
|
||||
// 10: /000000**/{:032x}.nca
|
||||
// 11: /{:032x}.nca
|
||||
for (u8 i = 0; i < 4; ++i) {
|
||||
const auto path = GetRelativePathFromNcaID(id, (i & 0b10) == 0, (i & 0b01) == 0);
|
||||
// Try all five relevant modes of file storage:
|
||||
// (bit 2 = uppercase/lower, bit 1 = within a two-digit dir, bit 0 = .cnmt suffix)
|
||||
// 000: /000000**/{:032X}.nca
|
||||
// 010: /{:032X}.nca
|
||||
// 100: /000000**/{:032x}.nca
|
||||
// 110: /{:032x}.nca
|
||||
// 111: /{:032x}.cnmt.nca
|
||||
for (u8 i = 0; i < 8; ++i) {
|
||||
if ((i % 2) == 1 && i != 7)
|
||||
continue;
|
||||
const auto path =
|
||||
GetRelativePathFromNcaID(id, (i & 0b100) == 0, (i & 0b010) == 0, (i & 0b001) == 0b001);
|
||||
file = OpenFileOrDirectoryConcat(dir, path);
|
||||
if (file != nullptr)
|
||||
return file;
|
||||
@ -472,7 +630,7 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
|
||||
memcpy(id.data(), hash.data(), 16);
|
||||
}
|
||||
|
||||
std::string path = GetRelativePathFromNcaID(id, false, true);
|
||||
std::string path = GetRelativePathFromNcaID(id, false, true, false);
|
||||
|
||||
if (GetFileAtID(id) != nullptr && !overwrite_if_exists) {
|
||||
LOG_WARNING(Loader, "Attempting to overwrite existing NCA. Skipping...");
|
||||
|
@ -25,6 +25,8 @@ enum class NCAContentType : u8;
|
||||
enum class TitleType : u8;
|
||||
|
||||
struct ContentRecord;
|
||||
struct MetaRecord;
|
||||
class RegisteredCache;
|
||||
|
||||
using NcaID = std::array<u8, 0x10>;
|
||||
using ContentProviderParsingFunction = std::function<VirtualFile(const VirtualFile&, const NcaID&)>;
|
||||
@ -89,6 +91,27 @@ protected:
|
||||
Core::Crypto::KeyManager keys;
|
||||
};
|
||||
|
||||
class PlaceholderCache {
|
||||
public:
|
||||
explicit PlaceholderCache(VirtualDir dir);
|
||||
|
||||
bool Create(const NcaID& id, u64 size) const;
|
||||
bool Delete(const NcaID& id) const;
|
||||
bool Exists(const NcaID& id) const;
|
||||
bool Write(const NcaID& id, u64 offset, const std::vector<u8>& data) const;
|
||||
bool Register(RegisteredCache* cache, const NcaID& placeholder, const NcaID& install) const;
|
||||
bool CleanAll() const;
|
||||
std::optional<std::array<u8, 0x10>> GetRightsID(const NcaID& id) const;
|
||||
u64 Size(const NcaID& id) const;
|
||||
bool SetSize(const NcaID& id, u64 new_size) const;
|
||||
std::vector<NcaID> List() const;
|
||||
|
||||
static NcaID Generate();
|
||||
|
||||
private:
|
||||
VirtualDir dir;
|
||||
};
|
||||
|
||||
/*
|
||||
* A class that catalogues NCAs in the registered directory structure.
|
||||
* Nintendo's registered format follows this structure:
|
||||
@ -103,6 +126,8 @@ protected:
|
||||
* when 4GB splitting can be ignored.)
|
||||
*/
|
||||
class RegisteredCache : public ContentProvider {
|
||||
friend class PlaceholderCache;
|
||||
|
||||
public:
|
||||
// Parsing function defines the conversion from raw file to NCA. If there are other steps
|
||||
// besides creating the NCA from the file (e.g. NAX0 on SD Card), that should go in a custom
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/card_image.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
@ -34,7 +35,7 @@ void RomFSFactory::SetPackedUpdate(VirtualFile update_raw) {
|
||||
this->update_raw = std::move(update_raw);
|
||||
}
|
||||
|
||||
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
|
||||
ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() const {
|
||||
if (!updatable)
|
||||
return MakeResult<VirtualFile>(file);
|
||||
|
||||
@ -43,7 +44,8 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess() {
|
||||
patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw));
|
||||
}
|
||||
|
||||
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, ContentRecordType type) {
|
||||
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage,
|
||||
ContentRecordType type) const {
|
||||
std::shared_ptr<NCA> res;
|
||||
|
||||
switch (storage) {
|
||||
@ -51,13 +53,17 @@ ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage, Conte
|
||||
res = Core::System::GetInstance().GetContentProvider().GetEntry(title_id, type);
|
||||
break;
|
||||
case StorageId::NandSystem:
|
||||
res = Service::FileSystem::GetSystemNANDContents()->GetEntry(title_id, type);
|
||||
res =
|
||||
Core::System::GetInstance().GetFileSystemController().GetSystemNANDContents()->GetEntry(
|
||||
title_id, type);
|
||||
break;
|
||||
case StorageId::NandUser:
|
||||
res = Service::FileSystem::GetUserNANDContents()->GetEntry(title_id, type);
|
||||
res = Core::System::GetInstance().GetFileSystemController().GetUserNANDContents()->GetEntry(
|
||||
title_id, type);
|
||||
break;
|
||||
case StorageId::SdCard:
|
||||
res = Service::FileSystem::GetSDMCContents()->GetEntry(title_id, type);
|
||||
res = Core::System::GetInstance().GetFileSystemController().GetSDMCContents()->GetEntry(
|
||||
title_id, type);
|
||||
break;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Unimplemented storage_id={:02X}", static_cast<u8>(storage));
|
||||
|
@ -33,8 +33,8 @@ public:
|
||||
~RomFSFactory();
|
||||
|
||||
void SetPackedUpdate(VirtualFile update_raw);
|
||||
ResultVal<VirtualFile> OpenCurrentProcess();
|
||||
ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type);
|
||||
ResultVal<VirtualFile> OpenCurrentProcess() const;
|
||||
ResultVal<VirtualFile> Open(u64 title_id, StorageId storage, ContentRecordType type) const;
|
||||
|
||||
private:
|
||||
VirtualFile file;
|
||||
|
@ -15,22 +15,8 @@ namespace FileSys {
|
||||
|
||||
constexpr char SAVE_DATA_SIZE_FILENAME[] = ".yuzu_save_size";
|
||||
|
||||
std::string SaveDataDescriptor::DebugInfo() const {
|
||||
return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, save_id={:016X}, "
|
||||
"rank={}, index={}]",
|
||||
static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id,
|
||||
static_cast<u8>(rank), index);
|
||||
}
|
||||
|
||||
SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
|
||||
// Delete all temporary storages
|
||||
// On hardware, it is expected that temporary storage be empty at first use.
|
||||
dir->DeleteSubdirectoryRecursive("temp");
|
||||
}
|
||||
|
||||
SaveDataFactory::~SaveDataFactory() = default;
|
||||
|
||||
ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, const SaveDataDescriptor& meta) {
|
||||
namespace {
|
||||
void PrintSaveDataDescriptorWarnings(SaveDataDescriptor meta) {
|
||||
if (meta.type == SaveDataType::SystemSaveData || meta.type == SaveDataType::SaveData) {
|
||||
if (meta.zero_1 != 0) {
|
||||
LOG_WARNING(Service_FS,
|
||||
@ -65,23 +51,51 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, const SaveDat
|
||||
"non-zero ({:016X}{:016X})",
|
||||
meta.user_id[1], meta.user_id[0]);
|
||||
}
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
std::string save_directory =
|
||||
std::string SaveDataDescriptor::DebugInfo() const {
|
||||
return fmt::format("[type={:02X}, title_id={:016X}, user_id={:016X}{:016X}, "
|
||||
"save_id={:016X}, "
|
||||
"rank={}, index={}]",
|
||||
static_cast<u8>(type), title_id, user_id[1], user_id[0], save_id,
|
||||
static_cast<u8>(rank), index);
|
||||
}
|
||||
|
||||
SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
|
||||
// Delete all temporary storages
|
||||
// On hardware, it is expected that temporary storage be empty at first use.
|
||||
dir->DeleteSubdirectoryRecursive("temp");
|
||||
}
|
||||
|
||||
SaveDataFactory::~SaveDataFactory() = default;
|
||||
|
||||
ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
|
||||
const SaveDataDescriptor& meta) const {
|
||||
PrintSaveDataDescriptorWarnings(meta);
|
||||
|
||||
const auto save_directory =
|
||||
GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
|
||||
|
||||
// TODO(DarkLordZach): Try to not create when opening, there are dedicated create save methods.
|
||||
// But, user_ids don't match so this works for now.
|
||||
auto out = dir->CreateDirectoryRelative(save_directory);
|
||||
|
||||
// Return an error if the save data doesn't actually exist.
|
||||
if (out == nullptr) {
|
||||
// TODO(DarkLordZach): Find out correct error code.
|
||||
return ResultCode(-1);
|
||||
}
|
||||
|
||||
return MakeResult<VirtualDir>(std::move(out));
|
||||
}
|
||||
|
||||
ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
|
||||
const SaveDataDescriptor& meta) const {
|
||||
|
||||
const auto save_directory =
|
||||
GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
|
||||
|
||||
auto out = dir->GetDirectoryRelative(save_directory);
|
||||
|
||||
if (out == nullptr) {
|
||||
// TODO(bunnei): This is a work-around to always create a save data directory if it does not
|
||||
// already exist. This is a hack, as we do not understand yet how this works on hardware.
|
||||
// Without a save data directory, many games will assert on boot. This should not have any
|
||||
// bad side-effects.
|
||||
out = dir->CreateDirectoryRelative(save_directory);
|
||||
}
|
||||
|
||||
// Return an error if the save data doesn't actually exist.
|
||||
if (out == nullptr) {
|
||||
// TODO(Subv): Find out correct error code.
|
||||
@ -152,7 +166,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
|
||||
}
|
||||
|
||||
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
|
||||
SaveDataSize new_value) {
|
||||
SaveDataSize new_value) const {
|
||||
const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
|
||||
const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
|
||||
|
||||
|
@ -64,7 +64,8 @@ public:
|
||||
explicit SaveDataFactory(VirtualDir dir);
|
||||
~SaveDataFactory();
|
||||
|
||||
ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataDescriptor& meta);
|
||||
ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataDescriptor& meta) const;
|
||||
ResultVal<VirtualDir> Open(SaveDataSpaceId space, const SaveDataDescriptor& meta) const;
|
||||
|
||||
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
|
||||
|
||||
@ -73,7 +74,8 @@ public:
|
||||
u128 user_id, u64 save_id);
|
||||
|
||||
SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const;
|
||||
void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id, SaveDataSize new_value);
|
||||
void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
|
||||
SaveDataSize new_value) const;
|
||||
|
||||
private:
|
||||
VirtualDir dir;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/sdmc_factory.h"
|
||||
#include "core/file_sys/xts_archive.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
@ -14,16 +15,38 @@ SDMCFactory::SDMCFactory(VirtualDir dir_)
|
||||
GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/registered"),
|
||||
[](const VirtualFile& file, const NcaID& id) {
|
||||
return NAX{file, id}.GetDecrypted();
|
||||
})) {}
|
||||
})),
|
||||
placeholder(std::make_unique<PlaceholderCache>(
|
||||
GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents/placehld"))) {}
|
||||
|
||||
SDMCFactory::~SDMCFactory() = default;
|
||||
|
||||
ResultVal<VirtualDir> SDMCFactory::Open() {
|
||||
ResultVal<VirtualDir> SDMCFactory::Open() const {
|
||||
return MakeResult<VirtualDir>(dir);
|
||||
}
|
||||
|
||||
VirtualDir SDMCFactory::GetSDMCContentDirectory() const {
|
||||
return GetOrCreateDirectoryRelative(dir, "/Nintendo/Contents");
|
||||
}
|
||||
|
||||
RegisteredCache* SDMCFactory::GetSDMCContents() const {
|
||||
return contents.get();
|
||||
}
|
||||
|
||||
PlaceholderCache* SDMCFactory::GetSDMCPlaceholder() const {
|
||||
return placeholder.get();
|
||||
}
|
||||
|
||||
VirtualDir SDMCFactory::GetImageDirectory() const {
|
||||
return GetOrCreateDirectoryRelative(dir, "/Nintendo/Album");
|
||||
}
|
||||
|
||||
u64 SDMCFactory::GetSDMCFreeSpace() const {
|
||||
return GetSDMCTotalSpace() - dir->GetSize();
|
||||
}
|
||||
|
||||
u64 SDMCFactory::GetSDMCTotalSpace() const {
|
||||
return static_cast<u64>(Settings::values.sdmc_size);
|
||||
}
|
||||
|
||||
} // namespace FileSys
|
||||
|
@ -11,6 +11,7 @@
|
||||
namespace FileSys {
|
||||
|
||||
class RegisteredCache;
|
||||
class PlaceholderCache;
|
||||
|
||||
/// File system interface to the SDCard archive
|
||||
class SDMCFactory {
|
||||
@ -18,13 +19,23 @@ public:
|
||||
explicit SDMCFactory(VirtualDir dir);
|
||||
~SDMCFactory();
|
||||
|
||||
ResultVal<VirtualDir> Open();
|
||||
ResultVal<VirtualDir> Open() const;
|
||||
|
||||
VirtualDir GetSDMCContentDirectory() const;
|
||||
|
||||
RegisteredCache* GetSDMCContents() const;
|
||||
PlaceholderCache* GetSDMCPlaceholder() const;
|
||||
|
||||
VirtualDir GetImageDirectory() const;
|
||||
|
||||
u64 GetSDMCFreeSpace() const;
|
||||
u64 GetSDMCTotalSpace() const;
|
||||
|
||||
private:
|
||||
VirtualDir dir;
|
||||
|
||||
std::unique_ptr<RegisteredCache> contents;
|
||||
std::unique_ptr<PlaceholderCache> placeholder;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
@ -248,7 +248,8 @@ void NSP::InitializeExeFSAndRomFS(const std::vector<VirtualFile>& files) {
|
||||
|
||||
void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
|
||||
for (const auto& outer_file : files) {
|
||||
if (outer_file->GetName().substr(outer_file->GetName().size() - 9) != ".cnmt.nca") {
|
||||
if (outer_file->GetName().size() < 9 ||
|
||||
outer_file->GetName().substr(outer_file->GetName().size() - 9) != ".cnmt.nca") {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1143,13 +1143,21 @@ void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest(
|
||||
|
||||
void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u128 uid = rp.PopRaw<u128>(); // What does this do?
|
||||
LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]);
|
||||
u128 user_id = rp.PopRaw<u128>();
|
||||
|
||||
LOG_DEBUG(Service_AM, "called, uid={:016X}{:016X}", user_id[1], user_id[0]);
|
||||
|
||||
FileSys::SaveDataDescriptor descriptor{};
|
||||
descriptor.title_id = Core::CurrentProcess()->GetTitleID();
|
||||
descriptor.user_id = user_id;
|
||||
descriptor.type = FileSys::SaveDataType::SaveData;
|
||||
const auto res = system.GetFileSystemController().CreateSaveData(
|
||||
FileSys::SaveDataSpaceId::NandUser, descriptor);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(res.Code());
|
||||
rb.Push<u64>(0);
|
||||
} // namespace Service::AM
|
||||
}
|
||||
|
||||
void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) {
|
||||
// Takes an input u32 Result, no output.
|
||||
@ -1261,8 +1269,8 @@ void IApplicationFunctions::ExtendSaveData(Kernel::HLERequestContext& ctx) {
|
||||
"new_journal={:016X}",
|
||||
static_cast<u8>(type), user_id[1], user_id[0], new_normal_size, new_journal_size);
|
||||
|
||||
const auto title_id = system.CurrentProcess()->GetTitleID();
|
||||
FileSystem::WriteSaveDataSize(type, title_id, user_id, {new_normal_size, new_journal_size});
|
||||
system.GetFileSystemController().WriteSaveDataSize(
|
||||
type, system.CurrentProcess()->GetTitleID(), user_id, {new_normal_size, new_journal_size});
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@ -1281,8 +1289,8 @@ void IApplicationFunctions::GetSaveDataSize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_AM, "called with type={:02X}, user_id={:016X}{:016X}", static_cast<u8>(type),
|
||||
user_id[1], user_id[0]);
|
||||
|
||||
const auto title_id = system.CurrentProcess()->GetTitleID();
|
||||
const auto size = FileSystem::ReadSaveDataSize(type, title_id, user_id);
|
||||
const auto size = system.GetFileSystemController().ReadSaveDataSize(
|
||||
type, system.CurrentProcess()->GetTitleID(), user_id);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
@ -9,6 +9,10 @@
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service {
|
||||
namespace FileSystem {
|
||||
class FileSystemController;
|
||||
}
|
||||
|
||||
namespace NVFlinger {
|
||||
class NVFlinger;
|
||||
}
|
||||
|
@ -9,6 +9,10 @@
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service {
|
||||
namespace FileSystem {
|
||||
class FileSystemController;
|
||||
}
|
||||
|
||||
namespace NVFlinger {
|
||||
class NVFlinger;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "common/file_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/bis_factory.h"
|
||||
#include "core/file_sys/card_image.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/file_sys/mode.h"
|
||||
@ -25,14 +26,10 @@
|
||||
#include "core/hle/service/filesystem/fsp_pr.h"
|
||||
#include "core/hle/service/filesystem/fsp_srv.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Service::FileSystem {
|
||||
|
||||
// Size of emulated sd card free space, reported in bytes.
|
||||
// Just using 32GB because thats reasonable
|
||||
// TODO(DarkLordZach): Eventually make this configurable in settings.
|
||||
constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000;
|
||||
|
||||
// A default size for normal/journal save data size if application control metadata cannot be found.
|
||||
// This should be large enough to satisfy even the most extreme requirements (~4.2GB)
|
||||
constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000;
|
||||
@ -226,13 +223,6 @@ ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const s
|
||||
return MakeResult(dir);
|
||||
}
|
||||
|
||||
u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const {
|
||||
if (backing->IsWritable())
|
||||
return EMULATED_SD_REPORTED_SIZE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
|
||||
const std::string& path_) const {
|
||||
std::string path(FileUtil::SanitizePath(path_));
|
||||
@ -251,44 +241,39 @@ ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
|
||||
return FileSys::ERROR_PATH_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of registered file systems, identified by type. Once an file system is registered here, it
|
||||
* is never removed until UnregisterFileSystems is called.
|
||||
*/
|
||||
static std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
|
||||
static std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
|
||||
static std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
|
||||
static std::unique_ptr<FileSys::BISFactory> bis_factory;
|
||||
FileSystemController::FileSystemController() = default;
|
||||
|
||||
ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
|
||||
ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second RomFS");
|
||||
FileSystemController::~FileSystemController() = default;
|
||||
|
||||
ResultCode FileSystemController::RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
|
||||
romfs_factory = std::move(factory);
|
||||
LOG_DEBUG(Service_FS, "Registered RomFS");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory) {
|
||||
ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second save data");
|
||||
ResultCode FileSystemController::RegisterSaveData(
|
||||
std::unique_ptr<FileSys::SaveDataFactory>&& factory) {
|
||||
ASSERT_MSG(save_data_factory == nullptr, "Tried to register a second save data");
|
||||
save_data_factory = std::move(factory);
|
||||
LOG_DEBUG(Service_FS, "Registered save data");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
|
||||
ResultCode FileSystemController::RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
|
||||
ASSERT_MSG(sdmc_factory == nullptr, "Tried to register a second SDMC");
|
||||
sdmc_factory = std::move(factory);
|
||||
LOG_DEBUG(Service_FS, "Registered SDMC");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
|
||||
ResultCode FileSystemController::RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
|
||||
ASSERT_MSG(bis_factory == nullptr, "Tried to register a second BIS");
|
||||
bis_factory = std::move(factory);
|
||||
LOG_DEBUG(Service_FS, "Registered BIS");
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void SetPackedUpdate(FileSys::VirtualFile update_raw) {
|
||||
void FileSystemController::SetPackedUpdate(FileSys::VirtualFile update_raw) {
|
||||
LOG_TRACE(Service_FS, "Setting packed update for romfs");
|
||||
|
||||
if (romfs_factory == nullptr)
|
||||
@ -297,7 +282,7 @@ void SetPackedUpdate(FileSys::VirtualFile update_raw) {
|
||||
romfs_factory->SetPackedUpdate(std::move(update_raw));
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() {
|
||||
ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFSCurrentProcess() const {
|
||||
LOG_TRACE(Service_FS, "Opening RomFS for current process");
|
||||
|
||||
if (romfs_factory == nullptr) {
|
||||
@ -308,8 +293,8 @@ ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() {
|
||||
return romfs_factory->OpenCurrentProcess();
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
|
||||
FileSys::ContentRecordType type) {
|
||||
ResultVal<FileSys::VirtualFile> FileSystemController::OpenRomFS(
|
||||
u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const {
|
||||
LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}",
|
||||
title_id, static_cast<u8>(storage_id), static_cast<u8>(type));
|
||||
|
||||
@ -321,8 +306,20 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
|
||||
return romfs_factory->Open(title_id, storage_id, type);
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
|
||||
const FileSys::SaveDataDescriptor& descriptor) {
|
||||
ResultVal<FileSys::VirtualDir> FileSystemController::CreateSaveData(
|
||||
FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const {
|
||||
LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}",
|
||||
static_cast<u8>(space), save_struct.DebugInfo());
|
||||
|
||||
if (save_data_factory == nullptr) {
|
||||
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||
}
|
||||
|
||||
return save_data_factory->Create(space, save_struct);
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveData(
|
||||
FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& descriptor) const {
|
||||
LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}",
|
||||
static_cast<u8>(space), descriptor.DebugInfo());
|
||||
|
||||
@ -333,7 +330,8 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
|
||||
return save_data_factory->Open(space, descriptor);
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) {
|
||||
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSaveDataSpace(
|
||||
FileSys::SaveDataSpaceId space) const {
|
||||
LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space));
|
||||
|
||||
if (save_data_factory == nullptr) {
|
||||
@ -343,7 +341,7 @@ ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space)
|
||||
return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space));
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> OpenSDMC() {
|
||||
ResultVal<FileSys::VirtualDir> FileSystemController::OpenSDMC() const {
|
||||
LOG_TRACE(Service_FS, "Opening SDMC");
|
||||
|
||||
if (sdmc_factory == nullptr) {
|
||||
@ -353,7 +351,92 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
|
||||
return sdmc_factory->Open();
|
||||
}
|
||||
|
||||
FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id) {
|
||||
ResultVal<FileSys::VirtualDir> FileSystemController::OpenBISPartition(
|
||||
FileSys::BisPartitionId id) const {
|
||||
LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", static_cast<u32>(id));
|
||||
|
||||
if (bis_factory == nullptr) {
|
||||
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||
}
|
||||
|
||||
auto part = bis_factory->OpenPartition(id);
|
||||
if (part == nullptr) {
|
||||
return FileSys::ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return MakeResult<FileSys::VirtualDir>(std::move(part));
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualFile> FileSystemController::OpenBISPartitionStorage(
|
||||
FileSys::BisPartitionId id) const {
|
||||
LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", static_cast<u32>(id));
|
||||
|
||||
if (bis_factory == nullptr) {
|
||||
return FileSys::ERROR_ENTITY_NOT_FOUND;
|
||||
}
|
||||
|
||||
auto part = bis_factory->OpenPartitionStorage(id);
|
||||
if (part == nullptr) {
|
||||
return FileSys::ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return MakeResult<FileSys::VirtualFile>(std::move(part));
|
||||
}
|
||||
|
||||
u64 FileSystemController::GetFreeSpaceSize(FileSys::StorageId id) const {
|
||||
switch (id) {
|
||||
case FileSys::StorageId::None:
|
||||
case FileSys::StorageId::GameCard:
|
||||
return 0;
|
||||
case FileSys::StorageId::SdCard:
|
||||
if (sdmc_factory == nullptr)
|
||||
return 0;
|
||||
return sdmc_factory->GetSDMCFreeSpace();
|
||||
case FileSys::StorageId::Host:
|
||||
if (bis_factory == nullptr)
|
||||
return 0;
|
||||
return bis_factory->GetSystemNANDFreeSpace() + bis_factory->GetUserNANDFreeSpace();
|
||||
case FileSys::StorageId::NandSystem:
|
||||
if (bis_factory == nullptr)
|
||||
return 0;
|
||||
return bis_factory->GetSystemNANDFreeSpace();
|
||||
case FileSys::StorageId::NandUser:
|
||||
if (bis_factory == nullptr)
|
||||
return 0;
|
||||
return bis_factory->GetUserNANDFreeSpace();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u64 FileSystemController::GetTotalSpaceSize(FileSys::StorageId id) const {
|
||||
switch (id) {
|
||||
case FileSys::StorageId::None:
|
||||
case FileSys::StorageId::GameCard:
|
||||
return 0;
|
||||
case FileSys::StorageId::SdCard:
|
||||
if (sdmc_factory == nullptr)
|
||||
return 0;
|
||||
return sdmc_factory->GetSDMCTotalSpace();
|
||||
case FileSys::StorageId::Host:
|
||||
if (bis_factory == nullptr)
|
||||
return 0;
|
||||
return bis_factory->GetFullNANDTotalSpace();
|
||||
case FileSys::StorageId::NandSystem:
|
||||
if (bis_factory == nullptr)
|
||||
return 0;
|
||||
return bis_factory->GetSystemNANDTotalSpace();
|
||||
case FileSys::StorageId::NandUser:
|
||||
if (bis_factory == nullptr)
|
||||
return 0;
|
||||
return bis_factory->GetUserNANDTotalSpace();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataType type,
|
||||
u64 title_id, u128 user_id) const {
|
||||
if (save_data_factory == nullptr) {
|
||||
return {0, 0};
|
||||
}
|
||||
@ -385,13 +468,32 @@ FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
|
||||
return value;
|
||||
}
|
||||
|
||||
void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
|
||||
FileSys::SaveDataSize new_value) {
|
||||
void FileSystemController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
|
||||
FileSys::SaveDataSize new_value) const {
|
||||
if (save_data_factory != nullptr)
|
||||
save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value);
|
||||
}
|
||||
|
||||
FileSys::RegisteredCache* GetSystemNANDContents() {
|
||||
void FileSystemController::SetGameCard(FileSys::VirtualFile file) {
|
||||
gamecard = std::make_unique<FileSys::XCI>(file);
|
||||
const auto dir = gamecard->ConcatenatedPseudoDirectory();
|
||||
gamecard_registered = std::make_unique<FileSys::RegisteredCache>(dir);
|
||||
gamecard_placeholder = std::make_unique<FileSys::PlaceholderCache>(dir);
|
||||
}
|
||||
|
||||
FileSys::XCI* FileSystemController::GetGameCard() const {
|
||||
return gamecard.get();
|
||||
}
|
||||
|
||||
FileSys::RegisteredCache* FileSystemController::GetGameCardContents() const {
|
||||
return gamecard_registered.get();
|
||||
}
|
||||
|
||||
FileSys::PlaceholderCache* FileSystemController::GetGameCardPlaceholder() const {
|
||||
return gamecard_placeholder.get();
|
||||
}
|
||||
|
||||
FileSys::RegisteredCache* FileSystemController::GetSystemNANDContents() const {
|
||||
LOG_TRACE(Service_FS, "Opening System NAND Contents");
|
||||
|
||||
if (bis_factory == nullptr)
|
||||
@ -400,7 +502,7 @@ FileSys::RegisteredCache* GetSystemNANDContents() {
|
||||
return bis_factory->GetSystemNANDContents();
|
||||
}
|
||||
|
||||
FileSys::RegisteredCache* GetUserNANDContents() {
|
||||
FileSys::RegisteredCache* FileSystemController::GetUserNANDContents() const {
|
||||
LOG_TRACE(Service_FS, "Opening User NAND Contents");
|
||||
|
||||
if (bis_factory == nullptr)
|
||||
@ -409,7 +511,7 @@ FileSys::RegisteredCache* GetUserNANDContents() {
|
||||
return bis_factory->GetUserNANDContents();
|
||||
}
|
||||
|
||||
FileSys::RegisteredCache* GetSDMCContents() {
|
||||
FileSys::RegisteredCache* FileSystemController::GetSDMCContents() const {
|
||||
LOG_TRACE(Service_FS, "Opening SDMC Contents");
|
||||
|
||||
if (sdmc_factory == nullptr)
|
||||
@ -418,7 +520,143 @@ FileSys::RegisteredCache* GetSDMCContents() {
|
||||
return sdmc_factory->GetSDMCContents();
|
||||
}
|
||||
|
||||
FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
|
||||
FileSys::PlaceholderCache* FileSystemController::GetSystemNANDPlaceholder() const {
|
||||
LOG_TRACE(Service_FS, "Opening System NAND Placeholder");
|
||||
|
||||
if (bis_factory == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return bis_factory->GetSystemNANDPlaceholder();
|
||||
}
|
||||
|
||||
FileSys::PlaceholderCache* FileSystemController::GetUserNANDPlaceholder() const {
|
||||
LOG_TRACE(Service_FS, "Opening User NAND Placeholder");
|
||||
|
||||
if (bis_factory == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return bis_factory->GetUserNANDPlaceholder();
|
||||
}
|
||||
|
||||
FileSys::PlaceholderCache* FileSystemController::GetSDMCPlaceholder() const {
|
||||
LOG_TRACE(Service_FS, "Opening SDMC Placeholder");
|
||||
|
||||
if (sdmc_factory == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return sdmc_factory->GetSDMCPlaceholder();
|
||||
}
|
||||
|
||||
FileSys::RegisteredCache* FileSystemController::GetRegisteredCacheForStorage(
|
||||
FileSys::StorageId id) const {
|
||||
switch (id) {
|
||||
case FileSys::StorageId::None:
|
||||
case FileSys::StorageId::Host:
|
||||
UNIMPLEMENTED();
|
||||
return nullptr;
|
||||
case FileSys::StorageId::GameCard:
|
||||
return GetGameCardContents();
|
||||
case FileSys::StorageId::NandSystem:
|
||||
return GetSystemNANDContents();
|
||||
case FileSys::StorageId::NandUser:
|
||||
return GetUserNANDContents();
|
||||
case FileSys::StorageId::SdCard:
|
||||
return GetSDMCContents();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileSys::PlaceholderCache* FileSystemController::GetPlaceholderCacheForStorage(
|
||||
FileSys::StorageId id) const {
|
||||
switch (id) {
|
||||
case FileSys::StorageId::None:
|
||||
case FileSys::StorageId::Host:
|
||||
UNIMPLEMENTED();
|
||||
return nullptr;
|
||||
case FileSys::StorageId::GameCard:
|
||||
return GetGameCardPlaceholder();
|
||||
case FileSys::StorageId::NandSystem:
|
||||
return GetSystemNANDPlaceholder();
|
||||
case FileSys::StorageId::NandUser:
|
||||
return GetUserNANDPlaceholder();
|
||||
case FileSys::StorageId::SdCard:
|
||||
return GetSDMCPlaceholder();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileSys::VirtualDir FileSystemController::GetSystemNANDContentDirectory() const {
|
||||
LOG_TRACE(Service_FS, "Opening system NAND content directory");
|
||||
|
||||
if (bis_factory == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return bis_factory->GetSystemNANDContentDirectory();
|
||||
}
|
||||
|
||||
FileSys::VirtualDir FileSystemController::GetUserNANDContentDirectory() const {
|
||||
LOG_TRACE(Service_FS, "Opening user NAND content directory");
|
||||
|
||||
if (bis_factory == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return bis_factory->GetUserNANDContentDirectory();
|
||||
}
|
||||
|
||||
FileSys::VirtualDir FileSystemController::GetSDMCContentDirectory() const {
|
||||
LOG_TRACE(Service_FS, "Opening SDMC content directory");
|
||||
|
||||
if (sdmc_factory == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return sdmc_factory->GetSDMCContentDirectory();
|
||||
}
|
||||
|
||||
FileSys::VirtualDir FileSystemController::GetNANDImageDirectory() const {
|
||||
LOG_TRACE(Service_FS, "Opening NAND image directory");
|
||||
|
||||
if (bis_factory == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return bis_factory->GetImageDirectory();
|
||||
}
|
||||
|
||||
FileSys::VirtualDir FileSystemController::GetSDMCImageDirectory() const {
|
||||
LOG_TRACE(Service_FS, "Opening SDMC image directory");
|
||||
|
||||
if (sdmc_factory == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return sdmc_factory->GetImageDirectory();
|
||||
}
|
||||
|
||||
FileSys::VirtualDir FileSystemController::GetContentDirectory(ContentStorageId id) const {
|
||||
switch (id) {
|
||||
case ContentStorageId::System:
|
||||
return GetSystemNANDContentDirectory();
|
||||
case ContentStorageId::User:
|
||||
return GetUserNANDContentDirectory();
|
||||
case ContentStorageId::SdCard:
|
||||
return GetSDMCContentDirectory();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileSys::VirtualDir FileSystemController::GetImageDirectory(ImageDirectoryId id) const {
|
||||
switch (id) {
|
||||
case ImageDirectoryId::NAND:
|
||||
return GetNANDImageDirectory();
|
||||
case ImageDirectoryId::SdCard:
|
||||
return GetSDMCImageDirectory();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FileSys::VirtualDir FileSystemController::GetModificationLoadRoot(u64 title_id) const {
|
||||
LOG_TRACE(Service_FS, "Opening mod load root for tid={:016X}", title_id);
|
||||
|
||||
if (bis_factory == nullptr)
|
||||
@ -427,7 +665,7 @@ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
|
||||
return bis_factory->GetModificationLoadRoot(title_id);
|
||||
}
|
||||
|
||||
FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) {
|
||||
FileSys::VirtualDir FileSystemController::GetModificationDumpRoot(u64 title_id) const {
|
||||
LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id);
|
||||
|
||||
if (bis_factory == nullptr)
|
||||
@ -436,7 +674,7 @@ FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) {
|
||||
return bis_factory->GetModificationDumpRoot(title_id);
|
||||
}
|
||||
|
||||
void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
|
||||
void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
|
||||
if (overwrite) {
|
||||
bis_factory = nullptr;
|
||||
save_data_factory = nullptr;
|
||||
@ -473,11 +711,10 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
|
||||
}
|
||||
|
||||
void InstallInterfaces(Core::System& system) {
|
||||
romfs_factory = nullptr;
|
||||
CreateFactories(*system.GetFilesystem(), false);
|
||||
std::make_shared<FSP_LDR>()->InstallAsService(system.ServiceManager());
|
||||
std::make_shared<FSP_PR>()->InstallAsService(system.ServiceManager());
|
||||
std::make_shared<FSP_SRV>(system.GetReporter())->InstallAsService(system.ServiceManager());
|
||||
std::make_shared<FSP_SRV>(system.GetFileSystemController(), system.GetReporter())
|
||||
->InstallAsService(system.ServiceManager());
|
||||
}
|
||||
|
||||
} // namespace Service::FileSystem
|
||||
|
@ -14,10 +14,13 @@ namespace FileSys {
|
||||
class BISFactory;
|
||||
class RegisteredCache;
|
||||
class RegisteredCacheUnion;
|
||||
class PlaceholderCache;
|
||||
class RomFSFactory;
|
||||
class SaveDataFactory;
|
||||
class SDMCFactory;
|
||||
class XCI;
|
||||
|
||||
enum class BisPartitionId : u32;
|
||||
enum class ContentRecordType : u8;
|
||||
enum class Mode : u32;
|
||||
enum class SaveDataSpaceId : u8;
|
||||
@ -36,34 +39,91 @@ class ServiceManager;
|
||||
|
||||
namespace FileSystem {
|
||||
|
||||
ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory);
|
||||
ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory);
|
||||
ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
|
||||
ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
|
||||
enum class ContentStorageId : u32 {
|
||||
System,
|
||||
User,
|
||||
SdCard,
|
||||
};
|
||||
|
||||
void SetPackedUpdate(FileSys::VirtualFile update_raw);
|
||||
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess();
|
||||
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
|
||||
FileSys::ContentRecordType type);
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
|
||||
const FileSys::SaveDataDescriptor& descriptor);
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
|
||||
ResultVal<FileSys::VirtualDir> OpenSDMC();
|
||||
enum class ImageDirectoryId : u32 {
|
||||
NAND,
|
||||
SdCard,
|
||||
};
|
||||
|
||||
FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id);
|
||||
void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
|
||||
FileSys::SaveDataSize new_value);
|
||||
class FileSystemController {
|
||||
public:
|
||||
FileSystemController();
|
||||
~FileSystemController();
|
||||
|
||||
FileSys::RegisteredCache* GetSystemNANDContents();
|
||||
FileSys::RegisteredCache* GetUserNANDContents();
|
||||
FileSys::RegisteredCache* GetSDMCContents();
|
||||
ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory);
|
||||
ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory);
|
||||
ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
|
||||
ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
|
||||
|
||||
FileSys::VirtualDir GetModificationLoadRoot(u64 title_id);
|
||||
FileSys::VirtualDir GetModificationDumpRoot(u64 title_id);
|
||||
void SetPackedUpdate(FileSys::VirtualFile update_raw);
|
||||
ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() const;
|
||||
ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
|
||||
FileSys::ContentRecordType type) const;
|
||||
ResultVal<FileSys::VirtualDir> CreateSaveData(
|
||||
FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const;
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveData(
|
||||
FileSys::SaveDataSpaceId space, const FileSys::SaveDataDescriptor& save_struct) const;
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) const;
|
||||
ResultVal<FileSys::VirtualDir> OpenSDMC() const;
|
||||
ResultVal<FileSys::VirtualDir> OpenBISPartition(FileSys::BisPartitionId id) const;
|
||||
ResultVal<FileSys::VirtualFile> OpenBISPartitionStorage(FileSys::BisPartitionId id) const;
|
||||
|
||||
// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
|
||||
// above is called.
|
||||
void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
|
||||
u64 GetFreeSpaceSize(FileSys::StorageId id) const;
|
||||
u64 GetTotalSpaceSize(FileSys::StorageId id) const;
|
||||
|
||||
FileSys::SaveDataSize ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
|
||||
u128 user_id) const;
|
||||
void WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
|
||||
FileSys::SaveDataSize new_value) const;
|
||||
|
||||
void SetGameCard(FileSys::VirtualFile file);
|
||||
FileSys::XCI* GetGameCard() const;
|
||||
|
||||
FileSys::RegisteredCache* GetSystemNANDContents() const;
|
||||
FileSys::RegisteredCache* GetUserNANDContents() const;
|
||||
FileSys::RegisteredCache* GetSDMCContents() const;
|
||||
FileSys::RegisteredCache* GetGameCardContents() const;
|
||||
|
||||
FileSys::PlaceholderCache* GetSystemNANDPlaceholder() const;
|
||||
FileSys::PlaceholderCache* GetUserNANDPlaceholder() const;
|
||||
FileSys::PlaceholderCache* GetSDMCPlaceholder() const;
|
||||
FileSys::PlaceholderCache* GetGameCardPlaceholder() const;
|
||||
|
||||
FileSys::RegisteredCache* GetRegisteredCacheForStorage(FileSys::StorageId id) const;
|
||||
FileSys::PlaceholderCache* GetPlaceholderCacheForStorage(FileSys::StorageId id) const;
|
||||
|
||||
FileSys::VirtualDir GetSystemNANDContentDirectory() const;
|
||||
FileSys::VirtualDir GetUserNANDContentDirectory() const;
|
||||
FileSys::VirtualDir GetSDMCContentDirectory() const;
|
||||
|
||||
FileSys::VirtualDir GetNANDImageDirectory() const;
|
||||
FileSys::VirtualDir GetSDMCImageDirectory() const;
|
||||
|
||||
FileSys::VirtualDir GetContentDirectory(ContentStorageId id) const;
|
||||
FileSys::VirtualDir GetImageDirectory(ImageDirectoryId id) const;
|
||||
|
||||
FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) const;
|
||||
FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) const;
|
||||
|
||||
// Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function
|
||||
// above is called.
|
||||
void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite = true);
|
||||
|
||||
private:
|
||||
std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
|
||||
std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
|
||||
std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
|
||||
std::unique_ptr<FileSys::BISFactory> bis_factory;
|
||||
|
||||
std::unique_ptr<FileSys::XCI> gamecard;
|
||||
std::unique_ptr<FileSys::RegisteredCache> gamecard_registered;
|
||||
std::unique_ptr<FileSys::PlaceholderCache> gamecard_placeholder;
|
||||
};
|
||||
|
||||
void InstallInterfaces(Core::System& system);
|
||||
|
||||
@ -159,12 +219,6 @@ public:
|
||||
*/
|
||||
ResultVal<FileSys::VirtualDir> OpenDirectory(const std::string& path);
|
||||
|
||||
/**
|
||||
* Get the free space
|
||||
* @return The number of free bytes in the archive
|
||||
*/
|
||||
u64 GetFreeSpaceSize() const;
|
||||
|
||||
/**
|
||||
* Get the type of the specified path
|
||||
* @return The type of the specified path or error code
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "core/file_sys/mode.h"
|
||||
#include "core/file_sys/nca_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/romfs_factory.h"
|
||||
#include "core/file_sys/savedata_factory.h"
|
||||
#include "core/file_sys/system_archive/system_archive.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
@ -30,6 +31,18 @@
|
||||
|
||||
namespace Service::FileSystem {
|
||||
|
||||
struct SizeGetter {
|
||||
std::function<u64()> get_free_size;
|
||||
std::function<u64()> get_total_size;
|
||||
|
||||
static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) {
|
||||
return {
|
||||
[&fsc, id] { return fsc.GetFreeSpaceSize(id); },
|
||||
[&fsc, id] { return fsc.GetTotalSpaceSize(id); },
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
enum class FileSystemType : u8 {
|
||||
Invalid0 = 0,
|
||||
Invalid1 = 1,
|
||||
@ -289,8 +302,8 @@ private:
|
||||
|
||||
class IFileSystem final : public ServiceFramework<IFileSystem> {
|
||||
public:
|
||||
explicit IFileSystem(FileSys::VirtualDir backend)
|
||||
: ServiceFramework("IFileSystem"), backend(std::move(backend)) {
|
||||
explicit IFileSystem(FileSys::VirtualDir backend, SizeGetter size)
|
||||
: ServiceFramework("IFileSystem"), backend(std::move(backend)), size(std::move(size)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IFileSystem::CreateFile, "CreateFile"},
|
||||
{1, &IFileSystem::DeleteFile, "DeleteFile"},
|
||||
@ -467,14 +480,31 @@ public:
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void GetFreeSpaceSize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FS, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(size.get_free_size());
|
||||
}
|
||||
|
||||
void GetTotalSpaceSize(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FS, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 4};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(size.get_total_size());
|
||||
}
|
||||
|
||||
private:
|
||||
VfsDirectoryServiceWrapper backend;
|
||||
SizeGetter size;
|
||||
};
|
||||
|
||||
class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
|
||||
public:
|
||||
explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space)
|
||||
: ServiceFramework("ISaveDataInfoReader") {
|
||||
explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space, FileSystemController& fsc)
|
||||
: ServiceFramework("ISaveDataInfoReader"), fsc(fsc) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
|
||||
};
|
||||
@ -520,8 +550,13 @@ private:
|
||||
}
|
||||
|
||||
void FindAllSaves(FileSys::SaveDataSpaceId space) {
|
||||
const auto save_root = OpenSaveDataSpace(space);
|
||||
ASSERT(save_root.Succeeded());
|
||||
const auto save_root = fsc.OpenSaveDataSpace(space);
|
||||
|
||||
if (save_root.Failed() || *save_root == nullptr) {
|
||||
LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!",
|
||||
static_cast<u8>(space));
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& type : (*save_root)->GetSubdirectories()) {
|
||||
if (type->GetName() == "save") {
|
||||
@ -610,11 +645,13 @@ private:
|
||||
};
|
||||
static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
|
||||
|
||||
FileSystemController& fsc;
|
||||
std::vector<SaveDataInfo> info;
|
||||
u64 next_entry_index = 0;
|
||||
};
|
||||
|
||||
FSP_SRV::FSP_SRV(const Core::Reporter& reporter) : ServiceFramework("fsp-srv"), reporter(reporter) {
|
||||
FSP_SRV::FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter)
|
||||
: ServiceFramework("fsp-srv"), fsc(fsc), reporter(reporter) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "OpenFileSystem"},
|
||||
@ -754,7 +791,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
|
||||
void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FS, "called");
|
||||
|
||||
IFileSystem filesystem(OpenSDMC().Unwrap());
|
||||
IFileSystem filesystem(fsc.OpenSDMC().Unwrap(),
|
||||
SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@ -768,8 +806,10 @@ void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
|
||||
u128 uid = rp.PopRaw<u128>();
|
||||
|
||||
LOG_WARNING(Service_FS, "(STUBBED) called save_struct = {}, uid = {:016X}{:016X}",
|
||||
save_struct.DebugInfo(), uid[1], uid[0]);
|
||||
LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
|
||||
uid[1], uid[0]);
|
||||
|
||||
fsc.CreateSaveData(FileSys::SaveDataSpaceId::NandUser, save_struct);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@ -786,14 +826,24 @@ void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto parameters = rp.PopRaw<Parameters>();
|
||||
|
||||
auto dir = OpenSaveData(parameters.save_data_space_id, parameters.descriptor);
|
||||
auto dir = fsc.OpenSaveData(parameters.save_data_space_id, parameters.descriptor);
|
||||
if (dir.Failed()) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 0};
|
||||
rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
IFileSystem filesystem(std::move(dir.Unwrap()));
|
||||
FileSys::StorageId id;
|
||||
if (parameters.save_data_space_id == FileSys::SaveDataSpaceId::NandUser) {
|
||||
id = FileSys::StorageId::NandUser;
|
||||
} else if (parameters.save_data_space_id == FileSys::SaveDataSpaceId::SdCardSystem ||
|
||||
parameters.save_data_space_id == FileSys::SaveDataSpaceId::SdCardUser) {
|
||||
id = FileSys::StorageId::SdCard;
|
||||
} else {
|
||||
id = FileSys::StorageId::NandSystem;
|
||||
}
|
||||
|
||||
IFileSystem filesystem(std::move(dir.Unwrap()), SizeGetter::FromStorageId(fsc, id));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
@ -812,7 +862,7 @@ void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext&
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space));
|
||||
rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space, fsc));
|
||||
}
|
||||
|
||||
void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
|
||||
@ -836,7 +886,7 @@ void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
|
||||
void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FS, "called");
|
||||
|
||||
auto romfs = OpenRomFSCurrentProcess();
|
||||
auto romfs = fsc.OpenRomFSCurrentProcess();
|
||||
if (romfs.Failed()) {
|
||||
// TODO (bunnei): Find the right error code to use here
|
||||
LOG_CRITICAL(Service_FS, "no file system interface available!");
|
||||
@ -861,7 +911,7 @@ void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
|
||||
static_cast<u8>(storage_id), unknown, title_id);
|
||||
|
||||
auto data = OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
|
||||
auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
|
||||
|
||||
if (data.Failed()) {
|
||||
const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
|
||||
|
@ -32,7 +32,7 @@ enum class LogMode : u32 {
|
||||
|
||||
class FSP_SRV final : public ServiceFramework<FSP_SRV> {
|
||||
public:
|
||||
explicit FSP_SRV(const Core::Reporter& reporter);
|
||||
explicit FSP_SRV(FileSystemController& fsc, const Core::Reporter& reporter);
|
||||
~FSP_SRV() override;
|
||||
|
||||
private:
|
||||
@ -51,6 +51,8 @@ private:
|
||||
void OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx);
|
||||
void GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx);
|
||||
|
||||
FileSystemController& fsc;
|
||||
|
||||
FileSys::VirtualFile romfs;
|
||||
u64 current_process_id = 0;
|
||||
u32 access_log_program_index = 0;
|
||||
|
@ -617,7 +617,7 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager) {
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSystemController& fsc) {
|
||||
std::make_shared<NS>("ns:am2")->InstallAsService(service_manager);
|
||||
std::make_shared<NS>("ns:ec")->InstallAsService(service_manager);
|
||||
std::make_shared<NS>("ns:rid")->InstallAsService(service_manager);
|
||||
@ -628,7 +628,7 @@ void InstallInterfaces(SM::ServiceManager& service_manager) {
|
||||
std::make_shared<NS_SU>()->InstallAsService(service_manager);
|
||||
std::make_shared<NS_VM>()->InstallAsService(service_manager);
|
||||
|
||||
std::make_shared<PL_U>()->InstallAsService(service_manager);
|
||||
std::make_shared<PL_U>(fsc)->InstallAsService(service_manager);
|
||||
}
|
||||
|
||||
} // namespace Service::NS
|
||||
|
@ -6,7 +6,13 @@
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::NS {
|
||||
namespace Service {
|
||||
|
||||
namespace FileSystem {
|
||||
class FileSystemController;
|
||||
} // namespace FileSystem
|
||||
|
||||
namespace NS {
|
||||
|
||||
class IAccountProxyInterface final : public ServiceFramework<IAccountProxyInterface> {
|
||||
public:
|
||||
@ -91,6 +97,8 @@ private:
|
||||
};
|
||||
|
||||
/// Registers all NS services with the specified service manager.
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager);
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager, FileSystem::FileSystemController& fsc);
|
||||
|
||||
} // namespace Service::NS
|
||||
} // namespace NS
|
||||
|
||||
} // namespace Service
|
||||
|
@ -150,7 +150,8 @@ struct PL_U::Impl {
|
||||
std::vector<FontRegion> shared_font_regions;
|
||||
};
|
||||
|
||||
PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
|
||||
PL_U::PL_U(FileSystem::FileSystemController& fsc)
|
||||
: ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &PL_U::RequestLoad, "RequestLoad"},
|
||||
{1, &PL_U::GetLoadState, "GetLoadState"},
|
||||
@ -161,7 +162,7 @@ PL_U::PL_U() : ServiceFramework("pl:u"), impl{std::make_unique<Impl>()} {
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
// Attempt to load shared font data from disk
|
||||
const auto* nand = FileSystem::GetSystemNANDContents();
|
||||
const auto* nand = fsc.GetSystemNANDContents();
|
||||
std::size_t offset = 0;
|
||||
// Rebuild shared fonts from data ncas
|
||||
if (nand->HasEntry(static_cast<u64>(FontArchives::Standard),
|
||||
|
@ -7,11 +7,17 @@
|
||||
#include <memory>
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::NS {
|
||||
namespace Service {
|
||||
|
||||
namespace FileSystem {
|
||||
class FileSystemController;
|
||||
} // namespace FileSystem
|
||||
|
||||
namespace NS {
|
||||
|
||||
class PL_U final : public ServiceFramework<PL_U> {
|
||||
public:
|
||||
PL_U();
|
||||
PL_U(FileSystem::FileSystemController& fsc);
|
||||
~PL_U() override;
|
||||
|
||||
private:
|
||||
@ -26,4 +32,6 @@ private:
|
||||
std::unique_ptr<Impl> impl;
|
||||
};
|
||||
|
||||
} // namespace Service::NS
|
||||
} // namespace NS
|
||||
|
||||
} // namespace Service
|
||||
|
@ -199,6 +199,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
|
||||
// NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
|
||||
// here and pass it into the respective InstallInterfaces functions.
|
||||
auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(system.CoreTiming());
|
||||
system.GetFileSystemController().CreateFactories(*system.GetFilesystem(), false);
|
||||
|
||||
SM::ServiceManager::InstallInterfaces(sm);
|
||||
|
||||
@ -235,7 +236,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
|
||||
NIFM::InstallInterfaces(*sm);
|
||||
NIM::InstallInterfaces(*sm);
|
||||
NPNS::InstallInterfaces(*sm);
|
||||
NS::InstallInterfaces(*sm);
|
||||
NS::InstallInterfaces(*sm, system.GetFileSystemController());
|
||||
Nvidia::InstallInterfaces(*sm, *nv_flinger, system);
|
||||
PCIe::InstallInterfaces(*sm);
|
||||
PCTL::InstallInterfaces(*sm);
|
||||
|
@ -18,10 +18,6 @@ namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace FileSys {
|
||||
class VfsFilesystem;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class ClientPort;
|
||||
class ServerPort;
|
||||
@ -31,6 +27,10 @@ class HLERequestContext;
|
||||
|
||||
namespace Service {
|
||||
|
||||
namespace FileSystem {
|
||||
class FileSystemController;
|
||||
} // namespace FileSystem
|
||||
|
||||
namespace SM {
|
||||
class ServiceManager;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
@ -176,7 +177,8 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
|
||||
// Register the RomFS if a ".romfs" file was found
|
||||
if (romfs_iter != files.end() && *romfs_iter != nullptr) {
|
||||
romfs = *romfs_iter;
|
||||
Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
|
||||
Core::System::GetInstance().GetFileSystemController().RegisterRomFS(
|
||||
std::make_unique<FileSys::RomFSFactory>(*this));
|
||||
}
|
||||
|
||||
is_loaded = true;
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/romfs_factory.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
@ -57,7 +58,8 @@ AppLoader_NCA::LoadResult AppLoader_NCA::Load(Kernel::Process& process) {
|
||||
}
|
||||
|
||||
if (nca->GetRomFS() != nullptr && nca->GetRomFS()->GetSize() > 0) {
|
||||
Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
|
||||
Core::System::GetInstance().GetFileSystemController().RegisterRomFS(
|
||||
std::make_unique<FileSys::RomFSFactory>(*this));
|
||||
}
|
||||
|
||||
is_loaded = true;
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/romfs_factory.h"
|
||||
#include "core/file_sys/vfs_offset.h"
|
||||
@ -214,7 +215,8 @@ AppLoader_NRO::LoadResult AppLoader_NRO::Load(Kernel::Process& process) {
|
||||
}
|
||||
|
||||
if (romfs != nullptr) {
|
||||
Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
|
||||
Core::System::GetInstance().GetFileSystemController().RegisterRomFS(
|
||||
std::make_unique<FileSys::RomFSFactory>(*this));
|
||||
}
|
||||
|
||||
is_loaded = true;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/card_image.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
@ -105,7 +106,8 @@ AppLoader_NSP::LoadResult AppLoader_NSP::Load(Kernel::Process& process) {
|
||||
|
||||
FileSys::VirtualFile update_raw;
|
||||
if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
|
||||
Service::FileSystem::SetPackedUpdate(std::move(update_raw));
|
||||
Core::System::GetInstance().GetFileSystemController().SetPackedUpdate(
|
||||
std::move(update_raw));
|
||||
}
|
||||
|
||||
is_loaded = true;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/card_image.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
@ -72,7 +73,8 @@ AppLoader_XCI::LoadResult AppLoader_XCI::Load(Kernel::Process& process) {
|
||||
|
||||
FileSys::VirtualFile update_raw;
|
||||
if (ReadUpdateRaw(update_raw) == ResultStatus::Success && update_raw != nullptr) {
|
||||
Service::FileSystem::SetPackedUpdate(std::move(update_raw));
|
||||
Core::System::GetInstance().GetFileSystemController().SetPackedUpdate(
|
||||
std::move(update_raw));
|
||||
}
|
||||
|
||||
is_loaded = true;
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/file_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/hle/service/hid/hid.h"
|
||||
@ -97,8 +98,8 @@ void LogSettings() {
|
||||
LogSetting("Audio_EnableAudioStretching", Settings::values.enable_audio_stretching);
|
||||
LogSetting("Audio_OutputDevice", Settings::values.audio_device_id);
|
||||
LogSetting("DataStorage_UseVirtualSd", Settings::values.use_virtual_sd);
|
||||
LogSetting("DataStorage_NandDir", Settings::values.nand_dir);
|
||||
LogSetting("DataStorage_SdmcDir", Settings::values.sdmc_dir);
|
||||
LogSetting("DataStorage_NandDir", FileUtil::GetUserPath(FileUtil::UserPath::NANDDir));
|
||||
LogSetting("DataStorage_SdmcDir", FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir));
|
||||
LogSetting("Debugging_UseGdbstub", Settings::values.use_gdbstub);
|
||||
LogSetting("Debugging_GdbstubPort", Settings::values.gdbstub_port);
|
||||
LogSetting("Debugging_ProgramArgs", Settings::values.program_args);
|
||||
|
@ -346,6 +346,31 @@ struct TouchscreenInput {
|
||||
u32 rotation_angle;
|
||||
};
|
||||
|
||||
enum class NANDTotalSize : u64 {
|
||||
S29_1GB = 0x747C00000ULL,
|
||||
};
|
||||
|
||||
enum class NANDUserSize : u64 {
|
||||
S26GB = 0x680000000ULL,
|
||||
};
|
||||
|
||||
enum class NANDSystemSize : u64 {
|
||||
S2_5GB = 0xA0000000,
|
||||
};
|
||||
|
||||
enum class SDMCSize : u64 {
|
||||
S1GB = 0x40000000,
|
||||
S2GB = 0x80000000,
|
||||
S4GB = 0x100000000ULL,
|
||||
S8GB = 0x200000000ULL,
|
||||
S16GB = 0x400000000ULL,
|
||||
S32GB = 0x800000000ULL,
|
||||
S64GB = 0x1000000000ULL,
|
||||
S128GB = 0x2000000000ULL,
|
||||
S256GB = 0x4000000000ULL,
|
||||
S1TB = 0x10000000000ULL,
|
||||
};
|
||||
|
||||
struct Values {
|
||||
// System
|
||||
bool use_docked_mode;
|
||||
@ -382,8 +407,13 @@ struct Values {
|
||||
|
||||
// Data Storage
|
||||
bool use_virtual_sd;
|
||||
std::string nand_dir;
|
||||
std::string sdmc_dir;
|
||||
bool gamecard_inserted;
|
||||
bool gamecard_current_game;
|
||||
std::string gamecard_path;
|
||||
NANDTotalSize nand_total_size;
|
||||
NANDSystemSize nand_system_size;
|
||||
NANDUserSize nand_user_size;
|
||||
SDMCSize sdmc_size;
|
||||
|
||||
// Renderer
|
||||
float resolution_factor;
|
||||
|
@ -33,6 +33,9 @@ add_executable(yuzu
|
||||
configuration/configure_debug.ui
|
||||
configuration/configure_dialog.cpp
|
||||
configuration/configure_dialog.h
|
||||
configuration/configure_filesystem.cpp
|
||||
configuration/configure_filesystem.h
|
||||
configuration/configure_filesystem.ui
|
||||
configuration/configure_gamelist.cpp
|
||||
configuration/configure_gamelist.h
|
||||
configuration/configure_gamelist.ui
|
||||
|
@ -459,6 +459,49 @@ void Config::ReadDataStorageValues() {
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)))
|
||||
.toString()
|
||||
.toStdString());
|
||||
FileUtil::GetUserPath(
|
||||
FileUtil::UserPath::LoadDir,
|
||||
qt_config
|
||||
->value(QStringLiteral("load_directory"),
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir)))
|
||||
.toString()
|
||||
.toStdString());
|
||||
FileUtil::GetUserPath(
|
||||
FileUtil::UserPath::DumpDir,
|
||||
qt_config
|
||||
->value(QStringLiteral("dump_directory"),
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir)))
|
||||
.toString()
|
||||
.toStdString());
|
||||
FileUtil::GetUserPath(
|
||||
FileUtil::UserPath::CacheDir,
|
||||
qt_config
|
||||
->value(QStringLiteral("cache_directory"),
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir)))
|
||||
.toString()
|
||||
.toStdString());
|
||||
Settings::values.gamecard_inserted =
|
||||
ReadSetting(QStringLiteral("gamecard_inserted"), false).toBool();
|
||||
Settings::values.gamecard_current_game =
|
||||
ReadSetting(QStringLiteral("gamecard_current_game"), false).toBool();
|
||||
Settings::values.gamecard_path =
|
||||
ReadSetting(QStringLiteral("gamecard_path"), QStringLiteral("")).toString().toStdString();
|
||||
Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(
|
||||
ReadSetting(QStringLiteral("nand_total_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB)))
|
||||
.toULongLong());
|
||||
Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(
|
||||
ReadSetting(QStringLiteral("nand_user_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB)))
|
||||
.toULongLong());
|
||||
Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
|
||||
ReadSetting(QStringLiteral("nand_system_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB)))
|
||||
.toULongLong());
|
||||
Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(
|
||||
ReadSetting(QStringLiteral("sdmc_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB)))
|
||||
.toULongLong());
|
||||
|
||||
qt_config->endGroup();
|
||||
}
|
||||
@ -875,7 +918,32 @@ void Config::SaveDataStorageValues() {
|
||||
WriteSetting(QStringLiteral("sdmc_directory"),
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)),
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)));
|
||||
|
||||
WriteSetting(QStringLiteral("load_directory"),
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir)),
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir)));
|
||||
WriteSetting(QStringLiteral("dump_directory"),
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir)),
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir)));
|
||||
WriteSetting(QStringLiteral("cache_directory"),
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir)),
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir)));
|
||||
WriteSetting(QStringLiteral("gamecard_inserted"), Settings::values.gamecard_inserted, false);
|
||||
WriteSetting(QStringLiteral("gamecard_current_game"), Settings::values.gamecard_current_game,
|
||||
false);
|
||||
WriteSetting(QStringLiteral("gamecard_path"),
|
||||
QString::fromStdString(Settings::values.gamecard_path), QStringLiteral(""));
|
||||
WriteSetting(QStringLiteral("nand_total_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_total_size)),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDTotalSize::S29_1GB)));
|
||||
WriteSetting(QStringLiteral("nand_user_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_user_size)),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDUserSize::S26GB)));
|
||||
WriteSetting(QStringLiteral("nand_system_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::values.nand_system_size)),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::NANDSystemSize::S2_5GB)));
|
||||
WriteSetting(QStringLiteral("sdmc_size"),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::values.sdmc_size)),
|
||||
QVariant::fromValue<u64>(static_cast<u64>(Settings::SDMCSize::S16GB)));
|
||||
qt_config->endGroup();
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,11 @@
|
||||
<string>Profiles</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="ConfigureFilesystem" name="filesystemTab">
|
||||
<attribute name="title">
|
||||
<string>Filesystem</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="ConfigureInputSimple" name="inputTab">
|
||||
<attribute name="title">
|
||||
<string>Input</string>
|
||||
@ -125,6 +130,12 @@
|
||||
<header>configuration/configure_profile_manager.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ConfigureFilesystem</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>configuration/configure_filesystem.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>ConfigureAudio</class>
|
||||
<extends>QWidget</extends>
|
||||
|
@ -34,8 +34,6 @@ void ConfigureDebug::SetConfiguration() {
|
||||
ui->toggle_console->setChecked(UISettings::values.show_console);
|
||||
ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter));
|
||||
ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args));
|
||||
ui->dump_exefs->setChecked(Settings::values.dump_exefs);
|
||||
ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso);
|
||||
ui->reporting_services->setChecked(Settings::values.reporting_services);
|
||||
ui->quest_flag->setChecked(Settings::values.quest_flag);
|
||||
}
|
||||
@ -46,8 +44,6 @@ void ConfigureDebug::ApplyConfiguration() {
|
||||
UISettings::values.show_console = ui->toggle_console->isChecked();
|
||||
Settings::values.log_filter = ui->log_filter_edit->text().toStdString();
|
||||
Settings::values.program_args = ui->homebrew_args_edit->text().toStdString();
|
||||
Settings::values.dump_exefs = ui->dump_exefs->isChecked();
|
||||
Settings::values.dump_nso = ui->dump_decompressed_nso->isChecked();
|
||||
Settings::values.reporting_services = ui->reporting_services->isChecked();
|
||||
Settings::values.quest_flag = ui->quest_flag->isChecked();
|
||||
Debugger::ToggleConsole();
|
||||
|
@ -103,58 +103,6 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Homebrew</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Arguments String</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="homebrew_args_edit"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Dump</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="dump_decompressed_nso">
|
||||
<property name="whatsThis">
|
||||
<string>When checked, any NSO yuzu tries to load or patch will be copied decompressed to the yuzu/dump directory.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Dump Decompressed NSOs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="dump_exefs">
|
||||
<property name="whatsThis">
|
||||
<string>When checked, any game that yuzu loads will have its ExeFS dumped to the yuzu/dump directory.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Dump ExeFS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="reporting_services">
|
||||
<property name="text">
|
||||
@ -163,7 +111,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
@ -196,11 +144,37 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Homebrew</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Arguments String</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="homebrew_args_edit"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
|
@ -37,6 +37,7 @@ void ConfigureDialog::ApplyConfiguration() {
|
||||
ui->gameListTab->ApplyConfiguration();
|
||||
ui->systemTab->ApplyConfiguration();
|
||||
ui->profileManagerTab->ApplyConfiguration();
|
||||
ui->filesystemTab->applyConfiguration();
|
||||
ui->inputTab->ApplyConfiguration();
|
||||
ui->hotkeysTab->ApplyConfiguration(registry);
|
||||
ui->graphicsTab->ApplyConfiguration();
|
||||
@ -73,7 +74,7 @@ Q_DECLARE_METATYPE(QList<QWidget*>);
|
||||
void ConfigureDialog::PopulateSelectionList() {
|
||||
const std::array<std::pair<QString, QList<QWidget*>>, 4> items{
|
||||
{{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->gameListTab}},
|
||||
{tr("System"), {ui->systemTab, ui->profileManagerTab, ui->audioTab}},
|
||||
{tr("System"), {ui->systemTab, ui->profileManagerTab, ui->filesystemTab, ui->audioTab}},
|
||||
{tr("Graphics"), {ui->graphicsTab}},
|
||||
{tr("Controls"), {ui->inputTab, ui->hotkeysTab}}},
|
||||
};
|
||||
@ -106,6 +107,7 @@ void ConfigureDialog::UpdateVisibleTabs() {
|
||||
{ui->debugTab, tr("Debug")},
|
||||
{ui->webTab, tr("Web")},
|
||||
{ui->gameListTab, tr("Game List")},
|
||||
{ui->filesystemTab, tr("Filesystem")},
|
||||
};
|
||||
|
||||
[[maybe_unused]] const QSignalBlocker blocker(ui->tabWidget);
|
||||
|
177
src/yuzu/configuration/configure_filesystem.cpp
Normal file
177
src/yuzu/configuration/configure_filesystem.cpp
Normal file
@ -0,0 +1,177 @@
|
||||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include "common/common_paths.h"
|
||||
#include "common/file_util.h"
|
||||
#include "core/settings.h"
|
||||
#include "ui_configure_filesystem.h"
|
||||
#include "yuzu/configuration/configure_filesystem.h"
|
||||
#include "yuzu/uisettings.h"
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
void SetComboBoxFromData(QComboBox* combo_box, T data) {
|
||||
const auto index = combo_box->findData(QVariant::fromValue(static_cast<u64>(data)));
|
||||
if (index >= combo_box->count() || index < 0)
|
||||
return;
|
||||
|
||||
combo_box->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
ConfigureFilesystem::ConfigureFilesystem(QWidget* parent)
|
||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureFilesystem>()) {
|
||||
ui->setupUi(this);
|
||||
this->setConfiguration();
|
||||
|
||||
connect(ui->nand_directory_button, &QToolButton::pressed, this,
|
||||
[this] { SetDirectory(DirectoryTarget::NAND, ui->nand_directory_edit); });
|
||||
connect(ui->sdmc_directory_button, &QToolButton::pressed, this,
|
||||
[this] { SetDirectory(DirectoryTarget::SD, ui->sdmc_directory_edit); });
|
||||
connect(ui->gamecard_path_button, &QToolButton::pressed, this,
|
||||
[this] { SetDirectory(DirectoryTarget::Gamecard, ui->gamecard_path_edit); });
|
||||
connect(ui->dump_path_button, &QToolButton::pressed, this,
|
||||
[this] { SetDirectory(DirectoryTarget::Dump, ui->dump_path_edit); });
|
||||
connect(ui->load_path_button, &QToolButton::pressed, this,
|
||||
[this] { SetDirectory(DirectoryTarget::Load, ui->load_path_edit); });
|
||||
connect(ui->cache_directory_button, &QToolButton::pressed, this,
|
||||
[this] { SetDirectory(DirectoryTarget::Cache, ui->cache_directory_edit); });
|
||||
|
||||
connect(ui->reset_game_list_cache, &QPushButton::pressed, this,
|
||||
&ConfigureFilesystem::ResetMetadata);
|
||||
|
||||
connect(ui->gamecard_inserted, &QCheckBox::stateChanged, this,
|
||||
&ConfigureFilesystem::UpdateEnabledControls);
|
||||
connect(ui->gamecard_current_game, &QCheckBox::stateChanged, this,
|
||||
&ConfigureFilesystem::UpdateEnabledControls);
|
||||
}
|
||||
|
||||
ConfigureFilesystem::~ConfigureFilesystem() = default;
|
||||
|
||||
void ConfigureFilesystem::setConfiguration() {
|
||||
ui->nand_directory_edit->setText(
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir)));
|
||||
ui->sdmc_directory_edit->setText(
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)));
|
||||
ui->gamecard_path_edit->setText(QString::fromStdString(Settings::values.gamecard_path));
|
||||
ui->dump_path_edit->setText(
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir)));
|
||||
ui->load_path_edit->setText(
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir)));
|
||||
ui->cache_directory_edit->setText(
|
||||
QString::fromStdString(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir)));
|
||||
|
||||
ui->gamecard_inserted->setChecked(Settings::values.gamecard_inserted);
|
||||
ui->gamecard_current_game->setChecked(Settings::values.gamecard_current_game);
|
||||
ui->dump_exefs->setChecked(Settings::values.dump_exefs);
|
||||
ui->dump_nso->setChecked(Settings::values.dump_nso);
|
||||
|
||||
ui->cache_game_list->setChecked(UISettings::values.cache_game_list);
|
||||
|
||||
SetComboBoxFromData(ui->nand_size, Settings::values.nand_total_size);
|
||||
SetComboBoxFromData(ui->usrnand_size, Settings::values.nand_user_size);
|
||||
SetComboBoxFromData(ui->sysnand_size, Settings::values.nand_system_size);
|
||||
SetComboBoxFromData(ui->sdmc_size, Settings::values.sdmc_size);
|
||||
|
||||
UpdateEnabledControls();
|
||||
}
|
||||
|
||||
void ConfigureFilesystem::applyConfiguration() {
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::NANDDir,
|
||||
ui->nand_directory_edit->text().toStdString());
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir,
|
||||
ui->sdmc_directory_edit->text().toStdString());
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::DumpDir, ui->dump_path_edit->text().toStdString());
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir, ui->load_path_edit->text().toStdString());
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::CacheDir,
|
||||
ui->cache_directory_edit->text().toStdString());
|
||||
Settings::values.gamecard_path = ui->gamecard_path_edit->text().toStdString();
|
||||
|
||||
Settings::values.gamecard_inserted = ui->gamecard_inserted->isChecked();
|
||||
Settings::values.gamecard_current_game = ui->gamecard_current_game->isChecked();
|
||||
Settings::values.dump_exefs = ui->dump_exefs->isChecked();
|
||||
Settings::values.dump_nso = ui->dump_nso->isChecked();
|
||||
|
||||
UISettings::values.cache_game_list = ui->cache_game_list->isChecked();
|
||||
|
||||
Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(
|
||||
ui->nand_size->itemData(ui->nand_size->currentIndex()).toULongLong());
|
||||
Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
|
||||
ui->nand_size->itemData(ui->sysnand_size->currentIndex()).toULongLong());
|
||||
Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(
|
||||
ui->nand_size->itemData(ui->usrnand_size->currentIndex()).toULongLong());
|
||||
Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(
|
||||
ui->nand_size->itemData(ui->sdmc_size->currentIndex()).toULongLong());
|
||||
}
|
||||
|
||||
void ConfigureFilesystem::SetDirectory(DirectoryTarget target, QLineEdit* edit) {
|
||||
QString caption;
|
||||
|
||||
switch (target) {
|
||||
case DirectoryTarget::NAND:
|
||||
caption = tr("Select Emulated NAND Directory...");
|
||||
break;
|
||||
case DirectoryTarget::SD:
|
||||
caption = tr("Select Emulated SD Directory...");
|
||||
break;
|
||||
case DirectoryTarget::Gamecard:
|
||||
caption = tr("Select Gamecard Path...");
|
||||
break;
|
||||
case DirectoryTarget::Dump:
|
||||
caption = tr("Select Dump Directory...");
|
||||
break;
|
||||
case DirectoryTarget::Load:
|
||||
caption = tr("Select Mod Load Directory...");
|
||||
break;
|
||||
case DirectoryTarget::Cache:
|
||||
caption = tr("Select Cache Directory...");
|
||||
break;
|
||||
}
|
||||
|
||||
QString str;
|
||||
if (target == DirectoryTarget::Gamecard) {
|
||||
str = QFileDialog::getOpenFileName(this, caption, QFileInfo(edit->text()).dir().path(),
|
||||
QStringLiteral("NX Gamecard;*.xci"));
|
||||
} else {
|
||||
str = QFileDialog::getExistingDirectory(this, caption, edit->text());
|
||||
}
|
||||
|
||||
if (str.isEmpty())
|
||||
return;
|
||||
|
||||
edit->setText(str);
|
||||
}
|
||||
|
||||
void ConfigureFilesystem::ResetMetadata() {
|
||||
if (!FileUtil::Exists(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) + DIR_SEP +
|
||||
"game_list")) {
|
||||
QMessageBox::information(this, tr("Reset Metadata Cache"),
|
||||
tr("The metadata cache is already empty."));
|
||||
} else if (FileUtil::DeleteDirRecursively(FileUtil::GetUserPath(FileUtil::UserPath::CacheDir) +
|
||||
DIR_SEP + "game_list")) {
|
||||
QMessageBox::information(this, tr("Reset Metadata Cache"),
|
||||
tr("The operation completed successfully."));
|
||||
UISettings::values.is_game_list_reload_pending.exchange(true);
|
||||
} else {
|
||||
QMessageBox::warning(
|
||||
this, tr("Reset Metadata Cache"),
|
||||
tr("The metadata cache couldn't be deleted. It might be in use or non-existent."));
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureFilesystem::UpdateEnabledControls() {
|
||||
ui->gamecard_current_game->setEnabled(ui->gamecard_inserted->isChecked());
|
||||
ui->gamecard_path_edit->setEnabled(ui->gamecard_inserted->isChecked() &&
|
||||
!ui->gamecard_current_game->isChecked());
|
||||
ui->gamecard_path_button->setEnabled(ui->gamecard_inserted->isChecked() &&
|
||||
!ui->gamecard_current_game->isChecked());
|
||||
}
|
||||
|
||||
void ConfigureFilesystem::retranslateUi() {
|
||||
ui->retranslateUi(this);
|
||||
}
|
43
src/yuzu/configuration/configure_filesystem.h
Normal file
43
src/yuzu/configuration/configure_filesystem.h
Normal file
@ -0,0 +1,43 @@
|
||||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <QWidget>
|
||||
|
||||
class QLineEdit;
|
||||
|
||||
namespace Ui {
|
||||
class ConfigureFilesystem;
|
||||
}
|
||||
|
||||
class ConfigureFilesystem : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfigureFilesystem(QWidget* parent = nullptr);
|
||||
~ConfigureFilesystem() override;
|
||||
|
||||
void applyConfiguration();
|
||||
void retranslateUi();
|
||||
|
||||
private:
|
||||
void setConfiguration();
|
||||
|
||||
enum class DirectoryTarget {
|
||||
NAND,
|
||||
SD,
|
||||
Gamecard,
|
||||
Dump,
|
||||
Load,
|
||||
Cache,
|
||||
};
|
||||
|
||||
void SetDirectory(DirectoryTarget target, QLineEdit* edit);
|
||||
void ResetMetadata();
|
||||
void UpdateEnabledControls();
|
||||
|
||||
std::unique_ptr<Ui::ConfigureFilesystem> ui;
|
||||
};
|
395
src/yuzu/configuration/configure_filesystem.ui
Normal file
395
src/yuzu/configuration/configure_filesystem.ui
Normal file
@ -0,0 +1,395 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConfigureFilesystem</class>
|
||||
<widget class="QWidget" name="ConfigureFilesystem">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>453</width>
|
||||
<height>561</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Storage Directories</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>NAND</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QToolButton" name="nand_directory_button">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="nand_directory_edit"/>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="sdmc_directory_edit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>SD Card</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QToolButton" name="sdmc_directory_button">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Maximum</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>60</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>Gamecard</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Path</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLineEdit" name="gamecard_path_edit"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QCheckBox" name="gamecard_inserted">
|
||||
<property name="text">
|
||||
<string>Inserted</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="gamecard_current_game">
|
||||
<property name="text">
|
||||
<string>Current Game</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="3">
|
||||
<widget class="QToolButton" name="gamecard_path_button">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_3">
|
||||
<property name="title">
|
||||
<string>Storage Sizes</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>SD Card</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>System NAND</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="sysnand_size">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>2.5 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QComboBox" name="sdmc_size">
|
||||
<property name="currentText">
|
||||
<string>32 GB</string>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>2 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>4 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>8 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>16 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>32 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>64 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>128 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>256 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>1 TB</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="usrnand_size">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>26 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>User NAND</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>NAND</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="nand_size">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>29.1 GB</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>Patch Manager</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="load_path_edit"/>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="dump_path_edit"/>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QToolButton" name="dump_path_button">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QToolButton" name="load_path_button">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="4">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="dump_nso">
|
||||
<property name="text">
|
||||
<string>Dump Decompressed NSOs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="dump_exefs">
|
||||
<property name="text">
|
||||
<string>Dump ExeFS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Mod Load Root</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Dump Root</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="title">
|
||||
<string>Caching</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Cache Directory</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="cache_directory_edit"/>
|
||||
</item>
|
||||
<item row="0" column="3">
|
||||
<widget class="QToolButton" name="cache_directory_button">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="4">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cache_game_list">
|
||||
<property name="text">
|
||||
<string>Cache Game List Metadata</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="reset_game_list_cache">
|
||||
<property name="text">
|
||||
<string>Reset Metadata Cache</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <QSpinBox>
|
||||
#include "core/core.h"
|
||||
#include "core/settings.h"
|
||||
#include "ui_configure_general.h"
|
||||
|
@ -221,7 +221,7 @@ GMainWindow::GMainWindow()
|
||||
std::make_unique<FileSys::ContentProviderUnion>());
|
||||
Core::System::GetInstance().RegisterContentProvider(
|
||||
FileSys::ContentProviderUnionSlot::FrontendManual, provider.get());
|
||||
Service::FileSystem::CreateFactories(*vfs);
|
||||
Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs);
|
||||
|
||||
// Gen keys if necessary
|
||||
OnReinitializeKeys(ReinitializeKeyBehavior::NoWarning);
|
||||
@ -1507,15 +1507,19 @@ void GMainWindow::OnMenuInstallToNAND() {
|
||||
failed();
|
||||
return;
|
||||
}
|
||||
const auto res =
|
||||
Service::FileSystem::GetUserNANDContents()->InstallEntry(*nsp, false, qt_raw_copy);
|
||||
const auto res = Core::System::GetInstance()
|
||||
.GetFileSystemController()
|
||||
.GetUserNANDContents()
|
||||
->InstallEntry(*nsp, false, qt_raw_copy);
|
||||
if (res == FileSys::InstallResult::Success) {
|
||||
success();
|
||||
} else {
|
||||
if (res == FileSys::InstallResult::ErrorAlreadyExists) {
|
||||
if (overwrite()) {
|
||||
const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry(
|
||||
*nsp, true, qt_raw_copy);
|
||||
const auto res2 = Core::System::GetInstance()
|
||||
.GetFileSystemController()
|
||||
.GetUserNANDContents()
|
||||
->InstallEntry(*nsp, true, qt_raw_copy);
|
||||
if (res2 == FileSys::InstallResult::Success) {
|
||||
success();
|
||||
} else {
|
||||
@ -1569,19 +1573,28 @@ void GMainWindow::OnMenuInstallToNAND() {
|
||||
|
||||
FileSys::InstallResult res;
|
||||
if (index >= static_cast<size_t>(FileSys::TitleType::Application)) {
|
||||
res = Service::FileSystem::GetUserNANDContents()->InstallEntry(
|
||||
*nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy);
|
||||
res = Core::System::GetInstance()
|
||||
.GetFileSystemController()
|
||||
.GetUserNANDContents()
|
||||
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false,
|
||||
qt_raw_copy);
|
||||
} else {
|
||||
res = Service::FileSystem::GetSystemNANDContents()->InstallEntry(
|
||||
*nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy);
|
||||
res = Core::System::GetInstance()
|
||||
.GetFileSystemController()
|
||||
.GetSystemNANDContents()
|
||||
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index), false,
|
||||
qt_raw_copy);
|
||||
}
|
||||
|
||||
if (res == FileSys::InstallResult::Success) {
|
||||
success();
|
||||
} else if (res == FileSys::InstallResult::ErrorAlreadyExists) {
|
||||
if (overwrite()) {
|
||||
const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry(
|
||||
*nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy);
|
||||
const auto res2 = Core::System::GetInstance()
|
||||
.GetFileSystemController()
|
||||
.GetUserNANDContents()
|
||||
->InstallEntry(*nca, static_cast<FileSys::TitleType>(index),
|
||||
true, qt_raw_copy);
|
||||
if (res2 == FileSys::InstallResult::Success) {
|
||||
success();
|
||||
} else {
|
||||
@ -1611,7 +1624,7 @@ void GMainWindow::OnMenuSelectEmulatedDirectory(EmulatedDirectoryTarget target)
|
||||
FileUtil::GetUserPath(target == EmulatedDirectoryTarget::SDMC ? FileUtil::UserPath::SDMCDir
|
||||
: FileUtil::UserPath::NANDDir,
|
||||
dir_path.toStdString());
|
||||
Service::FileSystem::CreateFactories(*vfs);
|
||||
Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs);
|
||||
game_list->PopulateAsync(UISettings::values.game_dirs);
|
||||
}
|
||||
}
|
||||
@ -1996,7 +2009,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
|
||||
|
||||
const auto function = [this, &keys, &pdm] {
|
||||
keys.PopulateFromPartitionData(pdm);
|
||||
Service::FileSystem::CreateFactories(*vfs);
|
||||
Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs);
|
||||
keys.DeriveETicket(pdm);
|
||||
};
|
||||
|
||||
@ -2041,7 +2054,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) {
|
||||
prog.close();
|
||||
}
|
||||
|
||||
Service::FileSystem::CreateFactories(*vfs);
|
||||
Core::System::GetInstance().GetFileSystemController().CreateFactories(*vfs);
|
||||
|
||||
if (behavior == ReinitializeKeyBehavior::Warning) {
|
||||
game_list->PopulateAsync(UISettings::values.game_dirs);
|
||||
|
@ -316,6 +316,29 @@ void Config::ReadValues() {
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir,
|
||||
sdl2_config->Get("Data Storage", "sdmc_directory",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir)));
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir,
|
||||
sdl2_config->Get("Data Storage", "load_directory",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::LoadDir)));
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::DumpDir,
|
||||
sdl2_config->Get("Data Storage", "dump_directory",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::DumpDir)));
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::CacheDir,
|
||||
sdl2_config->Get("Data Storage", "cache_directory",
|
||||
FileUtil::GetUserPath(FileUtil::UserPath::CacheDir)));
|
||||
Settings::values.gamecard_inserted =
|
||||
sdl2_config->GetBoolean("Data Storage", "gamecard_inserted", false);
|
||||
Settings::values.gamecard_current_game =
|
||||
sdl2_config->GetBoolean("Data Storage", "gamecard_current_game", false);
|
||||
Settings::values.gamecard_path = sdl2_config->Get("Data Storage", "gamecard_path", "");
|
||||
Settings::values.nand_total_size = static_cast<Settings::NANDTotalSize>(sdl2_config->GetInteger(
|
||||
"Data Storage", "nand_total_size", static_cast<long>(Settings::NANDTotalSize::S29_1GB)));
|
||||
Settings::values.nand_user_size = static_cast<Settings::NANDUserSize>(sdl2_config->GetInteger(
|
||||
"Data Storage", "nand_user_size", static_cast<long>(Settings::NANDUserSize::S26GB)));
|
||||
Settings::values.nand_system_size = static_cast<Settings::NANDSystemSize>(
|
||||
sdl2_config->GetInteger("Data Storage", "nand_system_size",
|
||||
static_cast<long>(Settings::NANDSystemSize::S2_5GB)));
|
||||
Settings::values.sdmc_size = static_cast<Settings::SDMCSize>(sdl2_config->GetInteger(
|
||||
"Data Storage", "sdmc_size", static_cast<long>(Settings::SDMCSize::S16GB)));
|
||||
|
||||
// System
|
||||
Settings::values.use_docked_mode = sdl2_config->GetBoolean("System", "use_docked_mode", false);
|
||||
|
@ -173,6 +173,20 @@ volume =
|
||||
# 1 (default): Yes, 0: No
|
||||
use_virtual_sd =
|
||||
|
||||
# Whether or not to enable gamecard emulation
|
||||
# 1: Yes, 0 (default): No
|
||||
gamecard_inserted =
|
||||
|
||||
# Whether or not the gamecard should be emulated as the current game
|
||||
# If 'gamecard_inserted' is 0 this setting is irrelevant
|
||||
# 1: Yes, 0 (default): No
|
||||
gamecard_current_game =
|
||||
|
||||
# Path to an XCI file to use as the gamecard
|
||||
# If 'gamecard_inserted' is 0 this setting is irrelevant
|
||||
# If 'gamecard_current_game' is 1 this setting is irrelevant
|
||||
gamecard_path =
|
||||
|
||||
[System]
|
||||
# Whether the system is docked
|
||||
# 1: Yes, 0 (default): No
|
||||
|
@ -184,7 +184,7 @@ int main(int argc, char** argv) {
|
||||
Core::System& system{Core::System::GetInstance()};
|
||||
system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
|
||||
system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
|
||||
Service::FileSystem::CreateFactories(*system.GetFilesystem());
|
||||
system.GetFileSystemController().CreateFactories(*system.GetFilesystem());
|
||||
|
||||
SCOPE_EXIT({ system.Shutdown(); });
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "common/telemetry.h"
|
||||
#include "core/core.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "core/file_sys/vfs_real.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/loader/loader.h"
|
||||
@ -216,8 +217,9 @@ int main(int argc, char** argv) {
|
||||
};
|
||||
|
||||
Core::System& system{Core::System::GetInstance()};
|
||||
system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>());
|
||||
system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
|
||||
Service::FileSystem::CreateFactories(*system.GetFilesystem());
|
||||
system.GetFileSystemController().CreateFactories(*system.GetFilesystem());
|
||||
|
||||
SCOPE_EXIT({ system.Shutdown(); });
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user