diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c30a7e281..1498ee343 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -249,6 +249,10 @@ add_library(core STATIC hle/service/frd/frd_u.h hle/service/fs/archive.cpp hle/service/fs/archive.h + hle/service/fs/directory.cpp + hle/service/fs/directory.h + hle/service/fs/file.cpp + hle/service/fs/file.h hle/service/fs/fs_user.cpp hle/service/fs/fs_user.h hle/service/gsp/gsp.cpp diff --git a/src/core/core.cpp b/src/core/core.cpp index 393d1f4d1..4f7a5e908 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" @@ -192,6 +193,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); @@ -220,6 +222,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 6d72b4c53..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" @@ -27,360 +25,18 @@ #include "core/file_sys/directory_backend.h" #include "core/file_sys/errors.h" #include "core/file_sys/file_backend.h" -#include "core/hle/ipc.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/client_port.h" -#include "core/hle/kernel/client_session.h" -#include "core/hle/kernel/event.h" -#include "core/hle/kernel/handle_table.h" -#include "core/hle/kernel/server_session.h" #include "core/hle/result.h" #include "core/hle/service/fs/archive.h" -#include "core/hle/service/fs/fs_user.h" -#include "core/hle/service/service.h" -#include "core/memory.h" namespace Service::FS { -// Command to access directory -enum class DirectoryCommand : u32 { - Dummy1 = 0x000100C6, - Control = 0x040100C4, - Read = 0x08010042, - Close = 0x08020000, -}; - -File::File(std::unique_ptr&& backend, const FileSys::Path& path) - : ServiceFramework("", 1), path(path), backend(std::move(backend)) { - static const FunctionInfo functions[] = { - {0x08010100, &File::OpenSubFile, "OpenSubFile"}, - {0x080200C2, &File::Read, "Read"}, - {0x08030102, &File::Write, "Write"}, - {0x08040000, &File::GetSize, "GetSize"}, - {0x08050080, &File::SetSize, "SetSize"}, - {0x08080000, &File::Close, "Close"}, - {0x08090000, &File::Flush, "Flush"}, - {0x080A0040, &File::SetPriority, "SetPriority"}, - {0x080B0000, &File::GetPriority, "GetPriority"}, - {0x080C0000, &File::OpenLinkFile, "OpenLinkFile"}, - }; - RegisterHandlers(functions); -} - -void File::Read(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x0802, 3, 2); - u64 offset = rp.Pop(); - u32 length = rp.Pop(); - auto& buffer = rp.PopMappedBuffer(); - LOG_TRACE(Service_FS, "Read {}: offset=0x{:x} length=0x{:08X}", GetName(), offset, length); - - const FileSessionSlot* file = GetSessionData(ctx.Session()); - - if (file->subfile && length > file->size) { - LOG_WARNING(Service_FS, "Trying to read beyond the subfile size, truncating"); - length = static_cast(file->size); - } - - // This file session might have a specific offset from where to start reading, apply it. - offset += file->offset; - - if (offset + length > backend->GetSize()) { - LOG_ERROR(Service_FS, - "Reading from out of bounds offset=0x{:x} length=0x{:08X} file_size=0x{:x}", - offset, length, backend->GetSize()); - } - - IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); - - std::vector data(length); - ResultVal read = backend->Read(offset, data.size(), data.data()); - if (read.Failed()) { - rb.Push(read.Code()); - rb.Push(0); - } else { - buffer.Write(data.data(), 0, *read); - rb.Push(RESULT_SUCCESS); - rb.Push(static_cast(*read)); - } - rb.PushMappedBuffer(buffer); - - std::chrono::nanoseconds read_timeout_ns{backend->GetReadDelayNs(length)}; - ctx.SleepClientThread(Kernel::GetCurrentThread(), "file::read", read_timeout_ns, - [](Kernel::SharedPtr thread, - Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) { - // Nothing to do here - }); -} - -void File::Write(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x0803, 4, 2); - u64 offset = rp.Pop(); - u32 length = rp.Pop(); - u32 flush = rp.Pop(); - auto& buffer = rp.PopMappedBuffer(); - LOG_TRACE(Service_FS, "Write {}: offset=0x{:x} length={}, flush=0x{:x}", GetName(), offset, - length, flush); - - IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); - - const FileSessionSlot* file = GetSessionData(ctx.Session()); - - // Subfiles can not be written to - if (file->subfile) { - rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS); - rb.Push(0); - rb.PushMappedBuffer(buffer); - return; - } - - std::vector data(length); - buffer.Read(data.data(), 0, data.size()); - ResultVal written = backend->Write(offset, data.size(), flush != 0, data.data()); - if (written.Failed()) { - rb.Push(written.Code()); - rb.Push(0); - } else { - rb.Push(RESULT_SUCCESS); - rb.Push(static_cast(*written)); - } - rb.PushMappedBuffer(buffer); -} - -void File::GetSize(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x0804, 0, 0); - - const FileSessionSlot* file = GetSessionData(ctx.Session()); - - IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); - rb.Push(RESULT_SUCCESS); - rb.Push(file->size); -} - -void File::SetSize(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x0805, 2, 0); - u64 size = rp.Pop(); - - FileSessionSlot* file = GetSessionData(ctx.Session()); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - - // SetSize can not be called on subfiles. - if (file->subfile) { - rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS); - return; - } - - file->size = size; - backend->SetSize(size); - rb.Push(RESULT_SUCCESS); -} - -void File::Close(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x0808, 0, 0); - - // TODO(Subv): Only close the backend if this client is the only one left. - if (connected_sessions.size() > 1) - LOG_WARNING(Service_FS, "Closing File backend but {} clients still connected", - connected_sessions.size()); - - backend->Close(); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(RESULT_SUCCESS); -} - -void File::Flush(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x0809, 0, 0); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - - const FileSessionSlot* file = GetSessionData(ctx.Session()); - - // Subfiles can not be flushed. - if (file->subfile) { - rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS); - return; - } - - backend->Flush(); - rb.Push(RESULT_SUCCESS); -} - -void File::SetPriority(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x080A, 1, 0); - - FileSessionSlot* file = GetSessionData(ctx.Session()); - file->priority = rp.Pop(); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(RESULT_SUCCESS); -} - -void File::GetPriority(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x080B, 0, 0); - const FileSessionSlot* file = GetSessionData(ctx.Session()); - - IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); - rb.Push(RESULT_SUCCESS); - rb.Push(file->priority); -} - -void File::OpenLinkFile(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile {}", GetName()); - using Kernel::ClientSession; - using Kernel::ServerSession; - using Kernel::SharedPtr; - IPC::RequestParser rp(ctx, 0x080C, 0, 0); - IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - auto sessions = ServerSession::CreateSessionPair(GetName()); - auto server = std::get>(sessions); - ClientConnected(server); - - FileSessionSlot* slot = GetSessionData(server); - const FileSessionSlot* original_file = GetSessionData(ctx.Session()); - - slot->priority = original_file->priority; - slot->offset = 0; - slot->size = backend->GetSize(); - slot->subfile = false; - - rb.Push(RESULT_SUCCESS); - rb.PushMoveObjects(std::get>(sessions)); -} - -void File::OpenSubFile(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x0801, 4, 0); - s64 offset = rp.PopRaw(); - s64 size = rp.PopRaw(); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); - - const FileSessionSlot* original_file = GetSessionData(ctx.Session()); - - if (original_file->subfile) { - // OpenSubFile can not be called on a file which is already as subfile - rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS); - return; - } - - if (offset < 0 || size < 0) { - rb.Push(FileSys::ERR_WRITE_BEYOND_END); - return; - } - - std::size_t end = offset + size; - - // TODO(Subv): Check for overflow and return ERR_WRITE_BEYOND_END - - if (end > original_file->size) { - rb.Push(FileSys::ERR_WRITE_BEYOND_END); - return; - } - - using Kernel::ClientSession; - using Kernel::ServerSession; - using Kernel::SharedPtr; - auto sessions = ServerSession::CreateSessionPair(GetName()); - auto server = std::get>(sessions); - ClientConnected(server); - - FileSessionSlot* slot = GetSessionData(server); - slot->priority = original_file->priority; - slot->offset = offset; - slot->size = size; - slot->subfile = true; - - rb.Push(RESULT_SUCCESS); - rb.PushMoveObjects(std::get>(sessions)); -} - -Kernel::SharedPtr File::Connect() { - auto sessions = Kernel::ServerSession::CreateSessionPair(GetName()); - auto server = std::get>(sessions); - ClientConnected(server); - - FileSessionSlot* slot = GetSessionData(server); - slot->priority = 0; - slot->offset = 0; - slot->size = backend->GetSize(); - slot->subfile = false; - - return std::get>(sessions); -} - -std::size_t File::GetSessionFileOffset(Kernel::SharedPtr session) { - const FileSessionSlot* slot = GetSessionData(session); - ASSERT(slot); - return slot->offset; -} - -std::size_t File::GetSessionFileSize(Kernel::SharedPtr session) { - const FileSessionSlot* slot = GetSessionData(session); - ASSERT(slot); - return slot->size; -} - -Directory::Directory(std::unique_ptr&& backend, - const FileSys::Path& path) - : ServiceFramework("", 1), path(path), backend(std::move(backend)) { - static const FunctionInfo functions[] = { - // clang-format off - {0x08010042, &Directory::Read, "Read"}, - {0x08020000, &Directory::Close, "Close"}, - // clang-format on - }; - RegisterHandlers(functions); -} - -Directory::~Directory() {} - -void Directory::Read(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x0801, 1, 2); - u32 count = rp.Pop(); - auto& buffer = rp.PopMappedBuffer(); - std::vector entries(count); - LOG_TRACE(Service_FS, "Read {}: count={}", GetName(), count); - // Number of entries actually read - u32 read = backend->Read(static_cast(entries.size()), entries.data()); - buffer.Write(entries.data(), 0, read * sizeof(FileSys::Entry)); - - IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); - rb.Push(RESULT_SUCCESS); - rb.Push(read); - rb.PushMappedBuffer(buffer); -} - -void Directory::Close(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp(ctx, 0x0802, 0, 0); - LOG_TRACE(Service_FS, "Close {}", GetName()); - backend->Close(); - - IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); - rb.Push(RESULT_SUCCESS); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -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); @@ -398,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 @@ -407,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; @@ -420,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; @@ -435,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; @@ -443,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) @@ -460,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; @@ -468,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; @@ -477,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; @@ -486,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; @@ -494,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) @@ -511,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; @@ -525,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 @@ -542,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 @@ -552,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); @@ -576,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); @@ -600,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); @@ -612,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); @@ -624,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). @@ -676,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, @@ -688,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 d6ceb9229..ef9b9efc2 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -6,18 +6,14 @@ #include #include +#include #include +#include #include "common/common_types.h" #include "core/file_sys/archive_backend.h" -#include "core/hle/kernel/hle_ipc.h" -#include "core/hle/kernel/kernel.h" #include "core/hle/result.h" -#include "core/hle/service/service.h" - -namespace FileSys { -class DirectoryBackend; -class FileBackend; -} // namespace FileSys +#include "core/hle/service/fs/directory.h" +#include "core/hle/service/fs/file.h" /// The unique system identifier hash, also known as ID0 static constexpr char SYSTEM_ID[]{"00000000000000000000000000000000"}; @@ -49,258 +45,209 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 }; typedef u64 ArchiveHandle; -struct FileSessionSlot : public Kernel::SessionRequestHandler::SessionDataBase { - u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means - u64 offset; ///< Offset that this session will start reading from. - u64 size; ///< Max size of the file that this session is allowed to access - bool subfile; ///< Whether this file was opened via OpenSubFile or not. -}; +using FileSys::ArchiveBackend; +using FileSys::ArchiveFactory; -// TODO: File is not a real service, but it can still utilize ServiceFramework::RegisterHandlers. -// Consider splitting ServiceFramework interface. -class File final : public ServiceFramework { +class ArchiveManager { public: - File(std::unique_ptr&& backend, const FileSys::Path& path); - ~File() = default; + 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); - std::string GetName() const { - return "Path: " + path.DebugStr(); - } + /** + * Closes an archive + * @param handle Handle to the archive to close + */ + ResultCode CloseArchive(ArchiveHandle handle); - FileSys::Path path; ///< Path of the file - std::unique_ptr backend; ///< File backend interface + /** + * 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); - /// Creates a new session to this File and returns the ClientSession part of the connection. - Kernel::SharedPtr Connect(); + /** + * 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); - // Returns the start offset of an open file represented by the input session, opened with - // OpenSubFile. - std::size_t GetSessionFileOffset(Kernel::SharedPtr session); + /** + * 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); - // Returns the size of an open file represented by the input session, opened with - // OpenSubFile. - std::size_t GetSessionFileSize(Kernel::SharedPtr session); + /** + * 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); + + /** + * 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); + + /** + * 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); + + /** + * 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()); + + /** + * 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); + + /** + * 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); + + /** + * 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); + + /// Registers a new NCCH file with the SelfNCCH archive factory + void RegisterSelfNCCH(Loader::AppLoader& app_loader); private: - void Read(Kernel::HLERequestContext& ctx); - void Write(Kernel::HLERequestContext& ctx); - void GetSize(Kernel::HLERequestContext& ctx); - void SetSize(Kernel::HLERequestContext& ctx); - void Close(Kernel::HLERequestContext& ctx); - void Flush(Kernel::HLERequestContext& ctx); - void SetPriority(Kernel::HLERequestContext& ctx); - void GetPriority(Kernel::HLERequestContext& ctx); - void OpenLinkFile(Kernel::HLERequestContext& ctx); - void OpenSubFile(Kernel::HLERequestContext& ctx); + /** + * 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); + + /// Register all archive types + void RegisterArchiveTypes(); + + ArchiveBackend* GetArchive(ArchiveHandle handle); + + /** + * 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; }; -class Directory final : public ServiceFramework { -public: - Directory(std::unique_ptr&& backend, const FileSys::Path& path); - ~Directory(); - - std::string GetName() const { - return "Directory: " + path.DebugStr(); - } - - FileSys::Path path; ///< Path of the directory - std::unique_ptr backend; ///< File backend interface - -protected: - void Read(Kernel::HLERequestContext& ctx); - void Close(Kernel::HLERequestContext& ctx); -}; - -/** - * 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); - -/** - * Closes an archive - * @param handle Handle to the archive to close - */ -ResultCode CloseArchive(ArchiveHandle handle); - -/** - * 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); - -/** - * 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); - -/** - * 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 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 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); - -/** - * 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); - -/** - * 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); - -/** - * 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 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); - -/// Initialize archives -void ArchiveInit(); - -/// Shutdown archives -void ArchiveShutdown(); - -/// Registers a new NCCH file with the SelfNCCH archive factory -void RegisterSelfNCCH(Loader::AppLoader& app_loader); - -/// Register all archive types -void RegisterArchiveTypes(); - -/// Unregister all archive types -void UnregisterArchiveTypes(); - } // namespace Service::FS diff --git a/src/core/hle/service/fs/directory.cpp b/src/core/hle/service/fs/directory.cpp new file mode 100644 index 000000000..a72a9307a --- /dev/null +++ b/src/core/hle/service/fs/directory.cpp @@ -0,0 +1,51 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/file_sys/directory_backend.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/fs/directory.h" + +namespace Service::FS { + +Directory::Directory(std::unique_ptr&& backend, + const FileSys::Path& path) + : ServiceFramework("", 1), path(path), backend(std::move(backend)) { + static const FunctionInfo functions[] = { + // clang-format off + {0x08010042, &Directory::Read, "Read"}, + {0x08020000, &Directory::Close, "Close"}, + // clang-format on + }; + RegisterHandlers(functions); +} + +Directory::~Directory() {} + +void Directory::Read(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0801, 1, 2); + u32 count = rp.Pop(); + auto& buffer = rp.PopMappedBuffer(); + std::vector entries(count); + LOG_TRACE(Service_FS, "Read {}: count={}", GetName(), count); + // Number of entries actually read + u32 read = backend->Read(static_cast(entries.size()), entries.data()); + buffer.Write(entries.data(), 0, read * sizeof(FileSys::Entry)); + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); + rb.Push(RESULT_SUCCESS); + rb.Push(read); + rb.PushMappedBuffer(buffer); +} + +void Directory::Close(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0802, 0, 0); + LOG_TRACE(Service_FS, "Close {}", GetName()); + backend->Close(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); +} + +} // namespace Service::FS diff --git a/src/core/hle/service/fs/directory.h b/src/core/hle/service/fs/directory.h new file mode 100644 index 000000000..2f4529ca0 --- /dev/null +++ b/src/core/hle/service/fs/directory.h @@ -0,0 +1,30 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/file_sys/archive_backend.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service::FS { + +class Directory final : public ServiceFramework { +public: + Directory(std::unique_ptr&& backend, const FileSys::Path& path); + ~Directory(); + + std::string GetName() const { + return "Directory: " + path.DebugStr(); + } + + FileSys::Path path; ///< Path of the directory + std::unique_ptr backend; ///< File backend interface + +protected: + void Read(Kernel::HLERequestContext& ctx); + void Close(Kernel::HLERequestContext& ctx); +}; + +} // namespace Service::FS diff --git a/src/core/hle/service/fs/file.cpp b/src/core/hle/service/fs/file.cpp new file mode 100644 index 000000000..d2f1f2a85 --- /dev/null +++ b/src/core/hle/service/fs/file.cpp @@ -0,0 +1,286 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/file_sys/errors.h" +#include "core/file_sys/file_backend.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/client_session.h" +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/server_session.h" +#include "core/hle/service/fs/file.h" + +namespace Service::FS { + +File::File(std::unique_ptr&& backend, const FileSys::Path& path) + : ServiceFramework("", 1), path(path), backend(std::move(backend)) { + static const FunctionInfo functions[] = { + {0x08010100, &File::OpenSubFile, "OpenSubFile"}, + {0x080200C2, &File::Read, "Read"}, + {0x08030102, &File::Write, "Write"}, + {0x08040000, &File::GetSize, "GetSize"}, + {0x08050080, &File::SetSize, "SetSize"}, + {0x08080000, &File::Close, "Close"}, + {0x08090000, &File::Flush, "Flush"}, + {0x080A0040, &File::SetPriority, "SetPriority"}, + {0x080B0000, &File::GetPriority, "GetPriority"}, + {0x080C0000, &File::OpenLinkFile, "OpenLinkFile"}, + }; + RegisterHandlers(functions); +} + +void File::Read(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0802, 3, 2); + u64 offset = rp.Pop(); + u32 length = rp.Pop(); + auto& buffer = rp.PopMappedBuffer(); + LOG_TRACE(Service_FS, "Read {}: offset=0x{:x} length=0x{:08X}", GetName(), offset, length); + + const FileSessionSlot* file = GetSessionData(ctx.Session()); + + if (file->subfile && length > file->size) { + LOG_WARNING(Service_FS, "Trying to read beyond the subfile size, truncating"); + length = static_cast(file->size); + } + + // This file session might have a specific offset from where to start reading, apply it. + offset += file->offset; + + if (offset + length > backend->GetSize()) { + LOG_ERROR(Service_FS, + "Reading from out of bounds offset=0x{:x} length=0x{:08X} file_size=0x{:x}", + offset, length, backend->GetSize()); + } + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); + + std::vector data(length); + ResultVal read = backend->Read(offset, data.size(), data.data()); + if (read.Failed()) { + rb.Push(read.Code()); + rb.Push(0); + } else { + buffer.Write(data.data(), 0, *read); + rb.Push(RESULT_SUCCESS); + rb.Push(static_cast(*read)); + } + rb.PushMappedBuffer(buffer); + + std::chrono::nanoseconds read_timeout_ns{backend->GetReadDelayNs(length)}; + ctx.SleepClientThread(Kernel::GetCurrentThread(), "file::read", read_timeout_ns, + [](Kernel::SharedPtr thread, + Kernel::HLERequestContext& ctx, Kernel::ThreadWakeupReason reason) { + // Nothing to do here + }); +} + +void File::Write(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0803, 4, 2); + u64 offset = rp.Pop(); + u32 length = rp.Pop(); + u32 flush = rp.Pop(); + auto& buffer = rp.PopMappedBuffer(); + LOG_TRACE(Service_FS, "Write {}: offset=0x{:x} length={}, flush=0x{:x}", GetName(), offset, + length, flush); + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); + + const FileSessionSlot* file = GetSessionData(ctx.Session()); + + // Subfiles can not be written to + if (file->subfile) { + rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS); + rb.Push(0); + rb.PushMappedBuffer(buffer); + return; + } + + std::vector data(length); + buffer.Read(data.data(), 0, data.size()); + ResultVal written = backend->Write(offset, data.size(), flush != 0, data.data()); + if (written.Failed()) { + rb.Push(written.Code()); + rb.Push(0); + } else { + rb.Push(RESULT_SUCCESS); + rb.Push(static_cast(*written)); + } + rb.PushMappedBuffer(buffer); +} + +void File::GetSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0804, 0, 0); + + const FileSessionSlot* file = GetSessionData(ctx.Session()); + + IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(file->size); +} + +void File::SetSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0805, 2, 0); + u64 size = rp.Pop(); + + FileSessionSlot* file = GetSessionData(ctx.Session()); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + + // SetSize can not be called on subfiles. + if (file->subfile) { + rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS); + return; + } + + file->size = size; + backend->SetSize(size); + rb.Push(RESULT_SUCCESS); +} + +void File::Close(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0808, 0, 0); + + // TODO(Subv): Only close the backend if this client is the only one left. + if (connected_sessions.size() > 1) + LOG_WARNING(Service_FS, "Closing File backend but {} clients still connected", + connected_sessions.size()); + + backend->Close(); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); +} + +void File::Flush(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0809, 0, 0); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + + const FileSessionSlot* file = GetSessionData(ctx.Session()); + + // Subfiles can not be flushed. + if (file->subfile) { + rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS); + return; + } + + backend->Flush(); + rb.Push(RESULT_SUCCESS); +} + +void File::SetPriority(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x080A, 1, 0); + + FileSessionSlot* file = GetSessionData(ctx.Session()); + file->priority = rp.Pop(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); + rb.Push(RESULT_SUCCESS); +} + +void File::GetPriority(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x080B, 0, 0); + const FileSessionSlot* file = GetSessionData(ctx.Session()); + + IPC::RequestBuilder rb = rp.MakeBuilder(2, 0); + rb.Push(RESULT_SUCCESS); + rb.Push(file->priority); +} + +void File::OpenLinkFile(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) File command OpenLinkFile {}", GetName()); + using Kernel::ClientSession; + using Kernel::ServerSession; + using Kernel::SharedPtr; + IPC::RequestParser rp(ctx, 0x080C, 0, 0); + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + auto sessions = ServerSession::CreateSessionPair(GetName()); + auto server = std::get>(sessions); + ClientConnected(server); + + FileSessionSlot* slot = GetSessionData(server); + const FileSessionSlot* original_file = GetSessionData(ctx.Session()); + + slot->priority = original_file->priority; + slot->offset = 0; + slot->size = backend->GetSize(); + slot->subfile = false; + + rb.Push(RESULT_SUCCESS); + rb.PushMoveObjects(std::get>(sessions)); +} + +void File::OpenSubFile(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp(ctx, 0x0801, 4, 0); + s64 offset = rp.PopRaw(); + s64 size = rp.PopRaw(); + + IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); + + const FileSessionSlot* original_file = GetSessionData(ctx.Session()); + + if (original_file->subfile) { + // OpenSubFile can not be called on a file which is already as subfile + rb.Push(FileSys::ERROR_UNSUPPORTED_OPEN_FLAGS); + return; + } + + if (offset < 0 || size < 0) { + rb.Push(FileSys::ERR_WRITE_BEYOND_END); + return; + } + + std::size_t end = offset + size; + + // TODO(Subv): Check for overflow and return ERR_WRITE_BEYOND_END + + if (end > original_file->size) { + rb.Push(FileSys::ERR_WRITE_BEYOND_END); + return; + } + + using Kernel::ClientSession; + using Kernel::ServerSession; + using Kernel::SharedPtr; + auto sessions = ServerSession::CreateSessionPair(GetName()); + auto server = std::get>(sessions); + ClientConnected(server); + + FileSessionSlot* slot = GetSessionData(server); + slot->priority = original_file->priority; + slot->offset = offset; + slot->size = size; + slot->subfile = true; + + rb.Push(RESULT_SUCCESS); + rb.PushMoveObjects(std::get>(sessions)); +} + +Kernel::SharedPtr File::Connect() { + auto sessions = Kernel::ServerSession::CreateSessionPair(GetName()); + auto server = std::get>(sessions); + ClientConnected(server); + + FileSessionSlot* slot = GetSessionData(server); + slot->priority = 0; + slot->offset = 0; + slot->size = backend->GetSize(); + slot->subfile = false; + + return std::get>(sessions); +} + +std::size_t File::GetSessionFileOffset(Kernel::SharedPtr session) { + const FileSessionSlot* slot = GetSessionData(session); + ASSERT(slot); + return slot->offset; +} + +std::size_t File::GetSessionFileSize(Kernel::SharedPtr session) { + const FileSessionSlot* slot = GetSessionData(session); + ASSERT(slot); + return slot->size; +} + +} // namespace Service::FS diff --git a/src/core/hle/service/fs/file.h b/src/core/hle/service/fs/file.h new file mode 100644 index 000000000..2de9add98 --- /dev/null +++ b/src/core/hle/service/fs/file.h @@ -0,0 +1,58 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/file_sys/archive_backend.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service::FS { + +struct FileSessionSlot : public Kernel::SessionRequestHandler::SessionDataBase { + u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means + u64 offset; ///< Offset that this session will start reading from. + u64 size; ///< Max size of the file that this session is allowed to access + bool subfile; ///< Whether this file was opened via OpenSubFile or not. +}; + +// TODO: File is not a real service, but it can still utilize ServiceFramework::RegisterHandlers. +// Consider splitting ServiceFramework interface. +class File final : public ServiceFramework { +public: + File(std::unique_ptr&& backend, const FileSys::Path& path); + ~File() = default; + + std::string GetName() const { + return "Path: " + path.DebugStr(); + } + + FileSys::Path path; ///< Path of the file + std::unique_ptr backend; ///< File backend interface + + /// Creates a new session to this File and returns the ClientSession part of the connection. + Kernel::SharedPtr Connect(); + + // Returns the start offset of an open file represented by the input session, opened with + // OpenSubFile. + std::size_t GetSessionFileOffset(Kernel::SharedPtr session); + + // Returns the size of an open file represented by the input session, opened with + // OpenSubFile. + std::size_t GetSessionFileSize(Kernel::SharedPtr session); + +private: + void Read(Kernel::HLERequestContext& ctx); + void Write(Kernel::HLERequestContext& ctx); + void GetSize(Kernel::HLERequestContext& ctx); + void SetSize(Kernel::HLERequestContext& ctx); + void Close(Kernel::HLERequestContext& ctx); + void Flush(Kernel::HLERequestContext& ctx); + void SetPriority(Kernel::HLERequestContext& ctx); + void GetPriority(Kernel::HLERequestContext& ctx); + void OpenLinkFile(Kernel::HLERequestContext& ctx); + void OpenSubFile(Kernel::HLERequestContext& ctx); +}; + +} // namespace Service::FS diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index d447b748d..e4a7c251d 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -57,7 +57,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()) { @@ -93,7 +93,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={}", @@ -102,10 +102,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; @@ -132,7 +132,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) { @@ -159,8 +159,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) { @@ -179,7 +179,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) { @@ -198,7 +198,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) { @@ -219,7 +219,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) { @@ -237,7 +237,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) { @@ -263,8 +263,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) { @@ -282,7 +282,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; @@ -309,7 +309,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); @@ -326,7 +326,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) { @@ -385,7 +385,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) { @@ -404,7 +404,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"); } @@ -412,7 +412,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()); @@ -446,7 +446,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, @@ -463,7 +463,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, @@ -484,7 +484,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) { @@ -507,7 +507,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) { @@ -529,7 +529,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) { @@ -596,7 +596,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"); @@ -664,7 +664,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, @@ -679,7 +679,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)); @@ -741,7 +741,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"}, @@ -860,6 +860,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 32ad8bc7d..eb1b5af36 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); @@ -531,6 +533,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 28e7639b3..23b7b8feb 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();