filesystem.cpp 27 KB

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