disk_filesystem.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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 Path& path) const {
  48. LOG_WARNING(Service_FS, "(STUBBED) called");
  49. // TODO(bunnei): Use correct error code
  50. return ResultCode(-1);
  51. }
  52. ResultCode Disk_FileSystem::RenameFile(const Path& src_path, const Path& dest_path) const {
  53. LOG_WARNING(Service_FS, "(STUBBED) called");
  54. // TODO(wwylele): Use correct error code
  55. return ResultCode(-1);
  56. }
  57. ResultCode Disk_FileSystem::DeleteDirectory(const Path& path) const {
  58. LOG_WARNING(Service_FS, "(STUBBED) called");
  59. // TODO(wwylele): Use correct error code
  60. return ResultCode(-1);
  61. }
  62. ResultCode Disk_FileSystem::DeleteDirectoryRecursively(const Path& path) const {
  63. LOG_WARNING(Service_FS, "(STUBBED) called");
  64. // TODO(wwylele): Use correct error code
  65. return ResultCode(-1);
  66. }
  67. ResultCode Disk_FileSystem::CreateFile(const std::string& path, u64 size) const {
  68. LOG_WARNING(Service_FS, "(STUBBED) called");
  69. std::string full_path = base_directory + path;
  70. if (size == 0) {
  71. FileUtil::CreateEmptyFile(full_path);
  72. return RESULT_SUCCESS;
  73. }
  74. FileUtil::IOFile file(full_path, "wb");
  75. // Creates a sparse file (or a normal file on filesystems without the concept of sparse files)
  76. // We do this by seeking to the right size, then writing a single null byte.
  77. if (file.Seek(size - 1, SEEK_SET) && file.WriteBytes("", 1) == 1) {
  78. return RESULT_SUCCESS;
  79. }
  80. LOG_ERROR(Service_FS, "Too large file");
  81. // TODO(Subv): Find out the correct error code
  82. return ResultCode(-1);
  83. }
  84. ResultCode Disk_FileSystem::CreateDirectory(const std::string& path) const {
  85. // TODO(Subv): Perform path validation to prevent escaping the emulator sandbox.
  86. std::string full_path = base_directory + path;
  87. if (FileUtil::CreateDir(full_path)) {
  88. return RESULT_SUCCESS;
  89. }
  90. LOG_CRITICAL(Service_FS, "(unreachable) Unknown error creating %s", full_path.c_str());
  91. // TODO(wwylele): Use correct error code
  92. return ResultCode(-1);
  93. }
  94. ResultCode Disk_FileSystem::RenameDirectory(const Path& src_path, const Path& dest_path) const {
  95. LOG_WARNING(Service_FS, "(STUBBED) called");
  96. // TODO(wwylele): Use correct error code
  97. return ResultCode(-1);
  98. }
  99. ResultVal<std::unique_ptr<DirectoryBackend>> Disk_FileSystem::OpenDirectory(
  100. const std::string& path) const {
  101. std::string full_path = base_directory + path;
  102. if (!FileUtil::IsDirectory(full_path)) {
  103. // TODO(Subv): Find the correct error code for this.
  104. return ResultCode(-1);
  105. }
  106. auto directory = std::make_unique<Disk_Directory>(full_path);
  107. return MakeResult<std::unique_ptr<DirectoryBackend>>(std::move(directory));
  108. }
  109. u64 Disk_FileSystem::GetFreeSpaceSize() const {
  110. LOG_WARNING(Service_FS, "(STUBBED) called");
  111. return 0;
  112. }
  113. ResultVal<FileSys::EntryType> Disk_FileSystem::GetEntryType(const std::string& path) const {
  114. std::string full_path = base_directory + path;
  115. if (!FileUtil::Exists(full_path)) {
  116. return ERROR_PATH_NOT_FOUND;
  117. }
  118. if (FileUtil::IsDirectory(full_path))
  119. return MakeResult(EntryType::Directory);
  120. return MakeResult(EntryType::File);
  121. }
  122. ResultVal<size_t> Disk_Storage::Read(const u64 offset, const size_t length, u8* buffer) const {
  123. LOG_TRACE(Service_FS, "called offset=%llu, length=%zu", offset, length);
  124. file->Seek(offset, SEEK_SET);
  125. return MakeResult<size_t>(file->ReadBytes(buffer, length));
  126. }
  127. ResultVal<size_t> Disk_Storage::Write(const u64 offset, const size_t length, const bool flush,
  128. const u8* buffer) const {
  129. LOG_WARNING(Service_FS, "(STUBBED) called");
  130. file->Seek(offset, SEEK_SET);
  131. size_t written = file->WriteBytes(buffer, length);
  132. if (flush) {
  133. file->Flush();
  134. }
  135. return MakeResult<size_t>(written);
  136. }
  137. u64 Disk_Storage::GetSize() const {
  138. return file->GetSize();
  139. }
  140. bool Disk_Storage::SetSize(const u64 size) const {
  141. file->Resize(size);
  142. file->Flush();
  143. return true;
  144. }
  145. Disk_Directory::Disk_Directory(const std::string& path) : directory() {
  146. unsigned size = FileUtil::ScanDirectoryTree(path, directory);
  147. directory.size = size;
  148. directory.isDirectory = true;
  149. children_iterator = directory.children.begin();
  150. }
  151. u64 Disk_Directory::Read(const u64 count, Entry* entries) {
  152. u64 entries_read = 0;
  153. while (entries_read < count && children_iterator != directory.children.cend()) {
  154. const FileUtil::FSTEntry& file = *children_iterator;
  155. const std::string& filename = file.virtualName;
  156. Entry& entry = entries[entries_read];
  157. LOG_TRACE(Service_FS, "File %s: size=%llu dir=%d", filename.c_str(), file.size,
  158. file.isDirectory);
  159. // TODO(Link Mauve): use a proper conversion to UTF-16.
  160. for (size_t j = 0; j < FILENAME_LENGTH; ++j) {
  161. entry.filename[j] = filename[j];
  162. if (!filename[j])
  163. break;
  164. }
  165. if (file.isDirectory) {
  166. entry.file_size = 0;
  167. entry.type = EntryType::Directory;
  168. } else {
  169. entry.file_size = file.size;
  170. entry.type = EntryType::File;
  171. }
  172. ++entries_read;
  173. ++children_iterator;
  174. }
  175. return entries_read;
  176. }
  177. u64 Disk_Directory::GetEntryCount() const {
  178. // We convert the children iterator into a const_iterator to allow template argument deduction
  179. // in std::distance.
  180. std::vector<FileUtil::FSTEntry>::const_iterator current = children_iterator;
  181. return std::distance(current, directory.children.end());
  182. }
  183. } // namespace FileSys