vfs.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <numeric>
  6. #include "common/file_util.h"
  7. #include "common/logging/backend.h"
  8. #include "core/file_sys/vfs.h"
  9. namespace FileSys {
  10. VfsFile::~VfsFile() = default;
  11. std::string VfsFile::GetExtension() const {
  12. return FileUtil::GetExtensionFromFilename(GetName());
  13. }
  14. VfsDirectory::~VfsDirectory() = default;
  15. boost::optional<u8> VfsFile::ReadByte(size_t offset) const {
  16. u8 out{};
  17. size_t size = Read(&out, 1, offset);
  18. if (size == 1)
  19. return out;
  20. return boost::none;
  21. }
  22. std::vector<u8> VfsFile::ReadBytes(size_t size, size_t offset) const {
  23. std::vector<u8> out(size);
  24. size_t read_size = Read(out.data(), size, offset);
  25. out.resize(read_size);
  26. return out;
  27. }
  28. std::vector<u8> VfsFile::ReadAllBytes() const {
  29. return ReadBytes(GetSize());
  30. }
  31. bool VfsFile::WriteByte(u8 data, size_t offset) {
  32. return Write(&data, 1, offset) == 1;
  33. }
  34. size_t VfsFile::WriteBytes(std::vector<u8> data, size_t offset) {
  35. return Write(data.data(), data.size(), offset);
  36. }
  37. std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(const std::string& path) const {
  38. auto vec = FileUtil::SplitPathComponents(path);
  39. vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
  40. vec.end());
  41. if (vec.empty())
  42. return nullptr;
  43. if (vec.size() == 1)
  44. return GetFile(vec[0]);
  45. auto dir = GetSubdirectory(vec[0]);
  46. for (size_t component = 1; component < vec.size() - 1; ++component) {
  47. if (dir == nullptr)
  48. return nullptr;
  49. dir = dir->GetSubdirectory(vec[component]);
  50. }
  51. if (dir == nullptr)
  52. return nullptr;
  53. return dir->GetFile(vec.back());
  54. }
  55. std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(const std::string& path) const {
  56. if (IsRoot())
  57. return GetFileRelative(path);
  58. return GetParentDirectory()->GetFileAbsolute(path);
  59. }
  60. std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(const std::string& path) const {
  61. auto vec = FileUtil::SplitPathComponents(path);
  62. vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
  63. vec.end());
  64. if (vec.empty())
  65. // TODO(DarkLordZach): Return this directory if path is '/' or similar. Can't currently
  66. // because of const-ness
  67. return nullptr;
  68. auto dir = GetSubdirectory(vec[0]);
  69. for (size_t component = 1; component < vec.size(); ++component) {
  70. if (dir == nullptr)
  71. return nullptr;
  72. dir = dir->GetSubdirectory(vec[component]);
  73. }
  74. return dir;
  75. }
  76. std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryAbsolute(const std::string& path) const {
  77. if (IsRoot())
  78. return GetDirectoryRelative(path);
  79. return GetParentDirectory()->GetDirectoryAbsolute(path);
  80. }
  81. std::shared_ptr<VfsFile> VfsDirectory::GetFile(const std::string& name) const {
  82. const auto& files = GetFiles();
  83. const auto iter = std::find_if(files.begin(), files.end(),
  84. [&name](const auto& file1) { return name == file1->GetName(); });
  85. return iter == files.end() ? nullptr : *iter;
  86. }
  87. std::shared_ptr<VfsDirectory> VfsDirectory::GetSubdirectory(const std::string& name) const {
  88. const auto& subs = GetSubdirectories();
  89. const auto iter = std::find_if(subs.begin(), subs.end(),
  90. [&name](const auto& file1) { return name == file1->GetName(); });
  91. return iter == subs.end() ? nullptr : *iter;
  92. }
  93. bool VfsDirectory::IsRoot() const {
  94. return GetParentDirectory() == nullptr;
  95. }
  96. size_t VfsDirectory::GetSize() const {
  97. const auto& files = GetFiles();
  98. const auto file_total =
  99. std::accumulate(files.begin(), files.end(), 0ull,
  100. [](const auto& f1, const auto& f2) { return f1 + f2->GetSize(); });
  101. const auto& sub_dir = GetSubdirectories();
  102. const auto subdir_total =
  103. std::accumulate(sub_dir.begin(), sub_dir.end(), 0ull,
  104. [](const auto& f1, const auto& f2) { return f1 + f2->GetSize(); });
  105. return file_total + subdir_total;
  106. }
  107. std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(const std::string& path) {
  108. auto vec = FileUtil::SplitPathComponents(path);
  109. vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
  110. vec.end());
  111. if (vec.empty())
  112. return nullptr;
  113. if (vec.size() == 1)
  114. return CreateFile(vec[0]);
  115. auto dir = GetSubdirectory(vec[0]);
  116. if (dir == nullptr) {
  117. dir = CreateSubdirectory(vec[0]);
  118. if (dir == nullptr)
  119. return nullptr;
  120. }
  121. return dir->CreateFileRelative(FileUtil::GetPathWithoutTop(path));
  122. }
  123. std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(const std::string& path) {
  124. if (IsRoot())
  125. return CreateFileRelative(path);
  126. return GetParentDirectory()->CreateFileAbsolute(path);
  127. }
  128. std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(const std::string& path) {
  129. auto vec = FileUtil::SplitPathComponents(path);
  130. vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
  131. vec.end());
  132. if (vec.empty())
  133. return nullptr;
  134. if (vec.size() == 1)
  135. return CreateSubdirectory(vec[0]);
  136. auto dir = GetSubdirectory(vec[0]);
  137. if (dir == nullptr) {
  138. dir = CreateSubdirectory(vec[0]);
  139. if (dir == nullptr)
  140. return nullptr;
  141. }
  142. return dir->CreateDirectoryRelative(FileUtil::GetPathWithoutTop(path));
  143. }
  144. std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryAbsolute(const std::string& path) {
  145. if (IsRoot())
  146. return CreateDirectoryRelative(path);
  147. return GetParentDirectory()->CreateDirectoryAbsolute(path);
  148. }
  149. bool VfsDirectory::DeleteSubdirectoryRecursive(const std::string& name) {
  150. auto dir = GetSubdirectory(name);
  151. if (dir == nullptr)
  152. return false;
  153. bool success = true;
  154. for (const auto& file : dir->GetFiles()) {
  155. if (!DeleteFile(file->GetName()))
  156. success = false;
  157. }
  158. for (const auto& sdir : dir->GetSubdirectories()) {
  159. if (!dir->DeleteSubdirectoryRecursive(sdir->GetName()))
  160. success = false;
  161. }
  162. return success;
  163. }
  164. bool VfsDirectory::Copy(const std::string& src, const std::string& dest) {
  165. const auto f1 = GetFile(src);
  166. auto f2 = CreateFile(dest);
  167. if (f1 == nullptr || f2 == nullptr)
  168. return false;
  169. if (!f2->Resize(f1->GetSize())) {
  170. DeleteFile(dest);
  171. return false;
  172. }
  173. return f2->WriteBytes(f1->ReadAllBytes()) == f1->GetSize();
  174. }
  175. bool ReadOnlyVfsDirectory::IsWritable() const {
  176. return false;
  177. }
  178. bool ReadOnlyVfsDirectory::IsReadable() const {
  179. return true;
  180. }
  181. std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateSubdirectory(const std::string& name) {
  182. return nullptr;
  183. }
  184. std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(const std::string& name) {
  185. return nullptr;
  186. }
  187. bool ReadOnlyVfsDirectory::DeleteSubdirectory(const std::string& name) {
  188. return false;
  189. }
  190. bool ReadOnlyVfsDirectory::DeleteFile(const std::string& name) {
  191. return false;
  192. }
  193. bool ReadOnlyVfsDirectory::Rename(const std::string& name) {
  194. return false;
  195. }
  196. } // namespace FileSys