common: fs: Rework the Common Filesystem interface to make use of std::filesystem (#6270)
* common: fs: fs_types: Create filesystem types Contains various filesystem types used by the Common::FS library * common: fs: fs_util: Add std::string to std::u8string conversion utility * common: fs: path_util: Add utlity functions for paths Contains various utility functions for getting or manipulating filesystem paths used by the Common::FS library * common: fs: file: Rewrite the IOFile implementation * common: fs: Reimplement Common::FS library using std::filesystem * common: fs: fs_paths: Add fs_paths to replace common_paths * common: fs: path_util: Add the rest of the path functions * common: Remove the previous Common::FS implementation * general: Remove unused fs includes * string_util: Remove unused function and include * nvidia_flags: Migrate to the new Common::FS library * settings: Migrate to the new Common::FS library * logging: backend: Migrate to the new Common::FS library * core: Migrate to the new Common::FS library * perf_stats: Migrate to the new Common::FS library * reporter: Migrate to the new Common::FS library * telemetry_session: Migrate to the new Common::FS library * key_manager: Migrate to the new Common::FS library * bis_factory: Migrate to the new Common::FS library * registered_cache: Migrate to the new Common::FS library * xts_archive: Migrate to the new Common::FS library * service: acc: Migrate to the new Common::FS library * applets/profile: Migrate to the new Common::FS library * applets/web: Migrate to the new Common::FS library * service: filesystem: Migrate to the new Common::FS library * loader: Migrate to the new Common::FS library * gl_shader_disk_cache: Migrate to the new Common::FS library * nsight_aftermath_tracker: Migrate to the new Common::FS library * vulkan_library: Migrate to the new Common::FS library * configure_debug: Migrate to the new Common::FS library * game_list_worker: Migrate to the new Common::FS library * config: Migrate to the new Common::FS library * configure_filesystem: Migrate to the new Common::FS library * configure_per_game_addons: Migrate to the new Common::FS library * configure_profile_manager: Migrate to the new Common::FS library * configure_ui: Migrate to the new Common::FS library * input_profiles: Migrate to the new Common::FS library * yuzu_cmd: config: Migrate to the new Common::FS library * yuzu_cmd: Migrate to the new Common::FS library * vfs_real: Migrate to the new Common::FS library * vfs: Migrate to the new Common::FS library * vfs_libzip: Migrate to the new Common::FS library * service: bcat: Migrate to the new Common::FS library * yuzu: main: Migrate to the new Common::FS library * vfs_real: Delete the contents of an existing file in CreateFile Current usages of CreateFile expect to delete the contents of an existing file, retain this behavior for now. * input_profiles: Don't iterate the input profile dir if it does not exist Silences an error produced in the log if the directory does not exist. * game_list_worker: Skip parsing file if the returned VfsFile is nullptr Prevents crashes in GetLoader when the virtual file is nullptr * common: fs: Validate paths for path length * service: filesystem: Open the mod load directory as read only
This commit is contained in:
parent
08a5cf0b5b
commit
065867e2c2
74 changed files with 3785 additions and 2169 deletions
|
@ -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());
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue