filesystem.cpp 26 KB

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