Merge pull request #7059 from leoetlino/fs-wiisave

WiiSave: Use new filesystem interface
This commit is contained in:
Léo Lam 2018-06-03 21:05:22 +02:00 committed by GitHub
commit 8fce18e4ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 223 additions and 235 deletions

View File

@ -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 std::string file_path = Common::GetTitleDataPath(Titles::SYSTEM_MENU) + "/" WII_STATE;
const auto fs = IOS::HLE::GetIOS()->GetFS(); const auto fs = IOS::HLE::GetIOS()->GetFS();
constexpr IOS::HLE::FS::Mode rw_mode = IOS::HLE::FS::Mode::ReadWrite; 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, const auto file = fs->CreateAndOpenFile(IOS::SYSMENU_UID, IOS::SYSMENU_GID, file_path,
rw_mode, rw_mode); {rw_mode, rw_mode, rw_mode});
if (!file) if (!file)
return; return;

View File

@ -269,7 +269,7 @@ bool CBoot::SetupWiiMemory()
constexpr IOS::HLE::FS::Mode rw_mode = IOS::HLE::FS::Mode::ReadWrite; constexpr IOS::HLE::FS::Mode rw_mode = IOS::HLE::FS::Mode::ReadWrite;
const auto settings_file = fs->CreateAndOpenFile(IOS::SYSMENU_UID, IOS::SYSMENU_GID, 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())) if (!settings_file || !settings_file->Write(gen.GetBytes().data(), gen.GetBytes().size()))
{ {
PanicAlertT("SetupWiiMemory: Can't create setting.txt file"); PanicAlertT("SetupWiiMemory: Can't create setting.txt file");
@ -343,7 +343,7 @@ static void WriteEmptyPlayRecord()
const auto fs = IOS::HLE::GetIOS()->GetFS(); const auto fs = IOS::HLE::GetIOS()->GetFS();
constexpr IOS::HLE::FS::Mode rw_mode = IOS::HLE::FS::Mode::ReadWrite; 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, 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) if (!playrec_file)
return; return;
std::vector<u8> empty_record(0x80); std::vector<u8> empty_record(0x80);

View File

@ -33,6 +33,7 @@
#include "Common/Swap.h" #include "Common/Swap.h"
#include "Core/CommonTitles.h" #include "Core/CommonTitles.h"
#include "Core/IOS/ES/ES.h" #include "Core/IOS/ES/ES.h"
#include "Core/IOS/FS/FileSystem.h"
#include "Core/IOS/IOS.h" #include "Core/IOS/IOS.h"
#include "Core/IOS/IOSC.h" #include "Core/IOS/IOSC.h"
#include "Core/IOS/Uids.h" #include "Core/IOS/Uids.h"
@ -141,31 +142,39 @@ void StorageDeleter::operator()(Storage* p) const
delete p; delete p;
} }
namespace FS = IOS::HLE::FS;
class NandStorage final : public Storage class NandStorage final : public Storage
{ {
public: 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); m_data_dir = Common::GetTitleDataPath(tid);
File::CreateFullPath(m_wii_title_path); InitTitleUidAndGid();
ScanForFiles(); 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 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{}; Header header{};
std::string banner_file_path = m_wii_title_path + "/banner.bin"; header.banner_size = banner->GetStatus()->size;
u32 banner_size = static_cast<u32>(File::GetSize(banner_file_path));
header.banner_size = banner_size;
header.tid = m_tid; header.tid = m_tid;
header.md5 = s_md5_blanker; header.md5 = s_md5_blanker;
header.permissions = 0x3C; const u8 mode = GetBinMode(m_data_dir + "/banner.bin");
if (!mode || !banner->Read(header.banner, header.banner_size))
File::IOFile banner_file(banner_file_path, "rb");
if (!banner_file.ReadBytes(header.banner, banner_size))
return {}; return {};
header.permissions = mode;
// remove nocopy flag // remove nocopy flag
header.banner[7] &= ~1; header.banner[7] &= ~1;
@ -188,58 +197,44 @@ public:
return bk_hdr; return bk_hdr;
} }
std::optional<std::vector<SaveFile>> ReadFiles() override std::optional<std::vector<SaveFile>> ReadFiles() override { return m_files_list; }
{
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;
}
bool WriteHeader(const Header& header) override bool WriteHeader(const Header& header) override
{ {
File::IOFile banner_file(m_wii_title_path + "/banner.bin", "wb"); if (!m_uid || !m_gid)
return banner_file.WriteBytes(header.banner, header.banner_size); 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 WriteBkHeader(const BkHeader& bk_header) override { return true; }
bool WriteFiles(const std::vector<SaveFile>& files) override bool WriteFiles(const std::vector<SaveFile>& files) override
{ {
if (!m_uid || !m_gid)
return false;
for (const SaveFile& file : files) for (const SaveFile& file : files)
{ {
// Allows files in subfolders to be escaped properly (ex: "nocopy/data00") const FS::Modes modes = GetFsMode(file.mode);
// 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) 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; const std::optional<std::vector<u8>>& data = *file.data;
if (!data) if (!data || !raw_file || !raw_file->Write(data->data(), data->size()))
return false; return false;
raw_save_file.WriteBytes(data->data(), data->size());
} }
else if (file.type == SaveFile::Type::Directory) else if (file.type == SaveFile::Type::Directory)
{ {
File::CreateDir(file_path_full); const FS::Result<FS::Metadata> meta = m_fs->GetMetadata(*m_uid, *m_gid, file.path);
if (!File::IsDirectory(file_path_full)) 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 false;
} }
} }
@ -247,50 +242,81 @@ public:
} }
private: private:
void ScanForFiles() void ScanForFiles(const std::string& dir)
{ {
std::vector<std::string> directories; if (!m_uid || !m_gid)
directories.push_back(m_wii_title_path); return;
u32 size = 0;
for (u32 i = 0; i < directories.size(); ++i) const auto entries = m_fs->ReadDirectory(*m_uid, *m_gid, dir);
{ if (!entries)
if (i != 0) return;
{
// add dir to fst
m_files_list.push_back(directories[i]);
}
File::FSTEntry fst_tmp = File::ScanDirectoryTree(directories[i], false); for (const std::string& elem : *entries)
for (const File::FSTEntry& elem : fst_tmp.children)
{ {
if (elem.virtualName != "banner.bin") if (elem == "banner.bin")
{ continue;
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); 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 else
{ ScanForFiles(path);
m_files_list.push_back(elem.physicalName);
size += static_cast<u32>(Common::AlignUp(elem.size, BLOCK_SZ));
} }
} }
}
}
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; u64 m_tid = 0;
std::string m_wii_title_path; std::optional<u32> m_uid;
std::vector<std::string> m_files_list; std::optional<u16> m_gid;
std::vector<SaveFile> m_files_list;
u32 m_files_size = 0; u32 m_files_size = 0;
}; };
@ -487,10 +513,9 @@ private:
File::IOFile m_file; 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{fs, tid}};
return StoragePointer{new NandStorage{tid}};
} }
StoragePointer MakeDataBinStorage(IOS::HLE::IOSC* iosc, const std::string& path, const char* mode) StoragePointer MakeDataBinStorage(IOS::HLE::IOSC* iosc, const std::string& path, const char* mode)

