code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>

namespace FileSys::SystemArchive::SharedFontData {

extern const std::array<unsigned char, 217276> FONT_CHINESE_SIMPLIFIED;

} // namespace FileSys::SystemArchive::SharedFontData

repo_name: litucks/torzu

license: mit


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>

namespace FileSys::SystemArchive::SharedFontData {

extern const std::array<unsigned char, 222236> FONT_CHINESE_TRADITIONAL;

} // namespace FileSys::SystemArchive::SharedFontData


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>

namespace FileSys::SystemArchive::SharedFontData {

extern const std::array<unsigned char, 293516> FONT_EXTENDED_CHINESE_SIMPLIFIED;

} // namespace FileSys::SystemArchive::SharedFontData


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>

namespace FileSys::SystemArchive::SharedFontData {

extern const std::array<unsigned char, 217276> FONT_KOREAN;

} // namespace FileSys::SystemArchive::SharedFontData


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>

namespace FileSys::SystemArchive::SharedFontData {

extern const std::array<unsigned char, 6024> FONT_NINTENDO_EXTENDED;

} // namespace FileSys::SystemArchive::SharedFontData


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <array>

namespace FileSys::SystemArchive::SharedFontData {

extern const std::array<unsigned char, 217276> FONT_STANDARD;

} // namespace FileSys::SystemArchive::SharedFontData


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/file_sys/system_archive/mii_model.h"
#include "core/file_sys/vfs/vfs_vector.h"

namespace FileSys::SystemArchive {

namespace MiiModelData {

constexpr std::array<u8, 0x10> NFTR_STANDARD{'N',  'F',  'T',  'R',  0x01, 0x00, 0x00, 0x00,
                                             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
constexpr std::array<u8, 0x10> NFSR_STANDARD{'N',  'F',  'S',  'R',  0x01, 0x00, 0x00, 0x00,
                                             0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

constexpr auto TEXTURE_LOW_LINEAR = NFTR_STANDARD;
constexpr auto TEXTURE_LOW_SRGB = NFTR_STANDARD;
constexpr auto TEXTURE_MID_LINEAR = NFTR_STANDARD;
constexpr auto TEXTURE_MID_SRGB = NFTR_STANDARD;
constexpr auto SHAPE_HIGH = NFSR_STANDARD;
constexpr auto SHAPE_MID = NFSR_STANDARD;

} // namespace MiiModelData

VirtualDir MiiModel() {
    auto out = std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{},
                                                    std::vector<VirtualDir>{}, "data");

    out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_LOW_LINEAR, "NXTextureLowLinear.dat"));
    out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_LOW_SRGB, "NXTextureLowSRGB.dat"));
    out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_MID_LINEAR, "NXTextureMidLinear.dat"));
    out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_MID_SRGB, "NXTextureMidSRGB.dat"));
    out->AddFile(MakeArrayFile(MiiModelData::SHAPE_HIGH, "ShapeHigh.dat"));
    out->AddFile(MakeArrayFile(MiiModelData::SHAPE_MID, "ShapeMid.dat"));

    return out;
}

} // namespace FileSys::SystemArchive


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/file_sys/vfs/vfs_types.h"

namespace FileSys::SystemArchive {

VirtualDir MiiModel();

} // namespace FileSys::SystemArchive


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <fmt/format.h>
#include "common/common_types.h"
#include "core/file_sys/system_archive/ng_word.h"
#include "core/file_sys/vfs/vfs_vector.h"

namespace FileSys::SystemArchive {

namespace NgWord1Data {

constexpr std::size_t NUMBER_WORD_TXT_FILES = 0x10;

// Should this archive replacement mysteriously not work on a future game, consider updating.
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x20}; // 11.0.1 System Version

constexpr std::array<u8, 30> WORD_TXT{
    0xFE, 0xFF, 0x00, 0x5E, 0x00, 0x76, 0x00, 0x65, 0x00, 0x72, 0x00, 0x79, 0x00, 0x62, 0x00,
    0x61, 0x00, 0x64, 0x00, 0x77, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x64, 0x00, 0x24, 0x00, 0x0A,
}; // "^verybadword$" in UTF-16

} // namespace NgWord1Data

VirtualDir NgWord1() {
    std::vector<VirtualFile> files;
    files.reserve(NgWord1Data::NUMBER_WORD_TXT_FILES);

    for (std::size_t i = 0; i < files.size(); ++i) {
        files.push_back(MakeArrayFile(NgWord1Data::WORD_TXT, fmt::format("{}.txt", i)));
    }

    files.push_back(MakeArrayFile(NgWord1Data::WORD_TXT, "common.txt"));
    files.push_back(MakeArrayFile(NgWord1Data::VERSION_DAT, "version.dat"));

    return std::make_shared<VectorVfsDirectory>(std::move(files), std::vector<VirtualDir>{},
                                                "data");
}

namespace NgWord2Data {

constexpr std::size_t NUMBER_AC_NX_FILES = 0x10;

// Should this archive replacement mysteriously not work on a future game, consider updating.
constexpr std::array<u8, 4> VERSION_DAT{0x0, 0x0, 0x0, 0x1A}; // 11.0.1 System Version

constexpr std::array<u8, 0x2C> AC_NX_DATA{
    0x1F, 0x8B, 0x08, 0x08, 0xD5, 0x2C, 0x09, 0x5C, 0x04, 0x00, 0x61, 0x63, 0x72, 0x61, 0x77,
    0x00, 0xED, 0xC1, 0x01, 0x0D, 0x00, 0x00, 0x00, 0xC2, 0x20, 0xFB, 0xA7, 0xB6, 0xC7, 0x07,
    0x0C, 0x00, 0x00, 0x00, 0xC8, 0x3B, 0x11, 0x00, 0x1C, 0xC7, 0x00, 0x10, 0x00, 0x00,
}; // Deserializes to no bad words

} // namespace NgWord2Data

VirtualDir NgWord2() {
    std::vector<VirtualFile> files;
    files.reserve(NgWord2Data::NUMBER_AC_NX_FILES * 3);

    for (std::size_t i = 0; i < NgWord2Data::NUMBER_AC_NX_FILES; ++i) {
        files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b1_nx", i)));
        files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b2_nx", i)));
        files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_not_b_nx", i)));
    }

    files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_b1_nx"));
    files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_b2_nx"));
    files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_not_b_nx"));
    files.push_back(MakeArrayFile(NgWord2Data::VERSION_DAT, "version.dat"));

    return std::make_shared<VectorVfsDirectory>(std::move(files), std::vector<VirtualDir>{},
                                                "data");
}

} // namespace FileSys::SystemArchive


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/file_sys/vfs/vfs_types.h"

namespace FileSys::SystemArchive {

VirtualDir NgWord1();
VirtualDir NgWord2();

} // namespace FileSys::SystemArchive


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/file_sys/system_archive/data/font_chinese_simplified.h"
#include "core/file_sys/system_archive/data/font_chinese_traditional.h"
#include "core/file_sys/system_archive/data/font_extended_chinese_simplified.h"
#include "core/file_sys/system_archive/data/font_korean.h"
#include "core/file_sys/system_archive/data/font_nintendo_extended.h"
#include "core/file_sys/system_archive/data/font_standard.h"
#include "core/file_sys/system_archive/shared_font.h"
#include "core/file_sys/vfs/vfs_vector.h"
#include "core/hle/service/ns/platform_service_manager.h"

namespace FileSys::SystemArchive {

namespace {

template <std::size_t Size>
VirtualFile PackBFTTF(const std::array<u8, Size>& data, const std::string& name) {
    std::vector<u32> vec(Size / sizeof(u32));
    std::memcpy(vec.data(), data.data(), vec.size() * sizeof(u32));

    std::vector<u8> bfttf(Size + sizeof(u64));

    size_t offset = 0;
    Service::NS::EncryptSharedFont(vec, bfttf, offset);
    return std::make_shared<VectorVfsFile>(std::move(bfttf), name);
}

} // Anonymous namespace

VirtualDir FontNintendoExtension() {
    return std::make_shared<VectorVfsDirectory>(
        std::vector<VirtualFile>{
            PackBFTTF(SharedFontData::FONT_NINTENDO_EXTENDED, "nintendo_ext_003.bfttf"),
            PackBFTTF(SharedFontData::FONT_NINTENDO_EXTENDED, "nintendo_ext2_003.bfttf"),
        },
        std::vector<VirtualDir>{});
}

VirtualDir FontStandard() {
    return std::make_shared<VectorVfsDirectory>(
        std::vector<VirtualFile>{
            PackBFTTF(SharedFontData::FONT_STANDARD, "nintendo_udsg-r_std_003.bfttf"),
        },
        std::vector<VirtualDir>{});
}

VirtualDir FontKorean() {
    return std::make_shared<VectorVfsDirectory>(
        std::vector<VirtualFile>{
            PackBFTTF(SharedFontData::FONT_KOREAN, "nintendo_udsg-r_ko_003.bfttf"),
        },
        std::vector<VirtualDir>{});
}

VirtualDir FontChineseTraditional() {
    return std::make_shared<VectorVfsDirectory>(
        std::vector<VirtualFile>{
            PackBFTTF(SharedFontData::FONT_CHINESE_TRADITIONAL,
                      "nintendo_udjxh-db_zh-tw_003.bfttf"),
        },
        std::vector<VirtualDir>{});
}

VirtualDir FontChineseSimple() {
    return std::make_shared<VectorVfsDirectory>(
        std::vector<VirtualFile>{
            PackBFTTF(SharedFontData::FONT_CHINESE_SIMPLIFIED,
                      "nintendo_udsg-r_org_zh-cn_003.bfttf"),
            PackBFTTF(SharedFontData::FONT_EXTENDED_CHINESE_SIMPLIFIED,
                      "nintendo_udsg-r_ext_zh-cn_003.bfttf"),
        },
        std::vector<VirtualDir>{});
}

} // namespace FileSys::SystemArchive


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/file_sys/vfs/vfs_types.h"

namespace FileSys::SystemArchive {

VirtualDir FontNintendoExtension();
VirtualDir FontStandard();
VirtualDir FontKorean();
VirtualDir FontChineseTraditional();
VirtualDir FontChineseSimple();

} // namespace FileSys::SystemArchive


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/logging/log.h"
#include "core/file_sys/romfs.h"
#include "core/file_sys/system_archive/mii_model.h"
#include "core/file_sys/system_archive/ng_word.h"
#include "core/file_sys/system_archive/shared_font.h"
#include "core/file_sys/system_archive/system_archive.h"
#include "core/file_sys/system_archive/system_version.h"
#include "core/file_sys/system_archive/time_zone_binary.h"

