diff options
Diffstat (limited to 'src/core')
54 files changed, 637 insertions, 696 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 826a00ad6..c5004b7b4 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -6,7 +6,7 @@ #include <memory> #include <utility> -#include "common/file_util.h" +#include "common/fs/fs.h" #include "common/logging/log.h" #include "common/microprofile.h" #include "common/settings.h" @@ -121,7 +121,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, dir->GetName()); } - if (Common::FS::IsDirectory(path)) { + if (Common::FS::IsDir(path)) { return vfs->OpenFile(path + "/main", FileSys::Mode::Read); } diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index a4b739c63..fb451a423 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -18,8 +18,9 @@ #include <mbedtls/cmac.h> #include <mbedtls/sha256.h> #include "common/common_funcs.h" -#include "common/common_paths.h" -#include "common/file_util.h" +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "common/hex_util.h" #include "common/logging/log.h" #include "common/settings.h" @@ -325,46 +326,55 @@ Key128 DeriveKeyblobMACKey(const Key128& keyblob_key, const Key128& mac_source) } std::optional<Key128> DeriveSDSeed() { - const Common::FS::IOFile save_43(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) + - "/system/save/8000000000000043", - "rb+"); + const auto system_save_43_path = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/8000000000000043"; + const Common::FS::IOFile save_43{system_save_43_path, Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile}; + if (!save_43.IsOpen()) { return std::nullopt; } - const Common::FS::IOFile sd_private(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir) + - "/Nintendo/Contents/private", - "rb+"); + const auto sd_private_path = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::SDMCDir) / "Nintendo/Contents/private"; + + const Common::FS::IOFile sd_private{sd_private_path, Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile}; + if (!sd_private.IsOpen()) { return std::nullopt; } std::array<u8, 0x10> private_seed{}; - if (sd_private.ReadBytes(private_seed.data(), private_seed.size()) != private_seed.size()) { + if (sd_private.Read(private_seed) != private_seed.size()) { return std::nullopt; } std::array<u8, 0x10> buffer{}; - std::size_t offset = 0; - for (; offset + 0x10 < save_43.GetSize(); ++offset) { - if (!save_43.Seek(offset, SEEK_SET)) { + s64 offset = 0; + for (; offset + 0x10 < static_cast<s64>(save_43.GetSize()); ++offset) { + if (!save_43.Seek(offset)) { + return std::nullopt; + } + + if (save_43.Read(buffer) != buffer.size()) { return std::nullopt; } - save_43.ReadBytes(buffer.data(), buffer.size()); if (buffer == private_seed) { break; } } - if (!save_43.Seek(offset + 0x10, SEEK_SET)) { + if (!save_43.Seek(offset + 0x10)) { return std::nullopt; } Key128 seed{}; - if (save_43.ReadBytes(seed.data(), seed.size()) != seed.size()) { + if (save_43.Read(seed) != seed.size()) { return std::nullopt; } + return seed; } @@ -435,7 +445,7 @@ std::vector<Ticket> GetTicketblob(const Common::FS::IOFile& ticket_save) { } std::vector<u8> buffer(ticket_save.GetSize()); - if (ticket_save.ReadBytes(buffer.data(), buffer.size()) != buffer.size()) { + if (ticket_save.Read(buffer) != buffer.size()) { return {}; } @@ -566,27 +576,26 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket, KeyManager::KeyManager() { // Initialize keys - const std::string hactool_keys_dir = Common::FS::GetHactoolConfigurationPath(); - const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir); + const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir); - if (!Common::FS::Exists(yuzu_keys_dir)) { - Common::FS::CreateDir(yuzu_keys_dir); + if (!Common::FS::CreateDir(yuzu_keys_dir)) { + LOG_ERROR(Core, "Failed to create the keys directory."); } if (Settings::values.use_dev_keys) { dev_mode = true; - AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "dev.keys", false); - AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "dev.keys_autogenerated", false); + LoadFromFile(yuzu_keys_dir / "dev.keys", false); + LoadFromFile(yuzu_keys_dir / "dev.keys_autogenerated", false); } else { dev_mode = false; - AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "prod.keys", false); - AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "prod.keys_autogenerated", false); + LoadFromFile(yuzu_keys_dir / "prod.keys", false); + LoadFromFile(yuzu_keys_dir / "prod.keys_autogenerated", false); } - AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "title.keys", true); - AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "title.keys_autogenerated", true); - AttemptLoadKeyFile(yuzu_keys_dir, hactool_keys_dir, "console.keys", false); - AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, "console.keys_autogenerated", false); + LoadFromFile(yuzu_keys_dir / "title.keys", true); + LoadFromFile(yuzu_keys_dir / "title.keys_autogenerated", true); + LoadFromFile(yuzu_keys_dir / "console.keys", false); + LoadFromFile(yuzu_keys_dir / "console.keys_autogenerated", false); } static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_t length) { @@ -597,9 +606,14 @@ static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_ [](u8 c) { return std::isxdigit(c); }); } -void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { +void KeyManager::LoadFromFile(const std::filesystem::path& file_path, bool is_title_keys) { + if (!Common::FS::Exists(file_path)) { + return; + } + std::ifstream file; - Common::FS::OpenFStream(file, filename, std::ios_base::in); + Common::FS::OpenFileStream(file, file_path, std::ios_base::in); + if (!file.is_open()) { return; } @@ -694,15 +708,6 @@ void KeyManager::LoadFromFile(const std::string& filename, bool is_title_keys) { } } -void KeyManager::AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2, - const std::string& filename, bool title) { - if (Common::FS::Exists(dir1 + DIR_SEP + filename)) { - LoadFromFile(dir1 + DIR_SEP + filename, title); - } else if (Common::FS::Exists(dir2 + DIR_SEP + filename)) { - LoadFromFile(dir2 + DIR_SEP + filename, title); - } -} - bool KeyManager::BaseDeriveNecessary() const { const auto check_key_existence = [this](auto key_type, u64 index1 = 0, u64 index2 = 0) { return !HasKey(key_type, index1, index2); @@ -766,30 +771,35 @@ Key256 KeyManager::GetBISKey(u8 partition_id) const { template <size_t Size> void KeyManager::WriteKeyToFile(KeyCategory category, std::string_view keyname, const std::array<u8, Size>& key) { - const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir); + const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir); + std::string filename = "title.keys_autogenerated"; + if (category == KeyCategory::Standard) { filename = dev_mode ? "dev.keys_autogenerated" : "prod.keys_autogenerated"; } else if (category == KeyCategory::Console) { filename = "console.keys_autogenerated"; } - const auto path = yuzu_keys_dir + DIR_SEP + filename; + const auto path = yuzu_keys_dir / filename; const auto add_info_text = !Common::FS::Exists(path); - Common::FS::CreateFullPath(path); - Common::FS::IOFile file{path, "a"}; + + Common::FS::IOFile file{path, Common::FS::FileAccessMode::Append, + Common::FS::FileType::TextFile}; + if (!file.IsOpen()) { return; } + if (add_info_text) { - file.WriteString( + void(file.WriteString( "# This file is autogenerated by Yuzu\n" "# It serves to store keys that were automatically generated from the normal keys\n" - "# If you are experiencing issues involving keys, it may help to delete this file\n"); + "# If you are experiencing issues involving keys, it may help to delete this file\n")); } - file.WriteString(fmt::format("\n{} = {}", keyname, Common::HexToString(key))); - AttemptLoadKeyFile(yuzu_keys_dir, yuzu_keys_dir, filename, category == KeyCategory::Title); + void(file.WriteString(fmt::format("\n{} = {}", keyname, Common::HexToString(key)))); + LoadFromFile(path, category == KeyCategory::Title); } void KeyManager::SetKey(S128KeyType id, Key128 key, u64 field1, u64 field2) { @@ -861,20 +871,17 @@ void KeyManager::SetKey(S256KeyType id, Key256 key, u64 field1, u64 field2) { } bool KeyManager::KeyFileExists(bool title) { - const std::string hactool_keys_dir = Common::FS::GetHactoolConfigurationPath(); - const std::string yuzu_keys_dir = Common::FS::GetUserPath(Common::FS::UserPath::KeysDir); + const auto yuzu_keys_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::KeysDir); + if (title) { - return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "title.keys") || - Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "title.keys"); + return Common::FS::Exists(yuzu_keys_dir / "title.keys"); } if (Settings::values.use_dev_keys) { - return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "dev.keys") || - Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "dev.keys"); + return Common::FS::Exists(yuzu_keys_dir / "dev.keys"); } - return Common::FS::Exists(hactool_keys_dir + DIR_SEP + "prod.keys") || - Common::FS::Exists(yuzu_keys_dir + DIR_SEP + "prod.keys"); + return Common::FS::Exists(yuzu_keys_dir / "prod.keys"); } void KeyManager::DeriveSDSeedLazy() { @@ -1115,15 +1122,21 @@ void KeyManager::PopulateTickets() { return; } - const Common::FS::IOFile save1(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) + - "/system/save/80000000000000e1", - "rb+"); - const Common::FS::IOFile save2(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) + - "/system/save/80000000000000e2", - "rb+"); + const auto system_save_e1_path = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/80000000000000e1"; + + const Common::FS::IOFile save_e1{system_save_e1_path, Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile}; + + const auto system_save_e2_path = + Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / "system/save/80000000000000e2"; + + const Common::FS::IOFile save_e2{system_save_e2_path, Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile}; + + const auto blob2 = GetTicketblob(save_e2); + auto res = GetTicketblob(save_e1); - const auto blob2 = GetTicketblob(save2); - auto res = GetTicketblob(save1); const auto idx = res.size(); res.insert(res.end(), blob2.begin(), blob2.end()); diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index 0a7220286..e771625e1 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h @@ -5,6 +5,7 @@ #pragma once #include <array> +#include <filesystem> #include <map> #include <optional> #include <string> @@ -283,9 +284,8 @@ private: std::array<u8, 576> eticket_extended_kek{}; bool dev_mode; - void LoadFromFile(const std::string& filename, bool is_title_keys); - void AttemptLoadKeyFile(const std::string& dir1, const std::string& dir2, - const std::string& filename, bool title); + void LoadFromFile(const std::filesystem::path& file_path, bool is_title_keys); + template <size_t Size> void WriteKeyToFile(KeyCategory category, std::string_view keyname, const std::array<u8, Size>& key); diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp index 7c6304ff0..f3891acf1 100644 --- a/src/core/file_sys/bis_factory.cpp +++ b/src/core/file_sys/bis_factory.cpp @@ -3,7 +3,7 @@ // Refer to the license.txt file included. #include <fmt/format.h> -#include "common/file_util.h" +#include "common/fs/path_util.h" #include "core/file_sys/bis_factory.h" #include "core/file_sys/mode.h" #include "core/file_sys/registered_cache.h" @@ -85,7 +85,7 @@ VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id, VirtualFilesystem file_system) const { auto& keys = Core::Crypto::KeyManager::Instance(); Core::Crypto::PartitionDataManager pdm{file_system->OpenDirectory( - Common::FS::GetUserPath(Common::FS::UserPath::SysDataDir), Mode::Read)}; + Common::FS::GetYuzuPathString(Common::FS::YuzuPath::NANDDir), Mode::Read)}; keys.PopulateFromPartitionData(pdm); switch (id) { diff --git a/src/core/file_sys/mode.h b/src/core/file_sys/mode.h index 2b4f21073..6c49a64e2 100644 --- a/src/core/file_sys/mode.h +++ b/src/core/file_sys/mode.h @@ -10,11 +10,13 @@ namespace FileSys { enum class Mode : u32 { - Read = 1, - Write = 2, + Read = 1 << 0, + Write = 1 << 1, ReadWrite = Read | Write, - Append = 4, + Append = 1 << 2, + ReadAppend = Read | Append, WriteAppend = Write | Append, + All = ReadWrite | Append, }; DECLARE_ENUM_FLAG_OPERATORS(Mode) diff --git a/src/core/file_sys/partition_filesystem.cpp b/src/core/file_sys/partition_filesystem.cpp index 48a2ed4d4..c5967049e 100644 --- a/src/core/file_sys/partition_filesystem.cpp +++ b/src/core/file_sys/partition_filesystem.cpp @@ -8,7 +8,6 @@ #include <iterator> #include <utility> -#include "common/file_util.h" #include "common/logging/log.h" #include "core/file_sys/partition_filesystem.h" #include "core/file_sys/vfs_offset.h" diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index cc9b4b637..53b8b7ca0 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -7,7 +7,6 @@ #include <cstddef> #include <cstring> -#include "common/file_util.h" #include "common/hex_util.h" #include "common/logging/log.h" #include "common/settings.h" diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index b0cb65952..066c6789a 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp @@ -7,7 +7,7 @@ #include <regex> #include <mbedtls/sha256.h> #include "common/assert.h" -#include "common/file_util.h" +#include "common/fs/path_util.h" #include "common/hex_util.h" #include "common/logging/log.h" #include "core/crypto/key_manager.h" diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index f497e9396..215e1cb1a 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp @@ -5,8 +5,7 @@ #include <algorithm> #include <numeric> #include <string> -#include "common/common_paths.h" -#include "common/file_util.h" +#include "common/fs/path_util.h" #include "common/logging/backend.h" #include "core/file_sys/mode.h" #include "core/file_sys/vfs.h" @@ -122,15 +121,14 @@ VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_ return nullptr; for (const auto& file : old_dir->GetFiles()) { - const auto x = - CopyFile(old_path + DIR_SEP + file->GetName(), new_path + DIR_SEP + file->GetName()); + const auto x = CopyFile(old_path + '/' + file->GetName(), new_path + '/' + file->GetName()); if (x == nullptr) return nullptr; } for (const auto& dir : old_dir->GetSubdirectories()) { const auto x = - CopyDirectory(old_path + DIR_SEP + dir->GetName(), new_path + DIR_SEP + dir->GetName()); + CopyDirectory(old_path + '/' + dir->GetName(), new_path + '/' + dir->GetName()); if (x == nullptr) return nullptr; } diff --git a/src/core/file_sys/vfs_libzip.cpp b/src/core/file_sys/vfs_libzip.cpp index 618eb658a..cd162c0c3 100644 --- a/src/core/file_sys/vfs_libzip.cpp +++ b/src/core/file_sys/vfs_libzip.cpp @@ -13,6 +13,7 @@ #pragma GCC diagnostic pop #endif +#include "common/fs/path_util.h" #include "common/logging/backend.h" #include "core/file_sys/vfs.h" #include "core/file_sys/vfs_libzip.h" diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 3d89dd644..d0b8fd046 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp @@ -7,8 +7,9 @@ #include <iterator> #include <utility> #include "common/assert.h" -#include "common/common_paths.h" -#include "common/file_util.h" +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "common/logging/log.h" #include "core/file_sys/vfs_real.h" @@ -16,33 +17,31 @@ namespace FileSys { namespace FS = Common::FS; -static std::string ModeFlagsToString(Mode mode) { - std::string mode_str; - - // Calculate the correct open mode for the file. - if (True(mode & Mode::Read) && True(mode & Mode::Write)) { - if (True(mode & Mode::Append)) { - mode_str = "a+"; - } else { - mode_str = "r+"; - } - } else { - if (True(mode & Mode::Read)) { - mode_str = "r"; - } else if (True(mode & Mode::Append)) { - mode_str = "a"; - } else if (True(mode & Mode::Write)) { - mode_str = "w"; - } else { - UNREACHABLE_MSG("Invalid file open mode: {:02X}", static_cast<u8>(mode)); - } +namespace { + +constexpr FS::FileAccessMode ModeFlagsToFileAccessMode(Mode mode) { + switch (mode) { + case Mode::Read: + return FS::FileAccessMode::Read; + case Mode::Write: + return FS::FileAccessMode::Write; + case Mode::ReadWrite: + return FS::FileAccessMode::ReadWrite; + case Mode::Append: + return FS::FileAccessMode::Append; + case Mode::ReadAppend: + return FS::FileAccessMode::ReadAppend; + case Mode::WriteAppend: + return FS::FileAccessMode::Append; + case Mode::All: + return FS::FileAccessMode::ReadAppend; + default: + return {}; } - - mode_str += "b"; - - return mode_str; } +} // Anonymous namespace + RealVfsFilesystem::RealVfsFilesystem() : VfsFilesystem(nullptr) {} RealVfsFilesystem::~RealVfsFilesystem() = default; @@ -63,7 +62,7 @@ VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const { if (!FS::Exists(path)) { return VfsEntryType::None; } - if (FS::IsDirectory(path)) { + if (FS::IsDir(path)) { return VfsEntryType::Directory; } @@ -81,12 +80,13 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { } } - if (!FS::Exists(path) && True(perms & Mode::WriteAppend)) { - FS::CreateEmptyFile(path); + auto backing = FS::FileOpen(path, ModeFlagsToFileAccessMode(perms), FS::FileType::BinaryFile); + + if (!backing) { + return nullptr; } - auto backing = std::make_shared<FS::IOFile>(path, ModeFlagsToString(perms).c_str()); - cache.insert_or_assign(path, backing); + cache.insert_or_assign(path, std::move(backing)); // Cannot use make_shared as RealVfsFile constructor is private return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, backing, path, perms)); @@ -94,25 +94,29 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); - const auto path_fwd = FS::SanitizePath(path, FS::DirectorySeparator::ForwardSlash); - if (!FS::Exists(path)) { - FS::CreateFullPath(path_fwd); - if (!FS::CreateEmptyFile(path)) { + // Current usages of CreateFile expect to delete the contents of an existing file. + if (FS::IsFile(path)) { + FS::IOFile temp{path, FS::FileAccessMode::Write, FS::FileType::BinaryFile}; + + if (!temp.IsOpen()) { return nullptr; } + + temp.Close(); + + return OpenFile(path, perms); + } + + if (!FS::NewFile(path)) { + return nullptr; } + return OpenFile(path, perms); } VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) { - const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault); - const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault); - - if (!FS::Exists(old_path) || FS::Exists(new_path) || FS::IsDirectory(old_path) || - !FS::Copy(old_path, new_path)) { - return nullptr; - } - return OpenFile(new_path, Mode::ReadWrite); + // Unused + return nullptr; } VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { @@ -127,13 +131,13 @@ VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_ file->Close(); } - if (!FS::Exists(old_path) || FS::Exists(new_path) || FS::IsDirectory(old_path) || - !FS::Rename(old_path, new_path)) { + if (!FS::RenameFile(old_path, new_path)) { return nullptr; } cache.erase(old_path); - if (file->Open(new_path, "r+b")) { + file->Open(new_path, FS::FileAccessMode::Read, FS::FileType::BinaryFile); + if (file->IsOpen()) { cache.insert_or_assign(new_path, std::move(file)); } else { LOG_ERROR(Service_FS, "Failed to open path {} in order to re-cache it", new_path); @@ -157,7 +161,7 @@ bool RealVfsFilesystem::DeleteFile(std::string_view path_) { cache.erase(path); } - return FS::Delete(path); + return FS::RemoveFile(path); } VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) { @@ -168,12 +172,8 @@ VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault); - const auto path_fwd = FS::SanitizePath(path, FS::DirectorySeparator::ForwardSlash); - if (!FS::Exists(path)) { - FS::CreateFullPath(path_fwd); - if (!FS::CreateDir(path)) { - return nullptr; - } + if (!FS::CreateDirs(path)) { + return nullptr; } // Cannot use make_shared as RealVfsDirectory constructor is private return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms)); @@ -181,13 +181,8 @@ VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_view new_path_) { - const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault); - const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault); - if (!FS::Exists(old_path) || FS::Exists(new_path) || !FS::IsDirectory(old_path)) { - return nullptr; - } - FS::CopyDir(old_path, new_path); - return OpenDirectory(new_path, Mode::ReadWrite); + // Unused + return nullptr; } VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, @@ -195,8 +190,7 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, const auto old_path = FS::SanitizePath(old_path_, FS::DirectorySeparator::PlatformDefault); const auto new_path = FS::SanitizePath(new_path_, FS::DirectorySeparator::PlatformDefault); - if (!FS::Exists(old_path) || FS::Exists(new_path) || FS::IsDirectory(old_path) || - !FS::Rename(old_path, new_path)) { + if (!FS::RenameDir(old_path, new_path)) { return nullptr; } @@ -208,7 +202,7 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, const auto file_old_path = FS::SanitizePath(kv.first, FS::DirectorySeparator::PlatformDefault); - auto file_new_path = FS::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()), + auto file_new_path = FS::SanitizePath(new_path + '/' + kv.first.substr(old_path.size()), FS::DirectorySeparator::PlatformDefault); const auto& cached = cache[file_old_path]; @@ -218,7 +212,8 @@ VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, auto file = cached.lock(); cache.erase(file_old_path); - if (file->Open(file_new_path, "r+b")) { + file->Open(file_new_path, FS::FileAccessMode::Read, FS::FileType::BinaryFile); + if (file->IsOpen()) { cache.insert_or_assign(std::move(file_new_path), std::move(file)); } else { LOG_ERROR(Service_FS, "Failed to open path {} in order to re-cache it", file_new_path); @@ -245,15 +240,13 @@ bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) { cache.erase(kv.first); } - return FS::DeleteDirRecursively(path); + return FS::RemoveDirRecursively(path); } RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::shared_ptr<FS::IOFile> backing_, const std::string& path_, Mode perms_) : base(base_), backing(std::move(backing_)), path(path_), parent_path(FS::GetParentPath(path_)), - path_components(FS::SplitPathComponents(path_)), - parent_components(FS::SliceVector(path_components, 0, path_components.size() - 1)), - perms(perms_) {} + path_components(FS::SplitPathComponents(path_)), perms(perms_) {} RealVfsFile::~RealVfsFile() = default; @@ -266,7 +259,7 @@ std::size_t RealVfsFile::GetSize() const { } bool RealVfsFile::Resize(std::size_t new_size) { - return backing->Resize(new_size); + return backing->SetSize(new_size); } VirtualDir RealVfsFile::GetContainingDirectory() const { @@ -274,33 +267,33 @@ VirtualDir RealVfsFile::GetContainingDirectory() const { } bool RealVfsFile::IsWritable() const { - return True(perms & Mode::WriteAppend); + return True(perms & Mode::Write); } bool RealVfsFile::IsReadable() const { - return True(perms & Mode::ReadWrite); + return True(perms & Mode::Read); } std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const { - if (!backing->Seek(static_cast<s64>(offset), SEEK_SET)) { + if (!backing->Seek(static_cast<s64>(offset))) { return 0; } - return backing->ReadBytes(data, length); + return backing->ReadSpan(std::span{data, length}); } std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) { - if (!backing->Seek(static_cast<s64>(offset), SEEK_SET)) { + if (!backing->Seek(static_cast<s64>(offset))) { return 0; } - return backing->WriteBytes(data, length); + return backing->WriteSpan(std::span{data, length}); } bool RealVfsFile::Rename(std::string_view name) { - return base.MoveFile(path, parent_path + DIR_SEP + std::string(name)) != nullptr; + return base.MoveFile(path, parent_path + '/' + std::string(name)) != nullptr; } -bool RealVfsFile::Close() { - return backing->Close(); +void RealVfsFile::Close() { + backing->Close(); } // TODO(DarkLordZach): MSVC would not let me combine the following two functions using 'if @@ -313,15 +306,16 @@ std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>( } std::vector<VirtualFile> out; - FS::ForeachDirectoryEntry( - nullptr, path, - [&out, this](u64* entries_out, const std::string& directory, const std::string& filename) { - const std::string full_path = directory + DIR_SEP + filename; - if (!FS::IsDirectory(full_path)) { - out.emplace_back(base.OpenFile(full_path, perms)); - } - return true; - }); + + const FS::DirEntryCallable callback = [this, &out](const std::filesystem::path& full_path) { + const auto full_path_string = FS::PathToUTF8String(full_path); + + out.emplace_back(base.OpenFile(full_path_string, perms)); + + return true; + }; + + FS::IterateDirEntries(path, callback, FS::DirEntryFilter::File); return out; } @@ -333,42 +327,41 @@ std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDi } std::vector<VirtualDir> out; - FS::ForeachDirectoryEntry( - nullptr, path, - [&out, this](u64* entries_out, const std::string& directory, const std::string& filename) { - const std::string full_path = directory + DIR_SEP + filename; - if (FS::IsDirectory(full_path)) { - out.emplace_back(base.OpenDirectory(full_path, perms)); - } - return true; - }); + + const FS::DirEntryCallable callback = [this, &out](const std::filesystem::path& full_path) { + const auto full_path_string = FS::PathToUTF8String(full_path); + + out.emplace_back(base.OpenDirectory(full_path_string, perms)); + + return true; + }; + + FS::IterateDirEntries(path, callback, FS::DirEntryFilter::Directory); return out; } RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_) : base(base_), path(FS::RemoveTrailingSlash(path_)), parent_path(FS::GetParentPath(path)), - path_components(FS::SplitPathComponents(path)), - parent_components(FS::SliceVector(path_components, 0, path_components.size() - 1)), - perms(perms_) { - if (!FS::Exists(path) && True(perms & Mode::WriteAppend)) { - FS::CreateDir(path); + path_components(FS::SplitPathComponents(path)), perms(perms_) { + if (!FS::Exists(path) && True(perms & Mode::Write)) { + void(FS::CreateDirs(path)); } } RealVfsDirectory::~RealVfsDirectory() = default; VirtualFile RealVfsDirectory::GetFileRelative(std::string_view relative_path) const { - const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path)); - if (!FS::Exists(full_path) || FS::IsDirectory(full_path)) { + const auto full_path = FS::SanitizePath(path + '/' + std::string(relative_path)); + if (!FS::Exists(full_path) || FS::IsDir(full_path)) { return nullptr; } return base.OpenFile(full_path, perms); } VirtualDir RealVfsDirectory::GetDirectoryRelative(std::string_view relative_path) const { - const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path)); - if (!FS::Exists(full_path) || !FS::IsDirectory(full_path)) { + const auto full_path = FS::SanitizePath(path + '/' + std::string(relative_path)); + if (!FS::Exists(full_path) || !FS::IsDir(full_path)) { return nullptr; } return base.OpenDirectory(full_path, perms); @@ -383,17 +376,20 @@ VirtualDir RealVfsDirectory::GetSubdirectory(std::string_view name) const { } VirtualFile RealVfsDirectory::CreateFileRelative(std::string_view relative_path) { - const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path)); + const auto full_path = FS::SanitizePath(path + '/' + std::string(relative_path)); + if (!FS::CreateParentDirs(full_path)) { + return nullptr; + } return base.CreateFile(full_path, perms); } VirtualDir RealVfsDirectory::CreateDirectoryRelative(std::string_view relative_path) { - const auto full_path = FS::SanitizePath(path + DIR_SEP + std::string(relative_path)); + const auto full_path = FS::SanitizePath(path + '/' + std::string(relative_path)); return base.CreateDirectory(full_path, perms); } bool RealVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) { - const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(name)); + const auto full_path = FS::SanitizePath(this->path + '/' + std::string(name)); return base.DeleteDirectory(full_path); } @@ -406,11 +402,11 @@ std::vector<VirtualDir> RealVfsDirectory::GetSubdirectories() const { } bool RealVfsDirectory::IsWritable() const { - return True(perms & Mode::WriteAppend); + return True(perms & Mode::Write); } bool RealVfsDirectory::IsReadable() const { - return True(perms & Mode::ReadWrite); + return True(perms & Mode::Read); } std::string RealVfsDirectory::GetName() const { @@ -426,27 +422,27 @@ VirtualDir RealVfsDirectory::GetParentDirectory() const { } VirtualDir RealVfsDirectory::CreateSubdirectory(std::string_view name) { - const std::string subdir_path = (path + DIR_SEP).append(name); + const std::string subdir_path = (path + '/').append(name); return base.CreateDirectory(subdir_path, perms); } VirtualFile RealVfsDirectory::CreateFile(std::string_view name) { - const std::string file_path = (path + DIR_SEP).append(name); + const std::string file_path = (path + '/').append(name); return base.CreateFile(file_path, perms); } bool RealVfsDirectory::DeleteSubdirectory(std::string_view name) { - const std::string subdir_path = (path + DIR_SEP).append(name); + const std::string subdir_path = (path + '/').append(name); return base.DeleteDirectory(subdir_path); } bool RealVfsDirectory::DeleteFile(std::string_view name) { - const std::string file_path = (path + DIR_SEP).append(name); + const std::string file_path = (path + '/').append(name); return base.DeleteFile(file_path); } bool RealVfsDirectory::Rename(std::string_view name) { - const std::string new_name = (parent_path + DIR_SEP).append(name); + const std::string new_name = (parent_path + '/').append(name); return base.MoveFile(path, new_name) != nullptr; } @@ -462,14 +458,17 @@ std::map<std::string, VfsEntryType, std::less<>> RealVfsDirectory::GetEntries() } std::map<std::string, VfsEntryType, std::less<>> out; - FS::ForeachDirectoryEntry( - nullptr, path, - [&out](u64* entries_out, const std::string& directory, const std::string& filename) { - const std::string full_path = directory + DIR_SEP + filename; - out.emplace(filename, - FS::IsDirectory(full_path) ? VfsEntryType::Directory : VfsEntryType::File); - return true; - }); + + const FS::DirEntryCallable callback = [&out](const std::filesystem::path& full_path) { + const auto filename = FS::PathToUTF8String(full_path.filename()); + + out.insert_or_assign(filename, + FS::IsDir(full_path) ? VfsEntryType::Directory : VfsEntryType::File); + + return true; + }; + + FS::IterateDirEntries(path, callback); return out; } diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index 0666f2679..e4d1bba79 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h @@ -61,14 +61,13 @@ private: RealVfsFile(RealVfsFilesystem& base, std::shared_ptr<Common::FS::IOFile> backing, const std::string& path, Mode perms = Mode::Read); - bool Close(); + void Close(); RealVfsFilesystem& base; std::shared_ptr<Common::FS::IOFile> backing; std::string path; std::string parent_path; std::vector<std::string> path_components; - std::vector<std::string> parent_components; Mode perms; }; @@ -110,7 +109,6 @@ private: std::string path; std::string parent_path; std::vector<std::string> path_components; - std::vector<std::string> parent_components; Mode perms; }; diff --git a/src/core/file_sys/xts_archive.cpp b/src/core/file_sys/xts_archive.cpp index 814fd5680..d6fe1af47 100644 --- a/src/core/file_sys/xts_archive.cpp +++ b/src/core/file_sys/xts_archive.cpp @@ -11,7 +11,7 @@ #include <mbedtls/md.h> #include <mbedtls/sha256.h> -#include "common/file_util.h" +#include "common/fs/path_util.h" #include "common/hex_util.h" #include "common/string_util.h" #include "core/crypto/aes_util.h" diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 497f35d23..61bda3786 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -80,16 +80,12 @@ public: memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH); - ctx.ClearIncomingObjects(); - IPC::CommandHeader header{}; // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory // padding. - u32 raw_data_size = ctx.IsTipc() - ? normal_params_size - 1 - : sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size; - + u32 raw_data_size = ctx.write_size = + ctx.IsTipc() ? normal_params_size - 1 : normal_params_size; u32 num_handles_to_move{}; u32 num_domain_objects{}; const bool always_move_handles{ @@ -101,16 +97,20 @@ public: } if (ctx.Session()->IsDomain()) { - raw_data_size += static_cast<u32>(sizeof(DomainMessageHeader) / 4 + num_domain_objects); + raw_data_size += + static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects); + ctx.write_size += num_domain_objects; } if (ctx.IsTipc()) { header.type.Assign(ctx.GetCommandType()); + } else { + raw_data_size += static_cast<u32>(sizeof(IPC::DataPayloadHeader) / sizeof(u32) + 4 + + normal_params_size); } - ctx.data_size = static_cast<u32>(raw_data_size); - header.data_size.Assign(static_cast<u32>(raw_data_size)); - if (num_handles_to_copy != 0 || num_handles_to_move != 0) { + header.data_size.Assign(raw_data_size); + if (num_handles_to_copy || num_handles_to_move) { header.enable_handle_descriptor.Assign(1); } PushRaw(header); @@ -143,7 +143,8 @@ public: data_payload_index = index; ctx.data_payload_offset = index; - ctx.domain_offset = index + raw_data_size / 4; + ctx.write_size += index; + ctx.domain_offset = static_cast<u32>(index + raw_data_size / sizeof(u32)); } template <class T> @@ -151,8 +152,8 @@ public: if (context->Session()->IsDomain()) { context->AddDomainObject(std::move(iface)); } else { - // kernel.CurrentProcess()->GetResourceLimit()->Reserve( - // Kernel::LimitableResource::Sessions, 1); + kernel.CurrentProcess()->GetResourceLimit()->Reserve( + Kernel::LimitableResource::Sessions, 1); auto* session = Kernel::KSession::Create(kernel); session->Initialize(nullptr, iface->GetServiceName()); @@ -167,24 +168,6 @@ public: PushIpcInterface<T>(std::make_shared<T>(std::forward<Args>(args)...)); } - void ValidateHeader() { - const std::size_t num_domain_objects = context->NumDomainObjects(); - const std::size_t num_move_objects = context->NumMoveObjects(); - ASSERT_MSG(!num_domain_objects || !num_move_objects, - "cannot move normal handles and domain objects"); - ASSERT_MSG((index - data_payload_index) == normal_params_size, - "normal_params_size value is incorrect"); - ASSERT_MSG((num_domain_objects + num_move_objects) == num_objects_to_move, - "num_objects_to_move value is incorrect"); - ASSERT_MSG(context->NumCopyObjects() == num_handles_to_copy, - "num_handles_to_copy value is incorrect"); - } - - // Validate on destruction, as there shouldn't be any case where we don't want it - ~ResponseBuilder() { - ValidateHeader(); - } - void PushImpl(s8 value); void PushImpl(s16 value); void PushImpl(s32 value); @@ -404,7 +387,7 @@ public: std::shared_ptr<T> PopIpcInterface() { ASSERT(context->Session()->IsDomain()); ASSERT(context->GetDomainMessageHeader().input_object_count > 0); - return context->GetDomainRequestHandler<T>(Pop<u32>() - 1); + return context->GetDomainHandler<T>(Pop<u32>() - 1); } }; diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 24700f7a5..9d069a78f 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -35,11 +35,11 @@ SessionRequestHandler::SessionRequestHandler() = default; SessionRequestHandler::~SessionRequestHandler() = default; void SessionRequestHandler::ClientConnected(KServerSession* session) { - session->SetHleHandler(shared_from_this()); + session->SetSessionHandler(shared_from_this()); } void SessionRequestHandler::ClientDisconnected(KServerSession* session) { - session->SetHleHandler(nullptr); + session->SetSessionHandler(nullptr); } HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, @@ -69,14 +69,10 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 if (incoming) { // Populate the object lists with the data in the IPC request. for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { - const u32 copy_handle{rp.Pop<Handle>()}; - copy_handles.push_back(copy_handle); - copy_objects.push_back(handle_table.GetObject(copy_handle).GetPointerUnsafe()); + incoming_copy_handles.push_back(rp.Pop<Handle>()); } for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { - const u32 move_handle{rp.Pop<Handle>()}; - move_handles.push_back(move_handle); - move_objects.push_back(handle_table.GetObject(move_handle).GetPointerUnsafe()); + incoming_move_handles.push_back(rp.Pop<Handle>()); } } else { // For responses we just ignore the handles, they're empty and will be populated when @@ -186,26 +182,14 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_t auto& owner_process = *requesting_thread.GetOwnerProcess(); auto& handle_table = owner_process.GetHandleTable(); - // The data_size already includes the payload header, the padding and the domain header. - std::size_t size{}; - - if (IsTipc()) { - size = cmd_buf.size(); - } else { - size = data_payload_offset + data_size - sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; - if (Session()->IsDomain()) { - size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); - } - } - - for (auto& object : copy_objects) { + for (auto& object : outgoing_copy_objects) { Handle handle{}; if (object) { R_TRY(handle_table.Add(&handle, object)); } cmd_buf[current_offset++] = handle; } - for (auto& object : move_objects) { + for (auto& object : outgoing_move_objects) { Handle handle{}; if (object) { R_TRY(handle_table.Add(&handle, object)); @@ -220,9 +204,9 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_t // TODO(Subv): This completely ignores C buffers. if (Session()->IsDomain()) { - current_offset = domain_offset - static_cast<u32>(domain_objects.size()); - for (const auto& object : domain_objects) { - server_session->AppendDomainRequestHandler(object); + current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size()); + for (const auto& object : outgoing_domain_objects) { + server_session->AppendDomainHandler(object); cmd_buf[current_offset++] = static_cast<u32_le>(server_session->NumDomainRequestHandlers()); } @@ -230,7 +214,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_t // Copy the translated command buffer back into the thread's command buffer area. memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(), - size * sizeof(u32)); + write_size * sizeof(u32)); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index e1b128281..b47e363cc 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -11,7 +11,8 @@ #include <string> #include <type_traits> #include <vector> -#include <boost/container/small_vector.hpp> + +#include "common/assert.h" #include "common/common_types.h" #include "common/concepts.h" #include "common/swap.h" @@ -84,6 +85,69 @@ public: void ClientDisconnected(KServerSession* session); }; +using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>; + +/** + * Manages the underlying HLE requests for a session, and whether (or not) the session should be + * treated as a domain. This is managed separately from server sessions, as this state is shared + * when objects are cloned. + */ +class SessionRequestManager final { +public: + SessionRequestManager() = default; + + bool IsDomain() const { + return is_domain; + } + + void ConvertToDomain() { + domain_handlers = {session_handler}; + is_domain = true; + } + + std::size_t DomainHandlerCount() const { + return domain_handlers.size(); + } + + bool HasSessionHandler() const { + return session_handler != nullptr; + } + + SessionRequestHandler& SessionHandler() { + return *session_handler; + } + + const SessionRequestHandler& SessionHandler() const { + return *session_handler; + } + + void CloseDomainHandler(std::size_t index) { + if (index < DomainHandlerCount()) { + domain_handlers[index] = nullptr; + } else { + UNREACHABLE_MSG("Unexpected handler index {}", index); + } + } + + SessionRequestHandlerPtr DomainHandler(std::size_t index) const { + ASSERT_MSG(index < DomainHandlerCount(), "Unexpected handler index {}", index); + return domain_handlers.at(index); + } + + void AppendDomainHandler(SessionRequestHandlerPtr&& handler) { + domain_handlers.emplace_back(std::move(handler)); + } + + void SetSessionHandler(SessionRequestHandlerPtr&& handler) { + session_handler = std::move(handler); + } + +private: + bool is_domain{}; + SessionRequestHandlerPtr session_handler; + std::vector<SessionRequestHandlerPtr> domain_handlers; +}; + /** * Class containing information about an in-flight IPC request being handled by an HLE service * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and @@ -224,53 +288,32 @@ public: bool CanWriteBuffer(std::size_t buffer_index = 0) const; Handle GetCopyHandle(std::size_t index) const { - return copy_handles.at(index); + return incoming_copy_handles.at(index); } Handle GetMoveHandle(std::size_t index) const { - return move_handles.at(index); + return incoming_move_handles.at(index); } void AddMoveObject(KAutoObject* object) { - move_objects.emplace_back(object); + outgoing_move_objects.emplace_back(object); } void AddCopyObject(KAutoObject* object) { - copy_objects.emplace_back(object); + outgoing_copy_objects.emplace_back(object); } - void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) { - domain_objects.emplace_back(std::move(object)); + void AddDomainObject(SessionRequestHandlerPtr object) { + outgoing_domain_objects.emplace_back(std::move(object)); } template <typename T> - std::shared_ptr<T> GetDomainRequestHandler(std::size_t index) const { - return std::static_pointer_cast<T>(domain_request_handlers.at(index)); - } - - void SetDomainRequestHandlers( - const std::vector<std::shared_ptr<SessionRequestHandler>>& handlers) { - domain_request_handlers = handlers; - } - - /// Clears the list of objects so that no lingering objects are written accidentally to the - /// response buffer. - void ClearIncomingObjects() { - move_objects.clear(); - copy_objects.clear(); - domain_objects.clear(); + std::shared_ptr<T> GetDomainHandler(std::size_t index) const { + return std::static_pointer_cast<T>(manager->DomainHandler(index)); } - std::size_t NumMoveObjects() const { - return move_objects.size(); - } - - std::size_t NumCopyObjects() const { - return copy_objects.size(); - } - - std::size_t NumDomainObjects() const { - return domain_objects.size(); + void SetSessionRequestManager(std::shared_ptr<SessionRequestManager> manager_) { + manager = std::move(manager_); } std::string Description() const; @@ -292,12 +335,12 @@ private: Kernel::KServerSession* server_session{}; KThread* thread; - // TODO(yuriks): Check common usage of this and optimize size accordingly - boost::container::small_vector<Handle, 8> move_handles; - boost::container::small_vector<Handle, 8> copy_handles; - boost::container::small_vector<KAutoObject*, 8> move_objects; - boost::container::small_vector<KAutoObject*, 8> copy_objects; - boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; + std::vector<Handle> incoming_move_handles; + std::vector<Handle> incoming_copy_handles; + + std::vector<KAutoObject*> outgoing_move_objects; + std::vector<KAutoObject*> outgoing_copy_objects; + std::vector<SessionRequestHandlerPtr> outgoing_domain_objects; std::optional<IPC::CommandHeader> command_header; std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; @@ -311,12 +354,12 @@ private: u32_le command{}; u64 pid{}; + u32 write_size{}; u32 data_payload_offset{}; u32 handles_offset{}; u32 domain_offset{}; - u32 data_size{}; - std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; + std::shared_ptr<SessionRequestManager> manager; bool is_thread_waiting{}; KernelCore& kernel; diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index 69ae405e6..10edede17 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -70,14 +70,22 @@ constexpr size_t SlabCountExtraKThread = 160; template <typename T> VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAddr address, size_t num_objects) { + // TODO(bunnei): This is just a place holder. We should initialize the appropriate KSlabHeap for + // kernel object type T with the backing kernel memory pointer once we emulate kernel memory. + const size_t size = Common::AlignUp(sizeof(T) * num_objects, alignof(void*)); VAddr start = Common::AlignUp(address, alignof(T)); + // This is intentionally empty. Once KSlabHeap is fully implemented, we can replace this with + // the pointer to emulated memory to pass along. Until then, KSlabHeap will just allocate/free + // host memory. + void* backing_kernel_memory{}; + if (size > 0) { const KMemoryRegion* region = memory_layout.FindVirtual(start + size - 1); ASSERT(region != nullptr); ASSERT(region->IsDerivedFrom(KMemoryRegionType_KernelSlab)); - T::InitializeSlabHeap(system.Kernel(), system.Memory().GetKernelBuffer(start, size), size); + T::InitializeSlabHeap(system.Kernel(), backing_kernel_memory, size); } return start + size; diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index ad01cf67e..4a12dee10 100644 --- a/src/core/hle/kernel/k_client_port.cpp +++ b/src/core/hle/kernel/k_client_port.cpp @@ -58,9 +58,9 @@ bool KClientPort::IsSignaled() const { ResultCode KClientPort::CreateSession(KClientSession** out) { // Reserve a new session from the resource limit. - // KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), - // LimitableResource::Sessions); - // R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); + KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), + LimitableResource::Sessions); + R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); // Update the session counts. { @@ -104,7 +104,7 @@ ResultCode KClientPort::CreateSession(KClientSession** out) { session->Initialize(this, parent->GetName()); // Commit the session reservation. - // session_reservation.Commit(); + session_reservation.Commit(); // Register the session. KSession::Register(kernel, session); diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h index d00ce3ddd..8501156e8 100644 --- a/src/core/hle/kernel/k_client_port.h +++ b/src/core/hle/kernel/k_client_port.h @@ -31,6 +31,9 @@ public: const KPort* GetParent() const { return parent; } + KPort* GetParent() { + return parent; + } s32 GetNumSessions() const { return num_sessions; diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp index feb2bb11f..223c0b205 100644 --- a/src/core/hle/kernel/k_port.cpp +++ b/src/core/hle/kernel/k_port.cpp @@ -56,11 +56,8 @@ ResultCode KPort::EnqueueSession(KServerSession* session) { R_UNLESS(state == State::Normal, ResultPortClosed); - if (server.HasHLEHandler()) { - server.GetHLEHandler()->ClientConnected(session); - } else { - server.EnqueueSession(session); - } + server.EnqueueSession(session); + server.GetSessionRequestHandler()->ClientConnected(server.AcceptSession()); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h index e76792253..d1a757ec3 100644 --- a/src/core/hle/kernel/k_server_port.h +++ b/src/core/hle/kernel/k_server_port.h @@ -32,26 +32,24 @@ public: explicit KServerPort(KernelCore& kernel_); virtual ~KServerPort() override; - using HLEHandler = std::shared_ptr<SessionRequestHandler>; - void Initialize(KPort* parent_, std::string&& name_); /// Whether or not this server port has an HLE handler available. - bool HasHLEHandler() const { - return hle_handler != nullptr; + bool HasSessionRequestHandler() const { + return session_handler != nullptr; } /// Gets the HLE handler for this port. - HLEHandler GetHLEHandler() const { - return hle_handler; + SessionRequestHandlerPtr GetSessionRequestHandler() const { + return session_handler; } /** * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port * will inherit a reference to this handler. */ - void SetHleHandler(HLEHandler hle_handler_) { - hle_handler = std::move(hle_handler_); + void SetSessionHandler(SessionRequestHandlerPtr&& handler) { + session_handler = std::move(handler); } void EnqueueSession(KServerSession* pending_session); @@ -73,7 +71,7 @@ private: private: SessionList session_list; - HLEHandler hle_handler; + SessionRequestHandlerPtr session_handler; KPort* parent{}; }; diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 8850d9af5..457fdfd60 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -23,7 +23,8 @@ namespace Kernel { -KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} +KServerSession::KServerSession(KernelCore& kernel_) + : KSynchronizationObject{kernel_}, manager{std::make_shared<SessionRequestManager>()} {} KServerSession::~KServerSession() { kernel.ReleaseServiceThread(service_thread); @@ -43,14 +44,8 @@ void KServerSession::Destroy() { } void KServerSession::OnClientClosed() { - // We keep a shared pointer to the hle handler to keep it alive throughout - // the call to ClientDisconnected, as ClientDisconnected invalidates the - // hle_handler member itself during the course of the function executing. - std::shared_ptr<SessionRequestHandler> handler = hle_handler; - if (handler) { - // Note that after this returns, this server session's hle_handler is - // invalidated (set to null). - handler->ClientDisconnected(this); + if (manager->HasSessionHandler()) { + manager->SessionHandler().ClientDisconnected(this); } } @@ -66,12 +61,12 @@ bool KServerSession::IsSignaled() const { return false; } -void KServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) { - domain_request_handlers.push_back(std::move(handler)); +void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) { + manager->AppendDomainHandler(std::move(handler)); } std::size_t KServerSession::NumDomainRequestHandlers() const { - return domain_request_handlers.size(); + return manager->DomainHandlerCount(); } ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { @@ -80,14 +75,14 @@ ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& co } // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs - context.SetDomainRequestHandlers(domain_request_handlers); + context.SetSessionRequestManager(manager); // If there is a DomainMessageHeader, then this is CommandType "Request" const auto& domain_message_header = context.GetDomainMessageHeader(); const u32 object_id{domain_message_header.object_id}; switch (domain_message_header.command) { case IPC::DomainMessageHeader::CommandType::SendMessage: - if (object_id > domain_request_handlers.size()) { + if (object_id > manager->DomainHandlerCount()) { LOG_CRITICAL(IPC, "object_id {} is too big! This probably means a recent service call " "to {} needed to return a new interface!", @@ -95,12 +90,12 @@ ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& co UNREACHABLE(); return RESULT_SUCCESS; // Ignore error if asserts are off } - return domain_request_handlers[object_id - 1]->HandleSyncRequest(*this, context); + return manager->DomainHandler(object_id - 1)->HandleSyncRequest(*this, context); case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); - domain_request_handlers[object_id - 1] = nullptr; + manager->CloseDomainHandler(object_id - 1); IPC::ResponseBuilder rb{context, 2}; rb.Push(RESULT_SUCCESS); @@ -133,14 +128,14 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { if (IsDomain() && context.HasDomainMessageHeader()) { result = HandleDomainSyncRequest(context); // If there is no domain header, the regular session handler is used - } else if (hle_handler != nullptr) { + } else if (manager->HasSessionHandler()) { // If this ServerSession has an associated HLE handler, forward the request to it. - result = hle_handler->HandleSyncRequest(*this, context); + result = manager->SessionHandler().HandleSyncRequest(*this, context); } if (convert_to_domain) { - ASSERT_MSG(IsSession(), "ServerSession is already a domain instance."); - domain_request_handlers = {hle_handler}; + ASSERT_MSG(!IsDomain(), "ServerSession is already a domain instance."); + manager->ConvertToDomain(); convert_to_domain = false; } diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index 597d76d38..dd4de2904 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h @@ -12,6 +12,7 @@ #include <boost/intrusive/list.hpp> #include "common/threadsafe_queue.h" +#include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/service_thread.h" #include "core/hle/result.h" @@ -64,8 +65,8 @@ public: * instead of the regular IPC machinery. (The regular IPC machinery is currently not * implemented.) */ - void SetHleHandler(std::shared_ptr<SessionRequestHandler> hle_handler_) { - hle_handler = std::move(hle_handler_); + void SetSessionHandler(SessionRequestHandlerPtr handler) { + manager->SetSessionHandler(std::move(handler)); } /** @@ -82,7 +83,7 @@ public: /// Adds a new domain request handler to the collection of request handlers within /// this ServerSession instance. - void AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler); + void AppendDomainHandler(SessionRequestHandlerPtr handler); /// Retrieves the total number of domain request handlers that have been /// appended to this ServerSession instance. @@ -90,12 +91,7 @@ public: /// Returns true if the session has been converted to a domain, otherwise False bool IsDomain() const { - return !IsSession(); - } - - /// Returns true if this session has not been converted to a domain, otherwise false. - bool IsSession() const { - return domain_request_handlers.empty(); + return manager->IsDomain(); } /// Converts the session to a domain at the end of the current command @@ -103,6 +99,21 @@ public: convert_to_domain = true; } + /// Gets the session request manager, which forwards requests to the underlying service + std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() { + return manager; + } + + /// Gets the session request manager, which forwards requests to the underlying service + const std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() const { + return manager; + } + + /// Sets the session request manager, which forwards requests to the underlying service + void SetSessionRequestManager(std::shared_ptr<SessionRequestManager> manager_) { + manager = std::move(manager_); + } + private: /// Queues a sync request from the emulated application. ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); @@ -114,11 +125,8 @@ private: /// object handle. ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); - /// This session's HLE request handler (applicable when not a domain) - std::shared_ptr<SessionRequestHandler> hle_handler; - - /// This is the list of domain request handlers (after conversion to a domain) - std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; + /// This session's HLE request handlers + std::shared_ptr<SessionRequestManager> manager; /// When set to True, converts the session to a domain at the end of the command bool convert_to_domain{}; diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp index b7ce27a0b..025b8b555 100644 --- a/src/core/hle/kernel/k_session.cpp +++ b/src/core/hle/kernel/k_session.cpp @@ -78,7 +78,7 @@ void KSession::OnClientClosed() { void KSession::PostDestroy(uintptr_t arg) { // Release the session count resource the owner process holds. KProcess* owner = reinterpret_cast<KProcess*>(arg); - // owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); + owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); owner->Close(); } diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h index 16901e19c..a981fd1f6 100644 --- a/src/core/hle/kernel/k_session.h +++ b/src/core/hle/kernel/k_session.h @@ -66,6 +66,10 @@ public: return port; } + KClientPort* GetParent() { + return port; + } + private: enum class State : u8 { Invalid = 0, diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h index 5ce9a1d7c..81d472a3e 100644 --- a/src/core/hle/kernel/k_slab_heap.h +++ b/src/core/hle/kernel/k_slab_heap.h @@ -4,165 +4,33 @@ #pragma once -#include <atomic> - -#include "common/assert.h" -#include "common/common_types.h" - namespace Kernel { -namespace impl { - -class KSlabHeapImpl final : NonCopyable { -public: - struct Node { - Node* next{}; - }; - - constexpr KSlabHeapImpl() = default; - - void Initialize(std::size_t size) { - ASSERT(head == nullptr); - obj_size = size; - } - - constexpr std::size_t GetObjectSize() const { - return obj_size; - } - - Node* GetHead() const { - return head; - } - - void* Allocate() { - Node* ret = head.load(); - - do { - if (ret == nullptr) { - break; - } - } while (!head.compare_exchange_weak(ret, ret->next)); - - return ret; - } - - void Free(void* obj) { - Node* node = static_cast<Node*>(obj); - - Node* cur_head = head.load(); - do { - node->next = cur_head; - } while (!head.compare_exchange_weak(cur_head, node)); - } - -private: - std::atomic<Node*> head{}; - std::size_t obj_size{}; -}; - -} // namespace impl - -class KSlabHeapBase : NonCopyable { -public: - constexpr KSlabHeapBase() = default; - - constexpr bool Contains(uintptr_t addr) const { - return start <= addr && addr < end; - } - - constexpr std::size_t GetSlabHeapSize() const { - return (end - start) / GetObjectSize(); - } - - constexpr std::size_t GetObjectSize() const { - return impl.GetObjectSize(); - } +class KernelCore; - constexpr uintptr_t GetSlabHeapAddress() const { - return start; - } - - std::size_t GetObjectIndexImpl(const void* obj) const { - return (reinterpret_cast<uintptr_t>(obj) - start) / GetObjectSize(); - } - - std::size_t GetPeakIndex() const { - return GetObjectIndexImpl(reinterpret_cast<const void*>(peak)); - } - - void* AllocateImpl() { - return impl.Allocate(); - } - - void FreeImpl(void* obj) { - // Don't allow freeing an object that wasn't allocated from this heap - ASSERT(Contains(reinterpret_cast<uintptr_t>(obj))); - - impl.Free(obj); - } - - void InitializeImpl(std::size_t obj_size, void* memory, std::size_t memory_size) { - // Ensure we don't initialize a slab using null memory - ASSERT(memory != nullptr); - - // Initialize the base allocator - impl.Initialize(obj_size); - - // Set our tracking variables - const std::size_t num_obj = (memory_size / obj_size); - start = reinterpret_cast<uintptr_t>(memory); - end = start + num_obj * obj_size; - peak = start; - - // Free the objects - u8* cur = reinterpret_cast<u8*>(end); - - for (std::size_t i{}; i < num_obj; i++) { - cur -= obj_size; - impl.Free(cur); - } - } - -private: - using Impl = impl::KSlabHeapImpl; - - Impl impl; - uintptr_t peak{}; - uintptr_t start{}; - uintptr_t end{}; -}; +/// This is a placeholder class to manage slab heaps for kernel objects. For now, we just allocate +/// these with new/delete, but this can be re-implemented later to allocate these in emulated +/// memory. template <typename T> -class KSlabHeap final : public KSlabHeapBase { +class KSlabHeap final : NonCopyable { public: - constexpr KSlabHeap() : KSlabHeapBase() {} + KSlabHeap() = default; - void Initialize(void* memory, std::size_t memory_size) { - InitializeImpl(sizeof(T), memory, memory_size); + void Initialize([[maybe_unused]] void* memory, [[maybe_unused]] std::size_t memory_size) { + // Placeholder that should initialize the backing slab heap implementation. } T* Allocate() { - T* obj = static_cast<T*>(AllocateImpl()); - if (obj != nullptr) { - new (obj) T(); - } - return obj; + return new T(); } T* AllocateWithKernel(KernelCore& kernel) { - T* obj = static_cast<T*>(AllocateImpl()); - if (obj != nullptr) { - new (obj) T(kernel); - } - return obj; + return new T(kernel); } void Free(T* obj) { - FreeImpl(obj); - } - - constexpr std::size_t GetObjectIndex(const T* obj) const { - return GetObjectIndexImpl(obj); + delete obj; } }; diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp index fcb8b1ea5..b2ceeceb3 100644 --- a/src/core/hle/kernel/process_capability.cpp +++ b/src/core/hle/kernel/process_capability.cpp @@ -22,6 +22,7 @@ enum : u32 { CapabilityOffset_Syscall = 4, CapabilityOffset_MapPhysical = 6, CapabilityOffset_MapIO = 7, + CapabilityOffset_MapRegion = 10, CapabilityOffset_Interrupt = 11, CapabilityOffset_ProgramType = 13, CapabilityOffset_KernelVersion = 14, @@ -46,6 +47,7 @@ enum class CapabilityType : u32 { Syscall = (1U << CapabilityOffset_Syscall) - 1, MapPhysical = (1U << CapabilityOffset_MapPhysical) - 1, MapIO = (1U << CapabilityOffset_MapIO) - 1, + MapRegion = (1U << CapabilityOffset_MapRegion) - 1, Interrupt = (1U << CapabilityOffset_Interrupt) - 1, ProgramType = (1U << CapabilityOffset_ProgramType) - 1, KernelVersion = (1U << CapabilityOffset_KernelVersion) - 1, @@ -187,6 +189,8 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s return HandleSyscallFlags(set_svc_bits, flag); case CapabilityType::MapIO: return HandleMapIOFlags(flag, page_table); + case CapabilityType::MapRegion: + return HandleMapRegionFlags(flag, page_table); case CapabilityType::Interrupt: return HandleInterruptFlags(flag); case CapabilityType::ProgramType: @@ -298,6 +302,11 @@ ResultCode ProcessCapabilities::HandleMapIOFlags(u32 flags, KPageTable& page_tab return RESULT_SUCCESS; } +ResultCode ProcessCapabilities::HandleMapRegionFlags(u32 flags, KPageTable& page_table) { + // TODO(Lioncache): Implement once the memory manager can handle this. + return RESULT_SUCCESS; +} + ResultCode ProcessCapabilities::HandleInterruptFlags(u32 flags) { constexpr u32 interrupt_ignore_value = 0x3FF; const u32 interrupt0 = (flags >> 12) & 0x3FF; diff --git a/src/core/hle/kernel/process_capability.h b/src/core/hle/kernel/process_capability.h index b7a9b2e45..2a7bf5505 100644 --- a/src/core/hle/kernel/process_capability.h +++ b/src/core/hle/kernel/process_capability.h @@ -231,6 +231,9 @@ private: /// Handles flags related to mapping IO pages. ResultCode HandleMapIOFlags(u32 flags, KPageTable& page_table); + /// Handles flags related to mapping physical memory regions. + ResultCode HandleMapRegionFlags(u32 flags, KPageTable& page_table); + /// Handles flags related to the interrupt capability flags. ResultCode HandleInterruptFlags(u32 flags); diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index 04be8a502..2ae80beca 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp @@ -74,21 +74,17 @@ void ServiceThread::Impl::QueueSyncRequest(KSession& session, { std::unique_lock lock{queue_mutex}; + auto* server_session{&session.GetServerSession()}; + // Open a reference to the session to ensure it is not closes while the service request // completes asynchronously. - session.Open(); + server_session->Open(); - requests.emplace([session_ptr{&session}, context{std::move(context)}]() { + requests.emplace([server_session, context{std::move(context)}]() { // Close the reference. - SCOPE_EXIT({ session_ptr->Close(); }); - - // If the session has been closed, we are done. - if (session_ptr->IsServerClosed()) { - return; - } + SCOPE_EXIT({ server_session->Close(); }); // Complete the service request. - KScopedAutoObject server_session{&session_ptr->GetServerSession()}; server_session->CompleteSyncRequest(*context); }); } diff --git a/src/core/hle/kernel/slab_helpers.h b/src/core/hle/kernel/slab_helpers.h index d0f7f084b..0c5995db0 100644 --- a/src/core/hle/kernel/slab_helpers.h +++ b/src/core/hle/kernel/slab_helpers.h @@ -67,11 +67,11 @@ class KAutoObjectWithSlabHeapAndContainer : public Base { private: static Derived* Allocate(KernelCore& kernel) { - return new Derived(kernel); + return kernel.SlabHeap<Derived>().AllocateWithKernel(kernel); } static void Free(KernelCore& kernel, Derived* obj) { - delete obj; + kernel.SlabHeap<Derived>().Free(obj); } public: diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 49c09a570..39cd1efc1 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -4,9 +4,9 @@ #include <algorithm> #include <array> -#include "common/common_paths.h" #include "common/common_types.h" -#include "common/file_util.h" +#include "common/fs/file.h" +#include "common/fs/path_util.h" #include "common/logging/log.h" #include "common/string_util.h" #include "common/swap.h" @@ -41,9 +41,9 @@ constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100}; // Thumbnails are hard coded to be at least this size constexpr std::size_t THUMBNAIL_SIZE = 0x24000; -static std::string GetImagePath(Common::UUID uuid) { - return Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) + - "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; +static std::filesystem::path GetImagePath(Common::UUID uuid) { + return Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / + fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormatSwitch()); } static constexpr u32 SanitizeJPEGSize(std::size_t size) { @@ -328,7 +328,8 @@ protected: IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - const Common::FS::IOFile image(GetImagePath(user_id), "rb"); + const Common::FS::IOFile image(GetImagePath(user_id), Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile); if (!image.IsOpen()) { LOG_WARNING(Service_ACC, "Failed to load user provided image! Falling back to built-in backup..."); @@ -339,7 +340,10 @@ protected: const u32 size = SanitizeJPEGSize(image.GetSize()); std::vector<u8> buffer(size); - image.ReadBytes(buffer.data(), buffer.size()); + + if (image.Read(buffer) != buffer.size()) { + LOG_ERROR(Service_ACC, "Failed to read all the bytes in the user provided image."); + } ctx.WriteBuffer(buffer); rb.Push<u32>(size); @@ -350,7 +354,8 @@ protected: IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - const Common::FS::IOFile image(GetImagePath(user_id), "rb"); + const Common::FS::IOFile image(GetImagePath(user_id), Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile); if (!image.IsOpen()) { LOG_WARNING(Service_ACC, @@ -415,10 +420,11 @@ protected: ProfileData data; std::memcpy(&data, user_data.data(), sizeof(ProfileData)); - Common::FS::IOFile image(GetImagePath(user_id), "wb"); + Common::FS::IOFile image(GetImagePath(user_id), Common::FS::FileAccessMode::Write, + Common::FS::FileType::BinaryFile); - if (!image.IsOpen() || !image.Resize(image_data.size()) || - image.WriteBytes(image_data.data(), image_data.size()) != image_data.size() || + if (!image.IsOpen() || !image.SetSize(image_data.size()) || + image.Write(image_data) != image_data.size() || !profile_manager.SetProfileBaseAndData(user_id, base, data)) { LOG_ERROR(Service_ACC, "Failed to update profile data, base, and image!"); IPC::ResponseBuilder rb{ctx, 2}; diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index de83d82a4..77510489c 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -7,7 +7,9 @@ #include <fmt/format.h> -#include "common/file_util.h" +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "common/settings.h" #include "core/hle/service/acc/profile_manager.h" @@ -36,7 +38,7 @@ constexpr ResultCode ERROR_TOO_MANY_USERS(ErrorModule::Account, u32(-1)); constexpr ResultCode ERROR_USER_ALREADY_EXISTS(ErrorModule::Account, u32(-2)); constexpr ResultCode ERROR_ARGUMENT_IS_NULL(ErrorModule::Account, 20); -constexpr char ACC_SAVE_AVATORS_BASE_PATH[] = "/system/save/8000000000000010/su/avators/"; +constexpr char ACC_SAVE_AVATORS_BASE_PATH[] = "system/save/8000000000000010/su/avators"; ProfileManager::ProfileManager() { ParseUserSaveFile(); @@ -325,8 +327,9 @@ bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& } void ProfileManager::ParseUserSaveFile() { - const FS::IOFile save( - FS::GetUserPath(FS::UserPath::NANDDir) + ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat", "rb"); + const auto save_path(FS::GetYuzuPath(FS::YuzuPath::NANDDir) / ACC_SAVE_AVATORS_BASE_PATH / + "profiles.dat"); + const FS::IOFile save(save_path, FS::FileAccessMode::Read, FS::FileType::BinaryFile); if (!save.IsOpen()) { LOG_WARNING(Service_ACC, "Failed to load profile data from save data... Generating new " @@ -335,7 +338,7 @@ void ProfileManager::ParseUserSaveFile() { } ProfileDataRaw data; - if (save.ReadBytes(&data, sizeof(ProfileDataRaw)) != sizeof(ProfileDataRaw)) { + if (!save.ReadObject(data)) { LOG_WARNING(Service_ACC, "profiles.dat is smaller than expected... Generating new user " "'yuzu' with random UUID."); return; @@ -372,31 +375,27 @@ void ProfileManager::WriteUserSaveFile() { }; } - const auto raw_path = FS::GetUserPath(FS::UserPath::NANDDir) + "/system/save/8000000000000010"; - if (FS::Exists(raw_path) && !FS::IsDirectory(raw_path)) { - FS::Delete(raw_path); + const auto raw_path(FS::GetYuzuPath(FS::YuzuPath::NANDDir) / "system/save/8000000000000010"); + if (FS::IsFile(raw_path) && !FS::RemoveFile(raw_path)) { + return; } - const auto path = - FS::GetUserPath(FS::UserPath::NANDDir) + ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat"; + const auto save_path(FS::GetYuzuPath(FS::YuzuPath::NANDDir) / ACC_SAVE_AVATORS_BASE_PATH / + "profiles.dat"); - if (!FS::CreateFullPath(path)) { + if (!FS::CreateParentDirs(save_path)) { LOG_WARNING(Service_ACC, "Failed to create full path of profiles.dat. Create the directory " "nand/system/save/8000000000000010/su/avators to mitigate this " "issue."); return; } - FS::IOFile save(path, "wb"); + FS::IOFile save(save_path, FS::FileAccessMode::Write, FS::FileType::BinaryFile); - if (!save.IsOpen()) { + if (!save.IsOpen() || !save.SetSize(sizeof(ProfileDataRaw)) || !save.WriteObject(raw)) { LOG_WARNING(Service_ACC, "Failed to write save data to file... No changes to user data " "made in current session will be saved."); - return; } - - save.Resize(sizeof(ProfileDataRaw)); - save.WriteBytes(&raw, sizeof(ProfileDataRaw)); } }; // namespace Service::Account diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index e5f4a4485..3b28e829b 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -3,8 +3,9 @@ // Refer to the license.txt file included. #include "common/assert.h" -#include "common/common_paths.h" -#include "common/file_util.h" +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "common/logging/log.h" #include "common/string_util.h" #include "core/core.h" @@ -135,14 +136,10 @@ void ExtractSharedFonts(Core::System& system) { "FontNintendoExtended2.ttf", }; - for (std::size_t i = 0; i < NS::SHARED_FONTS.size(); ++i) { - const auto fonts_dir = Common::FS::SanitizePath( - fmt::format("{}/fonts", Common::FS::GetUserPath(Common::FS::UserPath::CacheDir)), - Common::FS::DirectorySeparator::PlatformDefault); + const auto fonts_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "fonts"; - const auto font_file_path = - Common::FS::SanitizePath(fmt::format("{}/{}", fonts_dir, DECRYPTED_SHARED_FONTS[i]), - Common::FS::DirectorySeparator::PlatformDefault); + for (std::size_t i = 0; i < NS::SHARED_FONTS.size(); ++i) { + const auto font_file_path = fonts_dir / DECRYPTED_SHARED_FONTS[i]; if (Common::FS::Exists(font_file_path)) { continue; @@ -197,8 +194,8 @@ void ExtractSharedFonts(Core::System& system) { FileSys::VirtualFile decrypted_font = std::make_shared<FileSys::VectorVfsFile>( std::move(decrypted_data), DECRYPTED_SHARED_FONTS[i]); - const auto temp_dir = - system.GetFilesystem()->CreateDirectory(fonts_dir, FileSys::Mode::ReadWrite); + const auto temp_dir = system.GetFilesystem()->CreateDirectory( + Common::FS::PathToUTF8String(fonts_dir), FileSys::Mode::ReadWrite); const auto out_file = temp_dir->CreateFile(DECRYPTED_SHARED_FONTS[i]); @@ -312,13 +309,14 @@ void WebBrowser::Execute() { } void WebBrowser::ExtractOfflineRomFS() { - LOG_DEBUG(Service_AM, "Extracting RomFS to {}", offline_cache_dir); + LOG_DEBUG(Service_AM, "Extracting RomFS to {}", + Common::FS::PathToUTF8String(offline_cache_dir)); const auto extracted_romfs_dir = FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard); - const auto temp_dir = - system.GetFilesystem()->CreateDirectory(offline_cache_dir, FileSys::Mode::ReadWrite); + const auto temp_dir = system.GetFilesystem()->CreateDirectory( + Common::FS::PathToUTF8String(offline_cache_dir), FileSys::Mode::ReadWrite); FileSys::VfsRawCopyD(extracted_romfs_dir, temp_dir); } @@ -397,15 +395,12 @@ void WebBrowser::InitializeOffline() { "system_data", }; - offline_cache_dir = Common::FS::SanitizePath( - fmt::format("{}/offline_web_applet_{}/{:016X}", - Common::FS::GetUserPath(Common::FS::UserPath::CacheDir), - RESOURCE_TYPES[static_cast<u32>(document_kind) - 1], title_id), - Common::FS::DirectorySeparator::PlatformDefault); + offline_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / + fmt::format("offline_web_applet_{}/{:016X}", + RESOURCE_TYPES[static_cast<u32>(document_kind) - 1], title_id); - offline_document = Common::FS::SanitizePath( - fmt::format("{}/{}/{}", offline_cache_dir, additional_paths, document_path), - Common::FS::DirectorySeparator::PlatformDefault); + offline_document = Common::FS::ConcatPathSafe( + offline_cache_dir, fmt::format("{}/{}", additional_paths, document_path)); } void WebBrowser::InitializeShare() {} @@ -429,8 +424,7 @@ void WebBrowser::ExecuteLogin() { } void WebBrowser::ExecuteOffline() { - const auto main_url = Common::FS::SanitizePath(GetMainURL(offline_document), - Common::FS::DirectorySeparator::PlatformDefault); + const auto main_url = GetMainURL(Common::FS::PathToUTF8String(offline_document)); if (!Common::FS::Exists(main_url)) { offline_romfs = GetOfflineRomFS(system, title_id, nca_type); @@ -444,10 +438,11 @@ void WebBrowser::ExecuteOffline() { } } - LOG_INFO(Service_AM, "Opening offline document at {}", offline_document); + LOG_INFO(Service_AM, "Opening offline document at {}", + Common::FS::PathToUTF8String(offline_document)); frontend.OpenLocalWebPage( - offline_document, [this] { ExtractOfflineRomFS(); }, + Common::FS::PathToUTF8String(offline_document), [this] { ExtractOfflineRomFS(); }, [this](WebExitReason exit_reason, std::string last_url) { WebBrowserExit(exit_reason, last_url); }); diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h index 1e1812f36..cdeaf2c40 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h @@ -4,6 +4,7 @@ #pragma once +#include <filesystem> #include <optional> #include "common/common_funcs.h" @@ -75,8 +76,8 @@ private: u64 title_id{}; FileSys::ContentRecordType nca_type{}; - std::string offline_cache_dir; - std::string offline_document; + std::filesystem::path offline_cache_dir; + std::filesystem::path offline_document; FileSys::VirtualFile offline_romfs; std::string external_url; diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp index d6d2f52e5..3cc397604 100644 --- a/src/core/hle/service/bcat/backend/boxcat.cpp +++ b/src/core/hle/service/bcat/backend/boxcat.cpp @@ -15,6 +15,9 @@ #pragma GCC diagnostic pop #endif +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "common/hex_util.h" #include "common/logging/backend.h" #include "common/logging/log.h" @@ -96,14 +99,14 @@ constexpr u32 PORT = 443; constexpr u32 TIMEOUT_SECONDS = 30; [[maybe_unused]] constexpr u64 VFS_COPY_BLOCK_SIZE = 1ULL << 24; // 4MB -std::string GetBINFilePath(u64 title_id) { - return fmt::format("{}bcat/{:016X}/launchparam.bin", - Common::FS::GetUserPath(Common::FS::UserPath::CacheDir), title_id); +std::filesystem::path GetBINFilePath(u64 title_id) { + return Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "bcat" / + fmt::format("{:016X}/launchparam.bin", title_id); } -std::string GetZIPFilePath(u64 title_id) { - return fmt::format("{}bcat/{:016X}/data.zip", - Common::FS::GetUserPath(Common::FS::UserPath::CacheDir), title_id); +std::filesystem::path GetZIPFilePath(u64 title_id) { + return Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "bcat" / + fmt::format("{:016X}/data.zip", title_id); } // If the error is something the user should know about (build ID mismatch, bad client version), @@ -187,7 +190,7 @@ bool VfsRawCopyDProgress(FileSys::VirtualDir src, FileSys::VirtualDir dest, class Boxcat::Client { public: - Client(std::string path_, u64 title_id_, u64 build_id_) + Client(std::filesystem::path path_, u64 title_id_, u64 build_id_) : path(std::move(path_)), title_id(title_id_), build_id(build_id_) {} DownloadResult DownloadDataZip() { @@ -217,10 +220,11 @@ private: }; if (Common::FS::Exists(path)) { - Common::FS::IOFile file{path, "rb"}; + Common::FS::IOFile file{path, Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile}; if (file.IsOpen()) { std::vector<u8> bytes(file.GetSize()); - file.ReadBytes(bytes.data(), bytes.size()); + void(file.Read(bytes)); const auto digest = DigestFile(bytes); headers.insert({std::string("If-None-Match"), Common::HexToString(digest, false)}); } @@ -247,14 +251,23 @@ private: return DownloadResult::InvalidContentType; } - Common::FS::CreateFullPath(path); - Common::FS::IOFile file{path, "wb"}; - if (!file.IsOpen()) + if (!Common::FS::CreateDirs(path)) { return DownloadResult::GeneralFSError; - if (!file.Resize(response->body.size())) + } + + Common::FS::IOFile file{path, Common::FS::FileAccessMode::Append, + Common::FS::FileType::BinaryFile}; + if (!file.IsOpen()) { + return DownloadResult::GeneralFSError; + } + + if (!file.SetSize(response->body.size())) { return DownloadResult::GeneralFSError; - if (file.WriteBytes(response->body.data(), response->body.size()) != response->body.size()) + } + + if (file.Write(response->body) != response->body.size()) { return DownloadResult::GeneralFSError; + } return DownloadResult::Success; } @@ -267,7 +280,7 @@ private: } std::unique_ptr<httplib::SSLClient> client; - std::string path; + std::filesystem::path path; u64 title_id; u64 build_id; }; @@ -291,7 +304,7 @@ void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGe return; } - const auto zip_path{GetZIPFilePath(title.title_id)}; + const auto zip_path = GetZIPFilePath(title.title_id); Boxcat::Client client{zip_path, title.title_id, title.build_id}; progress.StartConnecting(); @@ -301,7 +314,7 @@ void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGe LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { - Common::FS::Delete(zip_path); + void(Common::FS::RemoveFile(zip_path)); } HandleDownloadDisplayResult(applet_manager, res); @@ -311,11 +324,13 @@ void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGe progress.StartProcessingDataList(); - Common::FS::IOFile zip{zip_path, "rb"}; + Common::FS::IOFile zip{zip_path, Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile}; const auto size = zip.GetSize(); std::vector<u8> bytes(size); - if (!zip.IsOpen() || size == 0 || zip.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) { - LOG_ERROR(Service_BCAT, "Boxcat failed to read ZIP file at path '{}'!", zip_path); + if (!zip.IsOpen() || size == 0 || zip.Read(bytes) != bytes.size()) { + LOG_ERROR(Service_BCAT, "Boxcat failed to read ZIP file at path '{}'!", + Common::FS::PathToUTF8String(zip_path)); progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); return; } @@ -419,19 +434,19 @@ void Boxcat::SetPassphrase(u64 title_id, const Passphrase& passphrase) { } std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title) { - const auto path{GetBINFilePath(title.title_id)}; + const auto bin_file_path = GetBINFilePath(title.title_id); if (Settings::values.bcat_boxcat_local) { LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download."); } else { - Client launch_client{path, title.title_id, title.build_id}; + Client launch_client{bin_file_path, title.title_id, title.build_id}; const auto res = launch_client.DownloadLaunchParam(); if (res != DownloadResult::Success) { LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { - Common::FS::Delete(path); + void(Common::FS::RemoveFile(bin_file_path)); } HandleDownloadDisplayResult(applet_manager, res); @@ -439,12 +454,13 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title) } } - Common::FS::IOFile bin{path, "rb"}; + Common::FS::IOFile bin{bin_file_path, Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile}; const auto size = bin.GetSize(); std::vector<u8> bytes(size); - if (!bin.IsOpen() || size == 0 || bin.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) { + if (!bin.IsOpen() || size == 0 || bin.Read(bytes) != bytes.size()) { LOG_ERROR(Service_BCAT, "Boxcat failed to read launch parameter binary at path '{}'!", - path); + Common::FS::PathToUTF8String(bin_file_path)); return std::nullopt; } diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 432abde76..b7666e95a 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -6,7 +6,6 @@ #include <cstring> #include <ctime> #include <fmt/chrono.h> -#include "common/file_util.h" #include "common/logging/log.h" #include "common/scm_rev.h" #include "common/swap.h" diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 67baaee9b..78664439d 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -5,7 +5,7 @@ #include <utility> #include "common/assert.h" -#include "common/file_util.h" +#include "common/fs/path_util.h" #include "common/settings.h" #include "core/core.h" #include "core/file_sys/bis_factory.h" @@ -728,14 +728,17 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove sdmc_factory = nullptr; } - auto nand_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir), - FileSys::Mode::ReadWrite); - auto sd_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir), - FileSys::Mode::ReadWrite); - auto load_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::LoadDir), - FileSys::Mode::ReadWrite); - auto dump_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::DumpDir), - FileSys::Mode::ReadWrite); + using YuzuPath = Common::FS::YuzuPath; + const auto rw_mode = FileSys::Mode::ReadWrite; + + auto nand_directory = + vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode); + auto sd_directory = + vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::SDMCDir), rw_mode); + auto load_directory = + vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir), FileSys::Mode::Read); + auto dump_directory = + vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::DumpDir), rw_mode); if (bis_factory == nullptr) { bis_factory = diff --git a/src/core/hle/service/mii/manager.cpp b/src/core/hle/service/mii/manager.cpp index 70350a2a3..114aff31c 100644 --- a/src/core/hle/service/mii/manager.cpp +++ b/src/core/hle/service/mii/manager.cpp @@ -6,7 +6,6 @@ #include <random> #include "common/assert.h" -#include "common/file_util.h" #include "common/logging/log.h" #include "common/string_util.h" diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index e14acce58..90ba5c752 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp @@ -7,9 +7,7 @@ #include <vector> #include "common/assert.h" -#include "common/common_paths.h" #include "common/common_types.h" -#include "common/file_util.h" #include "common/logging/log.h" #include "common/swap.h" #include "core/core.h" diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 2c9b2ce6d..fa61a5c7b 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -107,7 +107,7 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) ASSERT(!port_installed); auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); - port->SetHleHandler(shared_from_this()); + port->SetSessionHandler(shared_from_this()); port_installed = true; } @@ -118,7 +118,7 @@ Kernel::KClientPort& ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel auto* port = Kernel::KPort::Create(kernel); port->Initialize(max_sessions, false, service_name); - port->GetServerPort().SetHleHandler(shared_from_this()); + port->GetServerPort().SetSessionHandler(shared_from_this()); port_installed = true; diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index de530cbfb..147f12147 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -4,8 +4,13 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "core/core.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_server_port.h" #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_session.h" #include "core/hle/service/sm/controller.h" @@ -13,7 +18,7 @@ namespace Service::SM { void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { - ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); + ASSERT_MSG(!ctx.Session()->IsDomain(), "Session is already a domain"); LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); ctx.Session()->ConvertToDomain(); @@ -29,16 +34,36 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service, "called"); - auto session = ctx.Session()->GetParent(); + auto& kernel = system.Kernel(); + auto* session = ctx.Session()->GetParent(); + auto* port = session->GetParent()->GetParent(); - // Open a reference to the session to simulate a new one being created. - session->Open(); - session->GetClientSession().Open(); - session->GetServerSession().Open(); + // Reserve a new session from the process resource limit. + Kernel::KScopedResourceReservation session_reservation( + kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); + if (!session_reservation.Succeeded()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(Kernel::ResultLimitReached); + } + // Create a new session. + auto* clone = Kernel::KSession::Create(kernel); + clone->Initialize(&port->GetClientPort(), session->GetName()); + + // Commit the session reservation. + session_reservation.Commit(); + + // Enqueue the session with the named port. + port->EnqueueSession(&clone->GetServerSession()); + + // Set the session request manager. + clone->GetServerSession().SetSessionRequestManager( + session->GetServerSession().GetSessionRequestManager()); + + // We succeeded. IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(RESULT_SUCCESS); - rb.PushMoveObjects(session->GetClientSession()); + rb.PushMoveObjects(clone->GetClientSession()); } void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 8cc9aee8a..a9bc7da74 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -150,31 +150,31 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& IPC::RequestParser rp{ctx}; std::string name(PopServiceName(rp)); + // Find the named port. auto result = service_manager.GetServicePort(name); if (result.Failed()) { LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw); return result.Code(); } - auto* port = result.Unwrap(); - // Kernel::KScopedResourceReservation session_reservation( - // kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); - // R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached); + // Reserve a new session from the process resource limit. + Kernel::KScopedResourceReservation session_reservation( + kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); + R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached); + // Create a new session. auto* session = Kernel::KSession::Create(kernel); session->Initialize(&port->GetClientPort(), std::move(name)); // Commit the session reservation. - // session_reservation.Commit(); + session_reservation.Commit(); - if (port->GetServerPort().GetHLEHandler()) { - port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession()); - } else { - port->EnqueueSession(&session->GetServerSession()); - } + // Enqueue the session with the named port. + port->EnqueueSession(&session->GetServerSession()); LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); + return MakeResult(&session->GetClientSession()); } diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 60f0b3f8a..ea37f11d4 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -73,7 +73,7 @@ public: if (port == nullptr) { return nullptr; } - return std::static_pointer_cast<T>(port->GetServerPort().GetHLEHandler()); + return std::static_pointer_cast<T>(port->GetServerPort().GetSessionRequestHandler()); } void InvokeControlRequest(Kernel::HLERequestContext& context); diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 022885c1b..a19bb220a 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp @@ -5,7 +5,6 @@ #include <cinttypes> #include <cstring> #include "common/common_funcs.h" -#include "common/file_util.h" #include "common/logging/log.h" #include "core/core.h" #include "core/file_sys/content_archive.h" diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index c062a4259..3d9276f15 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -7,7 +7,6 @@ #include <string> #include "common/common_funcs.h" #include "common/common_types.h" -#include "common/file_util.h" #include "common/logging/log.h" #include "core/hle/kernel/code_set.h" #include "core/hle/kernel/k_page_table.h" diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index d4808fb5b..228dc6389 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp @@ -7,7 +7,7 @@ #include <ostream> #include <string> #include "common/concepts.h" -#include "common/file_util.h" +#include "common/fs/path_util.h" #include "common/logging/log.h" #include "common/string_util.h" #include "core/core.h" diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index 418cbf61b..aa51b0daa 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp @@ -4,7 +4,6 @@ #include <utility> -#include "common/file_util.h" #include "common/logging/log.h" #include "core/core.h" #include "core/file_sys/content_archive.h" diff --git a/src/core/loader/nro.cpp b/src/core/loader/nro.cpp index ef54fa574..618555202 100644 --- a/src/core/loader/nro.cpp +++ b/src/core/loader/nro.cpp @@ -7,7 +7,6 @@ #include "common/common_funcs.h" #include "common/common_types.h" -#include "common/file_util.h" #include "common/logging/log.h" #include "common/settings.h" #include "common/swap.h" diff --git a/src/core/loader/nso.cpp b/src/core/loader/nso.cpp index df59412cf..0f5cfda68 100644 --- a/src/core/loader/nso.cpp +++ b/src/core/loader/nso.cpp @@ -7,7 +7,6 @@ #include <vector> #include "common/common_funcs.h" -#include "common/file_util.h" #include "common/hex_util.h" #include "common/logging/log.h" #include "common/lz4_compression.h" diff --git a/src/core/memory.cpp b/src/core/memory.cpp index b4c56e1c1..bf2ef7816 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -82,22 +82,6 @@ struct Memory::Impl { return nullptr; } - u8* GetKernelBuffer(VAddr start_vaddr, size_t size) { - // TODO(bunnei): This is just a workaround until we have kernel memory layout mapped & - // managed. Until then, we use this to allocate and access kernel memory regions. - - auto search = kernel_memory_regions.find(start_vaddr); - if (search != kernel_memory_regions.end()) { - return search->second.get(); - } - - std::unique_ptr<u8[]> new_memory_region{new u8[size]}; - u8* raw_ptr = new_memory_region.get(); - kernel_memory_regions[start_vaddr] = std::move(new_memory_region); - - return raw_ptr; - } - u8 Read8(const VAddr addr) { return Read<u8>(addr); } @@ -727,7 +711,6 @@ struct Memory::Impl { } Common::PageTable* current_page_table = nullptr; - std::unordered_map<VAddr, std::unique_ptr<u8[]>> kernel_memory_regions; Core::System& system; }; @@ -765,10 +748,6 @@ u8* Memory::GetPointer(VAddr vaddr) { return impl->GetPointer(vaddr); } -u8* Memory::GetKernelBuffer(VAddr start_vaddr, size_t size) { - return impl->GetKernelBuffer(start_vaddr, size); -} - const u8* Memory::GetPointer(VAddr vaddr) const { return impl->GetPointer(vaddr); } diff --git a/src/core/memory.h b/src/core/memory.h index 345fd870d..c91eeced9 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -121,15 +121,6 @@ public: */ u8* GetPointer(VAddr vaddr); - /** - * Gets a pointer to the start of a kernel heap allocated memory region. Will allocate one if it - * does not already exist. - * - * @param start_vaddr Start virtual address for the memory region. - * @param size Size of the memory region. - */ - u8* GetKernelBuffer(VAddr start_vaddr, size_t size); - template <typename T> T* GetPointer(VAddr vaddr) { return reinterpret_cast<T*>(GetPointer(vaddr)); diff --git a/src/core/perf_stats.cpp b/src/core/perf_stats.cpp index c42c437b7..6635a1339 100644 --- a/src/core/perf_stats.cpp +++ b/src/core/perf_stats.cpp @@ -11,7 +11,9 @@ #include <thread> #include <fmt/chrono.h> #include <fmt/format.h> -#include "common/file_util.h" +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "common/math_util.h" #include "common/settings.h" #include "core/perf_stats.h" @@ -38,12 +40,17 @@ PerfStats::~PerfStats() { std::ostringstream stream; std::copy(perf_history.begin() + IgnoreFrames, perf_history.begin() + current_index, std::ostream_iterator<double>(stream, "\n")); - const std::string& path = Common::FS::GetUserPath(Common::FS::UserPath::LogDir); + + const auto path = Common::FS::GetYuzuPath(Common::FS::YuzuPath::LogDir); // %F Date format expanded is "%Y-%m-%d" - const std::string filename = - fmt::format("{}/{:%F-%H-%M}_{:016X}.csv", path, *std::localtime(&t), title_id); - Common::FS::IOFile file(filename, "w"); - file.WriteString(stream.str()); + const auto filename = fmt::format("{:%F-%H-%M}_{:016X}.csv", *std::localtime(&t), title_id); + const auto filepath = path / filename; + + if (Common::FS::CreateParentDir(filepath)) { + Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Write, + Common::FS::FileType::TextFile); + void(file.WriteString(stream.str())); + } } void PerfStats::BeginSystemFrame() { diff --git a/src/core/reporter.cpp b/src/core/reporter.cpp index d1e807dd4..a9596fe4d 100644 --- a/src/core/reporter.cpp +++ b/src/core/reporter.cpp @@ -11,7 +11,9 @@ #include <fmt/ostream.h> #include <nlohmann/json.hpp> -#include "common/file_util.h" +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "common/hex_util.h" #include "common/scm_rev.h" #include "common/settings.h" @@ -26,10 +28,9 @@ namespace { -std::string GetPath(std::string_view type, u64 title_id, std::string_view timestamp) { - return fmt::format("{}{}/{:016X}_{}.json", - Common::FS::GetUserPath(Common::FS::UserPath::LogDir), type, title_id, - timestamp); +std::filesystem::path GetPath(std::string_view type, u64 title_id, std::string_view timestamp) { + return Common::FS::GetYuzuPath(Common::FS::YuzuPath::LogDir) / type / + fmt::format("{:016X}_{}.json", title_id, timestamp); } std::string GetTimestamp() { @@ -39,14 +40,16 @@ std::string GetTimestamp() { using namespace nlohmann; -void SaveToFile(json json, const std::string& filename) { - if (!Common::FS::CreateFullPath(filename)) { - LOG_ERROR(Core, "Failed to create path for '{}' to save report!", filename); +void SaveToFile(json json, const std::filesystem::path& filename) { + if (!Common::FS::CreateParentDirs(filename)) { + LOG_ERROR(Core, "Failed to create path for '{}' to save report!", + Common::FS::PathToUTF8String(filename)); return; } - std::ofstream file( - Common::FS::SanitizePath(filename, Common::FS::DirectorySeparator::PlatformDefault)); + std::ofstream file; + Common::FS::OpenFileStream(file, filename, std::ios_base::out | std::ios_base::trunc); + file << std::setw(4) << json << std::endl; } diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 6dcff5400..ad1a9ffb4 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -9,7 +9,9 @@ #include "common/assert.h" #include "common/common_types.h" -#include "common/file_util.h" +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "common/logging/log.h" #include "common/settings.h" @@ -72,31 +74,41 @@ static const char* TranslateGPUAccuracyLevel(Settings::GPUAccuracy backend) { u64 GetTelemetryId() { u64 telemetry_id{}; - const std::string filename{Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir) + - "telemetry_id"}; + const auto filename = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "telemetry_id"; bool generate_new_id = !Common::FS::Exists(filename); + if (!generate_new_id) { - Common::FS::IOFile file(filename, "rb"); + Common::FS::IOFile file{filename, Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile}; + if (!file.IsOpen()) { - LOG_ERROR(Core, "failed to open telemetry_id: {}", filename); + LOG_ERROR(Core, "failed to open telemetry_id: {}", + Common::FS::PathToUTF8String(filename)); return {}; } - file.ReadBytes(&telemetry_id, sizeof(u64)); - if (telemetry_id == 0) { + + if (!file.ReadObject(telemetry_id) || telemetry_id == 0) { LOG_ERROR(Frontend, "telemetry_id is 0. Generating a new one.", telemetry_id); generate_new_id = true; } } if (generate_new_id) { - Common::FS::IOFile file(filename, "wb"); + Common::FS::IOFile file{filename, Common::FS::FileAccessMode::Write, + Common::FS::FileType::BinaryFile}; + if (!file.IsOpen()) { - LOG_ERROR(Core, "failed to open telemetry_id: {}", filename); + LOG_ERROR(Core, "failed to open telemetry_id: {}", + Common::FS::PathToUTF8String(filename)); return {}; } + telemetry_id = GenerateTelemetryId(); - file.WriteBytes(&telemetry_id, sizeof(u64)); + + if (!file.WriteObject(telemetry_id)) { + LOG_ERROR(Core, "Failed to write telemetry_id to file."); + } } return telemetry_id; @@ -104,15 +116,20 @@ u64 GetTelemetryId() { u64 RegenerateTelemetryId() { const u64 new_telemetry_id{GenerateTelemetryId()}; - const std::string filename{Common::FS::GetUserPath(Common::FS::UserPath::ConfigDir) + - "telemetry_id"}; + const auto filename = Common::FS::GetYuzuPath(Common::FS::YuzuPath::ConfigDir) / "telemetry_id"; + + Common::FS::IOFile file{filename, Common::FS::FileAccessMode::Write, + Common::FS::FileType::BinaryFile}; - Common::FS::IOFile file(filename, "wb"); if (!file.IsOpen()) { - LOG_ERROR(Core, "failed to open telemetry_id: {}", filename); + LOG_ERROR(Core, "failed to open telemetry_id: {}", Common::FS::PathToUTF8String(filename)); return {}; } - file.WriteBytes(&new_telemetry_id, sizeof(u64)); + + if (!file.WriteObject(new_telemetry_id)) { + LOG_ERROR(Core, "Failed to write telemetry_id to file."); + } + return new_telemetry_id; } |