View File

@ -39,24 +39,22 @@ struct DirectoryToCreate
{ {
const char* path; const char* path;
FS::FileAttribute attribute; FS::FileAttribute attribute;
FS::Mode owner_mode; FS::Modes modes;
FS::Mode group_mode;
FS::Mode other_mode;
FS::Uid uid = PID_KERNEL; FS::Uid uid = PID_KERNEL;
FS::Gid gid = PID_KERNEL; FS::Gid gid = PID_KERNEL;
}; };
constexpr FS::Modes public_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::ReadWrite};
constexpr std::array<DirectoryToCreate, 9> s_directories_to_create = {{ constexpr std::array<DirectoryToCreate, 9> s_directories_to_create = {{
{"/sys", 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None}, {"/sys", 0, {FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None}},
{"/ticket", 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None}, {"/ticket", 0, {FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None}},
{"/title", 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::Read}, {"/title", 0, {FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::Read}},
{"/shared1", 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None}, {"/shared1", 0, {FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None}},
{"/shared2", 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::ReadWrite}, {"/shared2", 0, public_modes},
{"/tmp", 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::ReadWrite}, {"/tmp", 0, public_modes},
{"/import", 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None}, {"/import", 0, {FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None}},
{"/meta", 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::ReadWrite, SYSMENU_UID, {"/meta", 0, public_modes, SYSMENU_UID, SYSMENU_GID},
SYSMENU_GID}, {"/wfs", 0, {FS::Mode::ReadWrite, FS::Mode::None, FS::Mode::None}, PID_UNKNOWN, PID_UNKNOWN},
{"/wfs", 0, FS::Mode::ReadWrite, FS::Mode::None, FS::Mode::None, PID_UNKNOWN, PID_UNKNOWN},
}}; }};
ES::ES(Kernel& ios, const std::string& device_name) : Device(ios, device_name) ES::ES(Kernel& ios, const std::string& device_name) : Device(ios, device_name)
@ -66,14 +64,13 @@ ES::ES(Kernel& ios, const std::string& device_name) : Device(ios, device_name)
// Note: ES sets its own UID and GID to 0/0 at boot, so all filesystem accesses in ES are done // Note: ES sets its own UID and GID to 0/0 at boot, so all filesystem accesses in ES are done
// as UID 0 even though its PID is 1. // as UID 0 even though its PID is 1.
const auto result = m_ios.GetFS()->CreateDirectory(PID_KERNEL, PID_KERNEL, directory.path, const auto result = m_ios.GetFS()->CreateDirectory(PID_KERNEL, PID_KERNEL, directory.path,
directory.attribute, directory.owner_mode, directory.attribute, directory.modes);
directory.group_mode, directory.other_mode);
if (result != FS::ResultCode::Success && result != FS::ResultCode::AlreadyExists) if (result != FS::ResultCode::Success && result != FS::ResultCode::AlreadyExists)
ERROR_LOG(IOS_ES, "Failed to create %s: error %d", directory.path, FS::ConvertResult(result)); ERROR_LOG(IOS_ES, "Failed to create %s: error %d", directory.path, FS::ConvertResult(result));
// Now update the UID/GID and other attributes. // Now update the UID/GID and other attributes.
m_ios.GetFS()->SetMetadata(0, directory.path, directory.uid, directory.gid, directory.attribute, m_ios.GetFS()->SetMetadata(0, directory.path, directory.uid, directory.gid, directory.attribute,
directory.owner_mode, directory.group_mode, directory.other_mode); directory.modes);
} }
FinishAllStaleImports(); FinishAllStaleImports();
@ -623,9 +620,9 @@ static s32 WriteTmdForDiVerify(FS::FileSystem* fs, const IOS::ES::TMDReader& tmd
{ {
const std::string temp_path = "/tmp/title.tmd"; const std::string temp_path = "/tmp/title.tmd";
fs->Delete(PID_KERNEL, PID_KERNEL, temp_path); fs->Delete(PID_KERNEL, PID_KERNEL, temp_path);
constexpr FS::Modes internal_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None};
{ {
const auto file = fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, temp_path, FS::Mode::ReadWrite, const auto file = fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, temp_path, internal_modes);
FS::Mode::ReadWrite, FS::Mode::None);
if (!file) if (!file)
return FS::ConvertResult(file.Error()); return FS::ConvertResult(file.Error());
if (!file->Write(tmd.GetBytes().data(), tmd.GetBytes().size())) if (!file->Write(tmd.GetBytes().data(), tmd.GetBytes().size()))
@ -634,13 +631,12 @@ static s32 WriteTmdForDiVerify(FS::FileSystem* fs, const IOS::ES::TMDReader& tmd
const std::string tmd_dir = Common::GetTitleContentPath(tmd.GetTitleId()); const std::string tmd_dir = Common::GetTitleContentPath(tmd.GetTitleId());
const std::string tmd_path = Common::GetTMDFileName(tmd.GetTitleId()); const std::string tmd_path = Common::GetTMDFileName(tmd.GetTitleId());
const auto result = fs->CreateFullPath(PID_KERNEL, PID_KERNEL, tmd_path, 0, FS::Mode::ReadWrite, constexpr FS::Modes parent_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::Read};
FS::Mode::ReadWrite, FS::Mode::Read); const auto result = fs->CreateFullPath(PID_KERNEL, PID_KERNEL, tmd_path, 0, parent_modes);
if (result != FS::ResultCode::Success) if (result != FS::ResultCode::Success)
return FS::ConvertResult(result); return FS::ConvertResult(result);
fs->SetMetadata(PID_KERNEL, tmd_dir, PID_KERNEL, PID_KERNEL, 0, FS::Mode::ReadWrite, fs->SetMetadata(PID_KERNEL, tmd_dir, PID_KERNEL, PID_KERNEL, 0, internal_modes);
FS::Mode::ReadWrite, FS::Mode::None);
return FS::ConvertResult(fs->Rename(PID_KERNEL, PID_KERNEL, temp_path, tmd_path)); return FS::ConvertResult(fs->Rename(PID_KERNEL, PID_KERNEL, temp_path, tmd_path));
} }
@ -678,10 +674,10 @@ s32 ES::DIVerify(const IOS::ES::TMDReader& tmd, const IOS::ES::TicketReader& tic
const std::string data_dir = Common::GetTitleDataPath(tmd.GetTitleId()); const std::string data_dir = Common::GetTitleDataPath(tmd.GetTitleId());
// Might already exist, so we only need to check whether the second operation succeeded. // Might already exist, so we only need to check whether the second operation succeeded.
fs->CreateDirectory(PID_KERNEL, PID_KERNEL, data_dir, 0, FS::Mode::ReadWrite, FS::Mode::None, constexpr FS::Modes data_dir_modes{FS::Mode::ReadWrite, FS::Mode::None, FS::Mode::None};
FS::Mode::None); fs->CreateDirectory(PID_KERNEL, PID_KERNEL, data_dir, 0, data_dir_modes);
return FS::ConvertResult(fs->SetMetadata(0, data_dir, m_ios.GetUidForPPC(), m_ios.GetGidForPPC(), return FS::ConvertResult(
0, FS::Mode::ReadWrite, FS::Mode::None, FS::Mode::None)); fs->SetMetadata(0, data_dir, m_ios.GetUidForPPC(), m_ios.GetGidForPPC(), 0, data_dir_modes));
} }
ReturnCode ES::CheckStreamKeyPermissions(const u32 uid, const u8* ticket_view, ReturnCode ES::CheckStreamKeyPermissions(const u32 uid, const u8* ticket_view,
@ -877,8 +873,8 @@ ReturnCode ES::WriteNewCertToStore(const IOS::ES::CertReader& cert)
// Otherwise, write the new cert at the end of the store. // Otherwise, write the new cert at the end of the store.
const auto store_file = const auto store_file =
m_ios.GetFS()->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, CERT_STORE_PATH, FS::Mode::ReadWrite, m_ios.GetFS()->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, CERT_STORE_PATH,
FS::Mode::ReadWrite, FS::Mode::Read); {FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::Read});
if (!store_file || !store_file->Seek(0, FS::SeekMode::End) || if (!store_file || !store_file->Seek(0, FS::SeekMode::End) ||
!store_file->Write(cert.GetBytes().data(), cert.GetBytes().size())) !store_file->Write(cert.GetBytes().data(), cert.GetBytes().size()))
{ {

View File

@ -591,9 +591,9 @@ bool SharedContentMap::WriteEntries() const
const std::string temp_path = "/tmp/content.map"; const std::string temp_path = "/tmp/content.map";
// Atomically write the new content map. // Atomically write the new content map.
{ {
const auto file = constexpr HLE::FS::Modes modes{HLE::FS::Mode::ReadWrite, HLE::FS::Mode::ReadWrite,
m_fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, temp_path, HLE::FS::Mode::ReadWrite, HLE::FS::Mode::None};
HLE::FS::Mode::ReadWrite, HLE::FS::Mode::None); const auto file = m_fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, temp_path, modes);
if (!file || !file->Write(m_entries.data(), m_entries.size())) if (!file || !file->Write(m_entries.data(), m_entries.size()))
return false; return false;
} }
@ -665,9 +665,9 @@ u32 UIDSys::GetOrInsertUIDForTitle(const u64 title_id)
const u64 swapped_title_id = Common::swap64(title_id); const u64 swapped_title_id = Common::swap64(title_id);
const u32 swapped_uid = Common::swap32(uid); const u32 swapped_uid = Common::swap32(uid);
const auto file = constexpr HLE::FS::Modes modes{HLE::FS::Mode::ReadWrite, HLE::FS::Mode::ReadWrite,
m_fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, UID_MAP_PATH, HLE::FS::Mode::ReadWrite, HLE::FS::Mode::None};
HLE::FS::Mode::ReadWrite, HLE::FS::Mode::None); const auto file = m_fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, UID_MAP_PATH, modes);
if (!file || !file->Seek(0, HLE::FS::SeekMode::End) || !file->Write(&swapped_title_id, 1) || if (!file || !file->Seek(0, HLE::FS::SeekMode::End) || !file->Write(&swapped_title_id, 1) ||
!file->Write(&swapped_uid, 1)) !file->Write(&swapped_uid, 1))
{ {

View File

@ -222,15 +222,19 @@ static bool DeleteDirectoriesIfEmpty(FS::FileSystem* fs, const std::string& path
return true; return true;
} }
constexpr FS::Modes title_dir_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::Read};
constexpr FS::Modes content_dir_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None};
constexpr FS::Modes data_dir_modes{FS::Mode::ReadWrite, FS::Mode::None, FS::Mode::None};
bool ES::CreateTitleDirectories(u64 title_id, u16 group_id) const bool ES::CreateTitleDirectories(u64 title_id, u16 group_id) const
{ {
const auto fs = m_ios.GetFS(); const auto fs = m_ios.GetFS();
const std::string content_dir = Common::GetTitleContentPath(title_id); const std::string content_dir = Common::GetTitleContentPath(title_id);
const auto result1 = fs->CreateFullPath(PID_KERNEL, PID_KERNEL, content_dir + '/', 0, const auto result1 =
FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::Read); fs->CreateFullPath(PID_KERNEL, PID_KERNEL, content_dir + '/', 0, title_dir_modes);
const auto result2 = fs->SetMetadata(PID_KERNEL, content_dir, PID_KERNEL, PID_KERNEL, 0, const auto result2 =
FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None); fs->SetMetadata(PID_KERNEL, content_dir, PID_KERNEL, PID_KERNEL, 0, content_dir_modes);
if (result1 != FS::ResultCode::Success || result2 != FS::ResultCode::Success) if (result1 != FS::ResultCode::Success || result2 != FS::ResultCode::Success)
{ {
ERROR_LOG(IOS_ES, "Failed to create or set metadata on content dir for %016" PRIx64, title_id); ERROR_LOG(IOS_ES, "Failed to create or set metadata on content dir for %016" PRIx64, title_id);
@ -239,10 +243,9 @@ bool ES::CreateTitleDirectories(u64 title_id, u16 group_id) const
const std::string data_dir = Common::GetTitleDataPath(title_id); const std::string data_dir = Common::GetTitleDataPath(title_id);
const auto data_dir_contents = fs->ReadDirectory(PID_KERNEL, PID_KERNEL, data_dir); const auto data_dir_contents = fs->ReadDirectory(PID_KERNEL, PID_KERNEL, data_dir);
if (!data_dir_contents && if (!data_dir_contents && (data_dir_contents.Error() != FS::ResultCode::NotFound ||
(data_dir_contents.Error() != FS::ResultCode::NotFound || fs->CreateDirectory(PID_KERNEL, PID_KERNEL, data_dir, 0,
fs->CreateDirectory(PID_KERNEL, PID_KERNEL, data_dir, 0, FS::Mode::ReadWrite, FS::Mode::None, data_dir_modes) != FS::ResultCode::Success))
FS::Mode::None) != FS::ResultCode::Success))
{ {
ERROR_LOG(IOS_ES, "Failed to create data dir for %016" PRIx64, title_id); ERROR_LOG(IOS_ES, "Failed to create data dir for %016" PRIx64, title_id);
return false; return false;
@ -250,8 +253,7 @@ bool ES::CreateTitleDirectories(u64 title_id, u16 group_id) const
IOS::ES::UIDSys uid_sys{fs}; IOS::ES::UIDSys uid_sys{fs};
const u32 uid = uid_sys.GetOrInsertUIDForTitle(title_id); const u32 uid = uid_sys.GetOrInsertUIDForTitle(title_id);
if (fs->SetMetadata(0, data_dir, uid, group_id, 0, FS::Mode::ReadWrite, FS::Mode::None, if (fs->SetMetadata(0, data_dir, uid, group_id, 0, data_dir_modes) != FS::ResultCode::Success)
FS::Mode::None) != FS::ResultCode::Success)
{ {
ERROR_LOG(IOS_ES, "Failed to set metadata on data dir for %016" PRIx64, title_id); ERROR_LOG(IOS_ES, "Failed to set metadata on data dir for %016" PRIx64, title_id);
return false; return false;
@ -267,8 +269,8 @@ bool ES::InitImport(const IOS::ES::TMDReader& tmd)
const auto fs = m_ios.GetFS(); const auto fs = m_ios.GetFS();
const std::string import_content_dir = Common::GetImportTitlePath(tmd.GetTitleId()) + "/content"; const std::string import_content_dir = Common::GetImportTitlePath(tmd.GetTitleId()) + "/content";
const auto result = fs->CreateFullPath(PID_KERNEL, PID_KERNEL, import_content_dir + '/', 0, const auto result =
FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None); fs->CreateFullPath(PID_KERNEL, PID_KERNEL, import_content_dir + '/', 0, content_dir_modes);
if (result != FS::ResultCode::Success) if (result != FS::ResultCode::Success)
{ {
ERROR_LOG(IOS_ES, "InitImport: Failed to create content dir for %016" PRIx64, tmd.GetTitleId()); ERROR_LOG(IOS_ES, "InitImport: Failed to create content dir for %016" PRIx64, tmd.GetTitleId());
@ -330,8 +332,7 @@ bool ES::WriteImportTMD(const IOS::ES::TMDReader& tmd)
const auto fs = m_ios.GetFS(); const auto fs = m_ios.GetFS();
const std::string tmd_path = "/tmp/title.tmd"; const std::string tmd_path = "/tmp/title.tmd";
{ {
const auto file = fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, tmd_path, FS::Mode::ReadWrite, const auto file = fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, tmd_path, content_dir_modes);
FS::Mode::ReadWrite, FS::Mode::None);
if (!file || !file->Write(tmd.GetBytes().data(), tmd.GetBytes().size())) if (!file || !file->Write(tmd.GetBytes().data(), tmd.GetBytes().size()))
return false; return false;
} }

View File

@ -33,11 +33,9 @@ static ReturnCode WriteTicket(FS::FileSystem* fs, const IOS::ES::TicketReader& t
const u64 title_id = ticket.GetTitleId(); const u64 title_id = ticket.GetTitleId();
const std::string path = Common::GetTicketFileName(title_id); const std::string path = Common::GetTicketFileName(title_id);
fs->CreateFullPath(PID_KERNEL, PID_KERNEL, path, 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite, constexpr FS::Modes ticket_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None};
FS::Mode::None); fs->CreateFullPath(PID_KERNEL, PID_KERNEL, path, 0, ticket_modes);
const auto file = fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, path, ticket_modes);
const auto file = fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, path, FS::Mode::ReadWrite,
FS::Mode::ReadWrite, FS::Mode::None);
if (!file) if (!file)
return FS::ConvertResult(file.Error()); return FS::ConvertResult(file.Error());
@ -400,8 +398,8 @@ ReturnCode ES::ImportContentEnd(Context& context, u32 content_fd)
"/tmp/" + content_path.substr(content_path.find_last_of('/') + 1, std::string::npos); "/tmp/" + content_path.substr(content_path.find_last_of('/') + 1, std::string::npos);
{ {
const auto file = fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, temp_path, FS::Mode::ReadWrite, constexpr FS::Modes content_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::None};
FS::Mode::ReadWrite, FS::Mode::None); const auto file = fs->CreateAndOpenFile(PID_KERNEL, PID_KERNEL, temp_path, content_modes);
if (!file || !file->Write(decrypted_data.data(), content_info.size)) if (!file || !file->Write(decrypted_data.data(), content_info.size))
{ {
ERROR_LOG(IOS_ES, "ImportContentEnd: Failed to write to %s", temp_path.c_str()); ERROR_LOG(IOS_ES, "ImportContentEnd: Failed to write to %s", temp_path.c_str());

View File

@ -69,17 +69,17 @@ Result<FileStatus> FileHandle::GetStatus() const
void FileSystem::Init() void FileSystem::Init()
{ {
if (Delete(0, 0, "/tmp") == ResultCode::Success) if (Delete(0, 0, "/tmp") == ResultCode::Success)
CreateDirectory(0, 0, "/tmp", 0, Mode::ReadWrite, Mode::ReadWrite, Mode::ReadWrite); CreateDirectory(0, 0, "/tmp", 0, {Mode::ReadWrite, Mode::ReadWrite, Mode::ReadWrite});
} }
Result<FileHandle> FileSystem::CreateAndOpenFile(Uid uid, Gid gid, const std::string& path, Result<FileHandle> FileSystem::CreateAndOpenFile(Uid uid, Gid gid, const std::string& path,
Mode owner_mode, Mode group_mode, Mode other_mode) Modes modes)
{ {
Result<FileHandle> file = OpenFile(uid, gid, path, Mode::ReadWrite); Result<FileHandle> file = OpenFile(uid, gid, path, Mode::ReadWrite);
if (file.Succeeded()) if (file.Succeeded())
return file; return file;
const ResultCode result = CreateFile(uid, gid, path, 0, owner_mode, group_mode, other_mode); const ResultCode result = CreateFile(uid, gid, path, 0, modes);
if (result != ResultCode::Success) if (result != ResultCode::Success)
return result; return result;
@ -87,7 +87,7 @@ Result<FileHandle> FileSystem::CreateAndOpenFile(Uid uid, Gid gid, const std::st
} }
ResultCode FileSystem::CreateFullPath(Uid uid, Gid gid, const std::string& path, ResultCode FileSystem::CreateFullPath(Uid uid, Gid gid, const std::string& path,
FileAttribute attribute, Mode owner, Mode group, Mode other) FileAttribute attribute, Modes modes)
{ {
std::string::size_type position = 1; std::string::size_type position = 1;
while (true) while (true)
@ -103,7 +103,7 @@ ResultCode FileSystem::CreateFullPath(Uid uid, Gid gid, const std::string& path,
if (metadata && metadata->is_file) if (metadata && metadata->is_file)
return ResultCode::Invalid; return ResultCode::Invalid;
const ResultCode result = CreateDirectory(uid, gid, subpath, attribute, owner, group, other); const ResultCode result = CreateDirectory(uid, gid, subpath, attribute, modes);
if (result != ResultCode::Success && result != ResultCode::AlreadyExists) if (result != ResultCode::Success && result != ResultCode::AlreadyExists)
return result; return result;

View File

@ -67,12 +67,17 @@ enum class SeekMode : u32
using FileAttribute = u8; using FileAttribute = u8;
struct Modes
{
Mode owner, group, other;
};
struct Metadata struct Metadata
{ {
Uid uid; Uid uid;
Gid gid; Gid gid;
FileAttribute attribute; FileAttribute attribute;
Mode owner_mode, group_mode, other_mode; Modes modes;
bool is_file; bool is_file;
u32 size; u32 size;
u16 fst_index; u16 fst_index;
@ -142,8 +147,7 @@ public:
/// Get a file descriptor for accessing a file. The FD will be automatically closed after use. /// Get a file descriptor for accessing a file. The FD will be automatically closed after use.
virtual Result<FileHandle> OpenFile(Uid uid, Gid gid, const std::string& path, Mode mode) = 0; virtual Result<FileHandle> OpenFile(Uid uid, Gid gid, const std::string& path, Mode mode) = 0;
/// Create a file if it doesn't exist and open it in read/write mode. /// Create a file if it doesn't exist and open it in read/write mode.
Result<FileHandle> CreateAndOpenFile(Uid uid, Gid gid, const std::string& path, Mode owner_mode, Result<FileHandle> CreateAndOpenFile(Uid uid, Gid gid, const std::string& path, Modes modes);
Mode group_mode, Mode other_mode);
/// Close a file descriptor. /// Close a file descriptor.
virtual ResultCode Close(Fd fd) = 0; virtual ResultCode Close(Fd fd) = 0;
/// Read `size` bytes from the file descriptor. Returns the number of bytes read. /// Read `size` bytes from the file descriptor. Returns the number of bytes read.
@ -157,17 +161,15 @@ public:
/// Create a file with the specified path and metadata. /// Create a file with the specified path and metadata.
virtual ResultCode CreateFile(Uid caller_uid, Gid caller_gid, const std::string& path, virtual ResultCode CreateFile(Uid caller_uid, Gid caller_gid, const std::string& path,
FileAttribute attribute, Mode owner_mode, Mode group_mode, FileAttribute attribute, Modes modes) = 0;
Mode other_mode) = 0;
/// Create a directory with the specified path and metadata. /// Create a directory with the specified path and metadata.
virtual ResultCode CreateDirectory(Uid caller_uid, Gid caller_gid, const std::string& path, virtual ResultCode CreateDirectory(Uid caller_uid, Gid caller_gid, const std::string& path,
FileAttribute attribute, Mode owner_mode, Mode group_mode, FileAttribute attribute, Modes modes) = 0;
Mode other_mode) = 0;
/// Create any parent directories for a path with the specified metadata. /// Create any parent directories for a path with the specified metadata.
/// Example: "/a/b" to create directory /a; "/a/b/" to create directories /a and /a/b /// Example: "/a/b" to create directory /a; "/a/b/" to create directories /a and /a/b
ResultCode CreateFullPath(Uid caller_uid, Gid caller_gid, const std::string& path, ResultCode CreateFullPath(Uid caller_uid, Gid caller_gid, const std::string& path,
FileAttribute attribute, Mode ownerm, Mode group, Mode other); FileAttribute attribute, Modes modes);
/// Delete a file or directory with the specified path. /// Delete a file or directory with the specified path.
virtual ResultCode Delete(Uid caller_uid, Gid caller_gid, const std::string& path) = 0; virtual ResultCode Delete(Uid caller_uid, Gid caller_gid, const std::string& path) = 0;
@ -183,8 +185,7 @@ public:
virtual Result<Metadata> GetMetadata(Uid caller_uid, Gid caller_gid, const std::string& path) = 0; virtual Result<Metadata> GetMetadata(Uid caller_uid, Gid caller_gid, const std::string& path) = 0;
/// Set metadata for a file. /// Set metadata for a file.
virtual ResultCode SetMetadata(Uid caller_uid, const std::string& path, Uid uid, Gid gid, virtual ResultCode SetMetadata(Uid caller_uid, const std::string& path, Uid uid, Gid gid,
FileAttribute attribute, Mode owner_mode, Mode group_mode, FileAttribute attribute, Modes modes) = 0;
Mode other_mode) = 0;
/// Get usage information about the NAND (block size, cluster and inode counts). /// Get usage information about the NAND (block size, cluster and inode counts).
virtual Result<NandStats> GetNandStats() = 0; virtual Result<NandStats> GetNandStats() = 0;

View File

@ -282,9 +282,7 @@ struct ISFSParams
Common::BigEndianValue<Uid> uid; Common::BigEndianValue<Uid> uid;
Common::BigEndianValue<Gid> gid; Common::BigEndianValue<Gid> gid;
char path[64]; char path[64];
Mode owner_mode; Modes modes;
Mode group_mode;
Mode other_mode;
FileAttribute attribute; FileAttribute attribute;
}; };
@ -406,9 +404,8 @@ IPCCommandResult FS::CreateDirectory(const Handle& handle, const IOCtlRequest& r
if (!params) if (!params)
return GetFSReply(ConvertResult(params.Error())); return GetFSReply(ConvertResult(params.Error()));
const ResultCode result = const ResultCode result = m_ios.GetFS()->CreateDirectory(handle.uid, handle.gid, params->path,
m_ios.GetFS()->CreateDirectory(handle.uid, handle.gid, params->path, params->attribute, params->attribute, params->modes);
params->owner_mode, params->group_mode, params->other_mode);
LogResult(StringFromFormat("CreateDirectory(%s)", params->path), result); LogResult(StringFromFormat("CreateDirectory(%s)", params->path), result);
return GetReplyForSuperblockOperation(result); return GetReplyForSuperblockOperation(result);
} }
@ -474,8 +471,7 @@ IPCCommandResult FS::SetAttribute(const Handle& handle, const IOCtlRequest& requ
return GetFSReply(ConvertResult(params.Error())); return GetFSReply(ConvertResult(params.Error()));
const ResultCode result = m_ios.GetFS()->SetMetadata( const ResultCode result = m_ios.GetFS()->SetMetadata(
handle.uid, params->path, params->uid, params->gid, params->attribute, params->owner_mode, handle.uid, params->path, params->uid, params->gid, params->attribute, params->modes);
params->group_mode, params->other_mode);
LogResult(StringFromFormat("SetMetadata(%s)", params->path), result); LogResult(StringFromFormat("SetMetadata(%s)", params->path), result);
return GetReplyForSuperblockOperation(result); return GetReplyForSuperblockOperation(result);
} }
@ -499,9 +495,7 @@ IPCCommandResult FS::GetAttribute(const Handle& handle, const IOCtlRequest& requ
out.uid = metadata->uid; out.uid = metadata->uid;
out.gid = metadata->gid; out.gid = metadata->gid;
out.attribute = metadata->attribute; out.attribute = metadata->attribute;
out.owner_mode = metadata->owner_mode; out.modes = metadata->modes;
out.group_mode = metadata->group_mode;
out.other_mode = metadata->other_mode;
Memory::CopyToEmu(request.buffer_out, &out, sizeof(out)); Memory::CopyToEmu(request.buffer_out, &out, sizeof(out));
return GetFSReply(IPC_SUCCESS, ticks); return GetFSReply(IPC_SUCCESS, ticks);
} }
@ -535,9 +529,8 @@ IPCCommandResult FS::CreateFile(const Handle& handle, const IOCtlRequest& reques
if (!params) if (!params)
return GetFSReply(ConvertResult(params.Error())); return GetFSReply(ConvertResult(params.Error()));
const ResultCode result = const ResultCode result = m_ios.GetFS()->CreateFile(handle.uid, handle.gid, params->path,
m_ios.GetFS()->CreateFile(handle.uid, handle.gid, params->path, params->attribute, params->attribute, params->modes);
params->owner_mode, params->group_mode, params->other_mode);
LogResult(StringFromFormat("CreateFile(%s)", params->path), result); LogResult(StringFromFormat("CreateFile(%s)", params->path), result);
return GetReplyForSuperblockOperation(result); return GetReplyForSuperblockOperation(result);
} }

View File

@ -167,8 +167,7 @@ ResultCode HostFileSystem::Format(Uid uid)
return ResultCode::Success; return ResultCode::Success;
} }
ResultCode HostFileSystem::CreateFile(Uid, Gid, const std::string& path, FileAttribute attribute, ResultCode HostFileSystem::CreateFile(Uid, Gid, const std::string& path, FileAttribute, Modes)
Mode owner_mode, Mode group_mode, Mode other_mode)
{ {
std::string file_name(BuildFilename(path)); std::string file_name(BuildFilename(path));
// check if the file already exist // check if the file already exist
@ -186,9 +185,7 @@ ResultCode HostFileSystem::CreateFile(Uid, Gid, const std::string& path, FileAtt
return ResultCode::Success; return ResultCode::Success;
} }
ResultCode HostFileSystem::CreateDirectory(Uid, Gid, const std::string& path, ResultCode HostFileSystem::CreateDirectory(Uid, Gid, const std::string& path, FileAttribute, Modes)
FileAttribute attribute, Mode owner_mode,
Mode group_mode, Mode other_mode)
{ {
if (!IsValidWiiPath(path)) if (!IsValidWiiPath(path))
return ResultCode::Invalid; return ResultCode::Invalid;
@ -310,9 +307,7 @@ Result<Metadata> HostFileSystem::GetMetadata(Uid, Gid, const std::string& path)
return ResultCode::Invalid; return ResultCode::Invalid;
std::string file_name = BuildFilename(path); std::string file_name = BuildFilename(path);
metadata.owner_mode = Mode::ReadWrite; metadata.modes = {Mode::ReadWrite, Mode::ReadWrite, Mode::ReadWrite};
metadata.group_mode = Mode::ReadWrite;
metadata.other_mode = Mode::ReadWrite;
metadata.attribute = 0x00; // no attributes metadata.attribute = 0x00; // no attributes
// Hack: if the path that is being accessed is within an installed title directory, get the // Hack: if the path that is being accessed is within an installed title directory, get the
@ -335,8 +330,7 @@ Result<Metadata> HostFileSystem::GetMetadata(Uid, Gid, const std::string& path)
} }
ResultCode HostFileSystem::SetMetadata(Uid caller_uid, const std::string& path, Uid uid, Gid gid, ResultCode HostFileSystem::SetMetadata(Uid caller_uid, const std::string& path, Uid uid, Gid gid,
FileAttribute attribute, Mode owner_mode, Mode group_mode, FileAttribute, Modes)
Mode other_mode)
{ {
if (!IsValidWiiPath(path)) if (!IsValidWiiPath(path))
return ResultCode::Invalid; return ResultCode::Invalid;

View File

@ -38,12 +38,10 @@ public:
Result<FileStatus> GetFileStatus(Fd fd) override; Result<FileStatus> GetFileStatus(Fd fd) override;
ResultCode CreateFile(Uid caller_uid, Gid caller_gid, const std::string& path, ResultCode CreateFile(Uid caller_uid, Gid caller_gid, const std::string& path,
FileAttribute attribute, Mode owner_mode, Mode group_mode, FileAttribute attribute, Modes modes) override;
Mode other_mode) override;
ResultCode CreateDirectory(Uid caller_uid, Gid caller_gid, const std::string& path, ResultCode CreateDirectory(Uid caller_uid, Gid caller_gid, const std::string& path,
FileAttribute attribute, Mode owner_mode, Mode group_mode, FileAttribute attribute, Modes modes) override;
Mode other_mode) override;
ResultCode Delete(Uid caller_uid, Gid caller_gid, const std::string& path) override; ResultCode Delete(Uid caller_uid, Gid caller_gid, const std::string& path) override;
ResultCode Rename(Uid caller_uid, Gid caller_gid, const std::string& old_path, ResultCode Rename(Uid caller_uid, Gid caller_gid, const std::string& old_path,
@ -54,8 +52,7 @@ public:
Result<Metadata> GetMetadata(Uid caller_uid, Gid caller_gid, const std::string& path) override; Result<Metadata> GetMetadata(Uid caller_uid, Gid caller_gid, const std::string& path) override;
ResultCode SetMetadata(Uid caller_uid, const std::string& path, Uid uid, Gid gid, ResultCode SetMetadata(Uid caller_uid, const std::string& path, Uid uid, Gid gid,
FileAttribute attribute, Mode owner_mode, Mode group_mode, FileAttribute attribute, Modes modes) override;
Mode other_mode) override;
Result<NandStats> GetNandStats() override; Result<NandStats> GetNandStats() override;
Result<DirectoryStats> GetDirectoryStats(const std::string& path) override; Result<DirectoryStats> GetDirectoryStats(const std::string& path) override;

View File

@ -44,9 +44,9 @@ void NWC24Config::ReadConfig()
void NWC24Config::WriteConfig() const void NWC24Config::WriteConfig() const
{ {
constexpr FS::Mode rw_mode = FS::Mode::ReadWrite; constexpr FS::Modes public_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::ReadWrite};
m_fs->CreateFullPath(PID_KD, PID_KD, CONFIG_PATH, 0, rw_mode, rw_mode, rw_mode); m_fs->CreateFullPath(PID_KD, PID_KD, CONFIG_PATH, 0, public_modes);
const auto file = m_fs->CreateAndOpenFile(PID_KD, PID_KD, CONFIG_PATH, rw_mode, rw_mode, rw_mode); const auto file = m_fs->CreateAndOpenFile(PID_KD, PID_KD, CONFIG_PATH, public_modes);
if (!file || !file->Write(&m_data, 1)) if (!file || !file->Write(&m_data, 1))
ERROR_LOG(IOS_WC24, "Failed to open or write WC24 config file"); ERROR_LOG(IOS_WC24, "Failed to open or write WC24 config file");
} }

View File

@ -36,10 +36,9 @@ void WiiNetConfig::ReadConfig(FS::FileSystem* fs)
void WiiNetConfig::WriteConfig(FS::FileSystem* fs) const void WiiNetConfig::WriteConfig(FS::FileSystem* fs) const
{ {
fs->CreateFullPath(PID_NCD, PID_NCD, CONFIG_PATH, 0, FS::Mode::ReadWrite, FS::Mode::ReadWrite, constexpr FS::Modes public_modes{FS::Mode::ReadWrite, FS::Mode::ReadWrite, FS::Mode::ReadWrite};
FS::Mode::ReadWrite); fs->CreateFullPath(PID_NCD, PID_NCD, CONFIG_PATH, 0, public_modes);
const auto file = fs->CreateAndOpenFile(PID_NCD, PID_NCD, CONFIG_PATH, FS::Mode::ReadWrite, const auto file = fs->CreateAndOpenFile(PID_NCD, PID_NCD, CONFIG_PATH, public_modes);
FS::Mode::ReadWrite, FS::Mode::ReadWrite);
if (!file || !file->Write(&m_data, 1)) if (!file || !file->Write(&m_data, 1))
ERROR_LOG(IOS_NET, "Failed to write config"); ERROR_LOG(IOS_NET, "Failed to write config");
} }

View File

@ -199,13 +199,13 @@ bool SysConf::Save() const
const std::string temp_file = "/tmp/SYSCONF"; const std::string temp_file = "/tmp/SYSCONF";
constexpr auto rw_mode = IOS::HLE::FS::Mode::ReadWrite; constexpr auto rw_mode = IOS::HLE::FS::Mode::ReadWrite;
{ {
auto file = m_fs->CreateAndOpenFile(IOS::SYSMENU_UID, IOS::SYSMENU_GID, temp_file, rw_mode, auto file = m_fs->CreateAndOpenFile(IOS::SYSMENU_UID, IOS::SYSMENU_GID, temp_file,
rw_mode, rw_mode); {rw_mode, rw_mode, rw_mode});
if (!file || !file->Write(buffer.data(), buffer.size())) if (!file || !file->Write(buffer.data(), buffer.size()))
return false; return false;
} }
m_fs->CreateDirectory(IOS::SYSMENU_UID, IOS::SYSMENU_GID, "/shared2/sys", 0, rw_mode, rw_mode, m_fs->CreateDirectory(IOS::SYSMENU_UID, IOS::SYSMENU_GID, "/shared2/sys", 0,
rw_mode); {rw_mode, rw_mode, rw_mode});
const auto result = const auto result =
m_fs->Rename(IOS::SYSMENU_UID, IOS::SYSMENU_GID, temp_file, "/shared2/sys/SYSCONF"); m_fs->Rename(IOS::SYSMENU_UID, IOS::SYSMENU_GID, temp_file, "/shared2/sys/SYSCONF");
return result == IOS::HLE::FS::ResultCode::Success; return result == IOS::HLE::FS::ResultCode::Success;

View File

@ -96,12 +96,11 @@ static bool CopySysmenuFilesToFS(IOS::HLE::FS::FileSystem* fs, const std::string
const std::string host_path = host_source_path + '/' + entry.virtualName; const std::string host_path = host_source_path + '/' + entry.virtualName;
const std::string nand_path = nand_target_path + '/' + entry.virtualName; const std::string nand_path = nand_target_path + '/' + entry.virtualName;
constexpr IOS::HLE::FS::Mode rw_mode = IOS::HLE::FS::Mode::ReadWrite; constexpr IOS::HLE::FS::Mode rw_mode = IOS::HLE::FS::Mode::ReadWrite;
constexpr IOS::HLE::FS::Modes public_modes{rw_mode, rw_mode, rw_mode};
if (entry.isDirectory) if (entry.isDirectory)
{ {
fs->CreateDirectory(IOS::SYSMENU_UID, IOS::SYSMENU_GID, nand_path, 0, rw_mode, rw_mode, fs->CreateDirectory(IOS::SYSMENU_UID, IOS::SYSMENU_GID, nand_path, 0, public_modes);
rw_mode);
if (!CopySysmenuFilesToFS(fs, host_path, nand_path)) if (!CopySysmenuFilesToFS(fs, host_path, nand_path))
return false; return false;
} }
@ -116,8 +115,8 @@ static bool CopySysmenuFilesToFS(IOS::HLE::FS::FileSystem* fs, const std::string
if (!host_file.ReadBytes(file_data.data(), file_data.size())) if (!host_file.ReadBytes(file_data.data(), file_data.size()))
return false; return false;
const auto nand_file = fs->CreateAndOpenFile(IOS::SYSMENU_UID, IOS::SYSMENU_GID, nand_path, const auto nand_file =
rw_mode, rw_mode, rw_mode); fs->CreateAndOpenFile(IOS::SYSMENU_UID, IOS::SYSMENU_GID, nand_path, public_modes);
if (!nand_file || !nand_file->Write(file_data.data(), file_data.size())) if (!nand_file || !nand_file->Write(file_data.data(), file_data.size()))
return false; return false;
} }

View File

@ -16,6 +16,8 @@
using namespace IOS::HLE::FS; using namespace IOS::HLE::FS;
constexpr Modes modes{Mode::ReadWrite, Mode::None, Mode::None};
class FileSystemTest : public testing::Test class FileSystemTest : public testing::Test
{ {
protected: protected:
@ -50,8 +52,7 @@ TEST_F(FileSystemTest, CreateFile)
{ {
const std::string PATH = "/tmp/f"; const std::string PATH = "/tmp/f";
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, PATH, 0, Mode::Read, Mode::None, Mode::None), ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, PATH, 0, modes), ResultCode::Success);
ResultCode::Success);
const Result<Metadata> stats = m_fs->GetMetadata(Uid{0}, Gid{0}, PATH); const Result<Metadata> stats = m_fs->GetMetadata(Uid{0}, Gid{0}, PATH);
ASSERT_TRUE(stats.Succeeded()); ASSERT_TRUE(stats.Succeeded());
@ -60,8 +61,7 @@ TEST_F(FileSystemTest, CreateFile)
// TODO: After we start saving metadata correctly, check the UID, GID, permissions // TODO: After we start saving metadata correctly, check the UID, GID, permissions
// as well (issue 10234). // as well (issue 10234).
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, PATH, 0, Mode::Read, Mode::None, Mode::None), ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, PATH, 0, modes), ResultCode::AlreadyExists);
ResultCode::AlreadyExists);
const Result<std::vector<std::string>> tmp_files = m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp"); const Result<std::vector<std::string>> tmp_files = m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp");
ASSERT_TRUE(tmp_files.Succeeded()); ASSERT_TRUE(tmp_files.Succeeded());
@ -72,8 +72,7 @@ TEST_F(FileSystemTest, CreateDirectory)
{ {
const std::string PATH = "/tmp/d"; const std::string PATH = "/tmp/d";
ASSERT_EQ(m_fs->CreateDirectory(Uid{0}, Gid{0}, PATH, 0, Mode::Read, Mode::None, Mode::None), ASSERT_EQ(m_fs->CreateDirectory(Uid{0}, Gid{0}, PATH, 0, modes), ResultCode::Success);
ResultCode::Success);
const Result<Metadata> stats = m_fs->GetMetadata(Uid{0}, Gid{0}, PATH); const Result<Metadata> stats = m_fs->GetMetadata(Uid{0}, Gid{0}, PATH);
ASSERT_TRUE(stats.Succeeded()); ASSERT_TRUE(stats.Succeeded());
@ -112,15 +111,9 @@ TEST_F(FileSystemTest, RenameWithExistingTargetDirectory)
// Test directory -> existing, non-empty directory. // Test directory -> existing, non-empty directory.
// IOS's FS sysmodule is not POSIX compliant and will remove the existing directory // IOS's FS sysmodule is not POSIX compliant and will remove the existing directory
// if it exists, even when there are files in it. // if it exists, even when there are files in it.
ASSERT_EQ( ASSERT_EQ(m_fs->CreateDirectory(Uid{0}, Gid{0}, "/tmp/d", 0, modes), ResultCode::Success);
m_fs->CreateDirectory(Uid{0}, Gid{0}, "/tmp/d", 0, Mode::ReadWrite, Mode::None, Mode::None), ASSERT_EQ(m_fs->CreateDirectory(Uid{0}, Gid{0}, "/tmp/d2", 0, modes), ResultCode::Success);
ResultCode::Success); ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/d2/file", 0, modes), ResultCode::Success);
ASSERT_EQ(
m_fs->CreateDirectory(Uid{0}, Gid{0}, "/tmp/d2", 0, Mode::ReadWrite, Mode::None, Mode::None),
ResultCode::Success);
ASSERT_EQ(
m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/d2/file", 0, Mode::ReadWrite, Mode::None, Mode::None),
ResultCode::Success);
EXPECT_EQ(m_fs->Rename(Uid{0}, Gid{0}, "/tmp/d", "/tmp/d2"), ResultCode::Success); EXPECT_EQ(m_fs->Rename(Uid{0}, Gid{0}, "/tmp/d", "/tmp/d2"), ResultCode::Success);
EXPECT_EQ(m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp/d").Error(), ResultCode::NotFound); EXPECT_EQ(m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp/d").Error(), ResultCode::NotFound);
@ -132,8 +125,7 @@ TEST_F(FileSystemTest, RenameWithExistingTargetDirectory)
TEST_F(FileSystemTest, RenameWithExistingTargetFile) TEST_F(FileSystemTest, RenameWithExistingTargetFile)
{ {
// Create the test source file and write some data (so that we can check its size later on). // Create the test source file and write some data (so that we can check its size later on).
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f1", 0, Mode::ReadWrite, Mode::None, Mode::None), ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f1", 0, modes), ResultCode::Success);
ResultCode::Success);
const std::vector<u8> TEST_DATA{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; const std::vector<u8> TEST_DATA{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};
std::vector<u8> read_buffer(TEST_DATA.size()); std::vector<u8> read_buffer(TEST_DATA.size());
{ {
@ -143,8 +135,7 @@ TEST_F(FileSystemTest, RenameWithExistingTargetFile)
} }
// Create the test target file and leave it empty. // Create the test target file and leave it empty.
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f2", 0, Mode::ReadWrite, Mode::None, Mode::None), ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f2", 0, modes), ResultCode::Success);
ResultCode::Success);
// Rename f1 to f2 and check that f1 replaced f2. // Rename f1 to f2 and check that f1 replaced f2.
EXPECT_EQ(m_fs->Rename(Uid{0}, Gid{0}, "/tmp/f1", "/tmp/f2"), ResultCode::Success); EXPECT_EQ(m_fs->Rename(Uid{0}, Gid{0}, "/tmp/f1", "/tmp/f2"), ResultCode::Success);
@ -169,8 +160,7 @@ TEST_F(FileSystemTest, GetDirectoryStats)
check_stats(0u, 1u); check_stats(0u, 1u);
EXPECT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/file", 0, Mode::Read, Mode::None, Mode::None), EXPECT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/file", 0, modes), ResultCode::Success);
ResultCode::Success);
// Still no clusters (because the file is empty), but 2 inodes now. // Still no clusters (because the file is empty), but 2 inodes now.
check_stats(0u, 2u); check_stats(0u, 2u);
@ -204,8 +194,7 @@ TEST_F(FileSystemTest, Seek)
{ {
const std::vector<u8> TEST_DATA(10); const std::vector<u8> TEST_DATA(10);
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, Mode::ReadWrite, Mode::None, Mode::None), ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, modes), ResultCode::Success);
ResultCode::Success);
const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite); const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite);
ASSERT_TRUE(file.Succeeded()); ASSERT_TRUE(file.Succeeded());
@ -244,8 +233,7 @@ TEST_F(FileSystemTest, WriteAndSimpleReadback)
const std::vector<u8> TEST_DATA{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; const std::vector<u8> TEST_DATA{{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}};
std::vector<u8> read_buffer(TEST_DATA.size()); std::vector<u8> read_buffer(TEST_DATA.size());
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, Mode::ReadWrite, Mode::None, Mode::None), ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, modes), ResultCode::Success);
ResultCode::Success);
const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite); const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite);
ASSERT_TRUE(file.Succeeded()); ASSERT_TRUE(file.Succeeded());
@ -264,8 +252,7 @@ TEST_F(FileSystemTest, WriteAndRead)
const std::vector<u8> TEST_DATA{{0xf, 1, 2, 3, 4, 5, 6, 7, 8, 9}}; const std::vector<u8> TEST_DATA{{0xf, 1, 2, 3, 4, 5, 6, 7, 8, 9}};
std::vector<u8> buffer(TEST_DATA.size()); std::vector<u8> buffer(TEST_DATA.size());
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, Mode::ReadWrite, Mode::None, Mode::None), ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, modes), ResultCode::Success);
ResultCode::Success);
Result<FileHandle> tmp_handle = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite); Result<FileHandle> tmp_handle = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite);
ASSERT_TRUE(tmp_handle.Succeeded()); ASSERT_TRUE(tmp_handle.Succeeded());
@ -298,8 +285,7 @@ TEST_F(FileSystemTest, WriteAndRead)
TEST_F(FileSystemTest, MultipleHandles) TEST_F(FileSystemTest, MultipleHandles)
{ {
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, Mode::ReadWrite, Mode::None, Mode::None), ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, modes), ResultCode::Success);
ResultCode::Success);
{ {
const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite); const Result<FileHandle> file = m_fs->OpenFile(Uid{0}, Gid{0}, "/tmp/f", Mode::ReadWrite);
@ -333,8 +319,7 @@ TEST_F(FileSystemTest, MultipleHandles)
// If it is not a file, ResultCode::Invalid must be returned. // If it is not a file, ResultCode::Invalid must be returned.
TEST_F(FileSystemTest, ReadDirectoryOnFile) TEST_F(FileSystemTest, ReadDirectoryOnFile)
{ {
ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, Mode::Read, Mode::None, Mode::None), ASSERT_EQ(m_fs->CreateFile(Uid{0}, Gid{0}, "/tmp/f", 0, modes), ResultCode::Success);
ResultCode::Success);
const Result<std::vector<std::string>> result = m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp/f"); const Result<std::vector<std::string>> result = m_fs->ReadDirectory(Uid{0}, Gid{0}, "/tmp/f");
ASSERT_FALSE(result.Succeeded()); ASSERT_FALSE(result.Succeeded());