diff --git a/src/core/core.cpp b/src/core/core.cpp index f16e083a8..99cf495aa 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -19,6 +19,7 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/thread.h" +#include "core/hle/service/fs/archive.h" #include "core/hle/service/service.h" #include "core/hle/service/sm/sm.h" #include "core/hw/hw.h" @@ -191,6 +192,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) { service_manager = std::make_shared(); shared_page_handler = std::make_shared(); + archive_manager = std::make_unique(); HW::Init(); Kernel::Init(system_mode); @@ -219,6 +221,14 @@ const Service::SM::ServiceManager& System::ServiceManager() const { return *service_manager; } +Service::FS::ArchiveManager& System::ArchiveManager() { + return *archive_manager; +} + +const Service::FS::ArchiveManager& System::ArchiveManager() const { + return *archive_manager; +} + void System::RegisterSoftwareKeyboard(std::shared_ptr swkbd) { registered_swkbd = std::move(swkbd); } diff --git a/src/core/core.h b/src/core/core.h index 517d53e97..cecd29896 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -31,6 +31,9 @@ namespace Service { namespace SM { class ServiceManager; } +namespace FS { +class ArchiveManager; +} } // namespace Service namespace Core { @@ -158,6 +161,12 @@ public: */ const Service::SM::ServiceManager& ServiceManager() const; + /// Gets a reference to the archive manager + Service::FS::ArchiveManager& ArchiveManager(); + + /// Gets a const reference to the archive manager + const Service::FS::ArchiveManager& ArchiveManager() const; + PerfStats perf_stats; FrameLimiter frame_limiter; @@ -230,6 +239,8 @@ private: /// Shared Page std::shared_ptr shared_page_handler; + std::unique_ptr archive_manager; + static System s_instance; ResultStatus status = ResultStatus::Success; diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index e76ec1e13..0f2375124 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -8,9 +8,7 @@ #include #include #include -#include #include -#include #include "common/assert.h" #include "common/common_types.h" #include "common/file_util.h" @@ -32,27 +30,13 @@ namespace Service::FS { -using FileSys::ArchiveBackend; -using FileSys::ArchiveFactory; - -/** - * Map of registered archives, identified by id code. Once an archive is registered here, it is - * never removed until UnregisterArchiveTypes is called. - */ -static boost::container::flat_map> id_code_map; - -/** - * Map of active archive handles. Values are pointers to the archives in `idcode_map`. - */ -static std::unordered_map> handle_map; -static ArchiveHandle next_handle; - -static ArchiveBackend* GetArchive(ArchiveHandle handle) { +ArchiveBackend* ArchiveManager::GetArchive(ArchiveHandle handle) { auto itr = handle_map.find(handle); return (itr == handle_map.end()) ? nullptr : itr->second.get(); } -ResultVal OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path) { +ResultVal ArchiveManager::OpenArchive(ArchiveIdCode id_code, + FileSys::Path& archive_path) { LOG_TRACE(Service_FS, "Opening archive with id code 0x{:08X}", static_cast(id_code)); auto itr = id_code_map.find(id_code); @@ -70,7 +54,7 @@ ResultVal OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi return MakeResult(next_handle++); } -ResultCode CloseArchive(ArchiveHandle handle) { +ResultCode ArchiveManager::CloseArchive(ArchiveHandle handle) { if (handle_map.erase(handle) == 0) return FileSys::ERR_INVALID_ARCHIVE_HANDLE; else @@ -79,8 +63,8 @@ ResultCode CloseArchive(ArchiveHandle handle) { // TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in // http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22 -ResultCode RegisterArchiveType(std::unique_ptr&& factory, - ArchiveIdCode id_code) { +ResultCode ArchiveManager::RegisterArchiveType(std::unique_ptr&& factory, + ArchiveIdCode id_code) { auto result = id_code_map.emplace(id_code, std::move(factory)); bool inserted = result.second; @@ -92,9 +76,9 @@ ResultCode RegisterArchiveType(std::unique_ptr&& factor return RESULT_SUCCESS; } -ResultVal> OpenFileFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path, - const FileSys::Mode mode) { +ResultVal> ArchiveManager::OpenFileFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path, + const FileSys::Mode mode) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return FileSys::ERR_INVALID_ARCHIVE_HANDLE; @@ -107,7 +91,8 @@ ResultVal> OpenFileFromArchive(ArchiveHandle archive_handl return MakeResult>(std::move(file)); } -ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { +ResultCode ArchiveManager::DeleteFileFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return FileSys::ERR_INVALID_ARCHIVE_HANDLE; @@ -115,10 +100,10 @@ ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Pa return archive->DeleteFile(path); } -ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, - const FileSys::Path& src_path, - ArchiveHandle dest_archive_handle, - const FileSys::Path& dest_path) { +ResultCode ArchiveManager::RenameFileBetweenArchives(ArchiveHandle src_archive_handle, + const FileSys::Path& src_path, + ArchiveHandle dest_archive_handle, + const FileSys::Path& dest_path) { ArchiveBackend* src_archive = GetArchive(src_archive_handle); ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); if (src_archive == nullptr || dest_archive == nullptr) @@ -132,7 +117,8 @@ ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, } } -ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { +ResultCode ArchiveManager::DeleteDirectoryFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return FileSys::ERR_INVALID_ARCHIVE_HANDLE; @@ -140,8 +126,8 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy return archive->DeleteDirectory(path); } -ResultCode DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path) { +ResultCode ArchiveManager::DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return FileSys::ERR_INVALID_ARCHIVE_HANDLE; @@ -149,8 +135,8 @@ ResultCode DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle, return archive->DeleteDirectoryRecursively(path); } -ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, - u64 file_size) { +ResultCode ArchiveManager::CreateFileInArchive(ArchiveHandle archive_handle, + const FileSys::Path& path, u64 file_size) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return FileSys::ERR_INVALID_ARCHIVE_HANDLE; @@ -158,7 +144,8 @@ ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path return archive->CreateFile(path, file_size); } -ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { +ResultCode ArchiveManager::CreateDirectoryFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return FileSys::ERR_INVALID_ARCHIVE_HANDLE; @@ -166,10 +153,10 @@ ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy return archive->CreateDirectory(path); } -ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, - const FileSys::Path& src_path, - ArchiveHandle dest_archive_handle, - const FileSys::Path& dest_path) { +ResultCode ArchiveManager::RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, + const FileSys::Path& src_path, + ArchiveHandle dest_archive_handle, + const FileSys::Path& dest_path) { ArchiveBackend* src_archive = GetArchive(src_archive_handle); ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); if (src_archive == nullptr || dest_archive == nullptr) @@ -183,8 +170,8 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, } } -ResultVal> OpenDirectoryFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path) { +ResultVal> ArchiveManager::OpenDirectoryFromArchive( + ArchiveHandle archive_handle, const FileSys::Path& path) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return FileSys::ERR_INVALID_ARCHIVE_HANDLE; @@ -197,15 +184,16 @@ ResultVal> OpenDirectoryFromArchive(ArchiveHandle arc return MakeResult>(std::move(directory)); } -ResultVal GetFreeBytesInArchive(ArchiveHandle archive_handle) { +ResultVal ArchiveManager::GetFreeBytesInArchive(ArchiveHandle archive_handle) { ArchiveBackend* archive = GetArchive(archive_handle); if (archive == nullptr) return FileSys::ERR_INVALID_ARCHIVE_HANDLE; return MakeResult(archive->GetFreeBytes()); } -ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, - const FileSys::Path& path) { +ResultCode ArchiveManager::FormatArchive(ArchiveIdCode id_code, + const FileSys::ArchiveFormatInfo& format_info, + const FileSys::Path& path) { auto archive_itr = id_code_map.find(id_code); if (archive_itr == id_code_map.end()) { return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error @@ -214,8 +202,8 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo return archive_itr->second->Format(path, format_info); } -ResultVal GetArchiveFormatInfo(ArchiveIdCode id_code, - FileSys::Path& archive_path) { +ResultVal ArchiveManager::GetArchiveFormatInfo( + ArchiveIdCode id_code, FileSys::Path& archive_path) { auto archive = id_code_map.find(id_code); if (archive == id_code_map.end()) { return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error @@ -224,9 +212,9 @@ ResultVal GetArchiveFormatInfo(ArchiveIdCode id_code return archive->second->GetFormatInfo(archive_path); } -ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, - const std::vector& smdh_icon, - const FileSys::ArchiveFormatInfo& format_info) { +ResultCode ArchiveManager::CreateExtSaveData(MediaType media_type, u32 high, u32 low, + const std::vector& smdh_icon, + const FileSys::ArchiveFormatInfo& format_info) { // Construct the binary path to the archive first FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast(media_type), high, low); @@ -248,7 +236,7 @@ ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, return RESULT_SUCCESS; } -ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) { +ResultCode ArchiveManager::DeleteExtSaveData(MediaType media_type, u32 high, u32 low) { // Construct the binary path to the archive first FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast(media_type), high, low); @@ -272,7 +260,7 @@ ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) { return RESULT_SUCCESS; } -ResultCode DeleteSystemSaveData(u32 high, u32 low) { +ResultCode ArchiveManager::DeleteSystemSaveData(u32 high, u32 low) { // Construct the binary path to the archive first FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low); @@ -284,7 +272,7 @@ ResultCode DeleteSystemSaveData(u32 high, u32 low) { return RESULT_SUCCESS; } -ResultCode CreateSystemSaveData(u32 high, u32 low) { +ResultCode ArchiveManager::CreateSystemSaveData(u32 high, u32 low) { // Construct the binary path to the archive first FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low); @@ -296,7 +284,7 @@ ResultCode CreateSystemSaveData(u32 high, u32 low) { return RESULT_SUCCESS; } -void RegisterArchiveTypes() { +void ArchiveManager::RegisterArchiveTypes() { // TODO(Subv): Add the other archive types (see here for the known types: // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). @@ -348,7 +336,7 @@ void RegisterArchiveTypes() { RegisterArchiveType(std::move(selfncch_factory), ArchiveIdCode::SelfNCCH); } -void RegisterSelfNCCH(Loader::AppLoader& app_loader) { +void ArchiveManager::RegisterSelfNCCH(Loader::AppLoader& app_loader) { auto itr = id_code_map.find(ArchiveIdCode::SelfNCCH); if (itr == id_code_map.end()) { LOG_ERROR(Service_FS, @@ -360,20 +348,8 @@ void RegisterSelfNCCH(Loader::AppLoader& app_loader) { factory->Register(app_loader); } -void UnregisterArchiveTypes() { - id_code_map.clear(); -} - -/// Initialize archives -void ArchiveInit() { - next_handle = 1; +ArchiveManager::ArchiveManager() { RegisterArchiveTypes(); } -/// Shutdown archives -void ArchiveShutdown() { - handle_map.clear(); - UnregisterArchiveTypes(); -} - } // namespace Service::FS diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 4c568097c..ef9b9efc2 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -6,7 +6,9 @@ #include #include +#include #include +#include #include "common/common_types.h" #include "core/file_sys/archive_backend.h" #include "core/hle/result.h" @@ -43,196 +45,209 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 }; typedef u64 ArchiveHandle; -/** - * Opens an archive - * @param id_code IdCode of the archive to open - * @param archive_path Path to the archive, used with Binary paths - * @return Handle to the opened archive - */ -ResultVal OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path); +using FileSys::ArchiveBackend; +using FileSys::ArchiveFactory; -/** - * Closes an archive - * @param handle Handle to the archive to close - */ -ResultCode CloseArchive(ArchiveHandle handle); +class ArchiveManager { +public: + ArchiveManager(); + /** + * Opens an archive + * @param id_code IdCode of the archive to open + * @param archive_path Path to the archive, used with Binary paths + * @return Handle to the opened archive + */ + ResultVal OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path); -/** - * Registers an Archive type, instances of which can later be opened using its IdCode. - * @param factory File system backend interface to the archive - * @param id_code Id code used to access this type of archive - */ -ResultCode RegisterArchiveType(std::unique_ptr&& factory, - ArchiveIdCode id_code); + /** + * Closes an archive + * @param handle Handle to the archive to close + */ + ResultCode CloseArchive(ArchiveHandle handle); -/** - * Open a File from an Archive - * @param archive_handle Handle to an open Archive object - * @param path Path to the File inside of the Archive - * @param mode Mode under which to open the File - * @return The opened File object - */ -ResultVal> OpenFileFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path, - const FileSys::Mode mode); + /** + * Open a File from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the File inside of the Archive + * @param mode Mode under which to open the File + * @return The opened File object + */ + ResultVal> OpenFileFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path, + const FileSys::Mode mode); -/** - * Delete a File from an Archive - * @param archive_handle Handle to an open Archive object - * @param path Path to the File inside of the Archive - * @return Whether deletion succeeded - */ -ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); + /** + * Delete a File from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the File inside of the Archive + * @return Whether deletion succeeded + */ + ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); -/** - * Rename a File between two Archives - * @param src_archive_handle Handle to the source Archive object - * @param src_path Path to the File inside of the source Archive - * @param dest_archive_handle Handle to the destination Archive object - * @param dest_path Path to the File inside of the destination Archive - * @return Whether rename succeeded - */ -ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, - const FileSys::Path& src_path, - ArchiveHandle dest_archive_handle, - const FileSys::Path& dest_path); + /** + * Rename a File between two Archives + * @param src_archive_handle Handle to the source Archive object + * @param src_path Path to the File inside of the source Archive + * @param dest_archive_handle Handle to the destination Archive object + * @param dest_path Path to the File inside of the destination Archive + * @return Whether rename succeeded + */ + ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, + const FileSys::Path& src_path, + ArchiveHandle dest_archive_handle, + const FileSys::Path& dest_path); -/** - * Delete a Directory from an Archive - * @param archive_handle Handle to an open Archive object - * @param path Path to the Directory inside of the Archive - * @return Whether deletion succeeded - */ -ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); + /** + * Delete a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Whether deletion succeeded + */ + ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); -/** - * Delete a Directory and anything under it from an Archive - * @param archive_handle Handle to an open Archive object - * @param path Path to the Directory inside of the Archive - * @return Whether deletion succeeded - */ -ResultCode DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path); + /** + * Delete a Directory and anything under it from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Whether deletion succeeded + */ + ResultCode DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path); -/** - * Create a File in an Archive - * @param archive_handle Handle to an open Archive object - * @param path Path to the File inside of the Archive - * @param file_size The size of the new file, filled with zeroes - * @return File creation result code - */ -ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, - u64 file_size); + /** + * Create a File in an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the File inside of the Archive + * @param file_size The size of the new file, filled with zeroes + * @return File creation result code + */ + ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, + u64 file_size); -/** - * Create a Directory from an Archive - * @param archive_handle Handle to an open Archive object - * @param path Path to the Directory inside of the Archive - * @return Whether creation of directory succeeded - */ -ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); + /** + * Create a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Whether creation of directory succeeded + */ + ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); -/** - * Rename a Directory between two Archives - * @param src_archive_handle Handle to the source Archive object - * @param src_path Path to the Directory inside of the source Archive - * @param dest_archive_handle Handle to the destination Archive object - * @param dest_path Path to the Directory inside of the destination Archive - * @return Whether rename succeeded - */ -ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, - const FileSys::Path& src_path, - ArchiveHandle dest_archive_handle, - const FileSys::Path& dest_path); + /** + * Rename a Directory between two Archives + * @param src_archive_handle Handle to the source Archive object + * @param src_path Path to the Directory inside of the source Archive + * @param dest_archive_handle Handle to the destination Archive object + * @param dest_path Path to the Directory inside of the destination Archive + * @return Whether rename succeeded + */ + ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, + const FileSys::Path& src_path, + ArchiveHandle dest_archive_handle, + const FileSys::Path& dest_path); -/** - * Open a Directory from an Archive - * @param archive_handle Handle to an open Archive object - * @param path Path to the Directory inside of the Archive - * @return The opened Directory object - */ -ResultVal> OpenDirectoryFromArchive(ArchiveHandle archive_handle, - const FileSys::Path& path); + /** + * Open a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return The opened Directory object + */ + ResultVal> OpenDirectoryFromArchive(ArchiveHandle archive_handle, + const FileSys::Path& path); -/** - * Get the free space in an Archive - * @param archive_handle Handle to an open Archive object - * @return The number of free bytes in the archive - */ -ResultVal GetFreeBytesInArchive(ArchiveHandle archive_handle); + /** + * Get the free space in an Archive + * @param archive_handle Handle to an open Archive object + * @return The number of free bytes in the archive + */ + ResultVal GetFreeBytesInArchive(ArchiveHandle archive_handle); -/** - * Erases the contents of the physical folder that contains the archive - * identified by the specified id code and path - * @param id_code The id of the archive to format - * @param format_info Format information about the new archive - * @param path The path to the archive, if relevant. - * @return ResultCode 0 on success or the corresponding code on error - */ -ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, - const FileSys::Path& path = FileSys::Path()); + /** + * Erases the contents of the physical folder that contains the archive + * identified by the specified id code and path + * @param id_code The id of the archive to format + * @param format_info Format information about the new archive + * @param path The path to the archive, if relevant. + * @return ResultCode 0 on success or the corresponding code on error + */ + ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, + const FileSys::Path& path = FileSys::Path()); -/** - * Retrieves the format info about the archive of the specified type and path. - * The format info is supplied by the client code when creating archives. - * @param id_code The id of the archive - * @param archive_path The path of the archive, if relevant - * @return The format info of the archive, or the corresponding error code if failed. - */ -ResultVal GetArchiveFormatInfo(ArchiveIdCode id_code, - FileSys::Path& archive_path); + /** + * Retrieves the format info about the archive of the specified type and path. + * The format info is supplied by the client code when creating archives. + * @param id_code The id of the archive + * @param archive_path The path of the archive, if relevant + * @return The format info of the archive, or the corresponding error code if failed. + */ + ResultVal GetArchiveFormatInfo(ArchiveIdCode id_code, + FileSys::Path& archive_path); -/** - * Creates a blank SharedExtSaveData archive for the specified extdata ID - * @param media_type The media type of the archive to create (NAND / SDMC) - * @param high The high word of the extdata id to create - * @param low The low word of the extdata id to create - * @param smdh_icon the SMDH icon for this ExtSaveData - * @param format_info Format information about the new archive - * @return ResultCode 0 on success or the corresponding code on error - */ -ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, - const std::vector& smdh_icon, - const FileSys::ArchiveFormatInfo& format_info); + /** + * Creates a blank SharedExtSaveData archive for the specified extdata ID + * @param media_type The media type of the archive to create (NAND / SDMC) + * @param high The high word of the extdata id to create + * @param low The low word of the extdata id to create + * @param smdh_icon the SMDH icon for this ExtSaveData + * @param format_info Format information about the new archive + * @return ResultCode 0 on success or the corresponding code on error + */ + ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, + const std::vector& smdh_icon, + const FileSys::ArchiveFormatInfo& format_info); -/** - * Deletes the SharedExtSaveData archive for the specified extdata ID - * @param media_type The media type of the archive to delete (NAND / SDMC) - * @param high The high word of the extdata id to delete - * @param low The low word of the extdata id to delete - * @return ResultCode 0 on success or the corresponding code on error - */ -ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low); + /** + * Deletes the SharedExtSaveData archive for the specified extdata ID + * @param media_type The media type of the archive to delete (NAND / SDMC) + * @param high The high word of the extdata id to delete + * @param low The low word of the extdata id to delete + * @return ResultCode 0 on success or the corresponding code on error + */ + ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low); -/** - * Deletes the SystemSaveData archive folder for the specified save data id - * @param high The high word of the SystemSaveData archive to delete - * @param low The low word of the SystemSaveData archive to delete - * @return ResultCode 0 on success or the corresponding code on error - */ -ResultCode DeleteSystemSaveData(u32 high, u32 low); + /** + * Deletes the SystemSaveData archive folder for the specified save data id + * @param high The high word of the SystemSaveData archive to delete + * @param low The low word of the SystemSaveData archive to delete + * @return ResultCode 0 on success or the corresponding code on error + */ + ResultCode DeleteSystemSaveData(u32 high, u32 low); -/** - * Creates the SystemSaveData archive folder for the specified save data id - * @param high The high word of the SystemSaveData archive to create - * @param low The low word of the SystemSaveData archive to create - * @return ResultCode 0 on success or the corresponding code on error - */ -ResultCode CreateSystemSaveData(u32 high, u32 low); + /** + * Creates the SystemSaveData archive folder for the specified save data id + * @param high The high word of the SystemSaveData archive to create + * @param low The low word of the SystemSaveData archive to create + * @return ResultCode 0 on success or the corresponding code on error + */ + ResultCode CreateSystemSaveData(u32 high, u32 low); -/// Initialize archives -void ArchiveInit(); + /// Registers a new NCCH file with the SelfNCCH archive factory + void RegisterSelfNCCH(Loader::AppLoader& app_loader); -/// Shutdown archives -void ArchiveShutdown(); +private: + /** + * Registers an Archive type, instances of which can later be opened using its IdCode. + * @param factory File system backend interface to the archive + * @param id_code Id code used to access this type of archive + */ + ResultCode RegisterArchiveType(std::unique_ptr&& factory, + ArchiveIdCode id_code); -/// Registers a new NCCH file with the SelfNCCH archive factory -void RegisterSelfNCCH(Loader::AppLoader& app_loader); + /// Register all archive types + void RegisterArchiveTypes(); -/// Register all archive types -void RegisterArchiveTypes(); + ArchiveBackend* GetArchive(ArchiveHandle handle); -/// Unregister all archive types -void UnregisterArchiveTypes(); + /** + * Map of registered archives, identified by id code. Once an archive is registered here, it is + * never removed until UnregisterArchiveTypes is called. + */ + boost::container::flat_map> id_code_map; + + /** + * Map of active archive handles to archive objects + */ + std::unordered_map> handle_map; + ArchiveHandle next_handle = 1; +}; } // namespace Service::FS diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index daa7bb237..4386fd608 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -56,7 +56,7 @@ void FS_USER::OpenFile(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_FS, "path={}, mode={} attrs={}", file_path.DebugStr(), mode.hex, attributes); ResultVal> file_res = - OpenFileFromArchive(archive_handle, file_path, mode); + archives.OpenFileFromArchive(archive_handle, file_path, mode); IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); rb.Push(file_res.Code()); if (file_res.Succeeded()) { @@ -92,7 +92,7 @@ void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - ResultVal archive_handle = Service::FS::OpenArchive(archive_id, archive_path); + ResultVal archive_handle = archives.OpenArchive(archive_id, archive_path); if (archive_handle.Failed()) { LOG_ERROR(Service_FS, "Failed to get a handle for archive archive_id=0x{:08X} archive_path={}", @@ -101,10 +101,10 @@ void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) { rb.PushMoveObjects(nullptr); return; } - SCOPE_EXIT({ Service::FS::CloseArchive(*archive_handle); }); + SCOPE_EXIT({ archives.CloseArchive(*archive_handle); }); ResultVal> file_res = - OpenFileFromArchive(*archive_handle, file_path, mode); + archives.OpenFileFromArchive(*archive_handle, file_path, mode); rb.Push(file_res.Code()); if (file_res.Succeeded()) { std::shared_ptr file = *file_res; @@ -131,7 +131,7 @@ void FS_USER::DeleteFile(Kernel::HLERequestContext& ctx) { file_path.DebugStr()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(DeleteFileFromArchive(archive_handle, file_path)); + rb.Push(archives.DeleteFileFromArchive(archive_handle, file_path)); } void FS_USER::RenameFile(Kernel::HLERequestContext& ctx) { @@ -158,8 +158,8 @@ void FS_USER::RenameFile(Kernel::HLERequestContext& ctx) { static_cast(dest_filename_type), dest_filename_size, dest_file_path.DebugStr()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle, - dest_file_path)); + rb.Push(archives.RenameFileBetweenArchives(src_archive_handle, src_file_path, + dest_archive_handle, dest_file_path)); } void FS_USER::DeleteDirectory(Kernel::HLERequestContext& ctx) { @@ -178,7 +178,7 @@ void FS_USER::DeleteDirectory(Kernel::HLERequestContext& ctx) { dir_path.DebugStr()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(DeleteDirectoryFromArchive(archive_handle, dir_path)); + rb.Push(archives.DeleteDirectoryFromArchive(archive_handle, dir_path)); } void FS_USER::DeleteDirectoryRecursively(Kernel::HLERequestContext& ctx) { @@ -197,7 +197,7 @@ void FS_USER::DeleteDirectoryRecursively(Kernel::HLERequestContext& ctx) { dir_path.DebugStr()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(DeleteDirectoryRecursivelyFromArchive(archive_handle, dir_path)); + rb.Push(archives.DeleteDirectoryRecursivelyFromArchive(archive_handle, dir_path)); } void FS_USER::CreateFile(Kernel::HLERequestContext& ctx) { @@ -218,7 +218,7 @@ void FS_USER::CreateFile(Kernel::HLERequestContext& ctx) { static_cast(filename_type), attributes, file_size, file_path.DebugStr()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(CreateFileInArchive(archive_handle, file_path, file_size)); + rb.Push(archives.CreateFileInArchive(archive_handle, file_path, file_size)); } void FS_USER::CreateDirectory(Kernel::HLERequestContext& ctx) { @@ -236,7 +236,7 @@ void FS_USER::CreateDirectory(Kernel::HLERequestContext& ctx) { dir_path.DebugStr()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(CreateDirectoryFromArchive(archive_handle, dir_path)); + rb.Push(archives.CreateDirectoryFromArchive(archive_handle, dir_path)); } void FS_USER::RenameDirectory(Kernel::HLERequestContext& ctx) { @@ -262,8 +262,8 @@ void FS_USER::RenameDirectory(Kernel::HLERequestContext& ctx) { static_cast(dest_dirname_type), dest_dirname_size, dest_dir_path.DebugStr()); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, - dest_dir_path)); + rb.Push(archives.RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, + dest_archive_handle, dest_dir_path)); } void FS_USER::OpenDirectory(Kernel::HLERequestContext& ctx) { @@ -281,7 +281,7 @@ void FS_USER::OpenDirectory(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); ResultVal> dir_res = - OpenDirectoryFromArchive(archive_handle, dir_path); + archives.OpenDirectoryFromArchive(archive_handle, dir_path); rb.Push(dir_res.Code()); if (dir_res.Succeeded()) { std::shared_ptr directory = *dir_res; @@ -308,7 +308,7 @@ void FS_USER::OpenArchive(Kernel::HLERequestContext& ctx) { archive_path.DebugStr()); IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); - ResultVal handle = Service::FS::OpenArchive(archive_id, archive_path); + ResultVal handle = archives.OpenArchive(archive_id, archive_path); rb.Push(handle.Code()); if (handle.Succeeded()) { rb.PushRaw(*handle); @@ -325,7 +325,7 @@ void FS_USER::CloseArchive(Kernel::HLERequestContext& ctx) { auto archive_handle = rp.PopRaw(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(Service::FS::CloseArchive(archive_handle)); + rb.Push(archives.CloseArchive(archive_handle)); } void FS_USER::IsSdmcDetected(Kernel::HLERequestContext& ctx) { @@ -384,7 +384,7 @@ void FS_USER::FormatSaveData(Kernel::HLERequestContext& ctx) { format_info.number_files = number_files; format_info.total_size = block_size * 512; - rb.Push(FormatArchive(ArchiveIdCode::SaveData, format_info)); + rb.Push(archives.FormatArchive(ArchiveIdCode::SaveData, format_info)); } void FS_USER::FormatThisUserSaveData(Kernel::HLERequestContext& ctx) { @@ -403,7 +403,7 @@ void FS_USER::FormatThisUserSaveData(Kernel::HLERequestContext& ctx) { format_info.total_size = block_size * 512; IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(FormatArchive(ArchiveIdCode::SaveData, format_info)); + rb.Push(archives.FormatArchive(ArchiveIdCode::SaveData, format_info)); LOG_TRACE(Service_FS, "called"); } @@ -411,7 +411,7 @@ void FS_USER::FormatThisUserSaveData(Kernel::HLERequestContext& ctx) { void FS_USER::GetFreeBytes(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x812, 2, 0); ArchiveHandle archive_handle = rp.PopRaw(); - ResultVal bytes_res = GetFreeBytesInArchive(archive_handle); + ResultVal bytes_res = archives.GetFreeBytesInArchive(archive_handle); IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); rb.Push(bytes_res.Code()); @@ -445,7 +445,7 @@ void FS_USER::CreateExtSaveData(Kernel::HLERequestContext& ctx) { format_info.total_size = 0; IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(Service::FS::CreateExtSaveData(media_type, save_high, save_low, icon, format_info)); + rb.Push(archives.CreateExtSaveData(media_type, save_high, save_low, icon, format_info)); rb.PushMappedBuffer(icon_buffer); LOG_DEBUG(Service_FS, @@ -462,7 +462,7 @@ void FS_USER::DeleteExtSaveData(Kernel::HLERequestContext& ctx) { u32 unknown = rp.Pop(); // TODO(Subv): Figure out what this is IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(Service::FS::DeleteExtSaveData(media_type, save_high, save_low)); + rb.Push(archives.DeleteExtSaveData(media_type, save_high, save_low)); LOG_DEBUG(Service_FS, "called, save_low={:08X} save_high={:08X} media_type={:08X} unknown={:08X}", save_low, @@ -483,7 +483,7 @@ void FS_USER::DeleteSystemSaveData(Kernel::HLERequestContext& ctx) { u32 savedata_low = rp.Pop(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(Service::FS::DeleteSystemSaveData(savedata_high, savedata_low)); + rb.Push(archives.DeleteSystemSaveData(savedata_high, savedata_low)); } void FS_USER::CreateSystemSaveData(Kernel::HLERequestContext& ctx) { @@ -506,7 +506,7 @@ void FS_USER::CreateSystemSaveData(Kernel::HLERequestContext& ctx) { file_buckets, duplicate); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(Service::FS::CreateSystemSaveData(savedata_high, savedata_low)); + rb.Push(archives.CreateSystemSaveData(savedata_high, savedata_low)); } void FS_USER::CreateLegacySystemSaveData(Kernel::HLERequestContext& ctx) { @@ -528,7 +528,7 @@ void FS_USER::CreateLegacySystemSaveData(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); // With this command, the SystemSaveData always has save_high = 0 (Always created in the NAND) - rb.Push(Service::FS::CreateSystemSaveData(0, savedata_id)); + rb.Push(archives.CreateSystemSaveData(0, savedata_id)); } void FS_USER::InitializeWithSdkVersion(Kernel::HLERequestContext& ctx) { @@ -595,7 +595,7 @@ void FS_USER::GetFormatInfo(Kernel::HLERequestContext& ctx) { IPC::RequestBuilder rb = rp.MakeBuilder(5, 0); - auto format_info = GetArchiveFormatInfo(archive_id, archive_path); + auto format_info = archives.GetArchiveFormatInfo(archive_id, archive_path); rb.Push(format_info.Code()); if (format_info.Failed()) { LOG_ERROR(Service_FS, "Failed to retrieve the format info"); @@ -663,7 +663,7 @@ void FS_USER::ObsoletedCreateExtSaveData(Kernel::HLERequestContext& ctx) { format_info.total_size = 0; IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - rb.Push(Service::FS::CreateExtSaveData(media_type, save_high, save_low, icon, format_info)); + rb.Push(archives.CreateExtSaveData(media_type, save_high, save_low, icon, format_info)); rb.PushMappedBuffer(icon_buffer); LOG_DEBUG(Service_FS, @@ -678,7 +678,7 @@ void FS_USER::ObsoletedDeleteExtSaveData(Kernel::HLERequestContext& ctx) { u32 save_low = rp.Pop(); IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(Service::FS::DeleteExtSaveData(media_type, 0, save_low)); + rb.Push(archives.DeleteExtSaveData(media_type, 0, save_low)); LOG_DEBUG(Service_FS, "called, save_low={:08X} media_type={:08X}", save_low, static_cast(media_type)); @@ -736,7 +736,7 @@ void FS_USER::GetSaveDataSecureValue(Kernel::HLERequestContext& ctx) { rb.Push(0); // the secure value } -FS_USER::FS_USER() : ServiceFramework("fs:USER", 30) { +FS_USER::FS_USER(ArchiveManager& archives) : ServiceFramework("fs:USER", 30), archives(archives) { static const FunctionInfo functions[] = { {0x000100C6, nullptr, "Dummy1"}, {0x040100C4, nullptr, "Control"}, @@ -855,6 +855,6 @@ FS_USER::FS_USER() : ServiceFramework("fs:USER", 30) { void InstallInterfaces(Core::System& system) { auto& service_manager = system.ServiceManager(); - std::make_shared()->InstallAsService(service_manager); + std::make_shared(system.ArchiveManager())->InstallAsService(service_manager); } } // namespace Service::FS diff --git a/src/core/hle/service/fs/fs_user.h b/src/core/hle/service/fs/fs_user.h index d8a044dd9..9556c787a 100644 --- a/src/core/hle/service/fs/fs_user.h +++ b/src/core/hle/service/fs/fs_user.h @@ -13,9 +13,11 @@ class System; namespace Service::FS { +class ArchiveManager; + class FS_USER final : public ServiceFramework { public: - FS_USER(); + explicit FS_USER(ArchiveManager& archives); private: void Initialize(Kernel::HLERequestContext& ctx); @@ -519,6 +521,8 @@ private: void GetSaveDataSecureValue(Kernel::HLERequestContext& ctx); u32 priority = -1; ///< For SetPriority and GetPriority service functions + + ArchiveManager& archives; }; void InstallInterfaces(Core::System& system); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 7d6b25d0f..5755d0335 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -236,7 +236,6 @@ static bool AttemptLLE(const ServiceModuleInfo& service_module) { /// Initialize ServiceManager void Init(Core::System& core, std::shared_ptr& sm) { - FS::ArchiveInit(); SM::ServiceManager::InstallInterfaces(sm); for (const auto& service_module : service_module_map) { @@ -248,7 +247,6 @@ void Init(Core::System& core, std::shared_ptr& sm) { /// Shutdown ServiceManager void Shutdown() { - FS::ArchiveShutdown(); g_kernel_named_ports.clear(); LOG_DEBUG(Service, "shutdown OK"); diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index 5ec3000e8..d791c085c 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp @@ -5,7 +5,7 @@ #include #include #include "common/logging/log.h" -#include "core/file_sys/archive_selfncch.h" +#include "core/core.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" #include "core/hle/service/fs/archive.h" @@ -277,7 +277,7 @@ ResultStatus AppLoader_THREEDSX::Load(Kernel::SharedPtr& proces process->Run(48, Kernel::DEFAULT_STACK_SIZE); - Service::FS::RegisterSelfNCCH(*this); + Core::System::GetInstance().ArchiveManager().RegisterSelfNCCH(*this); is_loaded = true; return ResultStatus::Success; diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 12301cb94..c2a0ce0ab 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -14,7 +14,6 @@ #include "common/string_util.h" #include "common/swap.h" #include "core/core.h" -#include "core/file_sys/archive_selfncch.h" #include "core/file_sys/ncch_container.h" #include "core/file_sys/title_metadata.h" #include "core/hle/kernel/process.h" @@ -185,7 +184,7 @@ ResultStatus AppLoader_NCCH::Load(Kernel::SharedPtr& process) { if (ResultStatus::Success != result) return result; - Service::FS::RegisterSelfNCCH(*this); + Core::System::GetInstance().ArchiveManager().RegisterSelfNCCH(*this); ParseRegionLockoutInfo();