From 09d2afa91f7781c84c25e989d916957200e63eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Wed, 9 May 2018 20:40:56 +0200 Subject: [PATCH 1/4] SettingsHandler: Migrate to new filesystem interface Change SettingsHandler to take a buffer instead of assuming that the setting file to read is always on the host filesystem for more flexibility and make it possible to use the new filesystem interface. --- Source/Core/Common/SettingsHandler.cpp | 35 +++++++------------ Source/Core/Common/SettingsHandler.h | 8 ++--- Source/Core/Core/Boot/Boot_BS2Emu.cpp | 30 +++++++++++----- .../Core/Core/IOS/Network/KD/NetKDRequest.cpp | 25 +++++++------ 4 files changed, 52 insertions(+), 46 deletions(-) diff --git a/Source/Core/Common/SettingsHandler.cpp b/Source/Core/Common/SettingsHandler.cpp index 8a0240939b..7663959a20 100644 --- a/Source/Core/Common/SettingsHandler.cpp +++ b/Source/Core/Common/SettingsHandler.cpp @@ -19,8 +19,6 @@ #endif #include "Common/CommonTypes.h" -#include "Common/File.h" -#include "Common/FileUtil.h" #include "Common/SettingsHandler.h" #include "Common/Timer.h" @@ -29,30 +27,21 @@ SettingsHandler::SettingsHandler() Reset(); } -bool SettingsHandler::Open(const std::string& settings_file_path) +SettingsHandler::SettingsHandler(Buffer&& buffer) +{ + SetBytes(std::move(buffer)); +} + +const SettingsHandler::Buffer& SettingsHandler::GetBytes() const +{ + return m_buffer; +} + +void SettingsHandler::SetBytes(SettingsHandler::Buffer&& buffer) { Reset(); - - File::IOFile file{settings_file_path, "rb"}; - if (!file.ReadBytes(m_buffer.data(), m_buffer.size())) - return false; - + m_buffer = std::move(buffer); Decrypt(); - return true; -} - -bool SettingsHandler::Save(const std::string& destination_file_path) const -{ - if (!File::CreateFullPath(destination_file_path)) - return false; - - File::IOFile file{destination_file_path, "wb"}; - return file.WriteBytes(m_buffer.data(), m_buffer.size()); -} - -const u8* SettingsHandler::GetData() const -{ - return m_buffer.data(); } const std::string SettingsHandler::GetValue(const std::string& key) diff --git a/Source/Core/Common/SettingsHandler.h b/Source/Core/Common/SettingsHandler.h index 54ef8f34cd..d22da844fd 100644 --- a/Source/Core/Common/SettingsHandler.h +++ b/Source/Core/Common/SettingsHandler.h @@ -21,14 +21,14 @@ public: INITIAL_SEED = 0x73B5DBFA }; + using Buffer = std::array; SettingsHandler(); - - bool Open(const std::string& settings_file_path); - bool Save(const std::string& destination_file_path) const; + explicit SettingsHandler(Buffer&& buffer); void AddSetting(const std::string& key, const std::string& value); - const u8* GetData() const; + const Buffer& GetBytes() const; + void SetBytes(Buffer&& buffer); const std::string GetValue(const std::string& key); void Decrypt(); diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index baa451dc96..9aa077a9c3 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -25,7 +25,9 @@ #include "Core/HW/Memmap.h" #include "Core/IOS/ES/ES.h" #include "Core/IOS/ES/Formats.h" +#include "Core/IOS/FS/FileSystem.h" #include "Core/IOS/IOS.h" +#include "Core/IOS/Uids.h" #include "Core/PowerPC/PowerPC.h" #include "DiscIO/Enums.h" @@ -225,15 +227,22 @@ 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); - if (File::Exists(settings_file_path) && gen.Open(settings_file_path)) - { - serno = gen.GetValue("SERNO"); - gen.Reset(); + const std::string settings_file_path(Common::GetTitleDataPath(Titles::SYSTEM_MENU) + + "/" WII_SETTING); - File::Delete(settings_file_path); + const auto fs = IOS::HLE::GetIOS()->GetFS(); + { + SettingsHandler::Buffer data; + const auto file = fs->OpenFile(IOS::SYSMENU_UID, IOS::SYSMENU_GID, settings_file_path, + IOS::HLE::FS::Mode::Read); + if (file && file->Read(data.data(), data.size())) + { + gen.SetBytes(std::move(data)); + serno = gen.GetValue("SERNO"); + gen.Reset(); + } } + fs->Delete(IOS::SYSMENU_UID, IOS::SYSMENU_GID, settings_file_path); if (serno.empty() || serno == "000000000") { @@ -258,14 +267,17 @@ bool CBoot::SetupWiiMemory() gen.AddSetting("VIDEO", region_setting.video); gen.AddSetting("GAME", region_setting.game); - if (!gen.Save(settings_file_path)) + constexpr IOS::HLE::FS::Mode rw_mode = IOS::HLE::FS::Mode::ReadWrite; + const auto settings_file = fs->CreateAndOpenFile(IOS::SYSMENU_UID, IOS::SYSMENU_GID, + settings_file_path, rw_mode, rw_mode, rw_mode); + if (!settings_file || !settings_file->Write(gen.GetBytes().data(), gen.GetBytes().size())) { PanicAlertT("SetupWiiMemory: Can't create setting.txt file"); return false; } // Write the 256 byte setting.txt to memory. - Memory::CopyToEmu(0x3800, gen.GetData(), SettingsHandler::SETTINGS_SIZE); + Memory::CopyToEmu(0x3800, gen.GetBytes().data(), gen.GetBytes().size()); INFO_LOG(BOOT, "Setup Wii Memory..."); diff --git a/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp b/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp index ce3f202ddc..7baf260102 100644 --- a/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp +++ b/Source/Core/Core/IOS/Network/KD/NetKDRequest.cpp @@ -16,7 +16,9 @@ #include "Core/CommonTitles.h" #include "Core/HW/Memmap.h" +#include "Core/IOS/FS/FileSystem.h" #include "Core/IOS/Network/Socket.h" +#include "Core/IOS/Uids.h" namespace IOS { @@ -82,20 +84,23 @@ IPCCommandResult NetKDRequest::IOCtl(const IOCtlRequest& request) INFO_LOG(IOS_WC24, "NET_KD_REQ: IOCTL_NWC24_REQUEST_GENERATED_USER_ID"); 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); - SettingsHandler gen; + const std::string settings_file_path = + Common::GetTitleDataPath(Titles::SYSTEM_MENU) + "/" WII_SETTING; std::string area, model; - bool got_settings = false; - if (File::Exists(settings_file_path) && gen.Open(settings_file_path)) + const auto fs = m_ios.GetFS(); + if (const auto file = fs->OpenFile(PID_KD, PID_KD, settings_file_path, FS::Mode::Read)) { - area = gen.GetValue("AREA"); - model = gen.GetValue("MODEL"); - got_settings = true; + SettingsHandler::Buffer data; + if (file->Read(data.data(), data.size())) + { + const SettingsHandler gen{std::move(data)}; + area = gen.GetValue("AREA"); + model = gen.GetValue("MODEL"); + } } - if (got_settings) + + if (!area.empty() && !model.empty()) { u8 area_code = GetAreaCode(area); u8 id_ctr = config.IdGen(); From 722d31124ca4a958d658b3c8d2d5dba1cb637ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 10 May 2018 20:34:20 +0200 Subject: [PATCH 2/4] SettingsHandler: Fix const correctness --- Source/Core/Common/SettingsHandler.cpp | 2 +- Source/Core/Common/SettingsHandler.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/Core/Common/SettingsHandler.cpp b/Source/Core/Common/SettingsHandler.cpp index 7663959a20..6ce08f6579 100644 --- a/Source/Core/Common/SettingsHandler.cpp +++ b/Source/Core/Common/SettingsHandler.cpp @@ -44,7 +44,7 @@ void SettingsHandler::SetBytes(SettingsHandler::Buffer&& buffer) Decrypt(); } -const std::string SettingsHandler::GetValue(const std::string& key) +std::string SettingsHandler::GetValue(const std::string& key) const { std::string delim = std::string("\r\n"); std::string toFind = delim + key + "="; diff --git a/Source/Core/Common/SettingsHandler.h b/Source/Core/Common/SettingsHandler.h index d22da844fd..114a2bc0b6 100644 --- a/Source/Core/Common/SettingsHandler.h +++ b/Source/Core/Common/SettingsHandler.h @@ -29,7 +29,7 @@ public: const Buffer& GetBytes() const; void SetBytes(Buffer&& buffer); - const std::string GetValue(const std::string& key); + std::string GetValue(const std::string& key) const; void Decrypt(); void Reset(); From e6c489f1d45e380db73e805e406947a9de677a90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 10 May 2018 22:27:21 +0200 Subject: [PATCH 3/4] ES: Move title dir creation logic into separate function Since we're going to need it in the boot code, move it out to a separate, easily reusable function. This also makes the InitImport logic clearer. --- Source/Core/Core/IOS/ES/ES.h | 2 ++ Source/Core/Core/IOS/ES/NandUtils.cpp | 43 +++++++++++++++++++-------- 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/Source/Core/Core/IOS/ES/ES.h b/Source/Core/Core/IOS/ES/ES.h index 38492d39da..9e31ae83b7 100644 --- a/Source/Core/Core/IOS/ES/ES.h +++ b/Source/Core/Core/IOS/ES/ES.h @@ -139,6 +139,8 @@ public: ReturnCode SetUpStreamKey(u32 uid, const u8* ticket_view, const IOS::ES::TMDReader& tmd, u32* handle); + bool CreateTitleDirectories(u64 title_id, u16 group_id) const; + private: enum { diff --git a/Source/Core/Core/IOS/ES/NandUtils.cpp b/Source/Core/Core/IOS/ES/NandUtils.cpp index afa49c565f..a28fc56125 100644 --- a/Source/Core/Core/IOS/ES/NandUtils.cpp +++ b/Source/Core/Core/IOS/ES/NandUtils.cpp @@ -222,40 +222,56 @@ static bool DeleteDirectoriesIfEmpty(FS::FileSystem* fs, const std::string& path return true; } -bool ES::InitImport(const IOS::ES::TMDReader& tmd) +bool ES::CreateTitleDirectories(u64 title_id, u16 group_id) const { const auto fs = m_ios.GetFS(); - const std::string content_dir = Common::GetTitleContentPath(tmd.GetTitleId()); - const std::string import_content_dir = Common::GetImportTitlePath(tmd.GetTitleId()) + "/content"; + const std::string content_dir = Common::GetTitleContentPath(title_id); const auto result1 = fs->CreateFullPath(PID_KERNEL, PID_KERNEL, content_dir + '/', 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::Read); const auto result2 = fs->SetMetadata(PID_KERNEL, content_dir, PID_KERNEL, PID_KERNEL, 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None); - const auto result3 = fs->CreateFullPath(PID_KERNEL, PID_KERNEL, import_content_dir + '/', 0, - FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None); - if (result1 != FS::ResultCode::Success || result2 != FS::ResultCode::Success || - result3 != FS::ResultCode::Success) + if (result1 != FS::ResultCode::Success || result2 != FS::ResultCode::Success) { - ERROR_LOG(IOS_ES, "InitImport: Failed to create content dir for %016" PRIx64, tmd.GetTitleId()); + ERROR_LOG(IOS_ES, "Failed to create or set metadata on content dir for %016" PRIx64, title_id); return false; } - const std::string data_dir = Common::GetTitleDataPath(tmd.GetTitleId()); + const std::string data_dir = Common::GetTitleDataPath(title_id); const auto data_dir_contents = fs->ReadDirectory(PID_KERNEL, PID_KERNEL, data_dir); if (!data_dir_contents && (data_dir_contents.Error() != FS::ResultCode::NotFound || fs->CreateDirectory(PID_KERNEL, PID_KERNEL, data_dir, 0, FS::Mode::ReadWrite, FS::Mode::None, FS::Mode::None) != FS::ResultCode::Success)) { + ERROR_LOG(IOS_ES, "Failed to create data dir for %016" PRIx64, title_id); return false; } IOS::ES::UIDSys uid_sys{fs}; - const u32 uid = uid_sys.GetOrInsertUIDForTitle(tmd.GetTitleId()); - if (fs->SetMetadata(0, data_dir, uid, tmd.GetGroupId(), 0, FS::Mode::ReadWrite, FS::Mode::None, + const u32 uid = uid_sys.GetOrInsertUIDForTitle(title_id); + if (fs->SetMetadata(0, data_dir, uid, group_id, 0, FS::Mode::ReadWrite, FS::Mode::None, FS::Mode::None) != FS::ResultCode::Success) { + ERROR_LOG(IOS_ES, "Failed to set metadata on data dir for %016" PRIx64, title_id); + return false; + } + + return true; +} + +bool ES::InitImport(const IOS::ES::TMDReader& tmd) +{ + if (!CreateTitleDirectories(tmd.GetTitleId(), tmd.GetGroupId())) + return false; + + const auto fs = m_ios.GetFS(); + const std::string import_content_dir = Common::GetImportTitlePath(tmd.GetTitleId()) + "/content"; + const auto result = fs->CreateFullPath(PID_KERNEL, PID_KERNEL, import_content_dir + '/', 0, + FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None); + if (result != FS::ResultCode::Success) + { + ERROR_LOG(IOS_ES, "InitImport: Failed to create content dir for %016" PRIx64, tmd.GetTitleId()); return false; } @@ -265,8 +281,9 @@ bool ES::InitImport(const IOS::ES::TMDReader& tmd) if (!file_info || !file_info->is_file) return true; - const auto result = fs->Rename(PID_KERNEL, PID_KERNEL, content_dir, import_content_dir); - if (result != FS::ResultCode::Success) + const std::string content_dir = Common::GetTitleContentPath(tmd.GetTitleId()); + const auto rename_result = fs->Rename(PID_KERNEL, PID_KERNEL, content_dir, import_content_dir); + if (rename_result != FS::ResultCode::Success) { ERROR_LOG(IOS_ES, "InitImport: Failed to move content dir for %016" PRIx64, tmd.GetTitleId()); return false; From a977a564342916945e87384288424d5893b3a414 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 10 May 2018 21:55:16 +0200 Subject: [PATCH 4/4] Boot: Migrate to new filesystem interface --- Source/Core/Core/Boot/Boot.cpp | 39 +++++++++++++++------------ Source/Core/Core/Boot/Boot.h | 6 +++++ Source/Core/Core/Boot/Boot_BS2Emu.cpp | 16 ++++++----- 3 files changed, 38 insertions(+), 23 deletions(-) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index a03b9642af..06d234f220 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -39,7 +39,10 @@ #include "Core/HW/Memmap.h" #include "Core/HW/VideoInterface.h" #include "Core/Host.h" +#include "Core/IOS/ES/ES.h" +#include "Core/IOS/FS/FileSystem.h" #include "Core/IOS/IOS.h" +#include "Core/IOS/Uids.h" #include "Core/PatchEngine.h" #include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/PPCSymbolDB.h" @@ -470,26 +473,28 @@ 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; + CreateSystemMenuTitleDirs(); + const std::string file_path = Common::GetTitleDataPath(Titles::SYSTEM_MENU) + "/" WII_STATE; + const auto fs = IOS::HLE::GetIOS()->GetFS(); + constexpr IOS::HLE::FS::Mode rw_mode = IOS::HLE::FS::Mode::ReadWrite; + const auto file = fs->CreateAndOpenFile(IOS::SYSMENU_UID, IOS::SYSMENU_GID, file_path, rw_mode, + rw_mode, rw_mode); + if (!file) + return; - File::IOFile file; - StateFlags state; - if (File::Exists(file_path)) - { - file.Open(file_path, "r+b"); - file.ReadBytes(&state, sizeof(state)); - } - else - { - File::CreateFullPath(file_path); - file.Open(file_path, "a+b"); - memset(&state, 0, sizeof(state)); - } + StateFlags state{}; + if (file->GetStatus()->size == sizeof(StateFlags)) + file->Read(&state, 1); update_function(&state); state.UpdateChecksum(); - file.Seek(0, SEEK_SET); - file.WriteBytes(&state, sizeof(state)); + file->Seek(0, IOS::HLE::FS::SeekMode::Set); + file->Write(&state, 1); +} + +void CreateSystemMenuTitleDirs() +{ + const auto es = IOS::HLE::GetIOS()->GetES(); + es->CreateTitleDirectories(Titles::SYSTEM_MENU, IOS::SYSMENU_GID); } diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index a6b7391b44..b1b5ad3c07 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -151,3 +151,9 @@ struct StateFlags // Reads the state file from the NAND, then calls the passed update function to update the struct, // and finally writes the updated state file to the NAND. void UpdateStateFlags(std::function update_function); + +/// Create title directories for the system menu (if needed). +/// +/// Normally, this is automatically done by ES when the System Menu is installed, +/// but we cannot rely on this because we don't require any system titles to be installed. +void CreateSystemMenuTitleDirs(); diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp index 9aa077a9c3..f406c47e5b 100644 --- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp +++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp @@ -9,8 +9,6 @@ #include "Common/CommonPaths.h" #include "Common/CommonTypes.h" -#include "Common/File.h" -#include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/MsgHandler.h" #include "Common/NandPaths.h" @@ -227,6 +225,7 @@ bool CBoot::SetupWiiMemory() SettingsHandler gen; std::string serno; + CreateSystemMenuTitleDirs(); const std::string settings_file_path(Common::GetTitleDataPath(Titles::SYSTEM_MENU) + "/" WII_SETTING); @@ -338,11 +337,16 @@ bool CBoot::SetupWiiMemory() static void WriteEmptyPlayRecord() { - const std::string file_path = - Common::GetTitleDataPath(Titles::SYSTEM_MENU, Common::FROM_SESSION_ROOT) + "/play_rec.dat"; - File::IOFile playrec_file(file_path, "r+b"); + CreateSystemMenuTitleDirs(); + const std::string file_path = Common::GetTitleDataPath(Titles::SYSTEM_MENU) + "/play_rec.dat"; + const auto fs = IOS::HLE::GetIOS()->GetFS(); + constexpr IOS::HLE::FS::Mode rw_mode = IOS::HLE::FS::Mode::ReadWrite; + const auto playrec_file = fs->CreateAndOpenFile(IOS::SYSMENU_UID, IOS::SYSMENU_GID, file_path, + rw_mode, rw_mode, rw_mode); + if (!playrec_file) + return; std::vector empty_record(0x80); - playrec_file.WriteBytes(empty_record.data(), empty_record.size()); + playrec_file->Write(empty_record.data(), empty_record.size()); } // __________________________________________________________________________________________________