filesystem.cpp 30 KB

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