disk_filesystem.cpp 7.5 KB

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