diff --git a/Source/Core/Common/NandPaths.cpp b/Source/Core/Common/NandPaths.cpp index b670be635d..336c1bb7bb 100644 --- a/Source/Core/Common/NandPaths.cpp +++ b/Source/Core/Common/NandPaths.cpp @@ -21,41 +21,46 @@ std::string RootUserPath(FromWhichRoot from) return File::GetUserPath(idx); } -std::string GetImportTitlePath(u64 title_id, FromWhichRoot from) +static std::string RootUserPath(std::optional from) +{ + return from ? RootUserPath(*from) : ""; +} + +std::string GetImportTitlePath(u64 title_id, std::optional from) { return RootUserPath(from) + StringFromFormat("/import/%08x/%08x", static_cast(title_id >> 32), static_cast(title_id)); } -std::string GetTicketFileName(u64 title_id, FromWhichRoot from) +std::string GetTicketFileName(u64 title_id, std::optional from) { return StringFromFormat("%s/ticket/%08x/%08x.tik", RootUserPath(from).c_str(), static_cast(title_id >> 32), static_cast(title_id)); } -std::string GetTitlePath(u64 title_id, FromWhichRoot from) +std::string GetTitlePath(u64 title_id, std::optional from) { - return StringFromFormat("%s/title/%08x/%08x/", RootUserPath(from).c_str(), + return StringFromFormat("%s/title/%08x/%08x", RootUserPath(from).c_str(), static_cast(title_id >> 32), static_cast(title_id)); } -std::string GetTitleDataPath(u64 title_id, FromWhichRoot from) +std::string GetTitleDataPath(u64 title_id, std::optional from) { - return GetTitlePath(title_id, from) + "data/"; + return GetTitlePath(title_id, from) + "/data"; } -std::string GetTitleContentPath(u64 title_id, FromWhichRoot from) +std::string GetTitleContentPath(u64 title_id, std::optional from) { - return GetTitlePath(title_id, from) + "content/"; + return GetTitlePath(title_id, from) + "/content"; } -std::string GetTMDFileName(u64 title_id, FromWhichRoot from) +std::string GetTMDFileName(u64 title_id, std::optional from) { - return GetTitleContentPath(title_id, from) + "title.tmd"; + return GetTitleContentPath(title_id, from) + "/title.tmd"; } -bool IsTitlePath(const std::string& path, FromWhichRoot from, u64* title_id) +bool IsTitlePath(const std::string& path, std::optional from, u64* title_id) { std::string expected_prefix = RootUserPath(from) + "/title/"; if (!StringBeginsWith(path, expected_prefix)) diff --git a/Source/Core/Common/NandPaths.h b/Source/Core/Common/NandPaths.h index 5a1dcffce4..068a240f43 100644 --- a/Source/Core/Common/NandPaths.h +++ b/Source/Core/Common/NandPaths.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include "Common/CommonTypes.h" @@ -18,17 +19,22 @@ enum FromWhichRoot std::string RootUserPath(FromWhichRoot from); -// Returns /import/%08x/%08x. Intended for use by ES. -std::string GetImportTitlePath(u64 title_id, FromWhichRoot from = FROM_SESSION_ROOT); +// The following functions return paths relative to the NAND root. +// If a FromWhichRoot is passed, the NAND root on the host filesystem will be prepended to the path. +// TODO: remove the from parameter after all code is migrated off direct FS access. -std::string GetTicketFileName(u64 title_id, FromWhichRoot from); -std::string GetTitlePath(u64 title_id, FromWhichRoot from); -std::string GetTitleDataPath(u64 title_id, FromWhichRoot from); -std::string GetTitleContentPath(u64 title_id, FromWhichRoot from); -std::string GetTMDFileName(u64 title_id, FromWhichRoot from); +// Returns /import/%08x/%08x. Intended for use by ES. +std::string GetImportTitlePath(u64 title_id, std::optional from = {}); + +std::string GetTicketFileName(u64 title_id, std::optional from = {}); +std::string GetTitlePath(u64 title_id, std::optional from = {}); +std::string GetTitleDataPath(u64 title_id, std::optional from = {}); +std::string GetTitleContentPath(u64 title_id, std::optional from = {}); +std::string GetTMDFileName(u64 title_id, std::optional from = {}); // Returns whether a path is within an installed title's directory. -bool IsTitlePath(const std::string& path, FromWhichRoot from, u64* title_id = nullptr); +bool IsTitlePath(const std::string& path, std::optional from = {}, + u64* title_id = nullptr); // Escapes characters that are invalid or have special meanings in the host file system std::string EscapeFileName(const std::string& filename); diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index f93b584251..d38ec6ad59 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -472,7 +472,7 @@ void StateFlags::UpdateChecksum() void UpdateStateFlags(std::function update_function) { const std::string file_path = - Common::GetTitleDataPath(Titles::SYSTEM_MENU, Common::FROM_SESSION_ROOT) + WII_STATE; + Common::GetTitleDataPath(Titles::SYSTEM_MENU, Common::FROM_SESSION_ROOT) + "/" WII_STATE; File::IOFile file; StateFlags state; diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index f426175e58..dc4d5b91e8 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -227,7 +227,7 @@ bool CBoot::SetupWiiMemory() SettingsHandler gen; std::string serno; const std::string settings_file_path( - Common::GetTitleDataPath(Titles::SYSTEM_MENU, Common::FROM_SESSION_ROOT) + WII_SETTING); + Common::GetTitleDataPath(Titles::SYSTEM_MENU, Common::FROM_SESSION_ROOT) + "/" WII_SETTING); if (File::Exists(settings_file_path) && gen.Open(settings_file_path)) { serno = gen.GetValue("SERNO"); @@ -328,7 +328,7 @@ bool CBoot::SetupWiiMemory() static void WriteEmptyPlayRecord() { const std::string file_path = - Common::GetTitleDataPath(Titles::SYSTEM_MENU, Common::FROM_SESSION_ROOT) + "play_rec.dat"; + Common::GetTitleDataPath(Titles::SYSTEM_MENU, Common::FROM_SESSION_ROOT) + "/play_rec.dat"; File::IOFile playrec_file(file_path, "r+b"); std::vector empty_record(0x80); playrec_file.WriteBytes(empty_record.data(), empty_record.size()); diff --git a/Source/Core/Core/HW/WiiSaveCrypted.cpp b/Source/Core/Core/HW/WiiSaveCrypted.cpp index 835ff9b980..28c9150b34 100644 --- a/Source/Core/Core/HW/WiiSaveCrypted.cpp +++ b/Source/Core/Core/HW/WiiSaveCrypted.cpp @@ -181,7 +181,7 @@ void CWiiSaveCrypted::ReadHDR() m_valid = false; return; } - std::string banner_file_path = m_wii_title_path + "banner.bin"; + std::string banner_file_path = m_wii_title_path + "/banner.bin"; if (!File::Exists(banner_file_path) || AskYesNoT("%s already exists. Consider making a backup of the current save files before " "overwriting.\nOverwrite now?", @@ -203,7 +203,7 @@ void CWiiSaveCrypted::WriteHDR() return; memset(&m_header, 0, HEADER_SZ); - std::string banner_file_path = m_wii_title_path + "banner.bin"; + std::string banner_file_path = m_wii_title_path + "/banner.bin"; u32 banner_size = static_cast(File::GetSize(banner_file_path)); m_header.hdr.BannerSize = Common::swap32(banner_size); @@ -347,7 +347,7 @@ void CWiiSaveCrypted::ImportWiiSaveFiles() // Special characters in path components will be escaped such as /../ std::string file_path = Common::EscapePath(reinterpret_cast(file_hdr_tmp.name)); - std::string file_path_full = m_wii_title_path + file_path; + std::string file_path_full = m_wii_title_path + '/' + file_path; File::CreateFullPath(file_path_full); const File::FileInfo file_info(file_path_full); if (file_hdr_tmp.type == 1) @@ -585,7 +585,7 @@ bool CWiiSaveCrypted::getPaths(bool for_export) return false; } - if (!File::Exists(m_wii_title_path + "banner.bin")) + if (!File::Exists(m_wii_title_path + "/banner.bin")) { m_valid = false; ERROR_LOG(CONSOLE, "No banner file found for title %s", game_id); diff --git a/Source/Core/Core/IOS/ES/NandUtils.cpp b/Source/Core/Core/IOS/ES/NandUtils.cpp index 06c6efdf29..1b332bf97b 100644 --- a/Source/Core/Core/IOS/ES/NandUtils.cpp +++ b/Source/Core/Core/IOS/ES/NandUtils.cpp @@ -42,7 +42,8 @@ static IOS::ES::TMDReader FindTMD(u64 title_id, const std::string& tmd_path) IOS::ES::TMDReader ES::FindImportTMD(u64 title_id) const { - return FindTMD(title_id, Common::GetImportTitlePath(title_id) + "/content/title.tmd"); + return FindTMD(title_id, Common::GetImportTitlePath(title_id, Common::FROM_SESSION_ROOT) + + "/content/title.tmd"); } IOS::ES::TMDReader ES::FindInstalledTMD(u64 title_id) const @@ -218,7 +219,8 @@ bool ES::InitImport(u64 title_id) // IOS moves the title content directory to /import if the TMD exists during an import. if (File::Exists(Common::GetTMDFileName(title_id, Common::FROM_SESSION_ROOT))) { - const std::string import_content_dir = Common::GetImportTitlePath(title_id) + "/content"; + const std::string import_content_dir = + Common::GetImportTitlePath(title_id, Common::FROM_SESSION_ROOT) + "/content"; File::CreateFullPath(import_content_dir); if (!File::Rename(content_dir, import_content_dir)) { @@ -233,7 +235,8 @@ bool ES::InitImport(u64 title_id) bool ES::FinishImport(const IOS::ES::TMDReader& tmd) { const u64 title_id = tmd.GetTitleId(); - const std::string import_content_dir = Common::GetImportTitlePath(title_id) + "/content"; + const std::string import_content_dir = + Common::GetImportTitlePath(title_id, Common::FROM_SESSION_ROOT) + "/content"; // Remove everything not listed in the TMD. std::unordered_set expected_entries = {"title.tmd"}; @@ -274,7 +277,8 @@ bool ES::WriteImportTMD(const IOS::ES::TMDReader& tmd) return false; } - const std::string dest = Common::GetImportTitlePath(tmd.GetTitleId()) + "/content/title.tmd"; + const std::string dest = Common::GetImportTitlePath(tmd.GetTitleId(), Common::FROM_SESSION_ROOT) + + "/content/title.tmd"; return File::Rename(tmd_path, dest); } @@ -282,7 +286,8 @@ void ES::FinishStaleImport(u64 title_id) { const auto import_tmd = FindImportTMD(title_id); if (!import_tmd.IsValid()) - File::DeleteDirRecursively(Common::GetImportTitlePath(title_id) + "/content"); + File::DeleteDirRecursively(Common::GetImportTitlePath(title_id, Common::FROM_SESSION_ROOT) + + "/content"); else FinishImport(import_tmd); } @@ -305,7 +310,7 @@ std::string ES::GetContentPath(const u64 title_id, const IOS::ES::Content& conte return content_map.GetFilenameFromSHA1(content.sha1).value_or(""); return Common::GetTitleContentPath(title_id, Common::FROM_SESSION_ROOT) + - StringFromFormat("%08x.app", content.id); + StringFromFormat("/%08x.app", content.id); } } // namespace Device } // namespace HLE diff --git a/Source/Core/Core/IOS/ES/TitleManagement.cpp b/Source/Core/Core/IOS/ES/TitleManagement.cpp index 2496f854f7..1bb9a1a752 100644 --- a/Source/Core/Core/IOS/ES/TitleManagement.cpp +++ b/Source/Core/Core/IOS/ES/TitleManagement.cpp @@ -342,7 +342,8 @@ static bool CheckIfContentHashMatches(const std::vector& content, const IOS: static std::string GetImportContentPath(u64 title_id, u32 content_id) { - return Common::GetImportTitlePath(title_id) + StringFromFormat("/content/%08x.app", content_id); + return Common::GetImportTitlePath(title_id, Common::FROM_SESSION_ROOT) + + StringFromFormat("/content/%08x.app", content_id); } ReturnCode ES::ImportContentEnd(Context& context, u32 content_fd) @@ -604,7 +605,7 @@ ReturnCode ES::DeleteContent(u64 title_id, u32 content_id) const return ES_EINVAL; if (!File::Delete(Common::GetTitleContentPath(title_id, Common::FROM_SESSION_ROOT) + - StringFromFormat("%08x.app", content_id))) + StringFromFormat("/%08x.app", content_id))) { return FS_ENOENT; } diff --git a/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp b/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp index a36ccf537a..ce3f202ddc 100644 --- a/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp +++ b/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp @@ -83,7 +83,8 @@ IPCCommandResult NetKDRequest::IOCtl(const IOCtlRequest& request) if (config.CreationStage() == NWC24::NWC24Config::NWC24_IDCS_INITIAL) { const std::string settings_file_path( - Common::GetTitleDataPath(Titles::SYSTEM_MENU, Common::FROM_SESSION_ROOT) + WII_SETTING); + Common::GetTitleDataPath(Titles::SYSTEM_MENU, Common::FROM_SESSION_ROOT) + + "/" WII_SETTING); SettingsHandler gen; std::string area, model; bool got_settings = false; diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index bf3b0c099f..980e75ee82 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -1384,8 +1384,8 @@ void GetSettings() if (SConfig::GetInstance().bWii) { u64 title_id = SConfig::GetInstance().GetTitleID(); - s_bClearSave = - !File::Exists(Common::GetTitleDataPath(title_id, Common::FROM_SESSION_ROOT) + "banner.bin"); + s_bClearSave = !File::Exists(Common::GetTitleDataPath(title_id, Common::FROM_SESSION_ROOT) + + "/banner.bin"); } else { diff --git a/Source/Core/Core/WiiRoot.cpp b/Source/Core/Core/WiiRoot.cpp index a705801fc1..8058ab2685 100644 --- a/Source/Core/Core/WiiRoot.cpp +++ b/Source/Core/Core/WiiRoot.cpp @@ -36,7 +36,7 @@ static void InitializeDeterministicWiiSaves() else { // TODO: Check for the actual save data - Movie::SetClearSave(!File::Exists(user_save_path + "banner.bin")); + Movie::SetClearSave(!File::Exists(user_save_path + "/banner.bin")); } } @@ -44,7 +44,7 @@ static void InitializeDeterministicWiiSaves() (Movie::IsMovieActive() && !Movie::IsStartingFromClearSave())) { // Copy the current user's save to the Blank NAND - if (File::Exists(user_save_path + "banner.bin")) + if (File::Exists(user_save_path + "/banner.bin")) { File::CopyDir(user_save_path, save_path); } @@ -86,10 +86,10 @@ void ShutdownWiiRoot() std::string user_backup_path = File::GetUserPath(D_BACKUP_IDX) + StringFromFormat("%08x/%08x/", static_cast(title_id >> 32), static_cast(title_id)); - if (File::Exists(save_path + "banner.bin") && SConfig::GetInstance().bEnableMemcardSdWriting) + if (File::Exists(save_path + "/banner.bin") && SConfig::GetInstance().bEnableMemcardSdWriting) { // Backup the existing save just in case it's still needed. - if (File::Exists(user_save_path + "banner.bin")) + if (File::Exists(user_save_path + "/banner.bin")) { if (File::Exists(user_backup_path)) File::DeleteDirRecursively(user_backup_path); diff --git a/Source/Core/DiscIO/WiiSaveBanner.cpp b/Source/Core/DiscIO/WiiSaveBanner.cpp index a248151e44..444cb0590d 100644 --- a/Source/Core/DiscIO/WiiSaveBanner.cpp +++ b/Source/Core/DiscIO/WiiSaveBanner.cpp @@ -25,7 +25,8 @@ constexpr unsigned int ICON_HEIGHT = 48; constexpr unsigned int ICON_SIZE = ICON_WIDTH * ICON_HEIGHT * 2; WiiSaveBanner::WiiSaveBanner(u64 title_id) - : WiiSaveBanner(Common::GetTitleDataPath(title_id, Common::FROM_CONFIGURED_ROOT) + "banner.bin") + : WiiSaveBanner(Common::GetTitleDataPath(title_id, Common::FROM_CONFIGURED_ROOT) + + "/banner.bin") { }