namespace FileSys::SystemArchive {

constexpr u64 SYSTEM_ARCHIVE_BASE_TITLE_ID = 0x0100000000000800;
constexpr std::size_t SYSTEM_ARCHIVE_COUNT = 0x28;

using SystemArchiveSupplier = VirtualDir (*)();

struct SystemArchiveDescriptor {
    u64 title_id;
    const char* name;
    SystemArchiveSupplier supplier;
};

constexpr std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHIVES{{
    {0x0100000000000800, "CertStore", nullptr},
    {0x0100000000000801, "ErrorMessage", nullptr},
    {0x0100000000000802, "MiiModel", &MiiModel},
    {0x0100000000000803, "BrowserDll", nullptr},
    {0x0100000000000804, "Help", nullptr},
    {0x0100000000000805, "SharedFont", nullptr},
    {0x0100000000000806, "NgWord", &NgWord1},
    {0x0100000000000807, "SsidList", nullptr},
    {0x0100000000000808, "Dictionary", nullptr},
    {0x0100000000000809, "SystemVersion", &SystemVersion},
    {0x010000000000080A, "AvatarImage", nullptr},
    {0x010000000000080B, "LocalNews", nullptr},
    {0x010000000000080C, "Eula", nullptr},
    {0x010000000000080D, "UrlBlackList", nullptr},
    {0x010000000000080E, "TimeZoneBinary", &TimeZoneBinary},
    {0x010000000000080F, "CertStoreCruiser", nullptr},
    {0x0100000000000810, "FontNintendoExtension", &FontNintendoExtension},
    {0x0100000000000811, "FontStandard", &FontStandard},
    {0x0100000000000812, "FontKorean", &FontKorean},
    {0x0100000000000813, "FontChineseTraditional", &FontChineseTraditional},
    {0x0100000000000814, "FontChineseSimple", &FontChineseSimple},
    {0x0100000000000815, "FontBfcpx", nullptr},
    {0x0100000000000816, "SystemUpdate", nullptr},
    {0x0100000000000817, "0100000000000817", nullptr},
    {0x0100000000000818, "FirmwareDebugSettings", nullptr},
    {0x0100000000000819, "BootImagePackage", nullptr},
    {0x010000000000081A, "BootImagePackageSafe", nullptr},
    {0x010000000000081B, "BootImagePackageExFat", nullptr},
    {0x010000000000081C, "BootImagePackageExFatSafe", nullptr},
    {0x010000000000081D, "FatalMessage", nullptr},
    {0x010000000000081E, "ControllerIcon", nullptr},
    {0x010000000000081F, "PlatformConfigIcosa", nullptr},
    {0x0100000000000820, "PlatformConfigCopper", nullptr},
    {0x0100000000000821, "PlatformConfigHoag", nullptr},
    {0x0100000000000822, "ControllerFirmware", nullptr},
    {0x0100000000000823, "NgWord2", &NgWord2},
    {0x0100000000000824, "PlatformConfigIcosaMariko", nullptr},
    {0x0100000000000825, "ApplicationBlackList", nullptr},
    {0x0100000000000826, "RebootlessSystemUpdateVersion", nullptr},
    {0x0100000000000827, "ContentActionTable", nullptr},
}};

VirtualFile SynthesizeSystemArchive(const u64 title_id) {
    if (title_id < SYSTEM_ARCHIVES.front().title_id || title_id > SYSTEM_ARCHIVES.back().title_id) {
        return nullptr;
    }

    const auto& desc = SYSTEM_ARCHIVES[title_id - SYSTEM_ARCHIVE_BASE_TITLE_ID];

    LOG_INFO(Service_FS, "Synthesizing system archive '{}' (0x{:016X}).", desc.name, desc.title_id);

    if (desc.supplier == nullptr) {
        return nullptr;
    }

    const auto dir = desc.supplier();

    if (dir == nullptr) {
        return nullptr;
    }

    const auto romfs = CreateRomFS(dir);

    if (romfs == nullptr) {
        return nullptr;
    }

    LOG_INFO(Service_FS, "    - System archive generation successful!");
    return romfs;
}
} // namespace FileSys::SystemArchive


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "common/common_types.h"
#include "core/file_sys/vfs/vfs_types.h"

namespace FileSys::SystemArchive {

VirtualFile SynthesizeSystemArchive(u64 title_id);

} // namespace FileSys::SystemArchive


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/logging/log.h"
#include "core/file_sys/system_archive/system_version.h"
#include "core/file_sys/vfs/vfs_vector.h"
#include "core/hle/api_version.h"

namespace FileSys::SystemArchive {

std::string GetLongDisplayVersion() {
    return HLE::ApiVersion::DISPLAY_TITLE;
}

VirtualDir SystemVersion() {
    LOG_WARNING(Common_Filesystem, "called - Using hardcoded firmware version '{}'",
                GetLongDisplayVersion());

    VirtualFile file = std::make_shared<VectorVfsFile>(std::vector<u8>(0x100), "file");
    file->WriteObject(HLE::ApiVersion::HOS_VERSION_MAJOR, 0);
    file->WriteObject(HLE::ApiVersion::HOS_VERSION_MINOR, 1);
    file->WriteObject(HLE::ApiVersion::HOS_VERSION_MICRO, 2);
    file->WriteObject(HLE::ApiVersion::SDK_REVISION_MAJOR, 4);
    file->WriteObject(HLE::ApiVersion::SDK_REVISION_MINOR, 5);
    file->WriteArray(HLE::ApiVersion::PLATFORM_STRING,
                     std::min<u64>(sizeof(HLE::ApiVersion::PLATFORM_STRING), 0x20ULL), 0x8);
    file->WriteArray(HLE::ApiVersion::VERSION_HASH,
                     std::min<u64>(sizeof(HLE::ApiVersion::VERSION_HASH), 0x40ULL), 0x28);
    file->WriteArray(HLE::ApiVersion::DISPLAY_VERSION,
                     std::min<u64>(sizeof(HLE::ApiVersion::DISPLAY_VERSION), 0x18ULL), 0x68);
    file->WriteArray(HLE::ApiVersion::DISPLAY_TITLE,
                     std::min<u64>(sizeof(HLE::ApiVersion::DISPLAY_TITLE), 0x80ULL), 0x80);
    return std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{file},
                                                std::vector<VirtualDir>{}, "data");
}

} // namespace FileSys::SystemArchive


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <string>
#include "core/file_sys/vfs/vfs_types.h"

namespace FileSys::SystemArchive {

std::string GetLongDisplayVersion();

VirtualDir SystemVersion();

} // namespace FileSys::SystemArchive


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <vector>

#include "common/swap.h"
#include "core/file_sys/system_archive/time_zone_binary.h"
#include "core/file_sys/vfs/vfs_vector.h"

#include "nx_tzdb.h"

namespace FileSys::SystemArchive {

const static std::map<std::string, const std::map<const char*, const std::vector<u8>>&>
    tzdb_zoneinfo_dirs = {{"Africa", NxTzdb::africa},
                          {"America", NxTzdb::america},
                          {"Antarctica", NxTzdb::antarctica},
                          {"Arctic", NxTzdb::arctic},
                          {"Asia", NxTzdb::asia},
                          {"Atlantic", NxTzdb::atlantic},
                          {"Australia", NxTzdb::australia},
                          {"Brazil", NxTzdb::brazil},
                          {"Canada", NxTzdb::canada},
                          {"Chile", NxTzdb::chile},
                          {"Etc", NxTzdb::etc},
                          {"Europe", NxTzdb::europe},
                          {"Indian", NxTzdb::indian},
                          {"Mexico", NxTzdb::mexico},
                          {"Pacific", NxTzdb::pacific},
                          {"US", NxTzdb::us}};

const static std::map<std::string, const std::map<const char*, const std::vector<u8>>&>
    tzdb_america_dirs = {{"Argentina", NxTzdb::america_argentina},
                         {"Indiana", NxTzdb::america_indiana},
                         {"Kentucky", NxTzdb::america_kentucky},
                         {"North_Dakota", NxTzdb::america_north_dakota}};

static void GenerateFiles(std::vector<VirtualFile>& directory,
                          const std::map<const char*, const std::vector<u8>>& files) {
    for (const auto& [filename, data] : files) {
        const auto data_copy{data};
        const std::string filename_copy{filename};
        VirtualFile file{
            std::make_shared<VectorVfsFile>(std::move(data_copy), std::move(filename_copy))};
        directory.push_back(file);
    }
}

static std::vector<VirtualFile> GenerateZoneinfoFiles() {
    std::vector<VirtualFile> zoneinfo_files;
    GenerateFiles(zoneinfo_files, NxTzdb::zoneinfo);
    return zoneinfo_files;
}

VirtualDir TimeZoneBinary() {
    std::vector<VirtualDir> america_sub_dirs;
    for (const auto& [dir_name, files] : tzdb_america_dirs) {
        std::vector<VirtualFile> vfs_files;
        GenerateFiles(vfs_files, files);
        america_sub_dirs.push_back(std::make_shared<VectorVfsDirectory>(
            std::move(vfs_files), std::vector<VirtualDir>{}, dir_name));
    }

    std::vector<VirtualDir> zoneinfo_sub_dirs;
    for (const auto& [dir_name, files] : tzdb_zoneinfo_dirs) {
        std::vector<VirtualFile> vfs_files;
        GenerateFiles(vfs_files, files);
        if (dir_name == "America") {
            zoneinfo_sub_dirs.push_back(std::make_shared<VectorVfsDirectory>(
                std::move(vfs_files), std::move(america_sub_dirs), dir_name));
        } else {
            zoneinfo_sub_dirs.push_back(std::make_shared<VectorVfsDirectory>(
                std::move(vfs_files), std::vector<VirtualDir>{}, dir_name));
        }
    }

    std::vector<VirtualDir> zoneinfo_dir{std::make_shared<VectorVfsDirectory>(
        GenerateZoneinfoFiles(), std::move(zoneinfo_sub_dirs), "zoneinfo")};
    std::vector<VirtualFile> root_files;
    GenerateFiles(root_files, NxTzdb::base);

    return std::make_shared<VectorVfsDirectory>(std::move(root_files), std::move(zoneinfo_dir),
                                                "data");
}

} // namespace FileSys::SystemArchive


code:
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include "core/file_sys/vfs/vfs_types.h"

namespace FileSys::SystemArchive {

VirtualDir TimeZoneBinary();

} // namespace FileSys::SystemArchive


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <algorithm>
#include <numeric>
#include <string>
#include "common/fs/path_util.h"
#include "core/file_sys/vfs/vfs.h"

