diff options
Diffstat (limited to 'src/core/hle/service/filesystem')
-rw-r--r-- | src/core/hle/service/filesystem/filesystem.cpp | 57 | ||||
-rw-r--r-- | src/core/hle/service/filesystem/filesystem.h | 5 | ||||
-rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.cpp | 169 | ||||
-rw-r--r-- | src/core/hle/service/filesystem/fsp_srv.h | 1 |
4 files changed, 213 insertions, 19 deletions
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index e32a7c48e..2aa77f68d 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -303,25 +303,46 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, static_cast<u8>(space), save_struct.DebugInfo()); if (save_data_factory == nullptr) { - return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound); + return FileSys::ERROR_ENTITY_NOT_FOUND; } return save_data_factory->Open(space, save_struct); } +ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) { + LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space)); + + if (save_data_factory == nullptr) { + return FileSys::ERROR_ENTITY_NOT_FOUND; + } + + return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space)); +} + ResultVal<FileSys::VirtualDir> OpenSDMC() { LOG_TRACE(Service_FS, "Opening SDMC"); if (sdmc_factory == nullptr) { - return ResultCode(ErrorModule::FS, FileSys::ErrCodes::SdCardNotFound); + return FileSys::ERROR_SD_CARD_NOT_FOUND; } return sdmc_factory->Open(); } -std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() { - return std::make_unique<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{ - GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}); +std::shared_ptr<FileSys::RegisteredCacheUnion> registered_cache_union; + +std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() { + if (registered_cache_union == nullptr) { + registered_cache_union = + std::make_shared<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{ + GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()}); + } + + return registered_cache_union; +} + +void ClearUnionContents() { + registered_cache_union = nullptr; } FileSys::RegisteredCache* GetSystemNANDContents() { @@ -360,11 +381,21 @@ FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) { return bis_factory->GetModificationLoadRoot(title_id); } +FileSys::VirtualDir GetModificationDumpRoot(u64 title_id) { + LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id); + + if (bis_factory == nullptr) + return nullptr; + + return bis_factory->GetModificationDumpRoot(title_id); +} + void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { if (overwrite) { bis_factory = nullptr; save_data_factory = nullptr; sdmc_factory = nullptr; + ClearUnionContents(); } auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), @@ -373,13 +404,21 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { FileSys::Mode::ReadWrite); auto load_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir), FileSys::Mode::ReadWrite); + auto dump_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), + FileSys::Mode::ReadWrite); - if (bis_factory == nullptr) - bis_factory = std::make_unique<FileSys::BISFactory>(nand_directory, load_directory); - if (save_data_factory == nullptr) + if (bis_factory == nullptr) { + bis_factory = + std::make_unique<FileSys::BISFactory>(nand_directory, load_directory, dump_directory); + } + + if (save_data_factory == nullptr) { save_data_factory = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory)); - if (sdmc_factory == nullptr) + } + + if (sdmc_factory == nullptr) { sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory)); + } } void InstallInterfaces(SM::ServiceManager& service_manager, FileSys::VfsFilesystem& vfs) { diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 6ca5c5636..0a6cb6635 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -45,15 +45,18 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora FileSys::ContentRecordType type); ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space, FileSys::SaveDataDescriptor save_struct); +ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space); ResultVal<FileSys::VirtualDir> OpenSDMC(); -std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); +std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); +void ClearUnionContents(); FileSys::RegisteredCache* GetSystemNANDContents(); FileSys::RegisteredCache* GetUserNANDContents(); FileSys::RegisteredCache* GetSDMCContents(); FileSys::VirtualDir GetModificationLoadRoot(u64 title_id); +FileSys::VirtualDir GetModificationDumpRoot(u64 title_id); // Creates the SaveData, SDMC, and BIS Factories. Should be called once and before any function // above is called. diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index c1c83a11d..038dc80b1 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -11,6 +11,7 @@ #include "common/assert.h" #include "common/common_types.h" +#include "common/hex_util.h" #include "common/logging/log.h" #include "common/string_util.h" #include "core/file_sys/directory.h" @@ -62,12 +63,12 @@ private: // Error checking if (length < 0) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); + rb.Push(FileSys::ERROR_INVALID_SIZE); return; } if (offset < 0) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); + rb.Push(FileSys::ERROR_INVALID_OFFSET); return; } @@ -107,12 +108,12 @@ private: // Error checking if (length < 0) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); + rb.Push(FileSys::ERROR_INVALID_SIZE); return; } if (offset < 0) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); + rb.Push(FileSys::ERROR_INVALID_OFFSET); return; } @@ -138,12 +139,12 @@ private: // Error checking if (length < 0) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); + rb.Push(FileSys::ERROR_INVALID_SIZE); return; } if (offset < 0) { IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); + rb.Push(FileSys::ERROR_INVALID_OFFSET); return; } @@ -451,7 +452,147 @@ private: VfsDirectoryServiceWrapper backend; }; +class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> { +public: + explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space) + : ServiceFramework("ISaveDataInfoReader") { + static const FunctionInfo functions[] = { + {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"}, + }; + RegisterHandlers(functions); + + FindAllSaves(space); + } + + void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) { + // Calculate how many entries we can fit in the output buffer + const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(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, 3}; + rb.Push(RESULT_SUCCESS); + rb.Push<u32>(static_cast<u32>(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) { + const auto save_root = OpenSaveDataSpace(space); + ASSERT(save_root.Succeeded()); + + 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; + INSERT_PADDING_BYTES(0x28); + }; + static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size."); + + std::vector<SaveDataInfo> info; + u64 next_entry_index = 0; +}; + FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { + // clang-format off static const FunctionInfo functions[] = { {0, nullptr, "MountContent"}, {1, &FSP_SRV::Initialize, "Initialize"}, @@ -485,7 +626,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { {58, nullptr, "ReadSaveDataFileSystemExtraData"}, {59, nullptr, "WriteSaveDataFileSystemExtraData"}, {60, nullptr, "OpenSaveDataInfoReader"}, - {61, nullptr, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, + {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"}, {62, nullptr, "OpenCacheStorageList"}, {64, nullptr, "OpenSaveDataInternalStorageFileSystem"}, {65, nullptr, "UpdateSaveDataMacForDebug"}, @@ -544,6 +685,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { {1009, nullptr, "GetAndClearMemoryReportInfo"}, {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"}, }; + // clang-format on RegisterHandlers(functions); } @@ -602,7 +744,7 @@ void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) { if (dir.Failed()) { IPC::ResponseBuilder rb{ctx, 2, 0, 0}; - rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound)); + rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); return; } @@ -618,6 +760,15 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) { MountSaveData(ctx); } +void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>(); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space)); +} + void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_FS, "(STUBBED) called"); @@ -685,7 +836,7 @@ void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) { static_cast<u8>(storage_id), title_id); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound)); + rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND); } } // namespace Service::FileSystem diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index 4aa0358cb..e7abec0a3 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h @@ -25,6 +25,7 @@ private: void CreateSaveData(Kernel::HLERequestContext& ctx); void MountSaveData(Kernel::HLERequestContext& ctx); void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx); + void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx); void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx); |