filesystem.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734
  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/vfs.h"
  20. #include "core/file_sys/vfs/vfs_offset.h"
  21. #include "core/hle/service/filesystem/filesystem.h"
  22. #include "core/hle/service/filesystem/fsp/fsp_ldr.h"
  23. #include "core/hle/service/filesystem/fsp/fsp_pr.h"
  24. #include "core/hle/service/filesystem/fsp/fsp_srv.h"
  25. #include "core/hle/service/filesystem/romfs_controller.h"
  26. #include "core/hle/service/filesystem/save_data_controller.h"
  27. #include "core/hle/service/server_manager.h"
  28. #include "core/loader/loader.h"
  29. namespace Service::FileSystem {
  30. static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
  31. std::string_view dir_name_) {
  32. std::string dir_name(Common::FS::SanitizePath(dir_name_));
  33. if (dir_name.empty() || dir_name == "." || dir_name == "/" || dir_name == "\\")
  34. return base;
  35. return base->GetDirectoryRelative(dir_name);
  36. }
  37. VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(FileSys::VirtualDir backing_)
  38. : backing(std::move(backing_)) {}
  39. VfsDirectoryServiceWrapper::~VfsDirectoryServiceWrapper() = default;
  40. std::string VfsDirectoryServiceWrapper::GetName() const {
  41. return backing->GetName();
  42. }
  43. Result VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size) const {
  44. std::string path(Common::FS::SanitizePath(path_));
  45. auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
  46. if (dir == nullptr) {
  47. return FileSys::ERROR_PATH_NOT_FOUND;
  48. }
  49. FileSys::EntryType entry_type{};
  50. if (GetEntryType(&entry_type, path) == ResultSuccess) {
  51. return FileSys::ERROR_PATH_ALREADY_EXISTS;
  52. }
  53. auto file = dir->CreateFile(Common::FS::GetFilename(path));
  54. if (file == nullptr) {
  55. // TODO(DarkLordZach): Find a better error code for this
  56. return ResultUnknown;
  57. }
  58. if (!file->Resize(size)) {
  59. // TODO(DarkLordZach): Find a better error code for this
  60. return ResultUnknown;
  61. }
  62. return ResultSuccess;
  63. }
  64. Result VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const {
  65. std::string path(Common::FS::SanitizePath(path_));
  66. if (path.empty()) {
  67. // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but...
  68. return ResultSuccess;
  69. }
  70. auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
  71. if (dir == nullptr || dir->GetFile(Common::FS::GetFilename(path)) == nullptr) {
  72. return FileSys::ERROR_PATH_NOT_FOUND;
  73. }
  74. if (!dir->DeleteFile(Common::FS::GetFilename(path))) {
  75. // TODO(DarkLordZach): Find a better error code for this
  76. return ResultUnknown;
  77. }
  78. return ResultSuccess;
  79. }
  80. Result VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const {
  81. std::string path(Common::FS::SanitizePath(path_));
  82. // NOTE: This is inaccurate behavior. CreateDirectory is not recursive.
  83. // CreateDirectory should return PathNotFound if the parent directory does not exist.
  84. // This is here temporarily in order to have UMM "work" in the meantime.
  85. // TODO (Morph): Remove this when a hardware test verifies the correct behavior.
  86. const auto components = Common::FS::SplitPathComponents(path);
  87. std::string relative_path;
  88. for (const auto& component : components) {
  89. relative_path = Common::FS::SanitizePath(fmt::format("{}/{}", relative_path, component));
  90. auto new_dir = backing->CreateSubdirectory(relative_path);
  91. if (new_dir == nullptr) {
  92. // TODO(DarkLordZach): Find a better error code for this
  93. return ResultUnknown;
  94. }
  95. }
  96. return ResultSuccess;
  97. }
  98. Result VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path_) const {
  99. std::string path(Common::FS::SanitizePath(path_));
  100. auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
  101. if (!dir->DeleteSubdirectory(Common::FS::GetFilename(path))) {
  102. // TODO(DarkLordZach): Find a better error code for this
  103. return ResultUnknown;
  104. }
  105. return ResultSuccess;
  106. }
  107. Result VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path_) const {
  108. std::string path(Common::FS::SanitizePath(path_));
  109. auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
  110. if (!dir->DeleteSubdirectoryRecursive(Common::FS::GetFilename(path))) {
  111. // TODO(DarkLordZach): Find a better error code for this
  112. return ResultUnknown;
  113. }
  114. return ResultSuccess;
  115. }
  116. Result VfsDirectoryServiceWrapper::CleanDirectoryRecursively(const std::string& path) const {
  117. const std::string sanitized_path(Common::FS::SanitizePath(path));
  118. auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(sanitized_path));
  119. if (!dir->CleanSubdirectoryRecursive(Common::FS::GetFilename(sanitized_path))) {
  120. // TODO(DarkLordZach): Find a better error code for this
  121. return ResultUnknown;
  122. }
  123. return ResultSuccess;
  124. }
  125. Result VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
  126. const std::string& dest_path_) const {
  127. std::string src_path(Common::FS::SanitizePath(src_path_));
  128. std::string dest_path(Common::FS::SanitizePath(dest_path_));
  129. auto src = backing->GetFileRelative(src_path);
  130. auto dst = backing->GetFileRelative(dest_path);
  131. if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
  132. // Use more-optimized vfs implementation rename.
  133. if (src == nullptr) {
  134. return FileSys::ERROR_PATH_NOT_FOUND;
  135. }
  136. if (dst && Common::FS::Exists(dst->GetFullPath())) {
  137. LOG_ERROR(Service_FS, "File at new_path={} already exists", dst->GetFullPath());
  138. return FileSys::ERROR_PATH_ALREADY_EXISTS;
  139. }
  140. if (!src->Rename(Common::FS::GetFilename(dest_path))) {
  141. // TODO(DarkLordZach): Find a better error code for this
  142. return ResultUnknown;
  143. }
  144. return ResultSuccess;
  145. }
  146. // Move by hand -- TODO(DarkLordZach): Optimize
  147. auto c_res = CreateFile(dest_path, src->GetSize());
  148. if (c_res != ResultSuccess)
  149. return c_res;
  150. auto dest = backing->GetFileRelative(dest_path);
  151. ASSERT_MSG(dest != nullptr, "Newly created file with success cannot be found.");
  152. ASSERT_MSG(dest->WriteBytes(src->ReadAllBytes()) == src->GetSize(),
  153. "Could not write all of the bytes but everything else has succeeded.");
  154. if (!src->GetContainingDirectory()->DeleteFile(Common::FS::GetFilename(src_path))) {
  155. // TODO(DarkLordZach): Find a better error code for this
  156. return ResultUnknown;
  157. }
  158. return ResultSuccess;
  159. }
  160. Result VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_,
  161. const std::string& dest_path_) const {
  162. std::string src_path(Common::FS::SanitizePath(src_path_));
  163. std::string dest_path(Common::FS::SanitizePath(dest_path_));
  164. auto src = GetDirectoryRelativeWrapped(backing, src_path);
  165. if (Common::FS::GetParentPath(src_path) == Common::FS::GetParentPath(dest_path)) {
  166. // Use more-optimized vfs implementation rename.
  167. if (src == nullptr)
  168. return FileSys::ERROR_PATH_NOT_FOUND;
  169. if (!src->Rename(Common::FS::GetFilename(dest_path))) {
  170. // TODO(DarkLordZach): Find a better error code for this
  171. return ResultUnknown;
  172. }
  173. return ResultSuccess;
  174. }
  175. // TODO(DarkLordZach): Implement renaming across the tree (move).
  176. ASSERT_MSG(false,
  177. "Could not rename directory with path \"{}\" to new path \"{}\" because parent dirs "
  178. "don't match -- UNIMPLEMENTED",
  179. src_path, dest_path);
  180. // TODO(DarkLordZach): Find a better error code for this
  181. return ResultUnknown;
  182. }
  183. Result VfsDirectoryServiceWrapper::OpenFile(FileSys::VirtualFile* out_file,
  184. const std::string& path_, FileSys::Mode mode) const {
  185. const std::string path(Common::FS::SanitizePath(path_));
  186. std::string_view npath = path;
  187. while (!npath.empty() && (npath[0] == '/' || npath[0] == '\\')) {
  188. npath.remove_prefix(1);
  189. }
  190. auto file = backing->GetFileRelative(npath);
  191. if (file == nullptr) {
  192. return FileSys::ERROR_PATH_NOT_FOUND;
  193. }
  194. if (mode == FileSys::Mode::Append) {
  195. *out_file = std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize());
  196. } else {
  197. *out_file = file;
  198. }
  199. return ResultSuccess;
  200. }
  201. Result VfsDirectoryServiceWrapper::OpenDirectory(FileSys::VirtualDir* out_directory,
  202. const std::string& path_) {
  203. std::string path(Common::FS::SanitizePath(path_));
  204. auto dir = GetDirectoryRelativeWrapped(backing, path);
  205. if (dir == nullptr) {
  206. // TODO(DarkLordZach): Find a better error code for this
  207. return FileSys::ERROR_PATH_NOT_FOUND;
  208. }
  209. *out_directory = dir;
  210. return ResultSuccess;
  211. }
  212. Result VfsDirectoryServiceWrapper::GetEntryType(FileSys::EntryType* out_entry_type,
  213. const std::string& path_) const {
  214. std::string path(Common::FS::SanitizePath(path_));
  215. auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
  216. if (dir == nullptr) {
  217. return FileSys::ERROR_PATH_NOT_FOUND;
  218. }
  219. auto filename = Common::FS::GetFilename(path);
  220. // TODO(Subv): Some games use the '/' path, find out what this means.
  221. if (filename.empty()) {
  222. *out_entry_type = FileSys::EntryType::Directory;
  223. return ResultSuccess;
  224. }
  225. if (dir->GetFile(filename) != nullptr) {
  226. *out_entry_type = FileSys::EntryType::File;
  227. return ResultSuccess;
  228. }
  229. if (dir->GetSubdirectory(filename) != nullptr) {
  230. *out_entry_type = FileSys::EntryType::Directory;
  231. return ResultSuccess;
  232. }
  233. return FileSys::ERROR_PATH_NOT_FOUND;
  234. }
  235. Result VfsDirectoryServiceWrapper::GetFileTimeStampRaw(
  236. FileSys::FileTimeStampRaw* out_file_time_stamp_raw, const std::string& path) const {
  237. auto dir = GetDirectoryRelativeWrapped(backing, Common::FS::GetParentPath(path));
  238. if (dir == nullptr) {
  239. return FileSys::ERROR_PATH_NOT_FOUND;
  240. }
  241. FileSys::EntryType entry_type;
  242. if (GetEntryType(&entry_type, path) != ResultSuccess) {
  243. return FileSys::ERROR_PATH_NOT_FOUND;
  244. }
  245. *out_file_time_stamp_raw = dir->GetFileTimeStamp(Common::FS::GetFilename(path));
  246. return ResultSuccess;
  247. }
  248. FileSystemController::FileSystemController(Core::System& system_) : system{system_} {}
  249. FileSystemController::~FileSystemController() = default;
  250. Result FileSystemController::RegisterProcess(
  251. ProcessId process_id, ProgramId program_id,
  252. std::shared_ptr<FileSys::RomFSFactory>&& romfs_factory) {
  253. std::scoped_lock lk{registration_lock};
  254. registrations.emplace(process_id, Registration{
  255. .program_id = program_id,
  256. .romfs_factory = std::move(romfs_factory),
  257. .save_data_factory = CreateSaveDataFactory(program_id),
  258. });
  259. LOG_DEBUG(Service_FS, "Registered for process {}", process_id);
  260. return ResultSuccess;
  261. }
  262. Result FileSystemController::OpenProcess(
  263. ProgramId* out_program_id, std::shared_ptr<SaveDataController>* out_save_data_controller,
  264. std::shared_ptr<RomFsController>* out_romfs_controller, ProcessId process_id) {
  265. std::scoped_lock lk{registration_lock};
  266. const auto it = registrations.find(process_id);
  267. if (it == registrations.end()) {
  268. return FileSys::ERROR_ENTITY_NOT_FOUND;
  269. }
  270. *out_program_id = it->second.program_id;
  271. *out_save_data_controller =
  272. std::make_shared<SaveDataController>(system, it->second.save_data_factory);
  273. *out_romfs_controller =
  274. std::make_shared<RomFsController>(it->second.romfs_factory, it->second.program_id);
  275. return ResultSuccess;
  276. }
  277. void FileSystemController::SetPackedUpdate(ProcessId process_id, FileSys::VirtualFile update_raw) {
  278. LOG_TRACE(Service_FS, "Setting packed update for romfs");
  279. std::scoped_lock lk{registration_lock};
  280. const auto it = registrations.find(process_id);
  281. if (it == registrations.end()) {
  282. return;
  283. }
  284. it->second.romfs_factory->SetPackedUpdate(std::move(update_raw));
  285. }
  286. std::shared_ptr<SaveDataController> FileSystemController::OpenSaveDataController() {
  287. return std::make_shared<SaveDataController>(system, CreateSaveDataFactory(ProgramId{}));
  288. }
  289. std::shared_ptr<FileSys::SaveDataFactory> FileSystemController::CreateSaveDataFactory(
  290. ProgramId program_id) {
  291. using YuzuPath = Common::FS::YuzuPath;
  292. const auto rw_mode = FileSys::Mode::ReadWrite;
  293. auto vfs = system.GetFilesystem();
  294. const auto nand_directory =
  295. vfs->OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode);
  296. return std::make_shared<FileSys::SaveDataFactory>(system, program_id,
  297. std::move(nand_directory));
  298. }
  299. Result FileSystemController::OpenSDMC(FileSys::VirtualDir* out_sdmc) const {
  300. LOG_TRACE(Service_FS, "Opening SDMC");
  301. if (sdmc_factory == nullptr) {
  302. return FileSys::ERROR_SD_CARD_NOT_FOUND;
  303. }
  304. auto sdmc = sdmc_factory->Open();
  305. if (sdmc == nullptr) {
  306. return FileSys::ERROR_SD_CARD_NOT_FOUND;
  307. }
  308. *out_sdmc = sdmc;
  309. return ResultSuccess;
  310. }
  311. Result FileSystemController::OpenBISPartition(FileSys::VirtualDir* out_bis_partition,
  312. FileSys::BisPartitionId id) const {
  313. LOG_TRACE(Service_FS, "Opening BIS Partition with id={:08X}", id);
  314. if (bis_factory == nullptr) {
  315. return FileSys::ERROR_ENTITY_NOT_FOUND;
  316. }
  317. auto part = bis_factory->OpenPartition(id);
  318. if (part == nullptr) {
  319. return FileSys::ERROR_INVALID_ARGUMENT;
  320. }
  321. *out_bis_partition = part;
  322. return ResultSuccess;
  323. }
  324. Result FileSystemController::OpenBISPartitionStorage(
  325. FileSys::VirtualFile* out_bis_partition_storage, FileSys::BisPartitionId id) const {
  326. LOG_TRACE(Service_FS, "Opening BIS Partition Storage with id={:08X}", id);
  327. if (bis_factory == nullptr) {
  328. return FileSys::ERROR_ENTITY_NOT_FOUND;
  329. }
  330. auto part = bis_factory->OpenPartitionStorage(id, system.GetFilesystem());
  331. if (part == nullptr) {
  332. return FileSys::ERROR_INVALID_ARGUMENT;
  333. }
  334. *out_bis_partition_storage = part;
  335. return ResultSuccess;
  336. }
  337. u64 FileSystemController::GetFreeSpaceSize(FileSys::StorageId id) const {
  338. switch (id) {
  339. case FileSys::StorageId::None:
  340. case FileSys::StorageId::GameCard:
  341. return 0;
  342. case FileSys::StorageId::SdCard:
  343. if (sdmc_factory == nullptr)
  344. return 0;
  345. return sdmc_factory->GetSDMCFreeSpace();
  346. case FileSys::StorageId::Host:
  347. if (bis_factory == nullptr)
  348. return 0;
  349. return bis_factory->GetSystemNANDFreeSpace() + bis_factory->GetUserNANDFreeSpace();
  350. case FileSys::StorageId::NandSystem:
  351. if (bis_factory == nullptr)
  352. return 0;
  353. return bis_factory->GetSystemNANDFreeSpace();
  354. case FileSys::StorageId::NandUser:
  355. if (bis_factory == nullptr)
  356. return 0;
  357. return bis_factory->GetUserNANDFreeSpace();
  358. }
  359. return 0;
  360. }
  361. u64 FileSystemController::GetTotalSpaceSize(FileSys::StorageId id) const {
  362. switch (id) {
  363. case FileSys::StorageId::None:
  364. case FileSys::StorageId::GameCard:
  365. return 0;
  366. case FileSys::StorageId::SdCard:
  367. if (sdmc_factory == nullptr)
  368. return 0;
  369. return sdmc_factory->GetSDMCTotalSpace();
  370. case FileSys::StorageId::Host:
  371. if (bis_factory == nullptr)
  372. return 0;
  373. return bis_factory->GetFullNANDTotalSpace();
  374. case FileSys::StorageId::NandSystem:
  375. if (bis_factory == nullptr)
  376. return 0;
  377. return bis_factory->GetSystemNANDTotalSpace();
  378. case FileSys::StorageId::NandUser:
  379. if (bis_factory == nullptr)
  380. return 0;
  381. return bis_factory->GetUserNANDTotalSpace();
  382. }
  383. return 0;
  384. }
  385. void FileSystemController::SetGameCard(FileSys::VirtualFile file) {
  386. gamecard = std::make_unique<FileSys::XCI>(file);
  387. const auto dir = gamecard->ConcatenatedPseudoDirectory();
  388. gamecard_registered = std::make_unique<FileSys::RegisteredCache>(dir);
  389. gamecard_placeholder = std::make_unique<FileSys::PlaceholderCache>(dir);
  390. }
  391. FileSys::XCI* FileSystemController::GetGameCard() const {
  392. return gamecard.get();
  393. }
  394. FileSys::RegisteredCache* FileSystemController::GetGameCardContents() const {
  395. return gamecard_registered.get();
  396. }
  397. FileSys::PlaceholderCache* FileSystemController::GetGameCardPlaceholder() const {
  398. return gamecard_placeholder.get();
  399. }
  400. FileSys::RegisteredCache* FileSystemController::GetSystemNANDContents() const {
  401. LOG_TRACE(Service_FS, "Opening System NAND Contents");
  402. if (bis_factory == nullptr)
  403. return nullptr;
  404. return bis_factory->GetSystemNANDContents();
  405. }
  406. FileSys::RegisteredCache* FileSystemController::GetUserNANDContents() const {
  407. LOG_TRACE(Service_FS, "Opening User NAND Contents");
  408. if (bis_factory == nullptr)
  409. return nullptr;
  410. return bis_factory->GetUserNANDContents();
  411. }
  412. FileSys::RegisteredCache* FileSystemController::GetSDMCContents() const {
  413. LOG_TRACE(Service_FS, "Opening SDMC Contents");
  414. if (sdmc_factory == nullptr)
  415. return nullptr;
  416. return sdmc_factory->GetSDMCContents();
  417. }
  418. FileSys::PlaceholderCache* FileSystemController::GetSystemNANDPlaceholder() const {
  419. LOG_TRACE(Service_FS, "Opening System NAND Placeholder");
  420. if (bis_factory == nullptr)
  421. return nullptr;
  422. return bis_factory->GetSystemNANDPlaceholder();
  423. }
  424. FileSys::PlaceholderCache* FileSystemController::GetUserNANDPlaceholder() const {
  425. LOG_TRACE(Service_FS, "Opening User NAND Placeholder");
  426. if (bis_factory == nullptr)
  427. return nullptr;
  428. return bis_factory->GetUserNANDPlaceholder();
  429. }
  430. FileSys::PlaceholderCache* FileSystemController::GetSDMCPlaceholder() const {
  431. LOG_TRACE(Service_FS, "Opening SDMC Placeholder");
  432. if (sdmc_factory == nullptr)
  433. return nullptr;
  434. return sdmc_factory->GetSDMCPlaceholder();
  435. }
  436. FileSys::RegisteredCache* FileSystemController::GetRegisteredCacheForStorage(
  437. FileSys::StorageId id) const {
  438. switch (id) {
  439. case FileSys::StorageId::None:
  440. case FileSys::StorageId::Host:
  441. UNIMPLEMENTED();
  442. return nullptr;
  443. case FileSys::StorageId::GameCard:
  444. return GetGameCardContents();
  445. case FileSys::StorageId::NandSystem:
  446. return GetSystemNANDContents();
  447. case FileSys::StorageId::NandUser:
  448. return GetUserNANDContents();
  449. case FileSys::StorageId::SdCard:
  450. return GetSDMCContents();
  451. }
  452. return nullptr;
  453. }
  454. FileSys::PlaceholderCache* FileSystemController::GetPlaceholderCacheForStorage(
  455. FileSys::StorageId id) const {
  456. switch (id) {
  457. case FileSys::StorageId::None:
  458. case FileSys::StorageId::Host:
  459. UNIMPLEMENTED();
  460. return nullptr;
  461. case FileSys::StorageId::GameCard:
  462. return GetGameCardPlaceholder();
  463. case FileSys::StorageId::NandSystem:
  464. return GetSystemNANDPlaceholder();
  465. case FileSys::StorageId::NandUser:
  466. return GetUserNANDPlaceholder();
  467. case FileSys::StorageId::SdCard:
  468. return GetSDMCPlaceholder();
  469. }
  470. return nullptr;
  471. }
  472. FileSys::VirtualDir FileSystemController::GetSystemNANDContentDirectory() const {
  473. LOG_TRACE(Service_FS, "Opening system NAND content directory");
  474. if (bis_factory == nullptr)
  475. return nullptr;
  476. return bis_factory->GetSystemNANDContentDirectory();
  477. }
  478. FileSys::VirtualDir FileSystemController::GetUserNANDContentDirectory() const {
  479. LOG_TRACE(Service_FS, "Opening user NAND content directory");
  480. if (bis_factory == nullptr)
  481. return nullptr;
  482. return bis_factory->GetUserNANDContentDirectory();
  483. }
  484. FileSys::VirtualDir FileSystemController::GetSDMCContentDirectory() const {
  485. LOG_TRACE(Service_FS, "Opening SDMC content directory");
  486. if (sdmc_factory == nullptr)
  487. return nullptr;
  488. return sdmc_factory->GetSDMCContentDirectory();
  489. }
  490. FileSys::VirtualDir FileSystemController::GetNANDImageDirectory() const {
  491. LOG_TRACE(Service_FS, "Opening NAND image directory");
  492. if (bis_factory == nullptr)
  493. return nullptr;
  494. return bis_factory->GetImageDirectory();
  495. }
  496. FileSys::VirtualDir FileSystemController::GetSDMCImageDirectory() const {
  497. LOG_TRACE(Service_FS, "Opening SDMC image directory");
  498. if (sdmc_factory == nullptr)
  499. return nullptr;
  500. return sdmc_factory->GetImageDirectory();
  501. }
  502. FileSys::VirtualDir FileSystemController::GetContentDirectory(ContentStorageId id) const {
  503. switch (id) {
  504. case ContentStorageId::System:
  505. return GetSystemNANDContentDirectory();
  506. case ContentStorageId::User:
  507. return GetUserNANDContentDirectory();
  508. case ContentStorageId::SdCard:
  509. return GetSDMCContentDirectory();
  510. }
  511. return nullptr;
  512. }
  513. FileSys::VirtualDir FileSystemController::GetImageDirectory(ImageDirectoryId id) const {
  514. switch (id) {
  515. case ImageDirectoryId::NAND:
  516. return GetNANDImageDirectory();
  517. case ImageDirectoryId::SdCard:
  518. return GetSDMCImageDirectory();
  519. }
  520. return nullptr;
  521. }
  522. FileSys::VirtualDir FileSystemController::GetModificationLoadRoot(u64 title_id) const {
  523. LOG_TRACE(Service_FS, "Opening mod load root for tid={:016X}", title_id);
  524. if (bis_factory == nullptr)
  525. return nullptr;
  526. return bis_factory->GetModificationLoadRoot(title_id);
  527. }
  528. FileSys::VirtualDir FileSystemController::GetSDMCModificationLoadRoot(u64 title_id) const {
  529. LOG_TRACE(Service_FS, "Opening SDMC mod load root for tid={:016X}", title_id);
  530. if (sdmc_factory == nullptr) {
  531. return nullptr;
  532. }
  533. return sdmc_factory->GetSDMCModificationLoadRoot(title_id);
  534. }
  535. FileSys::VirtualDir FileSystemController::GetModificationDumpRoot(u64 title_id) const {
  536. LOG_TRACE(Service_FS, "Opening mod dump root for tid={:016X}", title_id);
  537. if (bis_factory == nullptr)
  538. return nullptr;
  539. return bis_factory->GetModificationDumpRoot(title_id);
  540. }
  541. FileSys::VirtualDir FileSystemController::GetBCATDirectory(u64 title_id) const {
  542. LOG_TRACE(Service_FS, "Opening BCAT root for tid={:016X}", title_id);
  543. if (bis_factory == nullptr)
  544. return nullptr;
  545. return bis_factory->GetBCATDirectory(title_id);
  546. }
  547. void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) {
  548. if (overwrite) {
  549. bis_factory = nullptr;
  550. sdmc_factory = nullptr;
  551. }
  552. using YuzuPath = Common::FS::YuzuPath;
  553. const auto sdmc_dir_path = Common::FS::GetYuzuPath(YuzuPath::SDMCDir);
  554. const auto sdmc_load_dir_path = sdmc_dir_path / "atmosphere/contents";
  555. const auto rw_mode = FileSys::Mode::ReadWrite;
  556. auto nand_directory =
  557. vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode);
  558. auto sd_directory = vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_dir_path), rw_mode);
  559. auto load_directory =
  560. vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir), FileSys::Mode::Read);
  561. auto sd_load_directory =
  562. vfs.OpenDirectory(Common::FS::PathToUTF8String(sdmc_load_dir_path), FileSys::Mode::Read);
  563. auto dump_directory =
  564. vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::DumpDir), rw_mode);
  565. if (bis_factory == nullptr) {
  566. bis_factory = std::make_unique<FileSys::BISFactory>(
  567. nand_directory, std::move(load_directory), std::move(dump_directory));
  568. system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::SysNAND,
  569. bis_factory->GetSystemNANDContents());
  570. system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::UserNAND,
  571. bis_factory->GetUserNANDContents());
  572. }
  573. if (sdmc_factory == nullptr) {
  574. sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory),
  575. std::move(sd_load_directory));
  576. system.RegisterContentProvider(FileSys::ContentProviderUnionSlot::SDMC,
  577. sdmc_factory->GetSDMCContents());
  578. }
  579. }
  580. void FileSystemController::Reset() {
  581. std::scoped_lock lk{registration_lock};
  582. registrations.clear();
  583. }
  584. void LoopProcess(Core::System& system) {
  585. auto server_manager = std::make_unique<ServerManager>(system);
  586. const auto FileSystemProxyFactory = [&] { return std::make_shared<FSP_SRV>(system); };
  587. server_manager->RegisterNamedService("fsp-ldr", std::make_shared<FSP_LDR>(system));
  588. server_manager->RegisterNamedService("fsp:pr", std::make_shared<FSP_PR>(system));
  589. server_manager->RegisterNamedService("fsp-srv", std::move(FileSystemProxyFactory));
  590. ServerManager::RunServer(std::move(server_manager));
  591. }
  592. } // namespace Service::FileSystem