namespace FileSys {

VfsFilesystem::VfsFilesystem(VirtualDir root_) : root(std::move(root_)) {}

VfsFilesystem::~VfsFilesystem() = default;

std::string VfsFilesystem::GetName() const {
    return root->GetName();
}

bool VfsFilesystem::IsReadable() const {
    return root->IsReadable();
}

bool VfsFilesystem::IsWritable() const {
    return root->IsWritable();
}

VfsEntryType VfsFilesystem::GetEntryType(std::string_view path_) const {
    const auto path = Common::FS::SanitizePath(path_);
    if (root->GetFileRelative(path) != nullptr)
        return VfsEntryType::File;
    if (root->GetDirectoryRelative(path) != nullptr)
        return VfsEntryType::Directory;

    return VfsEntryType::None;
}

VirtualFile VfsFilesystem::OpenFile(std::string_view path_, OpenMode perms) {
    const auto path = Common::FS::SanitizePath(path_);
    return root->GetFileRelative(path);
}

VirtualFile VfsFilesystem::CreateFile(std::string_view path_, OpenMode perms) {
    const auto path = Common::FS::SanitizePath(path_);
    return root->CreateFileRelative(path);
}

VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) {
    const auto old_path = Common::FS::SanitizePath(old_path_);
    const auto new_path = Common::FS::SanitizePath(new_path_);

    // VfsDirectory impls are only required to implement copy across the current directory.
    if (Common::FS::GetParentPath(old_path) == Common::FS::GetParentPath(new_path)) {
        if (!root->Copy(Common::FS::GetFilename(old_path), Common::FS::GetFilename(new_path)))
            return nullptr;
        return OpenFile(new_path, OpenMode::ReadWrite);
    }

    // Do it using RawCopy. Non-default impls are encouraged to optimize this.
    const auto old_file = OpenFile(old_path, OpenMode::Read);
    if (old_file == nullptr)
        return nullptr;
    auto new_file = OpenFile(new_path, OpenMode::Read);
    if (new_file != nullptr)
        return nullptr;
    new_file = CreateFile(new_path, OpenMode::Write);
    if (new_file == nullptr)
        return nullptr;
    if (!VfsRawCopy(old_file, new_file))
        return nullptr;
    return new_file;
}

VirtualFile VfsFilesystem::MoveFile(std::string_view old_path, std::string_view new_path) {
    const auto sanitized_old_path = Common::FS::SanitizePath(old_path);
    const auto sanitized_new_path = Common::FS::SanitizePath(new_path);

    // Again, non-default impls are highly encouraged to provide a more optimized version of this.
    auto out = CopyFile(sanitized_old_path, sanitized_new_path);
    if (out == nullptr)
        return nullptr;
    if (DeleteFile(sanitized_old_path))
        return out;
    return nullptr;
}

bool VfsFilesystem::DeleteFile(std::string_view path_) {
    const auto path = Common::FS::SanitizePath(path_);
    auto parent = OpenDirectory(Common::FS::GetParentPath(path), OpenMode::Write);
    if (parent == nullptr)
        return false;
    return parent->DeleteFile(Common::FS::GetFilename(path));
}

VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, OpenMode perms) {
    const auto path = Common::FS::SanitizePath(path_);
    return root->GetDirectoryRelative(path);
}

VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, OpenMode perms) {
    const auto path = Common::FS::SanitizePath(path_);
    return root->CreateDirectoryRelative(path);
}

VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_view new_path_) {
    const auto old_path = Common::FS::SanitizePath(old_path_);
    const auto new_path = Common::FS::SanitizePath(new_path_);

    // Non-default impls are highly encouraged to provide a more optimized version of this.
    auto old_dir = OpenDirectory(old_path, OpenMode::Read);
    if (old_dir == nullptr)
        return nullptr;
    auto new_dir = OpenDirectory(new_path, OpenMode::Read);
    if (new_dir != nullptr)
        return nullptr;
    new_dir = CreateDirectory(new_path, OpenMode::Write);
    if (new_dir == nullptr)
        return nullptr;

    for (const auto& file : old_dir->GetFiles()) {
        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->GetName(), new_path + '/' + dir->GetName());
        if (x == nullptr)
            return nullptr;
    }

    return new_dir;
}

VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path, std::string_view new_path) {
    const auto sanitized_old_path = Common::FS::SanitizePath(old_path);
    const auto sanitized_new_path = Common::FS::SanitizePath(new_path);

    // Non-default impls are highly encouraged to provide a more optimized version of this.
    auto out = CopyDirectory(sanitized_old_path, sanitized_new_path);
    if (out == nullptr)
        return nullptr;
    if (DeleteDirectory(sanitized_old_path))
        return out;
    return nullptr;
}

bool VfsFilesystem::DeleteDirectory(std::string_view path_) {
    const auto path = Common::FS::SanitizePath(path_);
    auto parent = OpenDirectory(Common::FS::GetParentPath(path), OpenMode::Write);
    if (parent == nullptr)
        return false;
    return parent->DeleteSubdirectoryRecursive(Common::FS::GetFilename(path));
}

VfsFile::~VfsFile() = default;

std::string VfsFile::GetExtension() const {
    return std::string(Common::FS::GetExtensionFromFilename(GetName()));
}

VfsDirectory::~VfsDirectory() = default;

std::optional<u8> VfsFile::ReadByte(std::size_t offset) const {
    u8 out{};
    const std::size_t size = Read(&out, sizeof(u8), offset);
    if (size == 1) {
        return out;
    }

    return std::nullopt;
}

std::vector<u8> VfsFile::ReadBytes(std::size_t size, std::size_t offset) const {
    std::vector<u8> out(size);
    std::size_t read_size = Read(out.data(), size, offset);
    out.resize(read_size);
    return out;
}

std::vector<u8> VfsFile::ReadAllBytes() const {
    return ReadBytes(GetSize());
}

bool VfsFile::WriteByte(u8 data, std::size_t offset) {
    return Write(&data, 1, offset) == 1;
}

std::size_t VfsFile::WriteBytes(const std::vector<u8>& data, std::size_t offset) {
    return Write(data.data(), data.size(), offset);
}

std::string VfsFile::GetFullPath() const {
    if (GetContainingDirectory() == nullptr)
        return '/' + GetName();

    return GetContainingDirectory()->GetFullPath() + '/' + GetName();
}

VirtualFile VfsDirectory::GetFileRelative(std::string_view path) const {
    auto vec = Common::FS::SplitPathComponents(path);
    if (vec.empty()) {
        return nullptr;
    }

    if (vec.size() == 1) {
        return GetFile(vec[0]);
    }

    auto dir = GetSubdirectory(vec[0]);
    for (std::size_t component = 1; component < vec.size() - 1; ++component) {
        if (dir == nullptr) {
            return nullptr;
        }

        dir = dir->GetSubdirectory(vec[component]);
    }

    if (dir == nullptr) {
        return nullptr;
    }

    return dir->GetFile(vec.back());
}

VirtualFile VfsDirectory::GetFileAbsolute(std::string_view path) const {
    if (IsRoot()) {
        return GetFileRelative(path);
    }

    return GetParentDirectory()->GetFileAbsolute(path);
}

VirtualDir VfsDirectory::GetDirectoryRelative(std::string_view path) const {
    auto vec = Common::FS::SplitPathComponents(path);
    if (vec.empty()) {
        // TODO(DarkLordZach): Return this directory if path is '/' or similar. Can't currently
        // because of const-ness
        return nullptr;
    }

    auto dir = GetSubdirectory(vec[0]);
    for (std::size_t component = 1; component < vec.size(); ++component) {
        if (dir == nullptr) {
            return nullptr;
        }

        dir = dir->GetSubdirectory(vec[component]);
    }

    return dir;
}

VirtualDir VfsDirectory::GetDirectoryAbsolute(std::string_view path) const {
    if (IsRoot()) {
        return GetDirectoryRelative(path);
    }

    return GetParentDirectory()->GetDirectoryAbsolute(path);
}

VirtualFile VfsDirectory::GetFile(std::string_view name) const {
    const auto& files = GetFiles();
    const auto iter = std::find_if(files.begin(), files.end(),
                                   [&name](const auto& file1) { return name == file1->GetName(); });
    return iter == files.end() ? nullptr : *iter;
}

FileTimeStampRaw VfsDirectory::GetFileTimeStamp([[maybe_unused]] std::string_view path) const {
    return {};
}

VirtualDir VfsDirectory::GetSubdirectory(std::string_view name) const {
    const auto& subs = GetSubdirectories();
    const auto iter = std::find_if(subs.begin(), subs.end(),
                                   [&name](const auto& file1) { return name == file1->GetName(); });
    return iter == subs.end() ? nullptr : *iter;
}

bool VfsDirectory::IsRoot() const {
    return GetParentDirectory() == nullptr;
}

std::size_t VfsDirectory::GetSize() const {
    const auto& files = GetFiles();
    const auto sum_sizes = [](const auto& range) {
        return std::accumulate(range.begin(), range.end(), 0ULL,
                               [](const auto& f1, const auto& f2) { return f1 + f2->GetSize(); });
    };

    const auto file_total = sum_sizes(files);
    const auto& sub_dir = GetSubdirectories();
    const auto subdir_total = sum_sizes(sub_dir);

    return file_total + subdir_total;
}

VirtualFile VfsDirectory::CreateFileRelative(std::string_view path) {
    auto vec = Common::FS::SplitPathComponents(path);
    if (vec.empty()) {
        return nullptr;
    }

    if (vec.size() == 1) {
        return CreateFile(vec[0]);
    }

    auto dir = GetSubdirectory(vec[0]);
    if (dir == nullptr) {
        dir = CreateSubdirectory(vec[0]);
        if (dir == nullptr) {
            return nullptr;
        }
    }

    return dir->CreateFileRelative(Common::FS::GetPathWithoutTop(path));
}

VirtualFile VfsDirectory::CreateFileAbsolute(std::string_view path) {
    if (IsRoot()) {
        return CreateFileRelative(path);
    }

    return GetParentDirectory()->CreateFileAbsolute(path);
}

VirtualDir VfsDirectory::CreateDirectoryRelative(std::string_view path) {
    auto vec = Common::FS::SplitPathComponents(path);
    if (vec.empty()) {
        return nullptr;
    }

    if (vec.size() == 1) {
        return CreateSubdirectory(vec[0]);
    }

    auto dir = GetSubdirectory(vec[0]);
    if (dir == nullptr) {
        dir = CreateSubdirectory(vec[0]);
        if (dir == nullptr) {
            return nullptr;
        }
    }

    return dir->CreateDirectoryRelative(Common::FS::GetPathWithoutTop(path));
}

VirtualDir VfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
    if (IsRoot()) {
        return CreateDirectoryRelative(path);
    }

    return GetParentDirectory()->CreateDirectoryAbsolute(path);
}

bool VfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
    auto dir = GetSubdirectory(name);
    if (dir == nullptr) {
        return false;
    }

    bool success = true;
    for (const auto& file : dir->GetFiles()) {
        if (!DeleteFile(file->GetName())) {
            success = false;
        }
    }

    for (const auto& sdir : dir->GetSubdirectories()) {
        if (!dir->DeleteSubdirectoryRecursive(sdir->GetName())) {
            success = false;
        }
    }

    return success;
}

bool VfsDirectory::CleanSubdirectoryRecursive(std::string_view name) {
    auto dir = GetSubdirectory(name);
    if (dir == nullptr) {
        return false;
    }

    bool success = true;
    for (const auto& file : dir->GetFiles()) {
        if (!dir->DeleteFile(file->GetName())) {
            success = false;
        }
    }

    for (const auto& sdir : dir->GetSubdirectories()) {
        if (!dir->DeleteSubdirectoryRecursive(sdir->GetName())) {
            success = false;
        }
    }

    return success;
}

