disk_filesystem.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <cstring>
  5. #include <memory>
  6. #include "common/common_types.h"
  7. #include "common/logging/log.h"
  8. #include "core/file_sys/disk_filesystem.h"
  9. #include "core/file_sys/errors.h"
  10. namespace FileSys {
  11. static std::string ModeFlagsToString(Mode mode) {
  12. std::string mode_str;
  13. u32 mode_flags = static_cast<u32>(mode);
  14. // Calculate the correct open mode for the file.
  15. if ((mode_flags & static_cast<u32>(Mode::Read)) &&
  16. (mode_flags & static_cast<u32>(Mode::Write))) {
  17. if (mode_flags & static_cast<u32>(Mode::Append))
  18. mode_str = "a+";
  19. else
  20. mode_str = "r+";
  21. } else {
  22. if (mode_flags & static_cast<u32>(Mode::Read))
  23. mode_str = "r";
  24. else if (mode_flags & static_cast<u32>(Mode::Append))
  25. mode_str = "a";
  26. else if (mode_flags & static_cast<u32>(Mode::Write))
  27. mode_str = "w";
  28. }
  29. mode_str += "b";
  30. return mode_str;
  31. }
  32. std::string Disk_FileSystem::GetName() const {
  33. return "Disk";
  34. }
  35. ResultVal<std::unique_ptr<StorageBackend>> Disk_FileSystem::OpenFile(const std::string& path,
  36. Mode mode) const {
  37. // Calculate the correct open mode for the file.
  38. std::string mode_str = ModeFlagsToString(mode);
  39. std::string full_path = base_directory + path;
  40. auto file = std::make_shared<FileUtil::IOFile>(full_path, mode_str.c_str());
  41. if (!file->IsOpen()) {
  42. return ERROR_PATH_NOT_FOUND;
  43. }
  44. return MakeResult<std::unique_ptr<StorageBackend>>(
  45. std::make_unique<Disk_Storage>(std::move(file)));
  46. }
  47. ResultCode Disk_FileSystem::DeleteFile(const std::string& path) const {
  48. if (!FileUtil::Exists(path)) {
  49. return ERROR_PATH_NOT_FOUND;
  50. }
  51. FileUtil::Delete(path);
  52. return RESULT_SUCCESS;
  53. }
  54. ResultCode Disk_FileSystem::RenameFile(const Path& src_path, const Path& dest_path) const {
  55. LOG_WARNING(Service_FS, "(STUBBED) called");
  56. // TODO(wwylele): Use correct error code
  57. return ResultCode(-1);
  58. }
  59. ResultCode Disk_FileSystem::DeleteDirectory(const Path& path) const {
  60. LOG_WARNING(Service_FS, "(STUBBED) called");
  61. // TODO(wwylele): Use correct error code
  62. return ResultCode(-1);
  63. }
  64. ResultCode Disk_FileSystem::DeleteDirectoryRecursively(const Path& path) const {
  65. LOG_WARNING(Service_FS, "(STUBBED) called");
  66. // TODO(wwylele): Use correct error code
  67. return ResultCode(-1);
  68. }
  69. ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const {
  70. LOG_WARNING(Service_FS, "(STUBBED) called");
  71. std::string full_path = base_directory + path;
  72. if (size == 0) {
  73. FileUtil::CreateEmptyFile(full_path);
  74. return RESULT_SUCCESS;
  75. }
  76. FileUtil::IOFile file(full_path, "wb");
  77. // Creates a sparse file (or a normal file on filesystems without the concept of sparse files)
  78. // We do this by seeking to the right size, then writing a single null byte.
  79. if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) {
  80. return RESULT_SUCCESS;
  81. }
  82. LOG_ERROR(Service_FS, "Too large file");
  83. // TODO(Subv): Find out the correct error code
  84. return ResultCode(-1);
  85. }
  86. ResultCode Disk_FileSystem::CreateDirectory(const std::string& path) const {
  87. // TODO(Subv): Perform path validation to prevent escaping the emulator sandbox.
  88. std::string full_path = base_directory + path;
  89. if (FileUtil::CreateDir(full_path)) {
  90. return RESULT_SUCCESS;
  91. }
  92. LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", full_path.c_str());
  93. // TODO(wwylele): Use correct error code
  94. return ResultCode(-1);
  95. }
  96. ResultCode Disk_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const {
  97. LOG_WARNING(Service_FS, "(STUBBED) called");
  98. // TODO(wwylele): Use correct error code
  99. return ResultCode(-1);
  100. }
  101. ResultVal<std::unique_ptr<DirectoryBackend>> Disk_FileSystem::OpenDirectory(
  102. const std::string& path) const {
  103. std::string full_path = base_directory + path;
  104. if (!FileUtil::IsDirectory(full_path)) {
  105. // TODO(Subv): Find the correct error code for this.
  106. return ResultCode(-1);
  107. }
  108. auto directory = std::make_unique<Disk_Directory>(full_path);
  109. return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory));
  110. }
  111. u64 Disk_FileSystem::GetFreeSpaceSize() const {
  112. LOG_WARNING(Service_FS, "(STUBBED) called");
  113. return 0;
  114. }
  115. ResultVal<FileSys::EntryType> Disk_FileSystem::GetEntryType(const std::string& path) const {
  116. std::string full_path = base_directory + path;
  117. if (!FileUtil::Exists(full_path)) {
  118. return ERROR_PATH_NOT_FOUND;
  119. }
  120. if (FileUtil::IsDirectory(full_path))
  121. return MakeResult(EntryType::Directory);
  122. return MakeResult(EntryType::File);
  123. }
  124. ResultVal<size_t> Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const {
  125. LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length);
  126. file->Seek(offset, SEEK_SET);
  127. return MakeResult<size_t>(file->ReadBytes(buffer, length));
  128. }
  129. ResultVal<size_t> Disk_Storage::Write(const u64 offset, const size_t length, const bool flush,
  130. const u8* buffer) const {
  131. LOG_WARNING(Service_FS, "(STUBBED) called");
  132. file->Seek(offset, SEEK_SET);
  133. size_t written = file->WriteBytes(buffer, length);
  134. if (flush) {
  135. file->Flush();
  136. }
  137. return MakeResult<size_t>(written);
  138. }
  139. u64 Disk_Storage::GetSize() const {
  140. return file->GetSize();
  141. }
  142. bool Disk_Storage::SetSize(const u64 size) const {
  143. file->Resize(size);
  144. file->Flush();
  145. return true;
  146. }
  147. Disk_Directory::Disk_Directory(const std::string& path) : directory() {
  148. unsigned size = FileUtil::ScanDirectoryTree(path, directory);
  149. directory.size = size;
  150. directory.isDirectory = true;
  151. children_iterator = directory.children.begin();
  152. }
  153. u64 Disk_Directory::Read(const u64 count, Entry* entries) {
  154. u64 entries_read = 0;
  155. while (entries_read < count && children_iterator != directory.children.cend()) {
  156. const FileUtil::FSTEntry& file = *children_iterator;
  157. const std::string& filename = file.virtualName;
  158. Entry& entry = entries[entries_read];
  159. LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size,
  160. file.isDirectory);
  161. // TODO(Link Mauve): use a proper conversion to UTF-16.
  162. for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
  163. entry.filename[j] = filename[j];
  164. if (!filename[j])
  165. break;
  166. }
  167. if (file.isDirectory) {
  168. entry.file_size = 0;
  169. entry.type = EntryType::Directory;
  170. } else {
  171. entry.file_size = file.size;
  172. entry.type = EntryType::File;
  173. }
  174. ++entries_read;
  175. ++children_iterator;
  176. }
  177. return entries_read;
  178. }
  179. u64 Disk_Directory::GetEntryCount() const {
  180. // We convert the children iterator into a const_iterator to allow template argument deduction
  181. // in std::distance.
  182. std::vector<FileUtil::FSTEntry>::const_iterator current = children_iterator;
  183. return std::distance(current, directory.children.end());
  184. }
  185. } // namespace FileSys