vfs.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <memory>
  6. #include <string>
  7. #include <string_view>
  8. #include <type_traits>
  9. #include <vector>
  10. #include "boost/optional.hpp"
  11. #include "common/common_types.h"
  12. namespace FileSys {
  13. struct VfsFile;
  14. struct VfsDirectory;
  15. // Convenience typedefs to use VfsDirectory and VfsFile
  16. using VirtualDir = std::shared_ptr<FileSys::VfsDirectory>;
  17. using VirtualFile = std::shared_ptr<FileSys::VfsFile>;
  18. // A class representing a file in an abstract filesystem.
  19. struct VfsFile : NonCopyable {
  20. virtual ~VfsFile();
  21. // Retrieves the file name.
  22. virtual std::string GetName() const = 0;
  23. // Retrieves the extension of the file name.
  24. virtual std::string GetExtension() const;
  25. // Retrieves the size of the file.
  26. virtual size_t GetSize() const = 0;
  27. // Resizes the file to new_size. Returns whether or not the operation was successful.
  28. virtual bool Resize(size_t new_size) = 0;
  29. // Gets a pointer to the directory containing this file, returning nullptr if there is none.
  30. virtual std::shared_ptr<VfsDirectory> GetContainingDirectory() const = 0;
  31. // Returns whether or not the file can be written to.
  32. virtual bool IsWritable() const = 0;
  33. // Returns whether or not the file can be read from.
  34. virtual bool IsReadable() const = 0;
  35. // The primary method of reading from the file. Reads length bytes into data starting at offset
  36. // into file. Returns number of bytes successfully read.
  37. virtual size_t Read(u8* data, size_t length, size_t offset = 0) const = 0;
  38. // The primary method of writing to the file. Writes length bytes from data starting at offset
  39. // into file. Returns number of bytes successfully written.
  40. virtual size_t Write(const u8* data, size_t length, size_t offset = 0) = 0;
  41. // Reads exactly one byte at the offset provided, returning boost::none on error.
  42. virtual boost::optional<u8> ReadByte(size_t offset = 0) const;
  43. // Reads size bytes starting at offset in file into a vector.
  44. virtual std::vector<u8> ReadBytes(size_t size, size_t offset = 0) const;
  45. // Reads all the bytes from the file into a vector. Equivalent to 'file->Read(file->GetSize(),
  46. // 0)'
  47. virtual std::vector<u8> ReadAllBytes() const;
  48. // Reads an array of type T, size number_elements starting at offset.
  49. // Returns the number of bytes (sizeof(T)*number_elements) read successfully.
  50. template <typename T>
  51. size_t ReadArray(T* data, size_t number_elements, size_t offset = 0) const {
  52. static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
  53. return Read(reinterpret_cast<u8*>(data), number_elements * sizeof(T), offset);
  54. }
  55. // Reads size bytes into the memory starting at data starting at offset into the file.
  56. // Returns the number of bytes read successfully.
  57. template <typename T>
  58. size_t ReadBytes(T* data, size_t size, size_t offset = 0) const {
  59. static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
  60. return Read(reinterpret_cast<u8*>(data), size, offset);
  61. }
  62. // Reads one object of type T starting at offset in file.
  63. // Returns the number of bytes read successfully (sizeof(T)).
  64. template <typename T>
  65. size_t ReadObject(T* data, size_t offset = 0) const {
  66. static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
  67. return Read(reinterpret_cast<u8*>(data), sizeof(T), offset);
  68. }
  69. // Writes exactly one byte to offset in file and retuns whether or not the byte was written
  70. // successfully.
  71. virtual bool WriteByte(u8 data, size_t offset = 0);
  72. // Writes a vector of bytes to offset in file and returns the number of bytes successfully
  73. // written.
  74. virtual size_t WriteBytes(const std::vector<u8>& data, size_t offset = 0);
  75. // Writes an array of type T, size number_elements to offset in file.
  76. // Returns the number of bytes (sizeof(T)*number_elements) written successfully.
  77. template <typename T>
  78. size_t WriteArray(const T* data, size_t number_elements, size_t offset = 0) {
  79. static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
  80. return Write(data, number_elements * sizeof(T), offset);
  81. }
  82. // Writes size bytes starting at memory location data to offset in file.
  83. // Returns the number of bytes written successfully.
  84. template <typename T>
  85. size_t WriteBytes(const T* data, size_t size, size_t offset = 0) {
  86. static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
  87. return Write(reinterpret_cast<const u8*>(data), size, offset);
  88. }
  89. // Writes one object of type T to offset in file.
  90. // Returns the number of bytes written successfully (sizeof(T)).
  91. template <typename T>
  92. size_t WriteObject(const T& data, size_t offset = 0) {
  93. static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
  94. return Write(&data, sizeof(T), offset);
  95. }
  96. // Renames the file to name. Returns whether or not the operation was successsful.
  97. virtual bool Rename(std::string_view name) = 0;
  98. // Returns the full path of this file as a string, recursively
  99. virtual std::string GetFullPath() const;
  100. };
  101. // A class representing a directory in an abstract filesystem.
  102. struct VfsDirectory : NonCopyable {
  103. virtual ~VfsDirectory();
  104. // Retrives the file located at path as if the current directory was root. Returns nullptr if
  105. // not found.
  106. virtual std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const;
  107. // Calls GetFileRelative(path) on the root of the current directory.
  108. virtual std::shared_ptr<VfsFile> GetFileAbsolute(std::string_view path) const;
  109. // Retrives the directory located at path as if the current directory was root. Returns nullptr
  110. // if not found.
  111. virtual std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const;
  112. // Calls GetDirectoryRelative(path) on the root of the current directory.
  113. virtual std::shared_ptr<VfsDirectory> GetDirectoryAbsolute(std::string_view path) const;
  114. // Returns a vector containing all of the files in this directory.
  115. virtual std::vector<std::shared_ptr<VfsFile>> GetFiles() const = 0;
  116. // Returns the file with filename matching name. Returns nullptr if directory dosen't have a
  117. // file with name.
  118. virtual std::shared_ptr<VfsFile> GetFile(std::string_view name) const;
  119. // Returns a vector containing all of the subdirectories in this directory.
  120. virtual std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const = 0;
  121. // Returns the directory with name matching name. Returns nullptr if directory dosen't have a
  122. // directory with name.
  123. virtual std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const;
  124. // Returns whether or not the directory can be written to.
  125. virtual bool IsWritable() const = 0;
  126. // Returns whether of not the directory can be read from.
  127. virtual bool IsReadable() const = 0;
  128. // Returns whether or not the directory is the root of the current file tree.
  129. virtual bool IsRoot() const;
  130. // Returns the name of the directory.
  131. virtual std::string GetName() const = 0;
  132. // Returns the total size of all files and subdirectories in this directory.
  133. virtual size_t GetSize() const;
  134. // Returns the parent directory of this directory. Returns nullptr if this directory is root or
  135. // has no parent.
  136. virtual std::shared_ptr<VfsDirectory> GetParentDirectory() const = 0;
  137. // Creates a new subdirectory with name name. Returns a pointer to the new directory or nullptr
  138. // if the operation failed.
  139. virtual std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) = 0;
  140. // Creates a new file with name name. Returns a pointer to the new file or nullptr if the
  141. // operation failed.
  142. virtual std::shared_ptr<VfsFile> CreateFile(std::string_view name) = 0;
  143. // Creates a new file at the path relative to this directory. Also creates directories if
  144. // they do not exist and is supported by this implementation. Returns nullptr on any failure.
  145. virtual std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path);
  146. // Creates a new file at the path relative to root of this directory. Also creates directories
  147. // if they do not exist and is supported by this implementation. Returns nullptr on any failure.
  148. virtual std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path);
  149. // Creates a new directory at the path relative to this directory. Also creates directories if
  150. // they do not exist and is supported by this implementation. Returns nullptr on any failure.
  151. virtual std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path);
  152. // Creates a new directory at the path relative to root of this directory. Also creates
  153. // directories if they do not exist and is supported by this implementation. Returns nullptr on
  154. // any failure.
  155. virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path);
  156. // Deletes the subdirectory with name and returns true on success.
  157. virtual bool DeleteSubdirectory(std::string_view name) = 0;
  158. // Deletes all subdirectories and files of subdirectory with name recirsively and then deletes
  159. // the subdirectory. Returns true on success.
  160. virtual bool DeleteSubdirectoryRecursive(std::string_view name);
  161. // Returnes whether or not the file with name name was deleted successfully.
  162. virtual bool DeleteFile(std::string_view name) = 0;
  163. // Returns whether or not this directory was renamed to name.
  164. virtual bool Rename(std::string_view name) = 0;
  165. // Returns whether or not the file with name src was successfully copied to a new file with name
  166. // dest.
  167. virtual bool Copy(std::string_view src, std::string_view dest);
  168. // Interprets the file with name file instead as a directory of type directory.
  169. // The directory must have a constructor that takes a single argument of type
  170. // std::shared_ptr<VfsFile>. Allows to reinterpret container files (i.e NCA, zip, XCI, etc) as a
  171. // subdirectory in one call.
  172. template <typename Directory>
  173. bool InterpretAsDirectory(std::string_view file) {
  174. auto file_p = GetFile(file);
  175. if (file_p == nullptr) {
  176. return false;
  177. }
  178. return ReplaceFileWithSubdirectory(file_p, std::make_shared<Directory>(file_p));
  179. }
  180. bool InterpretAsDirectory(const std::function<VirtualDir(VirtualFile)>& function,
  181. const std::string& file) {
  182. auto file_p = GetFile(file);
  183. if (file_p == nullptr)
  184. return false;
  185. return ReplaceFileWithSubdirectory(file_p, function(file_p));
  186. }
  187. // Returns the full path of this directory as a string, recursively
  188. virtual std::string GetFullPath() const;
  189. protected:
  190. // Backend for InterpretAsDirectory.
  191. // Removes all references to file and adds a reference to dir in the directory's implementation.
  192. virtual bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) = 0;
  193. };
  194. // A convenience partial-implementation of VfsDirectory that stubs out methods that should only work
  195. // if writable. This is to avoid redundant empty methods everywhere.
  196. struct ReadOnlyVfsDirectory : public VfsDirectory {
  197. bool IsWritable() const override;
  198. bool IsReadable() const override;
  199. std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
  200. std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
  201. bool DeleteSubdirectory(std::string_view name) override;
  202. bool DeleteFile(std::string_view name) override;
  203. bool Rename(std::string_view name) override;
  204. };
  205. // Compare the two files, byte-for-byte, in increments specificed by block_size
  206. bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block_size = 0x200);
  207. // A method that copies the raw data between two different implementations of VirtualFile. If you
  208. // are using the same implementation, it is probably better to use the Copy method in the parent
  209. // directory of src/dest.
  210. bool VfsRawCopy(VirtualFile src, VirtualFile dest);
  211. } // namespace FileSys