vfs.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  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 std::string(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(const std::vector<u8>& data, size_t offset) {
  35. return Write(data.data(), data.size(), offset);
  36. }
  37. std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view 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. }
  44. if (vec.size() == 1) {
  45. return GetFile(vec[0]);
  46. }
  47. auto dir = GetSubdirectory(vec[0]);
  48. for (size_t component = 1; component < vec.size() - 1; ++component) {
  49. if (dir == nullptr) {
  50. return nullptr;
  51. }
  52. dir = dir->GetSubdirectory(vec[component]);
  53. }
  54. if (dir == nullptr) {
  55. return nullptr;
  56. }
  57. return dir->GetFile(vec.back());
  58. }
  59. std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(std::string_view path) const {
  60. if (IsRoot()) {
  61. return GetFileRelative(path);
  62. }
  63. return GetParentDirectory()->GetFileAbsolute(path);
  64. }
  65. std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(std::string_view path) const {
  66. auto vec = FileUtil::SplitPathComponents(path);
  67. vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
  68. vec.end());
  69. if (vec.empty()) {
  70. // TODO(DarkLordZach): Return this directory if path is '/' or similar. Can't currently
  71. // because of const-ness
  72. return nullptr;
  73. }
  74. auto dir = GetSubdirectory(vec[0]);
  75. for (size_t component = 1; component < vec.size(); ++component) {
  76. if (dir == nullptr) {
  77. return nullptr;
  78. }
  79. dir = dir->GetSubdirectory(vec[component]);
  80. }
  81. return dir;
  82. }
  83. std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryAbsolute(std::string_view path) const {
  84. if (IsRoot()) {
  85. return GetDirectoryRelative(path);
  86. }
  87. return GetParentDirectory()->GetDirectoryAbsolute(path);
  88. }
  89. std::shared_ptr<VfsFile> VfsDirectory::GetFile(std::string_view name) const {
  90. const auto& files = GetFiles();
  91. const auto iter = std::find_if(files.begin(), files.end(),
  92. [&name](const auto& file1) { return name == file1->GetName(); });
  93. return iter == files.end() ? nullptr : *iter;
  94. }
  95. std::shared_ptr<VfsDirectory> VfsDirectory::GetSubdirectory(std::string_view name) const {
  96. const auto& subs = GetSubdirectories();
  97. const auto iter = std::find_if(subs.begin(), subs.end(),
  98. [&name](const auto& file1) { return name == file1->GetName(); });
  99. return iter == subs.end() ? nullptr : *iter;
  100. }
  101. bool VfsDirectory::IsRoot() const {
  102. return GetParentDirectory() == nullptr;
  103. }
  104. size_t VfsDirectory::GetSize() const {
  105. const auto& files = GetFiles();
  106. const auto sum_sizes = [](const auto& range) {
  107. return std::accumulate(range.begin(), range.end(), 0ULL,
  108. [](const auto& f1, const auto& f2) { return f1 + f2->GetSize(); });
  109. };
  110. const auto file_total = sum_sizes(files);
  111. const auto& sub_dir = GetSubdirectories();
  112. const auto subdir_total = sum_sizes(sub_dir);
  113. return file_total + subdir_total;
  114. }
  115. std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(std::string_view path) {
  116. auto vec = FileUtil::SplitPathComponents(path);
  117. vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
  118. vec.end());
  119. if (vec.empty()) {
  120. return nullptr;
  121. }
  122. if (vec.size() == 1) {
  123. return CreateFile(vec[0]);
  124. }
  125. auto dir = GetSubdirectory(vec[0]);
  126. if (dir == nullptr) {
  127. dir = CreateSubdirectory(vec[0]);
  128. if (dir == nullptr) {
  129. return nullptr;
  130. }
  131. }
  132. return dir->CreateFileRelative(FileUtil::GetPathWithoutTop(path));
  133. }
  134. std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(std::string_view path) {
  135. if (IsRoot()) {
  136. return CreateFileRelative(path);
  137. }
  138. return GetParentDirectory()->CreateFileAbsolute(path);
  139. }
  140. std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(std::string_view path) {
  141. auto vec = FileUtil::SplitPathComponents(path);
  142. vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
  143. vec.end());
  144. if (vec.empty()) {
  145. return nullptr;
  146. }
  147. if (vec.size() == 1) {
  148. return CreateSubdirectory(vec[0]);
  149. }
  150. auto dir = GetSubdirectory(vec[0]);
  151. if (dir == nullptr) {
  152. dir = CreateSubdirectory(vec[0]);
  153. if (dir == nullptr) {
  154. return nullptr;
  155. }
  156. }
  157. return dir->CreateDirectoryRelative(FileUtil::GetPathWithoutTop(path));
  158. }
  159. std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
  160. if (IsRoot()) {
  161. return CreateDirectoryRelative(path);
  162. }
  163. return GetParentDirectory()->CreateDirectoryAbsolute(path);
  164. }
  165. bool VfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
  166. auto dir = GetSubdirectory(name);
  167. if (dir == nullptr) {
  168. return false;
  169. }
  170. bool success = true;
  171. for (const auto& file : dir->GetFiles()) {
  172. if (!DeleteFile(file->GetName())) {
  173. success = false;
  174. }
  175. }
  176. for (const auto& sdir : dir->GetSubdirectories()) {
  177. if (!dir->DeleteSubdirectoryRecursive(sdir->GetName())) {
  178. success = false;
  179. }
  180. }
  181. return success;
  182. }
  183. bool VfsDirectory::Copy(std::string_view src, std::string_view dest) {
  184. const auto f1 = GetFile(src);
  185. auto f2 = CreateFile(dest);
  186. if (f1 == nullptr || f2 == nullptr) {
  187. return false;
  188. }
  189. if (!f2->Resize(f1->GetSize())) {
  190. DeleteFile(dest);
  191. return false;
  192. }
  193. return f2->WriteBytes(f1->ReadAllBytes()) == f1->GetSize();
  194. }
  195. bool ReadOnlyVfsDirectory::IsWritable() const {
  196. return false;
  197. }
  198. bool ReadOnlyVfsDirectory::IsReadable() const {
  199. return true;
  200. }
  201. std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateSubdirectory(std::string_view name) {
  202. return nullptr;
  203. }
  204. std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(std::string_view name) {
  205. return nullptr;
  206. }
  207. bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) {
  208. return false;
  209. }
  210. bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) {
  211. return false;
  212. }
  213. bool ReadOnlyVfsDirectory::Rename(std::string_view name) {
  214. return false;
  215. }
  216. } // namespace FileSys