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.
This commit is contained in:
Léo Lam 2018-03-11 12:05:12 +01:00
parent 3744a6d3f5
commit 0856d4a68a
6 changed files with 44 additions and 28 deletions

View File

@ -14,6 +14,7 @@
#include "Common/FileUtil.h" #include "Common/FileUtil.h"
#include "Common/Logging/Log.h" #include "Common/Logging/Log.h"
#include "Common/Swap.h" #include "Common/Swap.h"
#include "Core/IOS/FS/FileSystem.h"
constexpr size_t SYSCONF_SIZE = 0x4000; constexpr size_t SYSCONF_SIZE = 0x4000;
@ -35,9 +36,8 @@ static size_t GetNonArrayEntrySize(SysConf::Entry::Type type)
return 0; return 0;
} }
} }
SysConf::SysConf(const Common::FromWhichRoot root_type) SysConf::SysConf(std::shared_ptr<IOS::HLE::FS::FileSystem> fs) : m_fs{fs}
{ {
m_file_name = Common::RootUserPath(root_type) + DIR_SEP WII_SYSCONF_DIR DIR_SEP WII_SYSCONF;
Load(); Load();
} }
@ -55,39 +55,40 @@ void SysConf::Load()
{ {
Clear(); 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."); WARN_LOG(CORE, "No valid SYSCONF detected. Creating a new one.");
InsertDefaultEntries(); 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, IOS::HLE::FS::SeekMode::Set);
file.Seek(4, SEEK_SET);
u16 number_of_entries; 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); number_of_entries = Common::swap16(number_of_entries);
std::vector<u16> offsets(number_of_entries); std::vector<u16> offsets(number_of_entries);
for (u16& offset : offsets) for (u16& offset : offsets)
{ {
file.ReadBytes(&offset, sizeof(offset)); file.Read(&offset, 1);
offset = Common::swap16(offset); offset = Common::swap16(offset);
} }
for (const u16 offset : offsets) for (const u16 offset : offsets)
{ {
file.Seek(offset, SEEK_SET); file.Seek(offset, IOS::HLE::FS::SeekMode::Set);
// Metadata // Metadata
u8 description = 0; u8 description = 0;
file.ReadBytes(&description, sizeof(description)); file.Read(&description, 1);
const Entry::Type type = static_cast<Entry::Type>((description & 0xe0) >> 5); const Entry::Type type = static_cast<Entry::Type>((description & 0xe0) >> 5);
const u8 name_length = (description & 0x1f) + 1; const u8 name_length = (description & 0x1f) + 1;
std::string name(name_length, '\0'); std::string name(name_length, '\0');
file.ReadBytes(&name[0], name.size()); file.Read(&name[0], name.size());
// Data // Data
std::vector<u8> data; std::vector<u8> data;
@ -96,7 +97,7 @@ bool SysConf::LoadFromFile(const std::string& file_name)
case Entry::Type::BigArray: case Entry::Type::BigArray:
{ {
u16 data_length = 0; u16 data_length = 0;
file.ReadBytes(&data_length, sizeof(data_length)); file.Read(&data_length, 1);
// The stored u16 is length - 1, not length. // The stored u16 is length - 1, not length.
data.resize(Common::swap16(data_length) + 1); data.resize(Common::swap16(data_length) + 1);
break; break;
@ -104,7 +105,7 @@ bool SysConf::LoadFromFile(const std::string& file_name)
case Entry::Type::SmallArray: case Entry::Type::SmallArray:
{ {
u8 data_length = 0; u8 data_length = 0;
file.ReadBytes(&data_length, sizeof(data_length)); file.Read(&data_length, 1);
data.resize(data_length + 1); data.resize(data_length + 1);
break; break;
} }
@ -121,7 +122,7 @@ bool SysConf::LoadFromFile(const std::string& file_name)
return false; return false;
} }
file.ReadBytes(data.data(), data.size()); file.Read(data.data(), data.size());
AddEntry({type, name, std::move(data)}); AddEntry({type, name, std::move(data)});
} }
return true; return true;
@ -194,14 +195,19 @@ bool SysConf::Save() const
std::copy(footer.cbegin(), footer.cend(), buffer.end() - footer.size()); std::copy(footer.cbegin(), footer.cend(), buffer.end() - footer.size());
// Write the new data. // Write the new data.
const std::string temp_file = m_file_name + ".tmp"; const std::string temp_file = "/tmp/SYSCONF";
File::CreateFullPath(temp_file); 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"); m_fs->CreateFile(SYSMENU_UID, SYSMENU_GID, temp_file, 0, rw_mode, rw_mode, rw_mode);
if (!file.WriteBytes(buffer.data(), buffer.size())) 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 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_) SysConf::Entry::Entry(Type type_, const std::string& name_) : type(type_), name(name_)

View File

