mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	Merge pull request #4305 from wwylele/fs-global
FS/archive: wrap states into ArchiveManager class
This commit is contained in:
		
						commit
						0962ab8da9
					
				
					 14 changed files with 729 additions and 683 deletions
				
			
		|  | @ -249,6 +249,10 @@ add_library(core STATIC | ||||||
|     hle/service/frd/frd_u.h |     hle/service/frd/frd_u.h | ||||||
|     hle/service/fs/archive.cpp |     hle/service/fs/archive.cpp | ||||||
|     hle/service/fs/archive.h |     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.cpp | ||||||
|     hle/service/fs/fs_user.h |     hle/service/fs/fs_user.h | ||||||
|     hle/service/gsp/gsp.cpp |     hle/service/gsp/gsp.cpp | ||||||
|  |  | ||||||
|  | @ -19,6 +19,7 @@ | ||||||
| #include "core/hle/kernel/kernel.h" | #include "core/hle/kernel/kernel.h" | ||||||
| #include "core/hle/kernel/process.h" | #include "core/hle/kernel/process.h" | ||||||
| #include "core/hle/kernel/thread.h" | #include "core/hle/kernel/thread.h" | ||||||
|  | #include "core/hle/service/fs/archive.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| #include "core/hle/service/sm/sm.h" | #include "core/hle/service/sm/sm.h" | ||||||
| #include "core/hw/hw.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<Service::SM::ServiceManager>(); |     service_manager = std::make_shared<Service::SM::ServiceManager>(); | ||||||
|     shared_page_handler = std::make_shared<SharedPage::Handler>(); |     shared_page_handler = std::make_shared<SharedPage::Handler>(); | ||||||
|  |     archive_manager = std::make_unique<Service::FS::ArchiveManager>(); | ||||||
| 
 | 
 | ||||||
|     HW::Init(); |     HW::Init(); | ||||||
|     Kernel::Init(system_mode); |     Kernel::Init(system_mode); | ||||||
|  | @ -220,6 +222,14 @@ const Service::SM::ServiceManager& System::ServiceManager() const { | ||||||
|     return *service_manager; |     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<Frontend::SoftwareKeyboard> swkbd) { | void System::RegisterSoftwareKeyboard(std::shared_ptr<Frontend::SoftwareKeyboard> swkbd) { | ||||||
|     registered_swkbd = std::move(swkbd); |     registered_swkbd = std::move(swkbd); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -31,6 +31,9 @@ namespace Service { | ||||||
| namespace SM { | namespace SM { | ||||||
| class ServiceManager; | class ServiceManager; | ||||||
| } | } | ||||||
|  | namespace FS { | ||||||
|  | class ArchiveManager; | ||||||
|  | } | ||||||
| } // namespace Service
 | } // namespace Service
 | ||||||
| 
 | 
 | ||||||
| namespace Core { | namespace Core { | ||||||
|  | @ -158,6 +161,12 @@ public: | ||||||
|      */ |      */ | ||||||
|     const Service::SM::ServiceManager& ServiceManager() const; |     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; |     PerfStats perf_stats; | ||||||
|     FrameLimiter frame_limiter; |     FrameLimiter frame_limiter; | ||||||
| 
 | 
 | ||||||
|  | @ -230,6 +239,8 @@ private: | ||||||
|     /// Shared Page
 |     /// Shared Page
 | ||||||
|     std::shared_ptr<SharedPage::Handler> shared_page_handler; |     std::shared_ptr<SharedPage::Handler> shared_page_handler; | ||||||
| 
 | 
 | ||||||
|  |     std::unique_ptr<Service::FS::ArchiveManager> archive_manager; | ||||||
|  | 
 | ||||||
|     static System s_instance; |     static System s_instance; | ||||||
| 
 | 
 | ||||||
|     ResultStatus status = ResultStatus::Success; |     ResultStatus status = ResultStatus::Success; | ||||||
|  |  | ||||||
|  | @ -8,9 +8,7 @@ | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <system_error> | #include <system_error> | ||||||
| #include <type_traits> | #include <type_traits> | ||||||
| #include <unordered_map> |  | ||||||
| #include <utility> | #include <utility> | ||||||
| #include <boost/container/flat_map.hpp> |  | ||||||
| #include "common/assert.h" | #include "common/assert.h" | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "common/file_util.h" | #include "common/file_util.h" | ||||||
|  | @ -27,360 +25,18 @@ | ||||||
| #include "core/file_sys/directory_backend.h" | #include "core/file_sys/directory_backend.h" | ||||||
| #include "core/file_sys/errors.h" | #include "core/file_sys/errors.h" | ||||||
| #include "core/file_sys/file_backend.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/result.h" | ||||||
| #include "core/hle/service/fs/archive.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 { | namespace Service::FS { | ||||||
| 
 | 
 | ||||||
| // Command to access directory
 | ArchiveBackend* ArchiveManager::GetArchive(ArchiveHandle handle) { | ||||||
| enum class DirectoryCommand : u32 { |  | ||||||
|     Dummy1 = 0x000100C6, |  | ||||||
|     Control = 0x040100C4, |  | ||||||
|     Read = 0x08010042, |  | ||||||
|     Close = 0x08020000, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| File::File(std::unique_ptr<FileSys::FileBackend>&& 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<u64>(); |  | ||||||
|     u32 length = rp.Pop<u32>(); |  | ||||||
|     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<u32>(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<u8> data(length); |  | ||||||
|     ResultVal<std::size_t> read = backend->Read(offset, data.size(), data.data()); |  | ||||||
|     if (read.Failed()) { |  | ||||||
|         rb.Push(read.Code()); |  | ||||||
|         rb.Push<u32>(0); |  | ||||||
|     } else { |  | ||||||
|         buffer.Write(data.data(), 0, *read); |  | ||||||
|         rb.Push(RESULT_SUCCESS); |  | ||||||
|         rb.Push<u32>(static_cast<u32>(*read)); |  | ||||||
|     } |  | ||||||
|     rb.PushMappedBuffer(buffer); |  | ||||||
| 
 |  | ||||||
|     std::chrono::nanoseconds read_timeout_ns{backend->GetReadDelayNs(length)}; |  | ||||||
|     ctx.SleepClientThread(Kernel::GetCurrentThread(), "file::read", read_timeout_ns, |  | ||||||
|                           [](Kernel::SharedPtr<Kernel::Thread> 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<u64>(); |  | ||||||
|     u32 length = rp.Pop<u32>(); |  | ||||||
|     u32 flush = rp.Pop<u32>(); |  | ||||||
|     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<u32>(0); |  | ||||||
|         rb.PushMappedBuffer(buffer); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     std::vector<u8> data(length); |  | ||||||
|     buffer.Read(data.data(), 0, data.size()); |  | ||||||
|     ResultVal<std::size_t> written = backend->Write(offset, data.size(), flush != 0, data.data()); |  | ||||||
|     if (written.Failed()) { |  | ||||||
|         rb.Push(written.Code()); |  | ||||||
|         rb.Push<u32>(0); |  | ||||||
|     } else { |  | ||||||
|         rb.Push(RESULT_SUCCESS); |  | ||||||
|         rb.Push<u32>(static_cast<u32>(*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<u64>(file->size); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void File::SetSize(Kernel::HLERequestContext& ctx) { |  | ||||||
|     IPC::RequestParser rp(ctx, 0x0805, 2, 0); |  | ||||||
|     u64 size = rp.Pop<u64>(); |  | ||||||
| 
 |  | ||||||
|     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<u32>(); |  | ||||||
| 
 |  | ||||||
|     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<SharedPtr<ServerSession>>(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<SharedPtr<ClientSession>>(sessions)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void File::OpenSubFile(Kernel::HLERequestContext& ctx) { |  | ||||||
|     IPC::RequestParser rp(ctx, 0x0801, 4, 0); |  | ||||||
|     s64 offset = rp.PopRaw<s64>(); |  | ||||||
|     s64 size = rp.PopRaw<s64>(); |  | ||||||
| 
 |  | ||||||
|     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<SharedPtr<ServerSession>>(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<SharedPtr<ClientSession>>(sessions)); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Kernel::SharedPtr<Kernel::ClientSession> File::Connect() { |  | ||||||
|     auto sessions = Kernel::ServerSession::CreateSessionPair(GetName()); |  | ||||||
|     auto server = std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions); |  | ||||||
|     ClientConnected(server); |  | ||||||
| 
 |  | ||||||
|     FileSessionSlot* slot = GetSessionData(server); |  | ||||||
|     slot->priority = 0; |  | ||||||
|     slot->offset = 0; |  | ||||||
|     slot->size = backend->GetSize(); |  | ||||||
|     slot->subfile = false; |  | ||||||
| 
 |  | ||||||
|     return std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| std::size_t File::GetSessionFileOffset(Kernel::SharedPtr<Kernel::ServerSession> session) { |  | ||||||
|     const FileSessionSlot* slot = GetSessionData(session); |  | ||||||
|     ASSERT(slot); |  | ||||||
|     return slot->offset; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| std::size_t File::GetSessionFileSize(Kernel::SharedPtr<Kernel::ServerSession> session) { |  | ||||||
|     const FileSessionSlot* slot = GetSessionData(session); |  | ||||||
|     ASSERT(slot); |  | ||||||
|     return slot->size; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Directory::Directory(std::unique_ptr<FileSys::DirectoryBackend>&& 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<u32>(); |  | ||||||
|     auto& buffer = rp.PopMappedBuffer(); |  | ||||||
|     std::vector<FileSys::Entry> entries(count); |  | ||||||
|     LOG_TRACE(Service_FS, "Read {}: count={}", GetName(), count); |  | ||||||
|     // Number of entries actually read
 |  | ||||||
|     u32 read = backend->Read(static_cast<u32>(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<ArchiveIdCode, std::unique_ptr<ArchiveFactory>> id_code_map; |  | ||||||
| 
 |  | ||||||
| /**
 |  | ||||||
|  * Map of active archive handles. Values are pointers to the archives in `idcode_map`. |  | ||||||
|  */ |  | ||||||
| static std::unordered_map<ArchiveHandle, std::unique_ptr<ArchiveBackend>> handle_map; |  | ||||||
| static ArchiveHandle next_handle; |  | ||||||
| 
 |  | ||||||
| static ArchiveBackend* GetArchive(ArchiveHandle handle) { |  | ||||||
|     auto itr = handle_map.find(handle); |     auto itr = handle_map.find(handle); | ||||||
|     return (itr == handle_map.end()) ? nullptr : itr->second.get(); |     return (itr == handle_map.end()) ? nullptr : itr->second.get(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archive_path) { | ResultVal<ArchiveHandle> ArchiveManager::OpenArchive(ArchiveIdCode id_code, | ||||||
|  |                                                      FileSys::Path& archive_path) { | ||||||
|     LOG_TRACE(Service_FS, "Opening archive with id code 0x{:08X}", static_cast<u32>(id_code)); |     LOG_TRACE(Service_FS, "Opening archive with id code 0x{:08X}", static_cast<u32>(id_code)); | ||||||
| 
 | 
 | ||||||
|     auto itr = id_code_map.find(id_code); |     auto itr = id_code_map.find(id_code); | ||||||
|  | @ -398,7 +54,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi | ||||||
|     return MakeResult<ArchiveHandle>(next_handle++); |     return MakeResult<ArchiveHandle>(next_handle++); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode CloseArchive(ArchiveHandle handle) { | ResultCode ArchiveManager::CloseArchive(ArchiveHandle handle) { | ||||||
|     if (handle_map.erase(handle) == 0) |     if (handle_map.erase(handle) == 0) | ||||||
|         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; | ||||||
|     else |     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
 | // 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
 | // http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22
 | ||||||
| ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory, | ResultCode ArchiveManager::RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory, | ||||||
|                                ArchiveIdCode id_code) { |                                                ArchiveIdCode id_code) { | ||||||
|     auto result = id_code_map.emplace(id_code, std::move(factory)); |     auto result = id_code_map.emplace(id_code, std::move(factory)); | ||||||
| 
 | 
 | ||||||
|     bool inserted = result.second; |     bool inserted = result.second; | ||||||
|  | @ -420,9 +76,9 @@ ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factor | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handle, | ResultVal<std::shared_ptr<File>> ArchiveManager::OpenFileFromArchive(ArchiveHandle archive_handle, | ||||||
|                                                      const FileSys::Path& path, |                                                                      const FileSys::Path& path, | ||||||
|                                                      const FileSys::Mode mode) { |                                                                      const FileSys::Mode mode) { | ||||||
|     ArchiveBackend* archive = GetArchive(archive_handle); |     ArchiveBackend* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; | ||||||
|  | @ -435,7 +91,8 @@ ResultVal<std::shared_ptr<File>> OpenFileFromArchive(ArchiveHandle archive_handl | ||||||
|     return MakeResult<std::shared_ptr<File>>(std::move(file)); |     return MakeResult<std::shared_ptr<File>>(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); |     ArchiveBackend* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; | ||||||
|  | @ -443,10 +100,10 @@ ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Pa | ||||||
|     return archive->DeleteFile(path); |     return archive->DeleteFile(path); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, | ResultCode ArchiveManager::RenameFileBetweenArchives(ArchiveHandle src_archive_handle, | ||||||
|                                      const FileSys::Path& src_path, |                                                      const FileSys::Path& src_path, | ||||||
|                                      ArchiveHandle dest_archive_handle, |                                                      ArchiveHandle dest_archive_handle, | ||||||
|                                      const FileSys::Path& dest_path) { |                                                      const FileSys::Path& dest_path) { | ||||||
|     ArchiveBackend* src_archive = GetArchive(src_archive_handle); |     ArchiveBackend* src_archive = GetArchive(src_archive_handle); | ||||||
|     ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); |     ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); | ||||||
|     if (src_archive == nullptr || dest_archive == nullptr) |     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); |     ArchiveBackend* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; | ||||||
|  | @ -468,8 +126,8 @@ ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy | ||||||
|     return archive->DeleteDirectory(path); |     return archive->DeleteDirectory(path); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle, | ResultCode ArchiveManager::DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle, | ||||||
|                                                  const FileSys::Path& path) { |                                                                  const FileSys::Path& path) { | ||||||
|     ArchiveBackend* archive = GetArchive(archive_handle); |     ArchiveBackend* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; | ||||||
|  | @ -477,8 +135,8 @@ ResultCode DeleteDirectoryRecursivelyFromArchive(ArchiveHandle archive_handle, | ||||||
|     return archive->DeleteDirectoryRecursively(path); |     return archive->DeleteDirectoryRecursively(path); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path& path, | ResultCode ArchiveManager::CreateFileInArchive(ArchiveHandle archive_handle, | ||||||
|                                u64 file_size) { |                                                const FileSys::Path& path, u64 file_size) { | ||||||
|     ArchiveBackend* archive = GetArchive(archive_handle); |     ArchiveBackend* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; | ||||||
|  | @ -486,7 +144,8 @@ ResultCode CreateFileInArchive(ArchiveHandle archive_handle, const FileSys::Path | ||||||
|     return archive->CreateFile(path, file_size); |     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); |     ArchiveBackend* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; | ||||||
|  | @ -494,10 +153,10 @@ ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSy | ||||||
|     return archive->CreateDirectory(path); |     return archive->CreateDirectory(path); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, | ResultCode ArchiveManager::RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, | ||||||
|                                           const FileSys::Path& src_path, |                                                           const FileSys::Path& src_path, | ||||||
|                                           ArchiveHandle dest_archive_handle, |                                                           ArchiveHandle dest_archive_handle, | ||||||
|                                           const FileSys::Path& dest_path) { |                                                           const FileSys::Path& dest_path) { | ||||||
|     ArchiveBackend* src_archive = GetArchive(src_archive_handle); |     ArchiveBackend* src_archive = GetArchive(src_archive_handle); | ||||||
|     ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); |     ArchiveBackend* dest_archive = GetArchive(dest_archive_handle); | ||||||
|     if (src_archive == nullptr || dest_archive == nullptr) |     if (src_archive == nullptr || dest_archive == nullptr) | ||||||
|  | @ -511,8 +170,8 @@ ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle archive_handle, | ResultVal<std::shared_ptr<Directory>> ArchiveManager::OpenDirectoryFromArchive( | ||||||
|                                                                const FileSys::Path& path) { |     ArchiveHandle archive_handle, const FileSys::Path& path) { | ||||||
|     ArchiveBackend* archive = GetArchive(archive_handle); |     ArchiveBackend* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; | ||||||
|  | @ -525,15 +184,16 @@ ResultVal<std::shared_ptr<Directory>> OpenDirectoryFromArchive(ArchiveHandle arc | ||||||
|     return MakeResult<std::shared_ptr<Directory>>(std::move(directory)); |     return MakeResult<std::shared_ptr<Directory>>(std::move(directory)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<u64> GetFreeBytesInArchive(ArchiveHandle archive_handle) { | ResultVal<u64> ArchiveManager::GetFreeBytesInArchive(ArchiveHandle archive_handle) { | ||||||
|     ArchiveBackend* archive = GetArchive(archive_handle); |     ArchiveBackend* archive = GetArchive(archive_handle); | ||||||
|     if (archive == nullptr) |     if (archive == nullptr) | ||||||
|         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; |         return FileSys::ERR_INVALID_ARCHIVE_HANDLE; | ||||||
|     return MakeResult<u64>(archive->GetFreeBytes()); |     return MakeResult<u64>(archive->GetFreeBytes()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::ArchiveFormatInfo& format_info, | ResultCode ArchiveManager::FormatArchive(ArchiveIdCode id_code, | ||||||
|                          const FileSys::Path& path) { |                                          const FileSys::ArchiveFormatInfo& format_info, | ||||||
|  |                                          const FileSys::Path& path) { | ||||||
|     auto archive_itr = id_code_map.find(id_code); |     auto archive_itr = id_code_map.find(id_code); | ||||||
|     if (archive_itr == id_code_map.end()) { |     if (archive_itr == id_code_map.end()) { | ||||||
|         return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
 |         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); |     return archive_itr->second->Format(path, format_info); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code, | ResultVal<FileSys::ArchiveFormatInfo> ArchiveManager::GetArchiveFormatInfo( | ||||||
|                                                            FileSys::Path& archive_path) { |     ArchiveIdCode id_code, FileSys::Path& archive_path) { | ||||||
|     auto archive = id_code_map.find(id_code); |     auto archive = id_code_map.find(id_code); | ||||||
|     if (archive == id_code_map.end()) { |     if (archive == id_code_map.end()) { | ||||||
|         return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
 |         return UnimplementedFunction(ErrorModule::FS); // TODO(Subv): Find the right error
 | ||||||
|  | @ -552,9 +212,9 @@ ResultVal<FileSys::ArchiveFormatInfo> GetArchiveFormatInfo(ArchiveIdCode id_code | ||||||
|     return archive->second->GetFormatInfo(archive_path); |     return archive->second->GetFormatInfo(archive_path); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, | ResultCode ArchiveManager::CreateExtSaveData(MediaType media_type, u32 high, u32 low, | ||||||
|                              const std::vector<u8>& smdh_icon, |                                              const std::vector<u8>& smdh_icon, | ||||||
|                              const FileSys::ArchiveFormatInfo& format_info) { |                                              const FileSys::ArchiveFormatInfo& format_info) { | ||||||
|     // Construct the binary path to the archive first
 |     // Construct the binary path to the archive first
 | ||||||
|     FileSys::Path path = |     FileSys::Path path = | ||||||
|         FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); |         FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); | ||||||
|  | @ -576,7 +236,7 @@ ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, | ||||||
|     return RESULT_SUCCESS; |     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
 |     // Construct the binary path to the archive first
 | ||||||
|     FileSys::Path path = |     FileSys::Path path = | ||||||
|         FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); |         FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); | ||||||
|  | @ -600,7 +260,7 @@ ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) { | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode DeleteSystemSaveData(u32 high, u32 low) { | ResultCode ArchiveManager::DeleteSystemSaveData(u32 high, u32 low) { | ||||||
|     // Construct the binary path to the archive first
 |     // Construct the binary path to the archive first
 | ||||||
|     FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low); |     FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low); | ||||||
| 
 | 
 | ||||||
|  | @ -612,7 +272,7 @@ ResultCode DeleteSystemSaveData(u32 high, u32 low) { | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultCode CreateSystemSaveData(u32 high, u32 low) { | ResultCode ArchiveManager::CreateSystemSaveData(u32 high, u32 low) { | ||||||
|     // Construct the binary path to the archive first
 |     // Construct the binary path to the archive first
 | ||||||
|     FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low); |     FileSys::Path path = FileSys::ConstructSystemSaveDataBinaryPath(high, low); | ||||||
| 
 | 
 | ||||||
|  | @ -624,7 +284,7 @@ ResultCode CreateSystemSaveData(u32 high, u32 low) { | ||||||
|     return RESULT_SUCCESS; |     return RESULT_SUCCESS; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void RegisterArchiveTypes() { | void ArchiveManager::RegisterArchiveTypes() { | ||||||
|     // TODO(Subv): Add the other archive types (see here for the known types:
 |     // TODO(Subv): Add the other archive types (see here for the known types:
 | ||||||
|     // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes).
 |     // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes).
 | ||||||
| 
 | 
 | ||||||
|  | @ -676,7 +336,7 @@ void RegisterArchiveTypes() { | ||||||
|     RegisterArchiveType(std::move(selfncch_factory), ArchiveIdCode::SelfNCCH); |     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); |     auto itr = id_code_map.find(ArchiveIdCode::SelfNCCH); | ||||||
|     if (itr == id_code_map.end()) { |     if (itr == id_code_map.end()) { | ||||||
|         LOG_ERROR(Service_FS, |         LOG_ERROR(Service_FS, | ||||||
|  | @ -688,20 +348,8 @@ void RegisterSelfNCCH(Loader::AppLoader& app_loader) { | ||||||
|     factory->Register(app_loader); |     factory->Register(app_loader); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void UnregisterArchiveTypes() { | ArchiveManager::ArchiveManager() { | ||||||
|     id_code_map.clear(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Initialize archives
 |  | ||||||
| void ArchiveInit() { |  | ||||||
|     next_handle = 1; |  | ||||||
|     RegisterArchiveTypes(); |     RegisterArchiveTypes(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// Shutdown archives
 |  | ||||||
| void ArchiveShutdown() { |  | ||||||
|     handle_map.clear(); |  | ||||||
|     UnregisterArchiveTypes(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| } // namespace Service::FS
 | } // namespace Service::FS
 | ||||||
|  |  | ||||||
|  | @ -6,18 +6,14 @@ | ||||||
| 
 | 
 | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <string> | #include <string> | ||||||
|  | #include <unordered_map> | ||||||
| #include <vector> | #include <vector> | ||||||
|  | #include <boost/container/flat_map.hpp> | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "core/file_sys/archive_backend.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/result.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/fs/directory.h" | ||||||
| 
 | #include "core/hle/service/fs/file.h" | ||||||
| namespace FileSys { |  | ||||||
| class DirectoryBackend; |  | ||||||
| class FileBackend; |  | ||||||
| } // namespace FileSys
 |  | ||||||
| 
 | 
 | ||||||
| /// The unique system identifier hash, also known as ID0
 | /// The unique system identifier hash, also known as ID0
 | ||||||
| static constexpr char SYSTEM_ID[]{"00000000000000000000000000000000"}; | static constexpr char SYSTEM_ID[]{"00000000000000000000000000000000"}; | ||||||
|  | @ -49,258 +45,209 @@ enum class MediaType : u32 { NAND = 0, SDMC = 1, GameCard = 2 }; | ||||||
| 
 | 
 | ||||||
| typedef u64 ArchiveHandle; | typedef u64 ArchiveHandle; | ||||||
| 
 | 
 | ||||||
| struct FileSessionSlot : public Kernel::SessionRequestHandler::SessionDataBase { | using FileSys::ArchiveBackend; | ||||||
|     u32 priority; ///< Priority of the file. TODO(Subv): Find out what this means
 | using FileSys::ArchiveFactory; | ||||||
|     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.
 | class ArchiveManager { | ||||||
| // Consider splitting ServiceFramework interface.
 |  | ||||||
| class File final : public ServiceFramework<File, FileSessionSlot> { |  | ||||||
| public: | public: | ||||||
|     File(std::unique_ptr<FileSys::FileBackend>&& backend, const FileSys::Path& path); |     ArchiveManager(); | ||||||
|     ~File() = default; |     /**
 | ||||||
|  |      * 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<ArchiveHandle> 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<FileSys::FileBackend> 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<std::shared_ptr<File>> 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<Kernel::ClientSession> 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.
 |      * Rename a File between two Archives | ||||||
|     std::size_t GetSessionFileOffset(Kernel::SharedPtr<Kernel::ServerSession> session); |      * @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.
 |      * Delete a Directory from an Archive | ||||||
|     std::size_t GetSessionFileSize(Kernel::SharedPtr<Kernel::ServerSession> session); |      * @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<std::shared_ptr<Directory>> 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<u64> 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<FileSys::ArchiveFormatInfo> 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<u8>& 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: | private: | ||||||
|     void Read(Kernel::HLERequestContext& ctx); |     /**
 | ||||||
|     void Write(Kernel::HLERequestContext& ctx); |      * Registers an Archive type, instances of which can later be opened using its IdCode. | ||||||
|     void GetSize(Kernel::HLERequestContext& ctx); |      * @param factory File system backend interface to the archive | ||||||
|     void SetSize(Kernel::HLERequestContext& ctx); |      * @param id_code Id code used to access this type of archive | ||||||
|     void Close(Kernel::HLERequestContext& ctx); |      */ | ||||||
|     void Flush(Kernel::HLERequestContext& ctx); |     ResultCode RegisterArchiveType(std::unique_ptr<FileSys::ArchiveFactory>&& factory, | ||||||
|     void SetPriority(Kernel::HLERequestContext& ctx); |                                    ArchiveIdCode id_code); | ||||||
|     void GetPriority(Kernel::HLERequestContext& ctx); | 
 | ||||||
|     void OpenLinkFile(Kernel::HLERequestContext& ctx); |     /// Register all archive types
 | ||||||
|     void OpenSubFile(Kernel::HLERequestContext& ctx); |     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<ArchiveIdCode, std::unique_ptr<ArchiveFactory>> id_code_map; | ||||||
|  | 
 | ||||||
|  |     /**
 | ||||||
|  |      * Map of active archive handles to archive objects | ||||||
|  |      */ | ||||||
|  |     std::unordered_map<ArchiveHandle, std::unique_ptr<ArchiveBackend>> handle_map; | ||||||
|  |     ArchiveHandle next_handle = 1; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| class Directory final : public ServiceFramework<Directory> { |  | ||||||
| public: |  | ||||||
|     Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path); |  | ||||||
|     ~Directory(); |  | ||||||
| 
 |  | ||||||
|     std::string GetName() const { |  | ||||||
|         return "Directory: " + path.DebugStr(); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     FileSys::Path path;                                 ///< Path of the directory
 |  | ||||||
|     std::unique_ptr<FileSys::DirectoryBackend> 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<ArchiveHandle> 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<FileSys::ArchiveFactory>&& 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<std::shared_ptr<File>> 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<std::shared_ptr<Directory>> 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<u64> 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<FileSys::ArchiveFormatInfo> 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<u8>& 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
 | } // namespace Service::FS
 | ||||||
|  |  | ||||||
							
								
								
									
										51
									
								
								src/core/hle/service/fs/directory.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/core/hle/service/fs/directory.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<FileSys::DirectoryBackend>&& 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<u32>(); | ||||||
|  |     auto& buffer = rp.PopMappedBuffer(); | ||||||
|  |     std::vector<FileSys::Entry> entries(count); | ||||||
|  |     LOG_TRACE(Service_FS, "Read {}: count={}", GetName(), count); | ||||||
|  |     // Number of entries actually read
 | ||||||
|  |     u32 read = backend->Read(static_cast<u32>(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
 | ||||||
							
								
								
									
										30
									
								
								src/core/hle/service/fs/directory.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								src/core/hle/service/fs/directory.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<Directory> { | ||||||
|  | public: | ||||||
|  |     Directory(std::unique_ptr<FileSys::DirectoryBackend>&& backend, const FileSys::Path& path); | ||||||
|  |     ~Directory(); | ||||||
|  | 
 | ||||||
|  |     std::string GetName() const { | ||||||
|  |         return "Directory: " + path.DebugStr(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     FileSys::Path path;                                 ///< Path of the directory
 | ||||||
|  |     std::unique_ptr<FileSys::DirectoryBackend> backend; ///< File backend interface
 | ||||||
|  | 
 | ||||||
|  | protected: | ||||||
|  |     void Read(Kernel::HLERequestContext& ctx); | ||||||
|  |     void Close(Kernel::HLERequestContext& ctx); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } // namespace Service::FS
 | ||||||
							
								
								
									
										286
									
								
								src/core/hle/service/fs/file.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										286
									
								
								src/core/hle/service/fs/file.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<FileSys::FileBackend>&& 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<u64>(); | ||||||
|  |     u32 length = rp.Pop<u32>(); | ||||||
|  |     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<u32>(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<u8> data(length); | ||||||
|  |     ResultVal<std::size_t> read = backend->Read(offset, data.size(), data.data()); | ||||||
|  |     if (read.Failed()) { | ||||||
|  |         rb.Push(read.Code()); | ||||||
|  |         rb.Push<u32>(0); | ||||||
|  |     } else { | ||||||
|  |         buffer.Write(data.data(), 0, *read); | ||||||
|  |         rb.Push(RESULT_SUCCESS); | ||||||
|  |         rb.Push<u32>(static_cast<u32>(*read)); | ||||||
|  |     } | ||||||
|  |     rb.PushMappedBuffer(buffer); | ||||||
|  | 
 | ||||||
|  |     std::chrono::nanoseconds read_timeout_ns{backend->GetReadDelayNs(length)}; | ||||||
|  |     ctx.SleepClientThread(Kernel::GetCurrentThread(), "file::read", read_timeout_ns, | ||||||
|  |                           [](Kernel::SharedPtr<Kernel::Thread> 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<u64>(); | ||||||
|  |     u32 length = rp.Pop<u32>(); | ||||||
|  |     u32 flush = rp.Pop<u32>(); | ||||||
|  |     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<u32>(0); | ||||||
|  |         rb.PushMappedBuffer(buffer); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     std::vector<u8> data(length); | ||||||
|  |     buffer.Read(data.data(), 0, data.size()); | ||||||
|  |     ResultVal<std::size_t> written = backend->Write(offset, data.size(), flush != 0, data.data()); | ||||||
|  |     if (written.Failed()) { | ||||||
|  |         rb.Push(written.Code()); | ||||||
|  |         rb.Push<u32>(0); | ||||||
|  |     } else { | ||||||
|  |         rb.Push(RESULT_SUCCESS); | ||||||
|  |         rb.Push<u32>(static_cast<u32>(*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<u64>(file->size); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void File::SetSize(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx, 0x0805, 2, 0); | ||||||
|  |     u64 size = rp.Pop<u64>(); | ||||||
|  | 
 | ||||||
|  |     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<u32>(); | ||||||
|  | 
 | ||||||
|  |     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<SharedPtr<ServerSession>>(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<SharedPtr<ClientSession>>(sessions)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void File::OpenSubFile(Kernel::HLERequestContext& ctx) { | ||||||
|  |     IPC::RequestParser rp(ctx, 0x0801, 4, 0); | ||||||
|  |     s64 offset = rp.PopRaw<s64>(); | ||||||
|  |     s64 size = rp.PopRaw<s64>(); | ||||||
|  | 
 | ||||||
|  |     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<SharedPtr<ServerSession>>(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<SharedPtr<ClientSession>>(sessions)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Kernel::SharedPtr<Kernel::ClientSession> File::Connect() { | ||||||
|  |     auto sessions = Kernel::ServerSession::CreateSessionPair(GetName()); | ||||||
|  |     auto server = std::get<Kernel::SharedPtr<Kernel::ServerSession>>(sessions); | ||||||
|  |     ClientConnected(server); | ||||||
|  | 
 | ||||||
|  |     FileSessionSlot* slot = GetSessionData(server); | ||||||
|  |     slot->priority = 0; | ||||||
|  |     slot->offset = 0; | ||||||
|  |     slot->size = backend->GetSize(); | ||||||
|  |     slot->subfile = false; | ||||||
|  | 
 | ||||||
|  |     return std::get<Kernel::SharedPtr<Kernel::ClientSession>>(sessions); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::size_t File::GetSessionFileOffset(Kernel::SharedPtr<Kernel::ServerSession> session) { | ||||||
|  |     const FileSessionSlot* slot = GetSessionData(session); | ||||||
|  |     ASSERT(slot); | ||||||
|  |     return slot->offset; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | std::size_t File::GetSessionFileSize(Kernel::SharedPtr<Kernel::ServerSession> session) { | ||||||
|  |     const FileSessionSlot* slot = GetSessionData(session); | ||||||
|  |     ASSERT(slot); | ||||||
|  |     return slot->size; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } // namespace Service::FS
 | ||||||
							
								
								
									
										58
									
								
								src/core/hle/service/fs/file.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/core/hle/service/fs/file.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -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<File, FileSessionSlot> { | ||||||
|  | public: | ||||||
|  |     File(std::unique_ptr<FileSys::FileBackend>&& 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<FileSys::FileBackend> backend; ///< File backend interface
 | ||||||
|  | 
 | ||||||
|  |     /// Creates a new session to this File and returns the ClientSession part of the connection.
 | ||||||
|  |     Kernel::SharedPtr<Kernel::ClientSession> Connect(); | ||||||
|  | 
 | ||||||
|  |     // Returns the start offset of an open file represented by the input session, opened with
 | ||||||
|  |     // OpenSubFile.
 | ||||||
|  |     std::size_t GetSessionFileOffset(Kernel::SharedPtr<Kernel::ServerSession> session); | ||||||
|  | 
 | ||||||
|  |     // Returns the size of an open file represented by the input session, opened with
 | ||||||
|  |     // OpenSubFile.
 | ||||||
|  |     std::size_t GetSessionFileSize(Kernel::SharedPtr<Kernel::ServerSession> 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
 | ||||||
|  | @ -57,7 +57,7 @@ void FS_USER::OpenFile(Kernel::HLERequestContext& ctx) { | ||||||
|     LOG_DEBUG(Service_FS, "path={}, mode={} attrs={}", file_path.DebugStr(), mode.hex, attributes); |     LOG_DEBUG(Service_FS, "path={}, mode={} attrs={}", file_path.DebugStr(), mode.hex, attributes); | ||||||
| 
 | 
 | ||||||
|     ResultVal<std::shared_ptr<File>> file_res = |     ResultVal<std::shared_ptr<File>> file_res = | ||||||
|         OpenFileFromArchive(archive_handle, file_path, mode); |         archives.OpenFileFromArchive(archive_handle, file_path, mode); | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||||||
|     rb.Push(file_res.Code()); |     rb.Push(file_res.Code()); | ||||||
|     if (file_res.Succeeded()) { |     if (file_res.Succeeded()) { | ||||||
|  | @ -93,7 +93,7 @@ void FS_USER::OpenFileDirectly(Kernel::HLERequestContext& ctx) { | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||||||
| 
 | 
 | ||||||
|     ResultVal<ArchiveHandle> archive_handle = Service::FS::OpenArchive(archive_id, archive_path); |     ResultVal<ArchiveHandle> archive_handle = archives.OpenArchive(archive_id, archive_path); | ||||||
|     if (archive_handle.Failed()) { |     if (archive_handle.Failed()) { | ||||||
|         LOG_ERROR(Service_FS, |         LOG_ERROR(Service_FS, | ||||||
|                   "Failed to get a handle for archive archive_id=0x{:08X} archive_path={}", |                   "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<Kernel::Object>(nullptr); |         rb.PushMoveObjects<Kernel::Object>(nullptr); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     SCOPE_EXIT({ Service::FS::CloseArchive(*archive_handle); }); |     SCOPE_EXIT({ archives.CloseArchive(*archive_handle); }); | ||||||
| 
 | 
 | ||||||
|     ResultVal<std::shared_ptr<File>> file_res = |     ResultVal<std::shared_ptr<File>> file_res = | ||||||
|         OpenFileFromArchive(*archive_handle, file_path, mode); |         archives.OpenFileFromArchive(*archive_handle, file_path, mode); | ||||||
|     rb.Push(file_res.Code()); |     rb.Push(file_res.Code()); | ||||||
|     if (file_res.Succeeded()) { |     if (file_res.Succeeded()) { | ||||||
|         std::shared_ptr<File> file = *file_res; |         std::shared_ptr<File> file = *file_res; | ||||||
|  | @ -132,7 +132,7 @@ void FS_USER::DeleteFile(Kernel::HLERequestContext& ctx) { | ||||||
|               file_path.DebugStr()); |               file_path.DebugStr()); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     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) { | void FS_USER::RenameFile(Kernel::HLERequestContext& ctx) { | ||||||
|  | @ -159,8 +159,8 @@ void FS_USER::RenameFile(Kernel::HLERequestContext& ctx) { | ||||||
|               static_cast<u32>(dest_filename_type), dest_filename_size, dest_file_path.DebugStr()); |               static_cast<u32>(dest_filename_type), dest_filename_size, dest_file_path.DebugStr()); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|     rb.Push(RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle, |     rb.Push(archives.RenameFileBetweenArchives(src_archive_handle, src_file_path, | ||||||
|                                       dest_file_path)); |                                                dest_archive_handle, dest_file_path)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void FS_USER::DeleteDirectory(Kernel::HLERequestContext& ctx) { | void FS_USER::DeleteDirectory(Kernel::HLERequestContext& ctx) { | ||||||
|  | @ -179,7 +179,7 @@ void FS_USER::DeleteDirectory(Kernel::HLERequestContext& ctx) { | ||||||
|               dir_path.DebugStr()); |               dir_path.DebugStr()); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     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) { | void FS_USER::DeleteDirectoryRecursively(Kernel::HLERequestContext& ctx) { | ||||||
|  | @ -198,7 +198,7 @@ void FS_USER::DeleteDirectoryRecursively(Kernel::HLERequestContext& ctx) { | ||||||
|               dir_path.DebugStr()); |               dir_path.DebugStr()); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     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) { | void FS_USER::CreateFile(Kernel::HLERequestContext& ctx) { | ||||||
|  | @ -219,7 +219,7 @@ void FS_USER::CreateFile(Kernel::HLERequestContext& ctx) { | ||||||
|               static_cast<u32>(filename_type), attributes, file_size, file_path.DebugStr()); |               static_cast<u32>(filename_type), attributes, file_size, file_path.DebugStr()); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     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) { | void FS_USER::CreateDirectory(Kernel::HLERequestContext& ctx) { | ||||||
|  | @ -237,7 +237,7 @@ void FS_USER::CreateDirectory(Kernel::HLERequestContext& ctx) { | ||||||
|               dir_path.DebugStr()); |               dir_path.DebugStr()); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     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) { | void FS_USER::RenameDirectory(Kernel::HLERequestContext& ctx) { | ||||||
|  | @ -263,8 +263,8 @@ void FS_USER::RenameDirectory(Kernel::HLERequestContext& ctx) { | ||||||
|               static_cast<u32>(dest_dirname_type), dest_dirname_size, dest_dir_path.DebugStr()); |               static_cast<u32>(dest_dirname_type), dest_dirname_size, dest_dir_path.DebugStr()); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|     rb.Push(RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, |     rb.Push(archives.RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, | ||||||
|                                            dest_dir_path)); |                                                     dest_archive_handle, dest_dir_path)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void FS_USER::OpenDirectory(Kernel::HLERequestContext& ctx) { | 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); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); | ||||||
|     ResultVal<std::shared_ptr<Directory>> dir_res = |     ResultVal<std::shared_ptr<Directory>> dir_res = | ||||||
|         OpenDirectoryFromArchive(archive_handle, dir_path); |         archives.OpenDirectoryFromArchive(archive_handle, dir_path); | ||||||
|     rb.Push(dir_res.Code()); |     rb.Push(dir_res.Code()); | ||||||
|     if (dir_res.Succeeded()) { |     if (dir_res.Succeeded()) { | ||||||
|         std::shared_ptr<Directory> directory = *dir_res; |         std::shared_ptr<Directory> directory = *dir_res; | ||||||
|  | @ -309,7 +309,7 @@ void FS_USER::OpenArchive(Kernel::HLERequestContext& ctx) { | ||||||
|               archive_path.DebugStr()); |               archive_path.DebugStr()); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); | ||||||
|     ResultVal<ArchiveHandle> handle = Service::FS::OpenArchive(archive_id, archive_path); |     ResultVal<ArchiveHandle> handle = archives.OpenArchive(archive_id, archive_path); | ||||||
|     rb.Push(handle.Code()); |     rb.Push(handle.Code()); | ||||||
|     if (handle.Succeeded()) { |     if (handle.Succeeded()) { | ||||||
|         rb.PushRaw(*handle); |         rb.PushRaw(*handle); | ||||||
|  | @ -326,7 +326,7 @@ void FS_USER::CloseArchive(Kernel::HLERequestContext& ctx) { | ||||||
|     auto archive_handle = rp.PopRaw<ArchiveHandle>(); |     auto archive_handle = rp.PopRaw<ArchiveHandle>(); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     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) { | 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.number_files = number_files; | ||||||
|     format_info.total_size = block_size * 512; |     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) { | 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; |     format_info.total_size = block_size * 512; | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     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"); |     LOG_TRACE(Service_FS, "called"); | ||||||
| } | } | ||||||
|  | @ -412,7 +412,7 @@ void FS_USER::FormatThisUserSaveData(Kernel::HLERequestContext& ctx) { | ||||||
| void FS_USER::GetFreeBytes(Kernel::HLERequestContext& ctx) { | void FS_USER::GetFreeBytes(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx, 0x812, 2, 0); |     IPC::RequestParser rp(ctx, 0x812, 2, 0); | ||||||
|     ArchiveHandle archive_handle = rp.PopRaw<ArchiveHandle>(); |     ArchiveHandle archive_handle = rp.PopRaw<ArchiveHandle>(); | ||||||
|     ResultVal<u64> bytes_res = GetFreeBytesInArchive(archive_handle); |     ResultVal<u64> bytes_res = archives.GetFreeBytesInArchive(archive_handle); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); |     IPC::RequestBuilder rb = rp.MakeBuilder(3, 0); | ||||||
|     rb.Push(bytes_res.Code()); |     rb.Push(bytes_res.Code()); | ||||||
|  | @ -446,7 +446,7 @@ void FS_USER::CreateExtSaveData(Kernel::HLERequestContext& ctx) { | ||||||
|     format_info.total_size = 0; |     format_info.total_size = 0; | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); |     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); |     rb.PushMappedBuffer(icon_buffer); | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_FS, |     LOG_DEBUG(Service_FS, | ||||||
|  | @ -463,7 +463,7 @@ void FS_USER::DeleteExtSaveData(Kernel::HLERequestContext& ctx) { | ||||||
|     u32 unknown = rp.Pop<u32>(); // TODO(Subv): Figure out what this is
 |     u32 unknown = rp.Pop<u32>(); // TODO(Subv): Figure out what this is
 | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     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, |     LOG_DEBUG(Service_FS, | ||||||
|               "called, save_low={:08X} save_high={:08X} media_type={:08X} unknown={:08X}", save_low, |               "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<u32>(); |     u32 savedata_low = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     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) { | void FS_USER::CreateSystemSaveData(Kernel::HLERequestContext& ctx) { | ||||||
|  | @ -507,7 +507,7 @@ void FS_USER::CreateSystemSaveData(Kernel::HLERequestContext& ctx) { | ||||||
|         file_buckets, duplicate); |         file_buckets, duplicate); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     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) { | 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); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|     // With this command, the SystemSaveData always has save_high = 0 (Always created in the NAND)
 |     // 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) { | 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); |     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()); |     rb.Push(format_info.Code()); | ||||||
|     if (format_info.Failed()) { |     if (format_info.Failed()) { | ||||||
|         LOG_ERROR(Service_FS, "Failed to retrieve the format info"); |         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; |     format_info.total_size = 0; | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 2); |     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); |     rb.PushMappedBuffer(icon_buffer); | ||||||
| 
 | 
 | ||||||
|     LOG_DEBUG(Service_FS, |     LOG_DEBUG(Service_FS, | ||||||
|  | @ -679,7 +679,7 @@ void FS_USER::ObsoletedDeleteExtSaveData(Kernel::HLERequestContext& ctx) { | ||||||
|     u32 save_low = rp.Pop<u32>(); |     u32 save_low = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); |     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, |     LOG_DEBUG(Service_FS, "called, save_low={:08X} media_type={:08X}", save_low, | ||||||
|               static_cast<u32>(media_type)); |               static_cast<u32>(media_type)); | ||||||
|  | @ -741,7 +741,7 @@ void FS_USER::GetSaveDataSecureValue(Kernel::HLERequestContext& ctx) { | ||||||
|     rb.Push<u64>(0);      // the secure value
 |     rb.Push<u64>(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[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {0x000100C6, nullptr, "Dummy1"}, |         {0x000100C6, nullptr, "Dummy1"}, | ||||||
|         {0x040100C4, nullptr, "Control"}, |         {0x040100C4, nullptr, "Control"}, | ||||||
|  | @ -860,6 +860,6 @@ FS_USER::FS_USER() : ServiceFramework("fs:USER", 30) { | ||||||
| 
 | 
 | ||||||
| void InstallInterfaces(Core::System& system) { | void InstallInterfaces(Core::System& system) { | ||||||
|     auto& service_manager = system.ServiceManager(); |     auto& service_manager = system.ServiceManager(); | ||||||
|     std::make_shared<FS_USER>()->InstallAsService(service_manager); |     std::make_shared<FS_USER>(system.ArchiveManager())->InstallAsService(service_manager); | ||||||
| } | } | ||||||
| } // namespace Service::FS
 | } // namespace Service::FS
 | ||||||
|  |  | ||||||
|  | @ -13,9 +13,11 @@ class System; | ||||||
| 
 | 
 | ||||||
| namespace Service::FS { | namespace Service::FS { | ||||||
| 
 | 
 | ||||||
|  | class ArchiveManager; | ||||||
|  | 
 | ||||||
| class FS_USER final : public ServiceFramework<FS_USER> { | class FS_USER final : public ServiceFramework<FS_USER> { | ||||||
| public: | public: | ||||||
|     FS_USER(); |     explicit FS_USER(ArchiveManager& archives); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     void Initialize(Kernel::HLERequestContext& ctx); |     void Initialize(Kernel::HLERequestContext& ctx); | ||||||
|  | @ -531,6 +533,8 @@ private: | ||||||
|     void GetSaveDataSecureValue(Kernel::HLERequestContext& ctx); |     void GetSaveDataSecureValue(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|     u32 priority = -1; ///< For SetPriority and GetPriority service functions
 |     u32 priority = -1; ///< For SetPriority and GetPriority service functions
 | ||||||
|  | 
 | ||||||
|  |     ArchiveManager& archives; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void InstallInterfaces(Core::System& system); | void InstallInterfaces(Core::System& system); | ||||||
|  |  | ||||||
|  | @ -236,7 +236,6 @@ static bool AttemptLLE(const ServiceModuleInfo& service_module) { | ||||||
| 
 | 
 | ||||||
| /// Initialize ServiceManager
 | /// Initialize ServiceManager
 | ||||||
| void Init(Core::System& core, std::shared_ptr<SM::ServiceManager>& sm) { | void Init(Core::System& core, std::shared_ptr<SM::ServiceManager>& sm) { | ||||||
|     FS::ArchiveInit(); |  | ||||||
|     SM::ServiceManager::InstallInterfaces(sm); |     SM::ServiceManager::InstallInterfaces(sm); | ||||||
| 
 | 
 | ||||||
|     for (const auto& service_module : service_module_map) { |     for (const auto& service_module : service_module_map) { | ||||||
|  | @ -248,7 +247,6 @@ void Init(Core::System& core, std::shared_ptr<SM::ServiceManager>& sm) { | ||||||
| 
 | 
 | ||||||
| /// Shutdown ServiceManager
 | /// Shutdown ServiceManager
 | ||||||
| void Shutdown() { | void Shutdown() { | ||||||
|     FS::ArchiveShutdown(); |  | ||||||
| 
 | 
 | ||||||
|     g_kernel_named_ports.clear(); |     g_kernel_named_ports.clear(); | ||||||
|     LOG_DEBUG(Service, "shutdown OK"); |     LOG_DEBUG(Service, "shutdown OK"); | ||||||
|  |  | ||||||
|  | @ -5,7 +5,7 @@ | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include "common/logging/log.h" | #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/process.h" | ||||||
| #include "core/hle/kernel/resource_limit.h" | #include "core/hle/kernel/resource_limit.h" | ||||||
| #include "core/hle/service/fs/archive.h" | #include "core/hle/service/fs/archive.h" | ||||||
|  | @ -277,7 +277,7 @@ ResultStatus AppLoader_THREEDSX::Load(Kernel::SharedPtr<Kernel::Process>& proces | ||||||
| 
 | 
 | ||||||
|     process->Run(48, Kernel::DEFAULT_STACK_SIZE); |     process->Run(48, Kernel::DEFAULT_STACK_SIZE); | ||||||
| 
 | 
 | ||||||
|     Service::FS::RegisterSelfNCCH(*this); |     Core::System::GetInstance().ArchiveManager().RegisterSelfNCCH(*this); | ||||||
| 
 | 
 | ||||||
|     is_loaded = true; |     is_loaded = true; | ||||||
|     return ResultStatus::Success; |     return ResultStatus::Success; | ||||||
|  |  | ||||||
|  | @ -14,7 +14,6 @@ | ||||||
| #include "common/string_util.h" | #include "common/string_util.h" | ||||||
| #include "common/swap.h" | #include "common/swap.h" | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/file_sys/archive_selfncch.h" |  | ||||||
| #include "core/file_sys/ncch_container.h" | #include "core/file_sys/ncch_container.h" | ||||||
| #include "core/file_sys/title_metadata.h" | #include "core/file_sys/title_metadata.h" | ||||||
| #include "core/hle/kernel/process.h" | #include "core/hle/kernel/process.h" | ||||||
|  | @ -185,7 +184,7 @@ ResultStatus AppLoader_NCCH::Load(Kernel::SharedPtr<Kernel::Process>& process) { | ||||||
|     if (ResultStatus::Success != result) |     if (ResultStatus::Success != result) | ||||||
|         return result; |         return result; | ||||||
| 
 | 
 | ||||||
|     Service::FS::RegisterSelfNCCH(*this); |     Core::System::GetInstance().ArchiveManager().RegisterSelfNCCH(*this); | ||||||
| 
 | 
 | ||||||
|     ParseRegionLockoutInfo(); |     ParseRegionLockoutInfo(); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue