summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/filesystem
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp303
-rw-r--r--src/core/hle/service/filesystem/filesystem.h75
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_directory.cpp84
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_directory.h30
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_file.cpp127
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_file.h25
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp262
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_filesystem.h38
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.cpp62
-rw-r--r--src/core/hle/service/filesystem/fsp/fs_i_storage.h23
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_ldr.cpp22
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_ldr.h (renamed from src/core/hle/service/filesystem/fsp_ldr.h)0
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_pr.cpp23
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_pr.h (renamed from src/core/hle/service/filesystem/fsp_pr.h)0
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.cpp727
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_srv.h78
-rw-r--r--src/core/hle/service/filesystem/fsp/fsp_util.h22
-rw-r--r--src/core/hle/service/filesystem/fsp_ldr.cpp22
-rw-r--r--src/core/hle/service/filesystem/fsp_pr.cpp23
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp1250
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.h72
-rw-r--r--src/core/hle/service/filesystem/romfs_controller.cpp37
-rw-r--r--src/core/hle/service/filesystem/romfs_controller.h31
-rw-r--r--src/core/hle/service/filesystem/save_data_controller.cpp99
-rw-r--r--src/core/hle/service/filesystem/save_data_controller.h35
25 files changed, 1847 insertions, 1623 deletions
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 780f8c74d..ae230afc0 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -12,27 +12,24 @@
#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"
#include "core/file_sys/patch_manager.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.h"
-#include "core/file_sys/vfs_offset.h"
+#include "core/file_sys/vfs/vfs.h"
+#include "core/file_sys/vfs/vfs_offset.h"
#include "core/hle/service/filesystem/filesystem.h"
-#include "core/hle/service/filesystem/fsp_ldr.h"
-#include "core/hle/service/filesystem/fsp_pr.h"
-#include "core/hle/service/filesystem/fsp_srv.h"
+#include "core/hle/service/filesystem/fsp/fsp_ldr.h"
+#include "core/hle/service/filesystem/fsp/fsp_pr.h"
+#include "core/hle/service/filesystem/fsp/fsp_srv.h"
+#include "core/hle/service/filesystem/romfs_controller.h"
+#include "core/hle/service/filesystem/save_data_controller.h"
#include "core/hle/service/server_manager.h"
#include "core/loader/loader.h"
namespace Service::FileSystem {
-// 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;
-
static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
std::string_view dir_name_) {
std::string dir_name(Common::FS::SanitizePath(dir_name_));
@@ -55,12 +52,12 @@ Result VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size
std::string path(Common::FS::SanitizePath(path_));
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
if (dir == nullptr) {
- return FileSys::ERROR_PATH_NOT_FOUND;
+ return FileSys::ResultPathNotFound;
}
- FileSys::EntryType entry_type{};
+ FileSys::DirectoryEntryType entry_type{};
if (GetEntryType(&entry_type, path) == ResultSuccess) {
- return FileSys::ERROR_PATH_ALREADY_EXISTS;
+ return FileSys::ResultPathAlreadyExists;
}
auto file = dir->CreateFile(Common::FS::GetFilename(path));
@@ -84,7 +81,7 @@ Result VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const {
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) {
- return FileSys::ERROR_PATH_NOT_FOUND;
+ return FileSys::ResultPathNotFound;
}
if (!dir->DeleteFile(Common::FS::GetFilename(path))) {
// TODO(DarkLordZach): Find a better error code for this
@@ -155,12 +152,12 @@ Result VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
// Use more-optimized vfs implementation rename.
if (src == nullptr) {
- return FileSys::ERROR_PATH_NOT_FOUND;
+ return FileSys::ResultPathNotFound;
}
if (dst && Common::FS::Exists(dst->GetFullPath())) {
LOG_ERROR(Service_FS, "File at new_path={} already exists", dst->GetFullPath());
- return FileSys::ERROR_PATH_ALREADY_EXISTS;
+ return FileSys::ResultPathAlreadyExists;
}
if (!src->Rename(Common::FS::GetFilename(dest_path))) {
@@ -197,7 +194,7 @@ Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_,
if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
// Use more-optimized vfs implementation rename.
if (src == nullptr)
- return FileSys::ERROR_PATH_NOT_FOUND;
+ return FileSys::ResultPathNotFound;
if (!src->Rename(Common::FS::GetFilename(dest_path))) {
// TODO(DarkLordZach): Find a better error code for this
return ResultUnknown;
@@ -216,7 +213,8 @@ Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_,
}
Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file,
- const std::string& path_, FileSys::Mode mode) const {
+ const std::string& path_,
+ FileSys::OpenMode mode) const {
const std::string path(Common::FS::SanitizePath(path_));
std::string_view npath = path;
while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) {
@@ -225,10 +223,10 @@ Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file,
auto file = backing->GetFileRelative(npath);
if (file == nullptr) {
- return FileSys::ERROR_PATH_NOT_FOUND;
+ return FileSys::ResultPathNotFound;
}
- if (mode == FileSys::Mode::Append) {
+ if (mode == FileSys::OpenMode::AllowAppend) {
*out_file = std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize());
} else {
*out_file = file;
@@ -243,50 +241,50 @@ Result VfsDirectoryServiceWrapper::OpenDirectory(FileSys::VirtualDir* out_direct
auto dir = GetDirectoryRelativeWrapped(backing, path);
if (dir == nullptr) {
// TODO(DarkLordZach): Find a better error code for this
- return FileSys::ERROR_PATH_NOT_FOUND;
+ return FileSys::ResultPathNotFound;
}
*out_directory = dir;
return ResultSuccess;
}
-Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::EntryType* out_entry_type,
+Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::DirectoryEntryType* out_entry_type,
const std::string& path_) const {
std::string path(Common::FS::SanitizePath(path_));
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
if (dir == nullptr) {
- return FileSys::ERROR_PATH_NOT_FOUND;
+ return FileSys::ResultPathNotFound;
}
auto filename = Common::FS::GetFilename(path);
// TODO(Subv): Some games use the '/' path, find out what this means.
if (filename.empty()) {
- *out_entry_type = FileSys::EntryType::Directory;
+ *out_entry_type = FileSys::DirectoryEntryType::Directory;
return ResultSuccess;
}
if (dir->GetFile(filename) != nullptr) {
- *out_entry_type = FileSys::EntryType::File;
+ *out_entry_type = FileSys::DirectoryEntryType::File;
return ResultSuccess;
}
if (dir->GetSubdirectory(filename) != nullptr) {
- *out_entry_type = FileSys::EntryType::Directory;
+ *out_entry_type = FileSys::DirectoryEntryType::Directory;
return ResultSuccess;
}
- return FileSys::ERROR_PATH_NOT_FOUND;
+ return FileSys::ResultPathNotFound;
}
Result VfsDirectoryServiceWrapper::GetFileTimeStampRaw(
FileSys::FileTimeStampRaw* out_file_time_stamp_raw, const std::string& path) const {
auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
if (dir == nullptr) {
- return FileSys::ERROR_PATH_NOT_FOUND;
+ return FileSys::ResultPathNotFound;
}
- FileSys::EntryType entry_type;
+ FileSys::DirectoryEntryType entry_type;
if (GetEntryType(&entry_type, path) != ResultSuccess) {
- return FileSys::ERROR_PATH_NOT_FOUND;
+ return FileSys::ResultPathNotFound;
}
*out_file_time_stamp_raw = dir->GetFileTimeStamp(Common::FS::GetFilename(path));
@@ -297,157 +295,77 @@ FileSystemController::FileSystemController(Core::System& system_) : system{syste
FileSystemController::~FileSystemController() = default;
-Result FileSystemController::RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
- romfs_factory = std::move(factory);
- LOG_DEBUG(Service_FS, "Registered RomFS");
- return ResultSuccess;
-}
-
-Result 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 ResultSuccess;
-}
+Result FileSystemController::RegisterProcess(
+ ProcessId process_id, ProgramId program_id,
+ std::shared_ptr<FileSys::RomFSFactory>&& romfs_factory) {
+ std::scoped_lock lk{registration_lock};
-Result 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 ResultSuccess;
-}
+ registrations.emplace(process_id, Registration{
+ .program_id = program_id,
+ .romfs_factory = std::move(romfs_factory),
+ .save_data_factory = CreateSaveDataFactory(program_id),
+ });
-Result 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");
+ LOG_DEBUG(Service_FS, "Registered for process {}", process_id);
return ResultSuccess;
}
-void FileSystemController::SetPackedUpdate(FileSys::VirtualFile update_raw) {
- LOG_TRACE(Service_FS, "Setting packed update for romfs");
-
- if (romfs_factory == nullptr)
- return;
-
- romfs_factory->SetPackedUpdate(std::move(update_raw));
-}
-
-FileSys::VirtualFile FileSystemController::OpenRomFSCurrentProcess() const {
- LOG_TRACE(Service_FS, "Opening RomFS for current process");
-
- if (romfs_factory == nullptr) {
- return nullptr;
- }
-
- return romfs_factory->OpenCurrentProcess(system.GetApplicationProcessProgramID());
-}
-
-FileSys::VirtualFile FileSystemController::OpenPatchedRomFS(u64 title_id,
- FileSys::ContentRecordType type) const {
- LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}", title_id);
-
- if (romfs_factory == nullptr) {
- return nullptr;
- }
-
- return romfs_factory->OpenPatchedRomFS(title_id, type);
-}
-
-FileSys::VirtualFile FileSystemController::OpenPatchedRomFSWithProgramIndex(
- u64 title_id, u8 program_index, FileSys::ContentRecordType type) const {
- LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}, program_index={}", title_id,
- program_index);
-
- if (romfs_factory == nullptr) {
- return nullptr;
- }
-
- return romfs_factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type);
-}
-
-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, storage_id, type);
-
- if (romfs_factory == nullptr) {
- return nullptr;
- }
-
- return romfs_factory->Open(title_id, storage_id, type);
-}
-
-std::shared_ptr<FileSys::NCA> FileSystemController::OpenBaseNca(
- u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const {
- return romfs_factory->GetEntry(title_id, storage_id, type);
-}
-
-Result FileSystemController::CreateSaveData(FileSys::VirtualDir* out_save_data,
- FileSys::SaveDataSpaceId space,
- const FileSys::SaveDataAttribute& save_struct) const {
- LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space,
- save_struct.DebugInfo());
-
- if (save_data_factory == nullptr) {
- return FileSys::ERROR_ENTITY_NOT_FOUND;
- }
+Result FileSystemController::OpenProcess(
+ ProgramId* out_program_id, std::shared_ptr<SaveDataController>* out_save_data_controller,
+ std::shared_ptr<RomFsController>* out_romfs_controller, ProcessId process_id) {
+ std::scoped_lock lk{registration_lock};
- auto save_data = save_data_factory->Create(space, save_struct);
- if (save_data == nullptr) {
- return FileSys::ERROR_ENTITY_NOT_FOUND;
+ const auto it = registrations.find(process_id);
+ if (it == registrations.end()) {
+ return FileSys::ResultTargetNotFound;
}
- *out_save_data = save_data;
+ *out_program_id = it->second.program_id;
+ *out_save_data_controller =
+ std::make_shared<SaveDataController>(system, it->second.save_data_factory);
+ *out_romfs_controller =
+ std::make_shared<RomFsController>(it->second.romfs_factory, it->second.program_id);
return ResultSuccess;
}
-Result FileSystemController::OpenSaveData(FileSys::VirtualDir* out_save_data,
- FileSys::SaveDataSpaceId space,
- const FileSys::SaveDataAttribute& attribute) const {
- LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", space,
- attribute.DebugInfo());
-
- if (save_data_factory == nullptr) {
- return FileSys::ERROR_ENTITY_NOT_FOUND;
- }
+void FileSystemController::SetPackedUpdate(ProcessId process_id, FileSys::VirtualFile update_raw) {
+ LOG_TRACE(Service_FS, "Setting packed update for romfs");
- auto save_data = save_data_factory->Open(space, attribute);
- if (save_data == nullptr) {
- return FileSys::ERROR_ENTITY_NOT_FOUND;
+ std::scoped_lock lk{registration_lock};
+ const auto it = registrations.find(process_id);
+ if (it == registrations.end()) {
+ return;
}
- *out_save_data = save_data;
- return ResultSuccess;
+ it->second.romfs_factory->SetPackedUpdate(std::move(update_raw));
}
-Result FileSystemController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
- FileSys::SaveDataSpaceId space) const {
- LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", space);
-
- if (save_data_factory == nullptr) {
- return FileSys::ERROR_ENTITY_NOT_FOUND;
- }
+std::shared_ptr<SaveDataController> FileSystemController::OpenSaveDataController() {
+ return std::make_shared<SaveDataController>(system, CreateSaveDataFactory(ProgramId{}));
+}
- auto save_data_space = save_data_factory->GetSaveDataSpaceDirectory(space);
- if (save_data_space == nullptr) {
- return FileSys::ERROR_ENTITY_NOT_FOUND;
- }
+std::shared_ptr<FileSys::SaveDataFactory> FileSystemController::CreateSaveDataFactory(
+ ProgramId program_id) {
+ using YuzuPath = Common::FS::YuzuPath;
+ const auto rw_mode = FileSys::OpenMode::ReadWrite;
- *out_save_data_space = save_data_space;
- return ResultSuccess;
+ auto vfs = system.GetFilesystem();
+ const auto nand_directory =
+ vfs->OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode);
+ return std::make_shared<FileSys::SaveDataFactory>(system, program_id,
+ std::move(nand_directory));
}
Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const {
LOG_TRACE(Service_FS, "Opening SDMC");
if (sdmc_factory == nullptr) {
- return FileSys::ERROR_SD_CARD_NOT_FOUND;
+ return FileSys::ResultPortSdCardNoDevice;
}
auto sdmc = sdmc_factory->Open();
if (sdmc == nullptr) {
- return FileSys::ERROR_SD_CARD_NOT_FOUND;
+ return FileSys::ResultPortSdCardNoDevice;
}
*out_sdmc = sdmc;
@@ -459,12 +377,12 @@ Result FileSystemController::OpenBISPartition(FileSys::VirtualDir* out_bis_parti
LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", id);
if (bis_factory == nullptr) {
- return FileSys::ERROR_ENTITY_NOT_FOUND;
+ return FileSys::ResultTargetNotFound;
}
auto part = bis_factory->OpenPartition(id);
if (part == nullptr) {
- return FileSys::ERROR_INVALID_ARGUMENT;
+ return FileSys::ResultInvalidArgument;
}
*out_bis_partition = part;
@@ -476,12 +394,12 @@ Result FileSystemController::OpenBISPartitionStorage(
LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", id);
if (bis_factory == nullptr) {
- return FileSys::ERROR_ENTITY_NOT_FOUND;
+ return FileSys::ResultTargetNotFound;
}
auto part = bis_factory->OpenPartitionStorage(id, system.GetFilesystem());
if (part == nullptr) {
- return FileSys::ERROR_INVALID_ARGUMENT;
+ return FileSys::ResultInvalidArgument;
}
*out_bis_partition_storage = part;
@@ -540,48 +458,6 @@ u64 FileSystemController::GetTotalSpaceSize(FileSys::StorageId id) const {
return 0;
}
-FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataType type,
- u64 title_id, u128 user_id) const {
- if (save_data_factory == nullptr) {
- return {0, 0};
- }
-
- const auto value = save_data_factory->ReadSaveDataSize(type, title_id, user_id);
-
- if (value.normal == 0 && value.journal == 0) {
- FileSys::SaveDataSize new_size{SUFFICIENT_SAVE_DATA_SIZE, SUFFICIENT_SAVE_DATA_SIZE};
-
- FileSys::NACP nacp;
- const auto res = system.GetAppLoader().ReadControlData(nacp);
-
- if (res != Loader::ResultStatus::Success) {
- const FileSys::PatchManager pm{system.GetApplicationProcessProgramID(),
- system.GetFileSystemController(),
- system.GetContentProvider()};
- const auto metadata = pm.GetControlMetadata();
- const auto& nacp_unique = metadata.first;
-
- if (nacp_unique != nullptr) {
- new_size = {nacp_unique->GetDefaultNormalSaveSize(),
- nacp_unique->GetDefaultJournalSaveSize()};
- }
- } else {
- new_size = {nacp.GetDefaultNormalSaveSize(), nacp.GetDefaultJournalSaveSize()};
- }
-
- WriteSaveDataSize(type, title_id, user_id, new_size);
- return new_size;
- }
-
- return 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);
-}
-
void FileSystemController::SetGameCard(FileSys::VirtualFile file) {
gamecard = std::make_unique<FileSys::XCI>(file);
const auto dir = gamecard->ConcatenatedPseudoDirectory();
@@ -801,29 +677,24 @@ FileSys::VirtualDir FileSystemController::GetBCATDirectory(u64 title_id) const {
return bis_factory->GetBCATDirectory(title_id);
}
-void FileSystemController::SetAutoSaveDataCreation(bool enable) {
- save_data_factory->SetAutoCreate(enable);
-}
-
void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
if (overwrite) {
bis_factory = nullptr;
- save_data_factory = nullptr;
sdmc_factory = nullptr;
}
using YuzuPath = Common::FS::YuzuPath;
const auto sdmc_dir_path = Common::FS::GetYuzuPath(YuzuPath::SDMCDir);
const auto sdmc_load_dir_path = sdmc_dir_path / "atmosphere/contents";
- const auto rw_mode = FileSys::Mode::ReadWrite;
+ const auto rw_mode = FileSys::OpenMode::ReadWrite;
auto nand_directory =
vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode);
auto sd_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_dir_path), rw_mode);
- auto load_directory =
- vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir), FileSys::Mode::Read);
- auto sd_load_directory =
- vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_load_dir_path), FileSys::Mode::Read);
+ auto load_directory = vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir),
+ FileSys::OpenMode::Read);
+ auto sd_load_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_load_dir_path),
+ FileSys::OpenMode::Read);
auto dump_directory =
vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::DumpDir), rw_mode);
@@ -836,11 +707,6 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove
bis_factory->GetUserNANDContents());
}
- if (save_data_factory == nullptr) {
- save_data_factory =
- std::make_unique<FileSys::SaveDataFactory>(system, std::move(nand_directory));
- }
-
if (sdmc_factory == nullptr) {
sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory),
std::move(sd_load_directory));
@@ -849,12 +715,19 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove
}
}
+void FileSystemController::Reset() {
+ std::scoped_lock lk{registration_lock};
+ registrations.clear();
+}
+
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
+ const auto FileSystemProxyFactory = [&] { return std::make_shared<FSP_SRV>(system); };
+
server_manager->RegisterNamedService("fsp-ldr", std::make_shared<FSP_LDR>(system));
server_manager->RegisterNamedService("fsp:pr", std::make_shared<FSP_PR>(system));
- server_manager->RegisterNamedService("fsp-srv", std::make_shared<FSP_SRV>(system));
+ server_manager->RegisterNamedService("fsp-srv", std::move(FileSystemProxyFactory));
ServerManager::RunServer(std::move(server_manager));
}
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index 276d264e1..718500385 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -4,9 +4,11 @@
#pragma once
#include <memory>
+#include <mutex>
#include "common/common_types.h"
-#include "core/file_sys/directory.h"
-#include "core/file_sys/vfs.h"
+#include "core/file_sys/fs_directory.h"
+#include "core/file_sys/fs_filesystem.h"
+#include "core/file_sys/vfs/vfs.h"
#include "core/hle/result.h"
namespace Core {
@@ -26,7 +28,6 @@ class XCI;
enum class BisPartitionId : u32;
enum class ContentRecordType : u8;
-enum class Mode : u32;
enum class SaveDataSpaceId : u8;
enum class SaveDataType : u8;
enum class StorageId : u8;
@@ -43,6 +44,9 @@ class ServiceManager;
namespace FileSystem {
+class RomFsController;
+class SaveDataController;
+
enum class ContentStorageId : u32 {
System,
User,
@@ -54,39 +58,24 @@ enum class ImageDirectoryId : u32 {
SdCard,
};
-enum class OpenDirectoryMode : u64 {
- Directory = (1 << 0),
- File = (1 << 1),
- All = Directory | File
-};
-DECLARE_ENUM_FLAG_OPERATORS(OpenDirectoryMode);
+using ProcessId = u64;
+using ProgramId = u64;
class FileSystemController {
public:
explicit FileSystemController(Core::System& system_);
~FileSystemController();
- Result RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory);
- Result RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory);
- Result RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory);
- Result RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory);
-
- void SetPackedUpdate(FileSys::VirtualFile update_raw);
- FileSys::VirtualFile OpenRomFSCurrentProcess() const;
- FileSys::VirtualFile OpenPatchedRomFS(u64 title_id, FileSys::ContentRecordType type) const;
- FileSys::VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index,
- FileSys::ContentRecordType type) const;
- FileSys::VirtualFile OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
- FileSys::ContentRecordType type) const;
- std::shared_ptr<FileSys::NCA> OpenBaseNca(u64 title_id, FileSys::StorageId storage_id,
- FileSys::ContentRecordType type) const;
-
- Result CreateSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space,
- const FileSys::SaveDataAttribute& save_struct) const;
- Result OpenSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space,
- const FileSys::SaveDataAttribute& save_struct) const;
- Result OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
- FileSys::SaveDataSpaceId space) const;
+ Result RegisterProcess(ProcessId process_id, ProgramId program_id,
+ std::shared_ptr<FileSys::RomFSFactory>&& factory);
+ Result OpenProcess(ProgramId* out_program_id,
+ std::shared_ptr<SaveDataController>* out_save_data_controller,
+ std::shared_ptr<RomFsController>* out_romfs_controller,
+ ProcessId process_id);
+ void SetPackedUpdate(ProcessId process_id, FileSys::VirtualFile update_raw);
+
+ std::shared_ptr<SaveDataController> OpenSaveDataController();
+
Result OpenSDMC(FileSys::VirtualDir* out_sdmc) const;
Result OpenBISPartition(FileSys::VirtualDir* out_bis_partition,
FileSys::BisPartitionId id) const;
@@ -96,11 +85,6 @@ public:
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;
@@ -133,15 +117,24 @@ public:
FileSys::VirtualDir GetBCATDirectory(u64 title_id) const;
- void SetAutoSaveDataCreation(bool enable);
-
// 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);
+ void Reset();
+
private:
- std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
- std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
+ std::shared_ptr<FileSys::SaveDataFactory> CreateSaveDataFactory(ProgramId program_id);
+
+ struct Registration {
+ ProgramId program_id;
+ std::shared_ptr<FileSys::RomFSFactory> romfs_factory;
+ std::shared_ptr<FileSys::SaveDataFactory> save_data_factory;
+ };
+
+ std::mutex registration_lock;
+ std::map<ProcessId, Registration> registrations;
+
std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
std::unique_ptr<FileSys::BISFactory> bis_factory;
@@ -238,7 +231,7 @@ public:
* @return Opened file, or error code
*/
Result OpenFile(FileSys::VirtualFile* out_file, const std::string& path,
- FileSys::Mode mode) const;
+ FileSys::OpenMode mode) const;
/**
* Open a directory specified by its path
@@ -251,7 +244,7 @@ public:
* Get the type of the specified path
* @return The type of the specified path or error code
*/
- Result GetEntryType(FileSys::EntryType* out_entry_type, const std::string& path) const;
+ Result GetEntryType(FileSys::DirectoryEntryType* out_entry_type, const std::string& path) const;
/**
* Get the timestamp of the specified path
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
new file mode 100644
index 000000000..39690018b
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.cpp
@@ -0,0 +1,84 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/file_sys/fs_filesystem.h"
+#include "core/file_sys/savedata_factory.h"
+#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
+#include "core/hle/service/ipc_helpers.h"
+
+namespace Service::FileSystem {
+
+template <typename T>
+static void BuildEntryIndex(std::vector<FileSys::DirectoryEntry>& entries,
+ const std::vector<T>& new_data, FileSys::DirectoryEntryType type) {
+ entries.reserve(entries.size() + new_data.size());
+
+ for (const auto& new_entry : new_data) {
+ auto name = new_entry->GetName();
+
+ if (type == FileSys::DirectoryEntryType::File &&
+ name == FileSys::GetSaveDataSizeFileName()) {
+ continue;
+ }
+
+ entries.emplace_back(name, static_cast<s8>(type),
+ type == FileSys::DirectoryEntryType::Directory ? 0
+ : new_entry->GetSize());
+ }
+}
+
+IDirectory::IDirectory(Core::System& system_, FileSys::VirtualDir backend_,
+ FileSys::OpenDirectoryMode mode)
+ : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
+ static const FunctionInfo functions[] = {
+ {0, &IDirectory::Read, "Read"},
+ {1, &IDirectory::GetEntryCount, "GetEntryCount"},
+ };
+ RegisterHandlers(functions);
+
+ // TODO(DarkLordZach): Verify that this is the correct behavior.
+ // Build entry index now to save time later.
+ if (True(mode & FileSys::OpenDirectoryMode::Directory)) {
+ BuildEntryIndex(entries, backend->GetSubdirectories(),
+ FileSys::DirectoryEntryType::Directory);
+ }
+ if (True(mode & FileSys::OpenDirectoryMode::File)) {
+ BuildEntryIndex(entries, backend->GetFiles(), FileSys::DirectoryEntryType::File);
+ }
+}
+
+void IDirectory::Read(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called.");
+
+ // Calculate how many entries we can fit in the output buffer
+ const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::DirectoryEntry>();
+
+ // Cap at total number of entries.
+ const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
+
+ // Determine data start and end
+ const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
+ const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
+ const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
+
+ next_entry_index += actual_entries;
+
+ // Write the data to memory
+ ctx.WriteBuffer(begin, range_size);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push(actual_entries);
+}
+
+void IDirectory::GetEntryCount(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ u64 count = entries.size() - next_entry_index;
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push(count);
+}
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_directory.h b/src/core/hle/service/filesystem/fsp/fs_i_directory.h
new file mode 100644
index 000000000..793ecfcd7
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_directory.h
@@ -0,0 +1,30 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/file_sys/vfs/vfs.h"
+#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/service.h"
+
+namespace FileSys {
+struct DirectoryEntry;
+}
+
+namespace Service::FileSystem {
+
+class IDirectory final : public ServiceFramework<IDirectory> {
+public:
+ explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_,
+ FileSys::OpenDirectoryMode mode);
+
+private:
+ FileSys::VirtualDir backend;
+ std::vector<FileSys::DirectoryEntry> entries;
+ u64 next_entry_index = 0;
+
+ void Read(HLERequestContext& ctx);
+ void GetEntryCount(HLERequestContext& ctx);
+};
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.cpp b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
new file mode 100644
index 000000000..9a18f6ec5
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_file.cpp
@@ -0,0 +1,127 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/file_sys/errors.h"
+#include "core/hle/service/filesystem/fsp/fs_i_file.h"
+#include "core/hle/service/ipc_helpers.h"
+
+namespace Service::FileSystem {
+
+IFile::IFile(Core::System& system_, FileSys::VirtualFile backend_)
+ : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
+ static const FunctionInfo functions[] = {
+ {0, &IFile::Read, "Read"},
+ {1, &IFile::Write, "Write"},
+ {2, &IFile::Flush, "Flush"},
+ {3, &IFile::SetSize, "SetSize"},
+ {4, &IFile::GetSize, "GetSize"},
+ {5, nullptr, "OperateRange"},
+ {6, nullptr, "OperateRangeWithBuffer"},
+ };
+ RegisterHandlers(functions);
+}
+
+void IFile::Read(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const u64 option = rp.Pop<u64>();
+ const s64 offset = rp.Pop<s64>();
+ const s64 length = rp.Pop<s64>();
+
+ LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length);
+
+ // Error checking
+ if (length < 0) {
+ LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(FileSys::ResultInvalidSize);
+ return;
+ }
+ if (offset < 0) {
+ LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(FileSys::ResultInvalidOffset);
+ return;
+ }
+
+ // Read the data from the Storage backend
+ std::vector<u8> output = backend->ReadBytes(length, offset);
+
+ // Write the data to memory
+ ctx.WriteBuffer(output);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push(static_cast<u64>(output.size()));
+}
+
+void IFile::Write(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const u64 option = rp.Pop<u64>();
+ const s64 offset = rp.Pop<s64>();
+ const s64 length = rp.Pop<s64>();
+
+ LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset, length);
+
+ // Error checking
+ if (length < 0) {
+ LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(FileSys::ResultInvalidSize);
+ return;
+ }
+ if (offset < 0) {
+ LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(FileSys::ResultInvalidOffset);
+ return;
+ }
+
+ const auto data = ctx.ReadBuffer();
+
+ ASSERT_MSG(static_cast<s64>(data.size()) <= length,
+ "Attempting to write more data than requested (requested={:016X}, actual={:016X}).",
+ length, data.size());
+
+ // Write the data to the Storage backend
+ const auto write_size =
+ static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length));
+ const std::size_t written = backend->Write(data.data(), write_size, offset);
+
+ ASSERT_MSG(static_cast<s64>(written) == length,
+ "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length,
+ written);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IFile::Flush(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ // Exists for SDK compatibiltity -- No need to flush file.
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IFile::SetSize(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const u64 size = rp.Pop<u64>();
+ LOG_DEBUG(Service_FS, "called, size={}", size);
+
+ backend->Resize(size);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IFile::GetSize(HLERequestContext& ctx) {
+ const u64 size = backend->GetSize();
+ LOG_DEBUG(Service_FS, "called, size={}", size);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push<u64>(size);
+}
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_file.h b/src/core/hle/service/filesystem/fsp/fs_i_file.h
new file mode 100644
index 000000000..5e5430c67
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_file.h
@@ -0,0 +1,25 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/service.h"
+
+namespace Service::FileSystem {
+
+class IFile final : public ServiceFramework<IFile> {
+public:
+ explicit IFile(Core::System& system_, FileSys::VirtualFile backend_);
+
+private:
+ FileSys::VirtualFile backend;
+
+ void Read(HLERequestContext& ctx);
+ void Write(HLERequestContext& ctx);
+ void Flush(HLERequestContext& ctx);
+ void SetSize(HLERequestContext& ctx);
+ void GetSize(HLERequestContext& ctx);
+};
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
new file mode 100644
index 000000000..efa394dd1
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.cpp
@@ -0,0 +1,262 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/string_util.h"
+#include "core/hle/service/filesystem/fsp/fs_i_directory.h"
+#include "core/hle/service/filesystem/fsp/fs_i_file.h"
+#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
+#include "core/hle/service/ipc_helpers.h"
+
+namespace Service::FileSystem {
+
+IFileSystem::IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
+ : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move(
+ size_)} {
+ static const FunctionInfo functions[] = {
+ {0, &IFileSystem::CreateFile, "CreateFile"},
+ {1, &IFileSystem::DeleteFile, "DeleteFile"},
+ {2, &IFileSystem::CreateDirectory, "CreateDirectory"},
+ {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"},
+ {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"},
+ {5, &IFileSystem::RenameFile, "RenameFile"},
+ {6, nullptr, "RenameDirectory"},
+ {7, &IFileSystem::GetEntryType, "GetEntryType"},
+ {8, &IFileSystem::OpenFile, "OpenFile"},
+ {9, &IFileSystem::OpenDirectory, "OpenDirectory"},
+ {10, &IFileSystem::Commit, "Commit"},
+ {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"},
+ {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"},
+ {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
+ {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"},
+ {15, nullptr, "QueryEntry"},
+ {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"},
+ };
+ RegisterHandlers(functions);
+}
+
+void IFileSystem::CreateFile(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const auto file_buffer = ctx.ReadBuffer();
+ const std::string name = Common::StringFromBuffer(file_buffer);
+
+ const u64 file_mode = rp.Pop<u64>();
+ const u32 file_size = rp.Pop<u32>();
+
+ LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode,
+ file_size);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(backend.CreateFile(name, file_size));
+}
+
+void IFileSystem::DeleteFile(HLERequestContext& ctx) {
+ const auto file_buffer = ctx.ReadBuffer();
+ const std::string name = Common::StringFromBuffer(file_buffer);
+
+ LOG_DEBUG(Service_FS, "called. file={}", name);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(backend.DeleteFile(name));
+}
+
+void IFileSystem::CreateDirectory(HLERequestContext& ctx) {
+ const auto file_buffer = ctx.ReadBuffer();
+ const std::string name = Common::StringFromBuffer(file_buffer);
+
+ LOG_DEBUG(Service_FS, "called. directory={}", name);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(backend.CreateDirectory(name));
+}
+
+void IFileSystem::DeleteDirectory(HLERequestContext& ctx) {
+ const auto file_buffer = ctx.ReadBuffer();
+ const std::string name = Common::StringFromBuffer(file_buffer);
+
+ LOG_DEBUG(Service_FS, "called. directory={}", name);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(backend.DeleteDirectory(name));
+}
+
+void IFileSystem::DeleteDirectoryRecursively(HLERequestContext& ctx) {
+ const auto file_buffer = ctx.ReadBuffer();
+ const std::string name = Common::StringFromBuffer(file_buffer);
+
+ LOG_DEBUG(Service_FS, "called. directory={}", name);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(backend.DeleteDirectoryRecursively(name));
+}
+
+void IFileSystem::CleanDirectoryRecursively(HLERequestContext& ctx) {
+ const auto file_buffer = ctx.ReadBuffer();
+ const std::string name = Common::StringFromBuffer(file_buffer);
+
+ LOG_DEBUG(Service_FS, "called. Directory: {}", name);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(backend.CleanDirectoryRecursively(name));
+}
+
+void IFileSystem::RenameFile(HLERequestContext& ctx) {
+ const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0));
+ const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1));
+
+ LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(backend.RenameFile(src_name, dst_name));
+}
+
+void IFileSystem::OpenFile(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const auto file_buffer = ctx.ReadBuffer();
+ const std::string name = Common::StringFromBuffer(file_buffer);
+
+ const auto mode = static_cast<FileSys::OpenMode>(rp.Pop<u32>());
+
+ LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
+
+ FileSys::VirtualFile vfs_file{};
+ auto result = backend.OpenFile(&vfs_file, name, mode);
+ if (result != ResultSuccess) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
+
+ auto file = std::make_shared<IFile>(system, vfs_file);
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IFile>(std::move(file));
+}
+
+void IFileSystem::OpenDirectory(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const auto file_buffer = ctx.ReadBuffer();
+ const std::string name = Common::StringFromBuffer(file_buffer);
+ const auto mode = rp.PopRaw<FileSys::OpenDirectoryMode>();
+
+ LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode);
+
+ FileSys::VirtualDir vfs_dir{};
+ auto result = backend.OpenDirectory(&vfs_dir, name);
+ if (result != ResultSuccess) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
+
+ auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode);
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IDirectory>(std::move(directory));
+}
+
+void IFileSystem::GetEntryType(HLERequestContext& ctx) {
+ const auto file_buffer = ctx.ReadBuffer();
+ const std::string name = Common::StringFromBuffer(file_buffer);
+
+ LOG_DEBUG(Service_FS, "called. file={}", name);
+
+ FileSys::DirectoryEntryType vfs_entry_type{};
+ auto result = backend.GetEntryType(&vfs_entry_type, name);
+ if (result != ResultSuccess) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push<u32>(static_cast<u32>(vfs_entry_type));
+}
+
+void IFileSystem::Commit(HLERequestContext& ctx) {
+ LOG_WARNING(Service_FS, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IFileSystem::GetFreeSpaceSize(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push(size.get_free_size());
+}
+
+void IFileSystem::GetTotalSpaceSize(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push(size.get_total_size());
+}
+
+void IFileSystem::GetFileTimeStampRaw(HLERequestContext& ctx) {
+ const auto file_buffer = ctx.ReadBuffer();
+ const std::string name = Common::StringFromBuffer(file_buffer);
+
+ LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
+
+ FileSys::FileTimeStampRaw vfs_timestamp{};
+ auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name);
+ if (result != ResultSuccess) {
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ return;
+ }
+
+ IPC::ResponseBuilder rb{ctx, 10};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(vfs_timestamp);
+}
+
+void IFileSystem::GetFileSystemAttribute(HLERequestContext& ctx) {
+ LOG_WARNING(Service_FS, "(STUBBED) called");
+
+ struct FileSystemAttribute {
+ u8 dir_entry_name_length_max_defined;
+ u8 file_entry_name_length_max_defined;
+ u8 dir_path_name_length_max_defined;
+ u8 file_path_name_length_max_defined;
+ INSERT_PADDING_BYTES_NOINIT(0x5);
+ u8 utf16_dir_entry_name_length_max_defined;
+ u8 utf16_file_entry_name_length_max_defined;
+ u8 utf16_dir_path_name_length_max_defined;
+ u8 utf16_file_path_name_length_max_defined;
+ INSERT_PADDING_BYTES_NOINIT(0x18);
+ s32 dir_entry_name_length_max;
+ s32 file_entry_name_length_max;
+ s32 dir_path_name_length_max;
+ s32 file_path_name_length_max;
+ INSERT_PADDING_WORDS_NOINIT(0x5);
+ s32 utf16_dir_entry_name_length_max;
+ s32 utf16_file_entry_name_length_max;
+ s32 utf16_dir_path_name_length_max;
+ s32 utf16_file_path_name_length_max;
+ INSERT_PADDING_WORDS_NOINIT(0x18);
+ INSERT_PADDING_WORDS_NOINIT(0x1);
+ };
+ static_assert(sizeof(FileSystemAttribute) == 0xc0, "FileSystemAttribute has incorrect size");
+
+ FileSystemAttribute savedata_attribute{};
+ savedata_attribute.dir_entry_name_length_max_defined = true;
+ savedata_attribute.file_entry_name_length_max_defined = true;
+ savedata_attribute.dir_entry_name_length_max = 0x40;
+ savedata_attribute.file_entry_name_length_max = 0x40;
+
+ IPC::ResponseBuilder rb{ctx, 50};
+ rb.Push(ResultSuccess);
+ rb.PushRaw(savedata_attribute);
+}
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
new file mode 100644
index 000000000..b06b3ef0e
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_filesystem.h
@@ -0,0 +1,38 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/file_sys/vfs/vfs.h"
+#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/filesystem/fsp/fsp_util.h"
+#include "core/hle/service/service.h"
+
+namespace Service::FileSystem {
+
+class IFileSystem final : public ServiceFramework<IFileSystem> {
+public:
+ explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_);
+
+ void CreateFile(HLERequestContext& ctx);
+ void DeleteFile(HLERequestContext& ctx);
+ void CreateDirectory(HLERequestContext& ctx);
+ void DeleteDirectory(HLERequestContext& ctx);
+ void DeleteDirectoryRecursively(HLERequestContext& ctx);
+ void CleanDirectoryRecursively(HLERequestContext& ctx);
+ void RenameFile(HLERequestContext& ctx);
+ void OpenFile(HLERequestContext& ctx);
+ void OpenDirectory(HLERequestContext& ctx);
+ void GetEntryType(HLERequestContext& ctx);
+ void Commit(HLERequestContext& ctx);
+ void GetFreeSpaceSize(HLERequestContext& ctx);
+ void GetTotalSpaceSize(HLERequestContext& ctx);
+ void GetFileTimeStampRaw(HLERequestContext& ctx);
+ void GetFileSystemAttribute(HLERequestContext& ctx);
+
+private:
+ VfsDirectoryServiceWrapper backend;
+ SizeGetter size;
+};
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
new file mode 100644
index 000000000..98223c1f9
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.cpp
@@ -0,0 +1,62 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/file_sys/errors.h"
+#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
+#include "core/hle/service/ipc_helpers.h"
+
+namespace Service::FileSystem {
+
+IStorage::IStorage(Core::System& system_, FileSys::VirtualFile backend_)
+ : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
+ static const FunctionInfo functions[] = {
+ {0, &IStorage::Read, "Read"},
+ {1, nullptr, "Write"},
+ {2, nullptr, "Flush"},
+ {3, nullptr, "SetSize"},
+ {4, &IStorage::GetSize, "GetSize"},
+ {5, nullptr, "OperateRange"},
+ };
+ RegisterHandlers(functions);
+}
+
+void IStorage::Read(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const s64 offset = rp.Pop<s64>();
+ const s64 length = rp.Pop<s64>();
+
+ LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
+
+ // Error checking
+ if (length < 0) {
+ LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(FileSys::ResultInvalidSize);
+ return;
+ }
+ if (offset < 0) {
+ LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(FileSys::ResultInvalidOffset);
+ return;
+ }
+
+ // Read the data from the Storage backend
+ std::vector<u8> output = backend->ReadBytes(length, offset);
+ // Write the data to memory
+ ctx.WriteBuffer(output);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IStorage::GetSize(HLERequestContext& ctx) {
+ const u64 size = backend->GetSize();
+ LOG_DEBUG(Service_FS, "called, size={}", size);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push<u64>(size);
+}
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fs_i_storage.h b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
new file mode 100644
index 000000000..cb5bebcc9
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fs_i_storage.h
@@ -0,0 +1,23 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/file_sys/vfs/vfs.h"
+#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/service.h"
+
+namespace Service::FileSystem {
+
+class IStorage final : public ServiceFramework<IStorage> {
+public:
+ explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_);
+
+private:
+ FileSys::VirtualFile backend;
+
+ void Read(HLERequestContext& ctx);
+ void GetSize(HLERequestContext& ctx);
+};
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp/fsp_ldr.cpp
new file mode 100644
index 000000000..8ee733f47
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fsp_ldr.cpp
@@ -0,0 +1,22 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/filesystem/fsp/fsp_ldr.h"
+
+namespace Service::FileSystem {
+
+FSP_LDR::FSP_LDR(Core::System& system_) : ServiceFramework{system_, "fsp:ldr"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "OpenCodeFileSystem"},
+ {1, nullptr, "IsArchivedProgram"},
+ {2, nullptr, "SetCurrentProcess"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+FSP_LDR::~FSP_LDR() = default;
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_ldr.h b/src/core/hle/service/filesystem/fsp/fsp_ldr.h
index 358739a87..358739a87 100644
--- a/src/core/hle/service/filesystem/fsp_ldr.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_ldr.h
diff --git a/src/core/hle/service/filesystem/fsp/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp/fsp_pr.cpp
new file mode 100644
index 000000000..7c03ebaea
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fsp_pr.cpp
@@ -0,0 +1,23 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/filesystem/fsp/fsp_pr.h"
+
+namespace Service::FileSystem {
+
+FSP_PR::FSP_PR(Core::System& system_) : ServiceFramework{system_, "fsp:pr"} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "RegisterProgram"},
+ {1, nullptr, "UnregisterProgram"},
+ {2, nullptr, "SetCurrentProcess"},
+ {256, nullptr, "SetEnabledProgramVerification"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+}
+
+FSP_PR::~FSP_PR() = default;
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_pr.h b/src/core/hle/service/filesystem/fsp/fsp_pr.h
index bd4e0a730..bd4e0a730 100644
--- a/src/core/hle/service/filesystem/fsp_pr.h
+++ b/src/core/hle/service/filesystem/fsp/fsp_pr.h
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
new file mode 100644
index 000000000..2be72b021
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.cpp
@@ -0,0 +1,727 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <cinttypes>
+#include <cstring>
+#include <iterator>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "common/assert.h"
+#include "common/common_types.h"
+#include "common/hex_util.h"
+#include "common/logging/log.h"
+#include "common/settings.h"
+#include "common/string_util.h"
+#include "core/core.h"
+#include "core/file_sys/errors.h"
+#include "core/file_sys/fs_directory.h"
+#include "core/file_sys/fs_filesystem.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/vfs.h"
+#include "core/hle/result.h"
+#include "core/hle/service/filesystem/filesystem.h"
+#include "core/hle/service/filesystem/fsp/fs_i_filesystem.h"
+#include "core/hle/service/filesystem/fsp/fs_i_storage.h"
+#include "core/hle/service/filesystem/fsp/fsp_srv.h"
+#include "core/hle/service/filesystem/romfs_controller.h"
+#include "core/hle/service/filesystem/save_data_controller.h"
+#include "core/hle/service/hle_ipc.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/reporter.h"
+
+namespace Service::FileSystem {
+enum class FileSystemType : u8 {
+ Invalid0 = 0,
+ Invalid1 = 1,
+ Logo = 2,
+ ContentControl = 3,
+ ContentManual = 4,
+ ContentMeta = 5,
+ ContentData = 6,
+ ApplicationPackage = 7,
+};
+
+class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
+public:
+ explicit ISaveDataInfoReader(Core::System& system_,
+ std::shared_ptr<SaveDataController> save_data_controller_,
+ FileSys::SaveDataSpaceId space)
+ : ServiceFramework{system_, "ISaveDataInfoReader"}, save_data_controller{
+ save_data_controller_} {
+ static const FunctionInfo functions[] = {
+ {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
+ };
+ RegisterHandlers(functions);
+
+ FindAllSaves(space);
+ }
+
+ void ReadSaveDataInfo(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ // Calculate how many entries we can fit in the output buffer
+ const u64 count_entries = ctx.GetWriteBufferNumElements<SaveDataInfo>();
+
+ // Cap at total number of entries.
+ const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
+
+ // Determine data start and end
+ const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
+ const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
+ const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
+
+ next_entry_index += actual_entries;
+
+ // Write the data to memory
+ ctx.WriteBuffer(begin, range_size);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.Push<u64>(actual_entries);
+ }
+
+private:
+ static u64 stoull_be(std::string_view str) {
+ if (str.size() != 16)
+ return 0;
+
+ const auto bytes = Common::HexStringToArray<0x8>(str);
+ u64 out{};
+ std::memcpy(&out, bytes.data(), sizeof(u64));
+
+ return Common::swap64(out);
+ }
+
+ void FindAllSaves(FileSys::SaveDataSpaceId space) {
+ FileSys::VirtualDir save_root{};
+ const auto result = save_data_controller->OpenSaveDataSpace(&save_root, space);
+
+ if (result != ResultSuccess || save_root == nullptr) {
+ LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
+ return;
+ }
+
+ for (const auto& type : save_root->GetSubdirectories()) {
+ if (type->GetName() == "save") {
+ for (const auto& save_id : type->GetSubdirectories()) {
+ for (const auto& user_id : save_id->GetSubdirectories()) {
+ const auto save_id_numeric = stoull_be(save_id->GetName());
+ auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
+ std::reverse(user_id_numeric.begin(), user_id_numeric.end());
+
+ if (save_id_numeric != 0) {
+ // System Save Data
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ FileSys::SaveDataType::SystemSaveData,
+ {},
+ user_id_numeric,
+ save_id_numeric,
+ 0,
+ user_id->GetSize(),
+ {},
+ {},
+ });
+
+ continue;
+ }
+
+ for (const auto& title_id : user_id->GetSubdirectories()) {
+ const auto device =
+ std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
+ [](u8 val) { return val == 0; });
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ device ? FileSys::SaveDataType::DeviceSaveData
+ : FileSys::SaveDataType::SaveData,
+ {},
+ user_id_numeric,
+ save_id_numeric,
+ stoull_be(title_id->GetName()),
+ title_id->GetSize(),
+ {},
+ {},
+ });
+ }
+ }
+ }
+ } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
+ // Temporary Storage
+ for (const auto& user_id : type->GetSubdirectories()) {
+ for (const auto& title_id : user_id->GetSubdirectories()) {
+ if (!title_id->GetFiles().empty() ||
+ !title_id->GetSubdirectories().empty()) {
+ auto user_id_numeric =
+ Common::HexStringToArray<0x10>(user_id->GetName());
+ std::reverse(user_id_numeric.begin(), user_id_numeric.end());
+
+ info.emplace_back(SaveDataInfo{
+ 0,
+ space,
+ FileSys::SaveDataType::TemporaryStorage,
+ {},
+ user_id_numeric,
+ stoull_be(type->GetName()),
+ stoull_be(title_id->GetName()),
+ title_id->GetSize(),
+ {},
+ {},
+ });
+ }
+ }
+ }
+ }
+ }
+ }
+
+ struct SaveDataInfo {
+ u64_le save_id_unknown;
+ FileSys::SaveDataSpaceId space;
+ FileSys::SaveDataType type;
+ INSERT_PADDING_BYTES(0x6);
+ std::array<u8, 0x10> user_id;
+ u64_le save_id;
+ u64_le title_id;
+ u64_le save_image_size;
+ u16_le index;
+ FileSys::SaveDataRank rank;
+ INSERT_PADDING_BYTES(0x25);
+ };
+ static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
+
+ ProcessId process_id = 0;
+ std::shared_ptr<SaveDataController> save_data_controller;
+ std::vector<SaveDataInfo> info;
+ u64 next_entry_index = 0;
+};
+
+FSP_SRV::FSP_SRV(Core::System& system_)
+ : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()},
+ content_provider{system.GetContentProvider()}, reporter{system.GetReporter()} {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, nullptr, "OpenFileSystem"},
+ {1, &FSP_SRV::SetCurrentProcess, "SetCurrentProcess"},
+ {2, nullptr, "OpenDataFileSystemByCurrentProcess"},
+ {7, &FSP_SRV::OpenFileSystemWithPatch, "OpenFileSystemWithPatch"},
+ {8, nullptr, "OpenFileSystemWithId"},
+ {9, nullptr, "OpenDataFileSystemByApplicationId"},
+ {11, nullptr, "OpenBisFileSystem"},
+ {12, nullptr, "OpenBisStorage"},
+ {13, nullptr, "InvalidateBisCache"},
+ {17, nullptr, "OpenHostFileSystem"},
+ {18, &FSP_SRV::OpenSdCardFileSystem, "OpenSdCardFileSystem"},
+ {19, nullptr, "FormatSdCardFileSystem"},
+ {21, nullptr, "DeleteSaveDataFileSystem"},
+ {22, &FSP_SRV::CreateSaveDataFileSystem, "CreateSaveDataFileSystem"},
+ {23, &FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId, "CreateSaveDataFileSystemBySystemSaveDataId"},
+ {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"},
+ {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"},
+ {26, nullptr, "FormatSdCardDryRun"},
+ {27, nullptr, "IsExFatSupported"},
+ {28, nullptr, "DeleteSaveDataFileSystemBySaveDataAttribute"},
+ {30, nullptr, "OpenGameCardStorage"},
+ {31, nullptr, "OpenGameCardFileSystem"},
+ {32, nullptr, "ExtendSaveDataFileSystem"},
+ {33, nullptr, "DeleteCacheStorage"},
+ {34, &FSP_SRV::GetCacheStorageSize, "GetCacheStorageSize"},
+ {35, nullptr, "CreateSaveDataFileSystemByHashSalt"},
+ {36, nullptr, "OpenHostFileSystemWithOption"},
+ {51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"},
+ {52, &FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId, "OpenSaveDataFileSystemBySystemSaveDataId"},
+ {53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"},
+ {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"},
+ {58, nullptr, "ReadSaveDataFileSystemExtraData"},
+ {59, nullptr, "WriteSaveDataFileSystemExtraData"},
+ {60, nullptr, "OpenSaveDataInfoReader"},
+ {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
+ {62, &FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage, "OpenSaveDataInfoReaderOnlyCacheStorage"},
+ {64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
+ {65, nullptr, "UpdateSaveDataMacForDebug"},
+ {66, nullptr, "WriteSaveDataFileSystemExtraData2"},
+ {67, nullptr, "FindSaveDataWithFilter"},
+ {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"},
+ {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"},
+ {70, &FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
+ {71, &FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
+ {80, nullptr, "OpenSaveDataMetaFile"},
+ {81, nullptr, "OpenSaveDataTransferManager"},
+ {82, nullptr, "OpenSaveDataTransferManagerVersion2"},
+ {83, nullptr, "OpenSaveDataTransferProhibiterForCloudBackUp"},
+ {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"},
+ {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"},
+ {86, nullptr, "OpenSaveDataMover"},
+ {87, nullptr, "OpenSaveDataTransferManagerForRepair"},
+ {100, nullptr, "OpenImageDirectoryFileSystem"},
+ {101, nullptr, "OpenBaseFileSystem"},
+ {102, nullptr, "FormatBaseFileSystem"},
+ {110, nullptr, "OpenContentStorageFileSystem"},
+ {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
+ {130, nullptr, "OpenCustomStorageFileSystem"},
+ {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"},
+ {201, nullptr, "OpenDataStorageByProgramId"},
+ {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"},
+ {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"},
+ {204, nullptr, "OpenDataFileSystemByProgramIndex"},
+ {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"},
+ {206, nullptr, "OpenDataStorageByPath"},
+ {400, nullptr, "OpenDeviceOperator"},
+ {500, nullptr, "OpenSdCardDetectionEventNotifier"},
+ {501, nullptr, "OpenGameCardDetectionEventNotifier"},
+ {510, nullptr, "OpenSystemDataUpdateEventNotifier"},
+ {511, nullptr, "NotifySystemDataUpdateEvent"},
+ {520, nullptr, "SimulateGameCardDetectionEvent"},
+ {600, nullptr, "SetCurrentPosixTime"},
+ {601, nullptr, "QuerySaveDataTotalSize"},
+ {602, nullptr, "VerifySaveDataFileSystem"},
+ {603, nullptr, "CorruptSaveDataFileSystem"},
+ {604, nullptr, "CreatePaddingFile"},
+ {605, nullptr, "DeleteAllPaddingFiles"},
+ {606, nullptr, "GetRightsId"},
+ {607, nullptr, "RegisterExternalKey"},
+ {608, nullptr, "UnregisterAllExternalKey"},
+ {609, nullptr, "GetRightsIdByPath"},
+ {610, nullptr, "GetRightsIdAndKeyGenerationByPath"},
+ {611, nullptr, "SetCurrentPosixTimeWithTimeDifference"},
+ {612, nullptr, "GetFreeSpaceSizeForSaveData"},
+ {613, nullptr, "VerifySaveDataFileSystemBySaveDataSpaceId"},
+ {614, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId"},
+ {615, nullptr, "QuerySaveDataInternalStorageTotalSize"},
+ {616, nullptr, "GetSaveDataCommitId"},
+ {617, nullptr, "UnregisterExternalKey"},
+ {620, nullptr, "SetSdCardEncryptionSeed"},
+ {630, nullptr, "SetSdCardAccessibility"},
+ {631, nullptr, "IsSdCardAccessible"},
+ {640, nullptr, "IsSignedSystemPartitionOnSdCardValid"},
+ {700, nullptr, "OpenAccessFailureResolver"},
+ {701, nullptr, "GetAccessFailureDetectionEvent"},
+ {702, nullptr, "IsAccessFailureDetected"},
+ {710, nullptr, "ResolveAccessFailure"},
+ {720, nullptr, "AbandonAccessFailure"},
+ {800, nullptr, "GetAndClearFileSystemProxyErrorInfo"},
+ {810, nullptr, "RegisterProgramIndexMapInfo"},
+ {1000, nullptr, "SetBisRootForHost"},
+ {1001, nullptr, "SetSaveDataSize"},
+ {1002, nullptr, "SetSaveDataRootPath"},
+ {1003, &FSP_SRV::DisableAutoSaveDataCreation, "DisableAutoSaveDataCreation"},
+ {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"},
+ {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"},
+ {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"},
+ {1007, nullptr, "RegisterUpdatePartition"},
+ {1008, nullptr, "OpenRegisteredUpdatePartition"},
+ {1009, nullptr, "GetAndClearMemoryReportInfo"},
+ {1010, nullptr, "SetDataStorageRedirectTarget"},
+ {1011, &FSP_SRV::GetProgramIndexForAccessLog, "GetProgramIndexForAccessLog"},
+ {1012, nullptr, "GetFsStackUsage"},
+ {1013, nullptr, "UnsetSaveDataRootPath"},
+ {1014, nullptr, "OutputMultiProgramTagAccessLog"},
+ {1016, nullptr, "FlushAccessLogOnSdCard"},
+ {1017, nullptr, "OutputApplicationInfoAccessLog"},
+ {1018, nullptr, "SetDebugOption"},
+ {1019, nullptr, "UnsetDebugOption"},
+ {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
+ {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
+ {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"},
+ {1300, nullptr, "OpenBisWiper"},
+ };
+ // clang-format on
+ RegisterHandlers(functions);
+
+ if (Settings::values.enable_fs_access_log) {
+ access_log_mode = AccessLogMode::SdCard;
+ }
+}
+
+FSP_SRV::~FSP_SRV() = default;
+
+void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) {
+ current_process_id = ctx.GetPID();
+
+ LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id);
+
+ const auto res =
+ fsc.OpenProcess(&program_id, &save_data_controller, &romfs_controller, current_process_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(res);
+}
+
+void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const auto type = rp.PopRaw<FileSystemType>();
+ const auto title_id = rp.PopRaw<u64>();
+ LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", type, title_id);
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 0};
+ rb.Push(ResultUnknown);
+}
+
+void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ FileSys::VirtualDir sdmc_dir{};
+ fsc.OpenSDMC(&sdmc_dir);
+
+ auto filesystem = std::make_shared<IFileSystem>(
+ system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
+}
+
+void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
+ [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
+ u128 uid = rp.PopRaw<u128>();
+
+ LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
+ uid[1], uid[0]);
+
+ FileSys::VirtualDir save_data_dir{};
+ save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser,
+ save_struct);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
+ [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
+
+ LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo());
+
+ FileSys::VirtualDir save_data_dir{};
+ save_data_controller->CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem,
+ save_struct);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ struct Parameters {
+ FileSys::SaveDataSpaceId space_id;
+ FileSys::SaveDataAttribute attribute;
+ };
+
+ const auto parameters = rp.PopRaw<Parameters>();
+
+ LOG_INFO(Service_FS, "called.");
+
+ FileSys::VirtualDir dir{};
+ auto result =
+ save_data_controller->OpenSaveData(&dir, parameters.space_id, parameters.attribute);
+ if (result != ResultSuccess) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 0};
+ rb.Push(FileSys::ResultTargetNotFound);
+ return;
+ }
+
+ FileSys::StorageId id{};
+ switch (parameters.space_id) {
+ case FileSys::SaveDataSpaceId::NandUser:
+ id = FileSys::StorageId::NandUser;
+ break;
+ case FileSys::SaveDataSpaceId::SdCardSystem:
+ case FileSys::SaveDataSpaceId::SdCardUser:
+ id = FileSys::StorageId::SdCard;
+ break;
+ case FileSys::SaveDataSpaceId::NandSystem:
+ id = FileSys::StorageId::NandSystem;
+ break;
+ case FileSys::SaveDataSpaceId::TemporaryStorage:
+ case FileSys::SaveDataSpaceId::ProperSystem:
+ case FileSys::SaveDataSpaceId::SafeMode:
+ ASSERT(false);
+ }
+
+ auto filesystem =
+ std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id));
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
+}
+
+void FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) {
+ LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
+ OpenSaveDataFileSystem(ctx);
+}
+
+void FSP_SRV::OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx) {
+ LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
+ OpenSaveDataFileSystem(ctx);
+}
+
+void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
+ LOG_INFO(Service_FS, "called, space={}", space);
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<ISaveDataInfoReader>(
+ std::make_shared<ISaveDataInfoReader>(system, save_data_controller, space));
+}
+
+void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) {
+ LOG_WARNING(Service_FS, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<ISaveDataInfoReader>(system, save_data_controller,
+ FileSys::SaveDataSpaceId::TemporaryStorage);
+}
+
+void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) {
+ LOG_WARNING(Service_FS, "(STUBBED) called.");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ struct Parameters {
+ FileSys::SaveDataSpaceId space_id;
+ FileSys::SaveDataAttribute attribute;
+ };
+
+ const auto parameters = rp.PopRaw<Parameters>();
+ // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
+ constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
+
+ LOG_WARNING(Service_FS,
+ "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n"
+ "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
+ "attribute.type={}, attribute.rank={}, attribute.index={}",
+ flags, parameters.space_id, parameters.attribute.title_id,
+ parameters.attribute.user_id[1], parameters.attribute.user_id[0],
+ parameters.attribute.save_id, parameters.attribute.type, parameters.attribute.rank,
+ parameters.attribute.index);
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.Push(flags);
+}
+
+void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ if (!romfs) {
+ auto current_romfs = romfs_controller->OpenRomFSCurrentProcess();
+ if (!current_romfs) {
+ // TODO (bunnei): Find the right error code to use here
+ LOG_CRITICAL(Service_FS, "no file system interface available!");
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ romfs = current_romfs;
+ }
+
+ auto storage = std::make_shared<IStorage>(system, romfs);
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IStorage>(std::move(storage));
+}
+
+void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto storage_id = rp.PopRaw<FileSys::StorageId>();
+ const auto unknown = rp.PopRaw<u32>();
+ const auto title_id = rp.PopRaw<u64>();
+
+ LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
+ storage_id, unknown, title_id);
+
+ auto data = romfs_controller->OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
+
+ if (!data) {
+ const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
+
+ if (archive != nullptr) {
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface(std::make_shared<IStorage>(system, archive));
+ return;
+ }
+
+ // TODO(DarkLordZach): Find the right error code to use here
+ LOG_ERROR(Service_FS,
+ "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
+ storage_id);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ const FileSys::PatchManager pm{title_id, fsc, content_provider};
+
+ auto base =
+ romfs_controller->OpenBaseNca(title_id, storage_id, FileSys::ContentRecordType::Data);
+ auto storage = std::make_shared<IStorage>(
+ system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data));
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IStorage>(std::move(storage));
+}
+
+void FSP_SRV::OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const auto storage_id = rp.PopRaw<FileSys::StorageId>();
+ const auto title_id = rp.PopRaw<u64>();
+
+ LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(FileSys::ResultTargetNotFound);
+}
+
+void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+
+ const auto program_index = rp.PopRaw<u8>();
+
+ LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
+
+ auto patched_romfs = romfs_controller->OpenPatchedRomFSWithProgramIndex(
+ program_id, program_index, FileSys::ContentRecordType::Program);
+
+ if (!patched_romfs) {
+ // TODO: Find the right error code to use here
+ LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultUnknown);
+ return;
+ }
+
+ auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs));
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IStorage>(std::move(storage));
+}
+
+void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ save_data_controller->SetAutoCreate(false);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void FSP_SRV::SetGlobalAccessLogMode(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ access_log_mode = rp.PopEnum<AccessLogMode>();
+
+ LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void FSP_SRV::GetGlobalAccessLogMode(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ IPC::ResponseBuilder rb{ctx, 3};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(access_log_mode);
+}
+
+void FSP_SRV::OutputAccessLogToSdCard(HLERequestContext& ctx) {
+ const auto raw = ctx.ReadBufferCopy();
+ auto log = Common::StringFromFixedZeroTerminatedBuffer(
+ reinterpret_cast<const char*>(raw.data()), raw.size());
+
+ LOG_DEBUG(Service_FS, "called");
+
+ reporter.SaveFSAccessLog(log);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void FSP_SRV::GetProgramIndexForAccessLog(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(ResultSuccess);
+ rb.PushEnum(AccessLogVersion::Latest);
+ rb.Push(access_log_program_index);
+}
+
+void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ const auto index{rp.Pop<s32>()};
+
+ LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index);
+
+ IPC::ResponseBuilder rb{ctx, 6};
+ rb.Push(ResultSuccess);
+ rb.Push(s64{0});
+ rb.Push(s64{0});
+}
+
+class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
+public:
+ explicit IMultiCommitManager(Core::System& system_)
+ : ServiceFramework{system_, "IMultiCommitManager"} {
+ static const FunctionInfo functions[] = {
+ {1, &IMultiCommitManager::Add, "Add"},
+ {2, &IMultiCommitManager::Commit, "Commit"},
+ };
+ RegisterHandlers(functions);
+ }
+
+private:
+ FileSys::VirtualFile backend;
+
+ void Add(HLERequestContext& ctx) {
+ LOG_WARNING(Service_FS, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ void Commit(HLERequestContext& ctx) {
+ LOG_WARNING(Service_FS, "(STUBBED) called");
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+};
+
+void FSP_SRV::OpenMultiCommitManager(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_FS, "called");
+
+ IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+ rb.Push(ResultSuccess);
+ rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>(system));
+}
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fsp_srv.h b/src/core/hle/service/filesystem/fsp/fsp_srv.h
new file mode 100644
index 000000000..26980af99
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fsp_srv.h
@@ -0,0 +1,78 @@
+// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <memory>
+#include "core/hle/service/service.h"
+
+namespace Core {
+class Reporter;
+}
+
+namespace FileSys {
+class ContentProvider;
+class FileSystemBackend;
+} // namespace FileSys
+
+namespace Service::FileSystem {
+
+class RomFsController;
+class SaveDataController;
+
+enum class AccessLogVersion : u32 {
+ V7_0_0 = 2,
+
+ Latest = V7_0_0,
+};
+
+enum class AccessLogMode : u32 {
+ None,
+ Log,
+ SdCard,
+};
+
+class FSP_SRV final : public ServiceFramework<FSP_SRV> {
+public:
+ explicit FSP_SRV(Core::System& system_);
+ ~FSP_SRV() override;
+
+private:
+ void SetCurrentProcess(HLERequestContext& ctx);
+ void OpenFileSystemWithPatch(HLERequestContext& ctx);
+ void OpenSdCardFileSystem(HLERequestContext& ctx);
+ void CreateSaveDataFileSystem(HLERequestContext& ctx);
+ void CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx);
+ void OpenSaveDataFileSystem(HLERequestContext& ctx);
+ void OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx);
+ void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx);
+ void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx);
+ void OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx);
+ void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx);
+ void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx);
+ void OpenDataStorageByCurrentProcess(HLERequestContext& ctx);
+ void OpenDataStorageByDataId(HLERequestContext& ctx);
+ void OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx);
+ void OpenDataStorageWithProgramIndex(HLERequestContext& ctx);
+ void DisableAutoSaveDataCreation(HLERequestContext& ctx);
+ void SetGlobalAccessLogMode(HLERequestContext& ctx);
+ void GetGlobalAccessLogMode(HLERequestContext& ctx);
+ void OutputAccessLogToSdCard(HLERequestContext& ctx);
+ void GetProgramIndexForAccessLog(HLERequestContext& ctx);
+ void OpenMultiCommitManager(HLERequestContext& ctx);
+ void GetCacheStorageSize(HLERequestContext& ctx);
+
+ FileSystemController& fsc;
+ const FileSys::ContentProvider& content_provider;
+ const Core::Reporter& reporter;
+
+ FileSys::VirtualFile romfs;
+ u64 current_process_id = 0;
+ u32 access_log_program_index = 0;
+ AccessLogMode access_log_mode = AccessLogMode::None;
+ u64 program_id = 0;
+ std::shared_ptr<SaveDataController> save_data_controller;
+ std::shared_ptr<RomFsController> romfs_controller;
+};
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp/fsp_util.h b/src/core/hle/service/filesystem/fsp/fsp_util.h
new file mode 100644
index 000000000..253f866db
--- /dev/null
+++ b/src/core/hle/service/filesystem/fsp/fsp_util.h
@@ -0,0 +1,22 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/hle/service/filesystem/filesystem.h"
+
+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); },
+ };
+ }
+};
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_ldr.cpp b/src/core/hle/service/filesystem/fsp_ldr.cpp
deleted file mode 100644
index 1e3366e71..000000000
--- a/src/core/hle/service/filesystem/fsp_ldr.cpp
+++ /dev/null
@@ -1,22 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "core/hle/service/filesystem/fsp_ldr.h"
-
-namespace Service::FileSystem {
-
-FSP_LDR::FSP_LDR(Core::System& system_) : ServiceFramework{system_, "fsp:ldr"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "OpenCodeFileSystem"},
- {1, nullptr, "IsArchivedProgram"},
- {2, nullptr, "SetCurrentProcess"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-FSP_LDR::~FSP_LDR() = default;
-
-} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_pr.cpp b/src/core/hle/service/filesystem/fsp_pr.cpp
deleted file mode 100644
index 4ffc31977..000000000
--- a/src/core/hle/service/filesystem/fsp_pr.cpp
+++ /dev/null
@@ -1,23 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include "core/hle/service/filesystem/fsp_pr.h"
-
-namespace Service::FileSystem {
-
-FSP_PR::FSP_PR(Core::System& system_) : ServiceFramework{system_, "fsp:pr"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "RegisterProgram"},
- {1, nullptr, "UnregisterProgram"},
- {2, nullptr, "SetCurrentProcess"},
- {256, nullptr, "SetEnabledProgramVerification"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
-}
-
-FSP_PR::~FSP_PR() = default;
-
-} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
deleted file mode 100644
index 82ecc1b90..000000000
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ /dev/null
@@ -1,1250 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <cinttypes>
-#include <cstring>
-#include <iterator>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "common/assert.h"
-#include "common/common_types.h"
-#include "common/hex_util.h"
-#include "common/logging/log.h"
-#include "common/settings.h"
-#include "common/string_util.h"
-#include "core/core.h"
-#include "core/file_sys/directory.h"
-#include "core/file_sys/errors.h"
-#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"
-#include "core/hle/result.h"
-#include "core/hle/service/filesystem/filesystem.h"
-#include "core/hle/service/filesystem/fsp_srv.h"
-#include "core/hle/service/hle_ipc.h"
-#include "core/hle/service/ipc_helpers.h"
-#include "core/reporter.h"
-
-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,
- Logo = 2,
- ContentControl = 3,
- ContentManual = 4,
- ContentMeta = 5,
- ContentData = 6,
- ApplicationPackage = 7,
-};
-
-class IStorage final : public ServiceFramework<IStorage> {
-public:
- explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_)
- : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
- static const FunctionInfo functions[] = {
- {0, &IStorage::Read, "Read"},
- {1, nullptr, "Write"},
- {2, nullptr, "Flush"},
- {3, nullptr, "SetSize"},
- {4, &IStorage::GetSize, "GetSize"},
- {5, nullptr, "OperateRange"},
- };
- RegisterHandlers(functions);
- }
-
-private:
- FileSys::VirtualFile backend;
-
- void Read(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const s64 offset = rp.Pop<s64>();
- const s64 length = rp.Pop<s64>();
-
- LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
-
- // Error checking
- if (length < 0) {
- LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ERROR_INVALID_SIZE);
- return;
- }
- if (offset < 0) {
- LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ERROR_INVALID_OFFSET);
- return;
- }
-
- // Read the data from the Storage backend
- std::vector<u8> output = backend->ReadBytes(length, offset);
- // Write the data to memory
- ctx.WriteBuffer(output);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetSize(HLERequestContext& ctx) {
- const u64 size = backend->GetSize();
- LOG_DEBUG(Service_FS, "called, size={}", size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push<u64>(size);
- }
-};
-
-class IFile final : public ServiceFramework<IFile> {
-public:
- explicit IFile(Core::System& system_, FileSys::VirtualFile backend_)
- : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
- static const FunctionInfo functions[] = {
- {0, &IFile::Read, "Read"},
- {1, &IFile::Write, "Write"},
- {2, &IFile::Flush, "Flush"},
- {3, &IFile::SetSize, "SetSize"},
- {4, &IFile::GetSize, "GetSize"},
- {5, nullptr, "OperateRange"},
- {6, nullptr, "OperateRangeWithBuffer"},
- };
- RegisterHandlers(functions);
- }
-
-private:
- FileSys::VirtualFile backend;
-
- void Read(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const u64 option = rp.Pop<u64>();
- const s64 offset = rp.Pop<s64>();
- const s64 length = rp.Pop<s64>();
-
- LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset,
- length);
-
- // Error checking
- if (length < 0) {
- LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ERROR_INVALID_SIZE);
- return;
- }
- if (offset < 0) {
- LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ERROR_INVALID_OFFSET);
- return;
- }
-
- // Read the data from the Storage backend
- std::vector<u8> output = backend->ReadBytes(length, offset);
-
- // Write the data to memory
- ctx.WriteBuffer(output);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(static_cast<u64>(output.size()));
- }
-
- void Write(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const u64 option = rp.Pop<u64>();
- const s64 offset = rp.Pop<s64>();
- const s64 length = rp.Pop<s64>();
-
- LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset,
- length);
-
- // Error checking
- if (length < 0) {
- LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ERROR_INVALID_SIZE);
- return;
- }
- if (offset < 0) {
- LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ERROR_INVALID_OFFSET);
- return;
- }
-
- const auto data = ctx.ReadBuffer();
-
- ASSERT_MSG(
- static_cast<s64>(data.size()) <= length,
- "Attempting to write more data than requested (requested={:016X}, actual={:016X}).",
- length, data.size());
-
- // Write the data to the Storage backend
- const auto write_size =
- static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length));
- const std::size_t written = backend->Write(data.data(), write_size, offset);
-
- ASSERT_MSG(static_cast<s64>(written) == length,
- "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length,
- written);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void Flush(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
-
- // Exists for SDK compatibiltity -- No need to flush file.
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void SetSize(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const u64 size = rp.Pop<u64>();
- LOG_DEBUG(Service_FS, "called, size={}", size);
-
- backend->Resize(size);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetSize(HLERequestContext& ctx) {
- const u64 size = backend->GetSize();
- LOG_DEBUG(Service_FS, "called, size={}", size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push<u64>(size);
- }
-};
-
-template <typename T>
-static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data,
- FileSys::EntryType type) {
- entries.reserve(entries.size() + new_data.size());
-
- for (const auto& new_entry : new_data) {
- auto name = new_entry->GetName();
-
- if (type == FileSys::EntryType::File && name == FileSys::GetSaveDataSizeFileName()) {
- continue;
- }
-
- entries.emplace_back(name, type,
- type == FileSys::EntryType::Directory ? 0 : new_entry->GetSize());
- }
-}
-
-class IDirectory final : public ServiceFramework<IDirectory> {
-public:
- explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_, OpenDirectoryMode mode)
- : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
- static const FunctionInfo functions[] = {
- {0, &IDirectory::Read, "Read"},
- {1, &IDirectory::GetEntryCount, "GetEntryCount"},
- };
- RegisterHandlers(functions);
-
- // TODO(DarkLordZach): Verify that this is the correct behavior.
- // Build entry index now to save time later.
- if (True(mode & OpenDirectoryMode::Directory)) {
- BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory);
- }
- if (True(mode & OpenDirectoryMode::File)) {
- BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File);
- }
- }
-
-private:
- FileSys::VirtualDir backend;
- std::vector<FileSys::Entry> entries;
- u64 next_entry_index = 0;
-
- void Read(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called.");
-
- // Calculate how many entries we can fit in the output buffer
- const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::Entry>();
-
- // Cap at total number of entries.
- const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
-
- // Determine data start and end
- const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
- const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
- const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
-
- next_entry_index += actual_entries;
-
- // Write the data to memory
- ctx.WriteBuffer(begin, range_size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(actual_entries);
- }
-
- void GetEntryCount(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
-
- u64 count = entries.size() - next_entry_index;
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(count);
- }
-};
-
-class IFileSystem final : public ServiceFramework<IFileSystem> {
-public:
- explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
- : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move(
- size_)} {
- static const FunctionInfo functions[] = {
- {0, &IFileSystem::CreateFile, "CreateFile"},
- {1, &IFileSystem::DeleteFile, "DeleteFile"},
- {2, &IFileSystem::CreateDirectory, "CreateDirectory"},
- {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"},
- {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"},
- {5, &IFileSystem::RenameFile, "RenameFile"},
- {6, nullptr, "RenameDirectory"},
- {7, &IFileSystem::GetEntryType, "GetEntryType"},
- {8, &IFileSystem::OpenFile, "OpenFile"},
- {9, &IFileSystem::OpenDirectory, "OpenDirectory"},
- {10, &IFileSystem::Commit, "Commit"},
- {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"},
- {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"},
- {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
- {14, &IFileSystem::GetFileTimeStampRaw, "GetFileTimeStampRaw"},
- {15, nullptr, "QueryEntry"},
- {16, &IFileSystem::GetFileSystemAttribute, "GetFileSystemAttribute"},
- };
- RegisterHandlers(functions);
- }
-
- void CreateFile(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- const u64 file_mode = rp.Pop<u64>();
- const u32 file_size = rp.Pop<u32>();
-
- LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, file_mode,
- file_size);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.CreateFile(name, file_size));
- }
-
- void DeleteFile(HLERequestContext& ctx) {
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- LOG_DEBUG(Service_FS, "called. file={}", name);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.DeleteFile(name));
- }
-
- void CreateDirectory(HLERequestContext& ctx) {
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- LOG_DEBUG(Service_FS, "called. directory={}", name);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.CreateDirectory(name));
- }
-
- void DeleteDirectory(HLERequestContext& ctx) {
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- LOG_DEBUG(Service_FS, "called. directory={}", name);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.DeleteDirectory(name));
- }
-
- void DeleteDirectoryRecursively(HLERequestContext& ctx) {
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- LOG_DEBUG(Service_FS, "called. directory={}", name);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.DeleteDirectoryRecursively(name));
- }
-
- void CleanDirectoryRecursively(HLERequestContext& ctx) {
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- LOG_DEBUG(Service_FS, "called. Directory: {}", name);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.CleanDirectoryRecursively(name));
- }
-
- void RenameFile(HLERequestContext& ctx) {
- const std::string src_name = Common::StringFromBuffer(ctx.ReadBuffer(0));
- const std::string dst_name = Common::StringFromBuffer(ctx.ReadBuffer(1));
-
- LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(backend.RenameFile(src_name, dst_name));
- }
-
- void OpenFile(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>());
-
- LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
-
- FileSys::VirtualFile vfs_file{};
- auto result = backend.OpenFile(&vfs_file, name, mode);
- if (result != ResultSuccess) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- auto file = std::make_shared<IFile>(system, vfs_file);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IFile>(std::move(file));
- }
-
- void OpenDirectory(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
- const auto mode = rp.PopRaw<OpenDirectoryMode>();
-
- LOG_DEBUG(Service_FS, "called. directory={}, mode={}", name, mode);
-
- FileSys::VirtualDir vfs_dir{};
- auto result = backend.OpenDirectory(&vfs_dir, name);
- if (result != ResultSuccess) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- auto directory = std::make_shared<IDirectory>(system, vfs_dir, mode);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IDirectory>(std::move(directory));
- }
-
- void GetEntryType(HLERequestContext& ctx) {
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- LOG_DEBUG(Service_FS, "called. file={}", name);
-
- FileSys::EntryType vfs_entry_type{};
- auto result = backend.GetEntryType(&vfs_entry_type, name);
- if (result != ResultSuccess) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push<u32>(static_cast<u32>(vfs_entry_type));
- }
-
- void Commit(HLERequestContext& ctx) {
- LOG_WARNING(Service_FS, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void GetFreeSpaceSize(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(size.get_free_size());
- }
-
- void GetTotalSpaceSize(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(size.get_total_size());
- }
-
- void GetFileTimeStampRaw(HLERequestContext& ctx) {
- const auto file_buffer = ctx.ReadBuffer();
- const std::string name = Common::StringFromBuffer(file_buffer);
-
- LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
-
- FileSys::FileTimeStampRaw vfs_timestamp{};
- auto result = backend.GetFileTimeStampRaw(&vfs_timestamp, name);
- if (result != ResultSuccess) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- return;
- }
-
- IPC::ResponseBuilder rb{ctx, 10};
- rb.Push(ResultSuccess);
- rb.PushRaw(vfs_timestamp);
- }
-
- void GetFileSystemAttribute(HLERequestContext& ctx) {
- LOG_WARNING(Service_FS, "(STUBBED) called");
-
- struct FileSystemAttribute {
- u8 dir_entry_name_length_max_defined;
- u8 file_entry_name_length_max_defined;
- u8 dir_path_name_length_max_defined;
- u8 file_path_name_length_max_defined;
- INSERT_PADDING_BYTES_NOINIT(0x5);
- u8 utf16_dir_entry_name_length_max_defined;
- u8 utf16_file_entry_name_length_max_defined;
- u8 utf16_dir_path_name_length_max_defined;
- u8 utf16_file_path_name_length_max_defined;
- INSERT_PADDING_BYTES_NOINIT(0x18);
- s32 dir_entry_name_length_max;
- s32 file_entry_name_length_max;
- s32 dir_path_name_length_max;
- s32 file_path_name_length_max;
- INSERT_PADDING_WORDS_NOINIT(0x5);
- s32 utf16_dir_entry_name_length_max;
- s32 utf16_file_entry_name_length_max;
- s32 utf16_dir_path_name_length_max;
- s32 utf16_file_path_name_length_max;
- INSERT_PADDING_WORDS_NOINIT(0x18);
- INSERT_PADDING_WORDS_NOINIT(0x1);
- };
- static_assert(sizeof(FileSystemAttribute) == 0xc0,
- "FileSystemAttribute has incorrect size");
-
- FileSystemAttribute savedata_attribute{};
- savedata_attribute.dir_entry_name_length_max_defined = true;
- savedata_attribute.file_entry_name_length_max_defined = true;
- savedata_attribute.dir_entry_name_length_max = 0x40;
- savedata_attribute.file_entry_name_length_max = 0x40;
-
- IPC::ResponseBuilder rb{ctx, 50};
- rb.Push(ResultSuccess);
- rb.PushRaw(savedata_attribute);
- }
-
-private:
- VfsDirectoryServiceWrapper backend;
- SizeGetter size;
-};
-
-class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
-public:
- explicit ISaveDataInfoReader(Core::System& system_, FileSys::SaveDataSpaceId space,
- FileSystemController& fsc_)
- : ServiceFramework{system_, "ISaveDataInfoReader"}, fsc{fsc_} {
- static const FunctionInfo functions[] = {
- {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
- };
- RegisterHandlers(functions);
-
- FindAllSaves(space);
- }
-
- void ReadSaveDataInfo(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
-
- // Calculate how many entries we can fit in the output buffer
- const u64 count_entries = ctx.GetWriteBufferNumElements<SaveDataInfo>();
-
- // Cap at total number of entries.
- const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
-
- // Determine data start and end
- const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
- const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
- const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
-
- next_entry_index += actual_entries;
-
- // Write the data to memory
- ctx.WriteBuffer(begin, range_size);
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push<u64>(actual_entries);
- }
-
-private:
- static u64 stoull_be(std::string_view str) {
- if (str.size() != 16)
- return 0;
-
- const auto bytes = Common::HexStringToArray<0x8>(str);
- u64 out{};
- std::memcpy(&out, bytes.data(), sizeof(u64));
-
- return Common::swap64(out);
- }
-
- void FindAllSaves(FileSys::SaveDataSpaceId space) {
- FileSys::VirtualDir save_root{};
- const auto result = fsc.OpenSaveDataSpace(&save_root, space);
-
- if (result != ResultSuccess || save_root == nullptr) {
- LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
- return;
- }
-
- for (const auto& type : save_root->GetSubdirectories()) {
- if (type->GetName() == "save") {
- for (const auto& save_id : type->GetSubdirectories()) {
- for (const auto& user_id : save_id->GetSubdirectories()) {
- const auto save_id_numeric = stoull_be(save_id->GetName());
- auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
- std::reverse(user_id_numeric.begin(), user_id_numeric.end());
-
- if (save_id_numeric != 0) {
- // System Save Data
- info.emplace_back(SaveDataInfo{
- 0,
- space,
- FileSys::SaveDataType::SystemSaveData,
- {},
- user_id_numeric,
- save_id_numeric,
- 0,
- user_id->GetSize(),
- {},
- {},
- });
-
- continue;
- }
-
- for (const auto& title_id : user_id->GetSubdirectories()) {
- const auto device =
- std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
- [](u8 val) { return val == 0; });
- info.emplace_back(SaveDataInfo{
- 0,
- space,
- device ? FileSys::SaveDataType::DeviceSaveData
- : FileSys::SaveDataType::SaveData,
- {},
- user_id_numeric,
- save_id_numeric,
- stoull_be(title_id->GetName()),
- title_id->GetSize(),
- {},
- {},
- });
- }
- }
- }
- } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
- // Temporary Storage
- for (const auto& user_id : type->GetSubdirectories()) {
- for (const auto& title_id : user_id->GetSubdirectories()) {
- if (!title_id->GetFiles().empty() ||
- !title_id->GetSubdirectories().empty()) {
- auto user_id_numeric =
- Common::HexStringToArray<0x10>(user_id->GetName());
- std::reverse(user_id_numeric.begin(), user_id_numeric.end());
-
- info.emplace_back(SaveDataInfo{
- 0,
- space,
- FileSys::SaveDataType::TemporaryStorage,
- {},
- user_id_numeric,
- stoull_be(type->GetName()),
- stoull_be(title_id->GetName()),
- title_id->GetSize(),
- {},
- {},
- });
- }
- }
- }
- }
- }
- }
-
- struct SaveDataInfo {
- u64_le save_id_unknown;
- FileSys::SaveDataSpaceId space;
- FileSys::SaveDataType type;
- INSERT_PADDING_BYTES(0x6);
- std::array<u8, 0x10> user_id;
- u64_le save_id;
- u64_le title_id;
- u64_le save_image_size;
- u16_le index;
- FileSys::SaveDataRank rank;
- INSERT_PADDING_BYTES(0x25);
- };
- static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
-
- FileSystemController& fsc;
- std::vector<SaveDataInfo> info;
- u64 next_entry_index = 0;
-};
-
-FSP_SRV::FSP_SRV(Core::System& system_)
- : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()},
- content_provider{system.GetContentProvider()}, reporter{system.GetReporter()} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, nullptr, "OpenFileSystem"},
- {1, &FSP_SRV::SetCurrentProcess, "SetCurrentProcess"},
- {2, nullptr, "OpenDataFileSystemByCurrentProcess"},
- {7, &FSP_SRV::OpenFileSystemWithPatch, "OpenFileSystemWithPatch"},
- {8, nullptr, "OpenFileSystemWithId"},
- {9, nullptr, "OpenDataFileSystemByApplicationId"},
- {11, nullptr, "OpenBisFileSystem"},
- {12, nullptr, "OpenBisStorage"},
- {13, nullptr, "InvalidateBisCache"},
- {17, nullptr, "OpenHostFileSystem"},
- {18, &FSP_SRV::OpenSdCardFileSystem, "OpenSdCardFileSystem"},
- {19, nullptr, "FormatSdCardFileSystem"},
- {21, nullptr, "DeleteSaveDataFileSystem"},
- {22, &FSP_SRV::CreateSaveDataFileSystem, "CreateSaveDataFileSystem"},
- {23, &FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId, "CreateSaveDataFileSystemBySystemSaveDataId"},
- {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"},
- {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"},
- {26, nullptr, "FormatSdCardDryRun"},
- {27, nullptr, "IsExFatSupported"},
- {28, nullptr, "DeleteSaveDataFileSystemBySaveDataAttribute"},
- {30, nullptr, "OpenGameCardStorage"},
- {31, nullptr, "OpenGameCardFileSystem"},
- {32, nullptr, "ExtendSaveDataFileSystem"},
- {33, nullptr, "DeleteCacheStorage"},
- {34, &FSP_SRV::GetCacheStorageSize, "GetCacheStorageSize"},
- {35, nullptr, "CreateSaveDataFileSystemByHashSalt"},
- {36, nullptr, "OpenHostFileSystemWithOption"},
- {51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"},
- {52, &FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId, "OpenSaveDataFileSystemBySystemSaveDataId"},
- {53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"},
- {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"},
- {58, nullptr, "ReadSaveDataFileSystemExtraData"},
- {59, nullptr, "WriteSaveDataFileSystemExtraData"},
- {60, nullptr, "OpenSaveDataInfoReader"},
- {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
- {62, &FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage, "OpenSaveDataInfoReaderOnlyCacheStorage"},
- {64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
- {65, nullptr, "UpdateSaveDataMacForDebug"},
- {66, nullptr, "WriteSaveDataFileSystemExtraData2"},
- {67, nullptr, "FindSaveDataWithFilter"},
- {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"},
- {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"},
- {70, &FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
- {71, &FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
- {80, nullptr, "OpenSaveDataMetaFile"},
- {81, nullptr, "OpenSaveDataTransferManager"},
- {82, nullptr, "OpenSaveDataTransferManagerVersion2"},
- {83, nullptr, "OpenSaveDataTransferProhibiterForCloudBackUp"},
- {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"},
- {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"},
- {86, nullptr, "OpenSaveDataMover"},
- {87, nullptr, "OpenSaveDataTransferManagerForRepair"},
- {100, nullptr, "OpenImageDirectoryFileSystem"},
- {101, nullptr, "OpenBaseFileSystem"},
- {102, nullptr, "FormatBaseFileSystem"},
- {110, nullptr, "OpenContentStorageFileSystem"},
- {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
- {130, nullptr, "OpenCustomStorageFileSystem"},
- {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"},
- {201, nullptr, "OpenDataStorageByProgramId"},
- {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"},
- {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"},
- {204, nullptr, "OpenDataFileSystemByProgramIndex"},
- {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"},
- {206, nullptr, "OpenDataStorageByPath"},
- {400, nullptr, "OpenDeviceOperator"},
- {500, nullptr, "OpenSdCardDetectionEventNotifier"},
- {501, nullptr, "OpenGameCardDetectionEventNotifier"},
- {510, nullptr, "OpenSystemDataUpdateEventNotifier"},
- {511, nullptr, "NotifySystemDataUpdateEvent"},
- {520, nullptr, "SimulateGameCardDetectionEvent"},
- {600, nullptr, "SetCurrentPosixTime"},
- {601, nullptr, "QuerySaveDataTotalSize"},
- {602, nullptr, "VerifySaveDataFileSystem"},
- {603, nullptr, "CorruptSaveDataFileSystem"},
- {604, nullptr, "CreatePaddingFile"},
- {605, nullptr, "DeleteAllPaddingFiles"},
- {606, nullptr, "GetRightsId"},
- {607, nullptr, "RegisterExternalKey"},
- {608, nullptr, "UnregisterAllExternalKey"},
- {609, nullptr, "GetRightsIdByPath"},
- {610, nullptr, "GetRightsIdAndKeyGenerationByPath"},
- {611, nullptr, "SetCurrentPosixTimeWithTimeDifference"},
- {612, nullptr, "GetFreeSpaceSizeForSaveData"},
- {613, nullptr, "VerifySaveDataFileSystemBySaveDataSpaceId"},
- {614, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId"},
- {615, nullptr, "QuerySaveDataInternalStorageTotalSize"},
- {616, nullptr, "GetSaveDataCommitId"},
- {617, nullptr, "UnregisterExternalKey"},
- {620, nullptr, "SetSdCardEncryptionSeed"},
- {630, nullptr, "SetSdCardAccessibility"},
- {631, nullptr, "IsSdCardAccessible"},
- {640, nullptr, "IsSignedSystemPartitionOnSdCardValid"},
- {700, nullptr, "OpenAccessFailureResolver"},
- {701, nullptr, "GetAccessFailureDetectionEvent"},
- {702, nullptr, "IsAccessFailureDetected"},
- {710, nullptr, "ResolveAccessFailure"},
- {720, nullptr, "AbandonAccessFailure"},
- {800, nullptr, "GetAndClearFileSystemProxyErrorInfo"},
- {810, nullptr, "RegisterProgramIndexMapInfo"},
- {1000, nullptr, "SetBisRootForHost"},
- {1001, nullptr, "SetSaveDataSize"},
- {1002, nullptr, "SetSaveDataRootPath"},
- {1003, &FSP_SRV::DisableAutoSaveDataCreation, "DisableAutoSaveDataCreation"},
- {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"},
- {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"},
- {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"},
- {1007, nullptr, "RegisterUpdatePartition"},
- {1008, nullptr, "OpenRegisteredUpdatePartition"},
- {1009, nullptr, "GetAndClearMemoryReportInfo"},
- {1010, nullptr, "SetDataStorageRedirectTarget"},
- {1011, &FSP_SRV::GetProgramIndexForAccessLog, "GetProgramIndexForAccessLog"},
- {1012, nullptr, "GetFsStackUsage"},
- {1013, nullptr, "UnsetSaveDataRootPath"},
- {1014, nullptr, "OutputMultiProgramTagAccessLog"},
- {1016, nullptr, "FlushAccessLogOnSdCard"},
- {1017, nullptr, "OutputApplicationInfoAccessLog"},
- {1018, nullptr, "SetDebugOption"},
- {1019, nullptr, "UnsetDebugOption"},
- {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
- {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
- {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"},
- {1300, nullptr, "OpenBisWiper"},
- };
- // clang-format on
- RegisterHandlers(functions);
-
- if (Settings::values.enable_fs_access_log) {
- access_log_mode = AccessLogMode::SdCard;
- }
-
- // This should be true on creation
- fsc.SetAutoSaveDataCreation(true);
-}
-
-FSP_SRV::~FSP_SRV() = default;
-
-void FSP_SRV::SetCurrentProcess(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- current_process_id = rp.Pop<u64>();
-
- LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void FSP_SRV::OpenFileSystemWithPatch(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto type = rp.PopRaw<FileSystemType>();
- const auto title_id = rp.PopRaw<u64>();
- LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", type, title_id);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 0};
- rb.Push(ResultUnknown);
-}
-
-void FSP_SRV::OpenSdCardFileSystem(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
-
- FileSys::VirtualDir sdmc_dir{};
- fsc.OpenSDMC(&sdmc_dir);
-
- auto filesystem = std::make_shared<IFileSystem>(
- system, sdmc_dir, SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
-}
-
-void FSP_SRV::CreateSaveDataFileSystem(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
- [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
- u128 uid = rp.PopRaw<u128>();
-
- LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
- uid[1], uid[0]);
-
- FileSys::VirtualDir save_data_dir{};
- fsc.CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandUser, save_struct);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void FSP_SRV::CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
- [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
-
- LOG_DEBUG(Service_FS, "called save_struct = {}", save_struct.DebugInfo());
-
- FileSys::VirtualDir save_data_dir{};
- fsc.CreateSaveData(&save_data_dir, FileSys::SaveDataSpaceId::NandSystem, save_struct);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void FSP_SRV::OpenSaveDataFileSystem(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- struct Parameters {
- FileSys::SaveDataSpaceId space_id;
- FileSys::SaveDataAttribute attribute;
- };
-
- const auto parameters = rp.PopRaw<Parameters>();
-
- LOG_INFO(Service_FS, "called.");
-
- FileSys::VirtualDir dir{};
- auto result = fsc.OpenSaveData(&dir, parameters.space_id, parameters.attribute);
- if (result != ResultSuccess) {
- IPC::ResponseBuilder rb{ctx, 2, 0, 0};
- rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
- return;
- }
-
- FileSys::StorageId id{};
- switch (parameters.space_id) {
- case FileSys::SaveDataSpaceId::NandUser:
- id = FileSys::StorageId::NandUser;
- break;
- case FileSys::SaveDataSpaceId::SdCardSystem:
- case FileSys::SaveDataSpaceId::SdCardUser:
- id = FileSys::StorageId::SdCard;
- break;
- case FileSys::SaveDataSpaceId::NandSystem:
- id = FileSys::StorageId::NandSystem;
- break;
- case FileSys::SaveDataSpaceId::TemporaryStorage:
- case FileSys::SaveDataSpaceId::ProperSystem:
- case FileSys::SaveDataSpaceId::SafeMode:
- ASSERT(false);
- }
-
- auto filesystem =
- std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id));
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
-}
-
-void FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx) {
- LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
- OpenSaveDataFileSystem(ctx);
-}
-
-void FSP_SRV::OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx) {
- LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
- OpenSaveDataFileSystem(ctx);
-}
-
-void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
- LOG_INFO(Service_FS, "called, space={}", space);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<ISaveDataInfoReader>(
- std::make_shared<ISaveDataInfoReader>(system, space, fsc));
-}
-
-void FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx) {
- LOG_WARNING(Service_FS, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<ISaveDataInfoReader>(system, FileSys::SaveDataSpaceId::TemporaryStorage,
- fsc);
-}
-
-void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx) {
- LOG_WARNING(Service_FS, "(STUBBED) called.");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- struct Parameters {
- FileSys::SaveDataSpaceId space_id;
- FileSys::SaveDataAttribute attribute;
- };
-
- const auto parameters = rp.PopRaw<Parameters>();
- // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
- constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
-
- LOG_WARNING(Service_FS,
- "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n"
- "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
- "attribute.type={}, attribute.rank={}, attribute.index={}",
- flags, parameters.space_id, parameters.attribute.title_id,
- parameters.attribute.user_id[1], parameters.attribute.user_id[0],
- parameters.attribute.save_id, parameters.attribute.type, parameters.attribute.rank,
- parameters.attribute.index);
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.Push(flags);
-}
-
-void FSP_SRV::OpenDataStorageByCurrentProcess(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
-
- if (!romfs) {
- auto current_romfs = fsc.OpenRomFSCurrentProcess();
- if (!current_romfs) {
- // TODO (bunnei): Find the right error code to use here
- LOG_CRITICAL(Service_FS, "no file system interface available!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
- }
-
- romfs = current_romfs;
- }
-
- auto storage = std::make_shared<IStorage>(system, romfs);
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IStorage>(std::move(storage));
-}
-
-void FSP_SRV::OpenDataStorageByDataId(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto storage_id = rp.PopRaw<FileSys::StorageId>();
- const auto unknown = rp.PopRaw<u32>();
- const auto title_id = rp.PopRaw<u64>();
-
- LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
- storage_id, unknown, title_id);
-
- auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
-
- if (!data) {
- const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
-
- if (archive != nullptr) {
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface(std::make_shared<IStorage>(system, archive));
- return;
- }
-
- // TODO(DarkLordZach): Find the right error code to use here
- LOG_ERROR(Service_FS,
- "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
- storage_id);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
- }
-
- const FileSys::PatchManager pm{title_id, fsc, content_provider};
-
- auto base = fsc.OpenBaseNca(title_id, storage_id, FileSys::ContentRecordType::Data);
- auto storage = std::make_shared<IStorage>(
- system, pm.PatchRomFS(base.get(), std::move(data), FileSys::ContentRecordType::Data));
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IStorage>(std::move(storage));
-}
-
-void FSP_SRV::OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto storage_id = rp.PopRaw<FileSys::StorageId>();
- const auto title_id = rp.PopRaw<u64>();
-
- LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
-}
-
-void FSP_SRV::OpenDataStorageWithProgramIndex(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
-
- const auto program_index = rp.PopRaw<u8>();
-
- LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
-
- auto patched_romfs =
- fsc.OpenPatchedRomFSWithProgramIndex(system.GetApplicationProcessProgramID(), program_index,
- FileSys::ContentRecordType::Program);
-
- if (!patched_romfs) {
- // TODO: Find the right error code to use here
- LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultUnknown);
- return;
- }
-
- auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs));
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IStorage>(std::move(storage));
-}
-
-void FSP_SRV::DisableAutoSaveDataCreation(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
-
- fsc.SetAutoSaveDataCreation(false);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void FSP_SRV::SetGlobalAccessLogMode(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- access_log_mode = rp.PopEnum<AccessLogMode>();
-
- LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void FSP_SRV::GetGlobalAccessLogMode(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
-
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(ResultSuccess);
- rb.PushEnum(access_log_mode);
-}
-
-void FSP_SRV::OutputAccessLogToSdCard(HLERequestContext& ctx) {
- const auto raw = ctx.ReadBufferCopy();
- auto log = Common::StringFromFixedZeroTerminatedBuffer(
- reinterpret_cast<const char*>(raw.data()), raw.size());
-
- LOG_DEBUG(Service_FS, "called");
-
- reporter.SaveFSAccessLog(log);
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
-}
-
-void FSP_SRV::GetProgramIndexForAccessLog(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.PushEnum(AccessLogVersion::Latest);
- rb.Push(access_log_program_index);
-}
-
-void FSP_SRV::GetCacheStorageSize(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto index{rp.Pop<s32>()};
-
- LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index);
-
- IPC::ResponseBuilder rb{ctx, 6};
- rb.Push(ResultSuccess);
- rb.Push(s64{0});
- rb.Push(s64{0});
-}
-
-class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
-public:
- explicit IMultiCommitManager(Core::System& system_)
- : ServiceFramework{system_, "IMultiCommitManager"} {
- static const FunctionInfo functions[] = {
- {1, &IMultiCommitManager::Add, "Add"},
- {2, &IMultiCommitManager::Commit, "Commit"},
- };
- RegisterHandlers(functions);
- }
-
-private:
- FileSys::VirtualFile backend;
-
- void Add(HLERequestContext& ctx) {
- LOG_WARNING(Service_FS, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void Commit(HLERequestContext& ctx) {
- LOG_WARNING(Service_FS, "(STUBBED) called");
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-};
-
-void FSP_SRV::OpenMultiCommitManager(HLERequestContext& ctx) {
- LOG_DEBUG(Service_FS, "called");
-
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>(system));
-}
-
-} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h
deleted file mode 100644
index 280bc9867..000000000
--- a/src/core/hle/service/filesystem/fsp_srv.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include <memory>
-#include "core/hle/service/service.h"
-
-namespace Core {
-class Reporter;
-}
-
-namespace FileSys {
-class ContentProvider;
-class FileSystemBackend;
-} // namespace FileSys
-
-namespace Service::FileSystem {
-
-enum class AccessLogVersion : u32 {
- V7_0_0 = 2,
-
- Latest = V7_0_0,
-};
-
-enum class AccessLogMode : u32 {
- None,
- Log,
- SdCard,
-};
-
-class FSP_SRV final : public ServiceFramework<FSP_SRV> {
-public:
- explicit FSP_SRV(Core::System& system_);
- ~FSP_SRV() override;
-
-private:
- void SetCurrentProcess(HLERequestContext& ctx);
- void OpenFileSystemWithPatch(HLERequestContext& ctx);
- void OpenSdCardFileSystem(HLERequestContext& ctx);
- void CreateSaveDataFileSystem(HLERequestContext& ctx);
- void CreateSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx);
- void OpenSaveDataFileSystem(HLERequestContext& ctx);
- void OpenSaveDataFileSystemBySystemSaveDataId(HLERequestContext& ctx);
- void OpenReadOnlySaveDataFileSystem(HLERequestContext& ctx);
- void OpenSaveDataInfoReaderBySaveDataSpaceId(HLERequestContext& ctx);
- void OpenSaveDataInfoReaderOnlyCacheStorage(HLERequestContext& ctx);
- void WriteSaveDataFileSystemExtraDataBySaveDataAttribute(HLERequestContext& ctx);
- void ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(HLERequestContext& ctx);
- void OpenDataStorageByCurrentProcess(HLERequestContext& ctx);
- void OpenDataStorageByDataId(HLERequestContext& ctx);
- void OpenPatchDataStorageByCurrentProcess(HLERequestContext& ctx);
- void OpenDataStorageWithProgramIndex(HLERequestContext& ctx);
- void DisableAutoSaveDataCreation(HLERequestContext& ctx);
- void SetGlobalAccessLogMode(HLERequestContext& ctx);
- void GetGlobalAccessLogMode(HLERequestContext& ctx);
- void OutputAccessLogToSdCard(HLERequestContext& ctx);
- void GetProgramIndexForAccessLog(HLERequestContext& ctx);
- void OpenMultiCommitManager(HLERequestContext& ctx);
- void GetCacheStorageSize(HLERequestContext& ctx);
-
- FileSystemController& fsc;
- const FileSys::ContentProvider& content_provider;
- const Core::Reporter& reporter;
-
- FileSys::VirtualFile romfs;
- u64 current_process_id = 0;
- u32 access_log_program_index = 0;
- AccessLogMode access_log_mode = AccessLogMode::None;
-};
-
-} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/romfs_controller.cpp b/src/core/hle/service/filesystem/romfs_controller.cpp
new file mode 100644
index 000000000..19c9cec72
--- /dev/null
+++ b/src/core/hle/service/filesystem/romfs_controller.cpp
@@ -0,0 +1,37 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/service/filesystem/romfs_controller.h"
+
+namespace Service::FileSystem {
+
+RomFsController::RomFsController(std::shared_ptr<FileSys::RomFSFactory> factory_, u64 program_id_)
+ : factory{std::move(factory_)}, program_id{program_id_} {}
+RomFsController::~RomFsController() = default;
+
+FileSys::VirtualFile RomFsController::OpenRomFSCurrentProcess() {
+ return factory->OpenCurrentProcess(program_id);
+}
+
+FileSys::VirtualFile RomFsController::OpenPatchedRomFS(u64 title_id,
+ FileSys::ContentRecordType type) {
+ return factory->OpenPatchedRomFS(title_id, type);
+}
+
+FileSys::VirtualFile RomFsController::OpenPatchedRomFSWithProgramIndex(
+ u64 title_id, u8 program_index, FileSys::ContentRecordType type) {
+ return factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type);
+}
+
+FileSys::VirtualFile RomFsController::OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
+ FileSys::ContentRecordType type) {
+ return factory->Open(title_id, storage_id, type);
+}
+
+std::shared_ptr<FileSys::NCA> RomFsController::OpenBaseNca(u64 title_id,
+ FileSys::StorageId storage_id,
+ FileSys::ContentRecordType type) {
+ return factory->GetEntry(title_id, storage_id, type);
+}
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/romfs_controller.h b/src/core/hle/service/filesystem/romfs_controller.h
new file mode 100644
index 000000000..3c3ead344
--- /dev/null
+++ b/src/core/hle/service/filesystem/romfs_controller.h
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/romfs_factory.h"
+#include "core/file_sys/vfs/vfs_types.h"
+
+namespace Service::FileSystem {
+
+class RomFsController {
+public:
+ explicit RomFsController(std::shared_ptr<FileSys::RomFSFactory> factory_, u64 program_id_);
+ ~RomFsController();
+
+ FileSys::VirtualFile OpenRomFSCurrentProcess();
+ FileSys::VirtualFile OpenPatchedRomFS(u64 title_id, FileSys::ContentRecordType type);
+ FileSys::VirtualFile OpenPatchedRomFSWithProgramIndex(u64 title_id, u8 program_index,
+ FileSys::ContentRecordType type);
+ FileSys::VirtualFile OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
+ FileSys::ContentRecordType type);
+ std::shared_ptr<FileSys::NCA> OpenBaseNca(u64 title_id, FileSys::StorageId storage_id,
+ FileSys::ContentRecordType type);
+
+private:
+ const std::shared_ptr<FileSys::RomFSFactory> factory;
+ const u64 program_id;
+};
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/save_data_controller.cpp b/src/core/hle/service/filesystem/save_data_controller.cpp
new file mode 100644
index 000000000..03e45f7f9
--- /dev/null
+++ b/src/core/hle/service/filesystem/save_data_controller.cpp
@@ -0,0 +1,99 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/core.h"
+#include "core/file_sys/control_metadata.h"
+#include "core/file_sys/errors.h"
+#include "core/file_sys/patch_manager.h"
+#include "core/hle/service/filesystem/save_data_controller.h"
+#include "core/loader/loader.h"
+
+namespace Service::FileSystem {
+
+namespace {
+
+// 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 SufficientSaveDataSize = 0xF0000000;
+
+FileSys::SaveDataSize GetDefaultSaveDataSize(Core::System& system, u64 program_id) {
+ const FileSys::PatchManager pm{program_id, system.GetFileSystemController(),
+ system.GetContentProvider()};
+ const auto metadata = pm.GetControlMetadata();
+ const auto& nacp = metadata.first;
+
+ if (nacp != nullptr) {
+ return {nacp->GetDefaultNormalSaveSize(), nacp->GetDefaultJournalSaveSize()};
+ }
+
+ return {SufficientSaveDataSize, SufficientSaveDataSize};
+}
+
+} // namespace
+
+SaveDataController::SaveDataController(Core::System& system_,
+ std::shared_ptr<FileSys::SaveDataFactory> factory_)
+ : system{system_}, factory{std::move(factory_)} {}
+SaveDataController::~SaveDataController() = default;
+
+Result SaveDataController::CreateSaveData(FileSys::VirtualDir* out_save_data,
+ FileSys::SaveDataSpaceId space,
+ const FileSys::SaveDataAttribute& attribute) {
+ LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space,
+ attribute.DebugInfo());
+
+ auto save_data = factory->Create(space, attribute);
+ if (save_data == nullptr) {
+ return FileSys::ResultTargetNotFound;
+ }
+
+ *out_save_data = save_data;
+ return ResultSuccess;
+}
+
+Result SaveDataController::OpenSaveData(FileSys::VirtualDir* out_save_data,
+ FileSys::SaveDataSpaceId space,
+ const FileSys::SaveDataAttribute& attribute) {
+ auto save_data = factory->Open(space, attribute);
+ if (save_data == nullptr) {
+ return FileSys::ResultTargetNotFound;
+ }
+
+ *out_save_data = save_data;
+ return ResultSuccess;
+}
+
+Result SaveDataController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
+ FileSys::SaveDataSpaceId space) {
+ auto save_data_space = factory->GetSaveDataSpaceDirectory(space);
+ if (save_data_space == nullptr) {
+ return FileSys::ResultTargetNotFound;
+ }
+
+ *out_save_data_space = save_data_space;
+ return ResultSuccess;
+}
+
+FileSys::SaveDataSize SaveDataController::ReadSaveDataSize(FileSys::SaveDataType type, u64 title_id,
+ u128 user_id) {
+ const auto value = factory->ReadSaveDataSize(type, title_id, user_id);
+
+ if (value.normal == 0 && value.journal == 0) {
+ const auto size = GetDefaultSaveDataSize(system, title_id);
+ factory->WriteSaveDataSize(type, title_id, user_id, size);
+ return size;
+ }
+
+ return value;
+}
+
+void SaveDataController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
+ FileSys::SaveDataSize new_value) {
+ factory->WriteSaveDataSize(type, title_id, user_id, new_value);
+}
+
+void SaveDataController::SetAutoCreate(bool state) {
+ factory->SetAutoCreate(state);
+}
+
+} // namespace Service::FileSystem
diff --git a/src/core/hle/service/filesystem/save_data_controller.h b/src/core/hle/service/filesystem/save_data_controller.h
new file mode 100644
index 000000000..dc9d713df
--- /dev/null
+++ b/src/core/hle/service/filesystem/save_data_controller.h
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "core/file_sys/nca_metadata.h"
+#include "core/file_sys/savedata_factory.h"
+#include "core/file_sys/vfs/vfs_types.h"
+
+namespace Service::FileSystem {
+
+class SaveDataController {
+public:
+ explicit SaveDataController(Core::System& system,
+ std::shared_ptr<FileSys::SaveDataFactory> factory_);
+ ~SaveDataController();
+
+ Result CreateSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space,
+ const FileSys::SaveDataAttribute& attribute);
+ Result OpenSaveData(FileSys::VirtualDir* out_save_data, FileSys::SaveDataSpaceId space,
+ const FileSys::SaveDataAttribute& attribute);
+ Result OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
+ FileSys::SaveDataSpaceId space);
+
+ 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);
+ void SetAutoCreate(bool state);
+
+private:
+ Core::System& system;
+ const std::shared_ptr<FileSys::SaveDataFactory> factory;
+};
+
+} // namespace Service::FileSystem