From 00851a5ef442947c4237f32e063c37e7751db3ed Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 19 Jan 2018 22:34:48 -0500 Subject: file_sys: Cleanup to better match Switch file system constructs. file_sys: Add factory class for RomFS file system. --- src/core/CMakeLists.txt | 14 +-- src/core/file_sys/archive_backend.cpp | 122 --------------------- src/core/file_sys/archive_backend.h | 190 --------------------------------- src/core/file_sys/directory.h | 58 ++++++++++ src/core/file_sys/directory_backend.h | 58 ---------- src/core/file_sys/file_backend.h | 66 ------------ src/core/file_sys/filesystem.cpp | 122 +++++++++++++++++++++ src/core/file_sys/filesystem.h | 190 +++++++++++++++++++++++++++++++++ src/core/file_sys/path_parser.h | 2 +- src/core/file_sys/romfs_archive.cpp | 105 ------------------ src/core/file_sys/romfs_archive.h | 80 -------------- src/core/file_sys/romfs_factory.cpp | 39 +++++++ src/core/file_sys/romfs_factory.h | 35 ++++++ src/core/file_sys/romfs_filesystem.cpp | 105 ++++++++++++++++++ src/core/file_sys/romfs_filesystem.h | 80 ++++++++++++++ src/core/file_sys/storage.h | 63 +++++++++++ 16 files changed, 701 insertions(+), 628 deletions(-) delete mode 100644 src/core/file_sys/archive_backend.cpp delete mode 100644 src/core/file_sys/archive_backend.h create mode 100644 src/core/file_sys/directory.h delete mode 100644 src/core/file_sys/directory_backend.h delete mode 100644 src/core/file_sys/file_backend.h create mode 100644 src/core/file_sys/filesystem.cpp create mode 100644 src/core/file_sys/filesystem.h delete mode 100644 src/core/file_sys/romfs_archive.cpp delete mode 100644 src/core/file_sys/romfs_archive.h create mode 100644 src/core/file_sys/romfs_factory.cpp create mode 100644 src/core/file_sys/romfs_factory.h create mode 100644 src/core/file_sys/romfs_filesystem.cpp create mode 100644 src/core/file_sys/romfs_filesystem.h create mode 100644 src/core/file_sys/storage.h 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/archive_backend.cpp b/src/core/file_sys/archive_backend.cpp deleted file mode 100644 index fc472b44f..000000000 --- a/src/core/file_sys/archive_backend.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include "common/logging/log.h" -#include "common/string_util.h" -#include "core/file_sys/archive_backend.h" -#include "core/memory.h" - -namespace FileSys { - -Path::Path(LowPathType type, u32 size, u32 pointer) : type(type) { - switch (type) { - case Binary: { - binary.resize(size); - Memory::ReadBlock(pointer, binary.data(), binary.size()); - break; - } - - case Char: { - string.resize(size - 1); // Data is always null-terminated. - Memory::ReadBlock(pointer, &string[0], string.size()); - break; - } - - case Wchar: { - u16str.resize(size / 2 - 1); // Data is always null-terminated. - Memory::ReadBlock(pointer, &u16str[0], u16str.size() * sizeof(char16_t)); - break; - } - - default: - break; - } -} - -std::string Path::DebugStr() const { - switch (GetType()) { - case Invalid: - default: - 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() + ']'; - } -} - -std::string Path::AsString() const { - switch (GetType()) { - case Char: - return string; - case Wchar: - return Common::UTF16ToUTF8(u16str); - case Empty: - return {}; - case Invalid: - case Binary: - default: - // TODO(yuriks): Add assert - LOG_ERROR(Service_FS, "LowPathType cannot be converted to string!"); - return {}; - } -} - -std::u16string Path::AsU16Str() const { - switch (GetType()) { - case Char: - return Common::UTF8ToUTF16(string); - case Wchar: - return u16str; - case Empty: - return {}; - case Invalid: - case Binary: - // TODO(yuriks): Add assert - LOG_ERROR(Service_FS, "LowPathType cannot be converted to u16string!"); - return {}; - } - - UNREACHABLE(); -} - -std::vector Path::AsBinary() const { - switch (GetType()) { - case Binary: - return binary; - case Char: - return std::vector(string.begin(), string.end()); - case Wchar: { - // use two u8 for each character of u16str - std::vector to_return(u16str.size() * 2); - for (size_t i = 0; i < u16str.size(); ++i) { - u16 tmp_char = u16str.at(i); - to_return[i * 2] = (tmp_char & 0xFF00) >> 8; - to_return[i * 2 + 1] = (tmp_char & 0x00FF); - } - return to_return; - } - case Empty: - return {}; - case Invalid: - default: - // TODO(yuriks): Add assert - LOG_ERROR(Service_FS, "LowPathType cannot be converted to binary!"); - return {}; - } -} -} // namespace FileSys diff --git a/src/core/file_sys/archive_backend.h b/src/core/file_sys/archive_backend.h deleted file mode 100644 index 2255bee42..000000000 --- a/src/core/file_sys/archive_backend.h +++ /dev/null @@ -1,190 +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/bit_field.h" -#include "common/common_types.h" -#include "common/swap.h" -#include "core/hle/result.h" - -namespace FileSys { - -class FileBackend; -class DirectoryBackend; - -// 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(const char* path) : type(Char), string(path) {} - Path(std::vector binary_data) : type(Binary), binary(std::move(binary_data)) {} - Path(LowPathType type, u32 size, u32 pointer); - - LowPathType GetType() const { - return type; - } - - /** - * Gets the string representation of the path for debugging - * @return String representation of the path for debugging - */ - std::string DebugStr() const; - - std::string AsString() const; - std::u16string AsU16Str() const; - std::vector AsBinary() const; - -private: - LowPathType type; - std::vector binary; - std::string string; - std::u16string u16str; -}; - -/// Parameters of the archive, as specified in the Create or Format call. -struct ArchiveFormatInfo { - u32_le total_size; ///< The pre-defined size of the archive. - u32_le number_directories; ///< The pre-defined number of directories in the archive. - u32_le number_files; ///< The pre-defined number of files in the archive. - u8 duplicate_data; ///< Whether the archive should duplicate the data. -}; -static_assert(std::is_pod::value, "ArchiveFormatInfo is not POD"); - -class ArchiveBackend : NonCopyable { -public: - virtual ~ArchiveBackend() {} - - /** - * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) - */ - virtual std::string GetName() 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 - * @return Result of the operation - */ - virtual ResultCode CreateFile(const Path& path, u64 size) const = 0; - - /** - * Delete a file specified by its path - * @param path Path relative to the archive - * @return Result of the operation - */ - virtual ResultCode DeleteFile(const Path& path) 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; - - /** - * Delete a directory specified by its path - * @param path Path relative to the archive - * @return Result of the operation - */ - virtual ResultCode DeleteDirectory(const Path& path) const = 0; - - /** - * Delete a directory specified by its path and anything under it - * @param path Path relative to the archive - * @return Result of the operation - */ - virtual ResultCode DeleteDirectoryRecursively(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 - * @return Result of the operation - */ - virtual ResultCode RenameFile(const Path& src_path, const Path& dest_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 Result of the operation - */ - 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 - * @return Opened directory, or error code - */ - virtual ResultVal> OpenDirectory(const Path& path) const = 0; - - /** - * Get the free space - * @return The number of free bytes in the archive - */ - virtual u64 GetFreeSpaceSize() const = 0; -}; - -class ArchiveFactory : NonCopyable { -public: - virtual ~ArchiveFactory() {} - - /** - * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) - */ - virtual std::string GetName() const = 0; - - /** - * Tries to open the archive of this type with the specified path - * @param path Path to the archive - * @return An ArchiveBackend corresponding operating specified archive path. - */ - virtual ResultVal> Open(const Path& path) = 0; - - /** - * Deletes the archive contents and then re-creates the base folder - * @param path Path to the archive - * @param format_info Format information for the new archive - * @return ResultCode of the operation, 0 on success - */ - virtual ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) = 0; - - /** - * Retrieves the format info about the archive with the specified path - * @param path Path to the archive - * @return Format information about the archive or error code - */ - virtual ResultVal GetFormatInfo(const Path& path) const = 0; -}; - -} // namespace FileSys diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h new file mode 100644 index 000000000..5a40bf472 --- /dev/null +++ b/src/core/file_sys/directory.h @@ -0,0 +1,58 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include "common/common_types.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() {} + + /** + * 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 deleted file mode 100644 index 0c93f2074..000000000 --- a/src/core/file_sys/directory_backend.h +++ /dev/null @@ -1,58 +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 "common/common_types.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() {} - - /** - * 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/file_backend.h b/src/core/file_sys/file_backend.h deleted file mode 100644 index 5e7c2bab4..000000000 --- a/src/core/file_sys/file_backend.h +++ /dev/null @@ -1,66 +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 "common/common_types.h" -#include "core/hle/result.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// FileSys namespace - -namespace FileSys { - -class FileBackend : NonCopyable { -public: - FileBackend() {} - virtual ~FileBackend() {} - - /** - * 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, or error code - */ - virtual ResultVal Read(u64 offset, size_t 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, or error code - */ - virtual ResultVal Write(u64 offset, size_t length, bool flush, - const u8* buffer) const = 0; - - /** - * Get the size of the file in bytes - * @return Size of the file in bytes - */ - virtual u64 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(u64 size) 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 diff --git a/src/core/file_sys/filesystem.cpp b/src/core/file_sys/filesystem.cpp new file mode 100644 index 000000000..82fdb3c46 --- /dev/null +++ b/src/core/file_sys/filesystem.cpp @@ -0,0 +1,122 @@ +// Copyright 2018 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include +#include +#include "common/logging/log.h" +#include "common/string_util.h" +#include "core/file_sys/filesystem.h" +#include "core/memory.h" + +namespace FileSys { + +Path::Path(LowPathType type, u32 size, u32 pointer) : type(type) { + switch (type) { + case Binary: { + binary.resize(size); + Memory::ReadBlock(pointer, binary.data(), binary.size()); + break; + } + + case Char: { + string.resize(size - 1); // Data is always null-terminated. + Memory::ReadBlock(pointer, &string[0], string.size()); + break; + } + + case Wchar: { + u16str.resize(size / 2 - 1); // Data is always null-terminated. + Memory::ReadBlock(pointer, &u16str[0], u16str.size() * sizeof(char16_t)); + break; + } + + default: + break; + } +} + +std::string Path::DebugStr() const { + switch (GetType()) { + case Invalid: + default: + 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() + ']'; + } +} + +std::string Path::AsString() const { + switch (GetType()) { + case Char: + return string; + case Wchar: + return Common::UTF16ToUTF8(u16str); + case Empty: + return {}; + case Invalid: + case Binary: + default: + // TODO(yuriks): Add assert + LOG_ERROR(Service_FS, "LowPathType cannot be converted to string!"); + return {}; + } +} + +std::u16string Path::AsU16Str() const { + switch (GetType()) { + case Char: + return Common::UTF8ToUTF16(string); + case Wchar: + return u16str; + case Empty: + return {}; + case Invalid: + case Binary: + // TODO(yuriks): Add assert + LOG_ERROR(Service_FS, "LowPathType cannot be converted to u16string!"); + return {}; + } + + UNREACHABLE(); +} + +std::vector Path::AsBinary() const { + switch (GetType()) { + case Binary: + return binary; + case Char: + return std::vector(string.begin(), string.end()); + case Wchar: { + // use two u8 for each character of u16str + std::vector to_return(u16str.size() * 2); + for (size_t i = 0; i < u16str.size(); ++i) { + u16 tmp_char = u16str.at(i); + to_return[i * 2] = (tmp_char & 0xFF00) >> 8; + to_return[i * 2 + 1] = (tmp_char & 0x00FF); + } + return to_return; + } + case Empty: + return {}; + case Invalid: + default: + // TODO(yuriks): Add assert + LOG_ERROR(Service_FS, "LowPathType cannot be converted to binary!"); + return {}; + } +} +} // namespace FileSys diff --git a/src/core/file_sys/filesystem.h b/src/core/file_sys/filesystem.h new file mode 100644 index 000000000..eb3d9c4d6 --- /dev/null +++ b/src/core/file_sys/filesystem.h @@ -0,0 +1,190 @@ +// 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 +#include "common/bit_field.h" +#include "common/common_types.h" +#include "common/swap.h" +#include "core/hle/result.h" + +namespace FileSys { + +class StorageBackend; +class DirectoryBackend; + +// 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(const char* path) : type(Char), string(path) {} + Path(std::vector binary_data) : type(Binary), binary(std::move(binary_data)) {} + Path(LowPathType type, u32 size, u32 pointer); + + LowPathType GetType() const { + return type; + } + + /** + * Gets the string representation of the path for debugging + * @return String representation of the path for debugging + */ + std::string DebugStr() const; + + std::string AsString() const; + std::u16string AsU16Str() const; + std::vector AsBinary() const; + +private: + LowPathType type; + std::vector binary; + std::string string; + std::u16string u16str; +}; + +/// Parameters of the archive, as specified in the Create or Format call. +struct ArchiveFormatInfo { + u32_le total_size; ///< The pre-defined size of the archive. + u32_le number_directories; ///< The pre-defined number of directories in the archive. + u32_le number_files; ///< The pre-defined number of files in the archive. + u8 duplicate_data; ///< Whether the archive should duplicate the data. +}; +static_assert(std::is_pod::value, "ArchiveFormatInfo is not POD"); + +class FileSystemBackend : NonCopyable { +public: + virtual ~FileSystemBackend() {} + + /** + * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) + */ + virtual std::string GetName() 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 + * @return Result of the operation + */ + virtual ResultCode CreateFile(const Path& path, u64 size) const = 0; + + /** + * Delete a file specified by its path + * @param path Path relative to the archive + * @return Result of the operation + */ + virtual ResultCode DeleteFile(const Path& path) 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; + + /** + * Delete a directory specified by its path + * @param path Path relative to the archive + * @return Result of the operation + */ + virtual ResultCode DeleteDirectory(const Path& path) const = 0; + + /** + * Delete a directory specified by its path and anything under it + * @param path Path relative to the archive + * @return Result of the operation + */ + virtual ResultCode DeleteDirectoryRecursively(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 + * @return Result of the operation + */ + virtual ResultCode RenameFile(const Path& src_path, const Path& dest_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 Result of the operation + */ + 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 + * @return Opened directory, or error code + */ + virtual ResultVal> OpenDirectory(const Path& path) const = 0; + + /** + * Get the free space + * @return The number of free bytes in the archive + */ + virtual u64 GetFreeSpaceSize() const = 0; +}; + +class FileSystemFactory : NonCopyable { +public: + virtual ~FileSystemFactory() {} + + /** + * Get a descriptive name for the archive (e.g. "RomFS", "SaveData", etc.) + */ + virtual std::string GetName() const = 0; + + /** + * Tries to open the archive of this type with the specified path + * @param path Path to the archive + * @return An ArchiveBackend corresponding operating specified archive path. + */ + virtual ResultVal> Open(const Path& path) = 0; + + /** + * Deletes the archive contents and then re-creates the base folder + * @param path Path to the archive + * @param format_info Format information for the new archive + * @return ResultCode of the operation, 0 on success + */ + virtual ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info) = 0; + + /** + * Retrieves the format info about the archive with the specified path + * @param path Path to the archive + * @return Format information about the archive or error code + */ + virtual ResultVal GetFormatInfo(const Path& path) const = 0; +}; + +} // namespace FileSys 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_archive.cpp b/src/core/file_sys/romfs_archive.cpp deleted file mode 100644 index 0d93fccd4..000000000 --- a/src/core/file_sys/romfs_archive.cpp +++ /dev/null @@ -1,105 +0,0 @@ -// 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_archive.h" - -namespace FileSys { - -std::string ROMFSArchive::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)); -} - -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 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 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 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 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 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 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> ROMFSArchive::OpenDirectory(const Path& path) const { - return MakeResult>(std::make_unique()); -} - -u64 ROMFSArchive::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 { - 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); - - 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 { - LOG_ERROR(Service_FS, "Attempted to write to ROMFS file"); - // TODO(Subv): Find error code - return MakeResult(0); -} - -u64 ROMFSFile::GetSize() const { - return data_size; -} - -bool ROMFSFile::SetSize(const u64 size) const { - LOG_ERROR(Service_FS, "Attempted to set the size of an ROMFS file"); - return false; -} - -} // namespace FileSys diff --git a/src/core/file_sys/romfs_archive.h b/src/core/file_sys/romfs_archive.h deleted file mode 100644 index 2b6c573ba..000000000 --- a/src/core/file_sys/romfs_archive.h +++ /dev/null @@ -1,80 +0,0 @@ -// 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 -#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" - -namespace FileSys { - -/** - * 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 ROMFSArchive : public ArchiveBackend { -public: - ROMFSArchive(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; - 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::shared_ptr romfs_file; - u64 data_offset; - u64 data_size; -}; - -class ROMFSFile : public FileBackend { -public: - 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; - 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 { - return false; - } - void Flush() const override {} - -private: - std::shared_ptr romfs_file; - u64 data_offset; - u64 data_size; -}; - -class ROMFSDirectory : public DirectoryBackend { -public: - u32 Read(const u32 count, Entry* entries) override { - return 0; - } - bool Close() const override { - return false; - } -}; - -} // 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_filesystem.cpp b/src/core/file_sys/romfs_filesystem.cpp new file mode 100644 index 000000000..5b5c5a73e --- /dev/null +++ b/src/core/file_sys/romfs_filesystem.cpp @@ -0,0 +1,105 @@ +// 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_filesystem.h" + +namespace FileSys { + +std::string RomFS_FileSystem::GetName() const { + return "RomFS"; +} + +ResultVal> RomFS_FileSystem::OpenFile(const Path& path, + const Mode& mode) const { + return MakeResult>( + std::make_unique(romfs_file, data_offset, data_size)); +} + +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 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 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 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 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 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 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> RomFS_FileSystem::OpenDirectory(const Path& path) const { + return MakeResult>(std::make_unique()); +} + +u64 RomFS_FileSystem::GetFreeSpaceSize() const { + LOG_WARNING(Service_FS, "Attempted to get the free space in an ROMFS archive"); + return 0; +} + +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); + + return MakeResult(romfs_file->ReadBytes(buffer, read_length)); +} + +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 RomFS_Storage::GetSize() const { + return data_size; +} + +bool RomFS_Storage::SetSize(const u64 size) const { + LOG_ERROR(Service_FS, "Attempted to set the size of an ROMFS file"); + return false; +} + +} // namespace FileSys diff --git a/src/core/file_sys/romfs_filesystem.h b/src/core/file_sys/romfs_filesystem.h new file mode 100644 index 000000000..900ea567a --- /dev/null +++ b/src/core/file_sys/romfs_filesystem.h @@ -0,0 +1,80 @@ +// 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 +#include "common/common_types.h" +#include "common/file_util.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 { + +/** + * 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 RomFS_FileSystem : public FileSystemBackend { +public: + 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; + 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::shared_ptr romfs_file; + u64 data_offset; + u64 data_size; +}; + +class RomFS_Storage : public StorageBackend { +public: + 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; + 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 { + return false; + } + void Flush() const override {} + +private: + std::shared_ptr romfs_file; + u64 data_offset; + u64 data_size; +}; + +class ROMFSDirectory : public DirectoryBackend { +public: + u32 Read(const u32 count, Entry* entries) override { + return 0; + } + bool Close() const override { + return false; + } +}; + +} // namespace FileSys diff --git a/src/core/file_sys/storage.h b/src/core/file_sys/storage.h new file mode 100644 index 000000000..2a6811831 --- /dev/null +++ b/src/core/file_sys/storage.h @@ -0,0 +1,63 @@ +// 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/hle/result.h" + +namespace FileSys { + +class StorageBackend : NonCopyable { +public: + StorageBackend() {} + virtual ~StorageBackend() {} + + /** + * 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, or error code + */ + virtual ResultVal Read(u64 offset, size_t 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, or error code + */ + virtual ResultVal Write(u64 offset, size_t length, bool flush, + const u8* buffer) const = 0; + + /** + * Flushes the file + */ + virtual void Flush() const = 0; + + /** + * Set the size of the file in bytes + * @param size New size of the file + * @return true if successful + */ + 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; +}; + +} // namespace FileSys -- cgit v1.2.3