bool VfsDirectory::Copy(std::string_view src, std::string_view dest) {
    const auto f1 = GetFile(src);
    auto f2 = CreateFile(dest);
    if (f1 == nullptr || f2 == nullptr) {
        return false;
    }

    if (!f2->Resize(f1->GetSize())) {
        DeleteFile(dest);
        return false;
    }

    return f2->WriteBytes(f1->ReadAllBytes()) == f1->GetSize();
}

std::map<std::string, VfsEntryType, std::less<>> VfsDirectory::GetEntries() const {
    std::map<std::string, VfsEntryType, std::less<>> out;
    for (const auto& dir : GetSubdirectories())
        out.emplace(dir->GetName(), VfsEntryType::Directory);
    for (const auto& file : GetFiles())
        out.emplace(file->GetName(), VfsEntryType::File);
    return out;
}

std::string VfsDirectory::GetFullPath() const {
    if (IsRoot())
        return GetName();

    return GetParentDirectory()->GetFullPath() + '/' + GetName();
}

bool ReadOnlyVfsDirectory::IsWritable() const {
    return false;
}

bool ReadOnlyVfsDirectory::IsReadable() const {
    return true;
}

VirtualDir ReadOnlyVfsDirectory::CreateSubdirectory(std::string_view name) {
    return nullptr;
}

VirtualFile ReadOnlyVfsDirectory::CreateFile(std::string_view name) {
    return nullptr;
}

VirtualFile ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) {
    return nullptr;
}

VirtualFile ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) {
    return nullptr;
}

VirtualDir ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
    return nullptr;
}

VirtualDir ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) {
    return nullptr;
}

bool ReadOnlyVfsDirectory::DeleteSubdirectory(std::string_view name) {
    return false;
}

bool ReadOnlyVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
    return false;
}

bool ReadOnlyVfsDirectory::CleanSubdirectoryRecursive(std::string_view name) {
    return false;
}

bool ReadOnlyVfsDirectory::DeleteFile(std::string_view name) {
    return false;
}

bool ReadOnlyVfsDirectory::Rename(std::string_view name) {
    return false;
}

bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, std::size_t block_size) {
    if (file1->GetSize() != file2->GetSize())
        return false;

    std::vector<u8> f1_v(block_size);
    std::vector<u8> f2_v(block_size);
    for (std::size_t i = 0; i < file1->GetSize(); i += block_size) {
        auto f1_vs = file1->Read(f1_v.data(), block_size, i);
        auto f2_vs = file2->Read(f2_v.data(), block_size, i);

        if (f1_vs != f2_vs)
            return false;
        auto iters = std::mismatch(f1_v.begin(), f1_v.end(), f2_v.begin(), f2_v.end());
        if (iters.first != f1_v.end() && iters.second != f2_v.end())
            return false;
    }

    return true;
}

bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, std::size_t block_size) {
    if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
        return false;
    if (!dest->Resize(src->GetSize()))
        return false;

    std::vector<u8> temp(std::min(block_size, src->GetSize()));
    for (std::size_t i = 0; i < src->GetSize(); i += block_size) {
        const auto read = std::min(block_size, src->GetSize() - i);

        if (src->Read(temp.data(), read, i) != read) {
            return false;
        }

        if (dest->Write(temp.data(), read, i) != read) {
            return false;
        }
    }

    return true;
}

bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, std::size_t block_size) {
    if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable())
        return false;

    for (const auto& file : src->GetFiles()) {
        const auto out = dest->CreateFile(file->GetName());
        if (!VfsRawCopy(file, out, block_size))
            return false;
    }

    for (const auto& dir : src->GetSubdirectories()) {
        const auto out = dest->CreateSubdirectory(dir->GetName());
        if (!VfsRawCopyD(dir, out, block_size))
            return false;
    }

    return true;
}

VirtualDir GetOrCreateDirectoryRelative(const VirtualDir& rel, std::string_view path) {
    const auto res = rel->GetDirectoryRelative(path);
    if (res == nullptr)
        return rel->CreateDirectoryRelative(path);
    return res;
}
} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <functional>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <type_traits>
#include <vector>

#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/vfs/vfs_types.h"

namespace FileSys {

// An enumeration representing what can be at the end of a path in a VfsFilesystem
enum class VfsEntryType {
    None,
    File,
    Directory,
};

// A class representing an abstract filesystem. A default implementation given the root VirtualDir
// is provided for convenience, but if the Vfs implementation has any additional state or
// functionality, they will need to override.
class VfsFilesystem {
public:
    YUZU_NON_COPYABLE(VfsFilesystem);
    YUZU_NON_MOVEABLE(VfsFilesystem);

    explicit VfsFilesystem(VirtualDir root);
    virtual ~VfsFilesystem();

    // Gets the friendly name for the filesystem.
    virtual std::string GetName() const;

    // Return whether or not the user has read permissions on this filesystem.
    virtual bool IsReadable() const;
    // Return whether or not the user has write permission on this filesystem.
    virtual bool IsWritable() const;

    // Determine if the entry at path is non-existent, a file, or a directory.
    virtual VfsEntryType GetEntryType(std::string_view path) const;

    // Opens the file with path relative to root. If it doesn't exist, returns nullptr.
    virtual VirtualFile OpenFile(std::string_view path, OpenMode perms);
    // Creates a new, empty file at path
    virtual VirtualFile CreateFile(std::string_view path, OpenMode perms);
    // Copies the file from old_path to new_path, returning the new file on success and nullptr on
    // failure.
    virtual VirtualFile CopyFile(std::string_view old_path, std::string_view new_path);
    // Moves the file from old_path to new_path, returning the moved file on success and nullptr on
    // failure.
    virtual VirtualFile MoveFile(std::string_view old_path, std::string_view new_path);
    // Deletes the file with path relative to root, returning true on success.
    virtual bool DeleteFile(std::string_view path);

    // Opens the directory with path relative to root. If it doesn't exist, returns nullptr.
    virtual VirtualDir OpenDirectory(std::string_view path, OpenMode perms);
    // Creates a new, empty directory at path
    virtual VirtualDir CreateDirectory(std::string_view path, OpenMode perms);
    // Copies the directory from old_path to new_path, returning the new directory on success and
    // nullptr on failure.
    virtual VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path);
    // Moves the directory from old_path to new_path, returning the moved directory on success and
    // nullptr on failure.
    virtual VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path);
    // Deletes the directory with path relative to root, returning true on success.
    virtual bool DeleteDirectory(std::string_view path);

protected:
    // Root directory in default implementation.
    VirtualDir root;
};

// A class representing a file in an abstract filesystem.
class VfsFile {
public:
    YUZU_NON_COPYABLE(VfsFile);
    YUZU_NON_MOVEABLE(VfsFile);

    VfsFile() = default;
    virtual ~VfsFile();

    // Retrieves the file name.
    virtual std::string GetName() const = 0;
    // Retrieves the extension of the file name.
    virtual std::string GetExtension() const;
    // Retrieves the size of the file.
    virtual std::size_t GetSize() const = 0;
    // Resizes the file to new_size. Returns whether or not the operation was successful.
    virtual bool Resize(std::size_t new_size) = 0;
    // Gets a pointer to the directory containing this file, returning nullptr if there is none.
    virtual VirtualDir GetContainingDirectory() const = 0;

    // Returns whether or not the file can be written to.
    virtual bool IsWritable() const = 0;
    // Returns whether or not the file can be read from.
    virtual bool IsReadable() const = 0;

    // The primary method of reading from the file. Reads length bytes into data starting at offset
    // into file. Returns number of bytes successfully read.
    virtual std::size_t Read(u8* data, std::size_t length, std::size_t offset = 0) const = 0;
    // The primary method of writing to the file. Writes length bytes from data starting at offset
    // into file. Returns number of bytes successfully written.
    virtual std::size_t Write(const u8* data, std::size_t length, std::size_t offset = 0) = 0;

    // Reads exactly one byte at the offset provided, returning std::nullopt on error.
    virtual std::optional<u8> ReadByte(std::size_t offset = 0) const;
    // Reads size bytes starting at offset in file into a vector.
    virtual std::vector<u8> ReadBytes(std::size_t size, std::size_t offset = 0) const;
    // Reads all the bytes from the file into a vector. Equivalent to 'file->Read(file->GetSize(),
    // 0)'
    virtual std::vector<u8> ReadAllBytes() const;

    // Reads an array of type T, size number_elements starting at offset.
    // Returns the number of bytes (sizeof(T)*number_elements) read successfully.
    template <typename T>
    std::size_t ReadArray(T* data, std::size_t number_elements, std::size_t offset = 0) const {
        static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");

        return Read(reinterpret_cast<u8*>(data), number_elements * sizeof(T), offset);
    }

    // Reads size bytes into the memory starting at data starting at offset into the file.
    // Returns the number of bytes read successfully.
    template <typename T>
    std::size_t ReadBytes(T* data, std::size_t size, std::size_t offset = 0) const {
        static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
        return Read(reinterpret_cast<u8*>(data), size, offset);
    }

    // Reads one object of type T starting at offset in file.
    // Returns the number of bytes read successfully (sizeof(T)).
    template <typename T>
    std::size_t ReadObject(T* data, std::size_t offset = 0) const {
        static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
        return Read(reinterpret_cast<u8*>(data), sizeof(T), offset);
    }

    // Writes exactly one byte to offset in file and returns whether or not the byte was written
    // successfully.
    virtual bool WriteByte(u8 data, std::size_t offset = 0);
    // Writes a vector of bytes to offset in file and returns the number of bytes successfully
    // written.
    virtual std::size_t WriteBytes(const std::vector<u8>& data, std::size_t offset = 0);

    // Writes an array of type T, size number_elements to offset in file.
    // Returns the number of bytes (sizeof(T)*number_elements) written successfully.
    template <typename T>
    std::size_t WriteArray(const T* data, std::size_t number_elements, std::size_t offset = 0) {
        static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
        return Write(reinterpret_cast<const u8*>(data), number_elements * sizeof(T), offset);
    }

    // Writes size bytes starting at memory location data to offset in file.
    // Returns the number of bytes written successfully.
    template <typename T>
    std::size_t WriteBytes(const T* data, std::size_t size, std::size_t offset = 0) {
        static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
        return Write(reinterpret_cast<const u8*>(data), size, offset);
    }

    // Writes one object of type T to offset in file.
    // Returns the number of bytes written successfully (sizeof(T)).
    template <typename T>
    std::size_t WriteObject(const T& data, std::size_t offset = 0) {
        static_assert(std::is_trivially_copyable_v<T>, "Data type must be trivially copyable.");
        return Write(reinterpret_cast<const u8*>(&data), sizeof(T), offset);
    }

    // Renames the file to name. Returns whether or not the operation was successful.
    virtual bool Rename(std::string_view name) = 0;

    // Returns the full path of this file as a string, recursively
    virtual std::string GetFullPath() const;
};

// A class representing a directory in an abstract filesystem.
class VfsDirectory {
public:
    YUZU_NON_COPYABLE(VfsDirectory);
    YUZU_NON_MOVEABLE(VfsDirectory);

