vfs.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  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 <functional>
  6. #include <map>
  7. #include <memory>
  8. #include <optional>
  9. #include <string>
  10. #include <string_view>
  11. #include <type_traits>
  12. #include <vector>
  13. #include "common/common_types.h"
  14. #include "core/file_sys/vfs_types.h"
  15. namespace FileSys {
  16. enum class Mode : u32;
  17. // An enumeration representing what can be at the end of a path in a VfsFilesystem
  18. enum class VfsEntryType {
  19. None,
  20. File,
  21. Directory,
  22. };
  23. // A class representing an abstract filesystem. A default implementation given the root VirtualDir
  24. // is provided for convenience, but if the Vfs implementation has any additional state or
  25. // functionality, they will need to override.
  26. class VfsFilesystem : NonCopyable {
  27. public:
  28. explicit VfsFilesystem(VirtualDir root);
  29. virtual ~VfsFilesystem();
  30. // Gets the friendly name for the filesystem.
  31. virtual std::string GetName() const;
  32. // Return whether or not the user has read permissions on this filesystem.
  33. virtual bool IsReadable() const;
  34. // Return whether or not the user has write permission on this filesystem.
  35. virtual bool IsWritable() const;
  36. // Determine if the entry at path is non-existant, a file, or a directory.
  37. virtual VfsEntryType GetEntryType(std::string_view path) const;
  38. // Opens the file with path relative to root. If it doesn't exist, returns nullptr.
  39. virtual VirtualFile OpenFile(std::string_view path, Mode perms);
  40. // Creates a new, empty file at path
  41. virtual VirtualFile CreateFile(std::string_view path, Mode perms);
  42. // Copies the file from old_path to new_path, returning the new file on success and nullptr on
  43. // failure.
  44. virtual VirtualFile CopyFile(std::string_view old_path, std::string_view new_path);
  45. // Moves the file from old_path to new_path, returning the moved file on success and nullptr on
  46. // failure.
  47. virtual VirtualFile MoveFile(std::string_view old_path, std::string_view new_path);
  48. // Deletes the file with path relative to root, returing true on success.
  49. virtual bool DeleteFile(std::string_view path);
  50. // Opens the directory with path relative to root. If it doesn't exist, returns nullptr.
  51. virtual VirtualDir OpenDirectory(std::string_view path, Mode perms);
  52. // Creates a new, empty directory at path
  53. virtual VirtualDir CreateDirectory(std::string_view path, Mode perms);
  54. // Copies the directory from old_path to new_path, returning the new directory on success and
  55. // nullptr on failure.
  56. virtual VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path);
  57. // Moves the directory from old_path to new_path, returning the moved directory on success and
  58. // nullptr on failure.
  59. virtual VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path);
  60. // Deletes the directory with path relative to root, returing true on success.
  61. virtual bool DeleteDirectory(std::string_view path);
  62. protected:
  63. // Root directory in default implementation.
  64. VirtualDir root;
  65. };
  66. // A class representing a file in an abstract filesystem.
  67. class VfsFile : NonCopyable {
  68. public:
  69. virtual ~VfsFile();
  70. // Retrieves the file name.
  71. virtual std::string GetName() const = 0;
  72. // Retrieves the extension of the file name.
  73. virtual std::string GetExtension() const;
  74. // Retrieves the size of the file.
  75. virtual std::size_t GetSize() const = 0;
  76. // Resizes the file to new_size. Returns whether or not the operation was successful.
  77. virtual bool Resize(std::size_t new_size) = 0;
  78. // Gets a pointer to the directory containing this file, returning nullptr if there is none.
  79. virtual std::shared_ptr<VfsDirectory> GetContainingDirectory() const = 0;
  80. // Returns whether or not the file can be written to.
  81. virtual bool IsWritable() const = 0;
  82. // Returns whether or not the file can be read from.
  83. virtual bool IsReadable() const = 0;
  84. // The primary method of reading from the file. Reads length bytes into data starting at offset
  85. // into file. Returns number of bytes successfully read.
  86. virtual std::size_t Read(u8* data, std::size_t length, std::size_t offset = 0) const = 0;
  87. // The primary method of writing to the file. Writes length bytes from data starting at offset
  88. // into file. Returns number of bytes successfully written.
  89. virtual std::size_t Write(const u8* data, std::size_t length, std::size_t offset = 0) = 0;
  90. // Reads exactly one byte at the offset provided, returning std::nullopt on error.
  91. virtual std::optional<u8> ReadByte(std::size_t offset = 0) const;
  92. // Reads size bytes starting at offset in file into a vector.
  93. virtual std::vector<u8> ReadBytes(std::size_t size, std::size_t offset = 0) const;
  94. // Reads all the bytes from the file into a vector. Equivalent to 'file->Read(file->GetSize(),
  95. // 0)'
  96. virtual std::vector<u8> ReadAllBytes() const;
  97. // Reads an array of type T, size number_elements starting at offset.
  98. // Returns the number of bytes (sizeof(T)*number_elements) read successfully.
  99. template <typename T>
  100. std::size_t ReadArray(T* data, std::size_t number_elements, std::size_t offset = 0) const {
  101. static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
  102. return Read(reinterpret_cast<u8*>(data), number_elements * sizeof(T), offset);
  103. }
  104. // Reads size bytes into the memory starting at data starting at offset into the file.
  105. // Returns the number of bytes read successfully.
  106. template <typename T>
  107. std::size_t ReadBytes(T* data, std::size_t size, std::size_t offset = 0) const {
  108. static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
  109. return Read(reinterpret_cast<u8*>(data), size, offset);
  110. }
  111. // Reads one object of type T starting at offset in file.
  112. // Returns the number of bytes read successfully (sizeof(T)).
  113. template <typename T>
  114. std::size_t ReadObject(T* data, std::size_t offset = 0) const {
  115. static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
  116. return Read(reinterpret_cast<u8*>(data), sizeof(T), offset);
  117. }
  118. // Writes exactly one byte to offset in file and retuns whether or not the byte was written
  119. // successfully.
  120. virtual bool WriteByte(u8 data, std::size_t offset = 0);
  121. // Writes a vector of bytes to offset in file and returns the number of bytes successfully
  122. // written.
  123. virtual std::size_t WriteBytes(const std::vector<u8>& data, std::size_t offset = 0);
  124. // Writes an array of type T, size number_elements to offset in file.
  125. // Returns the number of bytes (sizeof(T)*number_elements) written successfully.
  126. template <typename T>
  127. std::size_t WriteArray(const T* data, std::size_t number_elements, std::size_t offset = 0) {
  128. static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
  129. return Write(reinterpret_cast<const u8*>(data), number_elements * sizeof(T), offset);
  130. }
  131. // Writes size bytes starting at memory location data to offset in file.
  132. // Returns the number of bytes written successfully.
  133. template <typename T>
  134. std::size_t WriteBytes(const T* data, std::size_t size, std::size_t offset = 0) {
  135. static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
  136. return Write(reinterpret_cast<const u8*>(data), size, offset);
  137. }
  138. // Writes one object of type T to offset in file.
  139. // Returns the number of bytes written successfully (sizeof(T)).
  140. template <typename T>
  141. std::size_t WriteObject(const T& data, std::size_t offset = 0) {
  142. static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
  143. return Write(reinterpret_cast<const u8*>(&data), sizeof(T), offset);
  144. }
  145. // Renames the file to name. Returns whether or not the operation was successsful.
  146. virtual bool Rename(std::string_view name) = 0;
  147. // Returns the full path of this file as a string, recursively
  148. virtual std::string GetFullPath() const;
  149. };
  150. // A class representing a directory in an abstract filesystem.
  151. class VfsDirectory : NonCopyable {
  152. public:
  153. virtual ~VfsDirectory();
  154. // Retrives the file located at path as if the current directory was root. Returns nullptr if
  155. // not found.
  156. virtual std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const;
  157. // Calls GetFileRelative(path) on the root of the current directory.
  158. virtual std::shared_ptr<VfsFile> GetFileAbsolute(std::string_view path) const;
  159. // Retrives the directory located at path as if the current directory was root. Returns nullptr
  160. // if not found.
  161. virtual std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const;
  162. // Calls GetDirectoryRelative(path) on the root of the current directory.
  163. virtual std::shared_ptr<VfsDirectory> GetDirectoryAbsolute(std::string_view path) const;
  164. // Returns a vector containing all of the files in this directory.
  165. virtual std::vector<std::shared_ptr<VfsFile>> GetFiles() const = 0;
  166. // Returns the file with filename matching name. Returns nullptr if directory dosen't have a
  167. // file with name.
  168. virtual std::shared_ptr<VfsFile> GetFile(std::string_view name) const;
  169. // Returns a vector containing all of the subdirectories in this directory.
  170. virtual std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const = 0;
  171. // Returns the directory with name matching name. Returns nullptr if directory dosen't have a
  172. // directory with name.
  173. virtual std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const;
  174. // Returns whether or not the directory can be written to.
  175. virtual bool IsWritable() const = 0;
  176. // Returns whether of not the directory can be read from.
  177. virtual bool IsReadable() const = 0;
  178. // Returns whether or not the directory is the root of the current file tree.
  179. virtual bool IsRoot() const;
  180. // Returns the name of the directory.
  181. virtual std::string GetName() const = 0;
  182. // Returns the total size of all files and subdirectories in this directory.
  183. virtual std::size_t GetSize() const;
  184. // Returns the parent directory of this directory. Returns nullptr if this directory is root or
  185. // has no parent.
  186. virtual std::shared_ptr<VfsDirectory> GetParentDirectory() const = 0;
  187. // Creates a new subdirectory with name name. Returns a pointer to the new directory or nullptr
  188. // if the operation failed.
  189. virtual std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) = 0;
  190. // Creates a new file with name name. Returns a pointer to the new file or nullptr if the
  191. // operation failed.
  192. virtual std::shared_ptr<VfsFile> CreateFile(std::string_view name) = 0;
  193. // Creates a new file at the path relative to this directory. Also creates directories if
  194. // they do not exist and is supported by this implementation. Returns nullptr on any failure.
  195. virtual std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path);
  196. // Creates a new file at the path relative to root of this directory. Also creates directories
  197. // if they do not exist and is supported by this implementation. Returns nullptr on any failure.
  198. virtual std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path);
  199. // Creates a new directory at the path relative to this directory. Also creates directories if
  200. // they do not exist and is supported by this implementation. Returns nullptr on any failure.
  201. virtual std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path);
  202. // Creates a new directory at the path relative to root of this directory. Also creates
  203. // directories if they do not exist and is supported by this implementation. Returns nullptr on
  204. // any failure.
  205. virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path);
  206. // Deletes the subdirectory with the given name and returns true on success.
  207. virtual bool DeleteSubdirectory(std::string_view name) = 0;
  208. // Deletes all subdirectories and files within the provided directory and then deletes
  209. // the directory itself. Returns true on success.
  210. virtual bool DeleteSubdirectoryRecursive(std::string_view name);
  211. // Deletes all subdirectories and files within the provided directory.
  212. // Unlike DeleteSubdirectoryRecursive, this does not delete the provided directory.
  213. virtual bool CleanSubdirectoryRecursive(std::string_view name);
  214. // Returns whether or not the file with name name was deleted successfully.
  215. virtual bool DeleteFile(std::string_view name) = 0;
  216. // Returns whether or not this directory was renamed to name.
  217. virtual bool Rename(std::string_view name) = 0;
  218. // Returns whether or not the file with name src was successfully copied to a new file with name
  219. // dest.
  220. virtual bool Copy(std::string_view src, std::string_view dest);
  221. // Gets all of the entries directly in the directory (files and dirs), returning a map between
  222. // item name -> type.
  223. virtual std::map<std::string, VfsEntryType, std::less<>> GetEntries() const;
  224. // Returns the full path of this directory as a string, recursively
  225. virtual std::string GetFullPath() const;
  226. };
  227. // A convenience partial-implementation of VfsDirectory that stubs out methods that should only work
  228. // if writable. This is to avoid redundant empty methods everywhere.
  229. class ReadOnlyVfsDirectory : public VfsDirectory {
  230. public:
  231. bool IsWritable() const override;
  232. bool IsReadable() const override;
  233. std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
  234. std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
  235. std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path) override;
  236. std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override;
  237. std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path) override;
  238. std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override;
  239. bool DeleteSubdirectory(std::string_view name) override;
  240. bool DeleteSubdirectoryRecursive(std::string_view name) override;
  241. bool CleanSubdirectoryRecursive(std::string_view name) override;
  242. bool DeleteFile(std::string_view name) override;
  243. bool Rename(std::string_view name) override;
  244. };
  245. // Compare the two files, byte-for-byte, in increments specified by block_size
  246. bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2,
  247. std::size_t block_size = 0x1000);
  248. // A method that copies the raw data between two different implementations of VirtualFile. If you
  249. // are using the same implementation, it is probably better to use the Copy method in the parent
  250. // directory of src/dest.
  251. bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, std::size_t block_size = 0x1000);
  252. // A method that performs a similar function to VfsRawCopy above, but instead copies entire
  253. // directories. It suffers the same performance penalties as above and an implementation-specific
  254. // Copy should always be preferred.
  255. bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, std::size_t block_size = 0x1000);
  256. // Checks if the directory at path relative to rel exists. If it does, returns that. If it does not
  257. // it attempts to create it and returns the new dir or nullptr on failure.
  258. VirtualDir GetOrCreateDirectoryRelative(const VirtualDir& rel, std::string_view path);
  259. } // namespace FileSys