@ -7,6 +7,7 @@
#pragma once #pragma once
#include <cstring> #include <cstring>
#include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
@ -14,10 +15,16 @@
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
#include "Common/NandPaths.h" #include "Common/NandPaths.h"
namespace IOS::HLE::FS
{
class FileHandle;
class FileSystem;
}
class SysConf final class SysConf final
{ {
public: public:
explicit SysConf(Common::FromWhichRoot root_type); explicit SysConf(std::shared_ptr<IOS::HLE::FS::FileSystem> fs);
~SysConf(); ~SysConf();
void Clear(); void Clear();
@ -85,8 +92,8 @@ public:
private: private:
void InsertDefaultEntries(); void InsertDefaultEntries();
bool LoadFromFile(const std::string& file_name); bool LoadFromFile(const IOS::HLE::FS::FileHandle& file);
std::string m_file_name;
std::vector<Entry> m_entries; std::vector<Entry> m_entries;
std::shared_ptr<IOS::HLE::FS::FileSystem> m_fs;
}; };

View File

@ -22,6 +22,7 @@
#include "Core/Config/SYSCONFSettings.h" #include "Core/Config/SYSCONFSettings.h"
#include "Core/ConfigLoaders/IsSettingSaveable.h" #include "Core/ConfigLoaders/IsSettingSaveable.h"
#include "Core/Core.h" #include "Core/Core.h"
#include "Core/IOS/IOS.h"
#include "Core/IOS/USB/Bluetooth/BTBase.h" #include "Core/IOS/USB/Bluetooth/BTBase.h"
namespace ConfigLoaders namespace ConfigLoaders
@ -31,7 +32,8 @@ void SaveToSYSCONF(Config::LayerType layer)
if (Core::IsRunning()) if (Core::IsRunning())
return; return;
SysConf sysconf{Common::FromWhichRoot::FROM_CONFIGURED_ROOT}; IOS::HLE::Kernel ios;
SysConf sysconf{ios.GetFS()};
for (const Config::SYSCONFSetting& setting : Config::SYSCONF_SETTINGS) for (const Config::SYSCONFSetting& setting : Config::SYSCONF_SETTINGS)
{ {
@ -154,7 +156,8 @@ private:
if (Core::IsRunning()) if (Core::IsRunning())
return; return;
SysConf sysconf{Common::FromWhichRoot::FROM_CONFIGURED_ROOT}; IOS::HLE::Kernel ios;
SysConf sysconf{ios.GetFS()};
for (const Config::SYSCONFSetting& setting : Config::SYSCONF_SETTINGS) for (const Config::SYSCONFSetting& setting : Config::SYSCONF_SETTINGS)
{ {
std::visit( std::visit(

View File

@ -42,8 +42,7 @@ namespace Device
BluetoothEmu::BluetoothEmu(Kernel& ios, const std::string& device_name) BluetoothEmu::BluetoothEmu(Kernel& ios, const std::string& device_name)
: BluetoothBase(ios, device_name) : BluetoothBase(ios, device_name)
{ {
SysConf sysconf{Core::WantsDeterminism() ? Common::FromWhichRoot::FROM_SESSION_ROOT : SysConf sysconf{ios.GetFS()};
Common::FromWhichRoot::FROM_CONFIGURED_ROOT};
if (!Core::WantsDeterminism()) if (!Core::WantsDeterminism())
BackUpBTInfoSection(&sysconf); BackUpBTInfoSection(&sysconf);

View File

@ -13,6 +13,7 @@
#include "Common/StringUtil.h" #include "Common/StringUtil.h"
#include "Common/SysConf.h" #include "Common/SysConf.h"
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/IOS/IOS.h"
#include "Core/Movie.h" #include "Core/Movie.h"
#include "Core/NetPlayClient.h" #include "Core/NetPlayClient.h"
@ -64,7 +65,7 @@ void InitializeWiiRoot(bool use_temporary)
WARN_LOG(IOS_FS, "Using temporary directory %s for minimal Wii FS", s_temp_wii_root.c_str()); WARN_LOG(IOS_FS, "Using temporary directory %s for minimal Wii FS", s_temp_wii_root.c_str());
File::SetUserPath(D_SESSION_WIIROOT_IDX, s_temp_wii_root); File::SetUserPath(D_SESSION_WIIROOT_IDX, s_temp_wii_root);
// Generate a SYSCONF with default settings for the temporary Wii NAND. // Generate a SYSCONF with default settings for the temporary Wii NAND.
SysConf sysconf{Common::FromWhichRoot::FROM_SESSION_ROOT}; SysConf sysconf{IOS::HLE::Kernel{}.GetFS()};
sysconf.Save(); sysconf.Save();
InitializeDeterministicWiiSaves(); InitializeDeterministicWiiSaves();

View File

@ -136,7 +136,7 @@ bool InstallWAD(IOS::HLE::Kernel& ios, const DiscIO::WiiWAD& wad, InstallType in
} }
// Delete a previous temporary title, if it exists. // Delete a previous temporary title, if it exists.
SysConf sysconf{Common::FROM_SESSION_ROOT}; SysConf sysconf{ios.GetFS()};
SysConf::Entry* tid_entry = sysconf.GetOrAddEntry("IPL.TID", SysConf::Entry::Type::LongLong); SysConf::Entry* tid_entry = sysconf.GetOrAddEntry("IPL.TID", SysConf::Entry::Type::LongLong);
if (const u64 previous_temporary_title_id = Common::swap64(tid_entry->GetData<u64>(0))) if (const u64 previous_temporary_title_id = Common::swap64(tid_entry->GetData<u64>(0)))
ios.GetES()->DeleteTitleContent(previous_temporary_title_id); ios.GetES()->DeleteTitleContent(previous_temporary_title_id);