filesystem.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. // Copyright 2018 yuzu emulator team
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <utility>
  5. #include "common/assert.h"
  6. #include "common/file_util.h"
  7. #include "core/core.h"
  8. #include "core/file_sys/bis_factory.h"
  9. #include "core/file_sys/errors.h"
  10. #include "core/file_sys/mode.h"
  11. #include "core/file_sys/registered_cache.h"
  12. #include "core/file_sys/romfs_factory.h"
  13. #include "core/file_sys/savedata_factory.h"
  14. #include "core/file_sys/sdmc_factory.h"
  15. #include "core/file_sys/vfs.h"
  16. #include "core/file_sys/vfs_offset.h"
  17. #include "core/hle/service/filesystem/filesystem.h"
  18. #include "core/hle/service/filesystem/fsp_ldr.h"
  19. #include "core/hle/service/filesystem/fsp_pr.h"
  20. #include "core/hle/service/filesystem/fsp_srv.h"
  21. namespace Service::FileSystem {
  22. // Size of emulated sd card free space, reported in bytes.
  23. // Just using 32GB because thats reasonable
  24. // TODO(DarkLordZach): Eventually make this configurable in settings.
  25. constexpr u64 EMULATED_SD_REPORTED_SIZE = 32000000000;
  26. static FileSys::VirtualDir GetDirectoryRelativeWrapped(FileSys::VirtualDir base,
  27. std::string_view dir_name_) {
  28. std::string dir_name(FileUtil::SanitizePath(dir_name_));
  29. if (dir_name.empty() || dir_name == "." || dir_name == "/" || dir_name == "\\")
  30. return base;
  31. return base->GetDirectoryRelative(dir_name);
  32. }
  33. VfsDirectoryServiceWrapper::VfsDirectoryServiceWrapper(FileSys::VirtualDir backing_)
  34. : backing(std::move(backing_)) {}
  35. VfsDirectoryServiceWrapper::~VfsDirectoryServiceWrapper() = default;
  36. std::string VfsDirectoryServiceWrapper::GetName() const {
  37. return backing->GetName();
  38. }
  39. ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 size) const {
  40. std::string path(FileUtil::SanitizePath(path_));
  41. auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
  42. auto file = dir->CreateFile(FileUtil::GetFilename(path));
  43. if (file == nullptr) {
  44. // TODO(DarkLordZach): Find a better error code for this
  45. return ResultCode(-1);
  46. }
  47. if (!file->Resize(size)) {
  48. // TODO(DarkLordZach): Find a better error code for this
  49. return ResultCode(-1);
  50. }
  51. return RESULT_SUCCESS;
  52. }
  53. ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const {
  54. std::string path(FileUtil::SanitizePath(path_));
  55. if (path.empty()) {
  56. // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but...
  57. return RESULT_SUCCESS;
  58. }
  59. auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
  60. if (dir->GetFile(FileUtil::GetFilename(path)) == nullptr) {
  61. return FileSys::ERROR_PATH_NOT_FOUND;
  62. }
  63. if (!dir->DeleteFile(FileUtil::GetFilename(path))) {
  64. // TODO(DarkLordZach): Find a better error code for this
  65. return ResultCode(-1);
  66. }
  67. return RESULT_SUCCESS;
  68. }
  69. ResultCode VfsDirectoryServiceWrapper::CreateDirectory(const std::string& path_) const {
  70. std::string path(FileUtil::SanitizePath(path_));
  71. auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
  72. if (dir == nullptr && FileUtil::GetFilename(FileUtil::GetParentPath(path)).empty())
  73. dir = backing;
  74. auto new_dir = dir->CreateSubdirectory(FileUtil::GetFilename(path));
  75. if (new_dir == nullptr) {
  76. // TODO(DarkLordZach): Find a better error code for this
  77. return ResultCode(-1);
  78. }
  79. return RESULT_SUCCESS;
  80. }
  81. ResultCode VfsDirectoryServiceWrapper::DeleteDirectory(const std::string& path_) const {
  82. std::string path(FileUtil::SanitizePath(path_));
  83. auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
  84. if (!dir->DeleteSubdirectory(FileUtil::GetFilename(path))) {
  85. // TODO(DarkLordZach): Find a better error code for this
  86. return ResultCode(-1);
  87. }
  88. return RESULT_SUCCESS;
  89. }
  90. ResultCode VfsDirectoryServiceWrapper::DeleteDirectoryRecursively(const std::string& path_) const {
  91. std::string path(FileUtil::SanitizePath(path_));
  92. auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
  93. if (!dir->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path))) {
  94. // TODO(DarkLordZach): Find a better error code for this
  95. return ResultCode(-1);
  96. }
  97. return RESULT_SUCCESS;
  98. }
  99. ResultCode VfsDirectoryServiceWrapper::RenameFile(const std::string& src_path_,
  100. const std::string& dest_path_) const {
  101. std::string src_path(FileUtil::SanitizePath(src_path_));
  102. std::string dest_path(FileUtil::SanitizePath(dest_path_));
  103. auto src = backing->GetFileRelative(src_path);
  104. if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) {
  105. // Use more-optimized vfs implementation rename.
  106. if (src == nullptr)
  107. return FileSys::ERROR_PATH_NOT_FOUND;
  108. if (!src->Rename(FileUtil::GetFilename(dest_path))) {
  109. // TODO(DarkLordZach): Find a better error code for this
  110. return ResultCode(-1);
  111. }
  112. return RESULT_SUCCESS;
  113. }
  114. // Move by hand -- TODO(DarkLordZach): Optimize
  115. auto c_res = CreateFile(dest_path, src->GetSize());
  116. if (c_res != RESULT_SUCCESS)
  117. return c_res;
  118. auto dest = backing->GetFileRelative(dest_path);
  119. ASSERT_MSG(dest != nullptr, "Newly created file with success cannot be found.");
  120. ASSERT_MSG(dest->WriteBytes(src->ReadAllBytes()) == src->GetSize(),
  121. "Could not write all of the bytes but everything else has succeded.");
  122. if (!src->GetContainingDirectory()->DeleteFile(FileUtil::GetFilename(src_path))) {
  123. // TODO(DarkLordZach): Find a better error code for this
  124. return ResultCode(-1);
  125. }
  126. return RESULT_SUCCESS;
  127. }
  128. ResultCode VfsDirectoryServiceWrapper::RenameDirectory(const std::string& src_path_,
  129. const std::string& dest_path_) const {
  130. std::string src_path(FileUtil::SanitizePath(src_path_));
  131. std::string dest_path(FileUtil::SanitizePath(dest_path_));
  132. auto src = GetDirectoryRelativeWrapped(backing, src_path);
  133. if (FileUtil::GetParentPath(src_path) == FileUtil::GetParentPath(dest_path)) {
  134. // Use more-optimized vfs implementation rename.
  135. if (src == nullptr)
  136. return FileSys::ERROR_PATH_NOT_FOUND;
  137. if (!src->Rename(FileUtil::GetFilename(dest_path))) {
  138. // TODO(DarkLordZach): Find a better error code for this
  139. return ResultCode(-1);
  140. }
  141. return RESULT_SUCCESS;
  142. }
  143. // TODO(DarkLordZach): Implement renaming across the tree (move).
  144. ASSERT_MSG(false,
  145. "Could not rename directory with path \"{}\" to new path \"{}\" because parent dirs "
  146. "don't match -- UNIMPLEMENTED",
  147. src_path, dest_path);
  148. // TODO(DarkLordZach): Find a better error code for this
  149. return ResultCode(-1);
  150. }
  151. ResultVal<FileSys::VirtualFile> VfsDirectoryServiceWrapper::OpenFile(const std::string& path_,
  152. FileSys::Mode mode) const {
  153. std::string path(FileUtil::SanitizePath(path_));
  154. auto npath = path;
  155. while (npath.size() > 0 && (npath[0] == '/' || npath[0] == '\\'))
  156. npath = npath.substr(1);
  157. auto file = backing->GetFileRelative(npath);
  158. if (file == nullptr)
  159. return FileSys::ERROR_PATH_NOT_FOUND;
  160. if (mode == FileSys::Mode::Append) {
  161. return MakeResult<FileSys::VirtualFile>(
  162. std::make_shared<FileSys::OffsetVfsFile>(file, 0, file->GetSize()));
  163. }
  164. return MakeResult<FileSys::VirtualFile>(file);
  165. }
  166. ResultVal<FileSys::VirtualDir> VfsDirectoryServiceWrapper::OpenDirectory(const std::string& path_) {
  167. std::string path(FileUtil::SanitizePath(path_));
  168. auto dir = GetDirectoryRelativeWrapped(backing, path);
  169. if (dir == nullptr) {
  170. // TODO(DarkLordZach): Find a better error code for this
  171. return FileSys::ERROR_PATH_NOT_FOUND;
  172. }
  173. return MakeResult(dir);
  174. }
  175. u64 VfsDirectoryServiceWrapper::GetFreeSpaceSize() const {
  176. if (backing->IsWritable())
  177. return EMULATED_SD_REPORTED_SIZE;
  178. return 0;
  179. }
  180. ResultVal<FileSys::EntryType> VfsDirectoryServiceWrapper::GetEntryType(
  181. const std::string& path_) const {
  182. std::string path(FileUtil::SanitizePath(path_));
  183. auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
  184. if (dir == nullptr)
  185. return FileSys::ERROR_PATH_NOT_FOUND;
  186. auto filename = FileUtil::GetFilename(path);
  187. // TODO(Subv): Some games use the '/' path, find out what this means.
  188. if (filename.empty())
  189. return MakeResult(FileSys::EntryType::Directory);
  190. if (dir->GetFile(filename) != nullptr)
  191. return MakeResult(FileSys::EntryType::File);
  192. if (dir->GetSubdirectory(filename) != nullptr)
  193. return MakeResult(FileSys::EntryType::Directory);
  194. return FileSys::ERROR_PATH_NOT_FOUND;
  195. }
  196. /**
  197. * Map of registered file systems, identified by type. Once an file system is registered here, it
  198. * is never removed until UnregisterFileSystems is called.
  199. */
  200. static std::unique_ptr<FileSys::RomFSFactory> romfs_factory;
  201. static std::unique_ptr<FileSys::SaveDataFactory> save_data_factory;
  202. static std::unique_ptr<FileSys::SDMCFactory> sdmc_factory;
  203. static std::unique_ptr<FileSys::BISFactory> bis_factory;
  204. ResultCode RegisterRomFS(std::unique_ptr<FileSys::RomFSFactory>&& factory) {
  205. ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second RomFS");
  206. romfs_factory = std::move(factory);
  207. LOG_DEBUG(Service_FS, "Registered RomFS");
  208. return RESULT_SUCCESS;
  209. }
  210. ResultCode RegisterSaveData(std::unique_ptr<FileSys::SaveDataFactory>&& factory) {
  211. ASSERT_MSG(romfs_factory == nullptr, "Tried to register a second save data");
  212. save_data_factory = std::move(factory);
  213. LOG_DEBUG(Service_FS, "Registered save data");
  214. return RESULT_SUCCESS;
  215. }
  216. ResultCode RegisterSDMC(std::unique_ptr<FileSys::SDMCFactory>&& factory) {
  217. ASSERT_MSG(sdmc_factory == nullptr, "Tried to register a second SDMC");
  218. sdmc_factory = std::move(factory);
  219. LOG_DEBUG(Service_FS, "Registered SDMC");
  220. return RESULT_SUCCESS;
  221. }
  222. ResultCode RegisterBIS(std::unique_ptr<FileSys::BISFactory>&& factory) {
  223. ASSERT_MSG(bis_factory == nullptr, "Tried to register a second BIS");
  224. bis_factory = std::move(factory);
  225. LOG_DEBUG(Service_FS, "Registered BIS");
  226. return RESULT_SUCCESS;
  227. }
  228. void SetPackedUpdate(FileSys::VirtualFile update_raw) {
  229. LOG_TRACE(Service_FS, "Setting packed update for romfs");
  230. if (romfs_factory == nullptr)
  231. return;
  232. romfs_factory->SetPackedUpdate(std::move(update_raw));
  233. }
  234. ResultVal<FileSys::VirtualFile> OpenRomFSCurrentProcess() {
  235. LOG_TRACE(Service_FS, "Opening RomFS for current process");
  236. if (romfs_factory == nullptr) {
  237. // TODO(bunnei): Find a better error code for this
  238. return ResultCode(-1);
  239. }
  240. return romfs_factory->OpenCurrentProcess();
  241. }
  242. ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId storage_id,
  243. FileSys::ContentRecordType type) {
  244. LOG_TRACE(Service_FS, "Opening RomFS for title_id={:016X}, storage_id={:02X}, type={:02X}",
  245. title_id, static_cast<u8>(storage_id), static_cast<u8>(type));
  246. if (romfs_factory == nullptr) {
  247. // TODO(bunnei): Find a better error code for this
  248. return ResultCode(-1);
  249. }
  250. return romfs_factory->Open(title_id, storage_id, type);
  251. }
  252. ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
  253. FileSys::SaveDataDescriptor save_struct) {
  254. LOG_TRACE(Service_FS, "Opening Save Data for space_id={:01X}, save_struct={}",
  255. static_cast<u8>(space), save_struct.DebugInfo());
  256. if (save_data_factory == nullptr) {
  257. return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound);
  258. }
  259. return save_data_factory->Open(space, save_struct);
  260. }
  261. ResultVal<FileSys::VirtualDir> OpenSDMC() {
  262. LOG_TRACE(Service_FS, "Opening SDMC");
  263. if (sdmc_factory == nullptr) {
  264. return ResultCode(ErrorModule::FS, FileSys::ErrCodes::SdCardNotFound);
  265. }
  266. return sdmc_factory->Open();
  267. }
  268. std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
  269. return std::make_shared<FileSys::RegisteredCacheUnion>(
  270. std::vector<std::shared_ptr<FileSys::RegisteredCache>>{
  271. GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()});
  272. }
  273. std::shared_ptr<FileSys::RegisteredCache> GetSystemNANDContents() {
  274. LOG_TRACE(Service_FS, "Opening System NAND Contents");
  275. if (bis_factory == nullptr)
  276. return nullptr;
  277. return bis_factory->GetSystemNANDContents();
  278. }
  279. std::shared_ptr<FileSys::RegisteredCache> GetUserNANDContents() {
  280. LOG_TRACE(Service_FS, "Opening User NAND Contents");
  281. if (bis_factory == nullptr)
  282. return nullptr;
  283. return bis_factory->GetUserNANDContents();
  284. }
  285. std::shared_ptr<FileSys::RegisteredCache> GetSDMCContents() {
  286. LOG_TRACE(Service_FS, "Opening SDMC Contents");
  287. if (sdmc_factory == nullptr)
  288. return nullptr;
  289. return sdmc_factory->GetSDMCContents();
  290. }
  291. FileSys::VirtualDir GetModificationLoadRoot(u64 title_id) {
  292. LOG_TRACE(Service_FS, "Opening mod load root for tid={:016X}", title_id);
  293. if (bis_factory == nullptr)
  294. return nullptr;
  295. return bis_factory->GetModificationLoadRoot(title_id);
  296. }
  297. void CreateFactories(const FileSys::VirtualFilesystem& vfs, bool overwrite) {
  298. if (overwrite) {
  299. bis_factory = nullptr;
  300. save_data_factory = nullptr;
  301. sdmc_factory = nullptr;
  302. }
  303. auto nand_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir),
  304. FileSys::Mode::ReadWrite);
  305. auto sd_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir),
  306. FileSys::Mode::ReadWrite);
  307. auto load_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::LoadDir),
  308. FileSys::Mode::ReadWrite);
  309. if (bis_factory == nullptr)
  310. bis_factory = std::make_unique<FileSys::BISFactory>(nand_directory, load_directory);
  311. if (save_data_factory == nullptr)
  312. save_data_factory = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
  313. if (sdmc_factory == nullptr)
  314. sdmc_factory = std::make_unique<FileSys::SDMCFactory>(std::move(sd_directory));
  315. }
  316. void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs) {
  317. romfs_factory = nullptr;
  318. CreateFactories(vfs, false);
  319. std::make_shared<FSP_LDR>()->InstallAsService(service_manager);
  320. std::make_shared<FSP_PR>()->InstallAsService(service_manager);
  321. std::make_shared<FSP_SRV>()->InstallAsService(service_manager);
  322. }
  323. } // namespace Service::FileSystem