2017-01-06 21:59:02 +01:00
|
|
|
// Copyright 2016 Dolphin Emulator Project
|
|
|
|
// Licensed under GPLv2+
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2017-02-24 22:56:33 -05:00
|
|
|
#include "Core/WiiRoot.h"
|
|
|
|
|
2018-05-27 20:45:05 +02:00
|
|
|
#include <cinttypes>
|
2017-01-06 21:59:02 +01:00
|
|
|
#include <string>
|
2018-05-12 18:44:47 +02:00
|
|
|
#include <vector>
|
2017-01-06 21:59:02 +01:00
|
|
|
|
|
|
|
#include "Common/CommonPaths.h"
|
2018-05-12 18:44:47 +02:00
|
|
|
#include "Common/CommonTypes.h"
|
|
|
|
#include "Common/File.h"
|
2017-01-06 21:59:02 +01:00
|
|
|
#include "Common/FileUtil.h"
|
|
|
|
#include "Common/Logging/Log.h"
|
|
|
|
#include "Common/NandPaths.h"
|
2017-02-24 22:56:33 -05:00
|
|
|
#include "Common/StringUtil.h"
|
2017-01-14 20:10:44 +01:00
|
|
|
#include "Core/ConfigManager.h"
|
2018-05-27 20:45:05 +02:00
|
|
|
#include "Core/HW/WiiSave.h"
|
2018-05-12 18:44:47 +02:00
|
|
|
#include "Core/IOS/FS/FileSystem.h"
|
2018-03-11 12:05:12 +01:00
|
|
|
#include "Core/IOS/IOS.h"
|
2018-05-12 18:44:47 +02:00
|
|
|
#include "Core/IOS/Uids.h"
|
2017-01-14 20:10:44 +01:00
|
|
|
#include "Core/Movie.h"
|
2016-12-23 20:37:23 -05:00
|
|
|
#include "Core/NetPlayClient.h"
|
2018-03-11 11:43:54 +01:00
|
|
|
#include "Core/SysConf.h"
|
2017-01-06 21:59:02 +01:00
|
|
|
|
|
|
|
namespace Core
|
|
|
|
{
|
|
|
|
static std::string s_temp_wii_root;
|
|
|
|
|
2018-06-03 21:37:28 +02:00
|
|
|
namespace FS = IOS::HLE::FS;
|
|
|
|
|
|
|
|
static void InitializeDeterministicWiiSaves(FS::FileSystem* session_fs)
|
2017-01-14 20:10:44 +01:00
|
|
|
{
|
2018-05-27 20:45:05 +02:00
|
|
|
const u64 title_id = SConfig::GetInstance().GetTitleID();
|
2018-06-03 21:37:28 +02:00
|
|
|
const auto configured_fs = FS::MakeFileSystem(FS::Location::Configured);
|
2016-12-23 20:37:23 -05:00
|
|
|
if (Movie::IsRecordingInput())
|
2017-01-14 20:10:44 +01:00
|
|
|
{
|
2016-12-23 20:37:23 -05:00
|
|
|
if (NetPlay::IsNetPlayRunning() && !SConfig::GetInstance().bCopyWiiSaveNetplay)
|
2017-01-14 20:10:44 +01:00
|
|
|
{
|
2016-12-23 20:37:23 -05:00
|
|
|
Movie::SetClearSave(true);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// TODO: Check for the actual save data
|
2018-05-27 20:45:05 +02:00
|
|
|
const std::string path = Common::GetTitleDataPath(title_id) + "/banner.bin";
|
|
|
|
Movie::SetClearSave(!configured_fs->GetMetadata(IOS::PID_KERNEL, IOS::PID_KERNEL, path));
|
2017-01-14 20:10:44 +01:00
|
|
|
}
|
|
|
|
}
|
2016-12-23 20:37:23 -05:00
|
|
|
|
|
|
|
if ((NetPlay::IsNetPlayRunning() && SConfig::GetInstance().bCopyWiiSaveNetplay) ||
|
|
|
|
(Movie::IsMovieActive() && !Movie::IsStartingFromClearSave()))
|
2017-01-14 20:10:44 +01:00
|
|
|
{
|
2016-12-23 20:37:23 -05:00
|
|
|
// Copy the current user's save to the Blank NAND
|
2018-05-27 20:45:05 +02:00
|
|
|
const auto user_save = WiiSave::MakeNandStorage(configured_fs.get(), title_id);
|
|
|
|
const auto session_save = WiiSave::MakeNandStorage(session_fs, title_id);
|
|
|
|
WiiSave::Copy(user_save.get(), session_save.get());
|
2017-01-14 20:10:44 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-06 21:59:02 +01:00
|
|
|
void InitializeWiiRoot(bool use_temporary)
|
|
|
|
{
|
|
|
|
if (use_temporary)
|
|
|
|
{
|
|
|
|
s_temp_wii_root = File::CreateTempDir();
|
|
|
|
if (s_temp_wii_root.empty())
|
|
|
|
{
|
2018-03-05 22:47:53 +01:00
|
|
|
ERROR_LOG(IOS_FS, "Could not create temporary directory");
|
2017-01-06 21:59:02 +01:00
|
|
|
return;
|
|
|
|
}
|
2018-03-05 22:47:53 +01:00
|
|
|
WARN_LOG(IOS_FS, "Using temporary directory %s for minimal Wii FS", s_temp_wii_root.c_str());
|
2017-01-06 21:59:02 +01:00
|
|
|
File::SetUserPath(D_SESSION_WIIROOT_IDX, s_temp_wii_root);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
File::SetUserPath(D_SESSION_WIIROOT_IDX, File::GetUserPath(D_WIIROOT_IDX));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ShutdownWiiRoot()
|
|
|
|
{
|
|
|
|
if (!s_temp_wii_root.empty())
|
|
|
|
{
|
|
|
|
File::DeleteDirRecursively(s_temp_wii_root);
|
|
|
|
s_temp_wii_root.clear();
|
|
|
|
}
|
|
|
|
}
|
2018-05-12 16:52:33 +02:00
|
|
|
|
2018-05-12 18:44:47 +02:00
|
|
|
/// Copy a directory from host_source_path (on the host FS) to nand_target_path on the NAND.
|
|
|
|
///
|
|
|
|
/// Both paths should not have trailing slashes. To specify the NAND root, use "".
|
2018-06-03 21:37:28 +02:00
|
|
|
static bool CopySysmenuFilesToFS(FS::FileSystem* fs, const std::string& host_source_path,
|
2018-05-12 18:44:47 +02:00
|
|
|
const std::string& nand_target_path)
|
|
|
|
{
|
|
|
|
const auto entries = File::ScanDirectoryTree(host_source_path, false);
|
|
|
|
for (const File::FSTEntry& entry : entries.children)
|
|
|
|
{
|
|
|
|
const std::string host_path = host_source_path + '/' + entry.virtualName;
|
|
|
|
const std::string nand_path = nand_target_path + '/' + entry.virtualName;
|
2018-06-03 21:37:28 +02:00
|
|
|
constexpr FS::Modes public_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::ReadWrite};
|
2018-05-12 18:44:47 +02:00
|
|
|
|
|
|
|
if (entry.isDirectory)
|
|
|
|
{
|
2018-06-03 20:32:32 +02:00
|
|
|
fs->CreateDirectory(IOS::SYSMENU_UID, IOS::SYSMENU_GID, nand_path, 0, public_modes);
|
2018-05-12 18:44:47 +02:00
|
|
|
if (!CopySysmenuFilesToFS(fs, host_path, nand_path))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Do not overwrite any existing files.
|
|
|
|
if (fs->GetMetadata(IOS::SYSMENU_UID, IOS::SYSMENU_UID, nand_path).Succeeded())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
File::IOFile host_file{host_path, "rb"};
|
|
|
|
std::vector<u8> file_data(host_file.GetSize());
|
|
|
|
if (!host_file.ReadBytes(file_data.data(), file_data.size()))
|
|
|
|
return false;
|
|
|
|
|
2018-06-03 20:32:32 +02:00
|
|
|
const auto nand_file =
|
|
|
|
fs->CreateAndOpenFile(IOS::SYSMENU_UID, IOS::SYSMENU_GID, nand_path, public_modes);
|
2018-05-12 18:44:47 +02:00
|
|
|
if (!nand_file || !nand_file->Write(file_data.data(), file_data.size()))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-05-12 16:52:33 +02:00
|
|
|
void InitializeWiiFileSystemContents()
|
|
|
|
{
|
2018-05-12 18:44:47 +02:00
|
|
|
const auto fs = IOS::HLE::GetIOS()->GetFS();
|
|
|
|
|
|
|
|
// Some games (such as Mario Kart Wii) assume that NWC24 files will always be present
|
|
|
|
// even upon the first launch as they are normally created by the system menu.
|
|
|
|
// Because we do not require the system menu to be run, WiiConnect24 files must be copied
|
|
|
|
// to the NAND manually.
|
|
|
|
if (!CopySysmenuFilesToFS(fs.get(), File::GetSysDirectory() + WII_USER_DIR, ""))
|
|
|
|
WARN_LOG(CORE, "Failed to copy initial System Menu files to the NAND");
|
2018-05-12 17:08:24 +02:00
|
|
|
|
2018-05-12 16:52:33 +02:00
|
|
|
if (s_temp_wii_root.empty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Generate a SYSCONF with default settings for the temporary Wii NAND.
|
2018-05-12 18:44:47 +02:00
|
|
|
SysConf sysconf{fs};
|
2018-05-12 16:52:33 +02:00
|
|
|
sysconf.Save();
|
|
|
|
|
2018-05-27 20:45:05 +02:00
|
|
|
InitializeDeterministicWiiSaves(fs.get());
|
2018-05-12 16:52:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void CleanUpWiiFileSystemContents()
|
|
|
|
{
|
2018-05-27 20:45:05 +02:00
|
|
|
if (s_temp_wii_root.empty() || !SConfig::GetInstance().bEnableMemcardSdWriting)
|
2018-05-12 16:52:33 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
const u64 title_id = SConfig::GetInstance().GetTitleID();
|
2018-05-27 20:45:05 +02:00
|
|
|
|
|
|
|
IOS::HLE::EmulationKernel* ios = IOS::HLE::GetIOS();
|
|
|
|
const auto session_save = WiiSave::MakeNandStorage(ios->GetFS().get(), title_id);
|
|
|
|
|
2018-06-03 21:37:28 +02:00
|
|
|
const auto configured_fs = FS::MakeFileSystem(FS::Location::Configured);
|
2018-05-27 20:45:05 +02:00
|
|
|
const auto user_save = WiiSave::MakeNandStorage(configured_fs.get(), title_id);
|
|
|
|
|
|
|
|
const std::string backup_path =
|
|
|
|
File::GetUserPath(D_BACKUP_IDX) + StringFromFormat("/%016" PRIx64 ".bin", title_id);
|
|
|
|
const auto backup_save = WiiSave::MakeDataBinStorage(&ios->GetIOSC(), backup_path, "w+b");
|
|
|
|
|
|
|
|
// Backup the existing save just in case it's still needed.
|
|
|
|
WiiSave::Copy(user_save.get(), backup_save.get());
|
|
|
|
WiiSave::Copy(session_save.get(), user_save.get());
|
2017-01-06 21:59:02 +01:00
|
|
|
}
|
2018-05-12 16:52:33 +02:00
|
|
|
} // namespace Core
|