    VfsDirectory() = default;
    virtual ~VfsDirectory();

    // Retrieves the file located at path as if the current directory was root. Returns nullptr if
    // not found.
    virtual VirtualFile GetFileRelative(std::string_view path) const;
    // Calls GetFileRelative(path) on the root of the current directory.
    virtual VirtualFile GetFileAbsolute(std::string_view path) const;

    // Retrieves the directory located at path as if the current directory was root. Returns nullptr
    // if not found.
    virtual VirtualDir GetDirectoryRelative(std::string_view path) const;
    // Calls GetDirectoryRelative(path) on the root of the current directory.
    virtual VirtualDir GetDirectoryAbsolute(std::string_view path) const;

    // Returns a vector containing all of the files in this directory.
    virtual std::vector<VirtualFile> GetFiles() const = 0;
    // Returns the file with filename matching name. Returns nullptr if directory doesn't have a
    // file with name.
    virtual VirtualFile GetFile(std::string_view name) const;

    // Returns a struct containing the file's timestamp.
    virtual FileTimeStampRaw GetFileTimeStamp(std::string_view path) const;

    // Returns a vector containing all of the subdirectories in this directory.
    virtual std::vector<VirtualDir> GetSubdirectories() const = 0;
    // Returns the directory with name matching name. Returns nullptr if directory doesn't have a
    // directory with name.
    virtual VirtualDir GetSubdirectory(std::string_view name) const;

    // Returns whether or not the directory can be written to.
    virtual bool IsWritable() const = 0;
    // Returns whether of not the directory can be read from.
    virtual bool IsReadable() const = 0;

    // Returns whether or not the directory is the root of the current file tree.
    virtual bool IsRoot() const;

    // Returns the name of the directory.
    virtual std::string GetName() const = 0;
    // Returns the total size of all files and subdirectories in this directory.
    virtual std::size_t GetSize() const;
    // Returns the parent directory of this directory. Returns nullptr if this directory is root or
    // has no parent.
    virtual VirtualDir GetParentDirectory() const = 0;

    // Creates a new subdirectory with name name. Returns a pointer to the new directory or nullptr
    // if the operation failed.
    virtual VirtualDir CreateSubdirectory(std::string_view name) = 0;
    // Creates a new file with name name. Returns a pointer to the new file or nullptr if the
    // operation failed.
    virtual VirtualFile CreateFile(std::string_view name) = 0;

    // Creates a new file at the path relative to this directory. Also creates directories if
    // they do not exist and is supported by this implementation. Returns nullptr on any failure.
    virtual VirtualFile CreateFileRelative(std::string_view path);

    // Creates a new file at the path relative to root of this directory. Also creates directories
    // if they do not exist and is supported by this implementation. Returns nullptr on any failure.
    virtual VirtualFile CreateFileAbsolute(std::string_view path);

    // Creates a new directory at the path relative to this directory. Also creates directories if
    // they do not exist and is supported by this implementation. Returns nullptr on any failure.
    virtual VirtualDir CreateDirectoryRelative(std::string_view path);

    // Creates a new directory at the path relative to root of this directory. Also creates
    // directories if they do not exist and is supported by this implementation. Returns nullptr on
    // any failure.
    virtual VirtualDir CreateDirectoryAbsolute(std::string_view path);

    // Deletes the subdirectory with the given name and returns true on success.
    virtual bool DeleteSubdirectory(std::string_view name) = 0;

    // Deletes all subdirectories and files within the provided directory and then deletes
    // the directory itself. Returns true on success.
    virtual bool DeleteSubdirectoryRecursive(std::string_view name);

    // Deletes all subdirectories and files within the provided directory.
    // Unlike DeleteSubdirectoryRecursive, this does not delete the provided directory.
    virtual bool CleanSubdirectoryRecursive(std::string_view name);

    // Returns whether or not the file with name name was deleted successfully.
    virtual bool DeleteFile(std::string_view name) = 0;

    // Returns whether or not this directory was renamed to name.
    virtual bool Rename(std::string_view name) = 0;

    // Returns whether or not the file with name src was successfully copied to a new file with name
    // dest.
    virtual bool Copy(std::string_view src, std::string_view dest);

    // Gets all of the entries directly in the directory (files and dirs), returning a map between
    // item name -> type.
    virtual std::map<std::string, VfsEntryType, std::less<>> GetEntries() const;

    // Returns the full path of this directory as a string, recursively
    virtual std::string GetFullPath() const;
};

// A convenience partial-implementation of VfsDirectory that stubs out methods that should only work
// if writable. This is to avoid redundant empty methods everywhere.
class ReadOnlyVfsDirectory : public VfsDirectory {
public:
    bool IsWritable() const override;
    bool IsReadable() const override;
    VirtualDir CreateSubdirectory(std::string_view name) override;
    VirtualFile CreateFile(std::string_view name) override;
    VirtualFile CreateFileAbsolute(std::string_view path) override;
    VirtualFile CreateFileRelative(std::string_view path) override;
    VirtualDir CreateDirectoryAbsolute(std::string_view path) override;
    VirtualDir CreateDirectoryRelative(std::string_view path) override;
    bool DeleteSubdirectory(std::string_view name) override;
    bool DeleteSubdirectoryRecursive(std::string_view name) override;
    bool CleanSubdirectoryRecursive(std::string_view name) override;
    bool DeleteFile(std::string_view name) override;
    bool Rename(std::string_view name) override;
};

// Compare the two files, byte-for-byte, in increments specified by block_size
bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2,
                std::size_t block_size = 0x1000);

// A method that copies the raw data between two different implementations of VirtualFile. If you
// are using the same implementation, it is probably better to use the Copy method in the parent
// directory of src/dest.
bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, std::size_t block_size = 0x1000);

// A method that performs a similar function to VfsRawCopy above, but instead copies entire
// directories. It suffers the same performance penalties as above and an implementation-specific
// Copy should always be preferred.
bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, std::size_t block_size = 0x1000);

// Checks if the directory at path relative to rel exists. If it does, returns that. If it does not
// it attempts to create it and returns the new dir or nullptr on failure.
VirtualDir GetOrCreateDirectoryRelative(const VirtualDir& rel, std::string_view path);

} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include "core/file_sys/vfs/vfs_cached.h"
#include "core/file_sys/vfs/vfs_types.h"

namespace FileSys {

CachedVfsDirectory::CachedVfsDirectory(VirtualDir&& source_dir)
    : name(source_dir->GetName()), parent(source_dir->GetParentDirectory()) {
    for (auto& dir : source_dir->GetSubdirectories()) {
        dirs.emplace(dir->GetName(), std::make_shared<CachedVfsDirectory>(std::move(dir)));
    }
    for (auto& file : source_dir->GetFiles()) {
        files.emplace(file->GetName(), std::move(file));
    }
}

CachedVfsDirectory::~CachedVfsDirectory() = default;

VirtualFile CachedVfsDirectory::GetFile(std::string_view file_name) const {
    auto it = files.find(file_name);
    if (it != files.end()) {
        return it->second;
    }

    return nullptr;
}

VirtualDir CachedVfsDirectory::GetSubdirectory(std::string_view dir_name) const {
    auto it = dirs.find(dir_name);
    if (it != dirs.end()) {
        return it->second;
    }

    return nullptr;
}

std::vector<VirtualFile> CachedVfsDirectory::GetFiles() const {
    std::vector<VirtualFile> out;
    for (auto& [file_name, file] : files) {
        out.push_back(file);
    }
    return out;
}

std::vector<VirtualDir> CachedVfsDirectory::GetSubdirectories() const {
    std::vector<VirtualDir> out;
    for (auto& [dir_name, dir] : dirs) {
        out.push_back(dir);
    }
    return out;
}

std::string CachedVfsDirectory::GetName() const {
    return name;
}

VirtualDir CachedVfsDirectory::GetParentDirectory() const {
    return parent;
}

} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <string_view>
#include <vector>
#include "core/file_sys/vfs/vfs.h"

namespace FileSys {

class CachedVfsDirectory : public ReadOnlyVfsDirectory {
public:
    CachedVfsDirectory(VirtualDir&& source_directory);

    ~CachedVfsDirectory() override;
    VirtualFile GetFile(std::string_view file_name) const override;
    VirtualDir GetSubdirectory(std::string_view dir_name) const override;
    std::vector<VirtualFile> GetFiles() const override;
    std::vector<VirtualDir> GetSubdirectories() const override;
    std::string GetName() const override;
    VirtualDir GetParentDirectory() const override;

private:
    std::string name;
    VirtualDir parent;
    std::map<std::string, VirtualDir, std::less<>> dirs;
    std::map<std::string, VirtualFile, std::less<>> files;
};

} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <algorithm>
#include <utility>

#include "common/assert.h"
#include "core/file_sys/vfs/vfs_concat.h"
#include "core/file_sys/vfs/vfs_static.h"

namespace FileSys {

ConcatenatedVfsFile::ConcatenatedVfsFile(std::string&& name_, ConcatenationMap&& concatenation_map_)
    : concatenation_map(std::move(concatenation_map_)), name(std::move(name_)) {
    DEBUG_ASSERT(this->VerifyContinuity());
}

bool ConcatenatedVfsFile::VerifyContinuity() const {
    u64 last_offset = 0;
    for (auto& entry : concatenation_map) {
        if (entry.offset != last_offset) {
            return false;
        }

        last_offset = entry.offset + entry.file->GetSize();
    }

    return true;
}

ConcatenatedVfsFile::~ConcatenatedVfsFile() = default;

VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::string&& name,
                                                      std::vector<VirtualFile>&& files) {
    // Fold trivial cases.
    if (files.empty()) {
        return nullptr;
    }
    if (files.size() == 1) {
        return files.front();
    }

    // Make the concatenation map from the input.
    std::vector<ConcatenationEntry> concatenation_map;
    concatenation_map.reserve(files.size());
    u64 last_offset = 0;

    for (auto& file : files) {
        const auto size = file->GetSize();

        concatenation_map.emplace_back(ConcatenationEntry{
            .offset = last_offset,
            .file = std::move(file),
        });

        last_offset += size;
    }

    return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map)));
}

VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(
    u8 filler_byte, std::string&& name, std::vector<std::pair<u64, VirtualFile>>&& files) {
    // Fold trivial cases.
    if (files.empty()) {
        return nullptr;
    }
    if (files.size() == 1) {
        return files.begin()->second;
    }

    // Make the concatenation map from the input.
    std::vector<ConcatenationEntry> concatenation_map;

    concatenation_map.reserve(files.size());
    u64 last_offset = 0;

    // Iteration of a multimap is ordered, so offset will be strictly non-decreasing.
    for (auto& [offset, file] : files) {
        const auto size = file->GetSize();

        if (offset > last_offset) {
            concatenation_map.emplace_back(ConcatenationEntry{
                .offset = last_offset,
                .file = std::make_shared<StaticVfsFile>(filler_byte, offset - last_offset),
            });
        }

        concatenation_map.emplace_back(ConcatenationEntry{
            .offset = offset,
            .file = std::move(file),
        });

        last_offset = offset + size;
    }

    return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map)));
}

