mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-13 07:49:19 +01:00
Core: Implement Wii NAND path redirects for Riivolution savegame patches.
This commit is contained in:
parent
588c31acb6
commit
fe242f79ee
@ -73,6 +73,8 @@
|
|||||||
#include "Core/MemoryWatcher.h"
|
#include "Core/MemoryWatcher.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "DiscIO/RiivolutionPatcher.h"
|
||||||
|
|
||||||
#include "InputCommon/ControlReference/ControlReference.h"
|
#include "InputCommon/ControlReference/ControlReference.h"
|
||||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||||
#include "InputCommon/GCAdapter.h"
|
#include "InputCommon/GCAdapter.h"
|
||||||
@ -603,6 +605,10 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
|
|||||||
else
|
else
|
||||||
cpuThreadFunc = CpuThread;
|
cpuThreadFunc = CpuThread;
|
||||||
|
|
||||||
|
std::optional<DiscIO::Riivolution::SavegameRedirect> savegame_redirect = std::nullopt;
|
||||||
|
if (SConfig::GetInstance().bWii)
|
||||||
|
savegame_redirect = DiscIO::Riivolution::ExtractSavegameRedirect(boot->riivolution_patches);
|
||||||
|
|
||||||
if (!CBoot::BootUp(std::move(boot)))
|
if (!CBoot::BootUp(std::move(boot)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -611,7 +617,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot, WindowSystemInfo wsi
|
|||||||
// with the correct title context since save copying requires title directories to exist.
|
// with the correct title context since save copying requires title directories to exist.
|
||||||
Common::ScopeGuard wiifs_guard{&Core::CleanUpWiiFileSystemContents};
|
Common::ScopeGuard wiifs_guard{&Core::CleanUpWiiFileSystemContents};
|
||||||
if (SConfig::GetInstance().bWii)
|
if (SConfig::GetInstance().bWii)
|
||||||
Core::InitializeWiiFileSystemContents();
|
Core::InitializeWiiFileSystemContents(savegame_redirect);
|
||||||
else
|
else
|
||||||
wiifs_guard.Dismiss();
|
wiifs_guard.Dismiss();
|
||||||
|
|
||||||
|
@ -72,6 +72,15 @@ enum class SeekMode : u32
|
|||||||
|
|
||||||
using FileAttribute = u8;
|
using FileAttribute = u8;
|
||||||
|
|
||||||
|
struct NandRedirect
|
||||||
|
{
|
||||||
|
// A Wii FS path, eg. "/title/00010000/534d4e45/data".
|
||||||
|
std::string source_path;
|
||||||
|
|
||||||
|
// An absolute host filesystem path the above should be redirected to.
|
||||||
|
std::string target_path;
|
||||||
|
};
|
||||||
|
|
||||||
struct Modes
|
struct Modes
|
||||||
{
|
{
|
||||||
Mode owner, group, other;
|
Mode owner, group, other;
|
||||||
@ -239,6 +248,8 @@ public:
|
|||||||
virtual Result<NandStats> GetNandStats() = 0;
|
virtual Result<NandStats> GetNandStats() = 0;
|
||||||
/// Get usage information about a directory (used cluster and inode counts).
|
/// Get usage information about a directory (used cluster and inode counts).
|
||||||
virtual Result<DirectoryStats> GetDirectoryStats(const std::string& path) = 0;
|
virtual Result<DirectoryStats> GetDirectoryStats(const std::string& path) = 0;
|
||||||
|
|
||||||
|
virtual void SetNandRedirects(std::vector<NandRedirect> nand_redirects) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -269,7 +280,8 @@ enum class Location
|
|||||||
Session,
|
Session,
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unique_ptr<FileSystem> MakeFileSystem(Location location = Location::Session);
|
std::unique_ptr<FileSystem> MakeFileSystem(Location location = Location::Session,
|
||||||
|
std::vector<NandRedirect> nand_redirects = {});
|
||||||
|
|
||||||
/// Convert a FS result code to an IOS error code.
|
/// Convert a FS result code to an IOS error code.
|
||||||
IOS::HLE::ReturnCode ConvertResult(ResultCode code);
|
IOS::HLE::ReturnCode ConvertResult(ResultCode code);
|
||||||
|
@ -28,11 +28,12 @@ SplitPathResult SplitPathAndBasename(std::string_view path)
|
|||||||
std::string(path.substr(last_separator + 1))};
|
std::string(path.substr(last_separator + 1))};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<FileSystem> MakeFileSystem(Location location)
|
std::unique_ptr<FileSystem> MakeFileSystem(Location location,
|
||||||
|
std::vector<NandRedirect> nand_redirects)
|
||||||
{
|
{
|
||||||
const std::string nand_root =
|
const std::string nand_root =
|
||||||
File::GetUserPath(location == Location::Session ? D_SESSION_WIIROOT_IDX : D_WIIROOT_IDX);
|
File::GetUserPath(location == Location::Session ? D_SESSION_WIIROOT_IDX : D_WIIROOT_IDX);
|
||||||
return std::make_unique<HostFileSystem>(nand_root);
|
return std::make_unique<HostFileSystem>(nand_root, std::move(nand_redirects));
|
||||||
}
|
}
|
||||||
|
|
||||||
IOS::HLE::ReturnCode ConvertResult(ResultCode code)
|
IOS::HLE::ReturnCode ConvertResult(ResultCode code)
|
||||||
|
@ -22,13 +22,24 @@
|
|||||||
|
|
||||||
namespace IOS::HLE::FS
|
namespace IOS::HLE::FS
|
||||||
{
|
{
|
||||||
std::string HostFileSystem::BuildFilename(const std::string& wii_path) const
|
HostFileSystem::HostFilename HostFileSystem::BuildFilename(const std::string& wii_path) const
|
||||||
{
|
{
|
||||||
|
for (const auto& redirect : m_nand_redirects)
|
||||||
|
{
|
||||||
|
if (StringBeginsWith(wii_path, redirect.source_path) &&
|
||||||
|
(wii_path.size() == redirect.source_path.size() ||
|
||||||
|
wii_path[redirect.source_path.size()] == '/'))
|
||||||
|
{
|
||||||
|
std::string relative_to_redirect = wii_path.substr(redirect.source_path.size());
|
||||||
|
return HostFilename{redirect.target_path + Common::EscapePath(relative_to_redirect), true};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (wii_path.compare(0, 1, "/") == 0)
|
if (wii_path.compare(0, 1, "/") == 0)
|
||||||
return m_root_path + Common::EscapePath(wii_path);
|
return HostFilename{m_root_path + Common::EscapePath(wii_path), false};
|
||||||
|
|
||||||
ASSERT(false);
|
ASSERT(false);
|
||||||
return m_root_path;
|
return HostFilename{m_root_path, false};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get total filesize of contents of a directory (recursive)
|
// Get total filesize of contents of a directory (recursive)
|
||||||
@ -101,7 +112,9 @@ bool HostFileSystem::FstEntry::CheckPermission(Uid caller_uid, Gid caller_gid,
|
|||||||
return (u8(requested_mode) & u8(file_mode)) == u8(requested_mode);
|
return (u8(requested_mode) & u8(file_mode)) == u8(requested_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
HostFileSystem::HostFileSystem(const std::string& root_path) : m_root_path{root_path}
|
HostFileSystem::HostFileSystem(const std::string& root_path,
|
||||||
|
std::vector<NandRedirect> nand_redirects)
|
||||||
|
: m_root_path{root_path}, m_nand_redirects(std::move(nand_redirects))
|
||||||
{
|
{
|
||||||
File::CreateFullPath(m_root_path + "/");
|
File::CreateFullPath(m_root_path + "/");
|
||||||
ResetFst();
|
ResetFst();
|
||||||
@ -197,11 +210,12 @@ HostFileSystem::FstEntry* HostFileSystem::GetFstEntryForPath(const std::string&
|
|||||||
if (!IsValidNonRootPath(path))
|
if (!IsValidNonRootPath(path))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
const File::FileInfo host_file_info{BuildFilename(path)};
|
auto host_file = BuildFilename(path);
|
||||||
|
const File::FileInfo host_file_info{host_file.host_path};
|
||||||
if (!host_file_info.Exists())
|
if (!host_file_info.Exists())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
FstEntry* entry = &m_root_entry;
|
FstEntry* entry = host_file.is_redirect ? &m_redirect_fst : &m_root_entry;
|
||||||
std::string complete_path = "";
|
std::string complete_path = "";
|
||||||
for (const std::string& component : SplitString(std::string(path.substr(1)), '/'))
|
for (const std::string& component : SplitString(std::string(path.substr(1)), '/'))
|
||||||
{
|
{
|
||||||
@ -217,7 +231,8 @@ HostFileSystem::FstEntry* HostFileSystem::GetFstEntryForPath(const std::string&
|
|||||||
// Fall back to dummy data to avoid breaking existing filesystems.
|
// Fall back to dummy data to avoid breaking existing filesystems.
|
||||||
// This code path is also reached when creating a new file or directory;
|
// This code path is also reached when creating a new file or directory;
|
||||||
// proper metadata is filled in later.
|
// proper metadata is filled in later.
|
||||||
INFO_LOG_FMT(IOS_FS, "Creating a default entry for {}", complete_path);
|
INFO_LOG_FMT(IOS_FS, "Creating a default entry for {} ({})", complete_path,
|
||||||
|
host_file.is_redirect ? "redirect" : "NAND");
|
||||||
entry = &entry->children.emplace_back();
|
entry = &entry->children.emplace_back();
|
||||||
entry->name = component;
|
entry->name = component;
|
||||||
entry->data.modes = {Mode::ReadWrite, Mode::ReadWrite, Mode::ReadWrite};
|
entry->data.modes = {Mode::ReadWrite, Mode::ReadWrite, Mode::ReadWrite};
|
||||||
@ -241,7 +256,7 @@ void HostFileSystem::DoState(PointerWrap& p)
|
|||||||
handle.host_file.reset();
|
handle.host_file.reset();
|
||||||
|
|
||||||
// handle /tmp
|
// handle /tmp
|
||||||
std::string Path = BuildFilename("/tmp");
|
std::string Path = BuildFilename("/tmp").host_path;
|
||||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||||
{
|
{
|
||||||
File::DeleteDirRecursively(Path);
|
File::DeleteDirRecursively(Path);
|
||||||
@ -336,7 +351,7 @@ void HostFileSystem::DoState(PointerWrap& p)
|
|||||||
p.Do(handle.wii_path);
|
p.Do(handle.wii_path);
|
||||||
p.Do(handle.file_offset);
|
p.Do(handle.file_offset);
|
||||||
if (handle.opened)
|
if (handle.opened)
|
||||||
handle.host_file = OpenHostFile(BuildFilename(handle.wii_path));
|
handle.host_file = OpenHostFile(BuildFilename(handle.wii_path).host_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,7 +361,7 @@ ResultCode HostFileSystem::Format(Uid uid)
|
|||||||
return ResultCode::AccessDenied;
|
return ResultCode::AccessDenied;
|
||||||
if (m_root_path.empty())
|
if (m_root_path.empty())
|
||||||
return ResultCode::AccessDenied;
|
return ResultCode::AccessDenied;
|
||||||
const std::string root = BuildFilename("/");
|
const std::string root = BuildFilename("/").host_path;
|
||||||
if (!File::DeleteDirRecursively(root) || !File::CreateDir(root))
|
if (!File::DeleteDirRecursively(root) || !File::CreateDir(root))
|
||||||
return ResultCode::UnknownError;
|
return ResultCode::UnknownError;
|
||||||
ResetFst();
|
ResetFst();
|
||||||
@ -366,7 +381,7 @@ ResultCode HostFileSystem::CreateFileOrDirectory(Uid uid, Gid gid, const std::st
|
|||||||
return ResultCode::TooManyPathComponents;
|
return ResultCode::TooManyPathComponents;
|
||||||
|
|
||||||
const auto split_path = SplitPathAndBasename(path);
|
const auto split_path = SplitPathAndBasename(path);
|
||||||
const std::string host_path = BuildFilename(path);
|
const std::string host_path = BuildFilename(path).host_path;
|
||||||
|
|
||||||
FstEntry* parent = GetFstEntryForPath(split_path.parent);
|
FstEntry* parent = GetFstEntryForPath(split_path.parent);
|
||||||
if (!parent)
|
if (!parent)
|
||||||
@ -428,7 +443,7 @@ ResultCode HostFileSystem::Delete(Uid uid, Gid gid, const std::string& path)
|
|||||||
if (!IsValidNonRootPath(path))
|
if (!IsValidNonRootPath(path))
|
||||||
return ResultCode::Invalid;
|
return ResultCode::Invalid;
|
||||||
|
|
||||||
const std::string host_path = BuildFilename(path);
|
const std::string host_path = BuildFilename(path).host_path;
|
||||||
const auto split_path = SplitPathAndBasename(path);
|
const auto split_path = SplitPathAndBasename(path);
|
||||||
|
|
||||||
FstEntry* parent = GetFstEntryForPath(split_path.parent);
|
FstEntry* parent = GetFstEntryForPath(split_path.parent);
|
||||||
@ -491,8 +506,8 @@ ResultCode HostFileSystem::Rename(Uid uid, Gid gid, const std::string& old_path,
|
|||||||
return ResultCode::InUse;
|
return ResultCode::InUse;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string host_old_path = BuildFilename(old_path);
|
const std::string host_old_path = BuildFilename(old_path).host_path;
|
||||||
const std::string host_new_path = BuildFilename(new_path);
|
const std::string host_new_path = BuildFilename(new_path).host_path;
|
||||||
|
|
||||||
// If there is already something of the same type at the new path, delete it.
|
// If there is already something of the same type at the new path, delete it.
|
||||||
if (File::Exists(host_new_path))
|
if (File::Exists(host_new_path))
|
||||||
@ -544,7 +559,7 @@ Result<std::vector<std::string>> HostFileSystem::ReadDirectory(Uid uid, Gid gid,
|
|||||||
if (entry->data.is_file)
|
if (entry->data.is_file)
|
||||||
return ResultCode::Invalid;
|
return ResultCode::Invalid;
|
||||||
|
|
||||||
const std::string host_path = BuildFilename(path);
|
const std::string host_path = BuildFilename(path).host_path;
|
||||||
File::FSTEntry host_entry = File::ScanDirectoryTree(host_path, false);
|
File::FSTEntry host_entry = File::ScanDirectoryTree(host_path, false);
|
||||||
for (File::FSTEntry& child : host_entry.children)
|
for (File::FSTEntry& child : host_entry.children)
|
||||||
{
|
{
|
||||||
@ -612,7 +627,7 @@ Result<Metadata> HostFileSystem::GetMetadata(Uid uid, Gid gid, const std::string
|
|||||||
return ResultCode::NotFound;
|
return ResultCode::NotFound;
|
||||||
|
|
||||||
Metadata metadata = entry->data;
|
Metadata metadata = entry->data;
|
||||||
metadata.size = File::GetSize(BuildFilename(path));
|
metadata.size = File::GetSize(BuildFilename(path).host_path);
|
||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -631,7 +646,7 @@ ResultCode HostFileSystem::SetMetadata(Uid caller_uid, const std::string& path,
|
|||||||
if (caller_uid != 0 && uid != entry->data.uid)
|
if (caller_uid != 0 && uid != entry->data.uid)
|
||||||
return ResultCode::AccessDenied;
|
return ResultCode::AccessDenied;
|
||||||
|
|
||||||
const bool is_empty = File::GetSize(BuildFilename(path)) == 0;
|
const bool is_empty = File::GetSize(BuildFilename(path).host_path) == 0;
|
||||||
if (entry->data.uid != uid && entry->data.is_file && !is_empty)
|
if (entry->data.uid != uid && entry->data.is_file && !is_empty)
|
||||||
return ResultCode::FileNotEmpty;
|
return ResultCode::FileNotEmpty;
|
||||||
|
|
||||||
@ -667,7 +682,7 @@ Result<DirectoryStats> HostFileSystem::GetDirectoryStats(const std::string& wii_
|
|||||||
return ResultCode::Invalid;
|
return ResultCode::Invalid;
|
||||||
|
|
||||||
DirectoryStats stats{};
|
DirectoryStats stats{};
|
||||||
std::string path(BuildFilename(wii_path));
|
std::string path(BuildFilename(wii_path).host_path);
|
||||||
if (File::IsDirectory(path))
|
if (File::IsDirectory(path))
|
||||||
{
|
{
|
||||||
File::FSTEntry parent_dir = File::ScanDirectoryTree(path, true);
|
File::FSTEntry parent_dir = File::ScanDirectoryTree(path, true);
|
||||||
@ -685,4 +700,8 @@ Result<DirectoryStats> HostFileSystem::GetDirectoryStats(const std::string& wii_
|
|||||||
return stats;
|
return stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HostFileSystem::SetNandRedirects(std::vector<NandRedirect> nand_redirects)
|
||||||
|
{
|
||||||
|
m_nand_redirects = std::move(nand_redirects);
|
||||||
|
}
|
||||||
} // namespace IOS::HLE::FS
|
} // namespace IOS::HLE::FS
|
||||||
|
@ -22,7 +22,7 @@ namespace IOS::HLE::FS
|
|||||||
class HostFileSystem final : public FileSystem
|
class HostFileSystem final : public FileSystem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HostFileSystem(const std::string& root_path);
|
HostFileSystem(const std::string& root_path, std::vector<NandRedirect> nand_redirects = {});
|
||||||
~HostFileSystem();
|
~HostFileSystem();
|
||||||
|
|
||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
@ -56,6 +56,8 @@ public:
|
|||||||
Result<NandStats> GetNandStats() override;
|
Result<NandStats> GetNandStats() override;
|
||||||
Result<DirectoryStats> GetDirectoryStats(const std::string& path) override;
|
Result<DirectoryStats> GetDirectoryStats(const std::string& path) override;
|
||||||
|
|
||||||
|
void SetNandRedirects(std::vector<NandRedirect> nand_redirects) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct FstEntry
|
struct FstEntry
|
||||||
{
|
{
|
||||||
@ -83,7 +85,12 @@ private:
|
|||||||
Handle* GetHandleFromFd(Fd fd);
|
Handle* GetHandleFromFd(Fd fd);
|
||||||
Fd ConvertHandleToFd(const Handle* handle) const;
|
Fd ConvertHandleToFd(const Handle* handle) const;
|
||||||
|
|
||||||
std::string BuildFilename(const std::string& wii_path) const;
|
struct HostFilename
|
||||||
|
{
|
||||||
|
std::string host_path;
|
||||||
|
bool is_redirect;
|
||||||
|
};
|
||||||
|
HostFilename BuildFilename(const std::string& wii_path) const;
|
||||||
std::shared_ptr<File::IOFile> OpenHostFile(const std::string& host_path);
|
std::shared_ptr<File::IOFile> OpenHostFile(const std::string& host_path);
|
||||||
|
|
||||||
ResultCode CreateFileOrDirectory(Uid uid, Gid gid, const std::string& path,
|
ResultCode CreateFileOrDirectory(Uid uid, Gid gid, const std::string& path,
|
||||||
@ -112,6 +119,9 @@ private:
|
|||||||
std::string m_root_path;
|
std::string m_root_path;
|
||||||
std::map<std::string, std::weak_ptr<File::IOFile>> m_open_files;
|
std::map<std::string, std::weak_ptr<File::IOFile>> m_open_files;
|
||||||
std::array<Handle, 16> m_handles{};
|
std::array<Handle, 16> m_handles{};
|
||||||
|
|
||||||
|
FstEntry m_redirect_fst{};
|
||||||
|
std::vector<NandRedirect> m_nand_redirects;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace IOS::HLE::FS
|
} // namespace IOS::HLE::FS
|
||||||
|
@ -80,7 +80,7 @@ Result<FileHandle> HostFileSystem::OpenFile(Uid, Gid, const std::string& path, M
|
|||||||
if (!handle)
|
if (!handle)
|
||||||
return ResultCode::NoFreeHandle;
|
return ResultCode::NoFreeHandle;
|
||||||
|
|
||||||
const std::string host_path = BuildFilename(path);
|
const std::string host_path = BuildFilename(path).host_path;
|
||||||
if (!File::IsFile(host_path))
|
if (!File::IsFile(host_path))
|
||||||
{
|
{
|
||||||
*handle = Handle{};
|
*handle = Handle{};
|
||||||
|
@ -498,7 +498,7 @@ void Kernel::AddDevice(std::unique_ptr<Device> device)
|
|||||||
|
|
||||||
void Kernel::AddCoreDevices()
|
void Kernel::AddCoreDevices()
|
||||||
{
|
{
|
||||||
m_fs = FS::MakeFileSystem();
|
m_fs = FS::MakeFileSystem(IOS::HLE::FS::Location::Session, Core::GetActiveNandRedirects());
|
||||||
ASSERT(m_fs);
|
ASSERT(m_fs);
|
||||||
|
|
||||||
std::lock_guard lock(m_device_map_mutex);
|
std::lock_guard lock(m_device_map_mutex);
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "Core/WiiRoot.h"
|
#include "Core/WiiRoot.h"
|
||||||
|
|
||||||
#include <cinttypes>
|
#include <cinttypes>
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@ -34,6 +35,12 @@ namespace FS = IOS::HLE::FS;
|
|||||||
|
|
||||||
static std::string s_temp_wii_root;
|
static std::string s_temp_wii_root;
|
||||||
static bool s_wii_root_initialized = false;
|
static bool s_wii_root_initialized = false;
|
||||||
|
static std::vector<IOS::HLE::FS::NandRedirect> s_nand_redirects;
|
||||||
|
|
||||||
|
const std::vector<IOS::HLE::FS::NandRedirect>& GetActiveNandRedirects()
|
||||||
|
{
|
||||||
|
return s_nand_redirects;
|
||||||
|
}
|
||||||
|
|
||||||
static bool CopyBackupFile(const std::string& path_from, const std::string& path_to)
|
static bool CopyBackupFile(const std::string& path_from, const std::string& path_to)
|
||||||
{
|
{
|
||||||
@ -202,6 +209,7 @@ void InitializeWiiRoot(bool use_temporary)
|
|||||||
File::SetUserPath(D_SESSION_WIIROOT_IDX, File::GetUserPath(D_WIIROOT_IDX));
|
File::SetUserPath(D_SESSION_WIIROOT_IDX, File::GetUserPath(D_WIIROOT_IDX));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s_nand_redirects.clear();
|
||||||
s_wii_root_initialized = true;
|
s_wii_root_initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,6 +221,7 @@ void ShutdownWiiRoot()
|
|||||||
s_temp_wii_root.clear();
|
s_temp_wii_root.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s_nand_redirects.clear();
|
||||||
s_wii_root_initialized = false;
|
s_wii_root_initialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -288,7 +297,8 @@ static bool CopySysmenuFilesToFS(FS::FileSystem* fs, const std::string& host_sou
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitializeWiiFileSystemContents()
|
void InitializeWiiFileSystemContents(
|
||||||
|
std::optional<DiscIO::Riivolution::SavegameRedirect> save_redirect)
|
||||||
{
|
{
|
||||||
const auto fs = IOS::HLE::GetIOS()->GetFS();
|
const auto fs = IOS::HLE::GetIOS()->GetFS();
|
||||||
|
|
||||||
@ -299,14 +309,31 @@ void InitializeWiiFileSystemContents()
|
|||||||
if (!CopySysmenuFilesToFS(fs.get(), File::GetSysDirectory() + WII_USER_DIR, ""))
|
if (!CopySysmenuFilesToFS(fs.get(), File::GetSysDirectory() + WII_USER_DIR, ""))
|
||||||
WARN_LOG_FMT(CORE, "Failed to copy initial System Menu files to the NAND");
|
WARN_LOG_FMT(CORE, "Failed to copy initial System Menu files to the NAND");
|
||||||
|
|
||||||
if (!WiiRootIsTemporary())
|
if (WiiRootIsTemporary())
|
||||||
return;
|
{
|
||||||
|
// Generate a SYSCONF with default settings for the temporary Wii NAND.
|
||||||
|
SysConf sysconf{fs};
|
||||||
|
sysconf.Save();
|
||||||
|
|
||||||
// Generate a SYSCONF with default settings for the temporary Wii NAND.
|
InitializeDeterministicWiiSaves(fs.get());
|
||||||
SysConf sysconf{fs};
|
}
|
||||||
sysconf.Save();
|
else if (save_redirect)
|
||||||
|
{
|
||||||
InitializeDeterministicWiiSaves(fs.get());
|
const u64 title_id = SConfig::GetInstance().GetTitleID();
|
||||||
|
std::string source_path = Common::GetTitleDataPath(title_id);
|
||||||
|
if (!File::IsDirectory(save_redirect->m_target_path))
|
||||||
|
{
|
||||||
|
File::CreateFullPath(save_redirect->m_target_path + "/");
|
||||||
|
if (save_redirect->m_clone)
|
||||||
|
{
|
||||||
|
File::CopyDir(Common::GetTitleDataPath(title_id, Common::FROM_CONFIGURED_ROOT),
|
||||||
|
save_redirect->m_target_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s_nand_redirects.emplace_back(IOS::HLE::FS::NandRedirect{
|
||||||
|
std::move(source_path), std::move(save_redirect->m_target_path)});
|
||||||
|
fs->SetNandRedirects(s_nand_redirects);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CleanUpWiiFileSystemContents()
|
void CleanUpWiiFileSystemContents()
|
||||||
|
@ -3,6 +3,16 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "DiscIO/RiivolutionPatcher.h"
|
||||||
|
|
||||||
|
namespace IOS::HLE::FS
|
||||||
|
{
|
||||||
|
struct NandRedirect;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Core
|
namespace Core
|
||||||
{
|
{
|
||||||
enum class RestoreReason
|
enum class RestoreReason
|
||||||
@ -21,6 +31,9 @@ void BackupWiiSettings();
|
|||||||
void RestoreWiiSettings(RestoreReason reason);
|
void RestoreWiiSettings(RestoreReason reason);
|
||||||
|
|
||||||
// Initialize or clean up the filesystem contents.
|
// Initialize or clean up the filesystem contents.
|
||||||
void InitializeWiiFileSystemContents();
|
void InitializeWiiFileSystemContents(
|
||||||
|
std::optional<DiscIO::Riivolution::SavegameRedirect> save_redirect);
|
||||||
void CleanUpWiiFileSystemContents();
|
void CleanUpWiiFileSystemContents();
|
||||||
|
|
||||||
|
const std::vector<IOS::HLE::FS::NandRedirect>& GetActiveNandRedirects();
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "Common/IOFile.h"
|
#include "Common/IOFile.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
|
#include "Core/IOS/FS/FileSystem.h"
|
||||||
#include "Core/PowerPC/MMU.h"
|
#include "Core/PowerPC/MMU.h"
|
||||||
#include "DiscIO/DirectoryBlob.h"
|
#include "DiscIO/DirectoryBlob.h"
|
||||||
#include "DiscIO/RiivolutionParser.h"
|
#include "DiscIO/RiivolutionParser.h"
|
||||||
@ -174,6 +175,12 @@ FileDataLoaderHostFS::MakeContentSource(std::string_view external_relative_path,
|
|||||||
ContentFile{std::move(*path), external_offset}};
|
ContentFile{std::move(*path), external_offset}};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::string>
|
||||||
|
FileDataLoaderHostFS::ResolveSavegameRedirectPath(std::string_view external_relative_path)
|
||||||
|
{
|
||||||
|
return MakeAbsoluteFromRelative(external_relative_path);
|
||||||
|
}
|
||||||
|
|
||||||
// 'before' and 'after' should be two copies of the same source
|
// 'before' and 'after' should be two copies of the same source
|
||||||
// 'split_at' needs to be between the start and end of the source, may not match either boundary
|
// 'split_at' needs to be between the start and end of the source, may not match either boundary
|
||||||
static void SplitAt(BuilderContentSource* before, BuilderContentSource* after, u64 split_at)
|
static void SplitAt(BuilderContentSource* before, BuilderContentSource* after, u64 split_at)
|
||||||
@ -588,4 +595,21 @@ void ApplyPatchesToMemory(const std::vector<Patch>& patches)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<SavegameRedirect>
|
||||||
|
ExtractSavegameRedirect(const std::vector<Patch>& riivolution_patches)
|
||||||
|
{
|
||||||
|
for (const auto& patch : riivolution_patches)
|
||||||
|
{
|
||||||
|
if (!patch.m_savegame_patches.empty())
|
||||||
|
{
|
||||||
|
const auto& save_patch = patch.m_savegame_patches[0];
|
||||||
|
auto resolved = patch.m_file_data_loader->ResolveSavegameRedirectPath(save_patch.m_external);
|
||||||
|
if (resolved)
|
||||||
|
return SavegameRedirect{std::move(*resolved), save_patch.m_clone};
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
} // namespace DiscIO::Riivolution
|
} // namespace DiscIO::Riivolution
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -12,6 +13,12 @@
|
|||||||
|
|
||||||
namespace DiscIO::Riivolution
|
namespace DiscIO::Riivolution
|
||||||
{
|
{
|
||||||
|
struct SavegameRedirect
|
||||||
|
{
|
||||||
|
std::string m_target_path;
|
||||||
|
bool m_clone;
|
||||||
|
};
|
||||||
|
|
||||||
class FileDataLoader
|
class FileDataLoader
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -28,6 +35,8 @@ public:
|
|||||||
virtual BuilderContentSource MakeContentSource(std::string_view external_relative_path,
|
virtual BuilderContentSource MakeContentSource(std::string_view external_relative_path,
|
||||||
u64 external_offset, u64 external_size,
|
u64 external_offset, u64 external_size,
|
||||||
u64 disc_offset) = 0;
|
u64 disc_offset) = 0;
|
||||||
|
virtual std::optional<std::string>
|
||||||
|
ResolveSavegameRedirectPath(std::string_view external_relative_path) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileDataLoaderHostFS : public FileDataLoader
|
class FileDataLoaderHostFS : public FileDataLoader
|
||||||
@ -46,6 +55,8 @@ public:
|
|||||||
BuilderContentSource MakeContentSource(std::string_view external_relative_path,
|
BuilderContentSource MakeContentSource(std::string_view external_relative_path,
|
||||||
u64 external_offset, u64 external_size,
|
u64 external_offset, u64 external_size,
|
||||||
u64 disc_offset) override;
|
u64 disc_offset) override;
|
||||||
|
std::optional<std::string>
|
||||||
|
ResolveSavegameRedirectPath(std::string_view external_relative_path) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::optional<std::string> MakeAbsoluteFromRelative(std::string_view external_relative_path);
|
std::optional<std::string> MakeAbsoluteFromRelative(std::string_view external_relative_path);
|
||||||
@ -58,4 +69,6 @@ void ApplyPatchesToFiles(const std::vector<Patch>& patches,
|
|||||||
std::vector<DiscIO::FSTBuilderNode>* fst,
|
std::vector<DiscIO::FSTBuilderNode>* fst,
|
||||||
DiscIO::FSTBuilderNode* dol_node);
|
DiscIO::FSTBuilderNode* dol_node);
|
||||||
void ApplyPatchesToMemory(const std::vector<Patch>& patches);
|
void ApplyPatchesToMemory(const std::vector<Patch>& patches);
|
||||||
|
std::optional<SavegameRedirect>
|
||||||
|
ExtractSavegameRedirect(const std::vector<Patch>& riivolution_patches);
|
||||||
} // namespace DiscIO::Riivolution
|
} // namespace DiscIO::Riivolution
|
||||||
|
Loading…
x
Reference in New Issue
Block a user