archive_selfncch.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. // Copyright 2017 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <array>
  5. #include "common/common_types.h"
  6. #include "common/logging/log.h"
  7. #include "common/swap.h"
  8. #include "core/file_sys/archive_selfncch.h"
  9. #include "core/file_sys/errors.h"
  10. #include "core/file_sys/ivfc_archive.h"
  11. ////////////////////////////////////////////////////////////////////////////////////////////////////
  12. // FileSys namespace
  13. namespace FileSys {
  14. enum class SelfNCCHFilePathType : u32 {
  15. RomFS = 0,
  16. Code = 1, // This is not supported by SelfNCCHArchive but by archive 0x2345678E
  17. ExeFS = 2,
  18. UpdateRomFS = 5, // This is presumably for accessing the RomFS of the update patch.
  19. };
  20. struct SelfNCCHFilePath {
  21. u32_le type;
  22. std::array<char, 8> exefs_filename;
  23. };
  24. static_assert(sizeof(SelfNCCHFilePath) == 12, "NCCHFilePath has wrong size!");
  25. // A read-only file created from a block of data. It only allows you to read the entire file at
  26. // once, in a single read operation.
  27. class ExeFSSectionFile final : public FileBackend {
  28. public:
  29. explicit ExeFSSectionFile(std::shared_ptr<std::vector<u8>> data_) : data(std::move(data_)) {}
  30. ResultVal<size_t> Read(u64 offset, size_t length, u8* buffer) const override {
  31. if (offset != 0) {
  32. LOG_ERROR(Service_FS, "offset must be zero!");
  33. return ERROR_UNSUPPORTED_OPEN_FLAGS;
  34. }
  35. if (length != data->size()) {
  36. LOG_ERROR(Service_FS, "size must match the file size!");
  37. return ERROR_INCORRECT_EXEFS_READ_SIZE;
  38. }
  39. std::memcpy(buffer, data->data(), data->size());
  40. return MakeResult<size_t>(data->size());
  41. }
  42. ResultVal<size_t> Write(u64 offset, size_t length, bool flush,
  43. const u8* buffer) const override {
  44. LOG_ERROR(Service_FS, "The file is read-only!");
  45. return ERROR_UNSUPPORTED_OPEN_FLAGS;
  46. }
  47. u64 GetSize() const override {
  48. return data->size();
  49. }
  50. bool SetSize(u64 size) const override {
  51. return false;
  52. }
  53. bool Close() const override {
  54. return true;
  55. }
  56. void Flush() const override {}
  57. private:
  58. std::shared_ptr<std::vector<u8>> data;
  59. };
  60. // SelfNCCHArchive represents the running application itself. From this archive the application can
  61. // open RomFS and ExeFS, excluding the .code section.
  62. class SelfNCCHArchive final : public ArchiveBackend {
  63. public:
  64. explicit SelfNCCHArchive(const NCCHData& ncch_data_) : ncch_data(ncch_data_) {}
  65. std::string GetName() const override {
  66. return "SelfNCCHArchive";
  67. }
  68. ResultVal<std::unique_ptr<FileBackend>> OpenFile(const Path& path, const Mode&) const override {
  69. // Note: SelfNCCHArchive doesn't check the open mode.
  70. if (path.GetType() != LowPathType::Binary) {
  71. LOG_ERROR(Service_FS, "Path need to be Binary");
  72. return ERROR_INVALID_PATH;
  73. }
  74. std::vector<u8> binary = path.AsBinary();
  75. if (binary.size() != sizeof(SelfNCCHFilePath)) {
  76. LOG_ERROR(Service_FS, "Wrong path size %zu", binary.size());
  77. return ERROR_INVALID_PATH;
  78. }
  79. SelfNCCHFilePath file_path;
  80. std::memcpy(&file_path, binary.data(), sizeof(SelfNCCHFilePath));
  81. switch (static_cast<SelfNCCHFilePathType>(file_path.type)) {
  82. case SelfNCCHFilePathType::UpdateRomFS:
  83. return OpenUpdateRomFS();
  84. case SelfNCCHFilePathType::RomFS:
  85. return OpenRomFS();
  86. case SelfNCCHFilePathType::Code:
  87. LOG_ERROR(Service_FS, "Reading the code section is not supported!");
  88. return ERROR_COMMAND_NOT_ALLOWED;
  89. case SelfNCCHFilePathType::ExeFS: {
  90. const auto& raw = file_path.exefs_filename;
  91. auto end = std::find(raw.begin(), raw.end(), '\0');
  92. std::string filename(raw.begin(), end);
  93. return OpenExeFS(filename);
  94. }
  95. default:
  96. LOG_ERROR(Service_FS, "Unknown file type %u!", static_cast<u32>(file_path.type));
  97. return ERROR_INVALID_PATH;
  98. }
  99. }
  100. ResultCode DeleteFile(const Path& path) const override {
  101. LOG_ERROR(Service_FS, "Unsupported");
  102. return ERROR_UNSUPPORTED_OPEN_FLAGS;
  103. }
  104. ResultCode RenameFile(const Path& src_path, const Path& dest_path) const override {
  105. LOG_ERROR(Service_FS, "Unsupported");
  106. return ERROR_UNSUPPORTED_OPEN_FLAGS;
  107. }
  108. ResultCode DeleteDirectory(const Path& path) const override {
  109. LOG_ERROR(Service_FS, "Unsupported");
  110. return ERROR_UNSUPPORTED_OPEN_FLAGS;
  111. }
  112. ResultCode DeleteDirectoryRecursively(const Path& path) const override {
  113. LOG_ERROR(Service_FS, "Unsupported");
  114. return ERROR_UNSUPPORTED_OPEN_FLAGS;
  115. }
  116. ResultCode CreateFile(const Path& path, u64 size) const override {
  117. LOG_ERROR(Service_FS, "Unsupported");
  118. return ERROR_UNSUPPORTED_OPEN_FLAGS;
  119. }
  120. ResultCode CreateDirectory(const Path& path) const override {
  121. LOG_ERROR(Service_FS, "Unsupported");
  122. return ERROR_UNSUPPORTED_OPEN_FLAGS;
  123. }
  124. ResultCode RenameDirectory(const Path& src_path, const Path& dest_path) const override {
  125. LOG_ERROR(Service_FS, "Unsupported");
  126. return ERROR_UNSUPPORTED_OPEN_FLAGS;
  127. }
  128. ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override {
  129. LOG_ERROR(Service_FS, "Unsupported");
  130. return ERROR_UNSUPPORTED_OPEN_FLAGS;
  131. }
  132. u64 GetFreeBytes() const override {
  133. return 0;
  134. }
  135. private:
  136. ResultVal<std::unique_ptr<FileBackend>> OpenRomFS() const {
  137. if (ncch_data.romfs_file) {
  138. return MakeResult<std::unique_ptr<FileBackend>>(std::make_unique<IVFCFile>(
  139. ncch_data.romfs_file, ncch_data.romfs_offset, ncch_data.romfs_size));
  140. } else {
  141. LOG_INFO(Service_FS, "Unable to read RomFS");
  142. return ERROR_ROMFS_NOT_FOUND;
  143. }
  144. }
  145. ResultVal<std::unique_ptr<FileBackend>> OpenUpdateRomFS() const {
  146. if (ncch_data.update_romfs_file) {
  147. return MakeResult<std::unique_ptr<FileBackend>>(std::make_unique<IVFCFile>(
  148. ncch_data.update_romfs_file, ncch_data.update_romfs_offset,
  149. ncch_data.update_romfs_size));
  150. } else {
  151. LOG_INFO(Service_FS, "Unable to read update RomFS");
  152. return ERROR_ROMFS_NOT_FOUND;
  153. }
  154. }
  155. ResultVal<std::unique_ptr<FileBackend>> OpenExeFS(const std::string& filename) const {
  156. if (filename == "icon") {
  157. if (ncch_data.icon) {
  158. return MakeResult<std::unique_ptr<FileBackend>>(
  159. std::make_unique<ExeFSSectionFile>(ncch_data.icon));
  160. }
  161. LOG_WARNING(Service_FS, "Unable to read icon");
  162. return ERROR_EXEFS_SECTION_NOT_FOUND;
  163. }
  164. if (filename == "logo") {
  165. if (ncch_data.logo) {
  166. return MakeResult<std::unique_ptr<FileBackend>>(
  167. std::make_unique<ExeFSSectionFile>(ncch_data.logo));
  168. }
  169. LOG_WARNING(Service_FS, "Unable to read logo");
  170. return ERROR_EXEFS_SECTION_NOT_FOUND;
  171. }
  172. if (filename == "banner") {
  173. if (ncch_data.banner) {
  174. return MakeResult<std::unique_ptr<FileBackend>>(
  175. std::make_unique<ExeFSSectionFile>(ncch_data.banner));
  176. }
  177. LOG_WARNING(Service_FS, "Unable to read banner");
  178. return ERROR_EXEFS_SECTION_NOT_FOUND;
  179. }
  180. LOG_ERROR(Service_FS, "Unknown ExeFS section %s!", filename.c_str());
  181. return ERROR_INVALID_PATH;
  182. }
  183. NCCHData ncch_data;
  184. };
  185. ArchiveFactory_SelfNCCH::ArchiveFactory_SelfNCCH(Loader::AppLoader& app_loader) {
  186. std::shared_ptr<FileUtil::IOFile> romfs_file;
  187. if (Loader::ResultStatus::Success ==
  188. app_loader.ReadRomFS(romfs_file, ncch_data.romfs_offset, ncch_data.romfs_size)) {
  189. ncch_data.romfs_file = std::move(romfs_file);
  190. }
  191. std::shared_ptr<FileUtil::IOFile> update_romfs_file;
  192. if (Loader::ResultStatus::Success ==
  193. app_loader.ReadUpdateRomFS(update_romfs_file, ncch_data.update_romfs_offset,
  194. ncch_data.update_romfs_size)) {
  195. ncch_data.update_romfs_file = std::move(update_romfs_file);
  196. }
  197. std::vector<u8> buffer;
  198. if (Loader::ResultStatus::Success == app_loader.ReadIcon(buffer))
  199. ncch_data.icon = std::make_shared<std::vector<u8>>(std::move(buffer));
  200. buffer.clear();
  201. if (Loader::ResultStatus::Success == app_loader.ReadLogo(buffer))
  202. ncch_data.logo = std::make_shared<std::vector<u8>>(std::move(buffer));
  203. buffer.clear();
  204. if (Loader::ResultStatus::Success == app_loader.ReadBanner(buffer))
  205. ncch_data.banner = std::make_shared<std::vector<u8>>(std::move(buffer));
  206. }
  207. ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SelfNCCH::Open(const Path& path) {
  208. auto archive = std::make_unique<SelfNCCHArchive>(ncch_data);
  209. return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
  210. }
  211. ResultCode ArchiveFactory_SelfNCCH::Format(const Path&, const FileSys::ArchiveFormatInfo&) {
  212. LOG_ERROR(Service_FS, "Attempted to format a SelfNCCH archive.");
  213. return ERROR_INVALID_PATH;
  214. }
  215. ResultVal<ArchiveFormatInfo> ArchiveFactory_SelfNCCH::GetFormatInfo(const Path&) const {
  216. LOG_ERROR(Service_FS, "Attempted to get format info of a SelfNCCH archive");
  217. return ERROR_INVALID_PATH;
  218. }
  219. } // namespace FileSys