fsp_srv.cpp 42 KB

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