From 2f71a32363ba062f42938091acdf11962cba932e Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 19 Jan 2018 21:45:07 -0500 Subject: [PATCH 1/8] file_sys: Repurpose 3DS IVFC code for Switch ROMFS. --- src/core/CMakeLists.txt | 4 +- .../{ivfc_archive.cpp => romfs_archive.cpp} | 69 +++++++++---------- .../{ivfc_archive.h => romfs_archive.h} | 21 +++--- 3 files changed, 43 insertions(+), 51 deletions(-) rename src/core/file_sys/{ivfc_archive.cpp => romfs_archive.cpp} (50%) rename src/core/file_sys/{ivfc_archive.h => romfs_archive.h} (75%) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7153c4f3f..ec25ec9cf 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -13,10 +13,10 @@ add_library(core STATIC file_sys/disk_archive.h file_sys/errors.h file_sys/file_backend.h - file_sys/ivfc_archive.cpp - file_sys/ivfc_archive.h file_sys/path_parser.cpp file_sys/path_parser.h + file_sys/romfs_archive.cpp + file_sys/romfs_archive.h file_sys/savedata_archive.cpp file_sys/savedata_archive.h file_sys/title_metadata.cpp diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/romfs_archive.cpp similarity index 50% rename from src/core/file_sys/ivfc_archive.cpp rename to src/core/file_sys/romfs_archive.cpp index b3c3f2c6f..482de2220 100644 --- a/src/core/file_sys/ivfc_archive.cpp +++ b/src/core/file_sys/romfs_archive.cpp @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2018 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -6,84 +6,79 @@ #include #include "common/common_types.h" #include "common/logging/log.h" -#include "core/file_sys/ivfc_archive.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace +#include "core/file_sys/romfs_archive.h" namespace FileSys { -std::string IVFCArchive::GetName() const { - return "IVFC"; +std::string ROMFSArchive::GetName() const { + return "RomFS"; } -ResultVal> IVFCArchive::OpenFile(const Path& path, - const Mode& mode) const { +ResultVal> ROMFSArchive::OpenFile(const Path& path, + const Mode& mode) const { return MakeResult>( - std::make_unique(romfs_file, data_offset, data_size)); + std::make_unique(romfs_file, data_offset, data_size)); } -ResultCode IVFCArchive::DeleteFile(const Path& path) const { - LOG_CRITICAL(Service_FS, "Attempted to delete a file from an IVFC archive (%s).", +ResultCode ROMFSArchive::DeleteFile(const Path& path) const { + LOG_CRITICAL(Service_FS, "Attempted to delete a file from an ROMFS archive (%s).", GetName().c_str()); // TODO(bunnei): Use correct error code return ResultCode(-1); } -ResultCode IVFCArchive::RenameFile(const Path& src_path, const Path& dest_path) const { - LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive (%s).", +ResultCode ROMFSArchive::RenameFile(const Path& src_path, const Path& dest_path) const { + LOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive (%s).", GetName().c_str()); // TODO(wwylele): Use correct error code return ResultCode(-1); } -ResultCode IVFCArchive::DeleteDirectory(const Path& path) const { - LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive (%s).", +ResultCode ROMFSArchive::DeleteDirectory(const Path& path) const { + LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive (%s).", GetName().c_str()); // TODO(wwylele): Use correct error code return ResultCode(-1); } -ResultCode IVFCArchive::DeleteDirectoryRecursively(const Path& path) const { - LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an IVFC archive (%s).", +ResultCode ROMFSArchive::DeleteDirectoryRecursively(const Path& path) const { + LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive (%s).", GetName().c_str()); // TODO(wwylele): Use correct error code return ResultCode(-1); } -ResultCode IVFCArchive::CreateFile(const Path& path, u64 size) const { - LOG_CRITICAL(Service_FS, "Attempted to create a file in an IVFC archive (%s).", +ResultCode ROMFSArchive::CreateFile(const Path& path, u64 size) const { + LOG_CRITICAL(Service_FS, "Attempted to create a file in an ROMFS archive (%s).", GetName().c_str()); // TODO(bunnei): Use correct error code return ResultCode(-1); } -ResultCode IVFCArchive::CreateDirectory(const Path& path) const { - LOG_CRITICAL(Service_FS, "Attempted to create a directory in an IVFC archive (%s).", +ResultCode ROMFSArchive::CreateDirectory(const Path& path) const { + LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive (%s).", GetName().c_str()); // TODO(wwylele): Use correct error code return ResultCode(-1); } -ResultCode IVFCArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const { - LOG_CRITICAL(Service_FS, "Attempted to rename a file within an IVFC archive (%s).", +ResultCode ROMFSArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const { + LOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive (%s).", GetName().c_str()); // TODO(wwylele): Use correct error code return ResultCode(-1); } -ResultVal> IVFCArchive::OpenDirectory(const Path& path) const { - return MakeResult>(std::make_unique()); +ResultVal> ROMFSArchive::OpenDirectory(const Path& path) const { + return MakeResult>(std::make_unique()); } -u64 IVFCArchive::GetFreeBytes() const { - LOG_WARNING(Service_FS, "Attempted to get the free space in an IVFC archive"); +u64 ROMFSArchive::GetFreeBytes() const { + LOG_WARNING(Service_FS, "Attempted to get the free space in an ROMFS archive"); return 0; } -//////////////////////////////////////////////////////////////////////////////////////////////////// - -ResultVal IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const { +ResultVal ROMFSFile::Read(const u64 offset, const size_t length, u8* buffer) const { LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length); romfs_file->Seek(data_offset + offset, SEEK_SET); size_t read_length = (size_t)std::min((u64)length, data_size - offset); @@ -91,19 +86,19 @@ ResultVal IVFCFile::Read(const u64 offset, const size_t length, u8* buff return MakeResult(romfs_file->ReadBytes(buffer, read_length)); } -ResultVal IVFCFile::Write(const u64 offset, const size_t length, const bool flush, - const u8* buffer) const { - LOG_ERROR(Service_FS, "Attempted to write to IVFC file"); +ResultVal ROMFSFile::Write(const u64 offset, const size_t length, const bool flush, + const u8* buffer) const { + LOG_ERROR(Service_FS, "Attempted to write to ROMFS file"); // TODO(Subv): Find error code return MakeResult(0); } -u64 IVFCFile::GetSize() const { +u64 ROMFSFile::GetSize() const { return data_size; } -bool IVFCFile::SetSize(const u64 size) const { - LOG_ERROR(Service_FS, "Attempted to set the size of an IVFC file"); +bool ROMFSFile::SetSize(const u64 size) const { + LOG_ERROR(Service_FS, "Attempted to set the size of an ROMFS file"); return false; } diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/romfs_archive.h similarity index 75% rename from src/core/file_sys/ivfc_archive.h rename to src/core/file_sys/romfs_archive.h index e6fbdfb1f..2bb13146b 100644 --- a/src/core/file_sys/ivfc_archive.h +++ b/src/core/file_sys/romfs_archive.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2018 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -15,19 +15,16 @@ #include "core/file_sys/file_backend.h" #include "core/hle/result.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - namespace FileSys { /** - * Helper which implements an interface to deal with IVFC images used in some archives - * This should be subclassed by concrete archive types, which will provide the - * input data (load the raw IVFC archive) and override any required methods + * Helper which implements an interface to deal with Switch .istorage ROMFS images used in some + * archives This should be subclassed by concrete archive types, which will provide the input data + * (load the raw ROMFS archive) and override any required methods */ -class IVFCArchive : public ArchiveBackend { +class ROMFSArchive : public ArchiveBackend { public: - IVFCArchive(std::shared_ptr file, u64 offset, u64 size) + ROMFSArchive(std::shared_ptr file, u64 offset, u64 size) : romfs_file(file), data_offset(offset), data_size(size) {} std::string GetName() const override; @@ -50,9 +47,9 @@ protected: u64 data_size; }; -class IVFCFile : public FileBackend { +class ROMFSFile : public FileBackend { public: - IVFCFile(std::shared_ptr file, u64 offset, u64 size) + ROMFSFile(std::shared_ptr file, u64 offset, u64 size) : romfs_file(file), data_offset(offset), data_size(size) {} ResultVal Read(u64 offset, size_t length, u8* buffer) const override; @@ -70,7 +67,7 @@ private: u64 data_size; }; -class IVFCDirectory : public DirectoryBackend { +class ROMFSDirectory : public DirectoryBackend { public: u32 Read(const u32 count, Entry* entries) override { return 0; From 7988f0248959b2284ce5cc74bac6aef897627a8e Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 19 Jan 2018 22:08:21 -0500 Subject: [PATCH 2/8] archive_backend: Minor changes to match Switch IFileSystem. --- src/core/file_sys/archive_backend.h | 44 +++++++++++++------------- src/core/file_sys/romfs_archive.cpp | 2 +- src/core/file_sys/romfs_archive.h | 2 +- src/core/file_sys/savedata_archive.cpp | 2 +- src/core/file_sys/savedata_archive.h | 2 +- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h index 58f6c150c..2255bee42 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/archive_backend.h @@ -81,13 +81,12 @@ public: 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 error code + * Create a file specified by its path + * @param path Path relative to the Archive + * @param size The size of the new file, filled with zeroes + * @return Result of the operation */ - virtual ResultVal> OpenFile(const Path& path, - const Mode& mode) const = 0; + virtual ResultCode CreateFile(const Path& path, u64 size) const = 0; /** * Delete a file specified by its path @@ -97,12 +96,11 @@ public: virtual ResultCode DeleteFile(const 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 + * Create a directory specified by its path + * @param path Path relative to the archive * @return Result of the operation */ - virtual ResultCode RenameFile(const Path& src_path, const Path& dest_path) const = 0; + virtual ResultCode CreateDirectory(const Path& path) const = 0; /** * Delete a directory specified by its path @@ -119,19 +117,12 @@ public: virtual ResultCode DeleteDirectoryRecursively(const Path& path) const = 0; /** - * Create a file specified by its path - * @param path Path relative to the Archive - * @param size The size of the new file, filled with zeroes + * 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 Result of the operation */ - virtual ResultCode CreateFile(const Path& path, u64 size) const = 0; - - /** - * Create a directory specified by its path - * @param path Path relative to the archive - * @return Result of the operation - */ - virtual ResultCode CreateDirectory(const Path& path) const = 0; + virtual ResultCode RenameFile(const Path& src_path, const Path& dest_path) const = 0; /** * Rename a Directory specified by its path @@ -141,6 +132,15 @@ public: */ virtual ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) 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 error code + */ + virtual ResultVal> OpenFile(const Path& path, + const Mode& mode) const = 0; + /** * Open a directory specified by its path * @param path Path relative to the archive @@ -152,7 +152,7 @@ public: * Get the free space * @return The number of free bytes in the archive */ - virtual u64 GetFreeBytes() const = 0; + virtual u64 GetFreeSpaceSize() const = 0; }; class ArchiveFactory : NonCopyable { diff --git a/src/core/file_sys/romfs_archive.cpp b/src/core/file_sys/romfs_archive.cpp index 482de2220..0d93fccd4 100644 --- a/src/core/file_sys/romfs_archive.cpp +++ b/src/core/file_sys/romfs_archive.cpp @@ -73,7 +73,7 @@ ResultVal> ROMFSArchive::OpenDirectory(const P return MakeResult>(std::make_unique()); } -u64 ROMFSArchive::GetFreeBytes() const { +u64 ROMFSArchive::GetFreeSpaceSize() const { LOG_WARNING(Service_FS, "Attempted to get the free space in an ROMFS archive"); return 0; } diff --git a/src/core/file_sys/romfs_archive.h b/src/core/file_sys/romfs_archive.h index 2bb13146b..2b6c573ba 100644 --- a/src/core/file_sys/romfs_archive.h +++ b/src/core/file_sys/romfs_archive.h @@ -39,7 +39,7 @@ public: ResultCode CreateDirectory(const Path& path) const override; ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; ResultVal> OpenDirectory(const Path& path) const override; - u64 GetFreeBytes() const override; + u64 GetFreeSpaceSize() const override; protected: std::shared_ptr romfs_file; diff --git a/src/core/file_sys/savedata_archive.cpp b/src/core/file_sys/savedata_archive.cpp index d7b012f6e..d12739ca7 100644 --- a/src/core/file_sys/savedata_archive.cpp +++ b/src/core/file_sys/savedata_archive.cpp @@ -322,7 +322,7 @@ ResultVal> SaveDataArchive::OpenDirectory( return MakeResult>(std::move(directory)); } -u64 SaveDataArchive::GetFreeBytes() const { +u64 SaveDataArchive::GetFreeSpaceSize() const { // TODO: Stubbed to return 1GiB return 1024 * 1024 * 1024; } diff --git a/src/core/file_sys/savedata_archive.h b/src/core/file_sys/savedata_archive.h index 176d35710..931dfb17b 100644 --- a/src/core/file_sys/savedata_archive.h +++ b/src/core/file_sys/savedata_archive.h @@ -34,7 +34,7 @@ public: ResultCode CreateDirectory(const Path& path) const override; ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; ResultVal> OpenDirectory(const Path& path) const override; - u64 GetFreeBytes() const override; + u64 GetFreeSpaceSize() const override; protected: std::string mount_point; From 1c06c918af30e4f431920c6197128524b2caee14 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 19 Jan 2018 22:18:01 -0500 Subject: [PATCH 3/8] file_sys: Remove disk_archive, savedata_archive, and title_metadata. --- src/core/CMakeLists.txt | 6 - src/core/file_sys/disk_archive.cpp | 99 -------- src/core/file_sys/disk_archive.h | 68 ----- src/core/file_sys/savedata_archive.cpp | 330 ------------------------- src/core/file_sys/savedata_archive.h | 43 ---- src/core/file_sys/title_metadata.cpp | 163 ------------ src/core/file_sys/title_metadata.h | 126 ---------- 7 files changed, 835 deletions(-) delete mode 100644 src/core/file_sys/disk_archive.cpp delete mode 100644 src/core/file_sys/disk_archive.h delete mode 100644 src/core/file_sys/savedata_archive.cpp delete mode 100644 src/core/file_sys/savedata_archive.h delete mode 100644 src/core/file_sys/title_metadata.cpp delete mode 100644 src/core/file_sys/title_metadata.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ec25ec9cf..b2dcc039a 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -9,18 +9,12 @@ add_library(core STATIC file_sys/archive_backend.cpp file_sys/archive_backend.h file_sys/directory_backend.h - file_sys/disk_archive.cpp - file_sys/disk_archive.h file_sys/errors.h file_sys/file_backend.h file_sys/path_parser.cpp file_sys/path_parser.h file_sys/romfs_archive.cpp file_sys/romfs_archive.h - file_sys/savedata_archive.cpp - file_sys/savedata_archive.h - file_sys/title_metadata.cpp - file_sys/title_metadata.h frontend/emu_window.cpp frontend/emu_window.h frontend/framebuffer_layout.cpp diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp deleted file mode 100644 index 98d80aabc..000000000 --- a/src/core/file_sys/disk_archive.cpp +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include "common/common_types.h" -#include "common/file_util.h" -#include "common/logging/log.h" -#include "core/file_sys/disk_archive.h" -#include "core/file_sys/errors.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -ResultVal DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const { - if (!mode.read_flag) - return ERROR_INVALID_OPEN_FLAGS; - - file->Seek(offset, SEEK_SET); - return MakeResult(file->ReadBytes(buffer, length)); -} - -ResultVal DiskFile::Write(const u64 offset, const size_t length, const bool flush, - const u8* buffer) const { - if (!mode.write_flag) - return ERROR_INVALID_OPEN_FLAGS; - - file->Seek(offset, SEEK_SET); - size_t written = file->WriteBytes(buffer, length); - if (flush) - file->Flush(); - return MakeResult(written); -} - -u64 DiskFile::GetSize() const { - return file->GetSize(); -} - -bool DiskFile::SetSize(const u64 size) const { - file->Resize(size); - file->Flush(); - return true; -} - -bool DiskFile::Close() const { - return file->Close(); -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// - -DiskDirectory::DiskDirectory(const std::string& path) : directory() { - unsigned size = FileUtil::ScanDirectoryTree(path, directory); - directory.size = size; - directory.isDirectory = true; - children_iterator = directory.children.begin(); -} - -u32 DiskDirectory::Read(const u32 count, Entry* entries) { - u32 entries_read = 0; - - while (entries_read < count && children_iterator != directory.children.cend()) { - const FileUtil::FSTEntry& file = *children_iterator; - const std::string& filename = file.virtualName; - Entry& entry = entries[entries_read]; - - LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size, - file.isDirectory); - - // TODO(Link Mauve): use a proper conversion to UTF-16. - for (size_t j = 0; j < FILENAME_LENGTH; ++j) { - entry.filename[j] = filename[j]; - if (!filename[j]) - break; - } - - FileUtil::SplitFilename83(filename, entry.short_name, entry.extension); - - entry.is_directory = file.isDirectory; - entry.is_hidden = (filename[0] == '.'); - entry.is_read_only = 0; - entry.file_size = file.size; - - // We emulate a SD card where the archive bit has never been cleared, as it would be on - // most user SD cards. - // Some homebrews (blargSNES for instance) are known to mistakenly use the archive bit as a - // file bit. - entry.is_archive = !file.isDirectory; - - ++entries_read; - ++children_iterator; - } - return entries_read; -} - -} // namespace FileSys diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h deleted file mode 100644 index eb9166df6..000000000 --- a/src/core/file_sys/disk_archive.h +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include -#include "common/common_types.h" -#include "common/file_util.h" -#include "core/file_sys/archive_backend.h" -#include "core/file_sys/directory_backend.h" -#include "core/file_sys/file_backend.h" -#include "core/hle/result.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -class DiskFile : public FileBackend { -public: - DiskFile(FileUtil::IOFile&& file_, const Mode& mode_) - : file(new FileUtil::IOFile(std::move(file_))) { - mode.hex = mode_.hex; - } - - ResultVal Read(u64 offset, size_t length, u8* buffer) const override; - ResultVal Write(u64 offset, size_t length, bool flush, const u8* buffer) const override; - u64 GetSize() const override; - bool SetSize(u64 size) const override; - bool Close() const override; - - void Flush() const override { - file->Flush(); - } - -protected: - Mode mode; - std::unique_ptr file; -}; - -class DiskDirectory : public DirectoryBackend { -public: - DiskDirectory(const std::string& path); - - ~DiskDirectory() override { - Close(); - } - - u32 Read(const u32 count, Entry* entries) override; - - bool Close() const override { - return true; - } - -protected: - u32 total_entries_in_directory; - FileUtil::FSTEntry directory; - - // We need to remember the last entry we returned, so a subsequent call to Read will continue - // from the next one. This iterator will always point to the next unread entry. - std::vector::iterator children_iterator; -}; - -} // namespace FileSys diff --git a/src/core/file_sys/savedata_archive.cpp b/src/core/file_sys/savedata_archive.cpp deleted file mode 100644 index d12739ca7..000000000 --- a/src/core/file_sys/savedata_archive.cpp +++ /dev/null @@ -1,330 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/file_util.h" -#include "core/file_sys/disk_archive.h" -#include "core/file_sys/errors.h" -#include "core/file_sys/path_parser.h" -#include "core/file_sys/savedata_archive.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -ResultVal> SaveDataArchive::OpenFile(const Path& path, - const Mode& mode) const { - LOG_DEBUG(Service_FS, "called path=%s mode=%01X", path.DebugStr().c_str(), mode.hex); - - const PathParser path_parser(path); - - if (!path_parser.IsValid()) { - LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - if (mode.hex == 0) { - LOG_ERROR(Service_FS, "Empty open mode"); - return ERROR_UNSUPPORTED_OPEN_FLAGS; - } - - if (mode.create_flag && !mode.write_flag) { - LOG_ERROR(Service_FS, "Create flag set but write flag not set"); - return ERROR_UNSUPPORTED_OPEN_FLAGS; - } - - const auto full_path = path_parser.BuildHostPath(mount_point); - - switch (path_parser.GetHostStatus(mount_point)) { - case PathParser::InvalidMountPoint: - LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); - return ERROR_FILE_NOT_FOUND; - case PathParser::PathNotFound: - LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); - return ERROR_PATH_NOT_FOUND; - case PathParser::FileInPath: - case PathParser::DirectoryFound: - LOG_ERROR(Service_FS, "Unexpected file or directory in %s", full_path.c_str()); - return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; - case PathParser::NotFound: - if (!mode.create_flag) { - LOG_ERROR(Service_FS, "Non-existing file %s can't be open without mode create.", - full_path.c_str()); - return ERROR_FILE_NOT_FOUND; - } else { - // Create the file - FileUtil::CreateEmptyFile(full_path); - } - break; - case PathParser::FileFound: - break; // Expected 'success' case - } - - FileUtil::IOFile file(full_path, mode.write_flag ? "r+b" : "rb"); - if (!file.IsOpen()) { - LOG_CRITICAL(Service_FS, "(unreachable) Unknown error opening %s", full_path.c_str()); - return ERROR_FILE_NOT_FOUND; - } - - auto disk_file = std::make_unique(std::move(file), mode); - return MakeResult>(std::move(disk_file)); -} - -ResultCode SaveDataArchive::DeleteFile(const Path& path) const { - const PathParser path_parser(path); - - if (!path_parser.IsValid()) { - LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const auto full_path = path_parser.BuildHostPath(mount_point); - - switch (path_parser.GetHostStatus(mount_point)) { - case PathParser::InvalidMountPoint: - LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); - return ERROR_FILE_NOT_FOUND; - case PathParser::PathNotFound: - LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); - return ERROR_PATH_NOT_FOUND; - case PathParser::FileInPath: - case PathParser::DirectoryFound: - case PathParser::NotFound: - LOG_ERROR(Service_FS, "File not found %s", full_path.c_str()); - return ERROR_FILE_NOT_FOUND; - case PathParser::FileFound: - break; // Expected 'success' case - } - - if (FileUtil::Delete(full_path)) { - return RESULT_SUCCESS; - } - - LOG_CRITICAL(Service_FS, "(unreachable) Unknown error deleting %s", full_path.c_str()); - return ERROR_FILE_NOT_FOUND; -} - -ResultCode SaveDataArchive::RenameFile(const Path& src_path, const Path& dest_path) const { - const PathParser path_parser_src(src_path); - - // TODO: Verify these return codes with HW - if (!path_parser_src.IsValid()) { - LOG_ERROR(Service_FS, "Invalid src path %s", src_path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const PathParser path_parser_dest(dest_path); - - if (!path_parser_dest.IsValid()) { - LOG_ERROR(Service_FS, "Invalid dest path %s", dest_path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const auto src_path_full = path_parser_src.BuildHostPath(mount_point); - const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point); - - if (FileUtil::Rename(src_path_full, dest_path_full)) { - return RESULT_SUCCESS; - } - - // TODO(bunnei): Use correct error code - return ResultCode(-1); -} - -template -static ResultCode DeleteDirectoryHelper(const Path& path, const std::string& mount_point, - T deleter) { - const PathParser path_parser(path); - - if (!path_parser.IsValid()) { - LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - if (path_parser.IsRootDirectory()) - return ERROR_DIRECTORY_NOT_EMPTY; - - const auto full_path = path_parser.BuildHostPath(mount_point); - - switch (path_parser.GetHostStatus(mount_point)) { - case PathParser::InvalidMountPoint: - LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); - return ERROR_PATH_NOT_FOUND; - case PathParser::PathNotFound: - case PathParser::NotFound: - LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); - return ERROR_PATH_NOT_FOUND; - case PathParser::FileInPath: - case PathParser::FileFound: - LOG_ERROR(Service_FS, "Unexpected file or directory %s", full_path.c_str()); - return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; - case PathParser::DirectoryFound: - break; // Expected 'success' case - } - - if (deleter(full_path)) { - return RESULT_SUCCESS; - } - - LOG_ERROR(Service_FS, "Directory not empty %s", full_path.c_str()); - return ERROR_DIRECTORY_NOT_EMPTY; -} - -ResultCode SaveDataArchive::DeleteDirectory(const Path& path) const { - return DeleteDirectoryHelper(path, mount_point, FileUtil::DeleteDir); -} - -ResultCode SaveDataArchive::DeleteDirectoryRecursively(const Path& path) const { - return DeleteDirectoryHelper( - path, mount_point, [](const std::string& p) { return FileUtil::DeleteDirRecursively(p); }); -} - -ResultCode SaveDataArchive::CreateFile(const FileSys::Path& path, u64 size) const { - const PathParser path_parser(path); - - if (!path_parser.IsValid()) { - LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const auto full_path = path_parser.BuildHostPath(mount_point); - - switch (path_parser.GetHostStatus(mount_point)) { - case PathParser::InvalidMountPoint: - LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); - return ERROR_FILE_NOT_FOUND; - case PathParser::PathNotFound: - LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); - return ERROR_PATH_NOT_FOUND; - case PathParser::FileInPath: - LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str()); - return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; - case PathParser::DirectoryFound: - case PathParser::FileFound: - LOG_ERROR(Service_FS, "%s already exists", full_path.c_str()); - return ERROR_FILE_ALREADY_EXISTS; - case PathParser::NotFound: - break; // Expected 'success' case - } - - if (size == 0) { - FileUtil::CreateEmptyFile(full_path); - return RESULT_SUCCESS; - } - - FileUtil::IOFile file(full_path, "wb"); - // Creates a sparse file (or a normal file on filesystems without the concept of sparse files) - // We do this by seeking to the right size, then writing a single null byte. - if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) { - return RESULT_SUCCESS; - } - - LOG_ERROR(Service_FS, "Too large file"); - - // TODO(bunnei): Use correct error code - return ResultCode(-1); -} - -ResultCode SaveDataArchive::CreateDirectory(const Path& path) const { - const PathParser path_parser(path); - - if (!path_parser.IsValid()) { - LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const auto full_path = path_parser.BuildHostPath(mount_point); - - switch (path_parser.GetHostStatus(mount_point)) { - case PathParser::InvalidMountPoint: - LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); - return ERROR_FILE_NOT_FOUND; - case PathParser::PathNotFound: - LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); - return ERROR_PATH_NOT_FOUND; - case PathParser::FileInPath: - LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str()); - return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; - case PathParser::DirectoryFound: - case PathParser::FileFound: - LOG_ERROR(Service_FS, "%s already exists", full_path.c_str()); - return ERROR_DIRECTORY_ALREADY_EXISTS; - case PathParser::NotFound: - break; // Expected 'success' case - } - - if (FileUtil::CreateDir(mount_point + path.AsString())) { - return RESULT_SUCCESS; - } - - LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", mount_point.c_str()); - - // TODO(bunnei): Use correct error code - return ResultCode(-1); -} - -ResultCode SaveDataArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const { - const PathParser path_parser_src(src_path); - - // TODO: Verify these return codes with HW - if (!path_parser_src.IsValid()) { - LOG_ERROR(Service_FS, "Invalid src path %s", src_path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const PathParser path_parser_dest(dest_path); - - if (!path_parser_dest.IsValid()) { - LOG_ERROR(Service_FS, "Invalid dest path %s", dest_path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const auto src_path_full = path_parser_src.BuildHostPath(mount_point); - const auto dest_path_full = path_parser_dest.BuildHostPath(mount_point); - - if (FileUtil::Rename(src_path_full, dest_path_full)) { - return RESULT_SUCCESS; - } - - // TODO(bunnei): Use correct error code - return ResultCode(-1); -} - -ResultVal> SaveDataArchive::OpenDirectory( - const Path& path) const { - const PathParser path_parser(path); - - if (!path_parser.IsValid()) { - LOG_ERROR(Service_FS, "Invalid path %s", path.DebugStr().c_str()); - return ERROR_INVALID_PATH; - } - - const auto full_path = path_parser.BuildHostPath(mount_point); - - switch (path_parser.GetHostStatus(mount_point)) { - case PathParser::InvalidMountPoint: - LOG_CRITICAL(Service_FS, "(unreachable) Invalid mount point %s", mount_point.c_str()); - return ERROR_FILE_NOT_FOUND; - case PathParser::PathNotFound: - case PathParser::NotFound: - LOG_ERROR(Service_FS, "Path not found %s", full_path.c_str()); - return ERROR_PATH_NOT_FOUND; - case PathParser::FileInPath: - case PathParser::FileFound: - LOG_ERROR(Service_FS, "Unexpected file in path %s", full_path.c_str()); - return ERROR_UNEXPECTED_FILE_OR_DIRECTORY; - case PathParser::DirectoryFound: - break; // Expected 'success' case - } - - auto directory = std::make_unique(full_path); - return MakeResult>(std::move(directory)); -} - -u64 SaveDataArchive::GetFreeSpaceSize() const { - // TODO: Stubbed to return 1GiB - return 1024 * 1024 * 1024; -} - -} // namespace FileSys diff --git a/src/core/file_sys/savedata_archive.h b/src/core/file_sys/savedata_archive.h deleted file mode 100644 index 931dfb17b..000000000 --- a/src/core/file_sys/savedata_archive.h +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "core/file_sys/archive_backend.h" -#include "core/file_sys/directory_backend.h" -#include "core/file_sys/file_backend.h" -#include "core/hle/result.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -/// Archive backend for general save data archive type (SaveData and SystemSaveData) -class SaveDataArchive : public ArchiveBackend { -public: - explicit SaveDataArchive(const std::string& mount_point_) : mount_point(mount_point_) {} - - std::string GetName() const override { - return "SaveDataArchive: " + mount_point; - } - - ResultVal> OpenFile(const Path& path, - const Mode& mode) const override; - ResultCode DeleteFile(const Path& path) const override; - ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override; - ResultCode DeleteDirectory(const Path& path) const override; - ResultCode DeleteDirectoryRecursively(const Path& path) const override; - ResultCode CreateFile(const Path& path, u64 size) const override; - ResultCode CreateDirectory(const Path& path) const override; - ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override; - ResultVal> OpenDirectory(const Path& path) const override; - u64 GetFreeSpaceSize() const override; - -protected: - std::string mount_point; -}; - -} // namespace FileSys diff --git a/src/core/file_sys/title_metadata.cpp b/src/core/file_sys/title_metadata.cpp deleted file mode 100644 index e29ba6064..000000000 --- a/src/core/file_sys/title_metadata.cpp +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include "common/alignment.h" -#include "common/file_util.h" -#include "common/logging/log.h" -#include "core/file_sys/title_metadata.h" -#include "core/loader/loader.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -static u32 GetSignatureSize(u32 signature_type) { - switch (signature_type) { - case Rsa4096Sha1: - case Rsa4096Sha256: - return 0x200; - - case Rsa2048Sha1: - case Rsa2048Sha256: - return 0x100; - - case EllipticSha1: - case EcdsaSha256: - return 0x3C; - } -} - -Loader::ResultStatus TitleMetadata::Load() { - FileUtil::IOFile file(filepath, "rb"); - if (!file.IsOpen()) - return Loader::ResultStatus::Error; - - if (!file.ReadBytes(&signature_type, sizeof(u32_be))) - return Loader::ResultStatus::Error; - - // Signature lengths are variable, and the body follows the signature - u32 signature_size = GetSignatureSize(signature_type); - - tmd_signature.resize(signature_size); - if (!file.ReadBytes(&tmd_signature[0], signature_size)) - return Loader::ResultStatus::Error; - - // The TMD body start position is rounded to the nearest 0x40 after the signature - size_t body_start = Common::AlignUp(signature_size + sizeof(u32), 0x40); - file.Seek(body_start, SEEK_SET); - - // Read our TMD body, then load the amount of ContentChunks specified - if (file.ReadBytes(&tmd_body, sizeof(TitleMetadata::Body)) != sizeof(TitleMetadata::Body)) - return Loader::ResultStatus::Error; - - for (u16 i = 0; i < tmd_body.content_count; i++) { - ContentChunk chunk; - if (file.ReadBytes(&chunk, sizeof(ContentChunk)) == sizeof(ContentChunk)) { - tmd_chunks.push_back(chunk); - } else { - LOG_ERROR(Service_FS, "Malformed TMD %s, failed to load content chunk index %u!", - filepath.c_str(), i); - return Loader::ResultStatus::ErrorInvalidFormat; - } - } - - return Loader::ResultStatus::Success; -} - -Loader::ResultStatus TitleMetadata::Save() { - UNIMPLEMENTED(); - return Loader::ResultStatus::Success; -} - -u64 TitleMetadata::GetTitleID() const { - return tmd_body.title_id; -} - -u32 TitleMetadata::GetTitleType() const { - return tmd_body.title_type; -} - -u16 TitleMetadata::GetTitleVersion() const { - return tmd_body.title_version; -} - -u64 TitleMetadata::GetSystemVersion() const { - return tmd_body.system_version; -} - -size_t TitleMetadata::GetContentCount() const { - return tmd_chunks.size(); -} - -u32 TitleMetadata::GetBootContentID() const { - return tmd_chunks[TMDContentIndex::Main].id; -} - -u32 TitleMetadata::GetManualContentID() const { - return tmd_chunks[TMDContentIndex::Manual].id; -} - -u32 TitleMetadata::GetDLPContentID() const { - return tmd_chunks[TMDContentIndex::DLP].id; -} - -void TitleMetadata::SetTitleID(u64 title_id) { - tmd_body.title_id = title_id; -} - -void TitleMetadata::SetTitleType(u32 type) { - tmd_body.title_type = type; -} - -void TitleMetadata::SetTitleVersion(u16 version) { - tmd_body.title_version = version; -} - -void TitleMetadata::SetSystemVersion(u64 version) { - tmd_body.system_version = version; -} - -void TitleMetadata::AddContentChunk(const ContentChunk& chunk) { - tmd_chunks.push_back(chunk); -} - -void TitleMetadata::Print() const { - LOG_DEBUG(Service_FS, "%s - %u chunks", filepath.c_str(), - static_cast(tmd_body.content_count)); - - // Content info describes ranges of content chunks - LOG_DEBUG(Service_FS, "Content info:"); - for (size_t i = 0; i < tmd_body.contentinfo.size(); i++) { - if (tmd_body.contentinfo[i].command_count == 0) - break; - - LOG_DEBUG(Service_FS, " Index %04X, Command Count %04X", - static_cast(tmd_body.contentinfo[i].index), - static_cast(tmd_body.contentinfo[i].command_count)); - } - - // For each content info, print their content chunk range - for (size_t i = 0; i < tmd_body.contentinfo.size(); i++) { - u16 index = static_cast(tmd_body.contentinfo[i].index); - u16 count = static_cast(tmd_body.contentinfo[i].command_count); - - if (count == 0) - continue; - - LOG_DEBUG(Service_FS, "Content chunks for content info index %zu:", i); - for (u16 j = index; j < index + count; j++) { - // Don't attempt to print content we don't have - if (j > tmd_body.content_count) - break; - - const ContentChunk& chunk = tmd_chunks[j]; - LOG_DEBUG(Service_FS, " ID %08X, Index %04X, Type %04x, Size %016" PRIX64, - static_cast(chunk.id), static_cast(chunk.index), - static_cast(chunk.type), static_cast(chunk.size)); - } - } -} -} // namespace FileSys diff --git a/src/core/file_sys/title_metadata.h b/src/core/file_sys/title_metadata.h deleted file mode 100644 index a4c7d1089..000000000 --- a/src/core/file_sys/title_metadata.h +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include "common/common_types.h" -#include "common/swap.h" - -namespace Loader { -enum class ResultStatus; -} - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -enum TMDSignatureType : u32 { - Rsa4096Sha1 = 0x10000, - Rsa2048Sha1 = 0x10001, - EllipticSha1 = 0x10002, - Rsa4096Sha256 = 0x10003, - Rsa2048Sha256 = 0x10004, - EcdsaSha256 = 0x10005 -}; - -enum TMDContentTypeFlag : u16 { - Encrypted = 1 << 1, - Disc = 1 << 2, - CFM = 1 << 3, - Optional = 1 << 14, - Shared = 1 << 15 -}; - -/** - * Helper which implements an interface to read and write Title Metadata (TMD) files. - * If a file path is provided and the file exists, it can be parsed and used, otherwise - * it must be created. The TMD file can then be interpreted, modified and/or saved. - */ -class TitleMetadata { -public: - struct ContentChunk { - u32_be id; - u16_be index; - u16_be type; - u64_be size; - std::array hash; - }; - - static_assert(sizeof(ContentChunk) == 0x30, "TMD ContentChunk structure size is wrong"); - - struct ContentInfo { - u16_be index; - u16_be command_count; - std::array hash; - }; - - static_assert(sizeof(ContentInfo) == 0x24, "TMD ContentInfo structure size is wrong"); - -#pragma pack(push, 1) - - struct Body { - std::array issuer; - u8 version; - u8 ca_crl_version; - u8 signer_crl_version; - u8 reserved; - u64_be system_version; - u64_be title_id; - u32_be title_type; - u16_be group_id; - u32_be savedata_size; - u32_be srl_private_savedata_size; - std::array reserved_2; - u8 srl_flag; - std::array reserved_3; - u32_be access_rights; - u16_be title_version; - u16_be content_count; - u16_be boot_content; - std::array reserved_4; - std::array contentinfo_hash; - std::array contentinfo; - }; - - static_assert(sizeof(Body) == 0x9C4, "TMD body structure size is wrong"); - -#pragma pack(pop) - - explicit TitleMetadata(std::string& path) : filepath(std::move(path)) {} - Loader::ResultStatus Load(); - Loader::ResultStatus Save(); - - u64 GetTitleID() const; - u32 GetTitleType() const; - u16 GetTitleVersion() const; - u64 GetSystemVersion() const; - size_t GetContentCount() const; - u32 GetBootContentID() const; - u32 GetManualContentID() const; - u32 GetDLPContentID() const; - - void SetTitleID(u64 title_id); - void SetTitleType(u32 type); - void SetTitleVersion(u16 version); - void SetSystemVersion(u64 version); - void AddContentChunk(const ContentChunk& chunk); - - void Print() const; - -private: - enum TMDContentIndex { Main = 0, Manual = 1, DLP = 2 }; - - Body tmd_body; - u32_be signature_type; - std::vector tmd_signature; - std::vector tmd_chunks; - - std::string filepath; -}; - -} // namespace FileSys From 00851a5ef442947c4237f32e063c37e7751db3ed Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 19 Jan 2018 22:34:48 -0500 Subject: [PATCH 4/8] file_sys: Cleanup to better match Switch file system constructs. file_sys: Add factory class for RomFS file system. --- src/core/CMakeLists.txt | 14 ++++--- .../{directory_backend.h => directory.h} | 2 +- .../{archive_backend.cpp => filesystem.cpp} | 4 +- .../{archive_backend.h => filesystem.h} | 18 ++++----- src/core/file_sys/path_parser.h | 2 +- src/core/file_sys/romfs_factory.cpp | 39 ++++++++++++++++++ src/core/file_sys/romfs_factory.h | 35 ++++++++++++++++ ...romfs_archive.cpp => romfs_filesystem.cpp} | 40 +++++++++---------- .../{romfs_archive.h => romfs_filesystem.h} | 18 ++++----- .../file_sys/{file_backend.h => storage.h} | 27 ++++++------- 10 files changed, 136 insertions(+), 63 deletions(-) rename src/core/file_sys/{directory_backend.h => directory.h} (98%) rename src/core/file_sys/{archive_backend.cpp => filesystem.cpp} (97%) rename src/core/file_sys/{archive_backend.h => filesystem.h} (92%) create mode 100644 src/core/file_sys/romfs_factory.cpp create mode 100644 src/core/file_sys/romfs_factory.h rename src/core/file_sys/{romfs_archive.cpp => romfs_filesystem.cpp} (62%) rename src/core/file_sys/{romfs_archive.h => romfs_filesystem.h} (80%) rename src/core/file_sys/{file_backend.h => storage.h} (86%) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index b2dcc039a..5ff1311a2 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -6,15 +6,17 @@ add_library(core STATIC core.h core_timing.cpp core_timing.h - file_sys/archive_backend.cpp - file_sys/archive_backend.h - file_sys/directory_backend.h + file_sys/directory.h file_sys/errors.h - file_sys/file_backend.h + file_sys/filesystem.cpp + file_sys/filesystem.h file_sys/path_parser.cpp file_sys/path_parser.h - file_sys/romfs_archive.cpp - file_sys/romfs_archive.h + file_sys/romfs_factory.cpp + file_sys/romfs_factory.h + file_sys/romfs_filesystem.cpp + file_sys/romfs_filesystem.h + file_sys/storage.h frontend/emu_window.cpp frontend/emu_window.h frontend/framebuffer_layout.cpp diff --git a/src/core/file_sys/directory_backend.h b/src/core/file_sys/directory.h similarity index 98% rename from src/core/file_sys/directory_backend.h rename to src/core/file_sys/directory.h index 0c93f2074..5a40bf472 100644 --- a/src/core/file_sys/directory_backend.h +++ b/src/core/file_sys/directory.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2018 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/core/file_sys/archive_backend.cpp b/src/core/file_sys/filesystem.cpp similarity index 97% rename from src/core/file_sys/archive_backend.cpp rename to src/core/file_sys/filesystem.cpp index fc472b44f..82fdb3c46 100644 --- a/src/core/file_sys/archive_backend.cpp +++ b/src/core/file_sys/filesystem.cpp @@ -1,4 +1,4 @@ -// Copyright 2015 Citra Emulator Project +// Copyright 2018 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -7,7 +7,7 @@ #include #include "common/logging/log.h" #include "common/string_util.h" -#include "core/file_sys/archive_backend.h" +#include "core/file_sys/filesystem.h" #include "core/memory.h" namespace FileSys { diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/filesystem.h similarity index 92% rename from src/core/file_sys/archive_backend.h rename to src/core/file_sys/filesystem.h index 2255bee42..eb3d9c4d6 100644 --- a/src/core/file_sys/archive_backend.h +++ b/src/core/file_sys/filesystem.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2018 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -15,7 +15,7 @@ namespace FileSys { -class FileBackend; +class StorageBackend; class DirectoryBackend; // Path string type @@ -71,9 +71,9 @@ struct ArchiveFormatInfo { }; static_assert(std::is_pod::value, "ArchiveFormatInfo is not POD"); -class ArchiveBackend : NonCopyable { +class FileSystemBackend : NonCopyable { public: - virtual ~ArchiveBackend() {} + virtual ~FileSystemBackend() {} /** * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) @@ -138,8 +138,8 @@ public: * @param mode Mode to open the file with * @return Opened file, or error code */ - virtual ResultVal> OpenFile(const Path& path, - const Mode& mode) const = 0; + virtual ResultVal> OpenFile(const Path& path, + const Mode& mode) const = 0; /** * Open a directory specified by its path @@ -155,9 +155,9 @@ public: virtual u64 GetFreeSpaceSize() const = 0; }; -class ArchiveFactory : NonCopyable { +class FileSystemFactory : NonCopyable { public: - virtual ~ArchiveFactory() {} + virtual ~FileSystemFactory() {} /** * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) @@ -169,7 +169,7 @@ public: * @param path Path to the archive * @return An ArchiveBackend corresponding operating specified archive path. */ - virtual ResultVal> Open(const Path& path) = 0; + virtual ResultVal> Open(const Path& path) = 0; /** * Deletes the archive contents and then re-creates the base folder diff --git a/src/core/file_sys/path_parser.h b/src/core/file_sys/path_parser.h index b9f52f65d..184f59d55 100644 --- a/src/core/file_sys/path_parser.h +++ b/src/core/file_sys/path_parser.h @@ -6,7 +6,7 @@ #include #include -#include "core/file_sys/archive_backend.h" +#include "core/file_sys/filesystem.h" namespace FileSys { diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp new file mode 100644 index 000000000..590c2acb3 --- /dev/null +++ b/src/core/file_sys/romfs_factory.cpp @@ -0,0 +1,39 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include "common/common_types.h" +#include "common/logging/log.h" +#include "core/file_sys/romfs_factory.h" +#include "core/file_sys/romfs_filesystem.h" + +namespace FileSys { + +RomFS_Factory::RomFS_Factory(Loader::AppLoader& app_loader) { + // Load the RomFS from the app + if (Loader::ResultStatus::Success != app_loader.ReadRomFS(romfs_file, data_offset, data_size)) { + LOG_ERROR(Service_FS, "Unable to read RomFS!"); + } +} + +ResultVal> RomFS_Factory::Open(const Path& path) { + auto archive = std::make_unique(romfs_file, data_offset, data_size); + return MakeResult>(std::move(archive)); +} + +ResultCode RomFS_Factory::Format(const Path& path, + const FileSys::ArchiveFormatInfo& format_info) { + LOG_ERROR(Service_FS, "Unimplemented Format archive %s", GetName().c_str()); + // TODO(bunnei): Find the right error code for this + return ResultCode(-1); +} + +ResultVal RomFS_Factory::GetFormatInfo(const Path& path) const { + LOG_ERROR(Service_FS, "Unimplemented GetFormatInfo archive %s", GetName().c_str()); + // TODO(bunnei): Find the right error code for this + return ResultCode(-1); +} + +} // namespace FileSys diff --git a/src/core/file_sys/romfs_factory.h b/src/core/file_sys/romfs_factory.h new file mode 100644 index 000000000..10ea13966 --- /dev/null +++ b/src/core/file_sys/romfs_factory.h @@ -0,0 +1,35 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include "common/common_types.h" +#include "core/file_sys/filesystem.h" +#include "core/hle/result.h" +#include "core/loader/loader.h" + +namespace FileSys { + +/// File system interface to the RomFS archive +class RomFS_Factory final : public FileSystemFactory { +public: + explicit RomFS_Factory(Loader::AppLoader& app_loader); + + std::string GetName() const override { + return "ArchiveFactory_RomFS"; + } + ResultVal> Open(const Path& path) override; + ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) override; + ResultVal GetFormatInfo(const Path& path) const override; + +private: + std::shared_ptr romfs_file; + u64 data_offset; + u64 data_size; +}; + +} // namespace FileSys diff --git a/src/core/file_sys/romfs_archive.cpp b/src/core/file_sys/romfs_filesystem.cpp similarity index 62% rename from src/core/file_sys/romfs_archive.cpp rename to src/core/file_sys/romfs_filesystem.cpp index 0d93fccd4..5b5c5a73e 100644 --- a/src/core/file_sys/romfs_archive.cpp +++ b/src/core/file_sys/romfs_filesystem.cpp @@ -6,79 +6,79 @@ #include #include "common/common_types.h" #include "common/logging/log.h" -#include "core/file_sys/romfs_archive.h" +#include "core/file_sys/romfs_filesystem.h" namespace FileSys { -std::string ROMFSArchive::GetName() const { +std::string RomFS_FileSystem::GetName() const { return "RomFS"; } -ResultVal> ROMFSArchive::OpenFile(const Path& path, - const Mode& mode) const { - return MakeResult>( - std::make_unique(romfs_file, data_offset, data_size)); +ResultVal> RomFS_FileSystem::OpenFile(const Path& path, + const Mode& mode) const { + return MakeResult>( + std::make_unique(romfs_file, data_offset, data_size)); } -ResultCode ROMFSArchive::DeleteFile(const Path& path) const { +ResultCode RomFS_FileSystem::DeleteFile(const Path& path) const { LOG_CRITICAL(Service_FS, "Attempted to delete a file from an ROMFS archive (%s).", GetName().c_str()); // TODO(bunnei): Use correct error code return ResultCode(-1); } -ResultCode ROMFSArchive::RenameFile(const Path& src_path, const Path& dest_path) const { +ResultCode RomFS_FileSystem::RenameFile(const Path& src_path, const Path& dest_path) const { LOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive (%s).", GetName().c_str()); // TODO(wwylele): Use correct error code return ResultCode(-1); } -ResultCode ROMFSArchive::DeleteDirectory(const Path& path) const { +ResultCode RomFS_FileSystem::DeleteDirectory(const Path& path) const { LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive (%s).", GetName().c_str()); // TODO(wwylele): Use correct error code return ResultCode(-1); } -ResultCode ROMFSArchive::DeleteDirectoryRecursively(const Path& path) const { +ResultCode RomFS_FileSystem::DeleteDirectoryRecursively(const Path& path) const { LOG_CRITICAL(Service_FS, "Attempted to delete a directory from an ROMFS archive (%s).", GetName().c_str()); // TODO(wwylele): Use correct error code return ResultCode(-1); } -ResultCode ROMFSArchive::CreateFile(const Path& path, u64 size) const { +ResultCode RomFS_FileSystem::CreateFile(const Path& path, u64 size) const { LOG_CRITICAL(Service_FS, "Attempted to create a file in an ROMFS archive (%s).", GetName().c_str()); // TODO(bunnei): Use correct error code return ResultCode(-1); } -ResultCode ROMFSArchive::CreateDirectory(const Path& path) const { +ResultCode RomFS_FileSystem::CreateDirectory(const Path& path) const { LOG_CRITICAL(Service_FS, "Attempted to create a directory in an ROMFS archive (%s).", GetName().c_str()); // TODO(wwylele): Use correct error code return ResultCode(-1); } -ResultCode ROMFSArchive::RenameDirectory(const Path& src_path, const Path& dest_path) const { +ResultCode RomFS_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const { LOG_CRITICAL(Service_FS, "Attempted to rename a file within an ROMFS archive (%s).", GetName().c_str()); // TODO(wwylele): Use correct error code return ResultCode(-1); } -ResultVal> ROMFSArchive::OpenDirectory(const Path& path) const { +ResultVal> RomFS_FileSystem::OpenDirectory(const Path& path) const { return MakeResult>(std::make_unique()); } -u64 ROMFSArchive::GetFreeSpaceSize() const { +u64 RomFS_FileSystem::GetFreeSpaceSize() const { LOG_WARNING(Service_FS, "Attempted to get the free space in an ROMFS archive"); return 0; } -ResultVal ROMFSFile::Read(const u64 offset, const size_t length, u8* buffer) const { +ResultVal RomFS_Storage::Read(const u64 offset, const size_t length, u8* buffer) const { LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length); romfs_file->Seek(data_offset + offset, SEEK_SET); size_t read_length = (size_t)std::min((u64)length, data_size - offset); @@ -86,18 +86,18 @@ ResultVal ROMFSFile::Read(const u64 offset, const size_t length, u8* buf return MakeResult(romfs_file->ReadBytes(buffer, read_length)); } -ResultVal ROMFSFile::Write(const u64 offset, const size_t length, const bool flush, - const u8* buffer) const { +ResultVal RomFS_Storage::Write(const u64 offset, const size_t length, const bool flush, + const u8* buffer) const { LOG_ERROR(Service_FS, "Attempted to write to ROMFS file"); // TODO(Subv): Find error code return MakeResult(0); } -u64 ROMFSFile::GetSize() const { +u64 RomFS_Storage::GetSize() const { return data_size; } -bool ROMFSFile::SetSize(const u64 size) const { +bool RomFS_Storage::SetSize(const u64 size) const { LOG_ERROR(Service_FS, "Attempted to set the size of an ROMFS file"); return false; } diff --git a/src/core/file_sys/romfs_archive.h b/src/core/file_sys/romfs_filesystem.h similarity index 80% rename from src/core/file_sys/romfs_archive.h rename to src/core/file_sys/romfs_filesystem.h index 2b6c573ba..900ea567a 100644 --- a/src/core/file_sys/romfs_archive.h +++ b/src/core/file_sys/romfs_filesystem.h @@ -10,9 +10,9 @@ #include #include "common/common_types.h" #include "common/file_util.h" -#include "core/file_sys/archive_backend.h" -#include "core/file_sys/directory_backend.h" -#include "core/file_sys/file_backend.h" +#include "core/file_sys/directory.h" +#include "core/file_sys/filesystem.h" +#include "core/file_sys/storage.h" #include "core/hle/result.h" namespace FileSys { @@ -22,15 +22,15 @@ namespace FileSys { * archives This should be subclassed by concrete archive types, which will provide the input data * (load the raw ROMFS archive) and override any required methods */ -class ROMFSArchive : public ArchiveBackend { +class RomFS_FileSystem : public FileSystemBackend { public: - ROMFSArchive(std::shared_ptr file, u64 offset, u64 size) + RomFS_FileSystem(std::shared_ptr file, u64 offset, u64 size) : romfs_file(file), data_offset(offset), data_size(size) {} std::string GetName() const override; - ResultVal> OpenFile(const Path& path, - const Mode& mode) const override; + ResultVal> OpenFile(const Path& path, + const Mode& mode) const override; ResultCode DeleteFile(const Path& path) const override; ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override; ResultCode DeleteDirectory(const Path& path) const override; @@ -47,9 +47,9 @@ protected: u64 data_size; }; -class ROMFSFile : public FileBackend { +class RomFS_Storage : public StorageBackend { public: - ROMFSFile(std::shared_ptr file, u64 offset, u64 size) + RomFS_Storage(std::shared_ptr file, u64 offset, u64 size) : romfs_file(file), data_offset(offset), data_size(size) {} ResultVal Read(u64 offset, size_t length, u8* buffer) const override; diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/storage.h similarity index 86% rename from src/core/file_sys/file_backend.h rename to src/core/file_sys/storage.h index 5e7c2bab4..2a6811831 100644 --- a/src/core/file_sys/file_backend.h +++ b/src/core/file_sys/storage.h @@ -1,4 +1,4 @@ -// Copyright 2014 Citra Emulator Project +// Copyright 2018 yuzu emulator team // Licensed under GPLv2 or any later version // Refer to the license.txt file included. @@ -8,15 +8,12 @@ #include "common/common_types.h" #include "core/hle/result.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - namespace FileSys { -class FileBackend : NonCopyable { +class StorageBackend : NonCopyable { public: - FileBackend() {} - virtual ~FileBackend() {} + StorageBackend() {} + virtual ~StorageBackend() {} /** * Read data from the file @@ -39,10 +36,9 @@ public: const u8* buffer) const = 0; /** - * Get the size of the file in bytes - * @return Size of the file in bytes + * Flushes the file */ - virtual u64 GetSize() const = 0; + virtual void Flush() const = 0; /** * Set the size of the file in bytes @@ -51,16 +47,17 @@ public: */ virtual bool SetSize(u64 size) const = 0; + /** + * Get the size of the file in bytes + * @return Size of the file in bytes + */ + virtual u64 GetSize() const = 0; + /** * Close the file * @return true if the file closed correctly */ virtual bool Close() const = 0; - - /** - * Flushes the file - */ - virtual void Flush() const = 0; }; } // namespace FileSys From d64b7d7dfda8123cc8e0d6abaf358a4a08ba795c Mon Sep 17 00:00:00 2001 From: David Marcec Date: Tue, 16 Jan 2018 19:20:12 -0800 Subject: [PATCH 5/8] filesystem: Implement basic IStorage functionality. --- src/core/CMakeLists.txt | 4 + .../hle/service/filesystem/filesystem.cpp | 54 +++++++ src/core/hle/service/filesystem/filesystem.h | 41 ++++++ src/core/hle/service/filesystem/fsp_srv.cpp | 132 ++++++++++++++++++ src/core/hle/service/filesystem/fsp_srv.h | 25 ++++ src/core/hle/service/service.cpp | 2 + 6 files changed, 258 insertions(+) create mode 100644 src/core/hle/service/filesystem/filesystem.cpp create mode 100644 src/core/hle/service/filesystem/filesystem.h create mode 100644 src/core/hle/service/filesystem/fsp_srv.cpp create mode 100644 src/core/hle/service/filesystem/fsp_srv.h diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5ff1311a2..433e7e596 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -97,6 +97,10 @@ add_library(core STATIC hle/service/audio/audio.h hle/service/audio/audout_u.cpp hle/service/audio/audout_u.h + hle/service/filesystem/filesystem.cpp + hle/service/filesystem/filesystem.h + hle/service/filesystem/fsp_srv.cpp + hle/service/filesystem/fsp_srv.h hle/service/hid/hid.cpp hle/service/hid/hid.h hle/service/lm/lm.cpp diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp new file mode 100644 index 000000000..4b47548fd --- /dev/null +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -0,0 +1,54 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include "core/file_sys/filesystem.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/filesystem/fsp_srv.h" + +namespace Service { +namespace FileSystem { + +/** + * Map of registered file systems, identified by type. Once an file system is registered here, it + * is never removed until UnregisterFileSystems is called. + */ +static boost::container::flat_map> filesystem_map; + +ResultCode RegisterFileSystem(std::unique_ptr&& factory, Type type) { + auto result = filesystem_map.emplace(type, std::move(factory)); + + bool inserted = result.second; + ASSERT_MSG(inserted, "Tried to register more than one system with same id code"); + + auto& filesystem = result.first->second; + LOG_DEBUG(Service_FS, "Registered file system %s with id code 0x%08X", + filesystem->GetName().c_str(), static_cast(type)); + return RESULT_SUCCESS; +} + +ResultVal> OpenFileSystem(Type type, + FileSys::Path& path) { + LOG_TRACE(Service_FS, "Opening FileSystem with type=%d", type); + + auto itr = filesystem_map.find(type); + if (itr == filesystem_map.end()) { + // TODO(bunnei): Find a better error code for this + return ResultCode(-1); + } + + return itr->second->Open(path); +} + +void UnregisterFileSystems() { + filesystem_map.clear(); +} + +void InstallInterfaces(SM::ServiceManager& service_manager) { + UnregisterFileSystems(); + std::make_shared()->InstallAsService(service_manager); +} + +} // namespace FileSystem +} // namespace Service diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h new file mode 100644 index 000000000..52db83e62 --- /dev/null +++ b/src/core/hle/service/filesystem/filesystem.h @@ -0,0 +1,41 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include "common/common_types.h" +#include "core/file_sys/filesystem.h" +#include "core/hle/result.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace FileSystem { + +/// Supported FileSystem types +enum class Type { + RomFS = 1, +}; + +/** + * Registers a FileSystem, instances of which can later be opened using its IdCode. + * @param factory FileSystem backend interface to use + * @param type Type used to access this type of FileSystem + */ +ResultCode RegisterFileSystem(std::unique_ptr&& factory, Type type); + +/** + * Opens a file system + * @param type Type of the file system to open + * @param path Path to the file system, used with Binary paths + * @return FileSys::FileSystemBackend interface to the file system + */ +ResultVal> OpenFileSystem(Type type, + FileSys::Path& path); + +/// Registers all Filesystem services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& service_manager); + +} // namespace Filesystem +} // namespace Service diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp new file mode 100644 index 000000000..47a97f0fd --- /dev/null +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -0,0 +1,132 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/core.h" +#include "core/file_sys/filesystem.h" +#include "core/file_sys/storage.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/client_port.h" +#include "core/hle/kernel/client_session.h" +#include "core/hle/service/filesystem/filesystem.h" +#include "core/hle/service/filesystem/fsp_srv.h" + +namespace Service { +namespace FileSystem { + +class IStorage final : public ServiceFramework { +public: + IStorage(std::unique_ptr&& backend) + : ServiceFramework("IStorage"), backend(std::move(backend)) { + static const FunctionInfo functions[] = { + {0, &IStorage::Read, "Read"}, {1, &IStorage::Write, "Write"}, + {2, &IStorage::Flush, "Flush"}, {3, &IStorage::SetSize, "SetSize"}, + {4, &IStorage::GetSize, "GetSize"}, + }; + RegisterHandlers(functions); + } + +private: + std::unique_ptr backend; + + void Read(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + u64 offset = rp.Pop(); + u64 length = rp.Pop(); + + LOG_DEBUG(Service, "called, offset=0x%llx, length=0x%llx", offset, length); + + auto descriptor = ctx.BufferDescriptorB()[0]; + std::vector output(length); + + ResultVal res = backend->Read(offset, length, output.data()); + if (res.Failed()) { + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(res.Code()); + } + + Memory::WriteBlock(descriptor.Address(), output.data(), descriptor.Size()); + + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + } + + void Write(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service, "(STUBBED) called"); + } + + void Flush(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service, "(STUBBED) called"); + } + + void SetSize(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service, "(STUBBED) called"); + } + + void GetSize(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service, "(STUBBED) called"); + } +}; + +FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { + static const FunctionInfo functions[] = { + {1, &FSP_SRV::Initalize, "Initalize"}, + {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"}, + {203, &FSP_SRV::OpenRomStorage, "OpenRomStorage"}, + {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"}, + }; + RegisterHandlers(functions); +} + +void FSP_SRV::Initalize(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(RESULT_SUCCESS); + LOG_WARNING(Service, "(STUBBED) called"); +} + +void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { + IPC::RequestBuilder rb{ctx, 4}; + rb.Push(RESULT_SUCCESS); + rb.Push(5); + LOG_WARNING(Service, "(STUBBED) called"); +} + +void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { + FileSys::Path path; + auto filesystem = OpenFileSystem(Type::RomFS, path); + if (filesystem.Failed()) { + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(filesystem.Code()); + return; + } + + auto storage = filesystem.Unwrap()->OpenFile({}, {}); + if (storage.Failed()) { + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(storage.Code()); + return; + } + + // TODO: What if already opened? + + IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; + rb.Push(RESULT_SUCCESS); + rb.PushIpcInterface(std::move(storage.Unwrap())); + LOG_WARNING(Service, "(STUBBED) called"); +} + +void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) { + OpenDataStorageByCurrentProcess(ctx); +} + +} // namespace Filesystem +} // namespace Service diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h new file mode 100644 index 000000000..b41ba6bd1 --- /dev/null +++ b/src/core/hle/service/filesystem/fsp_srv.h @@ -0,0 +1,25 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace FileSystem { + +class FSP_SRV final : public ServiceFramework { +public: + FSP_SRV(); + ~FSP_SRV() = default; + +private: + void Initalize(Kernel::HLERequestContext& ctx); + void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); + void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); + void OpenRomStorage(Kernel::HLERequestContext& ctx); +}; + +} // namespace Filesystem +} // namespace Service diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 19213a2f4..3f5ce56c6 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -19,6 +19,7 @@ #include "core/hle/service/aoc/aoc_u.h" #include "core/hle/service/apm/apm.h" #include "core/hle/service/audio/audio.h" +#include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/lm/lm.h" #include "core/hle/service/nvdrv/nvdrv.h" @@ -172,6 +173,7 @@ void Init() { AOC::InstallInterfaces(*SM::g_service_manager); APM::InstallInterfaces(*SM::g_service_manager); Audio::InstallInterfaces(*SM::g_service_manager); + FileSystem::InstallInterfaces(*SM::g_service_manager); HID::InstallInterfaces(*SM::g_service_manager); LM::InstallInterfaces(*SM::g_service_manager); Nvidia::InstallInterfaces(*SM::g_service_manager); From d9a91d76785da6d0fa32ce32417e12023c8f394e Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 20 Jan 2018 18:20:46 -0500 Subject: [PATCH 6/8] deconstructed_rom_directory: Implement istorage loading for RomFS. --- .../loader/deconstructed_rom_directory.cpp | 69 ++++++++++++++++++- src/core/loader/deconstructed_rom_directory.h | 4 ++ 2 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 4bee5fb86..37030683b 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -7,14 +7,44 @@ #include "common/file_util.h" #include "common/logging/log.h" #include "common/string_util.h" +#include "core/file_sys/romfs_factory.h" #include "core/hle/kernel/process.h" #include "core/hle/kernel/resource_limit.h" +#include "core/hle/service/filesystem/filesystem.h" #include "core/loader/deconstructed_rom_directory.h" #include "core/loader/nso.h" #include "core/memory.h" namespace Loader { +static std::string FindRomFS(const std::string& directory) { + std::string filepath_romfs; + const auto callback = [&filepath_romfs](unsigned*, const std::string& directory, + const std::string& virtual_name) -> bool { + const std::string physical_name = directory + virtual_name; + if (FileUtil::IsDirectory(physical_name)) { + // Skip directories + return true; + } + + // Verify extension + const std::string extension = physical_name.substr(physical_name.find_last_of(".") + 1); + if (Common::ToLower(extension) != "istorage") { + return true; + } + + // Found it - we are done + filepath_romfs = std::move(physical_name); + return false; + }; + + // Search the specified directory recursively, looking for the first .istorage file, which will + // be used for the RomFS + FileUtil::ForeachDirectoryEntry(nullptr, directory, callback); + + return filepath_romfs; +} + AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileUtil::IOFile&& file, std::string filepath) : AppLoader(std::move(file)), filepath(std::move(filepath)) {} @@ -79,10 +109,10 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( // Load NSO modules VAddr next_load_addr{Memory::PROCESS_IMAGE_VADDR}; + const std::string directory = filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP; for (const auto& module : {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "sdk"}) { - const std::string path = - filepath.substr(0, filepath.find_last_of("/\\")) + DIR_SEP + module; + const std::string path = directory + DIR_SEP + module; const VAddr load_addr = next_load_addr; next_load_addr = AppLoader_NSO::LoadModule(path, load_addr); if (next_load_addr) { @@ -98,8 +128,43 @@ ResultStatus AppLoader_DeconstructedRomDirectory::Load( Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE); + // Find the RomFS by searching for a ".istorage" file in this directory + filepath_romfs = FindRomFS(directory); + + // Register the RomFS if a ".istorage" file was found + if (!filepath_romfs.empty()) { + Service::FileSystem::RegisterFileSystem(std::make_unique(*this), + Service::FileSystem::Type::RomFS); + } + is_loaded = true; return ResultStatus::Success; } +ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS( + std::shared_ptr& romfs_file, u64& offset, u64& size) { + + if (filepath_romfs.empty()) { + LOG_DEBUG(Loader, "No RomFS available"); + return ResultStatus::ErrorNotUsed; + } + + // We reopen the file, to allow its position to be independent + romfs_file = std::make_shared(filepath_romfs, "rb"); + if (!romfs_file->IsOpen()) { + return ResultStatus::Error; + } + + offset = 0; + size = romfs_file->GetSize(); + + LOG_DEBUG(Loader, "RomFS offset: 0x%08X", offset); + LOG_DEBUG(Loader, "RomFS size: 0x%08X", size); + + // Reset read pointer + file.Seek(0, SEEK_SET); + + return ResultStatus::Success; +} + } // namespace Loader diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index 162541d54..26493de5e 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h @@ -35,7 +35,11 @@ public: ResultStatus Load(Kernel::SharedPtr& process) override; + ResultStatus ReadRomFS(std::shared_ptr& romfs_file, u64& offset, + u64& size) override; + private: + std::string filepath_romfs; std::string filepath; }; From 8e50d6002bd12dde7e4ba4fd3da1b53864c4058c Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 20 Jan 2018 21:32:36 -0500 Subject: [PATCH 7/8] fsp_srv: Various improvements to IStorage:Read implementation. --- src/core/hle/ipc_helpers.h | 5 ++ src/core/hle/result.h | 2 + src/core/hle/service/filesystem/filesystem.h | 15 +++- src/core/hle/service/filesystem/fsp_srv.cpp | 92 +++++++++++--------- src/core/hle/service/filesystem/fsp_srv.h | 13 ++- 5 files changed, 79 insertions(+), 48 deletions(-) diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 4c9b0de28..a27cfbc2d 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -304,6 +304,11 @@ inline u64 RequestParser::Pop() { return msw << 32 | lsw; } +template <> +inline s64 RequestParser::Pop() { + return static_cast(Pop()); +} + template <> inline bool RequestParser::Pop() { return Pop() != 0; diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 10ddc4feb..656e1b4a7 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -19,6 +19,8 @@ enum class ErrorDescription : u32 { Success = 0, RemoteProcessDead = 301, + InvalidOffset = 6061, + InvalidLength = 6062, }; /** diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index 52db83e62..a674c9493 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h @@ -6,11 +6,20 @@ #include #include "common/common_types.h" -#include "core/file_sys/filesystem.h" #include "core/hle/result.h" -#include "core/hle/service/service.h" + +namespace FileSys { +class FileSystemBackend; +class FileSystemFactory; +class Path; +} // namespace FileSys namespace Service { + +namespace SM { +class ServiceManager; +} // namespace SM + namespace FileSystem { /// Supported FileSystem types @@ -37,5 +46,5 @@ ResultVal> OpenFileSystem(Type type, /// Registers all Filesystem services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager); -} // namespace Filesystem +} // namespace FileSystem } // namespace Service diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 47a97f0fd..ef1915e5a 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -20,9 +20,8 @@ public: IStorage(std::unique_ptr&& backend) : ServiceFramework("IStorage"), backend(std::move(backend)) { static const FunctionInfo functions[] = { - {0, &IStorage::Read, "Read"}, {1, &IStorage::Write, "Write"}, - {2, &IStorage::Flush, "Flush"}, {3, &IStorage::SetSize, "SetSize"}, - {4, &IStorage::GetSize, "GetSize"}, + {0, &IStorage::Read, "Read"}, {1, nullptr, "Write"}, {2, nullptr, "Flush"}, + {3, nullptr, "SetSize"}, {4, nullptr, "GetSize"}, }; RegisterHandlers(functions); } @@ -32,49 +31,40 @@ private: void Read(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - u64 offset = rp.Pop(); - u64 length = rp.Pop(); + const s64 offset = rp.Pop(); + const s64 length = rp.Pop(); + const auto& descriptor = ctx.BufferDescriptorB()[0]; - LOG_DEBUG(Service, "called, offset=0x%llx, length=0x%llx", offset, length); + LOG_DEBUG(Service_FS, "called, offset=0x%llx, length=0x%llx", offset, length); - auto descriptor = ctx.BufferDescriptorB()[0]; + // Error checking + ASSERT_MSG(length == descriptor.Size(), "unexpected size difference"); + if (length < 0) { + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidLength)); + return; + } + if (offset < 0) { + IPC::RequestBuilder rb{ctx, 2}; + rb.Push(ResultCode(ErrorModule::FS, ErrorDescription::InvalidOffset)); + return; + } + + // Read the data from the Storage backend std::vector output(length); - ResultVal res = backend->Read(offset, length, output.data()); if (res.Failed()) { IPC::RequestBuilder rb{ctx, 2}; rb.Push(res.Code()); + return; } + // Write the data to memory Memory::WriteBlock(descriptor.Address(), output.data(), descriptor.Size()); IPC::RequestBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); } - - void Write(Kernel::HLERequestContext& ctx) { - IPC::RequestBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service, "(STUBBED) called"); - } - - void Flush(Kernel::HLERequestContext& ctx) { - IPC::RequestBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service, "(STUBBED) called"); - } - - void SetSize(Kernel::HLERequestContext& ctx) { - IPC::RequestBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service, "(STUBBED) called"); - } - - void GetSize(Kernel::HLERequestContext& ctx) { - IPC::RequestBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service, "(STUBBED) called"); - } }; FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { @@ -87,46 +77,62 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") { RegisterHandlers(functions); } +void FSP_SRV::TryLoadRomFS() { + if (romfs) { + return; + } + FileSys::Path unused; + auto res = OpenFileSystem(Type::RomFS, unused); + if (res.Succeeded()) { + romfs = std::move(res.Unwrap()); + } +} + void FSP_SRV::Initalize(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + IPC::RequestBuilder rb{ctx, 2}; rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service, "(STUBBED) called"); } void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called"); + IPC::RequestBuilder rb{ctx, 4}; rb.Push(RESULT_SUCCESS); rb.Push(5); - LOG_WARNING(Service, "(STUBBED) called"); } void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) { - FileSys::Path path; - auto filesystem = OpenFileSystem(Type::RomFS, path); - if (filesystem.Failed()) { + LOG_DEBUG(Service_FS, "called"); + + TryLoadRomFS(); + if (!romfs) { + // TODO (bunnei): Find the right error code to use here + LOG_CRITICAL(Service_FS, "no file system interface available!"); IPC::RequestBuilder rb{ctx, 2}; - rb.Push(filesystem.Code()); + rb.Push(ResultCode(-1)); return; } - auto storage = filesystem.Unwrap()->OpenFile({}, {}); + // Attempt to open a StorageBackend interface to the RomFS + auto storage = romfs->OpenFile({}, {}); if (storage.Failed()) { + LOG_CRITICAL(Service_FS, "no storage interface available!"); IPC::RequestBuilder rb{ctx, 2}; rb.Push(storage.Code()); return; } - // TODO: What if already opened? - IPC::RequestBuilder rb{ctx, 2, 0, 0, 1}; rb.Push(RESULT_SUCCESS); rb.PushIpcInterface(std::move(storage.Unwrap())); - LOG_WARNING(Service, "(STUBBED) called"); } void FSP_SRV::OpenRomStorage(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_FS, "(STUBBED) called, using OpenDataStorageByCurrentProcess"); OpenDataStorageByCurrentProcess(ctx); } -} // namespace Filesystem +} // namespace FileSystem } // namespace Service diff --git a/src/core/hle/service/filesystem/fsp_srv.h b/src/core/hle/service/filesystem/fsp_srv.h index b41ba6bd1..15be8edc1 100644 --- a/src/core/hle/service/filesystem/fsp_srv.h +++ b/src/core/hle/service/filesystem/fsp_srv.h @@ -4,22 +4,31 @@ #pragma once +#include #include "core/hle/service/service.h" +namespace FileSys { +class FileSystemBackend; +} + namespace Service { namespace FileSystem { class FSP_SRV final : public ServiceFramework { public: - FSP_SRV(); + explicit FSP_SRV(); ~FSP_SRV() = default; private: + void TryLoadRomFS(); + void Initalize(Kernel::HLERequestContext& ctx); void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx); void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx); void OpenRomStorage(Kernel::HLERequestContext& ctx); + + std::unique_ptr romfs; }; -} // namespace Filesystem +} // namespace FileSystem } // namespace Service From 5035d18baaad5cee4cbc671710de472b9f25a920 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 20 Jan 2018 23:01:00 -0500 Subject: [PATCH 8/8] file_sys: Clang format fixes. --- src/core/file_sys/filesystem.h | 2 +- src/core/file_sys/romfs_factory.cpp | 3 +-- src/core/file_sys/romfs_filesystem.cpp | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h index eb3d9c4d6..02705506b 100644 --- a/src/core/file_sys/filesystem.h +++ b/src/core/file_sys/filesystem.h @@ -139,7 +139,7 @@ public: * @return Opened file, or error code */ virtual ResultVal> OpenFile(const Path& path, - const Mode& mode) const = 0; + const Mode& mode) const = 0; /** * Open a directory specified by its path diff --git a/src/core/file_sys/romfs_factory.cpp b/src/core/file_sys/romfs_factory.cpp index 590c2acb3..e0de49f05 100644 --- a/src/core/file_sys/romfs_factory.cpp +++ b/src/core/file_sys/romfs_factory.cpp @@ -23,8 +23,7 @@ ResultVal> RomFS_Factory::Open(const Path& pa return MakeResult>(std::move(archive)); } -ResultCode RomFS_Factory::Format(const Path& path, - const FileSys::ArchiveFormatInfo& format_info) { +ResultCode RomFS_Factory::Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) { LOG_ERROR(Service_FS, "Unimplemented Format archive %s", GetName().c_str()); // TODO(bunnei): Find the right error code for this return ResultCode(-1); diff --git a/src/core/file_sys/romfs_filesystem.cpp b/src/core/file_sys/romfs_filesystem.cpp index 5b5c5a73e..ca1463d7c 100644 --- a/src/core/file_sys/romfs_filesystem.cpp +++ b/src/core/file_sys/romfs_filesystem.cpp @@ -69,7 +69,8 @@ ResultCode RomFS_FileSystem::RenameDirectory(const Path& src_path, const Path& d return ResultCode(-1); } -ResultVal> RomFS_FileSystem::OpenDirectory(const Path& path) const { +ResultVal> RomFS_FileSystem::OpenDirectory( + const Path& path) const { return MakeResult>(std::make_unique()); }