std::string ConcatenatedVfsFile::GetName() const {
    if (concatenation_map.empty()) {
        return "";
    }
    if (!name.empty()) {
        return name;
    }
    return concatenation_map.front().file->GetName();
}

std::size_t ConcatenatedVfsFile::GetSize() const {
    if (concatenation_map.empty()) {
        return 0;
    }
    return concatenation_map.back().offset + concatenation_map.back().file->GetSize();
}

bool ConcatenatedVfsFile::Resize(std::size_t new_size) {
    return false;
}

VirtualDir ConcatenatedVfsFile::GetContainingDirectory() const {
    if (concatenation_map.empty()) {
        return nullptr;
    }
    return concatenation_map.front().file->GetContainingDirectory();
}

bool ConcatenatedVfsFile::IsWritable() const {
    return false;
}

bool ConcatenatedVfsFile::IsReadable() const {
    return true;
}

std::size_t ConcatenatedVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
    const ConcatenationEntry key{
        .offset = offset,
        .file = nullptr,
    };

    // Read nothing if the map is empty.
    if (concatenation_map.empty()) {
        return 0;
    }

    // Binary search to find the iterator to the first position we can check.
    // It must exist, since we are not empty and are comparing unsigned integers.
    auto it = std::prev(std::upper_bound(concatenation_map.begin(), concatenation_map.end(), key));
    u64 cur_length = length;
    u64 cur_offset = offset;

    while (cur_length > 0 && it != concatenation_map.end()) {
        // Check if we can read the file at this position.
        const auto& file = it->file;
        const u64 map_offset = it->offset;
        const u64 file_size = file->GetSize();

        if (cur_offset > map_offset + file_size) {
            // Entirely out of bounds read.
            break;
        }

        // Read the file at this position.
        const u64 file_seek = cur_offset - map_offset;
        const u64 intended_read_size = std::min<u64>(cur_length, file_size - file_seek);
        const u64 actual_read_size =
            file->Read(data + (cur_offset - offset), intended_read_size, file_seek);

        // Update tracking.
        cur_offset += actual_read_size;
        cur_length -= actual_read_size;
        it++;

        // If we encountered a short read, we're done.
        if (actual_read_size < intended_read_size) {
            break;
        }
    }

    return cur_offset - offset;
}

std::size_t ConcatenatedVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {
    return 0;
}

bool ConcatenatedVfsFile::Rename(std::string_view new_name) {
    return false;
}

} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <compare>
#include <map>
#include <memory>
#include "core/file_sys/vfs/vfs.h"

namespace FileSys {

// Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently
// read-only.
class ConcatenatedVfsFile : public VfsFile {
private:
    struct ConcatenationEntry {
        u64 offset;
        VirtualFile file;

        auto operator<=>(const ConcatenationEntry& other) const {
            return this->offset <=> other.offset;
        }
    };
    using ConcatenationMap = std::vector<ConcatenationEntry>;

    explicit ConcatenatedVfsFile(std::string&& name,
                                 std::vector<ConcatenationEntry>&& concatenation_map);
    bool VerifyContinuity() const;

public:
    ~ConcatenatedVfsFile() override;

    /// Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases.
    static VirtualFile MakeConcatenatedFile(std::string&& name, std::vector<VirtualFile>&& files);

    /// Convenience function that turns a map of offsets to files into a concatenated file, filling
    /// gaps with a given filler byte.
    static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::string&& name,
                                            std::vector<std::pair<u64, VirtualFile>>&& files);

    std::string GetName() const override;
    std::size_t GetSize() const override;
    bool Resize(std::size_t new_size) override;
    VirtualDir GetContainingDirectory() const override;
    bool IsWritable() const override;
    bool IsReadable() const override;
    std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
    std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
    bool Rename(std::string_view new_name) override;

private:
    ConcatenationMap concatenation_map;
    std::string name;
};

} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <algorithm>
#include <set>
#include <unordered_set>
#include <utility>
#include "core/file_sys/vfs/vfs_layered.h"

namespace FileSys {

LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs_, std::string name_)
    : dirs(std::move(dirs_)), name(std::move(name_)) {}

LayeredVfsDirectory::~LayeredVfsDirectory() = default;

VirtualDir LayeredVfsDirectory::MakeLayeredDirectory(std::vector<VirtualDir> dirs,
                                                     std::string name) {
    if (dirs.empty())
        return nullptr;
    if (dirs.size() == 1)
        return dirs[0];

    return VirtualDir(new LayeredVfsDirectory(std::move(dirs), std::move(name)));
}

VirtualFile LayeredVfsDirectory::GetFileRelative(std::string_view path) const {
    for (const auto& layer : dirs) {
        const auto file = layer->GetFileRelative(path);
        if (file != nullptr)
            return file;
    }

    return nullptr;
}

VirtualDir LayeredVfsDirectory::GetDirectoryRelative(std::string_view path) const {
    std::vector<VirtualDir> out;
    for (const auto& layer : dirs) {
        auto dir = layer->GetDirectoryRelative(path);
        if (dir != nullptr) {
            out.emplace_back(std::move(dir));
        }
    }

    return MakeLayeredDirectory(std::move(out));
}

VirtualFile LayeredVfsDirectory::GetFile(std::string_view file_name) const {
    return GetFileRelative(file_name);
}

VirtualDir LayeredVfsDirectory::GetSubdirectory(std::string_view subdir_name) const {
    return GetDirectoryRelative(subdir_name);
}

std::string LayeredVfsDirectory::GetFullPath() const {
    return dirs[0]->GetFullPath();
}

std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
    std::vector<VirtualFile> out;
    std::unordered_set<std::string> out_names;

    for (const auto& layer : dirs) {
        for (auto& file : layer->GetFiles()) {
            const auto [it, is_new] = out_names.emplace(file->GetName());
            if (is_new) {
                out.emplace_back(std::move(file));
            }
        }
    }

    return out;
}

std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const {
    std::vector<VirtualDir> out;
    std::unordered_set<std::string> out_names;

    for (const auto& layer : dirs) {
        for (const auto& sd : layer->GetSubdirectories()) {
            out_names.emplace(sd->GetName());
        }
    }

    out.reserve(out_names.size());
    for (const auto& subdir : out_names) {
        out.emplace_back(GetSubdirectory(subdir));
    }

    return out;
}

bool LayeredVfsDirectory::IsWritable() const {
    return false;
}

bool LayeredVfsDirectory::IsReadable() const {
    return true;
}

std::string LayeredVfsDirectory::GetName() const {
    return name.empty() ? dirs[0]->GetName() : name;
}

VirtualDir LayeredVfsDirectory::GetParentDirectory() const {
    return dirs[0]->GetParentDirectory();
}

VirtualDir LayeredVfsDirectory::CreateSubdirectory(std::string_view subdir_name) {
    return nullptr;
}

VirtualFile LayeredVfsDirectory::CreateFile(std::string_view file_name) {
    return nullptr;
}

bool LayeredVfsDirectory::DeleteSubdirectory(std::string_view subdir_name) {
    return false;
}

bool LayeredVfsDirectory::DeleteFile(std::string_view file_name) {
    return false;
}

bool LayeredVfsDirectory::Rename(std::string_view new_name) {
    name = new_name;
    return true;
}

} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <memory>
#include "core/file_sys/vfs/vfs.h"

namespace FileSys {

// Class that stacks multiple VfsDirectories on top of each other, attempting to read from the first
// one and falling back to the one after. The highest priority directory (overwrites all others)
// should be element 0 in the dirs vector.
class LayeredVfsDirectory : public VfsDirectory {
    explicit LayeredVfsDirectory(std::vector<VirtualDir> dirs_, std::string name_);

public:
    ~LayeredVfsDirectory() override;

    /// Wrapper function to allow for more efficient handling of dirs.size() == 0, 1 cases.
    static VirtualDir MakeLayeredDirectory(std::vector<VirtualDir> dirs, std::string name = "");

    VirtualFile GetFileRelative(std::string_view path) const override;
    VirtualDir GetDirectoryRelative(std::string_view path) const override;
    VirtualFile GetFile(std::string_view file_name) const override;
    VirtualDir GetSubdirectory(std::string_view subdir_name) const override;
    std::string GetFullPath() const override;

    std::vector<VirtualFile> GetFiles() const override;
    std::vector<VirtualDir> GetSubdirectories() const override;
    bool IsWritable() const override;
    bool IsReadable() const override;
    std::string GetName() const override;
    VirtualDir GetParentDirectory() const override;
    VirtualDir CreateSubdirectory(std::string_view subdir_name) override;
    VirtualFile CreateFile(std::string_view file_name) override;
    bool DeleteSubdirectory(std::string_view subdir_name) override;
    bool DeleteFile(std::string_view file_name) override;
    bool Rename(std::string_view new_name) override;

private:
    std::vector<VirtualDir> dirs;
    std::string name;
};

} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <algorithm>
#include <utility>

#include "core/file_sys/vfs/vfs_offset.h"

namespace FileSys {

OffsetVfsFile::OffsetVfsFile(VirtualFile file_, std::size_t size_, std::size_t offset_,
                             std::string name_, VirtualDir parent_)
    : file(file_), offset(offset_), size(size_), name(std::move(name_)),
      parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {}

OffsetVfsFile::~OffsetVfsFile() = default;

std::string OffsetVfsFile::GetName() const {
    return name.empty() ? file->GetName() : name;
}

std::size_t OffsetVfsFile::GetSize() const {
    return size;
}

bool OffsetVfsFile::Resize(std::size_t new_size) {
    if (offset + new_size < file->GetSize()) {
        size = new_size;
    } else {
        auto res = file->Resize(offset + new_size);
        if (!res)
            return false;
        size = new_size;
    }

    return true;
}

VirtualDir OffsetVfsFile::GetContainingDirectory() const {
    return parent;
}

bool OffsetVfsFile::IsWritable() const {
    return file->IsWritable();
}

bool OffsetVfsFile::IsReadable() const {
    return file->IsReadable();
}

std::size_t OffsetVfsFile::Read(u8* data, std::size_t length, std::size_t r_offset) const {
    return file->Read(data, TrimToFit(length, r_offset), offset + r_offset);
}

std::size_t OffsetVfsFile::Write(const u8* data, std::size_t length, std::size_t r_offset) {
    return file->Write(data, TrimToFit(length, r_offset), offset + r_offset);
}

std::optional<u8> OffsetVfsFile::ReadByte(std::size_t r_offset) const {
    if (r_offset >= size) {
        return std::nullopt;
    }

    return file->ReadByte(offset + r_offset);
}

std::vector<u8> OffsetVfsFile::ReadBytes(std::size_t r_size, std::size_t r_offset) const {
    return file->ReadBytes(TrimToFit(r_size, r_offset), offset + r_offset);
}

std::vector<u8> OffsetVfsFile::ReadAllBytes() const {
    return file->ReadBytes(size, offset);
}

bool OffsetVfsFile::WriteByte(u8 data, std::size_t r_offset) {
    if (r_offset < size)
        return file->WriteByte(data, offset + r_offset);

    return false;
}

std::size_t OffsetVfsFile::WriteBytes(const std::vector<u8>& data, std::size_t r_offset) {
    return file->Write(data.data(), TrimToFit(data.size(), r_offset), offset + r_offset);
}

bool OffsetVfsFile::Rename(std::string_view new_name) {
    return file->Rename(new_name);
}

std::size_t OffsetVfsFile::GetOffset() const {
    return offset;
}

std::size_t OffsetVfsFile::TrimToFit(std::size_t r_size, std::size_t r_offset) const {
    return std::clamp(r_size, std::size_t{0}, size - r_offset);
}

} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <memory>

