Skip to content

Commit

Permalink
Merge pull request #7059 from leoetlino/fs-wiisave
Browse files Browse the repository at this point in the history
WiiSave: Use new filesystem interface
  • Loading branch information
leoetlino authored Jun 3, 2018
2 parents 47bf809 + 6b9aef7 commit 8fce18e
Show file tree
Hide file tree
Showing 17 changed files with 224 additions and 236 deletions.
4 changes: 2 additions & 2 deletions Source/Core/Core/Boot/Boot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -478,8 +478,8 @@ void UpdateStateFlags(std::function<void(StateFlags*)> update_function)
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);
const auto file = fs->CreateAndOpenFile(IOS::SYSMENU_UID, IOS::SYSMENU_GID, file_path,
{rw_mode, rw_mode, rw_mode});
if (!file)
return;

Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/Boot/Boot_BS2Emu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ bool CBoot::SetupWiiMemory()

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);
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");
Expand Down Expand Up @@ -343,7 +343,7 @@ static void WriteEmptyPlayRecord()
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);
{rw_mode, rw_mode, rw_mode});
if (!playrec_file)
return;
std::vector<u8> empty_record(0x80);
Expand Down
195 changes: 110 additions & 85 deletions Source/Core/Core/HW/WiiSave.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "Common/Swap.h"
#include "Core/CommonTitles.h"
#include "Core/IOS/ES/ES.h"
#include "Core/IOS/FS/FileSystem.h"
#include "Core/IOS/IOS.h"
#include "Core/IOS/IOSC.h"
#include "Core/IOS/Uids.h"
Expand Down Expand Up @@ -141,31 +142,39 @@ void StorageDeleter::operator()(Storage* p) const
delete p;
}

namespace FS = IOS::HLE::FS;

