From 0856d4a68a61b274353b1b46d7eb8f725402bf5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 11 Mar 2018 12:05:12 +0100 Subject: SysConf: Migrate to new filesystem interface It was discovered that some titles rely on filesystem metadata to work properly. Currently, in master they either simply won't find their save files (for example Bolt) or will complain about the Wii system memory being corrupted (on first use or every time depending on the title). In order to even be able to keep track of file metadata, we first need to eliminate all direct accesses to the NAND and make all kinds of operations go through the filesystem code added in PR 6421. This commit starts the migration process by making SysConf use the new FS interface. --- Source/Core/Common/SysConf.cpp | 44 ++++++++++++++++++++++++------------------ 1 file changed, 25 insertions(+), 19 deletions(-) (limited to 'Source/Core/Common/SysConf.cpp') diff --git a/Source/Core/Common/SysConf.cpp b/Source/Core/Common/SysConf.cpp index 22e902d042..36ab4fa325 100644 --- a/Source/Core/Common/SysConf.cpp +++ b/Source/Core/Common/SysConf.cpp @@ -14,6 +14,7 @@ #include "Common/FileUtil.h" #include "Common/Logging/Log.h" #include "Common/Swap.h" +#include "Core/IOS/FS/FileSystem.h" constexpr size_t SYSCONF_SIZE = 0x4000; @@ -35,9 +36,8 @@ static size_t GetNonArrayEntrySize(SysConf::Entry::Type type) return 0; } } -SysConf::SysConf(const Common::FromWhichRoot root_type) +SysConf::SysConf(std::shared_ptr fs) : m_fs{fs} { - m_file_name = Common::RootUserPath(root_type) + DIR_SEP WII_SYSCONF_DIR DIR_SEP WII_SYSCONF; Load(); } @@ -55,39 +55,40 @@ void SysConf::Load() { Clear(); - if (File::GetSize(m_file_name) != SYSCONF_SIZE || !LoadFromFile(m_file_name)) + const auto file = m_fs->OpenFile(IOS::HLE::FS::Uid{0}, IOS::HLE::FS::Gid{0}, + "/shared2/sys/SYSCONF", IOS::HLE::FS::Mode::Read); + if (!file || file->GetStatus()->size != SYSCONF_SIZE || !LoadFromFile(*file)) { WARN_LOG(CORE, "No valid SYSCONF detected. Creating a new one."); InsertDefaultEntries(); } } -bool SysConf::LoadFromFile(const std::string& file_name) +bool SysConf::LoadFromFile(const IOS::HLE::FS::FileHandle& file) { - File::IOFile file(file_name, "rb"); - file.Seek(4, SEEK_SET); + file.Seek(4, IOS::HLE::FS::SeekMode::Set); u16 number_of_entries; - file.ReadBytes(&number_of_entries, sizeof(number_of_entries)); + file.Read(&number_of_entries, 1); number_of_entries = Common::swap16(number_of_entries); std::vector offsets(number_of_entries); for (u16& offset : offsets) { - file.ReadBytes(&offset, sizeof(offset)); + file.Read(&offset, 1); offset = Common::swap16(offset); } for (const u16 offset : offsets) { - file.Seek(offset, SEEK_SET); + file.Seek(offset, IOS::HLE::FS::SeekMode::Set); // Metadata u8 description = 0; - file.ReadBytes(&description, sizeof(description)); + file.Read(&description, 1); const Entry::Type type = static_cast((description & 0xe0) >> 5); const u8 name_length = (description & 0x1f) + 1; std::string name(name_length, '\0'); - file.ReadBytes(&name[0], name.size()); + file.Read(&name[0], name.size()); // Data std::vector data; @@ -96,7 +97,7 @@ bool SysConf::LoadFromFile(const std::string& file_name) case Entry::Type::BigArray: { u16 data_length = 0; - file.ReadBytes(&data_length, sizeof(data_length)); + file.Read(&data_length, 1); // The stored u16 is length - 1, not length. data.resize(Common::swap16(data_length) + 1); break; @@ -104,7 +105,7 @@ bool SysConf::LoadFromFile(const std::string& file_name) case Entry::Type::SmallArray: { u8 data_length = 0; - file.ReadBytes(&data_length, sizeof(data_length)); + file.Read(&data_length, 1); data.resize(data_length + 1); break; } @@ -121,7 +122,7 @@ bool SysConf::LoadFromFile(const std::string& file_name) return false; } - file.ReadBytes(data.data(), data.size()); + file.Read(data.data(), data.size()); AddEntry({type, name, std::move(data)}); } return true; @@ -194,14 +195,19 @@ bool SysConf::Save() const std::copy(footer.cbegin(), footer.cend(), buffer.end() - footer.size()); // Write the new data. - const std::string temp_file = m_file_name + ".tmp"; - File::CreateFullPath(temp_file); + const std::string temp_file = "/tmp/SYSCONF"; + constexpr u32 SYSMENU_UID = 0x1000; + constexpr u16 SYSMENU_GID = 1; + constexpr auto rw_mode = IOS::HLE::FS::Mode::ReadWrite; { - File::IOFile file(temp_file, "wb"); - if (!file.WriteBytes(buffer.data(), buffer.size())) + m_fs->CreateFile(SYSMENU_UID, SYSMENU_GID, temp_file, 0, rw_mode, rw_mode, rw_mode); + auto file = m_fs->OpenFile(SYSMENU_UID, SYSMENU_GID, temp_file, IOS::HLE::FS::Mode::Write); + if (!file || !file->Write(buffer.data(), buffer.size())) return false; } - return File::RenameSync(temp_file, m_file_name); + m_fs->CreateDirectory(SYSMENU_UID, SYSMENU_GID, "/shared2/sys", 0, rw_mode, rw_mode, rw_mode); + const auto result = m_fs->Rename(SYSMENU_UID, SYSMENU_GID, temp_file, "/shared2/sys/SYSCONF"); + return result == IOS::HLE::FS::ResultCode::Success; } SysConf::Entry::Entry(Type type_, const std::string& name_) : type(type_), name(name_) -- cgit v1.2.3 From a287bbc3bda6b07ae936494a3d01a2e789a906eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Sun, 11 Mar 2018 11:43:54 +0100 Subject: Move SysConf to Core It's not common code that could be reused for, say, Citra; it's absolutely specific to Wii emulation and only used by the Dolphin core, so let's move it there. Another reason for doing this is to avoid having Common depend on Core. --- Source/Core/Common/SysConf.cpp | 309 ----------------------------------------- 1 file changed, 309 deletions(-) delete mode 100644 Source/Core/Common/SysConf.cpp (limited to 'Source/Core/Common/SysConf.cpp') diff --git a/Source/Core/Common/SysConf.cpp b/Source/Core/Common/SysConf.cpp deleted file mode 100644 index 36ab4fa325..0000000000 --- a/Source/Core/Common/SysConf.cpp +++ /dev/null @@ -1,309 +0,0 @@ -// Copyright 2009 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include "Common/SysConf.h" - -#include -#include -#include - -#include "Common/CommonPaths.h" -#include "Common/CommonTypes.h" -#include "Common/File.h" -#include "Common/FileUtil.h" -#include "Common/Logging/Log.h" -#include "Common/Swap.h" -#include "Core/IOS/FS/FileSystem.h" - -constexpr size_t SYSCONF_SIZE = 0x4000; - -static size_t GetNonArrayEntrySize(SysConf::Entry::Type type) -{ - switch (type) - { - case SysConf::Entry::Type::Byte: - case SysConf::Entry::Type::ByteBool: - return 1; - case SysConf::Entry::Type::Short: - return 2; - case SysConf::Entry::Type::Long: - return 4; - case SysConf::Entry::Type::LongLong: - return 8; - default: - ASSERT(false); - return 0; - } -} -SysConf::SysConf(std::shared_ptr fs) : m_fs{fs} -{ - Load(); -} - -SysConf::~SysConf() -{ - Save(); -} - -void SysConf::Clear() -{ - m_entries.clear(); -} - -void SysConf::Load() -{ - Clear(); - - const auto file = m_fs->OpenFile(IOS::HLE::FS::Uid{0}, IOS::HLE::FS::Gid{0}, - "/shared2/sys/SYSCONF", IOS::HLE::FS::Mode::Read); - if (!file || file->GetStatus()->size != SYSCONF_SIZE || !LoadFromFile(*file)) - { - WARN_LOG(CORE, "No valid SYSCONF detected. Creating a new one."); - InsertDefaultEntries(); - } -} - -bool SysConf::LoadFromFile(const IOS::HLE::FS::FileHandle& file) -{ - file.Seek(4, IOS::HLE::FS::SeekMode::Set); - u16 number_of_entries; - file.Read(&number_of_entries, 1); - number_of_entries = Common::swap16(number_of_entries); - - std::vector offsets(number_of_entries); - for (u16& offset : offsets) - { - file.Read(&offset, 1); - offset = Common::swap16(offset); - } - - for (const u16 offset : offsets) - { - file.Seek(offset, IOS::HLE::FS::SeekMode::Set); - - // Metadata - u8 description = 0; - file.Read(&description, 1); - const Entry::Type type = static_cast((description & 0xe0) >> 5); - const u8 name_length = (description & 0x1f) + 1; - std::string name(name_length, '\0'); - file.Read(&name[0], name.size()); - - // Data - std::vector data; - switch (type) - { - case Entry::Type::BigArray: - { - u16 data_length = 0; - file.Read(&data_length, 1); - // The stored u16 is length - 1, not length. - data.resize(Common::swap16(data_length) + 1); - break; - } - case Entry::Type::SmallArray: - { - u8 data_length = 0; - file.Read(&data_length, 1); - data.resize(data_length + 1); - break; - } - case Entry::Type::Byte: - case Entry::Type::ByteBool: - case Entry::Type::Short: - case Entry::Type::Long: - case Entry::Type::LongLong: - data.resize(GetNonArrayEntrySize(type)); - break; - default: - ERROR_LOG(CORE, "Unknown entry type %d in SYSCONF for %s (offset %u)", static_cast(type), - name.c_str(), offset); - return false; - } - - file.Read(data.data(), data.size()); - AddEntry({type, name, std::move(data)}); - } - return true; -} - -template -static void AppendToBuffer(std::vector* vector, T value) -{ - const T swapped_value = Common::FromBigEndian(value); - vector->resize(vector->size() + sizeof(T)); - std::memcpy(&*(vector->end() - sizeof(T)), &swapped_value, sizeof(T)); -} - -bool SysConf::Save() const -{ - std::vector buffer; - buffer.reserve(SYSCONF_SIZE); - - // Header - constexpr std::array version{{'S', 'C', 'v', '0'}}; - buffer.insert(buffer.end(), version.cbegin(), version.cend()); - AppendToBuffer(&buffer, static_cast(m_entries.size())); - - const size_t entries_begin_offset = buffer.size() + sizeof(u16) * (m_entries.size() + 1); - std::vector entries; - for (const auto& item : m_entries) - { - // Offset - AppendToBuffer(&buffer, static_cast(entries_begin_offset + entries.size())); - - // Entry metadata (type and name) - entries.insert(entries.end(), - (static_cast(item.type) << 5) | (static_cast(item.name.size()) - 1)); - entries.insert(entries.end(), item.name.cbegin(), item.name.cend()); - - // Entry data - switch (item.type) - { - case Entry::Type::BigArray: - { - const u16 data_size = static_cast(item.bytes.size()); - // length - 1 is stored, not length. - AppendToBuffer(&entries, data_size - 1); - entries.insert(entries.end(), item.bytes.cbegin(), item.bytes.cbegin() + data_size); - break; - } - - case Entry::Type::SmallArray: - { - const u8 data_size = static_cast(item.bytes.size()); - AppendToBuffer(&entries, data_size - 1); - entries.insert(entries.end(), item.bytes.cbegin(), item.bytes.cbegin() + data_size); - break; - } - - default: - entries.insert(entries.end(), item.bytes.cbegin(), item.bytes.cend()); - break; - } - } - // Offset for the dummy past-the-end entry. - AppendToBuffer(&buffer, static_cast(entries_begin_offset + entries.size())); - - // Main data. - buffer.insert(buffer.end(), entries.cbegin(), entries.cend()); - - // Make sure the buffer size is 0x4000 bytes now and write the footer. - buffer.resize(SYSCONF_SIZE); - constexpr std::array footer = {{'S', 'C', 'e', 'd'}}; - std::copy(footer.cbegin(), footer.cend(), buffer.end() - footer.size()); - - // Write the new data. - const std::string temp_file = "/tmp/SYSCONF"; - constexpr u32 SYSMENU_UID = 0x1000; - constexpr u16 SYSMENU_GID = 1; - constexpr auto rw_mode = IOS::HLE::FS::Mode::ReadWrite; - { - m_fs->CreateFile(SYSMENU_UID, SYSMENU_GID, temp_file, 0, rw_mode, rw_mode, rw_mode); - auto file = m_fs->OpenFile(SYSMENU_UID, SYSMENU_GID, temp_file, IOS::HLE::FS::Mode::Write); - if (!file || !file->Write(buffer.data(), buffer.size())) - return false; - } - m_fs->CreateDirectory(SYSMENU_UID, SYSMENU_GID, "/shared2/sys", 0, rw_mode, rw_mode, rw_mode); - const auto result = m_fs->Rename(SYSMENU_UID, SYSMENU_GID, temp_file, "/shared2/sys/SYSCONF"); - return result == IOS::HLE::FS::ResultCode::Success; -} - -SysConf::Entry::Entry(Type type_, const std::string& name_) : type(type_), name(name_) -{ - if (type != Type::SmallArray && type != Type::BigArray) - bytes.resize(GetNonArrayEntrySize(type)); -} - -SysConf::Entry::Entry(Type type_, const std::string& name_, const std::vector& bytes_) - : type(type_), name(name_), bytes(bytes_) -{ -} - -SysConf::Entry::Entry(Type type_, const std::string& name_, std::vector&& bytes_) - : type(type_), name(name_), bytes(std::move(bytes_)) -{ -} - -void SysConf::AddEntry(Entry&& entry) -{ - m_entries.emplace_back(std::move(entry)); -} - -SysConf::Entry* SysConf::GetEntry(const std::string& key) -{ - const auto iterator = std::find_if(m_entries.begin(), m_entries.end(), - [&key](const auto& entry) { return entry.name == key; }); - return iterator != m_entries.end() ? &*iterator : nullptr; -} - -const SysConf::Entry* SysConf::GetEntry(const std::string& key) const -{ - const auto iterator = std::find_if(m_entries.begin(), m_entries.end(), - [&key](const auto& entry) { return entry.name == key; }); - return iterator != m_entries.end() ? &*iterator : nullptr; -} - -SysConf::Entry* SysConf::GetOrAddEntry(const std::string& key, Entry::Type type) -{ - if (Entry* entry = GetEntry(key)) - return entry; - AddEntry({type, key}); - return GetEntry(key); -} - -void SysConf::RemoveEntry(const std::string& key) -{ - m_entries.erase(std::remove_if(m_entries.begin(), m_entries.end(), - [&key](const auto& entry) { return entry.name == key; }), - m_entries.end()); -} - -void SysConf::InsertDefaultEntries() -{ - AddEntry({Entry::Type::BigArray, "BT.DINF", std::vector(0x460 + 1)}); - AddEntry({Entry::Type::BigArray, "BT.CDIF", std::vector(0x204 + 1)}); - AddEntry({Entry::Type::Long, "BT.SENS", {0, 0, 0, 3}}); - AddEntry({Entry::Type::Byte, "BT.BAR", {1}}); - AddEntry({Entry::Type::Byte, "BT.SPKV", {0x58}}); - AddEntry({Entry::Type::Byte, "BT.MOT", {1}}); - - std::vector console_nick = {0, 'd', 0, 'o', 0, 'l', 0, 'p', 0, 'h', 0, 'i', 0, 'n'}; - // 22 bytes: 2 bytes per character (10 characters maximum), - // 1 for a null terminating character, 1 for the string length - console_nick.resize(22); - console_nick[21] = static_cast(strlen("dolphin")); - AddEntry({Entry::Type::SmallArray, "IPL.NIK", std::move(console_nick)}); - - AddEntry({Entry::Type::Byte, "IPL.LNG", {1}}); - std::vector ipl_sadr(0x1007 + 1); - ipl_sadr[0] = 0x6c; - AddEntry({Entry::Type::BigArray, "IPL.SADR", std::move(ipl_sadr)}); - - std::vector ipl_pc(0x49 + 1); - ipl_pc[1] = 0x04; - ipl_pc[2] = 0x14; - AddEntry({Entry::Type::SmallArray, "IPL.PC", std::move(ipl_pc)}); - - AddEntry({Entry::Type::Long, "IPL.CB", {0x0f, 0x11, 0x14, 0xa6}}); - AddEntry({Entry::Type::Byte, "IPL.AR", {1}}); - AddEntry({Entry::Type::Byte, "IPL.SSV", {1}}); - - AddEntry({Entry::Type::ByteBool, "IPL.CD", {0}}); - AddEntry({Entry::Type::ByteBool, "IPL.CD2", {0}}); - AddEntry({Entry::Type::ByteBool, "IPL.EULA", {1}}); - AddEntry({Entry::Type::Byte, "IPL.UPT", {2}}); - AddEntry({Entry::Type::Byte, "IPL.PGS", {0}}); - AddEntry({Entry::Type::Byte, "IPL.E60", {1}}); - AddEntry({Entry::Type::Byte, "IPL.DH", {0}}); - AddEntry({Entry::Type::Long, "IPL.INC", {0, 0, 0, 8}}); - AddEntry({Entry::Type::Long, "IPL.FRC", {0, 0, 0, 0x28}}); - AddEntry({Entry::Type::SmallArray, "IPL.IDL", {0, 1}}); - - AddEntry({Entry::Type::Long, "NET.WCFG", {0, 0, 0, 1}}); - AddEntry({Entry::Type::Long, "NET.CTPC", std::vector(4)}); - AddEntry({Entry::Type::Byte, "WWW.RST", {0}}); - - AddEntry({Entry::Type::ByteBool, "MPLS.MOVIE", {1}}); -} -- cgit v1.2.3