From 77c684c1140f6bf3fb7d4560d06d2efb1a2ee5e2 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 6 Jul 2018 10:51:32 -0400 Subject: Virtual Filesystem (#597) * Add VfsFile and VfsDirectory classes * Finish abstract Vfs classes * Implement RealVfsFile (computer fs backend) * Finish RealVfsFile and RealVfsDirectory * Finished OffsetVfsFile * More changes * Fix import paths * Major refactor * Remove double const * Use experimental/filesystem or filesystem depending on compiler * Port partition_filesystem * More changes * More Overhaul * FSP_SRV fixes * Fixes and testing * Try to get filesystem to compile * Filesystem on linux * Remove std::filesystem and document/test * Compile fixes * Missing include * Bug fixes * Fixes * Rename v_file and v_dir * clang-format fix * Rename NGLOG_* to LOG_* * Most review changes * Fix TODO * Guess 'main' to be Directory by filename --- src/core/file_sys/vfs.h | 220 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 220 insertions(+) create mode 100644 src/core/file_sys/vfs.h (limited to 'src/core/file_sys/vfs.h') diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h new file mode 100644 index 000000000..0e30991b4 --- /dev/null +++ b/src/core/file_sys/vfs.h @@ -0,0 +1,220 @@ +// 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 "boost/optional.hpp" +#include "common/common_types.h" +#include "common/file_util.h" + +namespace FileSys { +struct VfsFile; +struct VfsDirectory; + +// Convenience typedefs to use VfsDirectory and VfsFile +using VirtualDir = std::shared_ptr; +using VirtualFile = std::shared_ptr; + +// A class representing a file in an abstract filesystem. +struct VfsFile : NonCopyable { + virtual ~VfsFile(); + + // Retrieves the file name. + virtual std::string GetName() const = 0; + // Retrieves the extension of the file name. + virtual std::string GetExtension() const; + // Retrieves the size of the file. + virtual size_t GetSize() const = 0; + // Resizes the file to new_size. Returns whether or not the operation was successful. + virtual bool Resize(size_t new_size) = 0; + // Gets a pointer to the directory containing this file, returning nullptr if there is none. + virtual std::shared_ptr GetContainingDirectory() const = 0; + + // Returns whether or not the file can be written to. + virtual bool IsWritable() const = 0; + // Returns whether or not the file can be read from. + virtual bool IsReadable() const = 0; + + // The primary method of reading from the file. Reads length bytes into data starting at offset + // into file. Returns number of bytes successfully read. + virtual size_t Read(u8* data, size_t length, size_t offset = 0) const = 0; + // The primary method of writing to the file. Writes length bytes from data starting at offset + // into file. Returns number of bytes successfully written. + virtual size_t Write(const u8* data, size_t length, size_t offset = 0) = 0; + + // Reads exactly one byte at the offset provided, returning boost::none on error. + virtual boost::optional ReadByte(size_t offset = 0) const; + // Reads size bytes starting at offset in file into a vector. + virtual std::vector ReadBytes(size_t size, size_t offset = 0) const; + // Reads all the bytes from the file into a vector. Equivalent to 'file->Read(file->GetSize(), + // 0)' + virtual std::vector ReadAllBytes() const; + + // Reads an array of type T, size number_elements starting at offset. + // Returns the number of bytes (sizeof(T)*number_elements) read successfully. + template + size_t ReadArray(T* data, size_t number_elements, size_t offset = 0) const { + static_assert(std::is_trivially_copyable::value, + "Data type must be trivially copyable."); + + return Read(reinterpret_cast(data), number_elements * sizeof(T), offset); + } + + // Reads size bytes into the memory starting at data starting at offset into the file. + // Returns the number of bytes read successfully. + template + size_t ReadBytes(T* data, size_t size, size_t offset = 0) const { + static_assert(std::is_trivially_copyable::value, + "Data type must be trivially copyable."); + return Read(reinterpret_cast(data), size, offset); + } + + // Reads one object of type T starting at offset in file. + // Returns the number of bytes read successfully (sizeof(T)). + template + size_t ReadObject(T* data, size_t offset = 0) const { + static_assert(std::is_trivially_copyable::value, + "Data type must be trivially copyable."); + return Read(reinterpret_cast(data), sizeof(T), offset); + } + + // Writes exactly one byte to offset in file and retuns whether or not the byte was written + // successfully. + virtual bool WriteByte(u8 data, size_t offset = 0); + // Writes a vector of bytes to offset in file and returns the number of bytes successfully + // written. + virtual size_t WriteBytes(std::vector data, size_t offset = 0); + + // Writes an array of type T, size number_elements to offset in file. + // Returns the number of bytes (sizeof(T)*number_elements) written successfully. + template + size_t WriteArray(T* data, size_t number_elements, size_t offset = 0) { + static_assert(std::is_trivially_copyable::value, + "Data type must be trivially copyable."); + + return Write(data, number_elements * sizeof(T), offset); + } + + // Writes size bytes starting at memory location data to offset in file. + // Returns the number of bytes written successfully. + template + size_t WriteBytes(T* data, size_t size, size_t offset = 0) { + static_assert(std::is_trivially_copyable::value, + "Data type must be trivially copyable."); + return Write(reinterpret_cast(data), size, offset); + } + + // Writes one object of type T to offset in file. + // Returns the number of bytes written successfully (sizeof(T)). + template + size_t WriteObject(const T& data, size_t offset = 0) { + static_assert(std::is_trivially_copyable::value, + "Data type must be trivially copyable."); + return Write(&data, sizeof(T), offset); + } + + // Renames the file to name. Returns whether or not the operation was successsful. + virtual bool Rename(const std::string& name) = 0; +}; + +// A class representing a directory in an abstract filesystem. +struct VfsDirectory : NonCopyable { + virtual ~VfsDirectory(); + + // Retrives the file located at path as if the current directory was root. Returns nullptr if + // not found. + virtual std::shared_ptr GetFileRelative(const std::string& path) const; + // Calls GetFileRelative(path) on the root of the current directory. + virtual std::shared_ptr GetFileAbsolute(const std::string& path) const; + + // Retrives the directory located at path as if the current directory was root. Returns nullptr + // if not found. + virtual std::shared_ptr GetDirectoryRelative(const std::string& path) const; + // Calls GetDirectoryRelative(path) on the root of the current directory. + virtual std::shared_ptr GetDirectoryAbsolute(const std::string& path) const; + + // Returns a vector containing all of the files in this directory. + virtual std::vector> GetFiles() const = 0; + // Returns the file with filename matching name. Returns nullptr if directory dosen't have a + // file with name. + virtual std::shared_ptr GetFile(const std::string& name) const; + + // Returns a vector containing all of the subdirectories in this directory. + virtual std::vector> GetSubdirectories() const = 0; + // Returns the directory with name matching name. Returns nullptr if directory dosen't have a + // directory with name. + virtual std::shared_ptr GetSubdirectory(const std::string& name) const; + + // Returns whether or not the directory can be written to. + virtual bool IsWritable() const = 0; + // Returns whether of not the directory can be read from. + virtual bool IsReadable() const = 0; + + // Returns whether or not the directory is the root of the current file tree. + virtual bool IsRoot() const; + + // Returns the name of the directory. + virtual std::string GetName() const = 0; + // Returns the total size of all files and subdirectories in this directory. + virtual size_t GetSize() const; + // Returns the parent directory of this directory. Returns nullptr if this directory is root or + // has no parent. + virtual std::shared_ptr GetParentDirectory() const = 0; + + // Creates a new subdirectory with name name. Returns a pointer to the new directory or nullptr + // if the operation failed. + virtual std::shared_ptr CreateSubdirectory(const std::string& name) = 0; + // Creates a new file with name name. Returns a pointer to the new file or nullptr if the + // operation failed. + virtual std::shared_ptr CreateFile(const std::string& name) = 0; + + // Deletes the subdirectory with name and returns true on success. + virtual bool DeleteSubdirectory(const std::string& name) = 0; + // Deletes all subdirectories and files of subdirectory with name recirsively and then deletes + // the subdirectory. Returns true on success. + virtual bool DeleteSubdirectoryRecursive(const std::string& name); + // Returnes whether or not the file with name name was deleted successfully. + virtual bool DeleteFile(const std::string& name) = 0; + + // Returns whether or not this directory was renamed to name. + virtual bool Rename(const std::string& name) = 0; + + // Returns whether or not the file with name src was successfully copied to a new file with name + // dest. + virtual bool Copy(const std::string& src, const std::string& dest); + + // Interprets the file with name file instead as a directory of type directory. + // The directory must have a constructor that takes a single argument of type + // std::shared_ptr. Allows to reinterpret container files (i.e NCA, zip, XCI, etc) as a + // subdirectory in one call. + template + bool InterpretAsDirectory(const std::string& file) { + auto file_p = GetFile(file); + if (file_p == nullptr) + return false; + return ReplaceFileWithSubdirectory(file, std::make_shared(file_p)); + } + +protected: + // Backend for InterpretAsDirectory. + // Removes all references to file and adds a reference to dir in the directory's implementation. + virtual bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) = 0; +}; + +// A convenience partial-implementation of VfsDirectory that stubs out methods that should only work +// if writable. This is to avoid redundant empty methods everywhere. +struct ReadOnlyVfsDirectory : public VfsDirectory { + bool IsWritable() const override; + bool IsReadable() const override; + std::shared_ptr CreateSubdirectory(const std::string& name) override; + std::shared_ptr CreateFile(const std::string& name) override; + bool DeleteSubdirectory(const std::string& name) override; + bool DeleteFile(const std::string& name) override; + bool Rename(const std::string& name) override; +}; +} // namespace FileSys -- cgit v1.2.3