filesystem.cpp 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861
  1. // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include <utility>
  4. #include "common/assert.h"
  5. #include "common/fs/fs.h"
  6. #include "common/fs/path_util.h"
  7. #include "common/settings.h"
  8. #include "core/core.h"
  9. #include "core/file_sys/bis_factory.h"
  10. #include "core/file_sys/card_image.h"
  11. #include "core/file_sys/control_metadata.h"
  12. #include "core/file_sys/errors.h"
  13. #include "core/file_sys/mode.h"
  14. #include "core/file_sys/patch_manager.h"
  15. #include "core/file_sys/registered_cache.h"
  16. #include "core/file_sys/romfs_factory.h"
  17. #include "core/file_sys/savedata_factory.h"
  18. #include "core/file_sys/sdmc_factory.h"
  19. #include "core/file_sys/vfs.h"
  20. #include "core/file_sys/vfs_offset.h"
  21. #include "core/hle/service/filesystem/filesystem.h"
  22. #include "core/hle/service/filesystem/fsp_ldr.h"
  23. #include "core/hle/service/filesystem/fsp_pr.h"
  24. #include "core/hle/service/filesystem/fsp_srv.h"
  25. #include "core/hle/service/server_manager.h"
  26. #include "core/loader/loader.h"
  27. namespace Service::FileSystem {
  28. // A default size for normal/journal save data size if application control metadata cannot be found.
  29. // This should be large enough to satisfy even the most extreme requirements (~4.2GB)
  30. constexpr u64 SUFFICIENT_SAVE_DATA_SIZE = 0xF0000000;
  31. static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
  32. std::string_view dir_name_) {
  33. std::string dir_name(Common::FS::SanitizePath(dir_name_));
  34. if (dir_name.empty() || dir_name == "." || dir_name == "/" || dir_name == "\\")
  35. return base;
  36. return base->GetDirectoryRelative(dir_name);
  37. }
  38. VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(FileSys::VirtualDir backing_)
  39. : backing(std::move(backing_)) {}
  40. VfsDirectoryServiceWrapper::~VfsDirectoryServiceWrapper() = default;
  41. std::string VfsDirectoryServiceWrapper::GetName() const {
  42. return backing->GetName();
  43. }
  44. Result VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size) const {
  45. std::string path(Common::FS::SanitizePath(path_));
  46. auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
  47. if (dir == nullptr) {
  48. return FileSys::ERROR_PATH_NOT_FOUND;
  49. }
  50. FileSys::EntryType entry_type{};
  51. if (GetEntryType(&entry_type, path) == ResultSuccess) {
  52. return FileSys::ERROR_PATH_ALREADY_EXISTS;
  53. }
  54. auto file = dir->CreateFile(Common::FS::GetFilename(path));
  55. if (file == nullptr) {
  56. // TODO(DarkLordZach): Find a better error code for this
  57. return ResultUnknown;
  58. }
  59. if (!file->Resize(size)) {
  60. // TODO(DarkLordZach): Find a better error code for this
  61. return ResultUnknown;
  62. }
  63. return ResultSuccess;
  64. }
  65. Result VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const {
  66. std::string path(Common::FS::SanitizePath(path_));
  67. if (path.empty()) {
  68. // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but...
  69. return ResultSuccess;
  70. }
  71. auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
  72. if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) {
  73. return FileSys::ERROR_PATH_NOT_FOUND;
  74. }
  75. if (!dir->DeleteFile(Common::FS::GetFilename(path))) {
  76. // TODO(DarkLordZach): Find a better error code for this
  77. return ResultUnknown;
  78. }
  79. return ResultSuccess;
  80. }
  81. Result VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const {
  82. std::string path(Common::FS::SanitizePath(path_));
  83. // NOTE: This is inaccurate behavior. CreateDirectory is not recursive.
  84. // CreateDirectory should return PathNotFound if the parent directory does not exist.
  85. // This is here temporarily in order to have UMM "work" in the meantime.
  86. // TODO (Morph): Remove this when a hardware test verifies the correct behavior.
  87. const auto components = Common::FS::SplitPathComponents(path);
  88. std::string relative_path;
  89. for (const auto& component : components) {
  90. relative_path = Common::FS::SanitizePath(fmt::format("{}/{}", relative_path, component));
  91. auto new_dir = backing->CreateSubdirectory(relative_path);
  92. if (new_dir == nullptr) {
  93. // TODO(DarkLordZach): Find a better error code for this
  94. return ResultUnknown;
  95. }
  96. }
  97. return ResultSuccess;
  98. }
  99. Result VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path_) const {
  100. std::string path(Common::FS::SanitizePath(path_));
  101. auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
  102. if (!dir->DeleteSubdirectory(Common::FS::GetFilename(path))) {
  103. // TODO(DarkLordZach): Find a better error code for this
  104. return ResultUnknown;
  105. }
  106. return ResultSuccess;
  107. }
  108. Result VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path_) const {
  109. std::string path(Common::FS::SanitizePath(path_));
  110. auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
  111. if (!dir->DeleteSubdirectoryRecursive(Common::FS::GetFilename(path))) {
  112. // TODO(DarkLordZach): Find a better error code for this
  113. return ResultUnknown;
  114. }
  115. return ResultSuccess;
  116. }
  117. Result VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::string& path) const {
  118. const std::string sanitized_path(Common::FS::SanitizePath(path));
  119. auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(sanitized_path));
  120. if (!dir->CleanSubdirectoryRecursive(Common::FS::GetFilename(sanitized_path))) {
  121. // TODO(DarkLordZach): Find a better error code for this
  122. return ResultUnknown;
  123. }
  124. return ResultSuccess;
  125. }
  126. Result VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
  127. const std::string& dest_path_) const {
  128. std::string src_path(Common::FS::SanitizePath(src_path_));
  129. std::string dest_path(Common::FS::SanitizePath(dest_path_));
  130. auto src = backing->GetFileRelative(src_path);
  131. auto dst = backing->GetFileRelative(dest_path);
  132. if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
  133. // Use more-optimized vfs implementation rename.
  134. if (src == nullptr) {
  135. return FileSys::ERROR_PATH_NOT_FOUND;
  136. }
  137. if (dst && Common::FS::Exists(dst->GetFullPath())) {
  138. LOG_ERROR(Service_FS, "File at new_path={} already exists", dst->GetFullPath());
  139. return FileSys::ERROR_PATH_ALREADY_EXISTS;
  140. }
  141. if (!src->Rename(Common::FS::GetFilename(dest_path))) {
  142. // TODO(DarkLordZach): Find a better error code for this
  143. return ResultUnknown;
  144. }
  145. return ResultSuccess;
  146. }
  147. // Move by hand -- TODO(DarkLordZach): Optimize
  148. auto c_res = CreateFile(dest_path, src->GetSize());
  149. if (c_res != ResultSuccess)
  150. return c_res;
  151. auto dest = backing->GetFileRelative(dest_path);
  152. ASSERT_MSG(dest != nullptr, "Newly created file with success cannot be found.");
  153. ASSERT_MSG(dest->WriteBytes(src->ReadAllBytes()) == src->GetSize(),
  154. "Could not write all of the bytes but everything else has succeeded.");
  155. if (!src->GetContainingDirectory()->DeleteFile(Common::FS::GetFilename(src_path))) {
  156. // TODO(DarkLordZach): Find a better error code for this
  157. return ResultUnknown;
  158. }
  159. return ResultSuccess;
  160. }
  161. Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_,
  162. const std::string& dest_path_) const {
  163. std::string src_path(Common::FS::SanitizePath(src_path_));
  164. std::string dest_path(Common::FS::SanitizePath(dest_path_));
  165. auto src = GetDirectoryRelativeWrapped(backing, src_path);
  166. if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
  167. // Use more-optimized vfs implementation rename.
  168. if (src == nullptr)
  169. return FileSys::ERROR_PATH_NOT_FOUND;
  170. if (!src->Rename(Common::FS::GetFilename(dest_path))) {
  171. // TODO(DarkLordZach): Find a better error code for this
  172. return ResultUnknown;
  173. }
  174. return ResultSuccess;
  175. }
  176. // TODO(DarkLordZach): Implement renaming across the tree (move).
  177. ASSERT_MSG(false,
  178. "Could not rename directory with path \"{}\" to new path \"{}\" because parent dirs "
  179. "don't match -- UNIMPLEMENTED",
  180. src_path, dest_path);
  181. // TODO(DarkLordZach): Find a better error code for this
  182. return ResultUnknown;
  183. }
  184. Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file,
  185. const std::string& path_, FileSys::Mode mode) const {
  186. const std::string path(Common::FS::SanitizePath(path_));
  187. std::string_view npath = path;
  188. while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) {
  189. npath.remove_prefix(1);
  190. }
  191. auto file = backing->GetFileRelative(npath);
  192. if (file == nullptr) {
  193. return FileSys::ERROR_PATH_NOT_FOUND;
  194. }
  195. if (mode == FileSys::Mode::Append) {
  196. *out_file = std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize());
  197. } else {
  198. *out_file = file;
  199. }
  200. return ResultSuccess;
  201. }
  202. Result VfsDirectoryServiceWrapper::OpenDirectory(FileSys::VirtualDir* out_directory,
  203. const std::string& path_) {
  204. std::string path(Common::FS::SanitizePath(path_));
  205. auto dir = GetDirectoryRelativeWrapped(backing, path);
  206. if (dir == nullptr) {
  207. // TODO(DarkLordZach): Find a better error code for this
  208. return FileSys::ERROR_PATH_NOT_FOUND;
  209. }
  210. *out_directory = dir;
  211. return ResultSuccess;
  212. }
  213. Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::EntryType* out_entry_type,
  214. const std::string& path_) const {
  215. std::string path(Common::FS::SanitizePath(path_));
  216. auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
  217. if (dir == nullptr) {
  218. return FileSys::ERROR_PATH_NOT_FOUND;
  219. }
  220. auto filename = Common::FS::GetFilename(path);
  221. // TODO(Subv): Some games use the '/' path, find out what this means.
  222. if (filename.empty()) {
  223. *out_entry_type = FileSys::EntryType::Directory;
  224. return ResultSuccess;
  225. }
  226. if (dir->GetFile(filename) != nullptr) {
  227. *out_entry_type = FileSys::EntryType::File;
  228. return ResultSuccess;
  229. }
  230. if (dir->GetSubdirectory(filename) != nullptr) {
  231. *out_entry_type = FileSys::EntryType::Directory;
  232. return ResultSuccess;
  233. }
  234. return FileSys::ERROR_PATH_NOT_FOUND;
  235. }
  236. Result VfsDirectoryServiceWrapper::GetFileTimeStampRaw(
  237. FileSys::FileTimeStampRaw* out_file_time_stamp_raw, const std::string& path) const {
  238. auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
  239. if (dir == nullptr) {
  240. return FileSys::ERROR_PATH_NOT_FOUND;
  241. }
  242. FileSys::EntryType entry_type;
  243. if (GetEntryType(&entry_type, path) != ResultSuccess) {
  244. return FileSys::ERROR_PATH_NOT_FOUND;
  245. }
  246. *out_file_time_stamp_raw = dir->GetFileTimeStamp(Common::FS::GetFilename(path));
  247. return ResultSuccess;
  248. }
  249. FileSystemController::FileSystemController(Core::System& system_) : system{system_} {}
  250. FileSystemController::~FileSystemController() = default;
  251. Result FileSystemController::RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
  252. romfs_factory = std::move(factory);
  253. LOG_DEBUG(Service_FS, "Registered RomFS");
  254. return ResultSuccess;
  255. }
  256. Result FileSystemController::RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory) {
  257. ASSERT_MSG(save_data_factory == nullptr, "Tried to register a second save data");
  258. save_data_factory = std::move(factory);
  259. LOG_DEBUG(Service_FS, "Registered save data");
  260. return ResultSuccess;
  261. }
  262. Result FileSystemController::RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
  263. ASSERT_MSG(sdmc_factory == nullptr, "Tried to register a second SDMC");
  264. sdmc_factory = std::move(factory);
  265. LOG_DEBUG(Service_FS, "Registered SDMC");
  266. return ResultSuccess;
  267. }
  268. Result FileSystemController::RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
  269. ASSERT_MSG(bis_factory == nullptr, "Tried to register a second BIS");
  270. bis_factory = std::move(factory);
  271. LOG_DEBUG(Service_FS, "Registered BIS");
  272. return ResultSuccess;
  273. }
  274. void FileSystemController::SetPackedUpdate(FileSys::VirtualFile update_raw) {
  275. LOG_TRACE(Service_FS, "Setting packed update for romfs");
  276. if (romfs_factory == nullptr)
  277. return;
  278. romfs_factory->SetPackedUpdate(std::move(update_raw));
  279. }
  280. FileSys::VirtualFile FileSystemController::OpenRomFSCurrentProcess() const {
  281. LOG_TRACE(Service_FS, "Opening RomFS for current process");
  282. if (romfs_factory == nullptr) {
  283. return nullptr;
  284. }
  285. return romfs_factory->OpenCurrentProcess(system.GetApplicationProcessProgramID());
  286. }
  287. FileSys::VirtualFile FileSystemController::OpenPatchedRomFS(u64 title_id,
  288. FileSys::ContentRecordType type) const {
  289. LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}", title_id);
  290. if (romfs_factory == nullptr) {
  291. return nullptr;
  292. }
  293. return romfs_factory->OpenPatchedRomFS(title_id, type);
  294. }
  295. FileSys::VirtualFile FileSystemController::OpenPatchedRomFSWithProgramIndex(
  296. u64 title_id, u8 program_index, FileSys::ContentRecordType type) const {
  297. LOG_TRACE(Service_FS, "Opening patched RomFS for title_id={:016X}, program_index={}", title_id,
  298. program_index);
  299. if (romfs_factory == nullptr) {
  300. return nullptr;
  301. }
  302. return romfs_factory->OpenPatchedRomFSWithProgramIndex(title_id, program_index, type);
  303. }
  304. FileSys::VirtualFile FileSystemController::OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
  305. FileSys::ContentRecordType type) const {
  306. LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}",
  307. title_id, storage_id, type);
  308. if (romfs_factory == nullptr) {
  309. return nullptr;
  310. }
  311. return romfs_factory->Open(title_id, storage_id, type);
  312. }
  313. std::shared_ptr<FileSys::NCA> FileSystemController::OpenBaseNca(
  314. u64 title_id, FileSys::StorageId storage_id, FileSys::ContentRecordType type) const {
  315. return romfs_factory->GetEntry(title_id, storage_id, type);
  316. }
  317. Result FileSystemController::CreateSaveData(FileSys::VirtualDir* out_save_data,
  318. FileSys::SaveDataSpaceId space,
  319. const FileSys::SaveDataAttribute& save_struct) const {
  320. LOG_TRACE(Service_FS, "Creating Save Data for space_id={:01X}, save_struct={}", space,
  321. save_struct.DebugInfo());
  322. if (save_data_factory == nullptr) {
  323. return FileSys::ERROR_ENTITY_NOT_FOUND;
  324. }
  325. auto save_data = save_data_factory->Create(space, save_struct);
  326. if (save_data == nullptr) {
  327. return FileSys::ERROR_ENTITY_NOT_FOUND;
  328. }
  329. *out_save_data = save_data;
  330. return ResultSuccess;
  331. }
  332. Result FileSystemController::OpenSaveData(FileSys::VirtualDir* out_save_data,
  333. FileSys::SaveDataSpaceId space,
  334. const FileSys::SaveDataAttribute& attribute) const {
  335. LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}", space,
  336. attribute.DebugInfo());
  337. if (save_data_factory == nullptr) {
  338. return FileSys::ERROR_ENTITY_NOT_FOUND;
  339. }
  340. auto save_data = save_data_factory->Open(space, attribute);
  341. if (save_data == nullptr) {
  342. return FileSys::ERROR_ENTITY_NOT_FOUND;
  343. }
  344. *out_save_data = save_data;
  345. return ResultSuccess;
  346. }
  347. Result FileSystemController::OpenSaveDataSpace(FileSys::VirtualDir* out_save_data_space,
  348. FileSys::SaveDataSpaceId space) const {
  349. LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", space);
  350. if (save_data_factory == nullptr) {
  351. return FileSys::ERROR_ENTITY_NOT_FOUND;
  352. }
  353. auto save_data_space = save_data_factory->GetSaveDataSpaceDirectory(space);
  354. if (save_data_space == nullptr) {
  355. return FileSys::ERROR_ENTITY_NOT_FOUND;
  356. }
  357. *out_save_data_space = save_data_space;
  358. return ResultSuccess;
  359. }
  360. Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const {
  361. LOG_TRACE(Service_FS, "Opening SDMC");
  362. if (sdmc_factory == nullptr) {
  363. return FileSys::ERROR_SD_CARD_NOT_FOUND;
  364. }
  365. auto sdmc = sdmc_factory->Open();
  366. if (sdmc == nullptr) {
  367. return FileSys::ERROR_SD_CARD_NOT_FOUND;
  368. }
  369. *out_sdmc = sdmc;
  370. return ResultSuccess;
  371. }
  372. Result FileSystemController::OpenBISPartition(FileSys::VirtualDir* out_bis_partition,
  373. FileSys::BisPartitionId id) const {
  374. LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", id);
  375. if (bis_factory == nullptr) {
  376. return FileSys::ERROR_ENTITY_NOT_FOUND;
  377. }
  378. auto part = bis_factory->OpenPartition(id);
  379. if (part == nullptr) {
  380. return FileSys::ERROR_INVALID_ARGUMENT;
  381. }
  382. *out_bis_partition = part;
  383. return ResultSuccess;
  384. }
  385. Result FileSystemController::OpenBISPartitionStorage(
  386. FileSys::VirtualFile* out_bis_partition_storage, FileSys::BisPartitionId id) const {
  387. LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", id);
  388. if (bis_factory == nullptr) {
  389. return FileSys::ERROR_ENTITY_NOT_FOUND;
  390. }
  391. auto part = bis_factory->OpenPartitionStorage(id, system.GetFilesystem());
  392. if (part == nullptr) {
  393. return FileSys::ERROR_INVALID_ARGUMENT;
  394. }
  395. *out_bis_partition_storage = part;
  396. return ResultSuccess;
  397. }
  398. u64 FileSystemController::GetFreeSpaceSize(FileSys::StorageId id) const {
  399. switch (id) {
  400. case FileSys::StorageId::None:
  401. case FileSys::StorageId::GameCard:
  402. return 0;
  403. case FileSys::StorageId::SdCard:
  404. if (sdmc_factory == nullptr)
  405. return 0;
  406. return sdmc_factory->GetSDMCFreeSpace();
  407. case FileSys::StorageId::Host:
  408. if (bis_factory == nullptr)
  409. return 0;
  410. return bis_factory->GetSystemNANDFreeSpace() + bis_factory->GetUserNANDFreeSpace();
  411. case FileSys::StorageId::NandSystem:
  412. if (bis_factory == nullptr)
  413. return 0;
  414. return bis_factory->GetSystemNANDFreeSpace();
  415. case FileSys::StorageId::NandUser:
  416. if (bis_factory == nullptr)
  417. return 0;
  418. return bis_factory->GetUserNANDFreeSpace();
  419. }
  420. return 0;
  421. }
  422. u64 FileSystemController::GetTotalSpaceSize(FileSys::StorageId id) const {
  423. switch (id) {
  424. case FileSys::StorageId::None:
  425. case FileSys::StorageId::GameCard:
  426. return 0;
  427. case FileSys::StorageId::SdCard:
  428. if (sdmc_factory == nullptr)
  429. return 0;
  430. return sdmc_factory->GetSDMCTotalSpace();
  431. case FileSys::StorageId::Host:
  432. if (bis_factory == nullptr)
  433. return 0;
  434. return bis_factory->GetFullNANDTotalSpace();
  435. case FileSys::StorageId::NandSystem:
  436. if (bis_factory == nullptr)
  437. return 0;
  438. return bis_factory->GetSystemNANDTotalSpace();
  439. case FileSys::StorageId::NandUser:
  440. if (bis_factory == nullptr)
  441. return 0;
  442. return bis_factory->GetUserNANDTotalSpace();
  443. }
  444. return 0;
  445. }
  446. FileSys::SaveDataSize FileSystemController::ReadSaveDataSize(FileSys::SaveDataType type,
  447. u64 title_id, u128 user_id) const {
  448. if (save_data_factory == nullptr) {
  449. return {0, 0};
  450. }
  451. const auto value = save_data_factory->ReadSaveDataSize(type, title_id, user_id);
  452. if (value.normal == 0 && value.journal == 0) {
  453. FileSys::SaveDataSize new_size{SUFFICIENT_SAVE_DATA_SIZE, SUFFICIENT_SAVE_DATA_SIZE};
  454. FileSys::NACP nacp;
  455. const auto res = system.GetAppLoader().ReadControlData(nacp);
  456. if (res != Loader::ResultStatus::Success) {
  457. const FileSys::PatchManager pm{system.GetApplicationProcessProgramID(),
  458. system.GetFileSystemController(),
  459. system.GetContentProvider()};
  460. const auto metadata = pm.GetControlMetadata();
  461. const auto& nacp_unique = metadata.first;
  462. if (nacp_unique != nullptr) {
  463. new_size = {nacp_unique->GetDefaultNormalSaveSize(),
  464. nacp_unique->GetDefaultJournalSaveSize()};
  465. }
  466. } else {
  467. new_size = {nacp.GetDefaultNormalSaveSize(), nacp.GetDefaultJournalSaveSize()};
  468. }
  469. WriteSaveDataSize(type, title_id, user_id, new_size);
  470. return new_size;
  471. }
  472. return value;
  473. }
  474. void FileSystemController::WriteSaveDataSize(FileSys::SaveDataType type, u64 title_id, u128 user_id,
  475. FileSys::SaveDataSize new_value) const {
  476. if (save_data_factory != nullptr)
  477. save_data_factory->WriteSaveDataSize(type, title_id, user_id, new_value);
  478. }
  479. void FileSystemController::SetGameCard(FileSys::VirtualFile file) {
  480. gamecard = std::make_unique<FileSys::XCI>(file);
  481. const auto dir = gamecard->ConcatenatedPseudoDirectory();
  482. gamecard_registered = std::make_unique<FileSys::RegisteredCache>(dir);
  483. gamecard_placeholder = std::make_unique<FileSys::PlaceholderCache>(dir);
  484. }
  485. FileSys::XCI* FileSystemController::GetGameCard() const {
  486. return gamecard.get();
  487. }
  488. FileSys::RegisteredCache* FileSystemController::GetGameCardContents() const {
  489. return gamecard_registered.get();
  490. }
  491. FileSys::PlaceholderCache* FileSystemController::GetGameCardPlaceholder() const {
  492. return gamecard_placeholder.get();
  493. }
  494. FileSys::RegisteredCache* FileSystemController::GetSystemNANDContents() const {
  495. LOG_TRACE(Service_FS, "Opening System NAND Contents");
  496. if (bis_factory == nullptr)
  497. return nullptr;
  498. return bis_factory->GetSystemNANDContents();
  499. }
  500. FileSys::RegisteredCache* FileSystemController::GetUserNANDContents() const {
  501. LOG_TRACE(Service_FS, "Opening User NAND Contents");
  502. if (bis_factory == nullptr)
  503. return nullptr;
  504. return bis_factory->GetUserNANDContents();
  505. }
  506. FileSys::RegisteredCache* FileSystemController::GetSDMCContents() const {
  507. LOG_TRACE(Service_FS, "Opening SDMC Contents");
  508. if (sdmc_factory == nullptr)
  509. return nullptr;
  510. return sdmc_factory->GetSDMCContents();
  511. }
  512. FileSys::PlaceholderCache* FileSystemController::GetSystemNANDPlaceholder() const {
  513. LOG_TRACE(Service_FS, "Opening System NAND Placeholder");
  514. if (bis_factory == nullptr)
  515. return nullptr;
  516. return bis_factory->GetSystemNANDPlaceholder();
  517. }
  518. FileSys::PlaceholderCache* FileSystemController::GetUserNANDPlaceholder() const {
  519. LOG_TRACE(Service_FS, "Opening User NAND Placeholder");
  520. if (bis_factory == nullptr)
  521. return nullptr;
  522. return bis_factory->GetUserNANDPlaceholder();
  523. }
  524. FileSys::PlaceholderCache* FileSystemController::GetSDMCPlaceholder() const {
  525. LOG_TRACE(Service_FS, "Opening SDMC Placeholder");
  526. if (sdmc_factory == nullptr)
  527. return nullptr;
  528. return sdmc_factory->GetSDMCPlaceholder();
  529. }
  530. FileSys::RegisteredCache* FileSystemController::GetRegisteredCacheForStorage(
  531. FileSys::StorageId id) const {
  532. switch (id) {
  533. case FileSys::StorageId::None:
  534. case FileSys::StorageId::Host:
  535. UNIMPLEMENTED();
  536. return nullptr;
  537. case FileSys::StorageId::GameCard:
  538. return GetGameCardContents();
  539. case FileSys::StorageId::NandSystem:
  540. return GetSystemNANDContents();
  541. case FileSys::StorageId::NandUser:
  542. return GetUserNANDContents();
  543. case FileSys::StorageId::SdCard:
  544. return GetSDMCContents();
  545. }
  546. return nullptr;
  547. }
  548. FileSys::PlaceholderCache* FileSystemController::GetPlaceholderCacheForStorage(
  549. FileSys::StorageId id) const {
  550. switch (id) {
  551. case FileSys::StorageId::None:
  552. case FileSys::StorageId::Host:
  553. UNIMPLEMENTED();
  554. return nullptr;
  555. case FileSys::StorageId::GameCard:
  556. return GetGameCardPlaceholder();
  557. case FileSys::StorageId::NandSystem:
  558. return GetSystemNANDPlaceholder();
  559. case FileSys::StorageId::NandUser:
  560. return GetUserNANDPlaceholder();
  561. case FileSys::StorageId::SdCard:
  562. return GetSDMCPlaceholder();
  563. }
  564. return nullptr;
  565. }
  566. FileSys::VirtualDir FileSystemController::GetSystemNANDContentDirectory() const {
  567. LOG_TRACE(Service_FS, "Opening system NAND content directory");
  568. if (bis_factory == nullptr)
  569. return nullptr;
  570. return bis_factory->GetSystemNANDContentDirectory();
  571. }
  572. FileSys::VirtualDir FileSystemController::GetUserNANDContentDirectory() const {
  573. LOG_TRACE(Service_FS, "Opening user NAND content directory");
  574. if (bis_factory == nullptr)
  575. return nullptr;
  576. return bis_factory->GetUserNANDContentDirectory();
  577. }
  578. FileSys::VirtualDir FileSystemController::GetSDMCContentDirectory() const {
  579. LOG_TRACE(Service_FS, "Opening SDMC content directory");
  580. if (sdmc_factory == nullptr)
  581. return nullptr;
  582. return sdmc_factory->GetSDMCContentDirectory();
  583. }
  584. FileSys::VirtualDir FileSystemController::GetNANDImageDirectory() const {
  585. LOG_TRACE(Service_FS, "Opening NAND image directory");
  586. if (bis_factory == nullptr)
  587. return nullptr;
  588. return bis_factory->GetImageDirectory();
  589. }
  590. FileSys::VirtualDir FileSystemController::GetSDMCImageDirectory() const {
  591. LOG_TRACE(Service_FS, "Opening SDMC image directory");
  592. if (sdmc_factory == nullptr)
  593. return nullptr;
  594. return sdmc_factory->GetImageDirectory();
  595. }
  596. FileSys::VirtualDir FileSystemController::GetContentDirectory(ContentStorageId id) const {
  597. switch (id) {
  598. case ContentStorageId::System:
  599. return GetSystemNANDContentDirectory();
  600. case ContentStorageId::User:
  601. return GetUserNANDContentDirectory();
  602. case ContentStorageId::SdCard:
  603. return GetSDMCContentDirectory();
  604. }
  605. return nullptr;
  606. }
  607. FileSys::VirtualDir FileSystemController::GetImageDirectory(ImageDirectoryId id) const {
  608. switch (id) {
  609. case ImageDirectoryId::NAND:
  610. return GetNANDImageDirectory();
  611. case ImageDirectoryId::SdCard:
  612. return GetSDMCImageDirectory();
  613. }
  614. return nullptr;
  615. }
  616. FileSys::VirtualDir FileSystemController::GetModificationLoadRoot(u64 title_id) const {
  617. LOG_TRACE(Service_FS, "Opening mod load root for tid={:016X}", title_id);
  618. if (bis_factory == nullptr)
  619. return nullptr;
  620. return bis_factory->GetModificationLoadRoot(title_id);
  621. }
  622. FileSys::VirtualDir FileSystemController::GetSDMCModificationLoadRoot(u64 title_id) const {
  623. LOG_TRACE(Service_FS, "Opening SDMC mod load root for tid={:016X}", title_id);
  624. if (sdmc_factory == nullptr) {
  625. return nullptr;
  626. }
  627. return sdmc_factory->GetSDMCModificationLoadRoot(title_id);
  628. }
  629. FileSys::VirtualDir FileSystemController::GetModificationDumpRoot(u64 title_id) const {
  630. LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id);
  631. if (bis_factory == nullptr)
  632. return nullptr;
  633. return bis_factory->GetModificationDumpRoot(title_id);
  634. }
  635. FileSys::VirtualDir FileSystemController::GetBCATDirectory(u64 title_id) const {
  636. LOG_TRACE(Service_FS, "Opening BCAT root for tid={:016X}", title_id);
  637. if (bis_factory == nullptr)
  638. return nullptr;
  639. return bis_factory->GetBCATDirectory(title_id);
  640. }
  641. void FileSystemController::SetAutoSaveDataCreation(bool enable) {
  642. save_data_factory->SetAutoCreate(enable);
  643. }
  644. void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
  645. if (overwrite) {
  646. bis_factory = nullptr;
  647. save_data_factory = nullptr;
  648. sdmc_factory = nullptr;
  649. }
  650. using YuzuPath = Common::FS::YuzuPath;
  651. const auto sdmc_dir_path = Common::FS::GetYuzuPath(YuzuPath::SDMCDir);
  652. const auto sdmc_load_dir_path = sdmc_dir_path / "atmosphere/contents";
  653. const auto rw_mode = FileSys::Mode::ReadWrite;
  654. auto nand_directory =
  655. vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode);
  656. auto sd_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_dir_path), rw_mode);
  657. auto load_directory =
  658. vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir), FileSys::Mode::Read);
  659. auto sd_load_directory =
  660. vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_load_dir_path), FileSys::Mode::Read);
  661. auto dump_directory =
  662. vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::DumpDir), rw_mode);
  663. if (bis_factory == nullptr) {
  664. bis_factory = std::make_unique<FileSys::BISFactory>(
  665. nand_directory, std::move(load_directory), std::move(dump_directory));
  666. system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::SysNAND,
  667. bis_factory->GetSystemNANDContents());
  668. system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::UserNAND,
  669. bis_factory->GetUserNANDContents());
  670. }
  671. if (save_data_factory == nullptr) {
  672. save_data_factory =
  673. std::make_unique<FileSys::SaveDataFactory>(system, std::move(nand_directory));
  674. }
  675. if (sdmc_factory == nullptr) {
  676. sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory),
  677. std::move(sd_load_directory));
  678. system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::SDMC,
  679. sdmc_factory->GetSDMCContents());
  680. }
  681. }
  682. void LoopProcess(Core::System& system) {
  683. auto server_manager = std::make_unique<ServerManager>(system);
  684. server_manager->RegisterNamedService("fsp-ldr", std::make_shared<FSP_LDR>(system));
  685. server_manager->RegisterNamedService("fsp:pr", std::make_shared<FSP_PR>(system));
  686. server_manager->RegisterNamedService("fsp-srv", std::make_shared<FSP_SRV>(system));
  687. ServerManager::RunServer(std::move(server_manager));
  688. }
  689. } // namespace Service::FileSystem