fsp_srv.cpp 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159
  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 std::vector<u8> 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. std::vector<u8> buffer = ctx.ReadBuffer(0);
  329. const std::string src_name = Common::StringFromBuffer(buffer);
  330. buffer = ctx.ReadBuffer(1);
  331. const std::string dst_name = Common::StringFromBuffer(buffer);
  332. LOG_DEBUG(Service_FS, "called. file '{}' to file '{}'", src_name, dst_name);
  333. IPC::ResponseBuilder rb{ctx, 2};
  334. rb.Push(backend.RenameFile(src_name, dst_name));
  335. }
  336. void OpenFile(Kernel::HLERequestContext& ctx) {
  337. IPC::RequestParser rp{ctx};
  338. const auto file_buffer = ctx.ReadBuffer();
  339. const std::string name = Common::StringFromBuffer(file_buffer);
  340. const auto mode = static_cast<FileSys::Mode>(rp.Pop<u32>());
  341. LOG_DEBUG(Service_FS, "called. file={}, mode={}", name, mode);
  342. auto result = backend.OpenFile(name, mode);
  343. if (result.Failed()) {
  344. IPC::ResponseBuilder rb{ctx, 2};
  345. rb.Push(result.Code());
  346. return;
  347. }
  348. auto file = std::make_shared<IFile>(system, result.Unwrap());
  349. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  350. rb.Push(ResultSuccess);
  351. rb.PushIpcInterface<IFile>(std::move(file));
  352. }
  353. void OpenDirectory(Kernel::HLERequestContext& ctx) {
  354. IPC::RequestParser rp{ctx};
  355. const auto file_buffer = ctx.ReadBuffer();
  356. const std::string name = Common::StringFromBuffer(file_buffer);
  357. // TODO(Subv): Implement this filter.
  358. const u32 filter_flags = rp.Pop<u32>();
  359. LOG_DEBUG(Service_FS, "called. directory={}, filter={}", name, filter_flags);
  360. auto result = backend.OpenDirectory(name);
  361. if (result.Failed()) {
  362. IPC::ResponseBuilder rb{ctx, 2};
  363. rb.Push(result.Code());
  364. return;
  365. }
  366. auto directory = std::make_shared<IDirectory>(system, result.Unwrap());
  367. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  368. rb.Push(ResultSuccess);
  369. rb.PushIpcInterface<IDirectory>(std::move(directory));
  370. }
  371. void GetEntryType(Kernel::HLERequestContext& ctx) {
  372. const auto file_buffer = ctx.ReadBuffer();
  373. const std::string name = Common::StringFromBuffer(file_buffer);
  374. LOG_DEBUG(Service_FS, "called. file={}", name);
  375. auto result = backend.GetEntryType(name);
  376. if (result.Failed()) {
  377. IPC::ResponseBuilder rb{ctx, 2};
  378. rb.Push(result.Code());
  379. return;
  380. }
  381. IPC::ResponseBuilder rb{ctx, 3};
  382. rb.Push(ResultSuccess);
  383. rb.Push<u32>(static_cast<u32>(*result));
  384. }
  385. void Commit(Kernel::HLERequestContext& ctx) {
  386. LOG_WARNING(Service_FS, "(STUBBED) called");
  387. IPC::ResponseBuilder rb{ctx, 2};
  388. rb.Push(ResultSuccess);
  389. }
  390. void GetFreeSpaceSize(Kernel::HLERequestContext& ctx) {
  391. LOG_DEBUG(Service_FS, "called");
  392. IPC::ResponseBuilder rb{ctx, 4};
  393. rb.Push(ResultSuccess);
  394. rb.Push(size.get_free_size());
  395. }
  396. void GetTotalSpaceSize(Kernel::HLERequestContext& ctx) {
  397. LOG_DEBUG(Service_FS, "called");
  398. IPC::ResponseBuilder rb{ctx, 4};
  399. rb.Push(ResultSuccess);
  400. rb.Push(size.get_total_size());
  401. }
  402. void GetFileTimeStampRaw(Kernel::HLERequestContext& ctx) {
  403. const auto file_buffer = ctx.ReadBuffer();
  404. const std::string name = Common::StringFromBuffer(file_buffer);
  405. LOG_WARNING(Service_FS, "(Partial Implementation) called. file={}", name);
  406. auto result = backend.GetFileTimeStampRaw(name);
  407. if (result.Failed()) {
  408. IPC::ResponseBuilder rb{ctx, 2};
  409. rb.Push(result.Code());
  410. return;
  411. }
  412. IPC::ResponseBuilder rb{ctx, 10};
  413. rb.Push(ResultSuccess);
  414. rb.PushRaw(*result);
  415. }
  416. private:
  417. VfsDirectoryServiceWrapper backend;
  418. SizeGetter size;
  419. };
  420. class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
  421. public:
  422. explicit ISaveDataInfoReader(Core::System& system_, FileSys::SaveDataSpaceId space,
  423. FileSystemController& fsc_)
  424. : ServiceFramework{system_, "ISaveDataInfoReader"}, fsc{fsc_} {
  425. static const FunctionInfo functions[] = {
  426. {0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
  427. };
  428. RegisterHandlers(functions);
  429. FindAllSaves(space);
  430. }
  431. void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) {
  432. LOG_DEBUG(Service_FS, "called");
  433. // Calculate how many entries we can fit in the output buffer
  434. const u64 count_entries = ctx.GetWriteBufferNumElements<SaveDataInfo>();
  435. // Cap at total number of entries.
  436. const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
  437. // Determine data start and end
  438. const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
  439. const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
  440. const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
  441. next_entry_index += actual_entries;
  442. // Write the data to memory
  443. ctx.WriteBuffer(begin, range_size);
  444. IPC::ResponseBuilder rb{ctx, 3};
  445. rb.Push(ResultSuccess);
  446. rb.Push<u32>(static_cast<u32>(actual_entries));
  447. }
  448. private:
  449. static u64 stoull_be(std::string_view str) {
  450. if (str.size() != 16)
  451. return 0;
  452. const auto bytes = Common::HexStringToArray<0x8>(str);
  453. u64 out{};
  454. std::memcpy(&out, bytes.data(), sizeof(u64));
  455. return Common::swap64(out);
  456. }
  457. void FindAllSaves(FileSys::SaveDataSpaceId space) {
  458. const auto save_root = fsc.OpenSaveDataSpace(space);
  459. if (save_root.Failed() || *save_root == nullptr) {
  460. LOG_ERROR(Service_FS, "The save root for the space_id={:02X} was invalid!", space);
  461. return;
  462. }
  463. for (const auto& type : (*save_root)->GetSubdirectories()) {
  464. if (type->GetName() == "save") {
  465. for (const auto& save_id : type->GetSubdirectories()) {
  466. for (const auto& user_id : save_id->GetSubdirectories()) {
  467. const auto save_id_numeric = stoull_be(save_id->GetName());
  468. auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
  469. std::reverse(user_id_numeric.begin(), user_id_numeric.end());
  470. if (save_id_numeric != 0) {
  471. // System Save Data
  472. info.emplace_back(SaveDataInfo{
  473. 0,
  474. space,
  475. FileSys::SaveDataType::SystemSaveData,
  476. {},
  477. user_id_numeric,
  478. save_id_numeric,
  479. 0,
  480. user_id->GetSize(),
  481. {},
  482. {},
  483. });
  484. continue;
  485. }
  486. for (const auto& title_id : user_id->GetSubdirectories()) {
  487. const auto device =
  488. std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
  489. [](u8 val) { return val == 0; });
  490. info.emplace_back(SaveDataInfo{
  491. 0,
  492. space,
  493. device ? FileSys::SaveDataType::DeviceSaveData
  494. : FileSys::SaveDataType::SaveData,
  495. {},
  496. user_id_numeric,
  497. save_id_numeric,
  498. stoull_be(title_id->GetName()),
  499. title_id->GetSize(),
  500. {},
  501. {},
  502. });
  503. }
  504. }
  505. }
  506. } else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
  507. // Temporary Storage
  508. for (const auto& user_id : type->GetSubdirectories()) {
  509. for (const auto& title_id : user_id->GetSubdirectories()) {
  510. if (!title_id->GetFiles().empty() ||
  511. !title_id->GetSubdirectories().empty()) {
  512. auto user_id_numeric =
  513. Common::HexStringToArray<0x10>(user_id->GetName());
  514. std::reverse(user_id_numeric.begin(), user_id_numeric.end());
  515. info.emplace_back(SaveDataInfo{
  516. 0,
  517. space,
  518. FileSys::SaveDataType::TemporaryStorage,
  519. {},
  520. user_id_numeric,
  521. stoull_be(type->GetName()),
  522. stoull_be(title_id->GetName()),
  523. title_id->GetSize(),
  524. {},
  525. {},
  526. });
  527. }
  528. }
  529. }
  530. }
  531. }
  532. }
  533. struct SaveDataInfo {
  534. u64_le save_id_unknown;
  535. FileSys::SaveDataSpaceId space;
  536. FileSys::SaveDataType type;
  537. INSERT_PADDING_BYTES(0x6);
  538. std::array<u8, 0x10> user_id;
  539. u64_le save_id;
  540. u64_le title_id;
  541. u64_le save_image_size;
  542. u16_le index;
  543. FileSys::SaveDataRank rank;
  544. INSERT_PADDING_BYTES(0x25);
  545. };
  546. static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
  547. FileSystemController& fsc;
  548. std::vector<SaveDataInfo> info;
  549. u64 next_entry_index = 0;
  550. };
  551. FSP_SRV::FSP_SRV(Core::System& system_)
  552. : ServiceFramework{system_, "fsp-srv"}, fsc{system.GetFileSystemController()},
  553. content_provider{system.GetContentProvider()}, reporter{system.GetReporter()} {
  554. // clang-format off
  555. static const FunctionInfo functions[] = {
  556. {0, nullptr, "OpenFileSystem"},
  557. {1, &FSP_SRV::SetCurrentProcess, "SetCurrentProcess"},
  558. {2, nullptr, "OpenDataFileSystemByCurrentProcess"},
  559. {7, &FSP_SRV::OpenFileSystemWithPatch, "OpenFileSystemWithPatch"},
  560. {8, nullptr, "OpenFileSystemWithId"},
  561. {9, nullptr, "OpenDataFileSystemByApplicationId"},
  562. {11, nullptr, "OpenBisFileSystem"},
  563. {12, nullptr, "OpenBisStorage"},
  564. {13, nullptr, "InvalidateBisCache"},
  565. {17, nullptr, "OpenHostFileSystem"},
  566. {18, &FSP_SRV::OpenSdCardFileSystem, "OpenSdCardFileSystem"},
  567. {19, nullptr, "FormatSdCardFileSystem"},
  568. {21, nullptr, "DeleteSaveDataFileSystem"},
  569. {22, &FSP_SRV::CreateSaveDataFileSystem, "CreateSaveDataFileSystem"},
  570. {23, nullptr, "CreateSaveDataFileSystemBySystemSaveDataId"},
  571. {24, nullptr, "RegisterSaveDataFileSystemAtomicDeletion"},
  572. {25, nullptr, "DeleteSaveDataFileSystemBySaveDataSpaceId"},
  573. {26, nullptr, "FormatSdCardDryRun"},
  574. {27, nullptr, "IsExFatSupported"},
  575. {28, nullptr, "DeleteSaveDataFileSystemBySaveDataAttribute"},
  576. {30, nullptr, "OpenGameCardStorage"},
  577. {31, nullptr, "OpenGameCardFileSystem"},
  578. {32, nullptr, "ExtendSaveDataFileSystem"},
  579. {33, nullptr, "DeleteCacheStorage"},
  580. {34, &FSP_SRV::GetCacheStorageSize, "GetCacheStorageSize"},
  581. {35, nullptr, "CreateSaveDataFileSystemByHashSalt"},
  582. {36, nullptr, "OpenHostFileSystemWithOption"},
  583. {51, &FSP_SRV::OpenSaveDataFileSystem, "OpenSaveDataFileSystem"},
  584. {52, nullptr, "OpenSaveDataFileSystemBySystemSaveDataId"},
  585. {53, &FSP_SRV::OpenReadOnlySaveDataFileSystem, "OpenReadOnlySaveDataFileSystem"},
  586. {57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"},
  587. {58, nullptr, "ReadSaveDataFileSystemExtraData"},
  588. {59, nullptr, "WriteSaveDataFileSystemExtraData"},
  589. {60, nullptr, "OpenSaveDataInfoReader"},
  590. {61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
  591. {62, nullptr, "OpenCacheStorageList"},
  592. {64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
  593. {65, nullptr, "UpdateSaveDataMacForDebug"},
  594. {66, nullptr, "WriteSaveDataFileSystemExtraData2"},
  595. {67, nullptr, "FindSaveDataWithFilter"},
  596. {68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"},
  597. {69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"},
  598. {70, &FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
  599. {71, &FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
  600. {80, nullptr, "OpenSaveDataMetaFile"},
  601. {81, nullptr, "OpenSaveDataTransferManager"},
  602. {82, nullptr, "OpenSaveDataTransferManagerVersion2"},
  603. {83, nullptr, "OpenSaveDataTransferProhibiterForCloudBackUp"},
  604. {84, nullptr, "ListApplicationAccessibleSaveDataOwnerId"},
  605. {85, nullptr, "OpenSaveDataTransferManagerForSaveDataRepair"},
  606. {86, nullptr, "OpenSaveDataMover"},
  607. {87, nullptr, "OpenSaveDataTransferManagerForRepair"},
  608. {100, nullptr, "OpenImageDirectoryFileSystem"},
  609. {101, nullptr, "OpenBaseFileSystem"},
  610. {102, nullptr, "FormatBaseFileSystem"},
  611. {110, nullptr, "OpenContentStorageFileSystem"},
  612. {120, nullptr, "OpenCloudBackupWorkStorageFileSystem"},
  613. {130, nullptr, "OpenCustomStorageFileSystem"},
  614. {200, &FSP_SRV::OpenDataStorageByCurrentProcess, "OpenDataStorageByCurrentProcess"},
  615. {201, nullptr, "OpenDataStorageByProgramId"},
  616. {202, &FSP_SRV::OpenDataStorageByDataId, "OpenDataStorageByDataId"},
  617. {203, &FSP_SRV::OpenPatchDataStorageByCurrentProcess, "OpenPatchDataStorageByCurrentProcess"},
  618. {204, nullptr, "OpenDataFileSystemByProgramIndex"},
  619. {205, &FSP_SRV::OpenDataStorageWithProgramIndex, "OpenDataStorageWithProgramIndex"},
  620. {206, nullptr, "OpenDataStorageByPath"},
  621. {400, nullptr, "OpenDeviceOperator"},
  622. {500, nullptr, "OpenSdCardDetectionEventNotifier"},
  623. {501, nullptr, "OpenGameCardDetectionEventNotifier"},
  624. {510, nullptr, "OpenSystemDataUpdateEventNotifier"},
  625. {511, nullptr, "NotifySystemDataUpdateEvent"},
  626. {520, nullptr, "SimulateGameCardDetectionEvent"},
  627. {600, nullptr, "SetCurrentPosixTime"},
  628. {601, nullptr, "QuerySaveDataTotalSize"},
  629. {602, nullptr, "VerifySaveDataFileSystem"},
  630. {603, nullptr, "CorruptSaveDataFileSystem"},
  631. {604, nullptr, "CreatePaddingFile"},
  632. {605, nullptr, "DeleteAllPaddingFiles"},
  633. {606, nullptr, "GetRightsId"},
  634. {607, nullptr, "RegisterExternalKey"},
  635. {608, nullptr, "UnregisterAllExternalKey"},
  636. {609, nullptr, "GetRightsIdByPath"},
  637. {610, nullptr, "GetRightsIdAndKeyGenerationByPath"},
  638. {611, nullptr, "SetCurrentPosixTimeWithTimeDifference"},
  639. {612, nullptr, "GetFreeSpaceSizeForSaveData"},
  640. {613, nullptr, "VerifySaveDataFileSystemBySaveDataSpaceId"},
  641. {614, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId"},
  642. {615, nullptr, "QuerySaveDataInternalStorageTotalSize"},
  643. {616, nullptr, "GetSaveDataCommitId"},
  644. {617, nullptr, "UnregisterExternalKey"},
  645. {620, nullptr, "SetSdCardEncryptionSeed"},
  646. {630, nullptr, "SetSdCardAccessibility"},
  647. {631, nullptr, "IsSdCardAccessible"},
  648. {640, nullptr, "IsSignedSystemPartitionOnSdCardValid"},
  649. {700, nullptr, "OpenAccessFailureResolver"},
  650. {701, nullptr, "GetAccessFailureDetectionEvent"},
  651. {702, nullptr, "IsAccessFailureDetected"},
  652. {710, nullptr, "ResolveAccessFailure"},
  653. {720, nullptr, "AbandonAccessFailure"},
  654. {800, nullptr, "GetAndClearFileSystemProxyErrorInfo"},
  655. {810, nullptr, "RegisterProgramIndexMapInfo"},
  656. {1000, nullptr, "SetBisRootForHost"},
  657. {1001, nullptr, "SetSaveDataSize"},
  658. {1002, nullptr, "SetSaveDataRootPath"},
  659. {1003, &FSP_SRV::DisableAutoSaveDataCreation, "DisableAutoSaveDataCreation"},
  660. {1004, &FSP_SRV::SetGlobalAccessLogMode, "SetGlobalAccessLogMode"},
  661. {1005, &FSP_SRV::GetGlobalAccessLogMode, "GetGlobalAccessLogMode"},
  662. {1006, &FSP_SRV::OutputAccessLogToSdCard, "OutputAccessLogToSdCard"},
  663. {1007, nullptr, "RegisterUpdatePartition"},
  664. {1008, nullptr, "OpenRegisteredUpdatePartition"},
  665. {1009, nullptr, "GetAndClearMemoryReportInfo"},
  666. {1010, nullptr, "SetDataStorageRedirectTarget"},
  667. {1011, &FSP_SRV::GetProgramIndexForAccessLog, "GetProgramIndexForAccessLog"},
  668. {1012, nullptr, "GetFsStackUsage"},
  669. {1013, nullptr, "UnsetSaveDataRootPath"},
  670. {1014, nullptr, "OutputMultiProgramTagAccessLog"},
  671. {1016, nullptr, "FlushAccessLogOnSdCard"},
  672. {1017, nullptr, "OutputApplicationInfoAccessLog"},
  673. {1018, nullptr, "SetDebugOption"},
  674. {1019, nullptr, "UnsetDebugOption"},
  675. {1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
  676. {1110, nullptr, "CorruptSaveDataFileSystemBySaveDataSpaceId2"},
  677. {1200, &FSP_SRV::OpenMultiCommitManager, "OpenMultiCommitManager"},
  678. {1300, nullptr, "OpenBisWiper"},
  679. };
  680. // clang-format on
  681. RegisterHandlers(functions);
  682. if (Settings::values.enable_fs_access_log) {
  683. access_log_mode = AccessLogMode::SdCard;
  684. }
  685. }
  686. FSP_SRV::~FSP_SRV() = default;
  687. void FSP_SRV::SetCurrentProcess(Kernel::HLERequestContext& ctx) {
  688. IPC::RequestParser rp{ctx};
  689. current_process_id = rp.Pop<u64>();
  690. LOG_DEBUG(Service_FS, "called. current_process_id=0x{:016X}", current_process_id);
  691. IPC::ResponseBuilder rb{ctx, 2};
  692. rb.Push(ResultSuccess);
  693. }
  694. void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) {
  695. IPC::RequestParser rp{ctx};
  696. const auto type = rp.PopRaw<FileSystemType>();
  697. const auto title_id = rp.PopRaw<u64>();
  698. LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", type, title_id);
  699. IPC::ResponseBuilder rb{ctx, 2, 0, 0};
  700. rb.Push(ResultUnknown);
  701. }
  702. void FSP_SRV::OpenSdCardFileSystem(Kernel::HLERequestContext& ctx) {
  703. LOG_DEBUG(Service_FS, "called");
  704. auto filesystem =
  705. std::make_shared<IFileSystem>(system, fsc.OpenSDMC().Unwrap(),
  706. SizeGetter::FromStorageId(fsc, FileSys::StorageId::SdCard));
  707. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  708. rb.Push(ResultSuccess);
  709. rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
  710. }
  711. void FSP_SRV::CreateSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
  712. IPC::RequestParser rp{ctx};
  713. auto save_struct = rp.PopRaw<FileSys::SaveDataAttribute>();
  714. [[maybe_unused]] auto save_create_struct = rp.PopRaw<std::array<u8, 0x40>>();
  715. u128 uid = rp.PopRaw<u128>();
  716. LOG_DEBUG(Service_FS, "called save_struct = {}, uid = {:016X}{:016X}", save_struct.DebugInfo(),
  717. uid[1], uid[0]);
  718. fsc.CreateSaveData(FileSys::SaveDataSpaceId::NandUser, save_struct);
  719. IPC::ResponseBuilder rb{ctx, 2};
  720. rb.Push(ResultSuccess);
  721. }
  722. void FSP_SRV::OpenSaveDataFileSystem(Kernel::HLERequestContext& ctx) {
  723. IPC::RequestParser rp{ctx};
  724. struct Parameters {
  725. FileSys::SaveDataSpaceId space_id;
  726. FileSys::SaveDataAttribute attribute;
  727. };
  728. const auto parameters = rp.PopRaw<Parameters>();
  729. LOG_INFO(Service_FS, "called.");
  730. auto dir = fsc.OpenSaveData(parameters.space_id, parameters.attribute);
  731. if (dir.Failed()) {
  732. IPC::ResponseBuilder rb{ctx, 2, 0, 0};
  733. rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
  734. return;
  735. }
  736. FileSys::StorageId id{};
  737. switch (parameters.space_id) {
  738. case FileSys::SaveDataSpaceId::NandUser:
  739. id = FileSys::StorageId::NandUser;
  740. break;
  741. case FileSys::SaveDataSpaceId::SdCardSystem:
  742. case FileSys::SaveDataSpaceId::SdCardUser:
  743. id = FileSys::StorageId::SdCard;
  744. break;
  745. case FileSys::SaveDataSpaceId::NandSystem:
  746. id = FileSys::StorageId::NandSystem;
  747. break;
  748. case FileSys::SaveDataSpaceId::TemporaryStorage:
  749. case FileSys::SaveDataSpaceId::ProperSystem:
  750. case FileSys::SaveDataSpaceId::SafeMode:
  751. ASSERT(false);
  752. }
  753. auto filesystem = std::make_shared<IFileSystem>(system, std::move(dir.Unwrap()),
  754. SizeGetter::FromStorageId(fsc, id));
  755. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  756. rb.Push(ResultSuccess);
  757. rb.PushIpcInterface<IFileSystem>(std::move(filesystem));
  758. }
  759. void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) {
  760. LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
  761. OpenSaveDataFileSystem(ctx);
  762. }
  763. void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) {
  764. IPC::RequestParser rp{ctx};
  765. const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
  766. LOG_INFO(Service_FS, "called, space={}", space);
  767. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  768. rb.Push(ResultSuccess);
  769. rb.PushIpcInterface<ISaveDataInfoReader>(
  770. std::make_shared<ISaveDataInfoReader>(system, space, fsc));
  771. }
  772. void FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute(Kernel::HLERequestContext& ctx) {
  773. LOG_WARNING(Service_FS, "(STUBBED) called.");
  774. IPC::ResponseBuilder rb{ctx, 2};
  775. rb.Push(ResultSuccess);
  776. }
  777. void FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
  778. Kernel::HLERequestContext& ctx) {
  779. IPC::RequestParser rp{ctx};
  780. struct Parameters {
  781. FileSys::SaveDataSpaceId space_id;
  782. FileSys::SaveDataAttribute attribute;
  783. };
  784. const auto parameters = rp.PopRaw<Parameters>();
  785. // Stub this to None for now, backend needs an impl to read/write the SaveDataExtraData
  786. constexpr auto flags = static_cast<u32>(FileSys::SaveDataFlags::None);
  787. LOG_WARNING(Service_FS,
  788. "(STUBBED) called, flags={}, space_id={}, attribute.title_id={:016X}\n"
  789. "attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
  790. "attribute.type={}, attribute.rank={}, attribute.index={}",
  791. flags, parameters.space_id, parameters.attribute.title_id,
  792. parameters.attribute.user_id[1], parameters.attribute.user_id[0],
  793. parameters.attribute.save_id, parameters.attribute.type, parameters.attribute.rank,
  794. parameters.attribute.index);
  795. IPC::ResponseBuilder rb{ctx, 3};
  796. rb.Push(ResultSuccess);
  797. rb.Push(flags);
  798. }
  799. void FSP_SRV::OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
  800. LOG_DEBUG(Service_FS, "called");
  801. auto current_romfs = fsc.OpenRomFSCurrentProcess();
  802. if (current_romfs.Failed()) {
  803. // TODO (bunnei): Find the right error code to use here
  804. LOG_CRITICAL(Service_FS, "no file system interface available!");
  805. IPC::ResponseBuilder rb{ctx, 2};
  806. rb.Push(ResultUnknown);
  807. return;
  808. }
  809. auto storage = std::make_shared<IStorage>(system, std::move(current_romfs.Unwrap()));
  810. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  811. rb.Push(ResultSuccess);
  812. rb.PushIpcInterface<IStorage>(std::move(storage));
  813. }
  814. void FSP_SRV::OpenDataStorageByDataId(Kernel::HLERequestContext& ctx) {
  815. IPC::RequestParser rp{ctx};
  816. const auto storage_id = rp.PopRaw<FileSys::StorageId>();
  817. const auto unknown = rp.PopRaw<u32>();
  818. const auto title_id = rp.PopRaw<u64>();
  819. LOG_DEBUG(Service_FS, "called with storage_id={:02X}, unknown={:08X}, title_id={:016X}",
  820. storage_id, unknown, title_id);
  821. auto data = fsc.OpenRomFS(title_id, storage_id, FileSys::ContentRecordType::Data);
  822. if (data.Failed()) {
  823. const auto archive = FileSys::SystemArchive::SynthesizeSystemArchive(title_id);
  824. if (archive != nullptr) {
  825. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  826. rb.Push(ResultSuccess);
  827. rb.PushIpcInterface(std::make_shared<IStorage>(system, archive));
  828. return;
  829. }
  830. // TODO(DarkLordZach): Find the right error code to use here
  831. LOG_ERROR(Service_FS,
  832. "could not open data storage with title_id={:016X}, storage_id={:02X}", title_id,
  833. storage_id);
  834. IPC::ResponseBuilder rb{ctx, 2};
  835. rb.Push(ResultUnknown);
  836. return;
  837. }
  838. const FileSys::PatchManager pm{title_id, fsc, content_provider};
  839. auto storage = std::make_shared<IStorage>(
  840. system, pm.PatchRomFS(std::move(data.Unwrap()), 0, FileSys::ContentRecordType::Data));
  841. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  842. rb.Push(ResultSuccess);
  843. rb.PushIpcInterface<IStorage>(std::move(storage));
  844. }
  845. void FSP_SRV::OpenPatchDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx) {
  846. IPC::RequestParser rp{ctx};
  847. const auto storage_id = rp.PopRaw<FileSys::StorageId>();
  848. const auto title_id = rp.PopRaw<u64>();
  849. LOG_DEBUG(Service_FS, "called with storage_id={:02X}, title_id={:016X}", storage_id, title_id);
  850. IPC::ResponseBuilder rb{ctx, 2};
  851. rb.Push(FileSys::ERROR_ENTITY_NOT_FOUND);
  852. }
  853. void FSP_SRV::OpenDataStorageWithProgramIndex(Kernel::HLERequestContext& ctx) {
  854. IPC::RequestParser rp{ctx};
  855. const auto program_index = rp.PopRaw<u8>();
  856. LOG_DEBUG(Service_FS, "called, program_index={}", program_index);
  857. auto patched_romfs = fsc.OpenPatchedRomFSWithProgramIndex(
  858. system.GetCurrentProcessProgramID(), program_index, FileSys::ContentRecordType::Program);
  859. if (patched_romfs.Failed()) {
  860. // TODO: Find the right error code to use here
  861. LOG_ERROR(Service_FS, "could not open storage with program_index={}", program_index);
  862. IPC::ResponseBuilder rb{ctx, 2};
  863. rb.Push(ResultUnknown);
  864. return;
  865. }
  866. auto storage = std::make_shared<IStorage>(system, std::move(patched_romfs.Unwrap()));
  867. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  868. rb.Push(ResultSuccess);
  869. rb.PushIpcInterface<IStorage>(std::move(storage));
  870. }
  871. void FSP_SRV::DisableAutoSaveDataCreation(Kernel::HLERequestContext& ctx) {
  872. LOG_DEBUG(Service_FS, "called");
  873. fsc.SetAutoSaveDataCreation(false);
  874. IPC::ResponseBuilder rb{ctx, 2};
  875. rb.Push(ResultSuccess);
  876. }
  877. void FSP_SRV::SetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
  878. IPC::RequestParser rp{ctx};
  879. access_log_mode = rp.PopEnum<AccessLogMode>();
  880. LOG_DEBUG(Service_FS, "called, access_log_mode={}", access_log_mode);
  881. IPC::ResponseBuilder rb{ctx, 2};
  882. rb.Push(ResultSuccess);
  883. }
  884. void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
  885. LOG_DEBUG(Service_FS, "called");
  886. IPC::ResponseBuilder rb{ctx, 3};
  887. rb.Push(ResultSuccess);
  888. rb.PushEnum(access_log_mode);
  889. }
  890. void FSP_SRV::OutputAccessLogToSdCard(Kernel::HLERequestContext& ctx) {
  891. const auto raw = ctx.ReadBuffer();
  892. auto log = Common::StringFromFixedZeroTerminatedBuffer(
  893. reinterpret_cast<const char*>(raw.data()), raw.size());
  894. LOG_DEBUG(Service_FS, "called");
  895. reporter.SaveFSAccessLog(log);
  896. IPC::ResponseBuilder rb{ctx, 2};
  897. rb.Push(ResultSuccess);
  898. }
  899. void FSP_SRV::GetProgramIndexForAccessLog(Kernel::HLERequestContext& ctx) {
  900. LOG_DEBUG(Service_FS, "called");
  901. IPC::ResponseBuilder rb{ctx, 4};
  902. rb.Push(ResultSuccess);
  903. rb.PushEnum(AccessLogVersion::Latest);
  904. rb.Push(access_log_program_index);
  905. }
  906. void FSP_SRV::GetCacheStorageSize(Kernel::HLERequestContext& ctx) {
  907. IPC::RequestParser rp{ctx};
  908. const auto index{rp.Pop<s32>()};
  909. LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index);
  910. IPC::ResponseBuilder rb{ctx, 6};
  911. rb.Push(ResultSuccess);
  912. rb.Push(s64{0});
  913. rb.Push(s64{0});
  914. }
  915. class IMultiCommitManager final : public ServiceFramework<IMultiCommitManager> {
  916. public:
  917. explicit IMultiCommitManager(Core::System& system_)
  918. : ServiceFramework{system_, "IMultiCommitManager"} {
  919. static const FunctionInfo functions[] = {
  920. {1, &IMultiCommitManager::Add, "Add"},
  921. {2, &IMultiCommitManager::Commit, "Commit"},
  922. };
  923. RegisterHandlers(functions);
  924. }
  925. private:
  926. FileSys::VirtualFile backend;
  927. void Add(Kernel::HLERequestContext& ctx) {
  928. LOG_WARNING(Service_FS, "(STUBBED) called");
  929. IPC::ResponseBuilder rb{ctx, 2};
  930. rb.Push(ResultSuccess);
  931. }
  932. void Commit(Kernel::HLERequestContext& ctx) {
  933. LOG_WARNING(Service_FS, "(STUBBED) called");
  934. IPC::ResponseBuilder rb{ctx, 2};
  935. rb.Push(ResultSuccess);
  936. }
  937. };
  938. void FSP_SRV::OpenMultiCommitManager(Kernel::HLERequestContext& ctx) {
  939. LOG_DEBUG(Service_FS, "called");
  940. IPC::ResponseBuilder rb{ctx, 2, 0, 1};
  941. rb.Push(ResultSuccess);
  942. rb.PushIpcInterface<IMultiCommitManager>(std::make_shared<IMultiCommitManager>(system));
  943. }
  944. } // namespace Service::FileSystem