From f1dbb8952c3060e5ebe9cdb60cc9e4539e93a4c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sat, 3 Mar 2018 00:56:15 +0100 Subject: [PATCH] IOS: Introduce a new FileSystem interface Add a new FileSystem class that can be used to perform operations on the emulated Wii filesystem. This will allow separating the IPC code (reading from and writing to memory to handle IOS FS commands) and the actual filesystem code in a much better way. This also paves the way for implementing another filesystem backend in the future -- NAND images for more complete emulation, including filesystem metadata like permissions or file orders, which some games and homebrew actually care about -- without needing to make any more changes to the other parts of the codebase, in addition to making filesystem behaviour tests easier to write. --- Source/Core/Core/Core.vcxproj | 1 + Source/Core/Core/Core.vcxproj.filters | 3 + Source/Core/Core/IOS/FS/FileSystem.h | 173 ++++++++++++++++++++++++++ 3 files changed, 177 insertions(+) create mode 100644 Source/Core/Core/IOS/FS/FileSystem.h diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 99f2b19876..79c478f980 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -446,6 +446,7 @@ + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 189b7d2088..d3b4d3be27 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -1404,6 +1404,9 @@ IOS\FS + + IOS\FS + IOS\ES diff --git a/Source/Core/Core/IOS/FS/FileSystem.h b/Source/Core/Core/IOS/FS/FileSystem.h new file mode 100644 index 0000000000..6607c9ab02 --- /dev/null +++ b/Source/Core/Core/IOS/FS/FileSystem.h @@ -0,0 +1,173 @@ +// Copyright 2018 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "Common/CommonTypes.h" +#include "Common/Result.h" + +class PointerWrap; + +namespace IOS::HLE::FS +{ +enum class ResultCode +{ + Success, + Invalid, + AccessDenied, + SuperblockWriteFailed, + SuperblockInitFailed, + AlreadyExists, + NotFound, + FstFull, + NoFreeSpace, + NoFreeHandle, + TooManyPathComponents, + InUse, + BadBlock, + EccError, + CriticalEccError, + FileNotEmpty, + CheckFailed, + UnknownError, + ShortRead, +}; + +template +using Result = Common::Result; + +using Uid = u32; +using Gid = u16; +using Fd = u32; + +enum class Mode : u8 +{ + None = 0, + Read = 1, + Write = 2, + ReadWrite = 3, +}; + +enum class SeekMode : u32 +{ + Set = 0, + Current = 1, + End = 2, +}; + +using FileAttribute = u8; + +struct Metadata +{ + Uid uid; + Gid gid; + FileAttribute attribute; + Mode owner_mode, group_mode, other_mode; + bool is_file; + u32 size; + u16 fst_index; +}; + +struct NandStats +{ + u32 cluster_size; + u32 free_clusters; + u32 used_clusters; + u32 bad_clusters; + u32 reserved_clusters; + u32 free_inodes; + u32 used_inodes; +}; + +struct DirectoryStats +{ + u32 used_clusters; + u32 used_inodes; +}; + +struct FileStatus +{ + u32 offset; + u32 size; +}; + +class FileSystem +{ +public: + virtual ~FileSystem() = default; + + virtual void DoState(PointerWrap& p) = 0; + + /// Format the file system. + virtual ResultCode Format(Uid uid) = 0; + + /// Get a file descriptor for accessing a file. + virtual Result OpenFile(Uid uid, Gid gid, const std::string& path, Mode mode) = 0; + /// Close a file descriptor. + virtual ResultCode Close(Fd fd) = 0; + /// Read `size` bytes from the file descriptor. Returns the number of bytes read. + virtual Result ReadBytesFromFile(Fd fd, u8* ptr, u32 size) = 0; + /// Write `size` bytes to the file descriptor. Returns the number of bytes written. + virtual Result WriteBytesToFile(Fd fd, const u8* ptr, u32 size) = 0; + /// Reposition the file offset for a file descriptor. + virtual Result SeekFile(Fd fd, u32 offset, SeekMode mode) = 0; + /// Get status for a file descriptor. + virtual Result GetFileStatus(Fd fd) = 0; + + template + Result ReadFile(Fd fd, T* ptr, u32 count) + { + const Result bytes = ReadBytesFromFile(fd, reinterpret_cast(ptr), sizeof(T) * count); + if (!bytes) + return bytes.Error(); + if (*bytes != sizeof(T) * count) + return ResultCode::ShortRead; + return count; + } + + template + Result WriteFile(Fd fd, const T* ptr, u32 count) + { + const auto result = WriteBytesToFile(fd, reinterpret_cast(ptr), sizeof(T) * count); + if (!result) + return result.Error(); + return count; + } + + /// Create a file with the specified path and metadata. + virtual ResultCode CreateFile(Uid caller_uid, Gid caller_gid, const std::string& path, + FileAttribute attribute, Mode owner_mode, Mode group_mode, + Mode other_mode) = 0; + /// Create a directory with the specified path and metadata. + virtual ResultCode CreateDirectory(Uid caller_uid, Gid caller_gid, const std::string& path, + FileAttribute attribute, Mode owner_mode, Mode group_mode, + Mode other_mode) = 0; + + /// Delete a file or directory with the specified path. + virtual ResultCode Delete(Uid caller_uid, Gid caller_gid, const std::string& path) = 0; + /// Rename a file or directory with the specified path. + virtual ResultCode Rename(Uid caller_uid, Gid caller_gid, const std::string& old_path, + const std::string& new_path) = 0; + + /// List the children of a directory (non-recursively). + virtual Result> ReadDirectory(Uid caller_uid, Gid caller_gid, + const std::string& path) = 0; + + /// Get metadata about a file. + virtual Result GetMetadata(Uid caller_uid, Gid caller_gid, const std::string& path) = 0; + /// Set metadata for a file. + virtual ResultCode SetMetadata(Uid caller_uid, const std::string& path, Uid uid, Gid gid, + FileAttribute attribute, Mode owner_mode, Mode group_mode, + Mode other_mode) = 0; + + /// Get usage information about the NAND (block size, cluster and inode counts). + virtual Result GetNandStats() = 0; + /// Get usage information about a directory (used cluster and inode counts). + virtual Result GetDirectoryStats(const std::string& path) = 0; +}; + +} // namespace IOS::HLE::FS