From fd3472442d169c4f9200663729a693c9ccc3d3e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 31 May 2018 20:51:33 +0200 Subject: [PATCH] WiiSave: Use new filesystem interface Converts WiiSave to the new filesystem interface. --- Source/Core/Core/HW/WiiSave.cpp | 177 +++++++++++++++++--------------- 1 file changed, 94 insertions(+), 83 deletions(-) diff --git a/Source/Core/Core/HW/WiiSave.cpp b/Source/Core/Core/HW/WiiSave.cpp index c87130c190..82d8e8d568 100644 --- a/Source/Core/Core/HW/WiiSave.cpp +++ b/Source/Core/Core/HW/WiiSave.cpp @@ -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" @@ -141,30 +142,37 @@ 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
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(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)) + if (!banner->Read(header.banner, header.banner_size)) return {}; // remove nocopy flag header.banner[7] &= ~1; @@ -188,58 +196,47 @@ public: return bk_hdr; } - std::optional> ReadFiles() override - { - std::vector 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> { - File::IOFile file{path, "rb"}; - std::vector data(file.GetSize()); - if (!file || !file.ReadBytes(data.data(), data.size())) - return std::nullopt; - return data; - }; - return save_file; - }); - return ret; - } + std::optional> 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 auto file = m_fs->CreateAndOpenFile(*m_uid, *m_gid, banner_file_path, FS::Mode::ReadWrite, + FS::Mode::ReadWrite, FS::Mode::ReadWrite); + return file && file->Write(header.banner, header.banner_size); } bool WriteBkHeader(const BkHeader& bk_header) override { return true; } bool WriteFiles(const std::vector& 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); - 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, FS::Mode::ReadWrite, + FS::Mode::ReadWrite, FS::Mode::ReadWrite); const std::optional>& 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 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, FS::Mode::ReadWrite, + FS::Mode::ReadWrite, FS::Mode::ReadWrite); + if (result != FS::ResultCode::Success) return false; } } @@ -247,50 +244,65 @@ public: } private: - void ScanForFiles() + void ScanForFiles(const std::string& dir) { - std::vector directories; - directories.push_back(m_wii_title_path); - u32 size = 0; + if (!m_uid || !m_gid) + return; - for (u32 i = 0; i < directories.size(); ++i) + const auto entries = m_fs->ReadDirectory(*m_uid, *m_gid, dir); + if (!entries) + return; + + 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."); - } + const std::string path = dir + '/' + elem; + const FS::Result metadata = m_fs->GetMetadata(*m_uid, *m_gid, path); + if (!metadata) + return; - directories.push_back(elem.physicalName); - } - else - { - m_files_list.push_back(elem.physicalName); - size += static_cast(Common::AlignUp(elem.size, BLOCK_SZ)); - } - } - } + SaveFile save_file; + // TODO: use the correct mode. + save_file.mode = 0x3c; + 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> { + const auto file = m_fs->OpenFile(*m_uid, *m_gid, path, FS::Mode::Read); + if (!file) + return {}; + std::vector 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(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; + } + + FS::FileSystem* m_fs = nullptr; + std::string m_data_dir; u64 m_tid = 0; - std::string m_wii_title_path; - std::vector m_files_list; + std::optional m_uid; + std::optional m_gid; + std::vector m_files_list; u32 m_files_size = 0; }; @@ -487,10 +499,9 @@ private: 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)