fsp_srv.cpp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <cinttypes>
  5. #include <cstring>
  6. #include <iterator>
  7. #include <string>
  8. #include <utility>
  9. #include <vector>
  10. #include "common/assert.h"
  11. #include "common/common_types.h"
  12. #include "common/hex_util.h"
  13. #include "common/logging/log.h"
  14. #include "common/string_util.h"
  15. #include "core/core.h"
  16. #include "core/file_sys/directory.h"
  17. #include "core/file_sys/errors.h"
  18. #include "core/file_sys/mode.h"
  19. #include "core/file_sys/nca_metadata.h"
  20. #include "core/file_sys/patch_manager.h"
  21. #include "core/file_sys/romfs_factory.h"
  22. #include "core/file_sys/savedata_factory.h"
  23. #include "core/file_sys/system_archive/system_archive.h"
  24. #include "core/file_sys/vfs.h"
  25. #include "core/hle/ipc_helpers.h"
  26. #include "core/hle/kernel/process.h"
  27. #include "core/hle/service/filesystem/filesystem.h"
  28. #include "core/hle/service/filesystem/fsp_srv.h"
  29. #include "core/reporter.h"
  30. namespace Service::FileSystem {
  31. struct SizeGetter {
  32. std::function<u64()> get_free_size;
  33. std::function<u64()> get_total_size;
  34. static SizeGetter FromStorageId(const FileSystemController& fsc, FileSys::StorageId id) {
  35. return {
  36. [&fsc, id] { return fsc.GetFreeSpaceSize(id); },
  37. [&fsc, id] { return fsc.GetTotalSpaceSize(id); },
  38. };
  39. }
  40. };
  41. enum class FileSystemType : u8 {
  42. Invalid0 = 0,
  43. Invalid1 = 1,
  44. Logo = 2,
  45. ContentControl = 3,
  46. ContentManual = 4,
  47. ContentMeta = 5,
  48. ContentData = 6,
  49. ApplicationPackage = 7,
  50. };
  51. class IStorage final : public ServiceFramework<IStorage> {
  52. public:
  53. explicit IStorage(Core::System& system_, FileSys::VirtualFile backend_)
  54. : ServiceFramework{system_, "IStorage"}, backend(std::move(backend_)) {
  55. static const FunctionInfo functions[] = {
  56. {0, &IStorage::Read, "Read"},
  57. {1, nullptr, "Write"},
  58. {2, nullptr, "Flush"},
  59. {3, nullptr, "SetSize"},
  60. {4, &IStorage::GetSize, "GetSize"},
  61. {5, nullptr, "OperateRange"},
  62. };
  63. RegisterHandlers(functions);
  64. }
  65. private:
  66. FileSys::VirtualFile backend;
  67. void Read(Kernel::HLERequestContext& ctx) {
  68. IPC::RequestParser rp{ctx};
  69. const s64 offset = rp.Pop<s64>();
  70. const s64 length = rp.Pop<s64>();
  71. LOG_DEBUG(Service_FS, "called, offset=0x{:X}, length={}", offset, length);
  72. // Error checking
  73. if (length < 0) {
  74. LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
  75. IPC::ResponseBuilder rb{ctx, 2};
  76. rb.Push(FileSys::ERROR_INVALID_SIZE);
  77. return;
  78. }
  79. if (offset < 0) {
  80. LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
  81. IPC::ResponseBuilder rb{ctx, 2};
  82. rb.Push(FileSys::ERROR_INVALID_OFFSET);
  83. return;
  84. }
  85. // Read the data from the Storage backend
  86. std::vector<u8> output = backend->ReadBytes(length, offset);
  87. // Write the data to memory
  88. ctx.WriteBuffer(output);
  89. IPC::ResponseBuilder rb{ctx, 2};
  90. rb.Push(RESULT_SUCCESS);
  91. }
  92. void GetSize(Kernel::HLERequestContext& ctx) {
  93. const u64 size = backend->GetSize();
  94. LOG_DEBUG(Service_FS, "called, size={}", size);
  95. IPC::ResponseBuilder rb{ctx, 4};
  96. rb.Push(RESULT_SUCCESS);
  97. rb.Push<u64>(size);
  98. }
  99. };
  100. class IFile final : public ServiceFramework<IFile> {
  101. public:
  102. explicit IFile(Core::System& system_, FileSys::VirtualFile backend_)
  103. : ServiceFramework{system_, "IFile"}, backend(std::move(backend_)) {
  104. static const FunctionInfo functions[] = {
  105. {0, &IFile::Read, "Read"}, {1, &IFile::Write, "Write"},
  106. {2, &IFile::Flush, "Flush"}, {3, &IFile::SetSize, "SetSize"},
  107. {4, &IFile::GetSize, "GetSize"}, {5, nullptr, "OperateRange"},
  108. };
  109. RegisterHandlers(functions);
  110. }
  111. private:
  112. FileSys::VirtualFile backend;
  113. void Read(Kernel::HLERequestContext& ctx) {
  114. IPC::RequestParser rp{ctx};
  115. const u64 option = rp.Pop<u64>();
  116. const s64 offset = rp.Pop<s64>();
  117. const s64 length = rp.Pop<s64>();
  118. LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset,
  119. length);
  120. // Error checking
  121. if (length < 0) {
  122. LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
  123. IPC::ResponseBuilder rb{ctx, 2};
  124. rb.Push(FileSys::ERROR_INVALID_SIZE);
  125. return;
  126. }
  127. if (offset < 0) {
  128. LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
  129. IPC::ResponseBuilder rb{ctx, 2};
  130. rb.Push(FileSys::ERROR_INVALID_OFFSET);
  131. return;
  132. }
  133. // Read the data from the Storage backend
  134. std::vector<u8> output = backend->ReadBytes(length, offset);
  135. // Write the data to memory
  136. ctx.WriteBuffer(output);
  137. IPC::ResponseBuilder rb{ctx, 4};
  138. rb.Push(RESULT_SUCCESS);
  139. rb.Push(static_cast<u64>(output.size()));
  140. }
  141. void Write(Kernel::HLERequestContext& ctx) {
  142. IPC::RequestParser rp{ctx};
  143. const u64 option = rp.Pop<u64>();
  144. const s64 offset = rp.Pop<s64>();
  145. const s64 length = rp.Pop<s64>();
  146. LOG_DEBUG(Service_FS, "called, option={}, offset=0x{:X}, length={}", option, offset,
  147. length);
  148. // Error checking
  149. if (length < 0) {
  150. LOG_ERROR(Service_FS, "Length is less than 0, length={}", length);
  151. IPC::ResponseBuilder rb{ctx, 2};
  152. rb.Push(FileSys::ERROR_INVALID_SIZE);
  153. return;
  154. }
  155. if (offset < 0) {
  156. LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset);
  157. IPC::ResponseBuilder rb{ctx, 2};
  158. rb.Push(FileSys::ERROR_INVALID_OFFSET);
  159. return;
  160. }
  161. const std::vector<u8> data = ctx.ReadBuffer();
  162. ASSERT_MSG(
  163. static_cast<s64>(data.size()) <= length,
  164. "Attempting to write more data than requested (requested={:016X}, actual={:016X}).",
  165. length, data.size());
  166. // Write the data to the Storage backend
  167. const auto write_size =
  168. static_cast<std::size_t>(std::distance(data.begin(), data.begin() + length));
  169. const std::size_t written = backend->Write(data.data(), write_size, offset);
  170. ASSERT_MSG(static_cast<s64>(written) == length,
  171. "Could not write all bytes to file (requested={:016X}, actual={:016X}).", length,
  172. written);
  173. IPC::ResponseBuilder rb{ctx, 2};
  174. rb.Push(RESULT_SUCCESS);
  175. }
  176. void Flush(Kernel::HLERequestContext& ctx) {
  177. LOG_DEBUG(Service_FS, "called");
  178. // Exists for SDK compatibiltity -- No need to flush file.
  179. IPC::ResponseBuilder rb{ctx, 2};
  180. rb.Push(RESULT_SUCCESS);
  181. }
  182. void SetSize(Kernel::HLERequestContext& ctx) {
  183. IPC::RequestParser rp{ctx};
  184. const u64 size = rp.Pop<u64>();
  185. LOG_DEBUG(Service_FS, "called, size={}", size);
  186. backend->Resize(size);
  187. IPC::ResponseBuilder rb{ctx, 2};
  188. rb.Push(RESULT_SUCCESS);
  189. }
  190. void GetSize(Kernel::HLERequestContext& ctx) {
  191. const u64 size = backend->GetSize();
  192. LOG_DEBUG(Service_FS, "called, size={}", size);
  193. IPC::ResponseBuilder rb{ctx, 4};
  194. rb.Push(RESULT_SUCCESS);
  195. rb.Push<u64>(size);
  196. }
  197. };
  198. template <typename T>
  199. static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data,
  200. FileSys::EntryType type) {
  201. entries.reserve(entries.size() + new_data.size());
  202. for (const auto& new_entry : new_data) {
  203. entries.emplace_back(new_entry->GetName(), type, new_entry->GetSize());
  204. }
  205. }
  206. class IDirectory final : public ServiceFramework<IDirectory> {
  207. public:
  208. explicit IDirectory(Core::System& system_, FileSys::VirtualDir backend_)
  209. : ServiceFramework{system_, "IDirectory"}, backend(std::move(backend_)) {
  210. static const FunctionInfo functions[] = {
  211. {0, &IDirectory::Read, "Read"},
  212. {1, &IDirectory::GetEntryCount, "GetEntryCount"},
  213. };
  214. RegisterHandlers(functions);
  215. // TODO(DarkLordZach): Verify that this is the correct behavior.
  216. // Build entry index now to save time later.
  217. BuildEntryIndex(entries, backend->GetFiles(), FileSys::EntryType::File);
  218. BuildEntryIndex(entries, backend->GetSubdirectories(), FileSys::EntryType::Directory);
  219. }
  220. private:
  221. FileSys::VirtualDir backend;
  222. std::vector<FileSys::Entry> entries;
  223. u64 next_entry_index = 0;
  224. void Read(Kernel::HLERequestContext& ctx) {
  225. LOG_DEBUG(Service_FS, "called.");
  226. // Calculate how many entries we can fit in the output buffer
  227. const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry);
  228. // Cap at total number of entries.
  229. const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index);
  230. // Determine data start and end
  231. const auto* begin = reinterpret_cast<u8*>(entries.data() + next_entry_index);
  232. const auto* end = reinterpret_cast<u8*>(entries.data() + next_entry_index + actual_entries);
  233. const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
  234. next_entry_index += actual_entries;
  235. // Write the data to memory
  236. ctx.WriteBuffer(begin, range_size);
  237. IPC::ResponseBuilder rb{ctx, 4};
  238. rb.Push(RESULT_SUCCESS);
  239. rb.Push(actual_entries);
  240. }
  241. void GetEntryCount(Kernel::HLERequestContext& ctx) {
  242. LOG_DEBUG(Service_FS, "called");
  243. u64 count = entries.size() - next_entry_index;
  244. IPC::ResponseBuilder rb{ctx, 4};
  245. rb.Push(RESULT_SUCCESS);
  246. rb.Push(count);
  247. }
  248. };
  249. class IFileSystem final : public ServiceFramework<IFileSystem> {
  250. public:
  251. explicit IFileSystem(Core::System& system_, FileSys::VirtualDir backend_, SizeGetter size_)
  252. : ServiceFramework{system_, "IFileSystem"}, backend{std::move(backend_)}, size{std::move(
  253. size_)} {
  254. static const FunctionInfo functions[] = {
  255. {0, &IFileSystem::CreateFile, "CreateFile"},
  256. {1, &IFileSystem::DeleteFile, "DeleteFile"},
  257. {2, &IFileSystem::CreateDirectory, "CreateDirectory"},
  258. {3, &IFileSystem::DeleteDirectory, "DeleteDirectory"},
  259. {4, &IFileSystem::DeleteDirectoryRecursively, "DeleteDirectoryRecursively"},
  260. {5, &IFileSystem::RenameFile, "RenameFile"},
  261. {6, nullptr, "RenameDirectory"},
  262. {7, &IFileSystem::GetEntryType, "GetEntryType"},
  263. {8, &IFileSystem::OpenFile, "OpenFile"},
  264. {9, &IFileSystem::OpenDirectory, "OpenDirectory"},
  265. {10, &IFileSystem::Commit, "Commit"},
  266. {11, &IFileSystem::GetFreeSpaceSize, "GetFreeSpaceSize"},
  267. {12, &IFileSystem::GetTotalSpaceSize, "GetTotalSpaceSize"},
  268. {13, &IFileSystem::CleanDirectoryRecursively, "CleanDirectoryRecursively"},
  269. {14, nullptr, "GetFileTimeStampRaw"},
  270. {15, nullptr, "QueryEntry"},
  271. };
  272. RegisterHandlers(functions);
  273. }
  274. void CreateFile(Kernel::HLERequestContext& ctx) {
  275. IPC::RequestParser rp{ctx};
  276. const auto file_buffer = ctx.ReadBuffer();
  277. const std::string name = Common::StringFromBuffer(file_buffer);
  278. const u64 mode = rp.Pop<u64>();
  279. const u32 size = rp.Pop<u32>();
  280. LOG_DEBUG(Service_FS, "called. file={}, mode=0x{:X}, size=0x{:08X}", name, mode, size);
  281. IPC::ResponseBuilder rb{ctx, 2};
  282. rb.Push(backend.CreateFile(name, size));
  283. }
  284. void DeleteFile(Kernel::HLERequestContext& ctx) {
  285. const auto file_buffer = ctx.ReadBuffer();
  286. const std::string name = Common::StringFromBuffer(file_buffer);
  287. LOG_DEBUG(Service_FS, "called. file={}", name);
  288. IPC::ResponseBuilder rb{ctx, 2};
  289. rb.Push(backend.DeleteFile(name));
  290. }
  291. void CreateDirectory(Kernel::HLERequestContext& ctx) {
  292. const auto file_buffer = ctx.ReadBuffer();
  293. const std::string name = Common::StringFromBuffer(file_buffer);
  294. LOG_DEBUG(Service_FS, "called. directory={}", name);
  295. IPC::ResponseBuilder rb{ctx, 2};
  296. rb.Push(backend.CreateDirectory(name));
  297. }
  298. void DeleteDirectory(Kernel::HLERequestContext& ctx) {
  299. const auto file_buffer = ctx.ReadBuffer();
  300. const std::string name = Common::StringFromBuffer(file_buffer);
  301. LOG_DEBUG(Service_FS, "called. directory={}", name);
  302. IPC::ResponseBuilder rb{ctx, 2};
  303. rb.Push(backend.DeleteDirectory(name));
  304. }
  305. void DeleteDirectoryRecursively(Kernel::HLERequestContext& ctx) {
  306. const auto file_buffer = ctx.ReadBuffer();
  307. const std::string name = Common::StringFromBuffer(file_buffer);
  308. LOG_DEBUG(Service_FS, "called. directory={}", name);
  309. IPC::ResponseBuilder rb{ctx, 2};
  310. rb.Push(backend.DeleteDirectoryRecursively(name));
  311. }
  312. void CleanDirectoryRecursively(Kernel::HLERequestContext& ctx) {
  313. const auto file_buffer = ctx.ReadBuffer();
  314. const std::string name = Common::StringFromBuffer(file_buffer);
  315. LOG_DEBUG(Service_FS, "called. Directory: {}", name);
  316. IPC::ResponseBuilder rb{ctx, 2};
  317. rb.Push(backend.CleanDirectoryRecursively(name));
  318. }
  319. void RenameFile(Kernel::HLERequestContext& ctx) {
  320. std::vector<u8> buffer = ctx.ReadBuffer(0);
  321. const std::string src_name = Common::StringFromBuffer(buffer);
  322. buffer = ctx.ReadBuffer(1);
  323. const std::string dst_name = Common::StringFromBuffer(buffer);
  324. LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
  325. IPC::ResponseBuilder rb{ctx, 2};
  326. rb.Push(backend.RenameFile(src_name, dst_name));
  327. }
  328. void OpenFile(Kernel::HLERequestContext& ctx) {
  329. IPC::RequestParser rp{ctx};
  330. const auto file_buffer = ctx.ReadBuffer();
  331. const std::string name = Common::StringFromBuffer(file_buffer);
  332. const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>());
  333. LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
  334. auto result = backend.OpenFile(name, mode);
  335. if (result.Failed()) {
  336. IPC::ResponseBuilder rb{ctx, 2};
  337. rb.Push(result.Code());
  338. return;
  339. }
  340. auto file = std::make_shared<IFile>(system, result.Unwrap());
  341. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  342. rb.Push(RESULT_SUCCESS);
  343. rb.PushIpcInterface<IFile>(std::move(file));
  344. }
  345. void OpenDirectory(Kernel::HLERequestContext& ctx) {
  346. IPC::RequestParser rp{ctx};
  347. const auto file_buffer = ctx.ReadBuffer();
  348. const std::string name = Common::StringFromBuffer(file_buffer);
  349. // TODO(Subv): Implement this filter.
  350. const u32 filter_flags = rp.Pop<u32>();
  351. LOG_DEBUG(Service_FS, "called. directory={}, filter={}", name, filter_flags);
  352. auto result = backend.OpenDirectory(name);
  353. if (result.Failed()) {
  354. IPC::ResponseBuilder rb{ctx, 2};
  355. rb.Push(result.Code());
  356. return;
  357. }
  358. auto directory = std::make_shared<IDirectory>(system, result.Unwrap());
  359. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  360. rb.Push(RESULT_SUCCESS);
  361. rb.PushIpcInterface<IDirectory>(std::move(directory));
  362. }
  363. void GetEntryType(Kernel::HLERequestContext& ctx) {
  364. const auto file_buffer = ctx.ReadBuffer();
  365. const std::string name = Common::StringFromBuffer(file_buffer);
  366. LOG_DEBUG(Service_FS, "called. file={}", name);
  367. auto result = backend.GetEntryType(name);
  368. if (result.Failed()) {
  369. IPC::ResponseBuilder rb{ctx, 2};
  370. rb.Push(result.Code());
  371. return;
  372. }
  373. IPC::ResponseBuilder rb{ctx, 3};
  374. rb.Push(RESULT_SUCCESS);
  375. rb.Push<u32>(static_cast<u32>(*result));
  376. }
  377. void Commit(Kernel::HLERequestContext& ctx) {
  378. LOG_WARNING(Service_FS, "(STUBBED) called");
  379. IPC::ResponseBuilder rb{ctx, 2};
  380. rb.Push(RESULT_SUCCESS);
  381. }
  382. void GetFreeSpaceSize(Kernel::HLERequestContext& ctx) {
  383. LOG_DEBUG(Service_FS, "called");
  384. IPC::ResponseBuilder rb{ctx, 4};
  385. rb.Push(RESULT_SUCCESS);
  386. rb.Push(size.get_free_size());
  387. }
  388. void GetTotalSpaceSize(Kernel::HLERequestContext& ctx) {
  389. LOG_DEBUG(Service_FS, "called");
  390. IPC::ResponseBuilder rb{ctx, 4};
  391. rb.Push(RESULT_SUCCESS);
  392. rb.Push(size.get_total_size());
  393. }
  394. private:
  395. VfsDirectoryServiceWrapper backend;
  396. SizeGetter size;
  397. };
  398. class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
  399. public:
  400. explicit ISaveDataInfoReader(Core::System& system_, FileSys::SaveDataSpaceId space,
  401. FileSystemController& fsc_)
  402. : ServiceFramework{system_, "ISaveDataInfoReader"}, fsc{fsc_} {
  403. static const FunctionInfo functions[] = {
  404. {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
  405. };
  406. RegisterHandlers(functions);
  407. FindAllSaves(space);
  408. }
  409. void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) {
  410. LOG_DEBUG(Service_FS, "called");
  411. // Calculate how many entries we can fit in the output buffer
  412. const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo);
  413. // Cap at total number of entries.
  414. const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
  415. // Determine data start and end
  416. const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
  417. const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
  418. const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
  419. next_entry_index += actual_entries;
  420. // Write the data to memory
  421. ctx.WriteBuffer(begin, range_size);
  422. IPC::ResponseBuilder rb{ctx, 3};
  423. rb.Push(RESULT_SUCCESS);
  424. rb.Push<u32>(static_cast<u32>(actual_entries));
  425. }
  426. private:
  427. static u64 stoull_be(std::string_view str) {
  428. if (str.size() != 16)
  429. return 0;
  430. const auto bytes = Common::HexStringToArray<0x8>(str);
  431. u64 out{};
  432. std::memcpy(&out, bytes.data(), sizeof(u64));
  433. return Common::swap64(out);
  434. }
  435. void FindAllSaves(FileSys::SaveDataSpaceId space) {
  436. const auto save_root = fsc.OpenSaveDataSpace(space);
  437. if (save_root.Failed() || *save_root == nullptr) {
  438. LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
  439. return;
  440. }
  441. for (const auto& type : (*save_root)->GetSubdirectories()) {
  442. if (type->GetName() == "save") {
  443. for (const auto& save_id : type->GetSubdirectories()) {
  444. for (const auto& user_id : save_id->GetSubdirectories()) {
  445. const auto save_id_numeric = stoull_be(save_id->GetName());
  446. auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
  447. std::reverse(user_id_numeric.begin(), user_id_numeric.end());
  448. if (save_id_numeric != 0) {
  449. // System Save Data
  450. info.emplace_back(SaveDataInfo{
  451. 0,
  452. space,
  453. FileSys::SaveDataType::SystemSaveData,
  454. {},
  455. user_id_numeric,
  456. save_id_numeric,
  457. 0,
  458. user_id->GetSize(),
  459. {},
  460. {},
  461. });
  462. continue;
  463. }
  464. for (const auto& title_id : user_id->GetSubdirectories()) {
  465. const auto device =
  466. std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
  467. [](u8 val) { return val == 0; });
  468. info.emplace_back(SaveDataInfo{
  469. 0,
  470. space,
  471. device ? FileSys::SaveDataType::DeviceSaveData
  472. : FileSys::SaveDataType::SaveData,
  473. {},
  474. user_id_numeric,
  475. save_id_numeric,
  476. stoull_be(title_id->GetName()),
  477. title_id->GetSize(),
  478. {},
  479. {},
  480. });
  481. }
  482. }
  483. }
  484. } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
  485. // Temporary Storage
  486. for (const auto& user_id : type->GetSubdirectories()) {
  487. for (const auto& title_id : user_id->GetSubdirectories()) {
  488. if (!title_id->GetFiles().empty() ||
  489. !title_id->GetSubdirectories().empty()) {
  490. auto user_id_numeric =
  491. Common::HexStringToArray<0x10>(user_id->GetName());
  492. std::reverse(user_id_numeric.begin(), user_id_numeric.end());
  493. info.emplace_back(SaveDataInfo{
  494. 0,
  495. space,
  496. FileSys::SaveDataType::TemporaryStorage,
  497. {},
  498. user_id_numeric,
  499. stoull_be(type->GetName()),
  500. stoull_be(title_id->GetName()),
  501. title_id->GetSize(),
  502. {},
  503. {},
  504. });
  505. }
  506. }
  507. }
  508. }
  509. }
  510. }
  511. struct SaveDataInfo {
  512. u64_le save_id_unknown;
  513. FileSys::SaveDataSpaceId space;
  514. FileSys::SaveDataType type;
  515. INSERT_PADDING_BYTES(0x6);
  516. std::array<u8, 0x10> user_id;
  517. u64_le save_id;
  518. u64_le title_id;
  519. u64_le save_image_size;
  520. u16_le index;
  521. FileSys::SaveDataRank rank;
  522. INSERT_PADDING_BYTES(0x25);
  523. };
  524. static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
  525. FileSystemController& fsc;
  526. std::vector<SaveDataInfo> info;
  527. u64 next_entry_index = 0;
  528. };
  529. FSP_SRV::FSP_SRV(Core::System& system_)
  530. : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()},
  531. content_provider{system.GetContentProvider()}, reporter{system.GetReporter()} {
  532. // clang-format off
  533. static const FunctionInfo functions[] = {
  534. {0, nullptr, "OpenFileSystem"},
  535. {1, &FSP_SRV::SetCurrentProcess, "SetCurrentProcess"},
  536. {2, nullptr, "OpenDataFileSystemByCurrentProcess"},
  537. {7, &FSP_SRV::OpenFileSystemWithPatch, "OpenFileSystemWithPatch"},
  538. {8, nullptr, "OpenFileSystemWithId"},
  539. {9, nullptr, "OpenDataFileSystemByApplicationId"},
  540. {11, nullptr, "OpenBisFileSystem"},
  541. {12, nullptr, "OpenBisStorage"},
  542. {13, nullptr, "InvalidateBisCache"},
  543. {17, nullptr, "OpenHostFileSystem"},
  544. {18, &FSP_SRV::OpenSdCardFileSystem, "OpenSdCardFileSystem"},
  545. {19, nullptr, "FormatSdCardFileSystem"},
  546. {21, nullptr, "DeleteSaveDataFileSystem"},
  547. {22, &FSP_SRV::CreateSaveDataFileSystem, "CreateSaveDataFileSystem"},
  548. {23, nullptr, "CreateSaveDataFileSystemBySystemSaveDataId"},
  549. {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"},
  550. {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"},
  551. {26, nullptr, "FormatSdCardDryRun"},
  552. {27, nullptr, "IsExFatSupported"},
  553. {28, nullptr, "DeleteSaveDataFileSystemBySaveDataAttribute"},
  554. {30, nullptr, "OpenGameCardStorage"},
  555. {31, nullptr, "OpenGameCardFileSystem"},
  556. {32, nullptr, "ExtendSaveDataFileSystem"},
  557. {33, nullptr, "DeleteCacheStorage"},
  558. {34, nullptr, "GetCacheStorageSize"},
  559. {35, nullptr, "CreateSaveDataFileSystemByHashSalt"},
  560. {36, nullptr, "OpenHostFileSystemWithOption"},
  561. {51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"},
  562. {52, nullptr, "OpenSaveDataFileSystemBySystemSaveDataId"},
  563. {53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"},
  564. {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"},
  565. {58, nullptr, "ReadSaveDataFileSystemExtraData"},
  566. {59, nullptr, "WriteSaveDataFileSystemExtraData"},
  567. {60, nullptr, "OpenSaveDataInfoReader"},
  568. {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
  569. {62, nullptr, "OpenCacheStorageList"},
  570. {64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
  571. {65, nullptr, "UpdateSaveDataMacForDebug"},
  572. {66, nullptr, "WriteSaveDataFileSystemExtraData2"},
  573. {67, nullptr, "FindSaveDataWithFilter"},
  574. {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"},
  575. {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"},
  576. {70, &FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
  577. {71, &FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
  578. {80, nullptr, "OpenSaveDataMetaFile"},
  579. {81, nullptr, "OpenSaveDataTransferManager"},
  580. {82, nullptr, "OpenSaveDataTransferManagerVersion2"},
  581. {83, nullptr, "OpenSaveDataTransferProhibiterForCloudBackUp"},
  582. {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"},
  583. {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"},
  584. {86, nullptr, "OpenSaveDataMover"},
  585. {100, nullptr, "OpenImageDirectoryFileSystem"},
  586. {110, nullptr, "OpenContentStorageFileSystem"},
  587. {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
  588. {130, nullptr, "OpenCustomStorageFileSystem"},
  589. {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"},
  590. {201, nullptr, "OpenDataStorageByProgramId"},
  591. {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"},
  592. {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"},
  593. {204, nullptr, "OpenDataFileSystemByProgramIndex"},
  594. {205, nullptr, "OpenDataStorageByProgramIndex"},
  595. {400, nullptr, "OpenDeviceOperator"},
  596. {500, nullptr, "OpenSdCardDetectionEventNotifier"},
  597. {501, nullptr, "OpenGameCardDetectionEventNotifier"},
  598. {510, nullptr, "OpenSystemDataUpdateEventNotifier"},
  599. {511, nullptr, "NotifySystemDataUpdateEvent"},
  600. {520, nullptr, "SimulateGameCardDetectionEvent"},
  601. {600, nullptr, "SetCurrentPosixTime"},
  602. {601, nullptr, "QuerySaveDataTotalSize"},
  603. {602, nullptr, "VerifySaveDataFileSystem"},
  604. {603, nullptr, "CorruptSaveDataFileSystem"},
  605. {604, nullptr, "CreatePaddingFile"},
  606. {605, nullptr, "DeleteAllPaddingFiles"},
  607. {606, nullptr, "GetRightsId"},
  608. {607, nullptr, "RegisterExternalKey"},
  609. {608, nullptr, "UnregisterAllExternalKey"},
  610. {609, nullptr, "GetRightsIdByPath"},
  611. {610, nullptr, "GetRightsIdAndKeyGenerationByPath"},
  612. {611, nullptr, "SetCurrentPosixTimeWithTimeDifference"},
  613. {612, nullptr, "GetFreeSpaceSizeForSaveData"},
  614. {613, nullptr, "VerifySaveDataFileSystemBySaveDataSpaceId"},
  615. {614, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId"},
  616. {615, nullptr, "QuerySaveDataInternalStorageTotalSize"},
  617. {616, nullptr, "GetSaveDataCommitId"},
  618. {617, nullptr, "UnregisterExternalKey"},
  619. {620, nullptr, "SetSdCardEncryptionSeed"},
  620. {630, nullptr, "SetSdCardAccessibility"},
  621. {631, nullptr, "IsSdCardAccessible"},
  622. {640, nullptr, "IsSignedSystemPartitionOnSdCardValid"},
  623. {700, nullptr, "OpenAccessFailureResolver"},
  624. {701, nullptr, "GetAccessFailureDetectionEvent"},
  625. {702, nullptr, "IsAccessFailureDetected"},
  626. {710, nullptr, "ResolveAccessFailure"},
  627. {720, nullptr, "AbandonAccessFailure"},
  628. {800, nullptr, "GetAndClearFileSystemProxyErrorInfo"},
  629. {810, nullptr, "RegisterProgramIndexMapInfo"},
  630. {1000, nullptr, "SetBisRootForHost"},
  631. {1001, nullptr, "SetSaveDataSize"},
  632. {1002, nullptr, "SetSaveDataRootPath"},
  633. {1003, nullptr, "DisableAutoSaveDataCreation"},
  634. {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"},
  635. {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"},
  636. {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"},
  637. {1007, nullptr, "RegisterUpdatePartition"},
  638. {1008, nullptr, "OpenRegisteredUpdatePartition"},
  639. {1009, nullptr, "GetAndClearMemoryReportInfo"},
  640. {1010, nullptr, "SetDataStorageRedirectTarget"},
  641. {1011, &FSP_SRV::GetAccessLogVersionInfo, "GetAccessLogVersionInfo"},
  642. {1012, nullptr, "GetFsStackUsage"},
  643. {1013, nullptr, "UnsetSaveDataRootPath"},
  644. {1014, nullptr, "OutputMultiProgramTagAccessLog"},
  645. {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
  646. {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
  647. {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"},
  648. {1300, nullptr, "OpenBisWiper"},
  649. };
  650. // clang-format on
  651. RegisterHandlers(functions);
  652. }
  653. FSP_SRV::~FSP_SRV() = default;
  654. void FSP_SRV::SetCurrentProcess(Kernel::HLERequestContext& ctx) {
  655. IPC::RequestParser rp{ctx};
  656. current_process_id = rp.Pop<u64>();
  657. LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id);
  658. IPC::ResponseBuilder rb{ctx, 2};
  659. rb.Push(RESULT_SUCCESS);
  660. }
  661. void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
  662. IPC::RequestParser rp{ctx};
  663. const auto type = rp.PopRaw<FileSystemType>();
  664. const auto title_id = rp.PopRaw<u64>();
  665. LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", type, title_id);
  666. IPC::ResponseBuilder rb{ctx, 2, 0, 0};
  667. rb.Push(RESULT_UNKNOWN);
  668. }
  669. void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
  670. LOG_DEBUG(Service_FS, "called");
  671. auto filesystem =
  672. std::make_shared<IFileSystem>(system, fsc.OpenSDMC().Unwrap(),
  673. SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
  674. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  675. rb.Push(RESULT_SUCCESS);
  676. rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
  677. }
  678. void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
  679. IPC::RequestParser rp{ctx};
  680. auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
  681. [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
  682. u128 uid = rp.PopRaw<u128>();
  683. LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
  684. uid[1], uid[0]);
  685. fsc.CreateSaveData(FileSys::SaveDataSpaceId::NandUser, save_struct);
  686. IPC::ResponseBuilder rb{ctx, 2};
  687. rb.Push(RESULT_SUCCESS);
  688. }
  689. void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
  690. IPC::RequestParser rp{ctx};
  691. struct Parameters {
  692. FileSys::SaveDataSpaceId space_id;
  693. FileSys::SaveDataAttribute attribute;
  694. };
  695. const auto parameters = rp.PopRaw<Parameters>();
  696. LOG_INFO(Service_FS, "called.");
  697. auto dir = fsc.OpenSaveData(parameters.space_id, parameters.attribute);
  698. if (dir.Failed()) {
  699. IPC::ResponseBuilder rb{ctx, 2, 0, 0};
  700. rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
  701. return;
  702. }
  703. FileSys::StorageId id{};
  704. switch (parameters.space_id) {
  705. case FileSys::SaveDataSpaceId::NandUser:
  706. id = FileSys::StorageId::NandUser;
  707. break;
  708. case FileSys::SaveDataSpaceId::SdCardSystem:
  709. case FileSys::SaveDataSpaceId::SdCardUser:
  710. id = FileSys::StorageId::SdCard;
  711. break;
  712. case FileSys::SaveDataSpaceId::NandSystem:
  713. id = FileSys::StorageId::NandSystem;
  714. break;
  715. case FileSys::SaveDataSpaceId::TemporaryStorage:
  716. case FileSys::SaveDataSpaceId::ProperSystem:
  717. case FileSys::SaveDataSpaceId::SafeMode:
  718. UNREACHABLE();
  719. }
  720. auto filesystem = std::make_shared<IFileSystem>(system, std::move(dir.Unwrap()),
  721. SizeGetter::FromStorageId(fsc, id));
  722. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  723. rb.Push(RESULT_SUCCESS);
  724. rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
  725. }
  726. void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) {
  727. LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
  728. OpenSaveDataFileSystem(ctx);
  729. }
  730. void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) {
  731. IPC::RequestParser rp{ctx};
  732. const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
  733. LOG_INFO(Service_FS, "called, space={}", space);
  734. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  735. rb.Push(RESULT_SUCCESS);
  736. rb.PushIpcInterface<ISaveDataInfoReader>(
  737. std::make_shared<ISaveDataInfoReader>(system, space, fsc));
  738. }
  739. void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(Kernel::HLERequestContext& ctx) {
  740. LOG_WARNING(Service_FS, "(STUBBED) called.");
  741. IPC::ResponseBuilder rb{ctx, 2};
  742. rb.Push(RESULT_SUCCESS);
  743. }
  744. void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
  745. Kernel::HLERequestContext& ctx) {
  746. IPC::RequestParser rp{ctx};
  747. struct Parameters {
  748. FileSys::SaveDataSpaceId space_id;
  749. FileSys::SaveDataAttribute attribute;
  750. };
  751. const auto parameters = rp.PopRaw<Parameters>();
  752. // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
  753. constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
  754. LOG_WARNING(Service_FS,
  755. "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n"
  756. "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
  757. "attribute.type={}, attribute.rank={}, attribute.index={}",
  758. flags, parameters.space_id, parameters.attribute.title_id,
  759. parameters.attribute.user_id[1], parameters.attribute.user_id[0],
  760. parameters.attribute.save_id, parameters.attribute.type, parameters.attribute.rank,
  761. parameters.attribute.index);
  762. IPC::ResponseBuilder rb{ctx, 3};
  763. rb.Push(RESULT_SUCCESS);
  764. rb.Push(flags);
  765. }
  766. void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
  767. LOG_DEBUG(Service_FS, "called");
  768. auto romfs = fsc.OpenRomFSCurrentProcess();
  769. if (romfs.Failed()) {
  770. // TODO (bunnei): Find the right error code to use here
  771. LOG_CRITICAL(Service_FS, "no file system interface available!");
  772. IPC::ResponseBuilder rb{ctx, 2};
  773. rb.Push(RESULT_UNKNOWN);
  774. return;
  775. }
  776. auto storage = std::make_shared<IStorage>(system, std::move(romfs.Unwrap()));
  777. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  778. rb.Push(RESULT_SUCCESS);
  779. rb.PushIpcInterface<IStorage>(std::move(storage));
  780. }
  781. void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
  782. IPC::RequestParser rp{ctx};
  783. const auto storage_id = rp.PopRaw<FileSys::StorageId>();
  784. const auto unknown = rp.PopRaw<u32>();
  785. const auto title_id = rp.PopRaw<u64>();
  786. LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
  787. storage_id, unknown, title_id);
  788. auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
  789. if (data.Failed()) {
  790. const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
  791. if (archive != nullptr) {
  792. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  793. rb.Push(RESULT_SUCCESS);
  794. rb.PushIpcInterface(std::make_shared<IStorage>(system, archive));
  795. return;
  796. }
  797. // TODO(DarkLordZach): Find the right error code to use here
  798. LOG_ERROR(Service_FS,
  799. "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
  800. storage_id);
  801. IPC::ResponseBuilder rb{ctx, 2};
  802. rb.Push(RESULT_UNKNOWN);
  803. return;
  804. }
  805. const FileSys::PatchManager pm{title_id, fsc, content_provider};
  806. auto storage = std::make_shared<IStorage>(
  807. system, pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data));
  808. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  809. rb.Push(RESULT_SUCCESS);
  810. rb.PushIpcInterface<IStorage>(std::move(storage));
  811. }
  812. void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
  813. IPC::RequestParser rp{ctx};
  814. const auto storage_id = rp.PopRaw<FileSys::StorageId>();
  815. const auto title_id = rp.PopRaw<u64>();
  816. LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id);
  817. IPC::ResponseBuilder rb{ctx, 2};
  818. rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
  819. }
  820. void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
  821. IPC::RequestParser rp{ctx};
  822. log_mode = rp.PopEnum<LogMode>();
  823. LOG_DEBUG(Service_FS, "called, log_mode={:08X}", log_mode);
  824. IPC::ResponseBuilder rb{ctx, 2};
  825. rb.Push(RESULT_SUCCESS);
  826. }
  827. void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
  828. LOG_DEBUG(Service_FS, "called");
  829. IPC::ResponseBuilder rb{ctx, 3};
  830. rb.Push(RESULT_SUCCESS);
  831. rb.PushEnum(log_mode);
  832. }
  833. void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) {
  834. const auto raw = ctx.ReadBuffer();
  835. auto log = Common::StringFromFixedZeroTerminatedBuffer(
  836. reinterpret_cast<const char*>(raw.data()), raw.size());
  837. LOG_DEBUG(Service_FS, "called, log='{}'", log);
  838. reporter.SaveFilesystemAccessReport(log_mode, std::move(log));
  839. IPC::ResponseBuilder rb{ctx, 2};
  840. rb.Push(RESULT_SUCCESS);
  841. }
  842. void FSP_SRV::GetAccessLogVersionInfo(Kernel::HLERequestContext& ctx) {
  843. LOG_DEBUG(Service_FS, "called");
  844. IPC::ResponseBuilder rb{ctx, 4};
  845. rb.Push(RESULT_SUCCESS);
  846. rb.PushEnum(AccessLogVersion::Latest);
  847. rb.Push(access_log_program_index);
  848. }
  849. class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
  850. public:
  851. explicit IMultiCommitManager(Core::System& system_)
  852. : ServiceFramework{system_, "IMultiCommitManager"} {
  853. static const FunctionInfo functions[] = {
  854. {1, &IMultiCommitManager::Add, "Add"},
  855. {2, &IMultiCommitManager::Commit, "Commit"},
  856. };
  857. RegisterHandlers(functions);
  858. }
  859. private:
  860. FileSys::VirtualFile backend;
  861. void Add(Kernel::HLERequestContext& ctx) {
  862. LOG_WARNING(Service_FS, "(STUBBED) called");
  863. IPC::ResponseBuilder rb{ctx, 2};
  864. rb.Push(RESULT_SUCCESS);
  865. }
  866. void Commit(Kernel::HLERequestContext& ctx) {
  867. LOG_WARNING(Service_FS, "(STUBBED) called");
  868. IPC::ResponseBuilder rb{ctx, 2};
  869. rb.Push(RESULT_SUCCESS);
  870. }
  871. };
  872. void FSP_SRV::OpenMultiCommitManager(Kernel::HLERequestContext& ctx) {
  873. LOG_DEBUG(Service_FS, "called");
  874. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  875. rb.Push(RESULT_SUCCESS);
  876. rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>(system));
  877. }
  878. } // namespace Service::FileSystem