#include "core/file_sys/vfs/vfs.h"

namespace FileSys {

// An implementation of VfsFile that wraps around another VfsFile at a certain offset.
// Similar to seeking to an offset.
// If the file is writable, operations that would write past the end of the offset file will expand
// the size of this wrapper.
class OffsetVfsFile : public VfsFile {
public:
    OffsetVfsFile(VirtualFile file, std::size_t size, std::size_t offset = 0,
                  std::string new_name = "", VirtualDir new_parent = nullptr);
    ~OffsetVfsFile() override;

    std::string GetName() const override;
    std::size_t GetSize() const override;
    bool Resize(std::size_t new_size) override;
    VirtualDir GetContainingDirectory() const override;
    bool IsWritable() const override;
    bool IsReadable() const override;
    std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
    std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
    std::optional<u8> ReadByte(std::size_t offset) const override;
    std::vector<u8> ReadBytes(std::size_t size, std::size_t offset) const override;
    std::vector<u8> ReadAllBytes() const override;
    bool WriteByte(u8 data, std::size_t offset) override;
    std::size_t WriteBytes(const std::vector<u8>& data, std::size_t offset) override;

    bool Rename(std::string_view new_name) override;

    std::size_t GetOffset() const;

private:
    std::size_t TrimToFit(std::size_t r_size, std::size_t r_offset) const;

    VirtualFile file;
    std::size_t offset;
    std::size_t size;
    std::string name;
    VirtualDir parent;
};

} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#include <algorithm>
#include <cstddef>
#include <iterator>
#include <utility>
#include "common/assert.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/vfs.h"
#include "core/file_sys/vfs/vfs_real.h"

// For FileTimeStampRaw
#include <sys/stat.h>

#ifdef _MSC_VER
#define stat _stat64
#endif

#ifdef ANDROID
#include "common/fs/fs_android.h"
#endif

namespace FileSys {

namespace FS = Common::FS;

namespace {

constexpr size_t MaxOpenFiles = 512;

constexpr FS::FileAccessMode ModeFlagsToFileAccessMode(OpenMode mode) {
    switch (mode) {
    case OpenMode::Read:
        return FS::FileAccessMode::Read;
    case OpenMode::Write:
    case OpenMode::ReadWrite:
    case OpenMode::AllowAppend:
    case OpenMode::All:
        return FS::FileAccessMode::ReadWrite;
    default:
        return {};
    }
}

} // Anonymous namespace

RealVfsFilesystem::RealVfsFilesystem() : VfsFilesystem(nullptr) {}
RealVfsFilesystem::~RealVfsFilesystem() = default;

std::string RealVfsFilesystem::GetName() const {
    return "Real";
}

bool RealVfsFilesystem::IsReadable() const {
    return true;
}

bool RealVfsFilesystem::IsWritable() const {
    return true;
}

VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const {
    const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
    if (!FS::Exists(path)) {
        return VfsEntryType::None;
    }
    if (FS::IsDir(path)) {
        return VfsEntryType::Directory;
    }

    return VfsEntryType::File;
}

VirtualFile RealVfsFilesystem::OpenFileFromEntry(std::string_view path_, std::optional<u64> size,
                                                 OpenMode perms) {
    const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
    std::scoped_lock lk{list_lock};

    if (auto it = cache.find(path); it != cache.end()) {
        if (auto file = it->second.lock(); file) {
            return file;
        }
    }

    if (!size && !FS::IsFile(path)) {
        return nullptr;
    }

    auto reference = std::make_unique<FileReference>();
    this->InsertReferenceIntoListLocked(*reference);

    auto file = std::shared_ptr<RealVfsFile>(
        new RealVfsFile(*this, std::move(reference), path, perms, size));
    cache[path] = file;

    return file;
}

VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, OpenMode perms) {
    return OpenFileFromEntry(path_, {}, perms);
}

VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, OpenMode perms) {
    const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
    {
        std::scoped_lock lk{list_lock};
        cache.erase(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_) {
    // Unused
    return nullptr;
}

VirtualFile RealVfsFilesystem::MoveFile(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);
    {
        std::scoped_lock lk{list_lock};
        cache.erase(old_path);
        cache.erase(new_path);
    }
    if (!FS::RenameFile(old_path, new_path)) {
        return nullptr;
    }
    return OpenFile(new_path, OpenMode::ReadWrite);
}

bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
    const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
    {
        std::scoped_lock lk{list_lock};
        cache.erase(path);
    }
    return FS::RemoveFile(path);
}

VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, OpenMode perms) {
    const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
    return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
}

VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, OpenMode perms) {
    const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
    if (!FS::CreateDirs(path)) {
        return nullptr;
    }
    return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
}

VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_,
                                            std::string_view new_path_) {
    // Unused
    return nullptr;
}

VirtualDir RealVfsFilesystem::MoveDirectory(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::RenameDir(old_path, new_path)) {
        return nullptr;
    }
    return OpenDirectory(new_path, OpenMode::ReadWrite);
}

bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {
    const auto path = FS::SanitizePath(path_, FS::DirectorySeparator::PlatformDefault);
    return FS::RemoveDirRecursively(path);
}

std::unique_lock<std::mutex> RealVfsFilesystem::RefreshReference(const std::string& path,
                                                                 OpenMode perms,
                                                                 FileReference& reference) {
    std::unique_lock lk{list_lock};

    // Temporarily remove from list.
    this->RemoveReferenceFromListLocked(reference);

    // Restore file if needed.
    if (!reference.file) {
        this->EvictSingleReferenceLocked();

        reference.file =
            FS::FileOpen(path, ModeFlagsToFileAccessMode(perms), FS::FileType::BinaryFile);
        if (reference.file) {
            num_open_files++;
        }
    }

    // Reinsert into list.
    this->InsertReferenceIntoListLocked(reference);

    return lk;
}

void RealVfsFilesystem::DropReference(std::unique_ptr<FileReference>&& reference) {
    std::scoped_lock lk{list_lock};

    // Remove from list.
    this->RemoveReferenceFromListLocked(*reference);

    // Close the file.
    if (reference->file) {
        reference->file.reset();
        num_open_files--;
    }
}

void RealVfsFilesystem::EvictSingleReferenceLocked() {
    if (num_open_files < MaxOpenFiles || open_references.empty()) {
        return;
    }

    // Get and remove from list.
    auto& reference = open_references.back();
    this->RemoveReferenceFromListLocked(reference);

    // Close the file.
    if (reference.file) {
        reference.file.reset();
        num_open_files--;
    }

    // Reinsert into closed list.
    this->InsertReferenceIntoListLocked(reference);
}

void RealVfsFilesystem::InsertReferenceIntoListLocked(FileReference& reference) {
    if (reference.file) {
        open_references.push_front(reference);
    } else {
        closed_references.push_front(reference);
    }
}

void RealVfsFilesystem::RemoveReferenceFromListLocked(FileReference& reference) {
    if (reference.file) {
        open_references.erase(open_references.iterator_to(reference));
    } else {
        closed_references.erase(closed_references.iterator_to(reference));
    }
}

RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::unique_ptr<FileReference> reference_,
                         const std::string& path_, OpenMode perms_, std::optional<u64> size_)
    : base(base_), reference(std::move(reference_)), path(path_),
      parent_path(FS::GetParentPath(path_)), path_components(FS::SplitPathComponentsCopy(path_)),
      size(size_), perms(perms_) {}

RealVfsFile::~RealVfsFile() {
    base.DropReference(std::move(reference));
}

std::string RealVfsFile::GetName() const {
#ifdef ANDROID
    if (path[0] != '/') {
        return FS::Android::GetFilename(path);
    }
#endif
    return path_components.empty() ? "" : std::string(path_components.back());
}

std::size_t RealVfsFile::GetSize() const {
    if (size) {
        return *size;
    }
    auto lk = base.RefreshReference(path, perms, *reference);
    return reference->file ? reference->file->GetSize() : 0;
}

bool RealVfsFile::Resize(std::size_t new_size) {
    size.reset();
    auto lk = base.RefreshReference(path, perms, *reference);
    return reference->file ? reference->file->SetSize(new_size) : false;
}

VirtualDir RealVfsFile::GetContainingDirectory() const {
    return base.OpenDirectory(parent_path, perms);
}

bool RealVfsFile::IsWritable() const {
    return True(perms & OpenMode::Write);
}

bool RealVfsFile::IsReadable() const {
    return True(perms & OpenMode::Read);
}

std::size_t RealVfsFile::Read(u8* data, std::size_t length, std::size_t offset) const {
    auto lk = base.RefreshReference(path, perms, *reference);
    if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) {
        return 0;
    }
    return reference->file->ReadSpan(std::span{data, length});
}

std::size_t RealVfsFile::Write(const u8* data, std::size_t length, std::size_t offset) {
    size.reset();
    auto lk = base.RefreshReference(path, perms, *reference);
    if (!reference->file || !reference->file->Seek(static_cast<s64>(offset))) {
        return 0;
    }
    return reference->file->WriteSpan(std::span{data, length});
}

bool RealVfsFile::Rename(std::string_view name) {
    return base.MoveFile(path, parent_path + '/' + std::string(name)) != nullptr;
}

// TODO(DarkLordZach): MSVC would not let me combine the following two functions using 'if
// constexpr' because there is a compile error in the branch not used.

template <>
std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>() const {
    if (perms == OpenMode::AllowAppend) {
        return {};
    }

    std::vector<VirtualFile> out;

    const FS::DirEntryCallable callback = [this,
                                           &out](const std::filesystem::directory_entry& entry) {
        const auto full_path_string = FS::PathToUTF8String(entry.path());

        out.emplace_back(base.OpenFileFromEntry(full_path_string, entry.file_size(), perms));

        return true;
    };

    FS::IterateDirEntries(path, callback, FS::DirEntryFilter::File);

    return out;
}