class NandStorage final : public Storage
{
public:
explicit NandStorage(u64 tid) : m_tid{tid}
explicit NandStorage(FS::FileSystem* fs, u64 tid) : m_fs{fs}, m_tid{tid}
{
m_wii_title_path = Common::GetTitleDataPath(tid, Common::FromWhichRoot::FROM_CONFIGURED_ROOT);
File::CreateFullPath(m_wii_title_path);
ScanForFiles();
m_data_dir = Common::GetTitleDataPath(tid);
InitTitleUidAndGid();
ScanForFiles(m_data_dir);
}

bool SaveExists() override { return File::Exists(m_wii_title_path + "/banner.bin"); }
bool SaveExists() override
{
return m_uid && m_gid && m_fs->GetMetadata(*m_uid, *m_gid, m_data_dir + "/banner.bin");
}

std::optional<Header> ReadHeader() override
{
if (!m_uid || !m_gid)
return {};

const auto banner = m_fs->OpenFile(*m_uid, *m_gid, m_data_dir + "/banner.bin", FS::Mode::Read);
if (!banner)
return {};
Header header{};
std::string banner_file_path = m_wii_title_path + "/banner.bin";
u32 banner_size = static_cast<u32>(File::GetSize(banner_file_path));
header.banner_size = banner_size;
header.banner_size = banner->GetStatus()->size;
header.tid = m_tid;
header.md5 = s_md5_blanker;
header.permissions = 0x3C;

File::IOFile banner_file(banner_file_path, "rb");
if (!banner_file.ReadBytes(header.banner, banner_size))
const u8 mode = GetBinMode(m_data_dir + "/banner.bin");
if (!mode || !banner->Read(header.banner, header.banner_size))
return {};
header.permissions = mode;
// remove nocopy flag
header.banner[7] &= ~1;

Expand All @@ -188,109 +197,126 @@ class NandStorage final : public Storage
return bk_hdr;
}

std::optional<std::vector<SaveFile>> ReadFiles() override
{
std::vector<SaveFile> ret(m_files_list.size());
std::transform(m_files_list.begin(), m_files_list.end(), ret.begin(), [this](const auto& path) {
const File::FileInfo file_info{path};
SaveFile save_file;
save_file.mode = 0x3c;
save_file.attributes = 0;
save_file.type = file_info.IsDirectory() ? SaveFile::Type::Directory : SaveFile::Type::File;
save_file.path = Common::UnescapeFileName(path.substr(m_wii_title_path.length() + 1));
save_file.data = [path]() -> std::optional<std::vector<u8>> {
File::IOFile file{path, "rb"};
std::vector<u8> data(file.GetSize());
if (!file || !file.ReadBytes(data.data(), data.size()))
return std::nullopt;
return data;
};
return save_file;
});
return ret;
}
std::optional<std::vector<SaveFile>> ReadFiles() override { return m_files_list; }

bool WriteHeader(const Header& header) override
{
File::IOFile banner_file(m_wii_title_path + "/banner.bin", "wb");
return banner_file.WriteBytes(header.banner, header.banner_size);
if (!m_uid || !m_gid)
return false;

const std::string banner_file_path = m_data_dir + "/banner.bin";
const FS::Modes modes = GetFsMode(header.permissions);
const auto file = m_fs->CreateAndOpenFile(*m_uid, *m_gid, banner_file_path, modes);
return file && file->Write(header.banner, header.banner_size);
}

bool WriteBkHeader(const BkHeader& bk_header) override { return true; }

bool WriteFiles(const std::vector<SaveFile>& files) override
{
if (!m_uid || !m_gid)
return false;

for (const SaveFile& file : files)
{
// Allows files in subfolders to be escaped properly (ex: "nocopy/data00")
// Special characters in path components will be escaped such as /../
std::string file_path = Common::EscapePath(file.path);
std::string file_path_full = m_wii_title_path + '/' + file_path;
File::CreateFullPath(file_path_full);

const FS::Modes modes = GetFsMode(file.mode);
if (file.type == SaveFile::Type::File)
{
File::IOFile raw_save_file(file_path_full, "wb");
const auto raw_file = m_fs->CreateAndOpenFile(*m_uid, *m_gid, file.path, modes);
const std::optional<std::vector<u8>>& data = *file.data;
if (!data)
if (!data || !raw_file || !raw_file->Write(data->data(), data->size()))
return false;
raw_save_file.WriteBytes(data->data(), data->size());
}
else if (file.type == SaveFile::Type::Directory)
{
File::CreateDir(file_path_full);
if (!File::IsDirectory(file_path_full))
const FS::Result<FS::Metadata> meta = m_fs->GetMetadata(*m_uid, *m_gid, file.path);
if (!meta || meta->is_file)
return false;

const FS::ResultCode result = m_fs->CreateDirectory(*m_uid, *m_gid, file.path, 0, modes);
if (result != FS::ResultCode::Success)
return false;
}
}
return true;
}

private:
void ScanForFiles()
void ScanForFiles(const std::string& dir)
{
std::vector<std::string> directories;
directories.push_back(m_wii_title_path);
u32 size = 0;
if (!m_uid || !m_gid)
return;

const auto entries = m_fs->ReadDirectory(*m_uid, *m_gid, dir);
if (!entries)
return;

for (u32 i = 0; i < directories.size(); ++i)
for (const std::string& elem : *entries)
{
if (i != 0)
{
// add dir to fst
m_files_list.push_back(directories[i]);
}
if (elem == "banner.bin")
continue;

File::FSTEntry fst_tmp = File::ScanDirectoryTree(directories[i], false);
for (const File::FSTEntry& elem : fst_tmp.children)
{
if (elem.virtualName != "banner.bin")
{
size += sizeof(FileHDR);
if (elem.isDirectory)
{
if (elem.virtualName == "nocopy" || elem.virtualName == "nomove")
{
NOTICE_LOG(CONSOLE,
"This save will likely require homebrew tools to copy to a real Wii.");
}

directories.push_back(elem.physicalName);
}
else
{
m_files_list.push_back(elem.physicalName);
size += static_cast<u32>(Common::AlignUp(elem.size, BLOCK_SZ));
}
}
}
const std::string path = dir + '/' + elem;
const FS::Result<FS::Metadata> metadata = m_fs->GetMetadata(*m_uid, *m_gid, path);
if (!metadata)
return;

SaveFile save_file;
save_file.mode = GetBinMode(metadata->modes);
save_file.attributes = 0;
save_file.type = metadata->is_file ? SaveFile::Type::File : SaveFile::Type::Directory;
save_file.path = path;
save_file.data = [this, path]() -> std::optional<std::vector<u8>> {
const auto file = m_fs->OpenFile(*m_uid, *m_gid, path, FS::Mode::Read);
if (!file)
return {};
std::vector<u8> data(file->GetStatus()->size);
if (!file->Read(data.data(), data.size()))
return std::nullopt;
return data;
};
m_files_list.emplace_back(std::move(save_file));
m_files_size += sizeof(FileHDR);

if (metadata->is_file)
m_files_size += static_cast<u32>(Common::AlignUp(metadata->size, BLOCK_SZ));
else
ScanForFiles(path);
}
m_files_size = size;
}

void InitTitleUidAndGid()
{
const auto metadata = m_fs->GetMetadata(IOS::PID_KERNEL, IOS::PID_KERNEL, m_data_dir);
if (!metadata)
return;
m_uid = metadata->uid;
m_gid = metadata->gid;
}

static constexpr FS::Modes GetFsMode(u8 bin_mode)
{
return {FS::Mode(bin_mode >> 4 & 3), FS::Mode(bin_mode >> 2 & 3), FS::Mode(bin_mode >> 0 & 3)};
}

static constexpr u8 GetBinMode(const FS::Modes& modes)
{
return u8(modes.owner) << 4 | u8(modes.group) << 2 | u8(modes.other) << 0;
}

u8 GetBinMode(const std::string& path) const
{
if (const FS::Result<FS::Metadata> meta = m_fs->GetMetadata(*m_uid, *m_gid, path))
return GetBinMode(meta->modes);
return 0;
}

FS::FileSystem* m_fs = nullptr;
std::string m_data_dir;
u64 m_tid = 0;
std::string m_wii_title_path;
std::vector<std::string> m_files_list;
std::optional<u32> m_uid;
std::optional<u16> m_gid;
std::vector<SaveFile> m_files_list;
u32 m_files_size = 0;
};

Expand Down Expand Up @@ -487,10 +513,9 @@ class DataBinStorage final : public Storage
File::IOFile m_file;
};

StoragePointer MakeNandStorage(IOS::HLE::FS::FileSystem* fs, u64 tid)
StoragePointer MakeNandStorage(FS::FileSystem* fs, u64 tid)
{
// fs parameter is not used yet but will be after WiiSave is migrated to the new FS interface.
return StoragePointer{new NandStorage{tid}};
return StoragePointer{new NandStorage{fs, tid}};
}

StoragePointer MakeDataBinStorage(IOS::HLE::IOSC* iosc, const std::string& path, const char* mode)
Expand Down
Loading

0 comments on commit 8fce18e

Please sign in to comment.