filesystem.cpp 28 KB

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