From c72ccfa6db41039ef2eb0ce118fabe1b38da841e Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 14 Dec 2014 04:32:45 -0200 Subject: HLE: Move kernel/archive.* to service/fs/ --- src/core/CMakeLists.txt | 8 +- src/core/hle/kernel/archive.cpp | 426 -------------------------------- src/core/hle/kernel/archive.h | 107 -------- src/core/hle/kernel/kernel.cpp | 2 +- src/core/hle/service/fs/archive.cpp | 426 ++++++++++++++++++++++++++++++++ src/core/hle/service/fs/archive.h | 107 ++++++++ src/core/hle/service/fs/fs_user.cpp | 474 +++++++++++++++++++++++++++++++++++ src/core/hle/service/fs/fs_user.h | 31 +++ src/core/hle/service/fs_user.cpp | 475 ------------------------------------ src/core/hle/service/fs_user.h | 31 --- src/core/hle/service/service.cpp | 2 +- src/core/loader/3dsx.cpp | 2 +- src/core/loader/loader.cpp | 2 +- 13 files changed, 1046 insertions(+), 1047 deletions(-) delete mode 100644 src/core/hle/kernel/archive.cpp delete mode 100644 src/core/hle/kernel/archive.h create mode 100644 src/core/hle/service/fs/archive.cpp create mode 100644 src/core/hle/service/fs/archive.h create mode 100644 src/core/hle/service/fs/fs_user.cpp create mode 100644 src/core/hle/service/fs/fs_user.h delete mode 100644 src/core/hle/service/fs_user.cpp delete mode 100644 src/core/hle/service/fs_user.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ab63f54d..18a41747 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -24,7 +24,6 @@ set(SRCS file_sys/directory_romfs.cpp file_sys/directory_sdmc.cpp hle/kernel/address_arbiter.cpp - hle/kernel/archive.cpp hle/kernel/event.cpp hle/kernel/kernel.cpp hle/kernel/mutex.cpp @@ -40,7 +39,8 @@ set(SRCS hle/service/csnd_snd.cpp hle/service/dsp_dsp.cpp hle/service/err_f.cpp - hle/service/fs_user.cpp + hle/service/fs/archive.cpp + hle/service/fs/fs_user.cpp hle/service/frd_u.cpp hle/service/gsp_gpu.cpp hle/service/hid_user.cpp @@ -103,7 +103,6 @@ set(HEADERS file_sys/directory_romfs.h file_sys/directory_sdmc.h hle/kernel/address_arbiter.h - hle/kernel/archive.h hle/kernel/event.h hle/kernel/kernel.h hle/kernel/mutex.h @@ -120,7 +119,8 @@ set(HEADERS hle/service/csnd_snd.h hle/service/dsp_dsp.h hle/service/err_f.h - hle/service/fs_user.h + hle/service/fs/archive.h + hle/service/fs/fs_user.h hle/service/frd_u.h hle/service/gsp_gpu.h hle/service/hid_user.h diff --git a/src/core/hle/kernel/archive.cpp b/src/core/hle/kernel/archive.cpp deleted file mode 100644 index 0e3eb456..00000000 --- a/src/core/hle/kernel/archive.cpp +++ /dev/null @@ -1,426 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include - -#include "common/common_types.h" -#include "common/file_util.h" -#include "common/math_util.h" - -#include "core/file_sys/archive.h" -#include "core/file_sys/archive_sdmc.h" -#include "core/file_sys/directory.h" -#include "core/hle/kernel/archive.h" -#include "core/hle/kernel/session.h" -#include "core/hle/result.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Kernel namespace - -namespace Kernel { - -// Command to access archive file -enum class FileCommand : u32 { - Dummy1 = 0x000100C6, - Control = 0x040100C4, - OpenSubFile = 0x08010100, - Read = 0x080200C2, - Write = 0x08030102, - GetSize = 0x08040000, - SetSize = 0x08050080, - GetAttributes = 0x08060000, - SetAttributes = 0x08070040, - Close = 0x08080000, - Flush = 0x08090000, -}; - -// Command to access directory -enum class DirectoryCommand : u32 { - Dummy1 = 0x000100C6, - Control = 0x040100C4, - Read = 0x08010042, - Close = 0x08020000, -}; - -class Archive : public Kernel::Session { -public: - std::string GetName() const override { return "Archive: " + name; } - - std::string name; ///< Name of archive (optional) - FileSys::Archive* backend; ///< Archive backend interface - - ResultVal SyncRequest() override { - u32* cmd_buff = Kernel::GetCommandBuffer(); - FileCommand cmd = static_cast(cmd_buff[0]); - - switch (cmd) { - // Read from archive... - case FileCommand::Read: - { - u64 offset = cmd_buff[1] | ((u64)cmd_buff[2] << 32); - u32 length = cmd_buff[3]; - u32 address = cmd_buff[5]; - - // Number of bytes read - cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); - break; - } - // Write to archive... - case FileCommand::Write: - { - u64 offset = cmd_buff[1] | ((u64)cmd_buff[2] << 32); - u32 length = cmd_buff[3]; - u32 flush = cmd_buff[4]; - u32 address = cmd_buff[6]; - - // Number of bytes written - cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); - break; - } - case FileCommand::GetSize: - { - u64 filesize = (u64) backend->GetSize(); - cmd_buff[2] = (u32) filesize; // Lower word - cmd_buff[3] = (u32) (filesize >> 32); // Upper word - break; - } - case FileCommand::SetSize: - { - backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32)); - break; - } - case FileCommand::Close: - { - LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); - CloseArchive(backend->GetIdCode()); - break; - } - // Unknown command... - default: - { - LOG_ERROR(Service_FS, "Unknown command=0x%08X", cmd); - cmd_buff[0] = UnimplementedFunction(ErrorModule::FS).raw; - return MakeResult(false); - } - } - cmd_buff[1] = 0; // No error - return MakeResult(false); - } -}; - -class File : public Kernel::Session { -public: - std::string GetName() const override { return "Path: " + path.DebugStr(); } - - FileSys::Path path; ///< Path of the file - std::unique_ptr backend; ///< File backend interface - - ResultVal SyncRequest() override { - u32* cmd_buff = Kernel::GetCommandBuffer(); - FileCommand cmd = static_cast(cmd_buff[0]); - switch (cmd) { - - // Read from file... - case FileCommand::Read: - { - u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; - u32 length = cmd_buff[3]; - u32 address = cmd_buff[5]; - LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x", - GetTypeName().c_str(), GetName().c_str(), offset, length, address); - cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); - break; - } - - // Write to file... - case FileCommand::Write: - { - u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; - u32 length = cmd_buff[3]; - u32 flush = cmd_buff[4]; - u32 address = cmd_buff[6]; - LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", - GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); - cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); - break; - } - - case FileCommand::GetSize: - { - LOG_TRACE(Service_FS, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str()); - u64 size = backend->GetSize(); - cmd_buff[2] = (u32)size; - cmd_buff[3] = size >> 32; - break; - } - - case FileCommand::SetSize: - { - u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); - LOG_TRACE(Service_FS, "SetSize %s %s size=%llu", - GetTypeName().c_str(), GetName().c_str(), size); - backend->SetSize(size); - break; - } - - case FileCommand::Close: - { - LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); - Kernel::g_object_pool.Destroy(GetHandle()); - break; - } - - // Unknown command... - default: - LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); - ResultCode error = UnimplementedFunction(ErrorModule::FS); - cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. - return error; - } - cmd_buff[1] = 0; // No error - return MakeResult(false); - } -}; - -class Directory : public Kernel::Session { -public: - std::string GetName() const override { return "Directory: " + path.DebugStr(); } - - FileSys::Path path; ///< Path of the directory - std::unique_ptr backend; ///< File backend interface - - ResultVal SyncRequest() override { - u32* cmd_buff = Kernel::GetCommandBuffer(); - DirectoryCommand cmd = static_cast(cmd_buff[0]); - switch (cmd) { - - // Read from directory... - case DirectoryCommand::Read: - { - u32 count = cmd_buff[1]; - u32 address = cmd_buff[3]; - auto entries = reinterpret_cast(Memory::GetPointer(address)); - LOG_TRACE(Service_FS, "Read %s %s: count=%d", - GetTypeName().c_str(), GetName().c_str(), count); - - // Number of entries actually read - cmd_buff[2] = backend->Read(count, entries); - break; - } - - case DirectoryCommand::Close: - { - LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); - Kernel::g_object_pool.Destroy(GetHandle()); - break; - } - - // Unknown command... - default: - LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); - ResultCode error = UnimplementedFunction(ErrorModule::FS); - cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. - return MakeResult(false); - } - cmd_buff[1] = 0; // No error - return MakeResult(false); - } -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -std::map g_archive_map; ///< Map of file archives by IdCode - -ResultVal OpenArchive(FileSys::Archive::IdCode id_code) { - auto itr = g_archive_map.find(id_code); - if (itr == g_archive_map.end()) { - return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, - ErrorSummary::NotFound, ErrorLevel::Permanent); - } - - return MakeResult(itr->second); -} - -ResultCode CloseArchive(FileSys::Archive::IdCode id_code) { - auto itr = g_archive_map.find(id_code); - if (itr == g_archive_map.end()) { - LOG_ERROR(Service_FS, "Cannot close archive %d, does not exist!", (int)id_code); - return InvalidHandle(ErrorModule::FS); - } - - LOG_TRACE(Service_FS, "Closed archive %d", (int) id_code); - return RESULT_SUCCESS; -} - -/** - * Mounts an archive - * @param archive Pointer to the archive to mount - */ -ResultCode MountArchive(Archive* archive) { - FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); - ResultVal archive_handle = OpenArchive(id_code); - if (archive_handle.Succeeded()) { - LOG_ERROR(Service_FS, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); - return archive_handle.Code(); - } - g_archive_map[id_code] = archive->GetHandle(); - LOG_TRACE(Service_FS, "Mounted archive %s", archive->GetName().c_str()); - return RESULT_SUCCESS; -} - -ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) { - Archive* archive = new Archive; - Handle handle = Kernel::g_object_pool.Create(archive); - archive->name = name; - archive->backend = backend; - - ResultCode result = MountArchive(archive); - if (result.IsError()) { - return result; - } - - return RESULT_SUCCESS; -} - -ResultVal OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { - // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create - // the archive file handles at app loading, and then keep them persistent throughout execution. - // Archives file handles are just reused and not actually freed until emulation shut down. - // Verify if real hardware works this way, or if new handles are created each time - if (path.GetType() == FileSys::Binary) - // TODO(bunnei): FixMe - this is a hack to compensate for an incorrect FileSys backend - // design. While the functionally of this is OK, our implementation decision to separate - // normal files from archive file pointers is very likely wrong. - // See https://github.com/citra-emu/citra/issues/205 - return MakeResult(archive_handle); - - File* file = new File; - Handle handle = Kernel::g_object_pool.Create(file); - - Archive* archive = Kernel::g_object_pool.Get(archive_handle); - if (archive == nullptr) { - return InvalidHandle(ErrorModule::FS); - } - file->path = path; - file->backend = archive->backend->OpenFile(path, mode); - - if (!file->backend) { - return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, - ErrorSummary::NotFound, ErrorLevel::Permanent); - } - - return MakeResult(handle); -} - -ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) { - Archive* archive = Kernel::g_object_pool.GetFast(archive_handle); - if (archive == nullptr) - return InvalidHandle(ErrorModule::FS); - if (archive->backend->DeleteFile(path)) - return RESULT_SUCCESS; - return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description - ErrorSummary::Canceled, ErrorLevel::Status); -} - -ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, - Handle dest_archive_handle, const FileSys::Path& dest_path) { - Archive* src_archive = Kernel::g_object_pool.GetFast(src_archive_handle); - Archive* dest_archive = Kernel::g_object_pool.GetFast(dest_archive_handle); - if (src_archive == nullptr || dest_archive == nullptr) - return InvalidHandle(ErrorModule::FS); - if (src_archive == dest_archive) { - if (src_archive->backend->RenameFile(src_path, dest_path)) - return RESULT_SUCCESS; - } else { - // TODO: Implement renaming across archives - return UnimplementedFunction(ErrorModule::FS); - } - return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description - ErrorSummary::NothingHappened, ErrorLevel::Status); -} - -ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { - Archive* archive = Kernel::g_object_pool.GetFast(archive_handle); - if (archive == nullptr) - return InvalidHandle(ErrorModule::FS); - if (archive->backend->DeleteDirectory(path)) - return RESULT_SUCCESS; - return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description - ErrorSummary::Canceled, ErrorLevel::Status); -} - -ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { - Archive* archive = Kernel::g_object_pool.GetFast(archive_handle); - if (archive == nullptr) - return InvalidHandle(ErrorModule::FS); - if (archive->backend->CreateDirectory(path)) - return RESULT_SUCCESS; - return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description - ErrorSummary::Canceled, ErrorLevel::Status); -} - -ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, - Handle dest_archive_handle, const FileSys::Path& dest_path) { - Archive* src_archive = Kernel::g_object_pool.GetFast(src_archive_handle); - Archive* dest_archive = Kernel::g_object_pool.GetFast(dest_archive_handle); - if (src_archive == nullptr || dest_archive == nullptr) - return InvalidHandle(ErrorModule::FS); - if (src_archive == dest_archive) { - if (src_archive->backend->RenameDirectory(src_path, dest_path)) - return RESULT_SUCCESS; - } else { - // TODO: Implement renaming across archives - return UnimplementedFunction(ErrorModule::FS); - } - return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description - ErrorSummary::NothingHappened, ErrorLevel::Status); -} - -/** - * 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 Opened Directory object - */ -ResultVal OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { - Directory* directory = new Directory; - Handle handle = Kernel::g_object_pool.Create(directory); - - Archive* archive = Kernel::g_object_pool.Get(archive_handle); - if (archive == nullptr) { - return InvalidHandle(ErrorModule::FS); - } - directory->path = path; - directory->backend = archive->backend->OpenDirectory(path); - - if (!directory->backend) { - return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, - ErrorSummary::NotFound, ErrorLevel::Permanent); - } - - return MakeResult(handle); -} - -/// Initialize archives -void ArchiveInit() { - g_archive_map.clear(); - - // TODO(Link Mauve): Add the other archive types (see here for the known types: - // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished - // archive type is SDMC, so it is the only one getting exposed. - - std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); - auto archive = new FileSys::Archive_SDMC(sdmc_directory); - if (archive->Initialize()) - CreateArchive(archive, "SDMC"); - else - LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); -} - -/// Shutdown archives -void ArchiveShutdown() { - g_archive_map.clear(); -} - -} // namespace Kernel diff --git a/src/core/hle/kernel/archive.h b/src/core/hle/kernel/archive.h deleted file mode 100644 index b50833a2..00000000 --- a/src/core/hle/kernel/archive.h +++ /dev/null @@ -1,107 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_types.h" - -#include "core/file_sys/archive.h" -#include "core/hle/kernel/kernel.h" -#include "core/hle/result.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Kernel namespace - -namespace Kernel { - -/** - * Opens an archive - * @param id_code IdCode of the archive to open - * @return Handle to the opened archive - */ -ResultVal OpenArchive(FileSys::Archive::IdCode id_code); - -/** - * Closes an archive - * @param id_code IdCode of the archive to open - */ -ResultCode CloseArchive(FileSys::Archive::IdCode id_code); - -/** - * Creates an Archive - * @param backend File system backend interface to the archive - * @param name Name of Archive - */ -ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name); - -/** - * 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 Handle to the opened File object - */ -ResultVal OpenFileFromArchive(Handle 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(Handle 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(Handle src_archive_handle, const FileSys::Path& src_path, - Handle 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(Handle archive_handle, const FileSys::Path& path); - -/** - * Create a Directory from an Archive - * @param archive_handle Handle to an open Archive object - * @param path Path to the Directory inside of the Archive - * @return Whether creation of directory succeeded - */ -ResultCode CreateDirectoryFromArchive(Handle 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(Handle src_archive_handle, const FileSys::Path& src_path, - Handle 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 Handle to the opened File object - */ -ResultVal OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); - -/// Initialize archives -void ArchiveInit(); - -/// Shutdown archives -void ArchiveShutdown(); - -} // namespace FileSys diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b38be0a4..95b4dfd6 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -9,7 +9,7 @@ #include "core/core.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" -#include "core/hle/kernel/archive.h" +#include "core/hle/service/fs/archive.h" namespace Kernel { diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp new file mode 100644 index 00000000..8889c633 --- /dev/null +++ b/src/core/hle/service/fs/archive.cpp @@ -0,0 +1,426 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include + +#include "common/common_types.h" +#include "common/file_util.h" +#include "common/math_util.h" + +#include "core/file_sys/archive.h" +#include "core/file_sys/archive_sdmc.h" +#include "core/file_sys/directory.h" +#include "core/hle/service/fs/archive.h" +#include "core/hle/kernel/session.h" +#include "core/hle/result.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Kernel namespace + +namespace Kernel { + +// Command to access archive file +enum class FileCommand : u32 { + Dummy1 = 0x000100C6, + Control = 0x040100C4, + OpenSubFile = 0x08010100, + Read = 0x080200C2, + Write = 0x08030102, + GetSize = 0x08040000, + SetSize = 0x08050080, + GetAttributes = 0x08060000, + SetAttributes = 0x08070040, + Close = 0x08080000, + Flush = 0x08090000, +}; + +// Command to access directory +enum class DirectoryCommand : u32 { + Dummy1 = 0x000100C6, + Control = 0x040100C4, + Read = 0x08010042, + Close = 0x08020000, +}; + +class Archive : public Kernel::Session { +public: + std::string GetName() const override { return "Archive: " + name; } + + std::string name; ///< Name of archive (optional) + FileSys::Archive* backend; ///< Archive backend interface + + ResultVal SyncRequest() override { + u32* cmd_buff = Kernel::GetCommandBuffer(); + FileCommand cmd = static_cast(cmd_buff[0]); + + switch (cmd) { + // Read from archive... + case FileCommand::Read: + { + u64 offset = cmd_buff[1] | ((u64)cmd_buff[2] << 32); + u32 length = cmd_buff[3]; + u32 address = cmd_buff[5]; + + // Number of bytes read + cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); + break; + } + // Write to archive... + case FileCommand::Write: + { + u64 offset = cmd_buff[1] | ((u64)cmd_buff[2] << 32); + u32 length = cmd_buff[3]; + u32 flush = cmd_buff[4]; + u32 address = cmd_buff[6]; + + // Number of bytes written + cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); + break; + } + case FileCommand::GetSize: + { + u64 filesize = (u64) backend->GetSize(); + cmd_buff[2] = (u32) filesize; // Lower word + cmd_buff[3] = (u32) (filesize >> 32); // Upper word + break; + } + case FileCommand::SetSize: + { + backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32)); + break; + } + case FileCommand::Close: + { + LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); + CloseArchive(backend->GetIdCode()); + break; + } + // Unknown command... + default: + { + LOG_ERROR(Service_FS, "Unknown command=0x%08X", cmd); + cmd_buff[0] = UnimplementedFunction(ErrorModule::FS).raw; + return MakeResult(false); + } + } + cmd_buff[1] = 0; // No error + return MakeResult(false); + } +}; + +class File : public Kernel::Session { +public: + std::string GetName() const override { return "Path: " + path.DebugStr(); } + + FileSys::Path path; ///< Path of the file + std::unique_ptr backend; ///< File backend interface + + ResultVal SyncRequest() override { + u32* cmd_buff = Kernel::GetCommandBuffer(); + FileCommand cmd = static_cast(cmd_buff[0]); + switch (cmd) { + + // Read from file... + case FileCommand::Read: + { + u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; + u32 length = cmd_buff[3]; + u32 address = cmd_buff[5]; + LOG_TRACE(Service_FS, "Read %s %s: offset=0x%llx length=%d address=0x%x", + GetTypeName().c_str(), GetName().c_str(), offset, length, address); + cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); + break; + } + + // Write to file... + case FileCommand::Write: + { + u64 offset = cmd_buff[1] | ((u64) cmd_buff[2]) << 32; + u32 length = cmd_buff[3]; + u32 flush = cmd_buff[4]; + u32 address = cmd_buff[6]; + LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", + GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); + cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); + break; + } + + case FileCommand::GetSize: + { + LOG_TRACE(Service_FS, "GetSize %s %s", GetTypeName().c_str(), GetName().c_str()); + u64 size = backend->GetSize(); + cmd_buff[2] = (u32)size; + cmd_buff[3] = size >> 32; + break; + } + + case FileCommand::SetSize: + { + u64 size = cmd_buff[1] | ((u64)cmd_buff[2] << 32); + LOG_TRACE(Service_FS, "SetSize %s %s size=%llu", + GetTypeName().c_str(), GetName().c_str(), size); + backend->SetSize(size); + break; + } + + case FileCommand::Close: + { + LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); + Kernel::g_object_pool.Destroy(GetHandle()); + break; + } + + // Unknown command... + default: + LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); + ResultCode error = UnimplementedFunction(ErrorModule::FS); + cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. + return error; + } + cmd_buff[1] = 0; // No error + return MakeResult(false); + } +}; + +class Directory : public Kernel::Session { +public: + std::string GetName() const override { return "Directory: " + path.DebugStr(); } + + FileSys::Path path; ///< Path of the directory + std::unique_ptr backend; ///< File backend interface + + ResultVal SyncRequest() override { + u32* cmd_buff = Kernel::GetCommandBuffer(); + DirectoryCommand cmd = static_cast(cmd_buff[0]); + switch (cmd) { + + // Read from directory... + case DirectoryCommand::Read: + { + u32 count = cmd_buff[1]; + u32 address = cmd_buff[3]; + auto entries = reinterpret_cast(Memory::GetPointer(address)); + LOG_TRACE(Service_FS, "Read %s %s: count=%d", + GetTypeName().c_str(), GetName().c_str(), count); + + // Number of entries actually read + cmd_buff[2] = backend->Read(count, entries); + break; + } + + case DirectoryCommand::Close: + { + LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); + Kernel::g_object_pool.Destroy(GetHandle()); + break; + } + + // Unknown command... + default: + LOG_ERROR(Service_FS, "Unknown command=0x%08X!", cmd); + ResultCode error = UnimplementedFunction(ErrorModule::FS); + cmd_buff[1] = error.raw; // TODO(Link Mauve): use the correct error code for that. + return MakeResult(false); + } + cmd_buff[1] = 0; // No error + return MakeResult(false); + } +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +std::map g_archive_map; ///< Map of file archives by IdCode + +ResultVal OpenArchive(FileSys::Archive::IdCode id_code) { + auto itr = g_archive_map.find(id_code); + if (itr == g_archive_map.end()) { + return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, + ErrorSummary::NotFound, ErrorLevel::Permanent); + } + + return MakeResult(itr->second); +} + +ResultCode CloseArchive(FileSys::Archive::IdCode id_code) { + auto itr = g_archive_map.find(id_code); + if (itr == g_archive_map.end()) { + LOG_ERROR(Service_FS, "Cannot close archive %d, does not exist!", (int)id_code); + return InvalidHandle(ErrorModule::FS); + } + + LOG_TRACE(Service_FS, "Closed archive %d", (int) id_code); + return RESULT_SUCCESS; +} + +/** + * Mounts an archive + * @param archive Pointer to the archive to mount + */ +ResultCode MountArchive(Archive* archive) { + FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); + ResultVal archive_handle = OpenArchive(id_code); + if (archive_handle.Succeeded()) { + LOG_ERROR(Service_FS, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); + return archive_handle.Code(); + } + g_archive_map[id_code] = archive->GetHandle(); + LOG_TRACE(Service_FS, "Mounted archive %s", archive->GetName().c_str()); + return RESULT_SUCCESS; +} + +ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) { + Archive* archive = new Archive; + Handle handle = Kernel::g_object_pool.Create(archive); + archive->name = name; + archive->backend = backend; + + ResultCode result = MountArchive(archive); + if (result.IsError()) { + return result; + } + + return RESULT_SUCCESS; +} + +ResultVal OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { + // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create + // the archive file handles at app loading, and then keep them persistent throughout execution. + // Archives file handles are just reused and not actually freed until emulation shut down. + // Verify if real hardware works this way, or if new handles are created each time + if (path.GetType() == FileSys::Binary) + // TODO(bunnei): FixMe - this is a hack to compensate for an incorrect FileSys backend + // design. While the functionally of this is OK, our implementation decision to separate + // normal files from archive file pointers is very likely wrong. + // See https://github.com/citra-emu/citra/issues/205 + return MakeResult(archive_handle); + + File* file = new File; + Handle handle = Kernel::g_object_pool.Create(file); + + Archive* archive = Kernel::g_object_pool.Get(archive_handle); + if (archive == nullptr) { + return InvalidHandle(ErrorModule::FS); + } + file->path = path; + file->backend = archive->backend->OpenFile(path, mode); + + if (!file->backend) { + return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, + ErrorSummary::NotFound, ErrorLevel::Permanent); + } + + return MakeResult(handle); +} + +ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) { + Archive* archive = Kernel::g_object_pool.GetFast(archive_handle); + if (archive == nullptr) + return InvalidHandle(ErrorModule::FS); + if (archive->backend->DeleteFile(path)) + return RESULT_SUCCESS; + return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description + ErrorSummary::Canceled, ErrorLevel::Status); +} + +ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, + Handle dest_archive_handle, const FileSys::Path& dest_path) { + Archive* src_archive = Kernel::g_object_pool.GetFast(src_archive_handle); + Archive* dest_archive = Kernel::g_object_pool.GetFast(dest_archive_handle); + if (src_archive == nullptr || dest_archive == nullptr) + return InvalidHandle(ErrorModule::FS); + if (src_archive == dest_archive) { + if (src_archive->backend->RenameFile(src_path, dest_path)) + return RESULT_SUCCESS; + } else { + // TODO: Implement renaming across archives + return UnimplementedFunction(ErrorModule::FS); + } + return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description + ErrorSummary::NothingHappened, ErrorLevel::Status); +} + +ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { + Archive* archive = Kernel::g_object_pool.GetFast(archive_handle); + if (archive == nullptr) + return InvalidHandle(ErrorModule::FS); + if (archive->backend->DeleteDirectory(path)) + return RESULT_SUCCESS; + return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description + ErrorSummary::Canceled, ErrorLevel::Status); +} + +ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { + Archive* archive = Kernel::g_object_pool.GetFast(archive_handle); + if (archive == nullptr) + return InvalidHandle(ErrorModule::FS); + if (archive->backend->CreateDirectory(path)) + return RESULT_SUCCESS; + return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description + ErrorSummary::Canceled, ErrorLevel::Status); +} + +ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, + Handle dest_archive_handle, const FileSys::Path& dest_path) { + Archive* src_archive = Kernel::g_object_pool.GetFast(src_archive_handle); + Archive* dest_archive = Kernel::g_object_pool.GetFast(dest_archive_handle); + if (src_archive == nullptr || dest_archive == nullptr) + return InvalidHandle(ErrorModule::FS); + if (src_archive == dest_archive) { + if (src_archive->backend->RenameDirectory(src_path, dest_path)) + return RESULT_SUCCESS; + } else { + // TODO: Implement renaming across archives + return UnimplementedFunction(ErrorModule::FS); + } + return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description + ErrorSummary::NothingHappened, ErrorLevel::Status); +} + +/** + * 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 Opened Directory object + */ +ResultVal OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { + Directory* directory = new Directory; + Handle handle = Kernel::g_object_pool.Create(directory); + + Archive* archive = Kernel::g_object_pool.Get(archive_handle); + if (archive == nullptr) { + return InvalidHandle(ErrorModule::FS); + } + directory->path = path; + directory->backend = archive->backend->OpenDirectory(path); + + if (!directory->backend) { + return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, + ErrorSummary::NotFound, ErrorLevel::Permanent); + } + + return MakeResult(handle); +} + +/// Initialize archives +void ArchiveInit() { + g_archive_map.clear(); + + // TODO(Link Mauve): Add the other archive types (see here for the known types: + // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished + // archive type is SDMC, so it is the only one getting exposed. + + std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); + auto archive = new FileSys::Archive_SDMC(sdmc_directory); + if (archive->Initialize()) + CreateArchive(archive, "SDMC"); + else + LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); +} + +/// Shutdown archives +void ArchiveShutdown() { + g_archive_map.clear(); +} + +} // namespace Kernel diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h new file mode 100644 index 00000000..b50833a2 --- /dev/null +++ b/src/core/hle/service/fs/archive.h @@ -0,0 +1,107 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/file_sys/archive.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/result.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Kernel namespace + +namespace Kernel { + +/** + * Opens an archive + * @param id_code IdCode of the archive to open + * @return Handle to the opened archive + */ +ResultVal OpenArchive(FileSys::Archive::IdCode id_code); + +/** + * Closes an archive + * @param id_code IdCode of the archive to open + */ +ResultCode CloseArchive(FileSys::Archive::IdCode id_code); + +/** + * Creates an Archive + * @param backend File system backend interface to the archive + * @param name Name of Archive + */ +ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name); + +/** + * 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 Handle to the opened File object + */ +ResultVal OpenFileFromArchive(Handle 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(Handle 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(Handle src_archive_handle, const FileSys::Path& src_path, + Handle 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(Handle archive_handle, const FileSys::Path& path); + +/** + * Create a Directory from an Archive + * @param archive_handle Handle to an open Archive object + * @param path Path to the Directory inside of the Archive + * @return Whether creation of directory succeeded + */ +ResultCode CreateDirectoryFromArchive(Handle 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(Handle src_archive_handle, const FileSys::Path& src_path, + Handle 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 Handle to the opened File object + */ +ResultVal OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); + +/// Initialize archives +void ArchiveInit(); + +/// Shutdown archives +void ArchiveShutdown(); + +} // namespace FileSys diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp new file mode 100644 index 00000000..c61b283c --- /dev/null +++ b/src/core/hle/service/fs/fs_user.cpp @@ -0,0 +1,474 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/common.h" + +#include "common/string_util.h" +#include "core/hle/service/fs/archive.h" +#include "core/hle/result.h" +#include "core/hle/service/fs/fs_user.h" +#include "core/settings.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace FS_User + +namespace FS_User { + +static void Initialize(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per + // http://3dbrew.org/wiki/FS:Initialize#Request + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_DEBUG(Service_FS, "called"); +} + +/** + * FS_User::OpenFile service function + * Inputs: + * 1 : Transaction + * 2 : Archive handle lower word + * 3 : Archive handle upper word + * 4 : Low path type + * 5 : Low path size + * 6 : Open flags + * 7 : Attributes + * 8 : (LowPathSize << 14) | 2 + * 9 : Low path data pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 3 : File handle + */ +static void OpenFile(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to + // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. + Handle archive_handle = static_cast(cmd_buff[3]); + auto filename_type = static_cast(cmd_buff[4]); + u32 filename_size = cmd_buff[5]; + FileSys::Mode mode; mode.hex = cmd_buff[6]; + u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes. + u32 filename_ptr = cmd_buff[9]; + FileSys::Path file_path(filename_type, filename_size, filename_ptr); + + LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); + + ResultVal handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode); + cmd_buff[1] = handle.Code().raw; + if (handle.Succeeded()) { + cmd_buff[3] = *handle; + } else { + LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); + } +} + +/** + * FS_User::OpenFileDirectly service function + * Inputs: + * 1 : Transaction + * 2 : Archive ID + * 3 : Archive low path type + * 4 : Archive low path size + * 5 : File low path type + * 6 : File low path size + * 7 : Flags + * 8 : Attributes + * 9 : (ArchiveLowPathSize << 14) | 0x802 + * 10 : Archive low path + * 11 : (FileLowPathSize << 14) | 2 + * 12 : File low path + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 3 : File handle + */ +static void OpenFileDirectly(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + auto archive_id = static_cast(cmd_buff[2]); + auto archivename_type = static_cast(cmd_buff[3]); + u32 archivename_size = cmd_buff[4]; + auto filename_type = static_cast(cmd_buff[5]); + u32 filename_size = cmd_buff[6]; + FileSys::Mode mode; mode.hex = cmd_buff[7]; + u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes. + u32 archivename_ptr = cmd_buff[10]; + u32 filename_ptr = cmd_buff[12]; + FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr); + FileSys::Path file_path(filename_type, filename_size, filename_ptr); + + LOG_DEBUG(Service_FS, "archive_path=%s file_path=%s, mode=%u attributes=%d", + archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode.hex, attributes); + + if (archive_path.GetType() != FileSys::Empty) { + LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); + cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; + return; + } + + // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it + // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here? + ResultVal archive_handle = Kernel::OpenArchive(archive_id); + cmd_buff[1] = archive_handle.Code().raw; + if (archive_handle.Failed()) { + LOG_ERROR(Service_FS, "failed to get a handle for archive"); + return; + } + // cmd_buff[2] isn't used according to 3dmoo's implementation. + cmd_buff[3] = *archive_handle; + + ResultVal handle = Kernel::OpenFileFromArchive(*archive_handle, file_path, mode); + cmd_buff[1] = handle.Code().raw; + if (handle.Succeeded()) { + cmd_buff[3] = *handle; + } else { + LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); + } +} + +/* + * FS_User::DeleteFile service function + * Inputs: + * 2 : Archive handle lower word + * 3 : Archive handle upper word + * 4 : File path string type + * 5 : File path string size + * 7 : File path string data + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void DeleteFile(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to + // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. + Handle archive_handle = static_cast(cmd_buff[3]); + auto filename_type = static_cast(cmd_buff[4]); + u32 filename_size = cmd_buff[5]; + u32 filename_ptr = cmd_buff[7]; + + FileSys::Path file_path(filename_type, filename_size, filename_ptr); + + LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", + filename_type, filename_size, file_path.DebugStr().c_str()); + + cmd_buff[1] = Kernel::DeleteFileFromArchive(archive_handle, file_path).raw; +} + +/* + * FS_User::RenameFile service function + * Inputs: + * 2 : Source archive handle lower word + * 3 : Source archive handle upper word + * 4 : Source file path type + * 5 : Source file path size + * 6 : Dest archive handle lower word + * 7 : Dest archive handle upper word + * 8 : Dest file path type + * 9 : Dest file path size + * 11: Source file path string data + * 13: Dest file path string + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void RenameFile(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to + // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. + Handle src_archive_handle = static_cast(cmd_buff[3]); + auto src_filename_type = static_cast(cmd_buff[4]); + u32 src_filename_size = cmd_buff[5]; + Handle dest_archive_handle = static_cast(cmd_buff[7]); + auto dest_filename_type = static_cast(cmd_buff[8]); + u32 dest_filename_size = cmd_buff[9]; + u32 src_filename_ptr = cmd_buff[11]; + u32 dest_filename_ptr = cmd_buff[13]; + + FileSys::Path src_file_path(src_filename_type, src_filename_size, src_filename_ptr); + FileSys::Path dest_file_path(dest_filename_type, dest_filename_size, dest_filename_ptr); + + LOG_DEBUG(Service_FS, "src_type=%d src_size=%d src_data=%s dest_type=%d dest_size=%d dest_data=%s", + src_filename_type, src_filename_size, src_file_path.DebugStr().c_str(), + dest_filename_type, dest_filename_size, dest_file_path.DebugStr().c_str()); + + cmd_buff[1] = Kernel::RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle, dest_file_path).raw; +} + +/* + * FS_User::DeleteDirectory service function + * Inputs: + * 2 : Archive handle lower word + * 3 : Archive handle upper word + * 4 : Directory path string type + * 5 : Directory path string size + * 7 : Directory path string data + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void DeleteDirectory(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to + // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. + Handle archive_handle = static_cast(cmd_buff[3]); + auto dirname_type = static_cast(cmd_buff[4]); + u32 dirname_size = cmd_buff[5]; + u32 dirname_ptr = cmd_buff[7]; + + FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); + + LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", + dirname_type, dirname_size, dir_path.DebugStr().c_str()); + + cmd_buff[1] = Kernel::DeleteDirectoryFromArchive(archive_handle, dir_path).raw; +} + +/* + * FS_User::CreateDirectory service function + * Inputs: + * 2 : Archive handle lower word + * 3 : Archive handle upper word + * 4 : Directory path string type + * 5 : Directory path string size + * 8 : Directory path string data + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +static void CreateDirectory(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to + // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. + Handle archive_handle = static_cast(cmd_buff[3]); + auto dirname_type = static_cast(cmd_buff[4]); + u32 dirname_size = cmd_buff[5]; + u32 dirname_ptr = cmd_buff[8]; + + FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); + + LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); + + cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_path).raw; +} + +/* + * FS_User::RenameDirectory service function + * Inputs: + * 2 : Source archive handle lower word + * 3 : Source archive handle upper word + * 4 : Source dir path type + * 5 : Source dir path size + * 6 : Dest archive handle lower word + * 7 : Dest archive handle upper word + * 8 : Dest dir path type + * 9 : Dest dir path size + * 11: Source dir path string data + * 13: Dest dir path string + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void RenameDirectory(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to + // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. + Handle src_archive_handle = static_cast(cmd_buff[3]); + auto src_dirname_type = static_cast(cmd_buff[4]); + u32 src_dirname_size = cmd_buff[5]; + Handle dest_archive_handle = static_cast(cmd_buff[7]); + auto dest_dirname_type = static_cast(cmd_buff[8]); + u32 dest_dirname_size = cmd_buff[9]; + u32 src_dirname_ptr = cmd_buff[11]; + u32 dest_dirname_ptr = cmd_buff[13]; + + FileSys::Path src_dir_path(src_dirname_type, src_dirname_size, src_dirname_ptr); + FileSys::Path dest_dir_path(dest_dirname_type, dest_dirname_size, dest_dirname_ptr); + + LOG_DEBUG(Service_FS, "src_type=%d src_size=%d src_data=%s dest_type=%d dest_size=%d dest_data=%s", + src_dirname_type, src_dirname_size, src_dir_path.DebugStr().c_str(), + dest_dirname_type, dest_dirname_size, dest_dir_path.DebugStr().c_str()); + + cmd_buff[1] = Kernel::RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw; +} + +static void OpenDirectory(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to + // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. + Handle archive_handle = static_cast(cmd_buff[2]); + auto dirname_type = static_cast(cmd_buff[3]); + u32 dirname_size = cmd_buff[4]; + u32 dirname_ptr = cmd_buff[6]; + + FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); + + LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); + + ResultVal handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path); + cmd_buff[1] = handle.Code().raw; + if (handle.Succeeded()) { + cmd_buff[3] = *handle; + } else { + LOG_ERROR(Service_FS, "failed to get a handle for directory"); + } +} + +/** + * FS_User::OpenArchive service function + * Inputs: + * 1 : Archive ID + * 2 : Archive low path type + * 3 : Archive low path size + * 4 : (LowPathSize << 14) | 2 + * 5 : Archive low path + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Archive handle lower word (unused) + * 3 : Archive handle upper word (same as file handle) + */ +static void OpenArchive(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + auto archive_id = static_cast(cmd_buff[1]); + auto archivename_type = static_cast(cmd_buff[2]); + u32 archivename_size = cmd_buff[3]; + u32 archivename_ptr = cmd_buff[5]; + FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr); + + LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str()); + + if (archive_path.GetType() != FileSys::Empty) { + LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); + cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; + return; + } + + ResultVal handle = Kernel::OpenArchive(archive_id); + cmd_buff[1] = handle.Code().raw; + if (handle.Succeeded()) { + // cmd_buff[2] isn't used according to 3dmoo's implementation. + cmd_buff[3] = *handle; + } else { + LOG_ERROR(Service_FS, "failed to get a handle for archive"); + } +} + +/* +* FS_User::IsSdmcDetected service function +* Outputs: +* 1 : Result of function, 0 on success, otherwise error code +* 2 : Whether the Sdmc could be detected +*/ +static void IsSdmcDetected(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = 0; + cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0; + + LOG_DEBUG(Service_FS, "called"); +} + +const Interface::FunctionInfo FunctionTable[] = { + {0x000100C6, nullptr, "Dummy1"}, + {0x040100C4, nullptr, "Control"}, + {0x08010002, Initialize, "Initialize"}, + {0x080201C2, OpenFile, "OpenFile"}, + {0x08030204, OpenFileDirectly, "OpenFileDirectly"}, + {0x08040142, DeleteFile, "DeleteFile"}, + {0x08050244, RenameFile, "RenameFile"}, + {0x08060142, DeleteDirectory, "DeleteDirectory"}, + {0x08070142, nullptr, "DeleteDirectoryRecursively"}, + {0x08080202, nullptr, "CreateFile"}, + {0x08090182, CreateDirectory, "CreateDirectory"}, + {0x080A0244, RenameDirectory, "RenameDirectory"}, + {0x080B0102, OpenDirectory, "OpenDirectory"}, + {0x080C00C2, OpenArchive, "OpenArchive"}, + {0x080D0144, nullptr, "ControlArchive"}, + {0x080E0080, nullptr, "CloseArchive"}, + {0x080F0180, nullptr, "FormatThisUserSaveData"}, + {0x08100200, nullptr, "CreateSystemSaveData"}, + {0x08110040, nullptr, "DeleteSystemSaveData"}, + {0x08120080, nullptr, "GetFreeBytes"}, + {0x08130000, nullptr, "GetCardType"}, + {0x08140000, nullptr, "GetSdmcArchiveResource"}, + {0x08150000, nullptr, "GetNandArchiveResource"}, + {0x08160000, nullptr, "GetSdmcFatfsErro"}, + {0x08170000, IsSdmcDetected, "IsSdmcDetected"}, + {0x08180000, nullptr, "IsSdmcWritable"}, + {0x08190042, nullptr, "GetSdmcCid"}, + {0x081A0042, nullptr, "GetNandCid"}, + {0x081B0000, nullptr, "GetSdmcSpeedInfo"}, + {0x081C0000, nullptr, "GetNandSpeedInfo"}, + {0x081D0042, nullptr, "GetSdmcLog"}, + {0x081E0042, nullptr, "GetNandLog"}, + {0x081F0000, nullptr, "ClearSdmcLog"}, + {0x08200000, nullptr, "ClearNandLog"}, + {0x08210000, nullptr, "CardSlotIsInserted"}, + {0x08220000, nullptr, "CardSlotPowerOn"}, + {0x08230000, nullptr, "CardSlotPowerOff"}, + {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"}, + {0x08250040, nullptr, "CardNorDirectCommand"}, + {0x08260080, nullptr, "CardNorDirectCommandWithAddress"}, + {0x08270082, nullptr, "CardNorDirectRead"}, + {0x082800C2, nullptr, "CardNorDirectReadWithAddress"}, + {0x08290082, nullptr, "CardNorDirectWrite"}, + {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"}, + {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"}, + {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"}, + {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"}, + {0x082E0040, nullptr, "GetProductInfo"}, + {0x082F0040, nullptr, "GetProgramLaunchInfo"}, + {0x08300182, nullptr, "CreateExtSaveData"}, + {0x08310180, nullptr, "CreateSharedExtSaveData"}, + {0x08320102, nullptr, "ReadExtSaveDataIcon"}, + {0x08330082, nullptr, "EnumerateExtSaveData"}, + {0x08340082, nullptr, "EnumerateSharedExtSaveData"}, + {0x08350080, nullptr, "DeleteExtSaveData"}, + {0x08360080, nullptr, "DeleteSharedExtSaveData"}, + {0x08370040, nullptr, "SetCardSpiBaudRate"}, + {0x08380040, nullptr, "SetCardSpiBusMode"}, + {0x08390000, nullptr, "SendInitializeInfoTo9"}, + {0x083A0100, nullptr, "GetSpecialContentIndex"}, + {0x083B00C2, nullptr, "GetLegacyRomHeader"}, + {0x083C00C2, nullptr, "GetLegacyBannerData"}, + {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"}, + {0x083E00C2, nullptr, "QueryTotalQuotaSize"}, + {0x083F00C0, nullptr, "GetExtDataBlockSize"}, + {0x08400040, nullptr, "AbnegateAccessRight"}, + {0x08410000, nullptr, "DeleteSdmcRoot"}, + {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"}, + {0x08430000, nullptr, "InitializeCtrFileSystem"}, + {0x08440000, nullptr, "CreateSeed"}, + {0x084500C2, nullptr, "GetFormatInfo"}, + {0x08460102, nullptr, "GetLegacyRomHeader2"}, + {0x08470180, nullptr, "FormatCtrCardUserSaveData"}, + {0x08480042, nullptr, "GetSdmcCtrRootPath"}, + {0x08490040, nullptr, "GetArchiveResource"}, + {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"}, + {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"}, + {0x084C0242, nullptr, "FormatSaveData"}, + {0x084D0102, nullptr, "GetLegacySubBannerData"}, + {0x084E0342, nullptr, "UpdateSha256Context"}, + {0x084F0102, nullptr, "ReadSpecialFile"}, + {0x08500040, nullptr, "GetSpecialFileSize"}, + {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"}, + {0x08610042, nullptr, "InitializeWithSdkVersion"}, + {0x08620040, nullptr, "SetPriority"}, + {0x08630000, nullptr, "GetPriority"}, +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Interface class + +Interface::Interface() { + Register(FunctionTable, ARRAY_SIZE(FunctionTable)); +} + +Interface::~Interface() { +} + +} // namespace diff --git a/src/core/hle/service/fs/fs_user.h b/src/core/hle/service/fs/fs_user.h new file mode 100644 index 00000000..00538254 --- /dev/null +++ b/src/core/hle/service/fs/fs_user.h @@ -0,0 +1,31 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Namespace FS_User + +namespace FS_User { + +/// Interface to "fs:USER" service +class Interface : public Service::Interface { +public: + + Interface(); + + ~Interface(); + + /** + * Gets the string port name used by CTROS for the service + * @return Port name of service + */ + std::string GetPortName() const override { + return "fs:USER"; + } +}; + +} // namespace diff --git a/src/core/hle/service/fs_user.cpp b/src/core/hle/service/fs_user.cpp deleted file mode 100644 index 672ba247..00000000 --- a/src/core/hle/service/fs_user.cpp +++ /dev/null @@ -1,475 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "common/common.h" - -#include "common/string_util.h" -#include "core/hle/kernel/archive.h" -#include "core/hle/kernel/archive.h" -#include "core/hle/result.h" -#include "core/hle/service/fs_user.h" -#include "core/settings.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace FS_User - -namespace FS_User { - -static void Initialize(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO(Link Mauve): check the behavior when cmd_buff[1] isn't 32, as per - // http://3dbrew.org/wiki/FS:Initialize#Request - cmd_buff[1] = RESULT_SUCCESS.raw; - - LOG_DEBUG(Service_FS, "called"); -} - -/** - * FS_User::OpenFile service function - * Inputs: - * 1 : Transaction - * 2 : Archive handle lower word - * 3 : Archive handle upper word - * 4 : Low path type - * 5 : Low path size - * 6 : Open flags - * 7 : Attributes - * 8 : (LowPathSize << 14) | 2 - * 9 : Low path data pointer - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 3 : File handle - */ -static void OpenFile(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to - // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. - Handle archive_handle = static_cast(cmd_buff[3]); - auto filename_type = static_cast(cmd_buff[4]); - u32 filename_size = cmd_buff[5]; - FileSys::Mode mode; mode.hex = cmd_buff[6]; - u32 attributes = cmd_buff[7]; // TODO(Link Mauve): do something with those attributes. - u32 filename_ptr = cmd_buff[9]; - FileSys::Path file_path(filename_type, filename_size, filename_ptr); - - LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); - - ResultVal handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode); - cmd_buff[1] = handle.Code().raw; - if (handle.Succeeded()) { - cmd_buff[3] = *handle; - } else { - LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); - } -} - -/** - * FS_User::OpenFileDirectly service function - * Inputs: - * 1 : Transaction - * 2 : Archive ID - * 3 : Archive low path type - * 4 : Archive low path size - * 5 : File low path type - * 6 : File low path size - * 7 : Flags - * 8 : Attributes - * 9 : (ArchiveLowPathSize << 14) | 0x802 - * 10 : Archive low path - * 11 : (FileLowPathSize << 14) | 2 - * 12 : File low path - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 3 : File handle - */ -static void OpenFileDirectly(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - auto archive_id = static_cast(cmd_buff[2]); - auto archivename_type = static_cast(cmd_buff[3]); - u32 archivename_size = cmd_buff[4]; - auto filename_type = static_cast(cmd_buff[5]); - u32 filename_size = cmd_buff[6]; - FileSys::Mode mode; mode.hex = cmd_buff[7]; - u32 attributes = cmd_buff[8]; // TODO(Link Mauve): do something with those attributes. - u32 archivename_ptr = cmd_buff[10]; - u32 filename_ptr = cmd_buff[12]; - FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr); - FileSys::Path file_path(filename_type, filename_size, filename_ptr); - - LOG_DEBUG(Service_FS, "archive_path=%s file_path=%s, mode=%u attributes=%d", - archive_path.DebugStr().c_str(), file_path.DebugStr().c_str(), mode.hex, attributes); - - if (archive_path.GetType() != FileSys::Empty) { - LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); - cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; - return; - } - - // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it - // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here? - ResultVal archive_handle = Kernel::OpenArchive(archive_id); - cmd_buff[1] = archive_handle.Code().raw; - if (archive_handle.Failed()) { - LOG_ERROR(Service_FS, "failed to get a handle for archive"); - return; - } - // cmd_buff[2] isn't used according to 3dmoo's implementation. - cmd_buff[3] = *archive_handle; - - ResultVal handle = Kernel::OpenFileFromArchive(*archive_handle, file_path, mode); - cmd_buff[1] = handle.Code().raw; - if (handle.Succeeded()) { - cmd_buff[3] = *handle; - } else { - LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); - } -} - -/* - * FS_User::DeleteFile service function - * Inputs: - * 2 : Archive handle lower word - * 3 : Archive handle upper word - * 4 : File path string type - * 5 : File path string size - * 7 : File path string data - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -void DeleteFile(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to - // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. - Handle archive_handle = static_cast(cmd_buff[3]); - auto filename_type = static_cast(cmd_buff[4]); - u32 filename_size = cmd_buff[5]; - u32 filename_ptr = cmd_buff[7]; - - FileSys::Path file_path(filename_type, filename_size, filename_ptr); - - LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", - filename_type, filename_size, file_path.DebugStr().c_str()); - - cmd_buff[1] = Kernel::DeleteFileFromArchive(archive_handle, file_path).raw; -} - -/* - * FS_User::RenameFile service function - * Inputs: - * 2 : Source archive handle lower word - * 3 : Source archive handle upper word - * 4 : Source file path type - * 5 : Source file path size - * 6 : Dest archive handle lower word - * 7 : Dest archive handle upper word - * 8 : Dest file path type - * 9 : Dest file path size - * 11: Source file path string data - * 13: Dest file path string - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -void RenameFile(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to - // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. - Handle src_archive_handle = static_cast(cmd_buff[3]); - auto src_filename_type = static_cast(cmd_buff[4]); - u32 src_filename_size = cmd_buff[5]; - Handle dest_archive_handle = static_cast(cmd_buff[7]); - auto dest_filename_type = static_cast(cmd_buff[8]); - u32 dest_filename_size = cmd_buff[9]; - u32 src_filename_ptr = cmd_buff[11]; - u32 dest_filename_ptr = cmd_buff[13]; - - FileSys::Path src_file_path(src_filename_type, src_filename_size, src_filename_ptr); - FileSys::Path dest_file_path(dest_filename_type, dest_filename_size, dest_filename_ptr); - - LOG_DEBUG(Service_FS, "src_type=%d src_size=%d src_data=%s dest_type=%d dest_size=%d dest_data=%s", - src_filename_type, src_filename_size, src_file_path.DebugStr().c_str(), - dest_filename_type, dest_filename_size, dest_file_path.DebugStr().c_str()); - - cmd_buff[1] = Kernel::RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle, dest_file_path).raw; -} - -/* - * FS_User::DeleteDirectory service function - * Inputs: - * 2 : Archive handle lower word - * 3 : Archive handle upper word - * 4 : Directory path string type - * 5 : Directory path string size - * 7 : Directory path string data - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -void DeleteDirectory(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to - // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. - Handle archive_handle = static_cast(cmd_buff[3]); - auto dirname_type = static_cast(cmd_buff[4]); - u32 dirname_size = cmd_buff[5]; - u32 dirname_ptr = cmd_buff[7]; - - FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); - - LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", - dirname_type, dirname_size, dir_path.DebugStr().c_str()); - - cmd_buff[1] = Kernel::DeleteDirectoryFromArchive(archive_handle, dir_path).raw; -} - -/* - * FS_User::CreateDirectory service function - * Inputs: - * 2 : Archive handle lower word - * 3 : Archive handle upper word - * 4 : Directory path string type - * 5 : Directory path string size - * 8 : Directory path string data - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -static void CreateDirectory(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to - // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. - Handle archive_handle = static_cast(cmd_buff[3]); - auto dirname_type = static_cast(cmd_buff[4]); - u32 dirname_size = cmd_buff[5]; - u32 dirname_ptr = cmd_buff[8]; - - FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); - - LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); - - cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_path).raw; -} - -/* - * FS_User::RenameDirectory service function - * Inputs: - * 2 : Source archive handle lower word - * 3 : Source archive handle upper word - * 4 : Source dir path type - * 5 : Source dir path size - * 6 : Dest archive handle lower word - * 7 : Dest archive handle upper word - * 8 : Dest dir path type - * 9 : Dest dir path size - * 11: Source dir path string data - * 13: Dest dir path string - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - */ -void RenameDirectory(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to - // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. - Handle src_archive_handle = static_cast(cmd_buff[3]); - auto src_dirname_type = static_cast(cmd_buff[4]); - u32 src_dirname_size = cmd_buff[5]; - Handle dest_archive_handle = static_cast(cmd_buff[7]); - auto dest_dirname_type = static_cast(cmd_buff[8]); - u32 dest_dirname_size = cmd_buff[9]; - u32 src_dirname_ptr = cmd_buff[11]; - u32 dest_dirname_ptr = cmd_buff[13]; - - FileSys::Path src_dir_path(src_dirname_type, src_dirname_size, src_dirname_ptr); - FileSys::Path dest_dir_path(dest_dirname_type, dest_dirname_size, dest_dirname_ptr); - - LOG_DEBUG(Service_FS, "src_type=%d src_size=%d src_data=%s dest_type=%d dest_size=%d dest_data=%s", - src_dirname_type, src_dirname_size, src_dir_path.DebugStr().c_str(), - dest_dirname_type, dest_dirname_size, dest_dir_path.DebugStr().c_str()); - - cmd_buff[1] = Kernel::RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw; -} - -static void OpenDirectory(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to - // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. - Handle archive_handle = static_cast(cmd_buff[2]); - auto dirname_type = static_cast(cmd_buff[3]); - u32 dirname_size = cmd_buff[4]; - u32 dirname_ptr = cmd_buff[6]; - - FileSys::Path dir_path(dirname_type, dirname_size, dirname_ptr); - - LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); - - ResultVal handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path); - cmd_buff[1] = handle.Code().raw; - if (handle.Succeeded()) { - cmd_buff[3] = *handle; - } else { - LOG_ERROR(Service_FS, "failed to get a handle for directory"); - } -} - -/** - * FS_User::OpenArchive service function - * Inputs: - * 1 : Archive ID - * 2 : Archive low path type - * 3 : Archive low path size - * 4 : (LowPathSize << 14) | 2 - * 5 : Archive low path - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : Archive handle lower word (unused) - * 3 : Archive handle upper word (same as file handle) - */ -static void OpenArchive(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - auto archive_id = static_cast(cmd_buff[1]); - auto archivename_type = static_cast(cmd_buff[2]); - u32 archivename_size = cmd_buff[3]; - u32 archivename_ptr = cmd_buff[5]; - FileSys::Path archive_path(archivename_type, archivename_size, archivename_ptr); - - LOG_DEBUG(Service_FS, "archive_path=%s", archive_path.DebugStr().c_str()); - - if (archive_path.GetType() != FileSys::Empty) { - LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); - cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; - return; - } - - ResultVal handle = Kernel::OpenArchive(archive_id); - cmd_buff[1] = handle.Code().raw; - if (handle.Succeeded()) { - // cmd_buff[2] isn't used according to 3dmoo's implementation. - cmd_buff[3] = *handle; - } else { - LOG_ERROR(Service_FS, "failed to get a handle for archive"); - } -} - -/* -* FS_User::IsSdmcDetected service function -* Outputs: -* 1 : Result of function, 0 on success, otherwise error code -* 2 : Whether the Sdmc could be detected -*/ -static void IsSdmcDetected(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - cmd_buff[1] = 0; - cmd_buff[2] = Settings::values.use_virtual_sd ? 1 : 0; - - LOG_DEBUG(Service_FS, "called"); -} - -const Interface::FunctionInfo FunctionTable[] = { - {0x000100C6, nullptr, "Dummy1"}, - {0x040100C4, nullptr, "Control"}, - {0x08010002, Initialize, "Initialize"}, - {0x080201C2, OpenFile, "OpenFile"}, - {0x08030204, OpenFileDirectly, "OpenFileDirectly"}, - {0x08040142, DeleteFile, "DeleteFile"}, - {0x08050244, RenameFile, "RenameFile"}, - {0x08060142, DeleteDirectory, "DeleteDirectory"}, - {0x08070142, nullptr, "DeleteDirectoryRecursively"}, - {0x08080202, nullptr, "CreateFile"}, - {0x08090182, CreateDirectory, "CreateDirectory"}, - {0x080A0244, RenameDirectory, "RenameDirectory"}, - {0x080B0102, OpenDirectory, "OpenDirectory"}, - {0x080C00C2, OpenArchive, "OpenArchive"}, - {0x080D0144, nullptr, "ControlArchive"}, - {0x080E0080, nullptr, "CloseArchive"}, - {0x080F0180, nullptr, "FormatThisUserSaveData"}, - {0x08100200, nullptr, "CreateSystemSaveData"}, - {0x08110040, nullptr, "DeleteSystemSaveData"}, - {0x08120080, nullptr, "GetFreeBytes"}, - {0x08130000, nullptr, "GetCardType"}, - {0x08140000, nullptr, "GetSdmcArchiveResource"}, - {0x08150000, nullptr, "GetNandArchiveResource"}, - {0x08160000, nullptr, "GetSdmcFatfsErro"}, - {0x08170000, IsSdmcDetected, "IsSdmcDetected"}, - {0x08180000, nullptr, "IsSdmcWritable"}, - {0x08190042, nullptr, "GetSdmcCid"}, - {0x081A0042, nullptr, "GetNandCid"}, - {0x081B0000, nullptr, "GetSdmcSpeedInfo"}, - {0x081C0000, nullptr, "GetNandSpeedInfo"}, - {0x081D0042, nullptr, "GetSdmcLog"}, - {0x081E0042, nullptr, "GetNandLog"}, - {0x081F0000, nullptr, "ClearSdmcLog"}, - {0x08200000, nullptr, "ClearNandLog"}, - {0x08210000, nullptr, "CardSlotIsInserted"}, - {0x08220000, nullptr, "CardSlotPowerOn"}, - {0x08230000, nullptr, "CardSlotPowerOff"}, - {0x08240000, nullptr, "CardSlotGetCardIFPowerStatus"}, - {0x08250040, nullptr, "CardNorDirectCommand"}, - {0x08260080, nullptr, "CardNorDirectCommandWithAddress"}, - {0x08270082, nullptr, "CardNorDirectRead"}, - {0x082800C2, nullptr, "CardNorDirectReadWithAddress"}, - {0x08290082, nullptr, "CardNorDirectWrite"}, - {0x082A00C2, nullptr, "CardNorDirectWriteWithAddress"}, - {0x082B00C2, nullptr, "CardNorDirectRead_4xIO"}, - {0x082C0082, nullptr, "CardNorDirectCpuWriteWithoutVerify"}, - {0x082D0040, nullptr, "CardNorDirectSectorEraseWithoutVerify"}, - {0x082E0040, nullptr, "GetProductInfo"}, - {0x082F0040, nullptr, "GetProgramLaunchInfo"}, - {0x08300182, nullptr, "CreateExtSaveData"}, - {0x08310180, nullptr, "CreateSharedExtSaveData"}, - {0x08320102, nullptr, "ReadExtSaveDataIcon"}, - {0x08330082, nullptr, "EnumerateExtSaveData"}, - {0x08340082, nullptr, "EnumerateSharedExtSaveData"}, - {0x08350080, nullptr, "DeleteExtSaveData"}, - {0x08360080, nullptr, "DeleteSharedExtSaveData"}, - {0x08370040, nullptr, "SetCardSpiBaudRate"}, - {0x08380040, nullptr, "SetCardSpiBusMode"}, - {0x08390000, nullptr, "SendInitializeInfoTo9"}, - {0x083A0100, nullptr, "GetSpecialContentIndex"}, - {0x083B00C2, nullptr, "GetLegacyRomHeader"}, - {0x083C00C2, nullptr, "GetLegacyBannerData"}, - {0x083D0100, nullptr, "CheckAuthorityToAccessExtSaveData"}, - {0x083E00C2, nullptr, "QueryTotalQuotaSize"}, - {0x083F00C0, nullptr, "GetExtDataBlockSize"}, - {0x08400040, nullptr, "AbnegateAccessRight"}, - {0x08410000, nullptr, "DeleteSdmcRoot"}, - {0x08420040, nullptr, "DeleteAllExtSaveDataOnNand"}, - {0x08430000, nullptr, "InitializeCtrFileSystem"}, - {0x08440000, nullptr, "CreateSeed"}, - {0x084500C2, nullptr, "GetFormatInfo"}, - {0x08460102, nullptr, "GetLegacyRomHeader2"}, - {0x08470180, nullptr, "FormatCtrCardUserSaveData"}, - {0x08480042, nullptr, "GetSdmcCtrRootPath"}, - {0x08490040, nullptr, "GetArchiveResource"}, - {0x084A0002, nullptr, "ExportIntegrityVerificationSeed"}, - {0x084B0002, nullptr, "ImportIntegrityVerificationSeed"}, - {0x084C0242, nullptr, "FormatSaveData"}, - {0x084D0102, nullptr, "GetLegacySubBannerData"}, - {0x084E0342, nullptr, "UpdateSha256Context"}, - {0x084F0102, nullptr, "ReadSpecialFile"}, - {0x08500040, nullptr, "GetSpecialFileSize"}, - {0x08580000, nullptr, "GetMovableSedHashedKeyYRandomData"}, - {0x08610042, nullptr, "InitializeWithSdkVersion"}, - {0x08620040, nullptr, "SetPriority"}, - {0x08630000, nullptr, "GetPriority"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable, ARRAY_SIZE(FunctionTable)); -} - -Interface::~Interface() { -} - -} // namespace diff --git a/src/core/hle/service/fs_user.h b/src/core/hle/service/fs_user.h deleted file mode 100644 index 00538254..00000000 --- a/src/core/hle/service/fs_user.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace FS_User - -namespace FS_User { - -/// Interface to "fs:USER" service -class Interface : public Service::Interface { -public: - - Interface(); - - ~Interface(); - - /** - * Gets the string port name used by CTROS for the service - * @return Port name of service - */ - std::string GetPortName() const override { - return "fs:USER"; - } -}; - -} // namespace diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index e6973572..68d199ac 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -15,7 +15,7 @@ #include "core/hle/service/csnd_snd.h" #include "core/hle/service/dsp_dsp.h" #include "core/hle/service/err_f.h" -#include "core/hle/service/fs_user.h" +#include "core/hle/service/fs/fs_user.h" #include "core/hle/service/frd_u.h" #include "core/hle/service/gsp_gpu.h" #include "core/hle/service/hid_user.h" diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp index f48d1353..0437e537 100644 --- a/src/core/loader/3dsx.cpp +++ b/src/core/loader/3dsx.cpp @@ -8,7 +8,7 @@ #include "core/file_sys/archive_romfs.h" #include "core/loader/elf.h" #include "core/loader/ncch.h" -#include "core/hle/kernel/archive.h" +#include "core/hle/service/fs/archive.h" #include "core/mem_map.h" #include "3dsx.h" diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 3883e130..d7786f1b 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -8,7 +8,7 @@ #include "core/loader/3dsx.h" #include "core/loader/elf.h" #include "core/loader/ncch.h" -#include "core/hle/kernel/archive.h" +#include "core/hle/service/fs/archive.h" #include "core/mem_map.h" //////////////////////////////////////////////////////////////////////////////////////////////////// -- cgit v1.2.3 From ca67bb7945bf358cf38242a04febfd3375760947 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Sun, 14 Dec 2014 05:55:11 -0200 Subject: HLE: Rename namespaces to match move & fix initialization order --- src/citra_qt/main.cpp | 6 ------ src/core/hle/hle.cpp | 3 +++ src/core/hle/kernel/kernel.cpp | 5 ----- src/core/hle/service/fs/archive.cpp | 9 ++++----- src/core/hle/service/fs/archive.h | 9 ++++----- src/core/hle/service/fs/fs_user.cpp | 32 +++++++++++++++++--------------- src/core/hle/service/fs/fs_user.h | 12 +++++++----- src/core/hle/service/service.cpp | 2 +- src/core/loader/loader.cpp | 2 +- src/core/system.cpp | 12 ++++++------ 10 files changed, 43 insertions(+), 49 deletions(-) (limited to 'src') diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 1299338a..23d4925b 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -157,12 +157,6 @@ void GMainWindow::BootGame(std::string filename) LOG_INFO(Frontend, "Citra starting...\n"); System::Init(render_window); - if (Core::Init()) { - LOG_CRITICAL(Frontend, "Core initialization failed, exiting..."); - Core::Stop(); - exit(1); - } - // Load a game or die... if (Loader::ResultStatus::Success != Loader::LoadFile(filename)) { LOG_CRITICAL(Frontend, "Failed to load ROM!"); diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index 3f73b553..cc3d5255 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp @@ -8,6 +8,7 @@ #include "core/hle/hle.h" #include "core/hle/kernel/thread.h" #include "core/hle/service/service.h" +#include "core/hle/service/fs/archive.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -56,6 +57,7 @@ void RegisterAllModules() { void Init() { Service::Init(); + Service::FS::ArchiveInit(); RegisterAllModules(); @@ -63,6 +65,7 @@ void Init() { } void Shutdown() { + Service::FS::ArchiveShutdown(); Service::Shutdown(); g_module_db.clear(); diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 95b4dfd6..929422b3 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -9,7 +9,6 @@ #include "core/core.h" #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/thread.h" -#include "core/hle/service/fs/archive.h" namespace Kernel { @@ -89,13 +88,11 @@ Object* ObjectPool::CreateByIDType(int type) { /// Initialize the kernel void Init() { Kernel::ThreadingInit(); - Kernel::ArchiveInit(); } /// Shutdown the kernel void Shutdown() { Kernel::ThreadingShutdown(); - Kernel::ArchiveShutdown(); g_object_pool.Clear(); // Free all kernel objects } @@ -106,8 +103,6 @@ void Shutdown() { * @return True on success, otherwise false */ bool LoadExec(u32 entry_point) { - Init(); - Core::g_app_core->SetPC(entry_point); // 0x30 is the typical main thread priority I've seen used so far diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 8889c633..5893a944 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -15,10 +15,8 @@ #include "core/hle/kernel/session.h" #include "core/hle/result.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Kernel namespace - -namespace Kernel { +namespace Service { +namespace FS { // Command to access archive file enum class FileCommand : u32 { @@ -423,4 +421,5 @@ void ArchiveShutdown() { g_archive_map.clear(); } -} // namespace Kernel +} // namespace FS +} // namespace Service diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index b50833a2..a7ee212d 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -10,10 +10,8 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/result.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Kernel namespace - -namespace Kernel { +namespace Service { +namespace FS { /** * Opens an archive @@ -104,4 +102,5 @@ void ArchiveInit(); /// Shutdown archives void ArchiveShutdown(); -} // namespace FileSys +} // namespace FS +} // namespace Service diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index c61b283c..76689c6a 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -13,7 +13,8 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace FS_User -namespace FS_User { +namespace Service { +namespace FS { static void Initialize(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); @@ -56,7 +57,7 @@ static void OpenFile(Service::Interface* self) { LOG_DEBUG(Service_FS, "path=%s, mode=%d attrs=%u", file_path.DebugStr().c_str(), mode.hex, attributes); - ResultVal handle = Kernel::OpenFileFromArchive(archive_handle, file_path, mode); + ResultVal handle = OpenFileFromArchive(archive_handle, file_path, mode); cmd_buff[1] = handle.Code().raw; if (handle.Succeeded()) { cmd_buff[3] = *handle; @@ -110,7 +111,7 @@ static void OpenFileDirectly(Service::Interface* self) { // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here? - ResultVal archive_handle = Kernel::OpenArchive(archive_id); + ResultVal archive_handle = OpenArchive(archive_id); cmd_buff[1] = archive_handle.Code().raw; if (archive_handle.Failed()) { LOG_ERROR(Service_FS, "failed to get a handle for archive"); @@ -119,7 +120,7 @@ static void OpenFileDirectly(Service::Interface* self) { // cmd_buff[2] isn't used according to 3dmoo's implementation. cmd_buff[3] = *archive_handle; - ResultVal handle = Kernel::OpenFileFromArchive(*archive_handle, file_path, mode); + ResultVal handle = OpenFileFromArchive(*archive_handle, file_path, mode); cmd_buff[1] = handle.Code().raw; if (handle.Succeeded()) { cmd_buff[3] = *handle; @@ -154,7 +155,7 @@ void DeleteFile(Service::Interface* self) { LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", filename_type, filename_size, file_path.DebugStr().c_str()); - cmd_buff[1] = Kernel::DeleteFileFromArchive(archive_handle, file_path).raw; + cmd_buff[1] = DeleteFileFromArchive(archive_handle, file_path).raw; } /* @@ -194,7 +195,7 @@ void RenameFile(Service::Interface* self) { src_filename_type, src_filename_size, src_file_path.DebugStr().c_str(), dest_filename_type, dest_filename_size, dest_file_path.DebugStr().c_str()); - cmd_buff[1] = Kernel::RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle, dest_file_path).raw; + cmd_buff[1] = RenameFileBetweenArchives(src_archive_handle, src_file_path, dest_archive_handle, dest_file_path).raw; } /* @@ -223,7 +224,7 @@ void DeleteDirectory(Service::Interface* self) { LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); - cmd_buff[1] = Kernel::DeleteDirectoryFromArchive(archive_handle, dir_path).raw; + cmd_buff[1] = DeleteDirectoryFromArchive(archive_handle, dir_path).raw; } /* @@ -251,7 +252,7 @@ static void CreateDirectory(Service::Interface* self) { LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); - cmd_buff[1] = Kernel::CreateDirectoryFromArchive(archive_handle, dir_path).raw; + cmd_buff[1] = CreateDirectoryFromArchive(archive_handle, dir_path).raw; } /* @@ -291,7 +292,7 @@ void RenameDirectory(Service::Interface* self) { src_dirname_type, src_dirname_size, src_dir_path.DebugStr().c_str(), dest_dirname_type, dest_dirname_size, dest_dir_path.DebugStr().c_str()); - cmd_buff[1] = Kernel::RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw; + cmd_buff[1] = RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw; } static void OpenDirectory(Service::Interface* self) { @@ -308,7 +309,7 @@ static void OpenDirectory(Service::Interface* self) { LOG_DEBUG(Service_FS, "type=%d size=%d data=%s", dirname_type, dirname_size, dir_path.DebugStr().c_str()); - ResultVal handle = Kernel::OpenDirectoryFromArchive(archive_handle, dir_path); + ResultVal handle = OpenDirectoryFromArchive(archive_handle, dir_path); cmd_buff[1] = handle.Code().raw; if (handle.Succeeded()) { cmd_buff[3] = *handle; @@ -347,7 +348,7 @@ static void OpenArchive(Service::Interface* self) { return; } - ResultVal handle = Kernel::OpenArchive(archive_id); + ResultVal handle = OpenArchive(archive_id); cmd_buff[1] = handle.Code().raw; if (handle.Succeeded()) { // cmd_buff[2] isn't used according to 3dmoo's implementation. @@ -372,7 +373,7 @@ static void IsSdmcDetected(Service::Interface* self) { LOG_DEBUG(Service_FS, "called"); } -const Interface::FunctionInfo FunctionTable[] = { +const FSUserInterface::FunctionInfo FunctionTable[] = { {0x000100C6, nullptr, "Dummy1"}, {0x040100C4, nullptr, "Control"}, {0x08010002, Initialize, "Initialize"}, @@ -464,11 +465,12 @@ const Interface::FunctionInfo FunctionTable[] = { //////////////////////////////////////////////////////////////////////////////////////////////////// // Interface class -Interface::Interface() { +FSUserInterface::FSUserInterface() { Register(FunctionTable, ARRAY_SIZE(FunctionTable)); } -Interface::~Interface() { +FSUserInterface::~FSUserInterface() { } -} // namespace +} // namespace FS +} // namespace Service diff --git a/src/core/hle/service/fs/fs_user.h b/src/core/hle/service/fs/fs_user.h index 00538254..80e3804e 100644 --- a/src/core/hle/service/fs/fs_user.h +++ b/src/core/hle/service/fs/fs_user.h @@ -9,15 +9,16 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace FS_User -namespace FS_User { +namespace Service { +namespace FS { /// Interface to "fs:USER" service -class Interface : public Service::Interface { +class FSUserInterface : public Service::Interface { public: - Interface(); + FSUserInterface(); - ~Interface(); + ~FSUserInterface(); /** * Gets the string port name used by CTROS for the service @@ -28,4 +29,5 @@ public: } }; -} // namespace +} // namespace FS +} // namespace Service diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 68d199ac..037211e7 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -93,7 +93,7 @@ void Init() { g_manager->AddService(new DSP_DSP::Interface); g_manager->AddService(new ERR_F::Interface); g_manager->AddService(new FRD_U::Interface); - g_manager->AddService(new FS_User::Interface); + g_manager->AddService(new FS::FSUserInterface); g_manager->AddService(new GSP_GPU::Interface); g_manager->AddService(new HID_User::Interface); g_manager->AddService(new IR_RST::Interface); diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index d7786f1b..6ce75256 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -74,7 +74,7 @@ ResultStatus LoadFile(const std::string& filename) { // Load application and RomFS if (ResultStatus::Success == app_loader.Load()) { - Kernel::CreateArchive(new FileSys::Archive_RomFS(app_loader), "RomFS"); + Service::FS::CreateArchive(new FileSys::Archive_RomFS(app_loader), "RomFS"); return ResultStatus::Success; } break; diff --git a/src/core/system.cpp b/src/core/system.cpp index 43d0eef2..2885ff45 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -23,10 +23,10 @@ void Init(EmuWindow* emu_window) { Core::Init(); Memory::Init(); HW::Init(); + Kernel::Init(); HLE::Init(); CoreTiming::Init(); VideoCore::Init(emu_window); - Kernel::Init(); } void RunLoopFor(int cycles) { @@ -37,13 +37,13 @@ void RunLoopUntil(u64 global_cycles) { } void Shutdown() { - Core::Shutdown(); - Memory::Shutdown(); - HW::Shutdown(); - HLE::Shutdown(); - CoreTiming::Shutdown(); VideoCore::Shutdown(); + CoreTiming::Shutdown(); + HLE::Shutdown(); Kernel::Shutdown(); + HW::Shutdown(); + Memory::Shutdown(); + Core::Shutdown(); } } // namespace -- cgit v1.2.3 From f6153679b0781eea084b22f3ceecc74b1fe6b018 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Mon, 15 Dec 2014 02:44:04 -0200 Subject: Service.FS: Do archive registration using IdCode instead of name --- src/core/file_sys/archive.h | 17 ++--------------- src/core/file_sys/archive_romfs.h | 6 +----- src/core/file_sys/archive_sdmc.h | 6 +----- src/core/hle/service/fs/archive.cpp | 20 ++++++++++---------- src/core/hle/service/fs/archive.h | 19 +++++++++++++++---- src/core/hle/service/fs/fs_user.cpp | 4 ++-- src/core/loader/loader.cpp | 2 +- 7 files changed, 32 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/core/file_sys/archive.h b/src/core/file_sys/archive.h index 27ed23cd..b7978bfb 100644 --- a/src/core/file_sys/archive.h +++ b/src/core/file_sys/archive.h @@ -162,25 +162,12 @@ private: class Archive : NonCopyable { public: - /// Supported archive types - enum class IdCode : u32 { - RomFS = 0x00000003, - SaveData = 0x00000004, - ExtSaveData = 0x00000006, - SharedExtSaveData = 0x00000007, - SystemSaveData = 0x00000008, - SDMC = 0x00000009, - SDMCWriteOnly = 0x0000000A, - }; - - Archive() { } virtual ~Archive() { } /** - * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.) - * @return IdCode of the archive + * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) */ - virtual IdCode GetIdCode() const = 0; + virtual std::string GetName() const = 0; /** * Open a file specified by its path, using the specified mode diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index 222bdc35..b60fcca9 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h @@ -22,11 +22,7 @@ public: Archive_RomFS(const Loader::AppLoader& app_loader); ~Archive_RomFS() override; - /** - * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.) - * @return IdCode of the archive - */ - IdCode GetIdCode() const override { return IdCode::RomFS; } + std::string GetName() const override { return "RomFS"; } /** * Open a file specified by its path, using the specified mode diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 19f563a6..54c18cb0 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h @@ -26,11 +26,7 @@ public: */ bool Initialize(); - /** - * Get the IdCode of the archive (e.g. RomFS, SaveData, etc.) - * @return IdCode of the archive - */ - IdCode GetIdCode() const override { return IdCode::SDMC; } + std::string GetName() const override { return "SDMC"; } /** * Open a file specified by its path, using the specified mode diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 5893a944..61cbfa73 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -43,9 +43,9 @@ enum class DirectoryCommand : u32 { class Archive : public Kernel::Session { public: - std::string GetName() const override { return "Archive: " + name; } + std::string GetName() const override { return "Archive: " + backend->GetName(); } - std::string name; ///< Name of archive (optional) + ArchiveIdCode id_code; ///< Id code of the archive FileSys::Archive* backend; ///< Archive backend interface ResultVal SyncRequest() override { @@ -91,7 +91,7 @@ public: case FileCommand::Close: { LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); - CloseArchive(backend->GetIdCode()); + CloseArchive(id_code); break; } // Unknown command... @@ -228,9 +228,9 @@ public: //////////////////////////////////////////////////////////////////////////////////////////////////// -std::map g_archive_map; ///< Map of file archives by IdCode +std::map g_archive_map; ///< Map of file archives by IdCode -ResultVal OpenArchive(FileSys::Archive::IdCode id_code) { +ResultVal OpenArchive(ArchiveIdCode id_code) { auto itr = g_archive_map.find(id_code); if (itr == g_archive_map.end()) { return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, @@ -240,7 +240,7 @@ ResultVal OpenArchive(FileSys::Archive::IdCode id_code) { return MakeResult(itr->second); } -ResultCode CloseArchive(FileSys::Archive::IdCode id_code) { +ResultCode CloseArchive(ArchiveIdCode id_code) { auto itr = g_archive_map.find(id_code); if (itr == g_archive_map.end()) { LOG_ERROR(Service_FS, "Cannot close archive %d, does not exist!", (int)id_code); @@ -256,7 +256,7 @@ ResultCode CloseArchive(FileSys::Archive::IdCode id_code) { * @param archive Pointer to the archive to mount */ ResultCode MountArchive(Archive* archive) { - FileSys::Archive::IdCode id_code = archive->backend->GetIdCode(); + ArchiveIdCode id_code = archive->id_code; ResultVal archive_handle = OpenArchive(id_code); if (archive_handle.Succeeded()) { LOG_ERROR(Service_FS, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); @@ -267,10 +267,10 @@ ResultCode MountArchive(Archive* archive) { return RESULT_SUCCESS; } -ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name) { +ResultCode CreateArchive(FileSys::Archive* backend, ArchiveIdCode id_code) { Archive* archive = new Archive; Handle handle = Kernel::g_object_pool.Create(archive); - archive->name = name; + archive->id_code = id_code; archive->backend = backend; ResultCode result = MountArchive(archive); @@ -411,7 +411,7 @@ void ArchiveInit() { std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); auto archive = new FileSys::Archive_SDMC(sdmc_directory); if (archive->Initialize()) - CreateArchive(archive, "SDMC"); + CreateArchive(archive, ArchiveIdCode::SDMC); else LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); } diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index a7ee212d..9a1df511 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -13,25 +13,36 @@ namespace Service { namespace FS { +/// Supported archive types +enum class ArchiveIdCode : u32 { + RomFS = 0x00000003, + SaveData = 0x00000004, + ExtSaveData = 0x00000006, + SharedExtSaveData = 0x00000007, + SystemSaveData = 0x00000008, + SDMC = 0x00000009, + SDMCWriteOnly = 0x0000000A, +}; + /** * Opens an archive * @param id_code IdCode of the archive to open * @return Handle to the opened archive */ -ResultVal OpenArchive(FileSys::Archive::IdCode id_code); +ResultVal OpenArchive(ArchiveIdCode id_code); /** * Closes an archive * @param id_code IdCode of the archive to open */ -ResultCode CloseArchive(FileSys::Archive::IdCode id_code); +ResultCode CloseArchive(ArchiveIdCode id_code); /** * Creates an Archive * @param backend File system backend interface to the archive - * @param name Name of Archive + * @param id_code Id code used to access this type of archive */ -ResultCode CreateArchive(FileSys::Archive* backend, const std::string& name); +ResultCode CreateArchive(FileSys::Archive* backend, ArchiveIdCode id_code); /** * Open a File from an Archive diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index 76689c6a..eda7cb8a 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -88,7 +88,7 @@ static void OpenFile(Service::Interface* self) { static void OpenFileDirectly(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - auto archive_id = static_cast(cmd_buff[2]); + auto archive_id = static_cast(cmd_buff[2]); auto archivename_type = static_cast(cmd_buff[3]); u32 archivename_size = cmd_buff[4]; auto filename_type = static_cast(cmd_buff[5]); @@ -334,7 +334,7 @@ static void OpenDirectory(Service::Interface* self) { static void OpenArchive(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - auto archive_id = static_cast(cmd_buff[1]); + auto archive_id = static_cast(cmd_buff[1]); auto archivename_type = static_cast(cmd_buff[2]); u32 archivename_size = cmd_buff[3]; u32 archivename_ptr = cmd_buff[5]; diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 6ce75256..49f8c458 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -74,7 +74,7 @@ ResultStatus LoadFile(const std::string& filename) { // Load application and RomFS if (ResultStatus::Success == app_loader.Load()) { - Service::FS::CreateArchive(new FileSys::Archive_RomFS(app_loader), "RomFS"); + Service::FS::CreateArchive(new FileSys::Archive_RomFS(app_loader), Service::FS::ArchiveIdCode::RomFS); return ResultStatus::Success; } break; -- cgit v1.2.3 From 82fe821e8734faab6cad29bc0377c2f630c1f876 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Mon, 15 Dec 2014 02:51:38 -0200 Subject: Service.FS: Rename FileSys::Archive to ArchiveBackend --- src/core/CMakeLists.txt | 2 +- src/core/file_sys/archive.h | 255 ------------------------------------ src/core/file_sys/archive_backend.h | 255 ++++++++++++++++++++++++++++++++++++ src/core/file_sys/archive_romfs.h | 4 +- src/core/file_sys/archive_sdmc.h | 4 +- src/core/hle/service/fs/archive.cpp | 6 +- src/core/hle/service/fs/archive.h | 4 +- 7 files changed, 265 insertions(+), 265 deletions(-) delete mode 100644 src/core/file_sys/archive.h create mode 100644 src/core/file_sys/archive_backend.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 18a41747..463f14ee 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -93,7 +93,7 @@ set(HEADERS arm/skyeye_common/vfp/vfp.h arm/skyeye_common/vfp/vfp_helper.h arm/arm_interface.h - file_sys/archive.h + file_sys/archive_backend.h file_sys/archive_romfs.h file_sys/archive_sdmc.h file_sys/file.h diff --git a/src/core/file_sys/archive.h b/src/core/file_sys/archive.h deleted file mode 100644 index b7978bfb..00000000 --- a/src/core/file_sys/archive.h +++ /dev/null @@ -1,255 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include - -#include "common/common_types.h" -#include "common/string_util.h" -#include "common/bit_field.h" - -#include "core/file_sys/file.h" -#include "core/file_sys/directory.h" - -#include "core/mem_map.h" -#include "core/hle/kernel/kernel.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -// Path string type -enum LowPathType : u32 { - Invalid = 0, - Empty = 1, - Binary = 2, - Char = 3, - Wchar = 4 -}; - -union Mode { - u32 hex; - BitField<0, 1, u32> read_flag; - BitField<1, 1, u32> write_flag; - BitField<2, 1, u32> create_flag; -}; - -class Path { -public: - - Path(): - type(Invalid) - { - } - - Path(LowPathType type, u32 size, u32 pointer): - type(type) - { - switch (type) { - case Binary: - { - u8* data = Memory::GetPointer(pointer); - binary = std::vector(data, data + size); - break; - } - case Char: - { - const char* data = reinterpret_cast(Memory::GetPointer(pointer)); - string = std::string(data, size - 1); // Data is always null-terminated. - break; - } - case Wchar: - { - const char16_t* data = reinterpret_cast(Memory::GetPointer(pointer)); - u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated. - break; - } - default: - break; - } - } - - LowPathType GetType() const { - return type; - } - - /** - * Gets the string representation of the path for debugging - * @return String representation of the path for debugging - */ - const std::string DebugStr() const { - switch (GetType()) { - case Invalid: - return "[Invalid]"; - case Empty: - return "[Empty]"; - case Binary: - { - std::stringstream res; - res << "[Binary: "; - for (unsigned byte : binary) - res << std::hex << std::setw(2) << std::setfill('0') << byte; - res << ']'; - return res.str(); - } - case Char: - return "[Char: " + AsString() + ']'; - case Wchar: - return "[Wchar: " + AsString() + ']'; - default: - // TODO(yuriks): Add assert - LOG_ERROR(Service_FS, "LowPathType cannot be converted to string!"); - return {}; - } - } - - const std::string AsString() const { - switch (GetType()) { - case Char: - return string; - case Wchar: - return Common::UTF16ToUTF8(u16str); - case Empty: - return {}; - default: - // TODO(yuriks): Add assert - LOG_ERROR(Service_FS, "LowPathType cannot be converted to string!"); - return {}; - } - } - - const std::u16string AsU16Str() const { - switch (GetType()) { - case Char: - return Common::UTF8ToUTF16(string); - case Wchar: - return u16str; - case Empty: - return {}; - default: - // TODO(yuriks): Add assert - LOG_ERROR(Service_FS, "LowPathType cannot be converted to u16string!"); - return {}; - } - } - - const std::vector AsBinary() const { - switch (GetType()) { - case Binary: - return binary; - case Char: - return std::vector(string.begin(), string.end()); - case Wchar: - return std::vector(u16str.begin(), u16str.end()); - case Empty: - return {}; - default: - // TODO(yuriks): Add assert - LOG_ERROR(Service_FS, "LowPathType cannot be converted to binary!"); - return {}; - } - } - -private: - LowPathType type; - std::vector binary; - std::string string; - std::u16string u16str; -}; - -class Archive : NonCopyable { -public: - virtual ~Archive() { } - - /** - * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) - */ - virtual std::string GetName() const = 0; - - /** - * Open a file specified by its path, using the specified mode - * @param path Path relative to the archive - * @param mode Mode to open the file with - * @return Opened file, or nullptr - */ - virtual std::unique_ptr OpenFile(const Path& path, const Mode mode) const = 0; - - /** - * Delete a file specified by its path - * @param path Path relative to the archive - * @return Whether the file could be deleted - */ - virtual bool DeleteFile(const FileSys::Path& path) const = 0; - - /** - * Rename a File specified by its path - * @param src_path Source path relative to the archive - * @param dest_path Destination path relative to the archive - * @return Whether rename succeeded - */ - virtual bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const = 0; - - /** - * Delete a directory specified by its path - * @param path Path relative to the archive - * @return Whether the directory could be deleted - */ - virtual bool DeleteDirectory(const FileSys::Path& path) const = 0; - - /** - * Create a directory specified by its path - * @param path Path relative to the archive - * @return Whether the directory could be created - */ - virtual bool CreateDirectory(const Path& path) const = 0; - - /** - * Rename a Directory specified by its path - * @param src_path Source path relative to the archive - * @param dest_path Destination path relative to the archive - * @return Whether rename succeeded - */ - virtual bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const = 0; - - /** - * Open a directory specified by its path - * @param path Path relative to the archive - * @return Opened directory, or nullptr - */ - virtual std::unique_ptr OpenDirectory(const Path& path) const = 0; - - /** - * Read data from the archive - * @param offset Offset in bytes to start reading data from - * @param length Length in bytes of data to read from archive - * @param buffer Buffer to read data into - * @return Number of bytes read - */ - virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0; - - /** - * Write data to the archive - * @param offset Offset in bytes to start writing data to - * @param length Length in bytes of data to write to archive - * @param buffer Buffer to write data from - * @param flush The flush parameters (0 == do not flush) - * @return Number of bytes written - */ - virtual size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) = 0; - - /** - * Get the size of the archive in bytes - * @return Size of the archive in bytes - */ - virtual size_t GetSize() const = 0; - - /** - * Set the size of the archive in bytes - */ - virtual void SetSize(const u64 size) = 0; -}; - -} // namespace FileSys diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h new file mode 100644 index 00000000..0558698f --- /dev/null +++ b/src/core/file_sys/archive_backend.h @@ -0,0 +1,255 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/common_types.h" +#include "common/string_util.h" +#include "common/bit_field.h" + +#include "core/file_sys/file.h" +#include "core/file_sys/directory.h" + +#include "core/mem_map.h" +#include "core/hle/kernel/kernel.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +// Path string type +enum LowPathType : u32 { + Invalid = 0, + Empty = 1, + Binary = 2, + Char = 3, + Wchar = 4 +}; + +union Mode { + u32 hex; + BitField<0, 1, u32> read_flag; + BitField<1, 1, u32> write_flag; + BitField<2, 1, u32> create_flag; +}; + +class Path { +public: + + Path(): + type(Invalid) + { + } + + Path(LowPathType type, u32 size, u32 pointer): + type(type) + { + switch (type) { + case Binary: + { + u8* data = Memory::GetPointer(pointer); + binary = std::vector(data, data + size); + break; + } + case Char: + { + const char* data = reinterpret_cast(Memory::GetPointer(pointer)); + string = std::string(data, size - 1); // Data is always null-terminated. + break; + } + case Wchar: + { + const char16_t* data = reinterpret_cast(Memory::GetPointer(pointer)); + u16str = std::u16string(data, size/2 - 1); // Data is always null-terminated. + break; + } + default: + break; + } + } + + LowPathType GetType() const { + return type; + } + + /** + * Gets the string representation of the path for debugging + * @return String representation of the path for debugging + */ + const std::string DebugStr() const { + switch (GetType()) { + case Invalid: + return "[Invalid]"; + case Empty: + return "[Empty]"; + case Binary: + { + std::stringstream res; + res << "[Binary: "; + for (unsigned byte : binary) + res << std::hex << std::setw(2) << std::setfill('0') << byte; + res << ']'; + return res.str(); + } + case Char: + return "[Char: " + AsString() + ']'; + case Wchar: + return "[Wchar: " + AsString() + ']'; + default: + // TODO(yuriks): Add assert + LOG_ERROR(Service_FS, "LowPathType cannot be converted to string!"); + return {}; + } + } + + const std::string AsString() const { + switch (GetType()) { + case Char: + return string; + case Wchar: + return Common::UTF16ToUTF8(u16str); + case Empty: + return {}; + default: + // TODO(yuriks): Add assert + LOG_ERROR(Service_FS, "LowPathType cannot be converted to string!"); + return {}; + } + } + + const std::u16string AsU16Str() const { + switch (GetType()) { + case Char: + return Common::UTF8ToUTF16(string); + case Wchar: + return u16str; + case Empty: + return {}; + default: + // TODO(yuriks): Add assert + LOG_ERROR(Service_FS, "LowPathType cannot be converted to u16string!"); + return {}; + } + } + + const std::vector AsBinary() const { + switch (GetType()) { + case Binary: + return binary; + case Char: + return std::vector(string.begin(), string.end()); + case Wchar: + return std::vector(u16str.begin(), u16str.end()); + case Empty: + return {}; + default: + // TODO(yuriks): Add assert + LOG_ERROR(Service_FS, "LowPathType cannot be converted to binary!"); + return {}; + } + } + +private: + LowPathType type; + std::vector binary; + std::string string; + std::u16string u16str; +}; + +class ArchiveBackend : NonCopyable { +public: + virtual ~ArchiveBackend() { } + + /** + * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) + */ + virtual std::string GetName() const = 0; + + /** + * Open a file specified by its path, using the specified mode + * @param path Path relative to the archive + * @param mode Mode to open the file with + * @return Opened file, or nullptr + */ + virtual std::unique_ptr OpenFile(const Path& path, const Mode mode) const = 0; + + /** + * Delete a file specified by its path + * @param path Path relative to the archive + * @return Whether the file could be deleted + */ + virtual bool DeleteFile(const FileSys::Path& path) const = 0; + + /** + * Rename a File specified by its path + * @param src_path Source path relative to the archive + * @param dest_path Destination path relative to the archive + * @return Whether rename succeeded + */ + virtual bool RenameFile(const FileSys::Path& src_path, const FileSys::Path& dest_path) const = 0; + + /** + * Delete a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be deleted + */ + virtual bool DeleteDirectory(const FileSys::Path& path) const = 0; + + /** + * Create a directory specified by its path + * @param path Path relative to the archive + * @return Whether the directory could be created + */ + virtual bool CreateDirectory(const Path& path) const = 0; + + /** + * Rename a Directory specified by its path + * @param src_path Source path relative to the archive + * @param dest_path Destination path relative to the archive + * @return Whether rename succeeded + */ + virtual bool RenameDirectory(const FileSys::Path& src_path, const FileSys::Path& dest_path) const = 0; + + /** + * Open a directory specified by its path + * @param path Path relative to the archive + * @return Opened directory, or nullptr + */ + virtual std::unique_ptr OpenDirectory(const Path& path) const = 0; + + /** + * Read data from the archive + * @param offset Offset in bytes to start reading data from + * @param length Length in bytes of data to read from archive + * @param buffer Buffer to read data into + * @return Number of bytes read + */ + virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0; + + /** + * Write data to the archive + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to archive + * @param buffer Buffer to write data from + * @param flush The flush parameters (0 == do not flush) + * @return Number of bytes written + */ + virtual size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) = 0; + + /** + * Get the size of the archive in bytes + * @return Size of the archive in bytes + */ + virtual size_t GetSize() const = 0; + + /** + * Set the size of the archive in bytes + */ + virtual void SetSize(const u64 size) = 0; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index b60fcca9..91505da4 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h @@ -8,7 +8,7 @@ #include "common/common_types.h" -#include "core/file_sys/archive.h" +#include "core/file_sys/archive_backend.h" #include "core/loader/loader.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -17,7 +17,7 @@ namespace FileSys { /// File system interface to the RomFS archive -class Archive_RomFS final : public Archive { +class Archive_RomFS final : public ArchiveBackend { public: Archive_RomFS(const Loader::AppLoader& app_loader); ~Archive_RomFS() override; diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 54c18cb0..347f3945 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h @@ -6,7 +6,7 @@ #include "common/common_types.h" -#include "core/file_sys/archive.h" +#include "core/file_sys/archive_backend.h" #include "core/loader/loader.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -15,7 +15,7 @@ namespace FileSys { /// File system interface to the SDMC archive -class Archive_SDMC final : public Archive { +class Archive_SDMC final : public ArchiveBackend { public: Archive_SDMC(const std::string& mount_point); ~Archive_SDMC() override; diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 61cbfa73..6ec310a6 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -8,7 +8,7 @@ #include "common/file_util.h" #include "common/math_util.h" -#include "core/file_sys/archive.h" +#include "core/file_sys/archive_backend.h" #include "core/file_sys/archive_sdmc.h" #include "core/file_sys/directory.h" #include "core/hle/service/fs/archive.h" @@ -46,7 +46,7 @@ public: std::string GetName() const override { return "Archive: " + backend->GetName(); } ArchiveIdCode id_code; ///< Id code of the archive - FileSys::Archive* backend; ///< Archive backend interface + FileSys::ArchiveBackend* backend; ///< Archive backend interface ResultVal SyncRequest() override { u32* cmd_buff = Kernel::GetCommandBuffer(); @@ -267,7 +267,7 @@ ResultCode MountArchive(Archive* archive) { return RESULT_SUCCESS; } -ResultCode CreateArchive(FileSys::Archive* backend, ArchiveIdCode id_code) { +ResultCode CreateArchive(FileSys::ArchiveBackend* backend, ArchiveIdCode id_code) { Archive* archive = new Archive; Handle handle = Kernel::g_object_pool.Create(archive); archive->id_code = id_code; diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 9a1df511..2c50dfff 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -6,7 +6,7 @@ #include "common/common_types.h" -#include "core/file_sys/archive.h" +#include "core/file_sys/archive_backend.h" #include "core/hle/kernel/kernel.h" #include "core/hle/result.h" @@ -42,7 +42,7 @@ ResultCode CloseArchive(ArchiveIdCode id_code); * @param backend File system backend interface to the archive * @param id_code Id code used to access this type of archive */ -ResultCode CreateArchive(FileSys::Archive* backend, ArchiveIdCode id_code); +ResultCode CreateArchive(FileSys::ArchiveBackend* backend, ArchiveIdCode id_code); /** * Open a File from an Archive -- cgit v1.2.3 From d51afab0bc3a7e06a73f9f51afaf26cf83d87cd2 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Mon, 15 Dec 2014 04:59:29 -0200 Subject: Service.FS: Rename FileSys::Directory to DirectoryBackend --- src/core/CMakeLists.txt | 2 +- src/core/file_sys/archive_backend.h | 4 +-- src/core/file_sys/archive_romfs.cpp | 4 +-- src/core/file_sys/archive_romfs.h | 2 +- src/core/file_sys/archive_sdmc.cpp | 4 +-- src/core/file_sys/archive_sdmc.h | 2 +- src/core/file_sys/directory.h | 65 ----------------------------------- src/core/file_sys/directory_backend.h | 65 +++++++++++++++++++++++++++++++++++ src/core/file_sys/directory_romfs.h | 4 +-- src/core/file_sys/directory_sdmc.h | 4 +-- src/core/hle/service/fs/archive.cpp | 4 +-- 11 files changed, 80 insertions(+), 80 deletions(-) delete mode 100644 src/core/file_sys/directory.h create mode 100644 src/core/file_sys/directory_backend.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 463f14ee..c0ebd1c7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -99,7 +99,7 @@ set(HEADERS file_sys/file.h file_sys/file_romfs.h file_sys/file_sdmc.h - file_sys/directory.h + file_sys/directory_backend.h file_sys/directory_romfs.h file_sys/directory_sdmc.h hle/kernel/address_arbiter.h diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index 0558698f..49a31038 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h @@ -11,7 +11,7 @@ #include "common/bit_field.h" #include "core/file_sys/file.h" -#include "core/file_sys/directory.h" +#include "core/file_sys/directory_backend.h" #include "core/mem_map.h" #include "core/hle/kernel/kernel.h" @@ -219,7 +219,7 @@ public: * @param path Path relative to the archive * @return Opened directory, or nullptr */ - virtual std::unique_ptr OpenDirectory(const Path& path) const = 0; + virtual std::unique_ptr OpenDirectory(const Path& path) const = 0; /** * Read data from the archive diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index 74974c2d..8db7d69c 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp @@ -78,8 +78,8 @@ bool Archive_RomFS::RenameDirectory(const FileSys::Path& src_path, const FileSys * @param path Path relative to the archive * @return Opened directory, or nullptr */ -std::unique_ptr Archive_RomFS::OpenDirectory(const Path& path) const { - return std::unique_ptr(new Directory_RomFS); +std::unique_ptr Archive_RomFS::OpenDirectory(const Path& path) const { + return std::unique_ptr(new Directory_RomFS); } /** diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index 91505da4..5a8a6b04 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h @@ -74,7 +74,7 @@ public: * @param path Path relative to the archive * @return Opened directory, or nullptr */ - std::unique_ptr OpenDirectory(const Path& path) const override; + std::unique_ptr OpenDirectory(const Path& path) const override; /** * Read data from the archive diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index 9e524b60..9d26d228 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp @@ -97,12 +97,12 @@ bool Archive_SDMC::RenameDirectory(const FileSys::Path& src_path, const FileSys: * @param path Path relative to the archive * @return Opened directory, or nullptr */ -std::unique_ptr Archive_SDMC::OpenDirectory(const Path& path) const { +std::unique_ptr Archive_SDMC::OpenDirectory(const Path& path) const { LOG_DEBUG(Service_FS, "called path=%s", path.DebugStr().c_str()); Directory_SDMC* directory = new Directory_SDMC(this, path); if (!directory->Open()) return nullptr; - return std::unique_ptr(directory); + return std::unique_ptr(directory); } /** diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 347f3945..f4cb9615 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h @@ -78,7 +78,7 @@ public: * @param path Path relative to the archive * @return Opened directory, or nullptr */ - std::unique_ptr OpenDirectory(const Path& path) const override; + std::unique_ptr OpenDirectory(const Path& path) const override; /** * Read data from the archive diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h deleted file mode 100644 index 1bb4101d..00000000 --- a/src/core/file_sys/directory.h +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include - -#include "common/common_types.h" - -#include "core/hle/kernel/kernel.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -// Structure of a directory entry, from http://3dbrew.org/wiki/FSDir:Read#Entry_format -const size_t FILENAME_LENGTH = 0x20C / 2; -struct Entry { - char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated) - std::array short_name; // 8.3 file name ('longfilename' -> 'LONGFI~1', null-terminated) - char unknown1; // unknown (observed values: 0x0A, 0x70, 0xFD) - std::array extension; // 8.3 file extension (set to spaces for directories, null-terminated) - char unknown2; // unknown (always 0x01) - char unknown3; // unknown (0x00 or 0x08) - char is_directory; // directory flag - char is_hidden; // hidden flag - char is_archive; // archive flag - char is_read_only; // read-only flag - u64 file_size; // file size (for files only) -}; -static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!"); -static_assert(offsetof(Entry, short_name) == 0x20C, "Wrong offset for short_name in Entry."); -static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension in Entry."); -static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry."); -static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry."); - -class Directory : NonCopyable { -public: - Directory() { } - virtual ~Directory() { } - - /** - * Open the directory - * @return true if the directory opened correctly - */ - virtual bool Open() = 0; - - /** - * List files contained in the directory - * @param count Number of entries to return at once in entries - * @param entries Buffer to read data into - * @return Number of entries listed - */ - virtual u32 Read(const u32 count, Entry* entries) = 0; - - /** - * Close the directory - * @return true if the directory closed correctly - */ - virtual bool Close() const = 0; -}; - -} // namespace FileSys diff --git a/src/core/file_sys/directory_backend.h b/src/core/file_sys/directory_backend.h new file mode 100644 index 00000000..188746a6 --- /dev/null +++ b/src/core/file_sys/directory_backend.h @@ -0,0 +1,65 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +// Structure of a directory entry, from http://3dbrew.org/wiki/FSDir:Read#Entry_format +const size_t FILENAME_LENGTH = 0x20C / 2; +struct Entry { + char16_t filename[FILENAME_LENGTH]; // Entry name (UTF-16, null-terminated) + std::array short_name; // 8.3 file name ('longfilename' -> 'LONGFI~1', null-terminated) + char unknown1; // unknown (observed values: 0x0A, 0x70, 0xFD) + std::array extension; // 8.3 file extension (set to spaces for directories, null-terminated) + char unknown2; // unknown (always 0x01) + char unknown3; // unknown (0x00 or 0x08) + char is_directory; // directory flag + char is_hidden; // hidden flag + char is_archive; // archive flag + char is_read_only; // read-only flag + u64 file_size; // file size (for files only) +}; +static_assert(sizeof(Entry) == 0x228, "Directory Entry struct isn't exactly 0x228 bytes long!"); +static_assert(offsetof(Entry, short_name) == 0x20C, "Wrong offset for short_name in Entry."); +static_assert(offsetof(Entry, extension) == 0x216, "Wrong offset for extension in Entry."); +static_assert(offsetof(Entry, is_archive) == 0x21E, "Wrong offset for is_archive in Entry."); +static_assert(offsetof(Entry, file_size) == 0x220, "Wrong offset for file_size in Entry."); + +class DirectoryBackend : NonCopyable { +public: + DirectoryBackend() { } + virtual ~DirectoryBackend() { } + + /** + * Open the directory + * @return true if the directory opened correctly + */ + virtual bool Open() = 0; + + /** + * List files contained in the directory + * @param count Number of entries to return at once in entries + * @param entries Buffer to read data into + * @return Number of entries listed + */ + virtual u32 Read(const u32 count, Entry* entries) = 0; + + /** + * Close the directory + * @return true if the directory closed correctly + */ + virtual bool Close() const = 0; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/directory_romfs.h b/src/core/file_sys/directory_romfs.h index e2944099..b775f014 100644 --- a/src/core/file_sys/directory_romfs.h +++ b/src/core/file_sys/directory_romfs.h @@ -6,7 +6,7 @@ #include "common/common_types.h" -#include "core/file_sys/directory.h" +#include "core/file_sys/directory_backend.h" #include "core/loader/loader.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -14,7 +14,7 @@ namespace FileSys { -class Directory_RomFS final : public Directory { +class Directory_RomFS final : public DirectoryBackend { public: Directory_RomFS(); ~Directory_RomFS() override; diff --git a/src/core/file_sys/directory_sdmc.h b/src/core/file_sys/directory_sdmc.h index 4c08b0d6..407a256e 100644 --- a/src/core/file_sys/directory_sdmc.h +++ b/src/core/file_sys/directory_sdmc.h @@ -7,7 +7,7 @@ #include "common/common_types.h" #include "common/file_util.h" -#include "core/file_sys/directory.h" +#include "core/file_sys/directory_backend.h" #include "core/file_sys/archive_sdmc.h" #include "core/loader/loader.h" @@ -16,7 +16,7 @@ namespace FileSys { -class Directory_SDMC final : public Directory { +class Directory_SDMC final : public DirectoryBackend { public: Directory_SDMC(); Directory_SDMC(const Archive_SDMC* archive, const Path& path); diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 6ec310a6..9a372513 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -10,7 +10,7 @@ #include "core/file_sys/archive_backend.h" #include "core/file_sys/archive_sdmc.h" -#include "core/file_sys/directory.h" +#include "core/file_sys/directory_backend.h" #include "core/hle/service/fs/archive.h" #include "core/hle/kernel/session.h" #include "core/hle/result.h" @@ -186,7 +186,7 @@ public: std::string GetName() const override { return "Directory: " + path.DebugStr(); } FileSys::Path path; ///< Path of the directory - std::unique_ptr backend; ///< File backend interface + std::unique_ptr backend; ///< File backend interface ResultVal SyncRequest() override { u32* cmd_buff = Kernel::GetCommandBuffer(); -- cgit v1.2.3 From 0931a42af0c0666dd9fbc20484b399c0e1ad3361 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Mon, 15 Dec 2014 05:03:17 -0200 Subject: Service.FS: Rename FileSys::File to FileBackend --- src/core/CMakeLists.txt | 2 +- src/core/file_sys/archive_backend.h | 4 +-- src/core/file_sys/archive_romfs.cpp | 4 +-- src/core/file_sys/archive_romfs.h | 2 +- src/core/file_sys/archive_sdmc.cpp | 4 +-- src/core/file_sys/archive_sdmc.h | 2 +- src/core/file_sys/file.h | 66 ------------------------------------- src/core/file_sys/file_backend.h | 66 +++++++++++++++++++++++++++++++++++++ src/core/file_sys/file_romfs.h | 4 +-- src/core/file_sys/file_sdmc.h | 4 +-- src/core/hle/service/fs/archive.cpp | 2 +- 11 files changed, 80 insertions(+), 80 deletions(-) delete mode 100644 src/core/file_sys/file.h create mode 100644 src/core/file_sys/file_backend.h (limited to 'src') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index c0ebd1c7..ce63aab0 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -96,7 +96,7 @@ set(HEADERS file_sys/archive_backend.h file_sys/archive_romfs.h file_sys/archive_sdmc.h - file_sys/file.h + file_sys/file_backend.h file_sys/file_romfs.h file_sys/file_sdmc.h file_sys/directory_backend.h diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index 49a31038..8d7a6a05 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h @@ -10,7 +10,7 @@ #include "common/string_util.h" #include "common/bit_field.h" -#include "core/file_sys/file.h" +#include "core/file_sys/file_backend.h" #include "core/file_sys/directory_backend.h" #include "core/mem_map.h" @@ -175,7 +175,7 @@ public: * @param mode Mode to open the file with * @return Opened file, or nullptr */ - virtual std::unique_ptr OpenFile(const Path& path, const Mode mode) const = 0; + virtual std::unique_ptr OpenFile(const Path& path, const Mode mode) const = 0; /** * Delete a file specified by its path diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index 8db7d69c..c515e0dd 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp @@ -29,8 +29,8 @@ Archive_RomFS::~Archive_RomFS() { * @param mode Mode to open the file with * @return Opened file, or nullptr */ -std::unique_ptr Archive_RomFS::OpenFile(const Path& path, const Mode mode) const { - return std::unique_ptr(new File_RomFS); +std::unique_ptr Archive_RomFS::OpenFile(const Path& path, const Mode mode) const { + return std::unique_ptr(new File_RomFS); } /** diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index 5a8a6b04..0390821b 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h @@ -30,7 +30,7 @@ public: * @param mode Mode to open the file with * @return Opened file, or nullptr */ - std::unique_ptr OpenFile(const Path& path, const Mode mode) const override; + std::unique_ptr OpenFile(const Path& path, const Mode mode) const override; /** * Delete a file specified by its path diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index 9d26d228..43252b98 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp @@ -49,12 +49,12 @@ bool Archive_SDMC::Initialize() { * @param mode Mode to open the file with * @return Opened file, or nullptr */ -std::unique_ptr Archive_SDMC::OpenFile(const Path& path, const Mode mode) const { +std::unique_ptr Archive_SDMC::OpenFile(const Path& path, const Mode mode) const { LOG_DEBUG(Service_FS, "called path=%s mode=%u", path.DebugStr().c_str(), mode.hex); File_SDMC* file = new File_SDMC(this, path, mode); if (!file->Open()) return nullptr; - return std::unique_ptr(file); + return std::unique_ptr(file); } /** diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index f4cb9615..5920051f 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h @@ -34,7 +34,7 @@ public: * @param mode Mode to open the file with * @return Opened file, or nullptr */ - std::unique_ptr OpenFile(const Path& path, const Mode mode) const override; + std::unique_ptr OpenFile(const Path& path, const Mode mode) const override; /** * Delete a file specified by its path diff --git a/src/core/file_sys/file.h b/src/core/file_sys/file.h deleted file mode 100644 index 4013b6c3..00000000 --- a/src/core/file_sys/file.h +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "common/common_types.h" - -#include "core/hle/kernel/kernel.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -class File : NonCopyable { -public: - File() { } - virtual ~File() { } - - /** - * Open the file - * @return true if the file opened correctly - */ - virtual bool Open() = 0; - - /** - * Read data from the file - * @param offset Offset in bytes to start reading data from - * @param length Length in bytes of data to read from file - * @param buffer Buffer to read data into - * @return Number of bytes read - */ - virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0; - - /** - * Write data to the file - * @param offset Offset in bytes to start writing data to - * @param length Length in bytes of data to write to file - * @param flush The flush parameters (0 == do not flush) - * @param buffer Buffer to read data from - * @return Number of bytes written - */ - virtual size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const = 0; - - /** - * Get the size of the file in bytes - * @return Size of the file in bytes - */ - virtual size_t GetSize() const = 0; - - /** - * Set the size of the file in bytes - * @param size New size of the file - * @return true if successful - */ - virtual bool SetSize(const u64 size) const = 0; - - /** - * Close the file - * @return true if the file closed correctly - */ - virtual bool Close() const = 0; -}; - -} // namespace FileSys diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h new file mode 100644 index 00000000..1b81d5fe --- /dev/null +++ b/src/core/file_sys/file_backend.h @@ -0,0 +1,66 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +#include "core/hle/kernel/kernel.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// FileSys namespace + +namespace FileSys { + +class FileBackend : NonCopyable { +public: + FileBackend() { } + virtual ~FileBackend() { } + + /** + * Open the file + * @return true if the file opened correctly + */ + virtual bool Open() = 0; + + /** + * Read data from the file + * @param offset Offset in bytes to start reading data from + * @param length Length in bytes of data to read from file + * @param buffer Buffer to read data into + * @return Number of bytes read + */ + virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0; + + /** + * Write data to the file + * @param offset Offset in bytes to start writing data to + * @param length Length in bytes of data to write to file + * @param flush The flush parameters (0 == do not flush) + * @param buffer Buffer to read data from + * @return Number of bytes written + */ + virtual size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const = 0; + + /** + * Get the size of the file in bytes + * @return Size of the file in bytes + */ + virtual size_t GetSize() const = 0; + + /** + * Set the size of the file in bytes + * @param size New size of the file + * @return true if successful + */ + virtual bool SetSize(const u64 size) const = 0; + + /** + * Close the file + * @return true if the file closed correctly + */ + virtual bool Close() const = 0; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h index 5196701d..4ddaafe2 100644 --- a/src/core/file_sys/file_romfs.h +++ b/src/core/file_sys/file_romfs.h @@ -6,7 +6,7 @@ #include "common/common_types.h" -#include "core/file_sys/file.h" +#include "core/file_sys/file_backend.h" #include "core/loader/loader.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -14,7 +14,7 @@ namespace FileSys { -class File_RomFS final : public File { +class File_RomFS final : public FileBackend { public: File_RomFS(); ~File_RomFS() override; diff --git a/src/core/file_sys/file_sdmc.h b/src/core/file_sys/file_sdmc.h index 80b44596..e0154859 100644 --- a/src/core/file_sys/file_sdmc.h +++ b/src/core/file_sys/file_sdmc.h @@ -7,7 +7,7 @@ #include "common/common_types.h" #include "common/file_util.h" -#include "core/file_sys/file.h" +#include "core/file_sys/file_backend.h" #include "core/file_sys/archive_sdmc.h" #include "core/loader/loader.h" @@ -16,7 +16,7 @@ namespace FileSys { -class File_SDMC final : public File { +class File_SDMC final : public FileBackend { public: File_SDMC(); File_SDMC(const Archive_SDMC* archive, const Path& path, const Mode mode); diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 9a372513..d04e5b2e 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -112,7 +112,7 @@ public: std::string GetName() const override { return "Path: " + path.DebugStr(); } FileSys::Path path; ///< Path of the file - std::unique_ptr backend; ///< File backend interface + std::unique_ptr backend; ///< File backend interface ResultVal SyncRequest() override { u32* cmd_buff = Kernel::GetCommandBuffer(); -- cgit v1.2.3 From 83e6e4ffec9ca67fbca5536bb0ed7b4876ade0db Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Mon, 15 Dec 2014 06:41:02 -0200 Subject: FS.Archive: Clean up treatment of archives and their handles - Refactor FS::Archive internals to make Archive creation and lifetime management clearer. - Remove the "Archive as a File" hack. - Implement 64-bit Archive handles. --- src/core/file_sys/archive_backend.h | 30 ----- src/core/file_sys/archive_romfs.cpp | 50 +------ src/core/file_sys/archive_romfs.h | 33 +---- src/core/file_sys/archive_sdmc.cpp | 41 ------ src/core/file_sys/archive_sdmc.h | 30 ----- src/core/file_sys/file_romfs.cpp | 19 ++- src/core/file_sys/file_romfs.h | 8 +- src/core/hle/service/fs/archive.cpp | 252 +++++++++++++++--------------------- src/core/hle/service/fs/archive.h | 26 ++-- src/core/hle/service/fs/fs_user.cpp | 93 ++++++++----- src/core/loader/loader.cpp | 2 +- 11 files changed, 197 insertions(+), 387 deletions(-) (limited to 'src') diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index 8d7a6a05..18c31488 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h @@ -220,36 +220,6 @@ public: * @return Opened directory, or nullptr */ virtual std::unique_ptr OpenDirectory(const Path& path) const = 0; - - /** - * Read data from the archive - * @param offset Offset in bytes to start reading data from - * @param length Length in bytes of data to read from archive - * @param buffer Buffer to read data into - * @return Number of bytes read - */ - virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0; - - /** - * Write data to the archive - * @param offset Offset in bytes to start writing data to - * @param length Length in bytes of data to write to archive - * @param buffer Buffer to write data from - * @param flush The flush parameters (0 == do not flush) - * @return Number of bytes written - */ - virtual size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) = 0; - - /** - * Get the size of the archive in bytes - * @return Size of the archive in bytes - */ - virtual size_t GetSize() const = 0; - - /** - * Set the size of the archive in bytes - */ - virtual void SetSize(const u64 size) = 0; }; } // namespace FileSys diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp index c515e0dd..0709b62a 100644 --- a/src/core/file_sys/archive_romfs.cpp +++ b/src/core/file_sys/archive_romfs.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 // Refer to the license.txt file included. +#include + #include "common/common_types.h" #include "core/file_sys/archive_romfs.h" @@ -20,9 +22,6 @@ Archive_RomFS::Archive_RomFS(const Loader::AppLoader& app_loader) { } } -Archive_RomFS::~Archive_RomFS() { -} - /** * Open a file specified by its path, using the specified mode * @param path Path relative to the archive @@ -30,7 +29,7 @@ Archive_RomFS::~Archive_RomFS() { * @return Opened file, or nullptr */ std::unique_ptr Archive_RomFS::OpenFile(const Path& path, const Mode mode) const { - return std::unique_ptr(new File_RomFS); + return std::make_unique(this); } /** @@ -79,48 +78,7 @@ bool Archive_RomFS::RenameDirectory(const FileSys::Path& src_path, const FileSys * @return Opened directory, or nullptr */ std::unique_ptr Archive_RomFS::OpenDirectory(const Path& path) const { - return std::unique_ptr(new Directory_RomFS); -} - -/** - * Read data from the archive - * @param offset Offset in bytes to start reading data from - * @param length Length in bytes of data to read from archive - * @param buffer Buffer to read data into - * @return Number of bytes read - */ -size_t Archive_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { - LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length); - memcpy(buffer, &raw_data[(u32)offset], length); - return length; -} - -/** - * Write data to the archive - * @param offset Offset in bytes to start writing data to - * @param length Length in bytes of data to write to archive - * @param buffer Buffer to write data from - * @param flush The flush parameters (0 == do not flush) - * @return Number of bytes written - */ -size_t Archive_RomFS::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) { - LOG_WARNING(Service_FS, "Attempted to write to ROMFS."); - return 0; -} - -/** - * Get the size of the archive in bytes - * @return Size of the archive in bytes - */ -size_t Archive_RomFS::GetSize() const { - return sizeof(u8) * raw_data.size(); -} - -/** - * Set the size of the archive in bytes - */ -void Archive_RomFS::SetSize(const u64 size) { - LOG_WARNING(Service_FS, "Attempted to set the size of ROMFS"); + return std::make_unique(); } } // namespace FileSys diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h index 0390821b..5b1ee633 100644 --- a/src/core/file_sys/archive_romfs.h +++ b/src/core/file_sys/archive_romfs.h @@ -20,7 +20,6 @@ namespace FileSys { class Archive_RomFS final : public ArchiveBackend { public: Archive_RomFS(const Loader::AppLoader& app_loader); - ~Archive_RomFS() override; std::string GetName() const override { return "RomFS"; } @@ -76,37 +75,9 @@ public: */ std::unique_ptr OpenDirectory(const Path& path) const override; - /** - * Read data from the archive - * @param offset Offset in bytes to start reading data from - * @param length Length in bytes of data to read from archive - * @param buffer Buffer to read data into - * @return Number of bytes read - */ - size_t Read(const u64 offset, const u32 length, u8* buffer) const override; - - /** - * Write data to the archive - * @param offset Offset in bytes to start writing data to - * @param length Length in bytes of data to write to archive - * @param buffer Buffer to write data from - * @param flush The flush parameters (0 == do not flush) - * @return Number of bytes written - */ - size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override; - - /** - * Get the size of the archive in bytes - * @return Size of the archive in bytes - */ - size_t GetSize() const override; - - /** - * Set the size of the archive in bytes - */ - void SetSize(const u64 size) override; - private: + friend class File_RomFS; + std::vector raw_data; }; diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp index 43252b98..9d58668e 100644 --- a/src/core/file_sys/archive_sdmc.cpp +++ b/src/core/file_sys/archive_sdmc.cpp @@ -105,47 +105,6 @@ std::unique_ptr Archive_SDMC::OpenDirectory(const Path& path) return std::unique_ptr(directory); } -/** - * Read data from the archive - * @param offset Offset in bytes to start reading archive from - * @param length Length in bytes to read data from archive - * @param buffer Buffer to read data into - * @return Number of bytes read - */ -size_t Archive_SDMC::Read(const u64 offset, const u32 length, u8* buffer) const { - LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); - return -1; -} - -/** - * Write data to the archive - * @param offset Offset in bytes to start writing data to - * @param length Length in bytes of data to write to archive - * @param buffer Buffer to write data from - * @param flush The flush parameters (0 == do not flush) - * @return Number of bytes written - */ -size_t Archive_SDMC::Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) { - LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); - return -1; -} - -/** - * Get the size of the archive in bytes - * @return Size of the archive in bytes - */ -size_t Archive_SDMC::GetSize() const { - LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); - return 0; -} - -/** - * Set the size of the archive in bytes - */ -void Archive_SDMC::SetSize(const u64 size) { - LOG_ERROR(Service_FS, "(UNIMPLEMENTED)"); -} - /** * Getter for the path used for this Archive * @return Mount point of that passthrough archive diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h index 5920051f..05904524 100644 --- a/src/core/file_sys/archive_sdmc.h +++ b/src/core/file_sys/archive_sdmc.h @@ -80,36 +80,6 @@ public: */ std::unique_ptr OpenDirectory(const Path& path) const override; - /** - * Read data from the archive - * @param offset Offset in bytes to start reading archive from - * @param length Length in bytes to read data from archive - * @param buffer Buffer to read data into - * @return Number of bytes read - */ - size_t Read(const u64 offset, const u32 length, u8* buffer) const override; - - /** - * Write data to the archive - * @param offset Offset in bytes to start writing data to - * @param length Length in bytes of data to write to archive - * @param buffer Buffer to write data from - * @param flush The flush parameters (0 == do not flush) - * @return Number of bytes written - */ - size_t Write(const u64 offset, const u32 length, const u32 flush, u8* buffer) override; - - /** - * Get the size of the archive in bytes - * @return Size of the archive in bytes - */ - size_t GetSize() const override; - - /** - * Set the size of the archive in bytes - */ - void SetSize(const u64 size) override; - /** * Getter for the path used for this Archive * @return Mount point of that passthrough archive diff --git a/src/core/file_sys/file_romfs.cpp b/src/core/file_sys/file_romfs.cpp index b55708df..5f38c270 100644 --- a/src/core/file_sys/file_romfs.cpp +++ b/src/core/file_sys/file_romfs.cpp @@ -5,24 +5,19 @@ #include "common/common_types.h" #include "core/file_sys/file_romfs.h" +#include "core/file_sys/archive_romfs.h" //////////////////////////////////////////////////////////////////////////////////////////////////// // FileSys namespace namespace FileSys { -File_RomFS::File_RomFS() { -} - -File_RomFS::~File_RomFS() { -} - /** * Open the file * @return true if the file opened correctly */ bool File_RomFS::Open() { - return false; + return true; } /** @@ -33,7 +28,9 @@ bool File_RomFS::Open() { * @return Number of bytes read */ size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { - return -1; + LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length); + memcpy(buffer, &archive->raw_data[(u32)offset], length); + return length; } /** @@ -45,7 +42,8 @@ size_t File_RomFS::Read(const u64 offset, const u32 length, u8* buffer) const { * @return Number of bytes written */ size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { - return -1; + LOG_WARNING(Service_FS, "Attempted to write to ROMFS."); + return 0; } /** @@ -53,7 +51,7 @@ size_t File_RomFS::Write(const u64 offset, const u32 length, const u32 flush, co * @return Size of the file in bytes */ size_t File_RomFS::GetSize() const { - return -1; + return sizeof(u8) * archive->raw_data.size(); } /** @@ -62,6 +60,7 @@ size_t File_RomFS::GetSize() const { * @return true if successful */ bool File_RomFS::SetSize(const u64 size) const { + LOG_WARNING(Service_FS, "Attempted to set the size of ROMFS"); return false; } diff --git a/src/core/file_sys/file_romfs.h b/src/core/file_sys/file_romfs.h index 4ddaafe2..09fa2e7e 100644 --- a/src/core/file_sys/file_romfs.h +++ b/src/core/file_sys/file_romfs.h @@ -14,10 +14,11 @@ namespace FileSys { +class Archive_RomFS; + class File_RomFS final : public FileBackend { public: - File_RomFS(); - ~File_RomFS() override; + File_RomFS(const Archive_RomFS* archive) : archive(archive) {} /** * Open the file @@ -62,6 +63,9 @@ public: * @return true if the file closed correctly */ bool Close() const override; + +private: + const Archive_RomFS* archive; }; } // namespace FileSys diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index d04e5b2e..a4ee7a15 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -2,7 +2,8 @@ // Licensed under GPLv2 // Refer to the license.txt file included. -#include +#include +#include #include "common/common_types.h" #include "common/file_util.h" @@ -41,74 +42,24 @@ enum class DirectoryCommand : u32 { Close = 0x08020000, }; -class Archive : public Kernel::Session { +class Archive { public: - std::string GetName() const override { return "Archive: " + backend->GetName(); } - - ArchiveIdCode id_code; ///< Id code of the archive - FileSys::ArchiveBackend* backend; ///< Archive backend interface - - ResultVal SyncRequest() override { - u32* cmd_buff = Kernel::GetCommandBuffer(); - FileCommand cmd = static_cast(cmd_buff[0]); - - switch (cmd) { - // Read from archive... - case FileCommand::Read: - { - u64 offset = cmd_buff[1] | ((u64)cmd_buff[2] << 32); - u32 length = cmd_buff[3]; - u32 address = cmd_buff[5]; + Archive(std::unique_ptr&& backend, ArchiveIdCode id_code) + : backend(std::move(backend)), id_code(id_code) { + } - // Number of bytes read - cmd_buff[2] = backend->Read(offset, length, Memory::GetPointer(address)); - break; - } - // Write to archive... - case FileCommand::Write: - { - u64 offset = cmd_buff[1] | ((u64)cmd_buff[2] << 32); - u32 length = cmd_buff[3]; - u32 flush = cmd_buff[4]; - u32 address = cmd_buff[6]; + std::string GetName() const { return "Archive: " + backend->GetName(); } - // Number of bytes written - cmd_buff[2] = backend->Write(offset, length, flush, Memory::GetPointer(address)); - break; - } - case FileCommand::GetSize: - { - u64 filesize = (u64) backend->GetSize(); - cmd_buff[2] = (u32) filesize; // Lower word - cmd_buff[3] = (u32) (filesize >> 32); // Upper word - break; - } - case FileCommand::SetSize: - { - backend->SetSize(cmd_buff[1] | ((u64)cmd_buff[2] << 32)); - break; - } - case FileCommand::Close: - { - LOG_TRACE(Service_FS, "Close %s %s", GetTypeName().c_str(), GetName().c_str()); - CloseArchive(id_code); - break; - } - // Unknown command... - default: - { - LOG_ERROR(Service_FS, "Unknown command=0x%08X", cmd); - cmd_buff[0] = UnimplementedFunction(ErrorModule::FS).raw; - return MakeResult(false); - } - } - cmd_buff[1] = 0; // No error - return MakeResult(false); - } + ArchiveIdCode id_code; ///< Id code of the archive + std::unique_ptr backend; ///< Archive backend interface }; class File : public Kernel::Session { public: + File(std::unique_ptr&& backend, const FileSys::Path& path) + : backend(std::move(backend)), path(path) { + } + std::string GetName() const override { return "Path: " + path.DebugStr(); } FileSys::Path path; ///< Path of the file @@ -183,6 +134,10 @@ public: class Directory : public Kernel::Session { public: + Directory(std::unique_ptr&& backend, const FileSys::Path& path) + : backend(std::move(backend)), path(path) { + } + std::string GetName() const override { return "Directory: " + path.DebugStr(); } FileSys::Path path; ///< Path of the directory @@ -228,105 +183,95 @@ public: //////////////////////////////////////////////////////////////////////////////////////////////////// -std::map g_archive_map; ///< Map of file archives by IdCode +/** + * Map of registered archives, identified by id code. Once an archive is registered here, it is + * never removed until the FS service is shut down. + */ +static std::unordered_map> id_code_map; -ResultVal OpenArchive(ArchiveIdCode id_code) { - auto itr = g_archive_map.find(id_code); - if (itr == g_archive_map.end()) { +/** + * Map of active archive handles. Values are pointers to the archives in `idcode_map`. + */ +static std::unordered_map handle_map; +static ArchiveHandle next_handle; + +static Archive* GetArchive(ArchiveHandle handle) { + auto itr = handle_map.find(handle); + return (itr == handle_map.end()) ? nullptr : itr->second; +} + +ResultVal OpenArchive(ArchiveIdCode id_code) { + LOG_TRACE(Service_FS, "Opening archive with id code 0x%08X", id_code); + + auto itr = id_code_map.find(id_code); + if (itr == id_code_map.end()) { + // TODO: Verify error against hardware return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Permanent); } - return MakeResult(itr->second); + // This should never even happen in the first place with 64-bit handles, + while (handle_map.count(next_handle) != 0) { + ++next_handle; + } + handle_map.emplace(next_handle, itr->second.get()); + return MakeResult(next_handle++); } -ResultCode CloseArchive(ArchiveIdCode id_code) { - auto itr = g_archive_map.find(id_code); - if (itr == g_archive_map.end()) { - LOG_ERROR(Service_FS, "Cannot close archive %d, does not exist!", (int)id_code); +ResultCode CloseArchive(ArchiveHandle handle) { + if (handle_map.erase(handle) == 0) return InvalidHandle(ErrorModule::FS); - } - - LOG_TRACE(Service_FS, "Closed archive %d", (int) id_code); - return RESULT_SUCCESS; + else + return RESULT_SUCCESS; } -/** - * Mounts an archive - * @param archive Pointer to the archive to mount - */ -ResultCode MountArchive(Archive* archive) { - ArchiveIdCode id_code = archive->id_code; - ResultVal archive_handle = OpenArchive(id_code); - if (archive_handle.Succeeded()) { - LOG_ERROR(Service_FS, "Cannot mount two archives with the same ID code! (%d)", (int) id_code); - return archive_handle.Code(); - } - g_archive_map[id_code] = archive->GetHandle(); - LOG_TRACE(Service_FS, "Mounted archive %s", archive->GetName().c_str()); - return RESULT_SUCCESS; -} +// TODO(yuriks): This might be what the fs:REG service is for. See the Register/Unregister calls in +// http://3dbrew.org/wiki/Filesystem_services#ProgramRegistry_service_.22fs:REG.22 +ResultCode CreateArchive(std::unique_ptr&& backend, ArchiveIdCode id_code) { + auto result = id_code_map.emplace(id_code, std::make_unique(std::move(backend), id_code)); -ResultCode CreateArchive(FileSys::ArchiveBackend* backend, ArchiveIdCode id_code) { - Archive* archive = new Archive; - Handle handle = Kernel::g_object_pool.Create(archive); - archive->id_code = id_code; - archive->backend = backend; + bool inserted = result.second; + _dbg_assert_msg_(Service_FS, inserted, "Tried to register more than one archive with same id code"); - ResultCode result = MountArchive(archive); - if (result.IsError()) { - return result; - } - + auto& archive = result.first->second; + LOG_DEBUG(Service_FS, "Registered archive %s with id code 0x%08X", archive->GetName().c_str(), id_code); return RESULT_SUCCESS; } -ResultVal OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { - // TODO(bunnei): Binary type files get a raw file pointer to the archive. Currently, we create - // the archive file handles at app loading, and then keep them persistent throughout execution. - // Archives file handles are just reused and not actually freed until emulation shut down. - // Verify if real hardware works this way, or if new handles are created each time - if (path.GetType() == FileSys::Binary) - // TODO(bunnei): FixMe - this is a hack to compensate for an incorrect FileSys backend - // design. While the functionally of this is OK, our implementation decision to separate - // normal files from archive file pointers is very likely wrong. - // See https://github.com/citra-emu/citra/issues/205 - return MakeResult(archive_handle); - - File* file = new File; - Handle handle = Kernel::g_object_pool.Create(file); - - Archive* archive = Kernel::g_object_pool.Get(archive_handle); - if (archive == nullptr) { +ResultVal OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode) { + Archive* archive = GetArchive(archive_handle); + if (archive == nullptr) return InvalidHandle(ErrorModule::FS); - } - file->path = path; - file->backend = archive->backend->OpenFile(path, mode); - if (!file->backend) { + std::unique_ptr backend = archive->backend->OpenFile(path, mode); + if (backend == nullptr) { return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, - ErrorSummary::NotFound, ErrorLevel::Permanent); + ErrorSummary::NotFound, ErrorLevel::Permanent); } + auto file = std::make_unique(std::move(backend), path); + Handle handle = Kernel::g_object_pool.Create(file.release()); return MakeResult(handle); } -ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path) { - Archive* archive = Kernel::g_object_pool.GetFast(archive_handle); +ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { + Archive* archive = GetArchive(archive_handle); if (archive == nullptr) return InvalidHandle(ErrorModule::FS); + if (archive->backend->DeleteFile(path)) return RESULT_SUCCESS; return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description ErrorSummary::Canceled, ErrorLevel::Status); } -ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, - Handle dest_archive_handle, const FileSys::Path& dest_path) { - Archive* src_archive = Kernel::g_object_pool.GetFast(src_archive_handle); - Archive* dest_archive = Kernel::g_object_pool.GetFast(dest_archive_handle); +ResultCode RenameFileBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, + ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { + Archive* src_archive = GetArchive(src_archive_handle); + Archive* dest_archive = GetArchive(dest_archive_handle); if (src_archive == nullptr || dest_archive == nullptr) return InvalidHandle(ErrorModule::FS); + if (src_archive == dest_archive) { if (src_archive->backend->RenameFile(src_path, dest_path)) return RESULT_SUCCESS; @@ -334,36 +279,42 @@ ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::P // TODO: Implement renaming across archives return UnimplementedFunction(ErrorModule::FS); } + + // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't + // exist or similar. Verify. return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description ErrorSummary::NothingHappened, ErrorLevel::Status); } -ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { - Archive* archive = Kernel::g_object_pool.GetFast(archive_handle); +ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { + Archive* archive = GetArchive(archive_handle); if (archive == nullptr) return InvalidHandle(ErrorModule::FS); + if (archive->backend->DeleteDirectory(path)) return RESULT_SUCCESS; return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description ErrorSummary::Canceled, ErrorLevel::Status); } -ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { - Archive* archive = Kernel::g_object_pool.GetFast(archive_handle); +ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { + Archive* archive = GetArchive(archive_handle); if (archive == nullptr) return InvalidHandle(ErrorModule::FS); + if (archive->backend->CreateDirectory(path)) return RESULT_SUCCESS; return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description ErrorSummary::Canceled, ErrorLevel::Status); } -ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, - Handle dest_archive_handle, const FileSys::Path& dest_path) { - Archive* src_archive = Kernel::g_object_pool.GetFast(src_archive_handle); - Archive* dest_archive = Kernel::g_object_pool.GetFast(dest_archive_handle); +ResultCode RenameDirectoryBetweenArchives(ArchiveHandle src_archive_handle, const FileSys::Path& src_path, + ArchiveHandle dest_archive_handle, const FileSys::Path& dest_path) { + Archive* src_archive = GetArchive(src_archive_handle); + Archive* dest_archive = GetArchive(dest_archive_handle); if (src_archive == nullptr || dest_archive == nullptr) return InvalidHandle(ErrorModule::FS); + if (src_archive == dest_archive) { if (src_archive->backend->RenameDirectory(src_path, dest_path)) return RESULT_SUCCESS; @@ -371,6 +322,9 @@ ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileS // TODO: Implement renaming across archives return UnimplementedFunction(ErrorModule::FS); } + + // TODO(yuriks): This code probably isn't right, it'll return a Status even if the file didn't + // exist or similar. Verify. return ResultCode(ErrorDescription::NoData, ErrorModule::FS, // TODO: verify description ErrorSummary::NothingHappened, ErrorLevel::Status); } @@ -381,44 +335,42 @@ ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileS * @param path Path to the Directory inside of the Archive * @return Opened Directory object */ -ResultVal OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path) { - Directory* directory = new Directory; - Handle handle = Kernel::g_object_pool.Create(directory); - - Archive* archive = Kernel::g_object_pool.Get(archive_handle); - if (archive == nullptr) { +ResultVal OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path) { + Archive* archive = GetArchive(archive_handle); + if (archive == nullptr) return InvalidHandle(ErrorModule::FS); - } - directory->path = path; - directory->backend = archive->backend->OpenDirectory(path); - if (!directory->backend) { + std::unique_ptr backend = archive->backend->OpenDirectory(path); + if (backend == nullptr) { return ResultCode(ErrorDescription::NotFound, ErrorModule::FS, ErrorSummary::NotFound, ErrorLevel::Permanent); } + auto directory = std::make_unique(std::move(backend), path); + Handle handle = Kernel::g_object_pool.Create(directory.release()); return MakeResult(handle); } /// Initialize archives void ArchiveInit() { - g_archive_map.clear(); + next_handle = 1; // TODO(Link Mauve): Add the other archive types (see here for the known types: // http://3dbrew.org/wiki/FS:OpenArchive#Archive_idcodes). Currently the only half-finished // archive type is SDMC, so it is the only one getting exposed. std::string sdmc_directory = FileUtil::GetUserPath(D_SDMC_IDX); - auto archive = new FileSys::Archive_SDMC(sdmc_directory); + auto archive = std::make_unique(sdmc_directory); if (archive->Initialize()) - CreateArchive(archive, ArchiveIdCode::SDMC); + CreateArchive(std::move(archive), ArchiveIdCode::SDMC); else LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); } /// Shutdown archives void ArchiveShutdown() { - g_archive_map.clear(); + handle_map.clear(); + id_code_map.clear(); } } // namespace FS diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index 2c50dfff..a38de92e 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -24,25 +24,27 @@ enum class ArchiveIdCode : u32 { SDMCWriteOnly = 0x0000000A, }; +typedef u64 ArchiveHandle; + /** * Opens an archive * @param id_code IdCode of the archive to open * @return Handle to the opened archive */ -ResultVal OpenArchive(ArchiveIdCode id_code); +ResultVal OpenArchive(ArchiveIdCode id_code); /** * Closes an archive * @param id_code IdCode of the archive to open */ -ResultCode CloseArchive(ArchiveIdCode id_code); +ResultCode CloseArchive(ArchiveHandle handle); /** * Creates an Archive * @param backend File system backend interface to the archive * @param id_code Id code used to access this type of archive */ -ResultCode CreateArchive(FileSys::ArchiveBackend* backend, ArchiveIdCode id_code); +ResultCode CreateArchive(std::unique_ptr&& backend, ArchiveIdCode id_code); /** * Open a File from an Archive @@ -51,7 +53,7 @@ ResultCode CreateArchive(FileSys::ArchiveBackend* backend, ArchiveIdCode id_code * @param mode Mode under which to open the File * @return Handle to the opened File object */ -ResultVal OpenFileFromArchive(Handle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); +ResultVal OpenFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path, const FileSys::Mode mode); /** * Delete a File from an Archive @@ -59,7 +61,7 @@ ResultVal OpenFileFromArchive(Handle archive_handle, const FileSys::Path * @param path Path to the File inside of the Archive * @return Whether deletion succeeded */ -ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& path); +ResultCode DeleteFileFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); /** * Rename a File between two Archives @@ -69,8 +71,8 @@ ResultCode DeleteFileFromArchive(Handle archive_handle, const FileSys::Path& pat * @param dest_path Path to the File inside of the destination Archive * @return Whether rename succeeded */ -ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, - Handle dest_archive_handle, const FileSys::Path& dest_path); +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 @@ -78,7 +80,7 @@ ResultCode RenameFileBetweenArchives(Handle src_archive_handle, const FileSys::P * @param path Path to the Directory inside of the Archive * @return Whether deletion succeeded */ -ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); +ResultCode DeleteDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); /** * Create a Directory from an Archive @@ -86,7 +88,7 @@ ResultCode DeleteDirectoryFromArchive(Handle archive_handle, const FileSys::Path * @param path Path to the Directory inside of the Archive * @return Whether creation of directory succeeded */ -ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); +ResultCode CreateDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); /** * Rename a Directory between two Archives @@ -96,8 +98,8 @@ ResultCode CreateDirectoryFromArchive(Handle archive_handle, const FileSys::Path * @param dest_path Path to the Directory inside of the destination Archive * @return Whether rename succeeded */ -ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileSys::Path& src_path, - Handle dest_archive_handle, const FileSys::Path& dest_path); +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 @@ -105,7 +107,7 @@ ResultCode RenameDirectoryBetweenArchives(Handle src_archive_handle, const FileS * @param path Path to the Directory inside of the Archive * @return Handle to the opened File object */ -ResultVal OpenDirectoryFromArchive(Handle archive_handle, const FileSys::Path& path); +ResultVal OpenDirectoryFromArchive(ArchiveHandle archive_handle, const FileSys::Path& path); /// Initialize archives void ArchiveInit(); diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index eda7cb8a..0f75d5e3 100644 --- a/src/core/hle/service/fs/fs_user.cpp +++ b/src/core/hle/service/fs/fs_user.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included. #include "common/common.h" +#include "common/scope_exit.h" #include "common/string_util.h" #include "core/hle/service/fs/archive.h" @@ -16,6 +17,10 @@ namespace Service { namespace FS { +static ArchiveHandle MakeArchiveHandle(u32 low_word, u32 high_word) { + return (u64)low_word | ((u64)high_word << 32); +} + static void Initialize(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); @@ -62,6 +67,7 @@ static void OpenFile(Service::Interface* self) { if (handle.Succeeded()) { cmd_buff[3] = *handle; } else { + cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); } } @@ -106,25 +112,25 @@ static void OpenFileDirectly(Service::Interface* self) { if (archive_path.GetType() != FileSys::Empty) { LOG_ERROR(Service_FS, "archive LowPath type other than empty is currently unsupported"); cmd_buff[1] = UnimplementedFunction(ErrorModule::FS).raw; + cmd_buff[3] = 0; return; } - // TODO(Link Mauve): Check if we should even get a handle for the archive, and don't leak it - // TODO(yuriks): Why is there all this duplicate (and seemingly useless) code up here? - ResultVal archive_handle = OpenArchive(archive_id); - cmd_buff[1] = archive_handle.Code().raw; + ResultVal archive_handle = OpenArchive(archive_id); if (archive_handle.Failed()) { LOG_ERROR(Service_FS, "failed to get a handle for archive"); + cmd_buff[1] = archive_handle.Code().raw; + cmd_buff[3] = 0; return; } - // cmd_buff[2] isn't used according to 3dmoo's implementation. - cmd_buff[3] = *archive_handle; + SCOPE_EXIT({ CloseArchive(*archive_handle); }); ResultVal handle = OpenFileFromArchive(*archive_handle, file_path, mode); cmd_buff[1] = handle.Code().raw; if (handle.Succeeded()) { cmd_buff[3] = *handle; } else { + cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); } } @@ -140,12 +146,10 @@ static void OpenFileDirectly(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -void DeleteFile(Service::Interface* self) { +static void DeleteFile(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to - // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. - Handle archive_handle = static_cast(cmd_buff[3]); + ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); auto filename_type = static_cast(cmd_buff[4]); u32 filename_size = cmd_buff[5]; u32 filename_ptr = cmd_buff[7]; @@ -174,15 +178,13 @@ void DeleteFile(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -void RenameFile(Service::Interface* self) { +static void RenameFile(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - // TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to - // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. - Handle src_archive_handle = static_cast(cmd_buff[3]); + ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); auto src_filename_type = static_cast(cmd_buff[4]); u32 src_filename_size = cmd_buff[5]; - Handle dest_archive_handle = static_cast(cmd_buff[7]); + ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]);; auto dest_filename_type = static_cast(cmd_buff[8]); u32 dest_filename_size = cmd_buff[9]; u32 src_filename_ptr = cmd_buff[11]; @@ -209,12 +211,10 @@ void RenameFile(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -void DeleteDirectory(Service::Interface* self) { +static void DeleteDirectory(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to - // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. - Handle archive_handle = static_cast(cmd_buff[3]); + ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); auto dirname_type = static_cast(cmd_buff[4]); u32 dirname_size = cmd_buff[5]; u32 dirname_ptr = cmd_buff[7]; @@ -241,9 +241,7 @@ void DeleteDirectory(Service::Interface* self) { static void CreateDirectory(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - // TODO: cmd_buff[2], aka archive handle lower word, isn't used according to - // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. - Handle archive_handle = static_cast(cmd_buff[3]); + ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); auto dirname_type = static_cast(cmd_buff[4]); u32 dirname_size = cmd_buff[5]; u32 dirname_ptr = cmd_buff[8]; @@ -271,15 +269,13 @@ static void CreateDirectory(Service::Interface* self) { * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ -void RenameDirectory(Service::Interface* self) { +static void RenameDirectory(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - // TODO(Link Mauve): cmd_buff[2] and cmd_buff[6], aka archive handle lower word, aren't used according to - // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. - Handle src_archive_handle = static_cast(cmd_buff[3]); + ArchiveHandle src_archive_handle = MakeArchiveHandle(cmd_buff[2], cmd_buff[3]); auto src_dirname_type = static_cast(cmd_buff[4]); u32 src_dirname_size = cmd_buff[5]; - Handle dest_archive_handle = static_cast(cmd_buff[7]); + ArchiveHandle dest_archive_handle = MakeArchiveHandle(cmd_buff[6], cmd_buff[7]); auto dest_dirname_type = static_cast(cmd_buff[8]); u32 dest_dirname_size = cmd_buff[9]; u32 src_dirname_ptr = cmd_buff[11]; @@ -295,12 +291,23 @@ void RenameDirectory(Service::Interface* self) { cmd_buff[1] = RenameDirectoryBetweenArchives(src_archive_handle, src_dir_path, dest_archive_handle, dest_dir_path).raw; } +/** + * FS_User::OpenDirectory service function + * Inputs: + * 1 : Archive handle low word + * 2 : Archive handle high word + * 3 : Low path type + * 4 : Low path size + * 7 : (LowPathSize << 14) | 2 + * 8 : Low path data pointer + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 3 : Directory handle + */ static void OpenDirectory(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - // TODO(Link Mauve): cmd_buff[2], aka archive handle lower word, isn't used according to - // 3dmoo's or ctrulib's implementations. Triple check if it's really the case. - Handle archive_handle = static_cast(cmd_buff[2]); + ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]); auto dirname_type = static_cast(cmd_buff[3]); u32 dirname_size = cmd_buff[4]; u32 dirname_ptr = cmd_buff[6]; @@ -348,16 +355,34 @@ static void OpenArchive(Service::Interface* self) { return; } - ResultVal handle = OpenArchive(archive_id); + ResultVal handle = OpenArchive(archive_id); cmd_buff[1] = handle.Code().raw; if (handle.Succeeded()) { - // cmd_buff[2] isn't used according to 3dmoo's implementation. - cmd_buff[3] = *handle; + cmd_buff[2] = *handle & 0xFFFFFFFF; + cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF; } else { + cmd_buff[2] = cmd_buff[3] = 0; LOG_ERROR(Service_FS, "failed to get a handle for archive"); } } +/** + * FS_User::CloseArchive service function + * Inputs: + * 0 : 0x080E0080 + * 1 : Archive handle low word + * 2 : Archive handle high word + * Outputs: + * 0 : ??? TODO(yuriks): Verify return header + * 1 : Result of function, 0 on success, otherwise error code + */ +static void CloseArchive(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + ArchiveHandle archive_handle = MakeArchiveHandle(cmd_buff[1], cmd_buff[2]); + cmd_buff[1] = CloseArchive(archive_handle).raw; +} + /* * FS_User::IsSdmcDetected service function * Outputs: @@ -389,7 +414,7 @@ const FSUserInterface::FunctionInfo FunctionTable[] = { {0x080B0102, OpenDirectory, "OpenDirectory"}, {0x080C00C2, OpenArchive, "OpenArchive"}, {0x080D0144, nullptr, "ControlArchive"}, - {0x080E0080, nullptr, "CloseArchive"}, + {0x080E0080, CloseArchive, "CloseArchive"}, {0x080F0180, nullptr, "FormatThisUserSaveData"}, {0x08100200, nullptr, "CreateSystemSaveData"}, {0x08110040, nullptr, "DeleteSystemSaveData"}, diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 49f8c458..463dacca 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -74,7 +74,7 @@ ResultStatus LoadFile(const std::string& filename) { // Load application and RomFS if (ResultStatus::Success == app_loader.Load()) { - Service::FS::CreateArchive(new FileSys::Archive_RomFS(app_loader), Service::FS::ArchiveIdCode::RomFS); + Service::FS::CreateArchive(std::make_unique(app_loader), Service::FS::ArchiveIdCode::RomFS); return ResultStatus::Success; } break; -- cgit v1.2.3 From 666f6deb47774ad101710f619fb9ac66514b3012 Mon Sep 17 00:00:00 2001 From: Yuri Kunde Schlesner Date: Mon, 15 Dec 2014 22:06:23 -0200 Subject: Work around libstdc++'s lack of support for std::hash on enums --- src/core/hle/service/fs/archive.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src') diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index a4ee7a15..caf82d55 100644 --- a/src/core/hle/service/fs/archive.cpp +++ b/src/core/hle/service/fs/archive.cpp @@ -16,6 +16,21 @@ #include "core/hle/kernel/session.h" #include "core/hle/result.h" +// Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map. +// Workaroung for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970 +namespace std { + template <> + struct hash { + typedef Service::FS::ArchiveIdCode argument_type; + typedef std::size_t result_type; + + result_type operator()(const argument_type& id_code) const { + typedef std::underlying_type::type Type; + return std::hash()(static_cast(id_code)); + } + }; +} + namespace Service { namespace FS { -- cgit v1.2.3