template <>
std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDirectory>() const {
    if (perms == OpenMode::AllowAppend) {
        return {};
    }

    std::vector<VirtualDir> out;

    const FS::DirEntryCallable callback = [this,
                                           &out](const std::filesystem::directory_entry& entry) {
        const auto full_path_string = FS::PathToUTF8String(entry.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_,
                                   OpenMode perms_)
    : base(base_), path(FS::RemoveTrailingSlash(path_)), parent_path(FS::GetParentPath(path)),
      path_components(FS::SplitPathComponentsCopy(path)), perms(perms_) {
    if (!FS::Exists(path) && True(perms & OpenMode::Write)) {
        void(FS::CreateDirs(path));
    }
}

RealVfsDirectory::~RealVfsDirectory() = default;

VirtualFile RealVfsDirectory::GetFileRelative(std::string_view relative_path) const {
    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 + '/' + std::string(relative_path));
    if (!FS::Exists(full_path) || !FS::IsDir(full_path)) {
        return nullptr;
    }
    return base.OpenDirectory(full_path, perms);
}

VirtualFile RealVfsDirectory::GetFile(std::string_view name) const {
    return GetFileRelative(name);
}

VirtualDir RealVfsDirectory::GetSubdirectory(std::string_view name) const {
    return GetDirectoryRelative(name);
}

VirtualFile RealVfsDirectory::CreateFileRelative(std::string_view 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 + '/' + 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 + '/' + std::string(name));
    return base.DeleteDirectory(full_path);
}

std::vector<VirtualFile> RealVfsDirectory::GetFiles() const {
    return IterateEntries<RealVfsFile, VfsFile>();
}

FileTimeStampRaw RealVfsDirectory::GetFileTimeStamp(std::string_view path_) const {
    const auto full_path = FS::SanitizePath(path + '/' + std::string(path_));
    const auto fs_path = std::filesystem::path{FS::ToU8String(full_path)};
    struct stat file_status;

#ifdef _WIN32
    const auto stat_result = _wstat64(fs_path.c_str(), &file_status);
#else
    const auto stat_result = stat(fs_path.c_str(), &file_status);
#endif

    if (stat_result != 0) {
        return {};
    }

    return {
        .created{static_cast<u64>(file_status.st_ctime)},
        .accessed{static_cast<u64>(file_status.st_atime)},
        .modified{static_cast<u64>(file_status.st_mtime)},
    };
}

std::vector<VirtualDir> RealVfsDirectory::GetSubdirectories() const {
    return IterateEntries<RealVfsDirectory, VfsDirectory>();
}

bool RealVfsDirectory::IsWritable() const {
    return True(perms & OpenMode::Write);
}

bool RealVfsDirectory::IsReadable() const {
    return True(perms & OpenMode::Read);
}

std::string RealVfsDirectory::GetName() const {
    return path_components.empty() ? "" : std::string(path_components.back());
}

VirtualDir RealVfsDirectory::GetParentDirectory() const {
    if (path_components.size() <= 1) {
        return nullptr;
    }

    return base.OpenDirectory(parent_path, perms);
}

VirtualDir RealVfsDirectory::CreateSubdirectory(std::string_view 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 + '/').append(name);
    return base.CreateFile(file_path, perms);
}

bool RealVfsDirectory::DeleteSubdirectory(std::string_view 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 + '/').append(name);
    return base.DeleteFile(file_path);
}

bool RealVfsDirectory::Rename(std::string_view name) {
    const std::string new_name = (parent_path + '/').append(name);
    return base.MoveFile(path, new_name) != nullptr;
}

std::string RealVfsDirectory::GetFullPath() const {
    auto out = path;
    std::replace(out.begin(), out.end(), '\\', '/');
    return out;
}

std::map<std::string, VfsEntryType, std::less<>> RealVfsDirectory::GetEntries() const {
    if (perms == OpenMode::AllowAppend) {
        return {};
    }

    std::map<std::string, VfsEntryType, std::less<>> out;

    const FS::DirEntryCallable callback = [&out](const std::filesystem::directory_entry& entry) {
        const auto filename = FS::PathToUTF8String(entry.path().filename());
        out.insert_or_assign(filename,
                             entry.is_directory() ? VfsEntryType::Directory : VfsEntryType::File);
        return true;
    };

    FS::IterateDirEntries(path, callback);

    return out;
}

} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <map>
#include <mutex>
#include <optional>
#include <string_view>
#include "common/intrusive_list.h"
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/vfs/vfs.h"

namespace Common::FS {
class IOFile;
}

namespace FileSys {

struct FileReference : public Common::IntrusiveListBaseNode<FileReference> {
    std::shared_ptr<Common::FS::IOFile> file{};
};

class RealVfsFile;
class RealVfsDirectory;

class RealVfsFilesystem : public VfsFilesystem {
public:
    RealVfsFilesystem();
    ~RealVfsFilesystem() override;

    std::string GetName() const override;
    bool IsReadable() const override;
    bool IsWritable() const override;
    VfsEntryType GetEntryType(std::string_view path) const override;
    VirtualFile OpenFile(std::string_view path, OpenMode perms = OpenMode::Read) override;
    VirtualFile CreateFile(std::string_view path, OpenMode perms = OpenMode::ReadWrite) override;
    VirtualFile CopyFile(std::string_view old_path, std::string_view new_path) override;
    VirtualFile MoveFile(std::string_view old_path, std::string_view new_path) override;
    bool DeleteFile(std::string_view path) override;
    VirtualDir OpenDirectory(std::string_view path, OpenMode perms = OpenMode::Read) override;
    VirtualDir CreateDirectory(std::string_view path,
                               OpenMode perms = OpenMode::ReadWrite) override;
    VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path) override;
    VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path) override;
    bool DeleteDirectory(std::string_view path) override;

private:
    using ReferenceListType = Common::IntrusiveListBaseTraits<FileReference>::ListType;
    std::map<std::string, std::weak_ptr<VfsFile>, std::less<>> cache;
    ReferenceListType open_references;
    ReferenceListType closed_references;
    std::mutex list_lock;
    size_t num_open_files{};

private:
    friend class RealVfsFile;
    std::unique_lock<std::mutex> RefreshReference(const std::string& path, OpenMode perms,
                                                  FileReference& reference);
    void DropReference(std::unique_ptr<FileReference>&& reference);

private:
    friend class RealVfsDirectory;
    VirtualFile OpenFileFromEntry(std::string_view path, std::optional<u64> size,
                                  OpenMode perms = OpenMode::Read);

private:
    void EvictSingleReferenceLocked();
    void InsertReferenceIntoListLocked(FileReference& reference);
    void RemoveReferenceFromListLocked(FileReference& reference);
};

// An implementation of VfsFile that represents a file on the user's computer.
class RealVfsFile : public VfsFile {
    friend class RealVfsDirectory;
    friend class RealVfsFilesystem;

public:
    ~RealVfsFile() override;

    std::string GetName() const override;
    std::size_t GetSize() const override;
    bool Resize(std::size_t new_size) override;
    VirtualDir GetContainingDirectory() const override;
    bool IsWritable() const override;
    bool IsReadable() const override;
    std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
    std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override;
    bool Rename(std::string_view name) override;

private:
    RealVfsFile(RealVfsFilesystem& base, std::unique_ptr<FileReference> reference,
                const std::string& path, OpenMode perms = OpenMode::Read,
                std::optional<u64> size = {});

    RealVfsFilesystem& base;
    std::unique_ptr<FileReference> reference;
    std::string path;
    std::string parent_path;
    std::vector<std::string> path_components;
    std::optional<u64> size;
    OpenMode perms;
};

// An implementation of VfsDirectory that represents a directory on the user's computer.
class RealVfsDirectory : public VfsDirectory {
    friend class RealVfsFilesystem;

public:
    ~RealVfsDirectory() override;

    VirtualFile GetFileRelative(std::string_view relative_path) const override;
    VirtualDir GetDirectoryRelative(std::string_view relative_path) const override;
    VirtualFile GetFile(std::string_view name) const override;
    VirtualDir GetSubdirectory(std::string_view name) const override;
    VirtualFile CreateFileRelative(std::string_view relative_path) override;
    VirtualDir CreateDirectoryRelative(std::string_view relative_path) override;
    bool DeleteSubdirectoryRecursive(std::string_view name) override;
    std::vector<VirtualFile> GetFiles() const override;
    FileTimeStampRaw GetFileTimeStamp(std::string_view path) const override;
    std::vector<VirtualDir> GetSubdirectories() const override;
    bool IsWritable() const override;
    bool IsReadable() const override;
    std::string GetName() const override;
    VirtualDir GetParentDirectory() const override;
    VirtualDir CreateSubdirectory(std::string_view name) override;
    VirtualFile CreateFile(std::string_view name) override;
    bool DeleteSubdirectory(std::string_view name) override;
    bool DeleteFile(std::string_view name) override;
    bool Rename(std::string_view name) override;
    std::string GetFullPath() const override;
    std::map<std::string, VfsEntryType, std::less<>> GetEntries() const override;

private:
    RealVfsDirectory(RealVfsFilesystem& base, const std::string& path,
                     OpenMode perms = OpenMode::Read);

    template <typename T, typename R>
    std::vector<std::shared_ptr<R>> IterateEntries() const;

    RealVfsFilesystem& base;
    std::string path;
    std::string parent_path;
    std::vector<std::string> path_components;
    OpenMode perms;
};

} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <algorithm>
#include <memory>
#include <string_view>

#include "core/file_sys/vfs/vfs.h"

namespace FileSys {

class StaticVfsFile : public VfsFile {
public:
    explicit StaticVfsFile(u8 value_, std::size_t size_ = 0, std::string name_ = "",
                           VirtualDir parent_ = nullptr)
        : value{value_}, size{size_}, name{std::move(name_)}, parent{std::move(parent_)} {}

    std::string GetName() const override {
        return name;
    }

    std::size_t GetSize() const override {
        return size;
    }

    bool Resize(std::size_t new_size) override {
        size = new_size;
        return true;
    }

    VirtualDir GetContainingDirectory() const override {
        return parent;
    }

    bool IsWritable() const override {
        return false;
    }

    bool IsReadable() const override {
        return true;
    }

    std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override {
        const auto read = std::min(length, size - offset);
        std::fill(data, data + read, value);
        return read;
    }

    std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override {
        return 0;
    }

    std::optional<u8> ReadByte(std::size_t offset) const override {
        if (offset >= size) {
            return std::nullopt;
        }

        return value;
    }

    std::vector<u8> ReadBytes(std::size_t length, std::size_t offset) const override {
        const auto read = std::min(length, size - offset);
        return std::vector<u8>(read, value);
    }

    bool Rename(std::string_view new_name) override {
        name = new_name;
        return true;
    }

private:
    u8 value;
    std::size_t size;
    std::string name;
    VirtualDir parent;
};

} // namespace FileSys


code:
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

#pragma once

#include <memory>

#include "common/common_types.h"

namespace FileSys {

class VfsDirectory;
class VfsFile;
class VfsFilesystem;

// Declarations for Vfs* pointer types

using VirtualDir = std::shared_ptr<VfsDirectory>;
using VirtualFile = std::shared_ptr<VfsFile>;
using VirtualFilesystem = std::shared_ptr<VfsFilesystem>;

struct FileTimeStampRaw {
    u64 created{};
    u64 accessed{};
    u64 modified{};
    u64 padding{};
};

} // namespace FileSys