Merge pull request #897 from DarkLordZach/vfs-accuracy-2
vfs: Add VfsFilesystem and fix RealVfs* implementations
This commit is contained in:
commit
96ef22d3d0
|
@ -884,11 +884,21 @@ std::string_view RemoveTrailingSlash(std::string_view path) {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string SanitizePath(std::string_view path_) {
|
std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) {
|
||||||
std::string path(path_);
|
std::string path(path_);
|
||||||
std::replace(path.begin(), path.end(), '\\', '/');
|
char type1 = directory_separator == DirectorySeparator::BackwardSlash ? '/' : '\\';
|
||||||
|
char type2 = directory_separator == DirectorySeparator::BackwardSlash ? '\\' : '/';
|
||||||
|
|
||||||
|
if (directory_separator == DirectorySeparator::PlatformDefault) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
type1 = '/';
|
||||||
|
type2 = '\\';
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
std::replace(path.begin(), path.end(), type1, type2);
|
||||||
path.erase(std::unique(path.begin(), path.end(),
|
path.erase(std::unique(path.begin(), path.end(),
|
||||||
[](char c1, char c2) { return c1 == '/' && c2 == '/'; }),
|
[type2](char c1, char c2) { return c1 == type2 && c2 == type2; }),
|
||||||
path.end());
|
path.end());
|
||||||
return std::string(RemoveTrailingSlash(path));
|
return std::string(RemoveTrailingSlash(path));
|
||||||
}
|
}
|
||||||
|
|
|
@ -182,8 +182,12 @@ std::vector<T> SliceVector(const std::vector<T>& vector, size_t first, size_t la
|
||||||
return std::vector<T>(vector.begin() + first, vector.begin() + first + last);
|
return std::vector<T>(vector.begin() + first, vector.begin() + first + last);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'.
|
enum class DirectorySeparator { ForwardSlash, BackwardSlash, PlatformDefault };
|
||||||
std::string SanitizePath(std::string_view path);
|
|
||||||
|
// Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\'
|
||||||
|
// depending if directory_separator is BackwardSlash or PlatformDefault and running on windows
|
||||||
|
std::string SanitizePath(std::string_view path,
|
||||||
|
DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash);
|
||||||
|
|
||||||
// simple wrapper for cstdlib file functions to
|
// simple wrapper for cstdlib file functions to
|
||||||
// hopefully will make error checking easier
|
// hopefully will make error checking easier
|
||||||
|
|
|
@ -89,7 +89,7 @@ System::ResultStatus System::SingleStep() {
|
||||||
}
|
}
|
||||||
|
|
||||||
System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& filepath) {
|
System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& filepath) {
|
||||||
app_loader = Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(filepath));
|
app_loader = Loader::GetLoader(virtual_filesystem->OpenFile(filepath, FileSys::Mode::Read));
|
||||||
|
|
||||||
if (!app_loader) {
|
if (!app_loader) {
|
||||||
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
|
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
|
||||||
|
@ -174,6 +174,10 @@ System::ResultStatus System::Init(EmuWindow& emu_window) {
|
||||||
|
|
||||||
CoreTiming::Init();
|
CoreTiming::Init();
|
||||||
|
|
||||||
|
// Create a default fs if one doesn't already exist.
|
||||||
|
if (virtual_filesystem == nullptr)
|
||||||
|
virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>();
|
||||||
|
|
||||||
current_process = Kernel::Process::Create("main");
|
current_process = Kernel::Process::Create("main");
|
||||||
|
|
||||||
cpu_barrier = std::make_shared<CpuBarrier>();
|
cpu_barrier = std::make_shared<CpuBarrier>();
|
||||||
|
@ -186,7 +190,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window) {
|
||||||
service_manager = std::make_shared<Service::SM::ServiceManager>();
|
service_manager = std::make_shared<Service::SM::ServiceManager>();
|
||||||
|
|
||||||
Kernel::Init();
|
Kernel::Init();
|
||||||
Service::Init(service_manager);
|
Service::Init(service_manager, virtual_filesystem);
|
||||||
GDBStub::Init();
|
GDBStub::Init();
|
||||||
|
|
||||||
renderer = VideoCore::CreateRenderer(emu_window);
|
renderer = VideoCore::CreateRenderer(emu_window);
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/perf_stats.h"
|
#include "core/perf_stats.h"
|
||||||
#include "core/telemetry_session.h"
|
#include "core/telemetry_session.h"
|
||||||
|
#include "file_sys/vfs_real.h"
|
||||||
|
#include "hle/service/filesystem/filesystem.h"
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
#include "video_core/debug_utils/debug_utils.h"
|
||||||
#include "video_core/gpu.h"
|
#include "video_core/gpu.h"
|
||||||
|
|
||||||
|
@ -211,6 +213,14 @@ public:
|
||||||
return debug_context;
|
return debug_context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetFilesystem(FileSys::VirtualFilesystem vfs) {
|
||||||
|
virtual_filesystem = std::move(vfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSys::VirtualFilesystem GetFilesystem() const {
|
||||||
|
return virtual_filesystem;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
System();
|
System();
|
||||||
|
|
||||||
|
@ -225,6 +235,8 @@ private:
|
||||||
*/
|
*/
|
||||||
ResultStatus Init(EmuWindow& emu_window);
|
ResultStatus Init(EmuWindow& emu_window);
|
||||||
|
|
||||||
|
/// RealVfsFilesystem instance
|
||||||
|
FileSys::VirtualFilesystem virtual_filesystem;
|
||||||
/// AppLoader used to load the current executing application
|
/// AppLoader used to load the current executing application
|
||||||
std::unique_ptr<Loader::AppLoader> app_loader;
|
std::unique_ptr<Loader::AppLoader> app_loader;
|
||||||
std::unique_ptr<VideoCore::RendererBase> renderer;
|
std::unique_ptr<VideoCore::RendererBase> renderer;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/swap.h"
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
|
@ -4,12 +4,160 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
|
#include <string>
|
||||||
|
#include "common/common_paths.h"
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "common/logging/backend.h"
|
#include "common/logging/backend.h"
|
||||||
#include "core/file_sys/vfs.h"
|
#include "core/file_sys/vfs.h"
|
||||||
|
|
||||||
namespace FileSys {
|
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 = FileUtil::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_, Mode perms) {
|
||||||
|
const auto path = FileUtil::SanitizePath(path_);
|
||||||
|
return root->GetFileRelative(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualFile VfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
|
||||||
|
const auto path = FileUtil::SanitizePath(path_);
|
||||||
|
return root->CreateFileRelative(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) {
|
||||||
|
const auto old_path = FileUtil::SanitizePath(old_path_);
|
||||||
|
const auto new_path = FileUtil::SanitizePath(new_path_);
|
||||||
|
|
||||||
|
// VfsDirectory impls are only required to implement copy across the current directory.
|
||||||
|
if (FileUtil::GetParentPath(old_path) == FileUtil::GetParentPath(new_path)) {
|
||||||
|
if (!root->Copy(FileUtil::GetFilename(old_path), FileUtil::GetFilename(new_path)))
|
||||||
|
return nullptr;
|
||||||
|
return OpenFile(new_path, Mode::ReadWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do it using RawCopy. Non-default impls are encouraged to optimize this.
|
||||||
|
const auto old_file = OpenFile(old_path, Mode::Read);
|
||||||
|
if (old_file == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
auto new_file = OpenFile(new_path, Mode::Read);
|
||||||
|
if (new_file != nullptr)
|
||||||
|
return nullptr;
|
||||||
|
new_file = CreateFile(new_path, Mode::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 old_path = FileUtil::SanitizePath(old_path_);
|
||||||
|
const auto new_path = FileUtil::SanitizePath(new_path_);
|
||||||
|
|
||||||
|
// Again, non-default impls are highly encouraged to provide a more optimized version of this.
|
||||||
|
auto out = CopyFile(old_path_, new_path_);
|
||||||
|
if (out == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
if (DeleteFile(old_path))
|
||||||
|
return out;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VfsFilesystem::DeleteFile(std::string_view path_) {
|
||||||
|
const auto path = FileUtil::SanitizePath(path_);
|
||||||
|
auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write);
|
||||||
|
if (parent == nullptr)
|
||||||
|
return false;
|
||||||
|
return parent->DeleteFile(FileUtil::GetFilename(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) {
|
||||||
|
const auto path = FileUtil::SanitizePath(path_);
|
||||||
|
return root->GetDirectoryRelative(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) {
|
||||||
|
const auto path = FileUtil::SanitizePath(path_);
|
||||||
|
return root->CreateDirectoryRelative(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_view new_path_) {
|
||||||
|
const auto old_path = FileUtil::SanitizePath(old_path_);
|
||||||
|
const auto new_path = FileUtil::SanitizePath(new_path_);
|
||||||
|
|
||||||
|
// Non-default impls are highly encouraged to provide a more optimized version of this.
|
||||||
|
auto old_dir = OpenDirectory(old_path, Mode::Read);
|
||||||
|
if (old_dir == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
auto new_dir = OpenDirectory(new_path, Mode::Read);
|
||||||
|
if (new_dir != nullptr)
|
||||||
|
return nullptr;
|
||||||
|
new_dir = CreateDirectory(new_path, Mode::Write);
|
||||||
|
if (new_dir == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
for (const auto& file : old_dir->GetFiles()) {
|
||||||
|
const auto x =
|
||||||
|
CopyFile(old_path + DIR_SEP + file->GetName(), new_path + DIR_SEP + file->GetName());
|
||||||
|
if (x == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& dir : old_dir->GetSubdirectories()) {
|
||||||
|
const auto x =
|
||||||
|
CopyDirectory(old_path + DIR_SEP + dir->GetName(), new_path + DIR_SEP + dir->GetName());
|
||||||
|
if (x == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path_, std::string_view new_path_) {
|
||||||
|
const auto old_path = FileUtil::SanitizePath(old_path_);
|
||||||
|
const auto new_path = FileUtil::SanitizePath(new_path_);
|
||||||
|
|
||||||
|
// Non-default impls are highly encouraged to provide a more optimized version of this.
|
||||||
|
auto out = CopyDirectory(old_path_, new_path_);
|
||||||
|
if (out == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
if (DeleteDirectory(old_path))
|
||||||
|
return out;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VfsFilesystem::DeleteDirectory(std::string_view path_) {
|
||||||
|
const auto path = FileUtil::SanitizePath(path_);
|
||||||
|
auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write);
|
||||||
|
if (parent == nullptr)
|
||||||
|
return false;
|
||||||
|
return parent->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path));
|
||||||
|
}
|
||||||
|
|
||||||
VfsFile::~VfsFile() = default;
|
VfsFile::~VfsFile() = default;
|
||||||
|
|
||||||
std::string VfsFile::GetExtension() const {
|
std::string VfsFile::GetExtension() const {
|
||||||
|
|
|
@ -11,14 +11,74 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "boost/optional.hpp"
|
#include "boost/optional.hpp"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "core/file_sys/mode.h"
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
||||||
|
struct VfsFilesystem;
|
||||||
struct VfsFile;
|
struct VfsFile;
|
||||||
struct VfsDirectory;
|
struct VfsDirectory;
|
||||||
|
|
||||||
// Convenience typedefs to use VfsDirectory and VfsFile
|
// Convenience typedefs to use Vfs* interfaces
|
||||||
using VirtualDir = std::shared_ptr<FileSys::VfsDirectory>;
|
using VirtualFilesystem = std::shared_ptr<VfsFilesystem>;
|
||||||
using VirtualFile = std::shared_ptr<FileSys::VfsFile>;
|
using VirtualDir = std::shared_ptr<VfsDirectory>;
|
||||||
|
using VirtualFile = std::shared_ptr<VfsFile>;
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
struct VfsFilesystem : NonCopyable {
|
||||||
|
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-existant, 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, Mode perms);
|
||||||
|
// Creates a new, empty file at path
|
||||||
|
virtual VirtualFile CreateFile(std::string_view path, Mode 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, returing 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, Mode perms);
|
||||||
|
// Creates a new, empty directory at path
|
||||||
|
virtual VirtualDir CreateDirectory(std::string_view path, Mode 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, returing 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.
|
// A class representing a file in an abstract filesystem.
|
||||||
struct VfsFile : NonCopyable {
|
struct VfsFile : NonCopyable {
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include "common/assert.h"
|
||||||
#include "common/common_paths.h"
|
#include "common/common_paths.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/file_sys/vfs_real.h"
|
#include "core/file_sys/vfs_real.h"
|
||||||
|
@ -29,6 +29,8 @@ static std::string ModeFlagsToString(Mode mode) {
|
||||||
mode_str = "a";
|
mode_str = "a";
|
||||||
else if (mode & Mode::Write)
|
else if (mode & Mode::Write)
|
||||||
mode_str = "w";
|
mode_str = "w";
|
||||||
|
else
|
||||||
|
UNREACHABLE_MSG("Invalid file open mode: {:02X}", static_cast<u8>(mode));
|
||||||
}
|
}
|
||||||
|
|
||||||
mode_str += "b";
|
mode_str += "b";
|
||||||
|
@ -36,8 +38,174 @@ static std::string ModeFlagsToString(Mode mode) {
|
||||||
return mode_str;
|
return mode_str;
|
||||||
}
|
}
|
||||||
|
|
||||||
RealVfsFile::RealVfsFile(const std::string& path_, Mode perms_)
|
RealVfsFilesystem::RealVfsFilesystem() : VfsFilesystem(nullptr) {}
|
||||||
: backing(path_, ModeFlagsToString(perms_).c_str()), path(path_),
|
|
||||||
|
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 = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
if (!FileUtil::Exists(path))
|
||||||
|
return VfsEntryType::None;
|
||||||
|
if (FileUtil::IsDirectory(path))
|
||||||
|
return VfsEntryType::Directory;
|
||||||
|
|
||||||
|
return VfsEntryType::File;
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) {
|
||||||
|
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
if (cache.find(path) != cache.end()) {
|
||||||
|
auto weak = cache[path];
|
||||||
|
if (!weak.expired()) {
|
||||||
|
return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, weak.lock(), path, perms));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FileUtil::Exists(path) && (perms & Mode::WriteAppend) != 0)
|
||||||
|
FileUtil::CreateEmptyFile(path);
|
||||||
|
|
||||||
|
auto backing = std::make_shared<FileUtil::IOFile>(path, ModeFlagsToString(perms).c_str());
|
||||||
|
cache[path] = backing;
|
||||||
|
|
||||||
|
// Cannot use make_shared as RealVfsFile constructor is private
|
||||||
|
return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, backing, path, perms));
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) {
|
||||||
|
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
if (!FileUtil::Exists(path) && !FileUtil::CreateEmptyFile(path))
|
||||||
|
return nullptr;
|
||||||
|
return OpenFile(path, perms);
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) {
|
||||||
|
const auto old_path =
|
||||||
|
FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
const auto new_path =
|
||||||
|
FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
|
||||||
|
if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
|
||||||
|
FileUtil::IsDirectory(old_path) || !FileUtil::Copy(old_path, new_path))
|
||||||
|
return nullptr;
|
||||||
|
return OpenFile(new_path, Mode::ReadWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) {
|
||||||
|
const auto old_path =
|
||||||
|
FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
const auto new_path =
|
||||||
|
FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
|
||||||
|
if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
|
||||||
|
FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
if (cache.find(old_path) != cache.end()) {
|
||||||
|
auto cached = cache[old_path];
|
||||||
|
if (!cached.expired()) {
|
||||||
|
auto file = cached.lock();
|
||||||
|
file->Open(new_path, "r+b");
|
||||||
|
cache.erase(old_path);
|
||||||
|
cache[new_path] = file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OpenFile(new_path, Mode::ReadWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RealVfsFilesystem::DeleteFile(std::string_view path_) {
|
||||||
|
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
if (cache.find(path) != cache.end()) {
|
||||||
|
if (!cache[path].expired())
|
||||||
|
cache[path].lock()->Close();
|
||||||
|
cache.erase(path);
|
||||||
|
}
|
||||||
|
return FileUtil::Delete(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) {
|
||||||
|
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
// Cannot use make_shared as RealVfsDirectory constructor is private
|
||||||
|
return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) {
|
||||||
|
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
if (!FileUtil::Exists(path) && !FileUtil::CreateDir(path))
|
||||||
|
return nullptr;
|
||||||
|
// Cannot use make_shared as RealVfsDirectory constructor is private
|
||||||
|
return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms));
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_,
|
||||||
|
std::string_view new_path_) {
|
||||||
|
const auto old_path =
|
||||||
|
FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
const auto new_path =
|
||||||
|
FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
|
||||||
|
!FileUtil::IsDirectory(old_path))
|
||||||
|
return nullptr;
|
||||||
|
FileUtil::CopyDir(old_path, new_path);
|
||||||
|
return OpenDirectory(new_path, Mode::ReadWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_,
|
||||||
|
std::string_view new_path_) {
|
||||||
|
const auto old_path =
|
||||||
|
FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
const auto new_path =
|
||||||
|
FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) ||
|
||||||
|
FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path))
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
for (auto& kv : cache) {
|
||||||
|
// Path in cache starts with old_path
|
||||||
|
if (kv.first.rfind(old_path, 0) == 0) {
|
||||||
|
const auto file_old_path =
|
||||||
|
FileUtil::SanitizePath(kv.first, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
const auto file_new_path =
|
||||||
|
FileUtil::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()),
|
||||||
|
FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
auto cached = cache[file_old_path];
|
||||||
|
if (!cached.expired()) {
|
||||||
|
auto file = cached.lock();
|
||||||
|
file->Open(file_new_path, "r+b");
|
||||||
|
cache.erase(file_old_path);
|
||||||
|
cache[file_new_path] = file;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OpenDirectory(new_path, Mode::ReadWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) {
|
||||||
|
const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault);
|
||||||
|
for (auto& kv : cache) {
|
||||||
|
// Path in cache starts with old_path
|
||||||
|
if (kv.first.rfind(path, 0) == 0) {
|
||||||
|
if (!cache[kv.first].expired())
|
||||||
|
cache[kv.first].lock()->Close();
|
||||||
|
cache.erase(kv.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FileUtil::DeleteDirRecursively(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::shared_ptr<FileUtil::IOFile> backing_,
|
||||||
|
const std::string& path_, Mode perms_)
|
||||||
|
: base(base_), backing(std::move(backing_)), path(path_),
|
||||||
parent_path(FileUtil::GetParentPath(path_)),
|
parent_path(FileUtil::GetParentPath(path_)),
|
||||||
path_components(FileUtil::SplitPathComponents(path_)),
|
path_components(FileUtil::SplitPathComponents(path_)),
|
||||||
parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
|
parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
|
||||||
|
@ -48,15 +216,15 @@ std::string RealVfsFile::GetName() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RealVfsFile::GetSize() const {
|
size_t RealVfsFile::GetSize() const {
|
||||||
return backing.GetSize();
|
return backing->GetSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RealVfsFile::Resize(size_t new_size) {
|
bool RealVfsFile::Resize(size_t new_size) {
|
||||||
return backing.Resize(new_size);
|
return backing->Resize(new_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const {
|
std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const {
|
||||||
return std::make_shared<RealVfsDirectory>(parent_path, perms);
|
return base.OpenDirectory(parent_path, perms);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RealVfsFile::IsWritable() const {
|
bool RealVfsFile::IsWritable() const {
|
||||||
|
@ -68,62 +236,118 @@ bool RealVfsFile::IsReadable() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const {
|
size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const {
|
||||||
if (!backing.Seek(offset, SEEK_SET))
|
if (!backing->Seek(offset, SEEK_SET))
|
||||||
return 0;
|
return 0;
|
||||||
return backing.ReadBytes(data, length);
|
return backing->ReadBytes(data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) {
|
size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) {
|
||||||
if (!backing.Seek(offset, SEEK_SET))
|
if (!backing->Seek(offset, SEEK_SET))
|
||||||
return 0;
|
return 0;
|
||||||
return backing.WriteBytes(data, length);
|
return backing->WriteBytes(data, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RealVfsFile::Rename(std::string_view name) {
|
bool RealVfsFile::Rename(std::string_view name) {
|
||||||
std::string name_str(name.begin(), name.end());
|
return base.MoveFile(path, parent_path + DIR_SEP + std::string(name)) != nullptr;
|
||||||
const auto out = FileUtil::Rename(GetName(), name_str);
|
}
|
||||||
|
|
||||||
path = (parent_path + DIR_SEP).append(name);
|
bool RealVfsFile::Close() {
|
||||||
path_components = parent_components;
|
return backing->Close();
|
||||||
path_components.push_back(std::move(name_str));
|
}
|
||||||
backing = FileUtil::IOFile(path, ModeFlagsToString(perms).c_str());
|
|
||||||
|
// 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 == Mode::Append)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
std::vector<VirtualFile> out;
|
||||||
|
FileUtil::ForeachDirectoryEntry(
|
||||||
|
nullptr, path,
|
||||||
|
[&out, this](u64* entries_out, const std::string& directory, const std::string& filename) {
|
||||||
|
const std::string full_path = directory + DIR_SEP + filename;
|
||||||
|
if (!FileUtil::IsDirectory(full_path))
|
||||||
|
out.emplace_back(base.OpenFile(full_path, perms));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RealVfsFile::Close() {
|
template <>
|
||||||
return backing.Close();
|
std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDirectory>() const {
|
||||||
|
if (perms == Mode::Append)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
std::vector<VirtualDir> out;
|
||||||
|
FileUtil::ForeachDirectoryEntry(
|
||||||
|
nullptr, path,
|
||||||
|
[&out, this](u64* entries_out, const std::string& directory, const std::string& filename) {
|
||||||
|
const std::string full_path = directory + DIR_SEP + filename;
|
||||||
|
if (FileUtil::IsDirectory(full_path))
|
||||||
|
out.emplace_back(base.OpenDirectory(full_path, perms));
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
RealVfsDirectory::RealVfsDirectory(const std::string& path_, Mode perms_)
|
RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_)
|
||||||
: path(FileUtil::RemoveTrailingSlash(path_)), parent_path(FileUtil::GetParentPath(path)),
|
: base(base_), path(FileUtil::RemoveTrailingSlash(path_)),
|
||||||
|
parent_path(FileUtil::GetParentPath(path)),
|
||||||
path_components(FileUtil::SplitPathComponents(path)),
|
path_components(FileUtil::SplitPathComponents(path)),
|
||||||
parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
|
parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)),
|
||||||
perms(perms_) {
|
perms(perms_) {
|
||||||
if (!FileUtil::Exists(path) && perms & Mode::WriteAppend)
|
if (!FileUtil::Exists(path) && perms & Mode::WriteAppend)
|
||||||
FileUtil::CreateDir(path);
|
FileUtil::CreateDir(path);
|
||||||
|
}
|
||||||
|
|
||||||
if (perms == Mode::Append)
|
std::shared_ptr<VfsFile> RealVfsDirectory::GetFileRelative(std::string_view path) const {
|
||||||
return;
|
const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||||
|
if (!FileUtil::Exists(full_path))
|
||||||
|
return nullptr;
|
||||||
|
return base.OpenFile(full_path, perms);
|
||||||
|
}
|
||||||
|
|
||||||
FileUtil::ForeachDirectoryEntry(
|
std::shared_ptr<VfsDirectory> RealVfsDirectory::GetDirectoryRelative(std::string_view path) const {
|
||||||
nullptr, path,
|
const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||||
[this](u64* entries_out, const std::string& directory, const std::string& filename) {
|
if (!FileUtil::Exists(full_path))
|
||||||
std::string full_path = directory + DIR_SEP + filename;
|
return nullptr;
|
||||||
if (FileUtil::IsDirectory(full_path))
|
return base.OpenDirectory(full_path, perms);
|
||||||
subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(full_path, perms));
|
}
|
||||||
else
|
|
||||||
files.emplace_back(std::make_shared<RealVfsFile>(full_path, perms));
|
std::shared_ptr<VfsFile> RealVfsDirectory::GetFile(std::string_view name) const {
|
||||||
return true;
|
return GetFileRelative(name);
|
||||||
});
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<VfsDirectory> RealVfsDirectory::GetSubdirectory(std::string_view name) const {
|
||||||
|
return GetDirectoryRelative(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<VfsFile> RealVfsDirectory::CreateFileRelative(std::string_view path) {
|
||||||
|
const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||||
|
return base.CreateFile(full_path, perms);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateDirectoryRelative(std::string_view path) {
|
||||||
|
const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path));
|
||||||
|
auto parent = std::string(FileUtil::GetParentPath(full_path));
|
||||||
|
return base.CreateDirectory(full_path, perms);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RealVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
|
||||||
|
auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(name));
|
||||||
|
return base.DeleteDirectory(full_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const {
|
std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const {
|
||||||
return files;
|
return IterateEntries<RealVfsFile, VfsFile>();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const {
|
std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const {
|
||||||
return subdirectories;
|
return IterateEntries<RealVfsDirectory, VfsDirectory>();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RealVfsDirectory::IsWritable() const {
|
bool RealVfsDirectory::IsWritable() const {
|
||||||
|
@ -142,57 +366,32 @@ std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const {
|
||||||
if (path_components.size() <= 1)
|
if (path_components.size() <= 1)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return std::make_shared<RealVfsDirectory>(parent_path, perms);
|
return base.OpenDirectory(parent_path, perms);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(std::string_view name) {
|
std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(std::string_view name) {
|
||||||
const std::string subdir_path = (path + DIR_SEP).append(name);
|
const std::string subdir_path = (path + DIR_SEP).append(name);
|
||||||
|
return base.CreateDirectory(subdir_path, perms);
|
||||||
if (!FileUtil::CreateDir(subdir_path)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(subdir_path, perms));
|
|
||||||
return subdirectories.back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(std::string_view name) {
|
std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(std::string_view name) {
|
||||||
const std::string file_path = (path + DIR_SEP).append(name);
|
const std::string file_path = (path + DIR_SEP).append(name);
|
||||||
|
return base.CreateFile(file_path, perms);
|
||||||
if (!FileUtil::CreateEmptyFile(file_path)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
files.emplace_back(std::make_shared<RealVfsFile>(file_path, perms));
|
|
||||||
return files.back();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RealVfsDirectory::DeleteSubdirectory(std::string_view name) {
|
bool RealVfsDirectory::DeleteSubdirectory(std::string_view name) {
|
||||||
const std::string subdir_path = (path + DIR_SEP).append(name);
|
const std::string subdir_path = (path + DIR_SEP).append(name);
|
||||||
|
return base.DeleteDirectory(subdir_path);
|
||||||
return FileUtil::DeleteDirRecursively(subdir_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RealVfsDirectory::DeleteFile(std::string_view name) {
|
bool RealVfsDirectory::DeleteFile(std::string_view name) {
|
||||||
const auto file = GetFile(name);
|
|
||||||
|
|
||||||
if (file == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
files.erase(std::find(files.begin(), files.end(), file));
|
|
||||||
|
|
||||||
auto real_file = std::static_pointer_cast<RealVfsFile>(file);
|
|
||||||
real_file->Close();
|
|
||||||
|
|
||||||
const std::string file_path = (path + DIR_SEP).append(name);
|
const std::string file_path = (path + DIR_SEP).append(name);
|
||||||
return FileUtil::Delete(file_path);
|
return base.DeleteFile(file_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RealVfsDirectory::Rename(std::string_view name) {
|
bool RealVfsDirectory::Rename(std::string_view name) {
|
||||||
const std::string new_name = (parent_path + DIR_SEP).append(name);
|
const std::string new_name = (parent_path + DIR_SEP).append(name);
|
||||||
|
return base.MoveFile(path, new_name) != nullptr;
|
||||||
return FileUtil::Rename(path, new_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string RealVfsDirectory::GetFullPath() const {
|
std::string RealVfsDirectory::GetFullPath() const {
|
||||||
|
@ -202,16 +401,6 @@ std::string RealVfsDirectory::GetFullPath() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
|
bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) {
|
||||||
const auto iter = std::find(files.begin(), files.end(), file);
|
|
||||||
if (iter == files.end())
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
const std::ptrdiff_t offset = std::distance(files.begin(), iter);
|
|
||||||
files[offset] = files.back();
|
|
||||||
files.pop_back();
|
|
||||||
|
|
||||||
subdirectories.emplace_back(std::move(dir));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
|
@ -6,18 +6,45 @@
|
||||||
|
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <boost/container/flat_map.hpp>
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "core/file_sys/mode.h"
|
#include "core/file_sys/mode.h"
|
||||||
#include "core/file_sys/vfs.h"
|
#include "core/file_sys/vfs.h"
|
||||||
|
|
||||||
namespace FileSys {
|
namespace FileSys {
|
||||||
|
|
||||||
|
class RealVfsFilesystem : public VfsFilesystem {
|
||||||
|
public:
|
||||||
|
RealVfsFilesystem();
|
||||||
|
|
||||||
|
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, Mode perms = Mode::Read) override;
|
||||||
|
VirtualFile CreateFile(std::string_view path, Mode perms = Mode::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, Mode perms = Mode::Read) override;
|
||||||
|
VirtualDir CreateDirectory(std::string_view path, Mode perms = Mode::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:
|
||||||
|
boost::container::flat_map<std::string, std::weak_ptr<FileUtil::IOFile>> cache;
|
||||||
|
};
|
||||||
|
|
||||||
// An implmentation of VfsFile that represents a file on the user's computer.
|
// An implmentation of VfsFile that represents a file on the user's computer.
|
||||||
struct RealVfsFile : public VfsFile {
|
class RealVfsFile : public VfsFile {
|
||||||
friend struct RealVfsDirectory;
|
friend class RealVfsDirectory;
|
||||||
|
friend class RealVfsFilesystem;
|
||||||
|
|
||||||
RealVfsFile(const std::string& name, Mode perms = Mode::Read);
|
RealVfsFile(RealVfsFilesystem& base, std::shared_ptr<FileUtil::IOFile> backing,
|
||||||
|
const std::string& path, Mode perms = Mode::Read);
|
||||||
|
|
||||||
|
public:
|
||||||
std::string GetName() const override;
|
std::string GetName() const override;
|
||||||
size_t GetSize() const override;
|
size_t GetSize() const override;
|
||||||
bool Resize(size_t new_size) override;
|
bool Resize(size_t new_size) override;
|
||||||
|
@ -31,7 +58,8 @@ struct RealVfsFile : public VfsFile {
|
||||||
private:
|
private:
|
||||||
bool Close();
|
bool Close();
|
||||||
|
|
||||||
FileUtil::IOFile backing;
|
RealVfsFilesystem& base;
|
||||||
|
std::shared_ptr<FileUtil::IOFile> backing;
|
||||||
std::string path;
|
std::string path;
|
||||||
std::string parent_path;
|
std::string parent_path;
|
||||||
std::vector<std::string> path_components;
|
std::vector<std::string> path_components;
|
||||||
|
@ -40,9 +68,19 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
// An implementation of VfsDirectory that represents a directory on the user's computer.
|
// An implementation of VfsDirectory that represents a directory on the user's computer.
|
||||||
struct RealVfsDirectory : public VfsDirectory {
|
class RealVfsDirectory : public VfsDirectory {
|
||||||
RealVfsDirectory(const std::string& path, Mode perms = Mode::Read);
|
friend class RealVfsFilesystem;
|
||||||
|
|
||||||
|
RealVfsDirectory(RealVfsFilesystem& base, const std::string& path, Mode perms = Mode::Read);
|
||||||
|
|
||||||
|
public:
|
||||||
|
std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override;
|
||||||
|
std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override;
|
||||||
|
std::shared_ptr<VfsFile> GetFile(std::string_view name) const override;
|
||||||
|
std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const override;
|
||||||
|
std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override;
|
||||||
|
std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override;
|
||||||
|
bool DeleteSubdirectoryRecursive(std::string_view name) override;
|
||||||
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
|
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
|
||||||
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
|
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
|
||||||
bool IsWritable() const override;
|
bool IsWritable() const override;
|
||||||
|
@ -60,13 +98,15 @@ protected:
|
||||||
bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
|
bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
template <typename T, typename R>
|
||||||
|
std::vector<std::shared_ptr<R>> IterateEntries() const;
|
||||||
|
|
||||||
|
RealVfsFilesystem& base;
|
||||||
std::string path;
|
std::string path;
|
||||||
std::string parent_path;
|
std::string parent_path;
|
||||||
std::vector<std::string> path_components;
|
std::vector<std::string> path_components;
|
||||||
std::vector<std::string> parent_components;
|
std::vector<std::string> parent_components;
|
||||||
Mode perms;
|
Mode perms;
|
||||||
std::vector<std::shared_ptr<VfsFile>> files;
|
|
||||||
std::vector<std::shared_ptr<VfsDirectory>> subdirectories;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace FileSys
|
} // namespace FileSys
|
||||||
|
|
|
@ -59,7 +59,7 @@ ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64
|
||||||
ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const {
|
ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const {
|
||||||
std::string path(FileUtil::SanitizePath(path_));
|
std::string path(FileUtil::SanitizePath(path_));
|
||||||
auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
|
auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path));
|
||||||
if (path == "/" || path == "\\") {
|
if (path.empty()) {
|
||||||
// TODO(DarkLordZach): Why do games call this and what should it do? Works as is but...
|
// TODO(DarkLordZach): Why do games call this and what should it do? Works as is but...
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -281,15 +281,15 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
|
||||||
return sdmc_factory->Open();
|
return sdmc_factory->Open();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterFileSystems() {
|
void RegisterFileSystems(const FileSys::VirtualFilesystem& vfs) {
|
||||||
romfs_factory = nullptr;
|
romfs_factory = nullptr;
|
||||||
save_data_factory = nullptr;
|
save_data_factory = nullptr;
|
||||||
sdmc_factory = nullptr;
|
sdmc_factory = nullptr;
|
||||||
|
|
||||||
auto nand_directory = std::make_shared<FileSys::RealVfsDirectory>(
|
auto nand_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir),
|
||||||
FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::ReadWrite);
|
FileSys::Mode::ReadWrite);
|
||||||
auto sd_directory = std::make_shared<FileSys::RealVfsDirectory>(
|
auto sd_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir),
|
||||||
FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::Mode::ReadWrite);
|
FileSys::Mode::ReadWrite);
|
||||||
|
|
||||||
auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
|
auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
|
||||||
save_data_factory = std::move(savedata);
|
save_data_factory = std::move(savedata);
|
||||||
|
@ -298,8 +298,8 @@ void RegisterFileSystems() {
|
||||||
sdmc_factory = std::move(sdcard);
|
sdmc_factory = std::move(sdcard);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InstallInterfaces(SM::ServiceManager& service_manager) {
|
void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs) {
|
||||||
RegisterFileSystems();
|
RegisterFileSystems(vfs);
|
||||||
std::make_shared<FSP_LDR>()->InstallAsService(service_manager);
|
std::make_shared<FSP_LDR>()->InstallAsService(service_manager);
|
||||||
std::make_shared<FSP_PR>()->InstallAsService(service_manager);
|
std::make_shared<FSP_PR>()->InstallAsService(service_manager);
|
||||||
std::make_shared<FSP_SRV>()->InstallAsService(service_manager);
|
std::make_shared<FSP_SRV>()->InstallAsService(service_manager);
|
||||||
|
|
|
@ -36,7 +36,7 @@ ResultVal<FileSys::VirtualDir> OpenSDMC();
|
||||||
// ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenBIS();
|
// ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenBIS();
|
||||||
|
|
||||||
/// Registers all Filesystem services with the specified service manager.
|
/// Registers all Filesystem services with the specified service manager.
|
||||||
void InstallInterfaces(SM::ServiceManager& service_manager);
|
void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs);
|
||||||
|
|
||||||
// A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of
|
// A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of
|
||||||
// pointers and booleans. This makes using a VfsDirectory with switch services much easier and
|
// pointers and booleans. This makes using a VfsDirectory with switch services much easier and
|
||||||
|
|
|
@ -198,7 +198,7 @@ void AddNamedPort(std::string name, SharedPtr<ClientPort> port) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize ServiceManager
|
/// Initialize ServiceManager
|
||||||
void Init(std::shared_ptr<SM::ServiceManager>& sm) {
|
void Init(std::shared_ptr<SM::ServiceManager>& sm, const FileSys::VirtualFilesystem& rfs) {
|
||||||
// NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
|
// NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it
|
||||||
// here and pass it into the respective InstallInterfaces functions.
|
// here and pass it into the respective InstallInterfaces functions.
|
||||||
auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>();
|
auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>();
|
||||||
|
@ -221,7 +221,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) {
|
||||||
EUPLD::InstallInterfaces(*sm);
|
EUPLD::InstallInterfaces(*sm);
|
||||||
Fatal::InstallInterfaces(*sm);
|
Fatal::InstallInterfaces(*sm);
|
||||||
FGM::InstallInterfaces(*sm);
|
FGM::InstallInterfaces(*sm);
|
||||||
FileSystem::InstallInterfaces(*sm);
|
FileSystem::InstallInterfaces(*sm, rfs);
|
||||||
Friend::InstallInterfaces(*sm);
|
Friend::InstallInterfaces(*sm);
|
||||||
GRC::InstallInterfaces(*sm);
|
GRC::InstallInterfaces(*sm);
|
||||||
HID::InstallInterfaces(*sm);
|
HID::InstallInterfaces(*sm);
|
||||||
|
|
|
@ -22,6 +22,10 @@ class ServerSession;
|
||||||
class HLERequestContext;
|
class HLERequestContext;
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
||||||
|
namespace FileSys {
|
||||||
|
struct VfsFilesystem;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Service {
|
namespace Service {
|
||||||
|
|
||||||
namespace SM {
|
namespace SM {
|
||||||
|
@ -177,7 +181,8 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Initialize ServiceManager
|
/// Initialize ServiceManager
|
||||||
void Init(std::shared_ptr<SM::ServiceManager>& sm);
|
void Init(std::shared_ptr<SM::ServiceManager>& sm,
|
||||||
|
const std::shared_ptr<FileSys::VfsFilesystem>& vfs);
|
||||||
|
|
||||||
/// Shutdown ServiceManager
|
/// Shutdown ServiceManager
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
|
@ -43,10 +43,6 @@ FileType IdentifyFile(FileSys::VirtualFile file) {
|
||||||
return FileType::Unknown;
|
return FileType::Unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileType IdentifyFile(const std::string& file_name) {
|
|
||||||
return IdentifyFile(std::make_shared<FileSys::RealVfsFile>(file_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
FileType GuessFromFilename(const std::string& name) {
|
FileType GuessFromFilename(const std::string& name) {
|
||||||
if (name == "main")
|
if (name == "main")
|
||||||
return FileType::DeconstructedRomDirectory;
|
return FileType::DeconstructedRomDirectory;
|
||||||
|
|
|
@ -42,14 +42,6 @@ enum class FileType {
|
||||||
*/
|
*/
|
||||||
FileType IdentifyFile(FileSys::VirtualFile file);
|
FileType IdentifyFile(FileSys::VirtualFile file);
|
||||||
|
|
||||||
/**
|
|
||||||
* Identifies the type of a bootable file based on the magic value in its header.
|
|
||||||
* @param file_name path to file
|
|
||||||
* @return FileType of file. Note: this will return FileType::Unknown if it is unable to determine
|
|
||||||
* a filetype, and will never return FileType::Error.
|
|
||||||
*/
|
|
||||||
FileType IdentifyFile(const std::string& file_name);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Guess the type of a bootable file from its name
|
* Guess the type of a bootable file from its name
|
||||||
* @param name String name of bootable file
|
* @param name String name of bootable file
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "core/file_sys/content_archive.h"
|
#include "core/file_sys/content_archive.h"
|
||||||
#include "core/file_sys/control_metadata.h"
|
#include "core/file_sys/control_metadata.h"
|
||||||
|
#include "core/file_sys/romfs.h"
|
||||||
#include "core/file_sys/vfs_real.h"
|
#include "core/file_sys/vfs_real.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
#include "game_list.h"
|
#include "game_list.h"
|
||||||
|
@ -197,7 +198,8 @@ void GameList::onFilterCloseClicked() {
|
||||||
main_window->filterBarSetChecked(false);
|
main_window->filterBarSetChecked(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
GameList::GameList(GMainWindow* parent) : QWidget{parent} {
|
GameList::GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent)
|
||||||
|
: QWidget{parent}, vfs(std::move(vfs)) {
|
||||||
watcher = new QFileSystemWatcher(this);
|
watcher = new QFileSystemWatcher(this);
|
||||||
connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory);
|
connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory);
|
||||||
|
|
||||||
|
@ -341,7 +343,7 @@ void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) {
|
||||||
|
|
||||||
emit ShouldCancelWorker();
|
emit ShouldCancelWorker();
|
||||||
|
|
||||||
GameListWorker* worker = new GameListWorker(dir_path, deep_scan);
|
GameListWorker* worker = new GameListWorker(vfs, dir_path, deep_scan);
|
||||||
|
|
||||||
connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection);
|
connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection);
|
||||||
connect(worker, &GameListWorker::Finished, this, &GameList::DonePopulating,
|
connect(worker, &GameListWorker::Finished, this, &GameList::DonePopulating,
|
||||||
|
@ -414,8 +416,8 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
|
||||||
bool is_dir = FileUtil::IsDirectory(physical_name);
|
bool is_dir = FileUtil::IsDirectory(physical_name);
|
||||||
QFileInfo file_info(physical_name.c_str());
|
QFileInfo file_info(physical_name.c_str());
|
||||||
if (!is_dir && file_info.suffix().toStdString() == "nca") {
|
if (!is_dir && file_info.suffix().toStdString() == "nca") {
|
||||||
auto nca = std::make_shared<FileSys::NCA>(
|
auto nca =
|
||||||
std::make_shared<FileSys::RealVfsFile>(physical_name));
|
std::make_shared<FileSys::NCA>(vfs->OpenFile(physical_name, FileSys::Mode::Read));
|
||||||
if (nca->GetType() == FileSys::NCAContentType::Control)
|
if (nca->GetType() == FileSys::NCAContentType::Control)
|
||||||
nca_control_map.insert_or_assign(nca->GetTitleId(), nca);
|
nca_control_map.insert_or_assign(nca->GetTitleId(), nca);
|
||||||
}
|
}
|
||||||
|
@ -436,7 +438,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
|
||||||
if (!is_dir &&
|
if (!is_dir &&
|
||||||
(HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {
|
(HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {
|
||||||
std::unique_ptr<Loader::AppLoader> loader =
|
std::unique_ptr<Loader::AppLoader> loader =
|
||||||
Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(physical_name));
|
Loader::GetLoader(vfs->OpenFile(physical_name, FileSys::Mode::Read));
|
||||||
if (!loader || ((loader->GetFileType() == Loader::FileType::Unknown ||
|
if (!loader || ((loader->GetFileType() == Loader::FileType::Unknown ||
|
||||||
loader->GetFileType() == Loader::FileType::Error) &&
|
loader->GetFileType() == Loader::FileType::Error) &&
|
||||||
!UISettings::values.show_unknown))
|
!UISettings::values.show_unknown))
|
||||||
|
@ -459,7 +461,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
|
||||||
// Use from metadata pool.
|
// Use from metadata pool.
|
||||||
if (nca_control_map.find(program_id) != nca_control_map.end()) {
|
if (nca_control_map.find(program_id) != nca_control_map.end()) {
|
||||||
const auto nca = nca_control_map[program_id];
|
const auto nca = nca_control_map[program_id];
|
||||||
const auto control_dir = nca->GetSubdirectories()[0];
|
const auto control_dir = FileSys::ExtractRomFS(nca->GetRomFS());
|
||||||
|
|
||||||
const auto nacp_file = control_dir->GetFile("control.nacp");
|
const auto nacp_file = control_dir->GetFile("control.nacp");
|
||||||
FileSys::NACP nacp(nacp_file);
|
FileSys::NACP nacp(nacp_file);
|
||||||
|
|
|
@ -59,7 +59,7 @@ public:
|
||||||
QToolButton* button_filter_close = nullptr;
|
QToolButton* button_filter_close = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit GameList(GMainWindow* parent = nullptr);
|
explicit GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent = nullptr);
|
||||||
~GameList() override;
|
~GameList() override;
|
||||||
|
|
||||||
void clearFilter();
|
void clearFilter();
|
||||||
|
@ -90,6 +90,7 @@ private:
|
||||||
void PopupContextMenu(const QPoint& menu_location);
|
void PopupContextMenu(const QPoint& menu_location);
|
||||||
void RefreshGameDirectory();
|
void RefreshGameDirectory();
|
||||||
|
|
||||||
|
FileSys::VirtualFilesystem vfs;
|
||||||
SearchField* search_field;
|
SearchField* search_field;
|
||||||
GMainWindow* main_window = nullptr;
|
GMainWindow* main_window = nullptr;
|
||||||
QVBoxLayout* layout = nullptr;
|
QVBoxLayout* layout = nullptr;
|
||||||
|
|
|
@ -139,8 +139,8 @@ class GameListWorker : public QObject, public QRunnable {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GameListWorker(QString dir_path, bool deep_scan)
|
GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan)
|
||||||
: dir_path(std::move(dir_path)), deep_scan(deep_scan) {}
|
: vfs(std::move(vfs)), dir_path(std::move(dir_path)), deep_scan(deep_scan) {}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
/// Starts the processing of directory tree information.
|
/// Starts the processing of directory tree information.
|
||||||
|
@ -163,6 +163,7 @@ signals:
|
||||||
void Finished(QStringList watch_list);
|
void Finished(QStringList watch_list);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
FileSys::VirtualFilesystem vfs;
|
||||||
QStringList watch_list;
|
QStringList watch_list;
|
||||||
QString dir_path;
|
QString dir_path;
|
||||||
bool deep_scan;
|
bool deep_scan;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "common/string_util.h"
|
#include "common/string_util.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/crypto/key_manager.h"
|
#include "core/crypto/key_manager.h"
|
||||||
|
#include "core/file_sys/vfs_real.h"
|
||||||
#include "core/gdbstub/gdbstub.h"
|
#include "core/gdbstub/gdbstub.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
|
@ -83,7 +84,9 @@ void GMainWindow::ShowCallouts() {}
|
||||||
|
|
||||||
const int GMainWindow::max_recent_files_item;
|
const int GMainWindow::max_recent_files_item;
|
||||||
|
|
||||||
GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) {
|
GMainWindow::GMainWindow()
|
||||||
|
: config(new Config()), emu_thread(nullptr),
|
||||||
|
vfs(std::make_shared<FileSys::RealVfsFilesystem>()) {
|
||||||
|
|
||||||
debug_context = Tegra::DebugContext::Construct();
|
debug_context = Tegra::DebugContext::Construct();
|
||||||
|
|
||||||
|
@ -132,7 +135,7 @@ void GMainWindow::InitializeWidgets() {
|
||||||
render_window = new GRenderWindow(this, emu_thread.get());
|
render_window = new GRenderWindow(this, emu_thread.get());
|
||||||
render_window->hide();
|
render_window->hide();
|
||||||
|
|
||||||
game_list = new GameList(this);
|
game_list = new GameList(vfs, this);
|
||||||
ui.horizontalLayout->addWidget(game_list);
|
ui.horizontalLayout->addWidget(game_list);
|
||||||
|
|
||||||
// Create status bar
|
// Create status bar
|
||||||
|
@ -406,6 +409,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::System& system{Core::System::GetInstance()};
|
Core::System& system{Core::System::GetInstance()};
|
||||||
|
system.SetFilesystem(vfs);
|
||||||
|
|
||||||
system.SetGPUDebugContext(debug_context);
|
system.SetGPUDebugContext(debug_context);
|
||||||
|
|
||||||
|
|
|
@ -161,6 +161,9 @@ private:
|
||||||
bool emulation_running = false;
|
bool emulation_running = false;
|
||||||
std::unique_ptr<EmuThread> emu_thread;
|
std::unique_ptr<EmuThread> emu_thread;
|
||||||
|
|
||||||
|
// FS
|
||||||
|
FileSys::VirtualFilesystem vfs;
|
||||||
|
|
||||||
// Debugger panes
|
// Debugger panes
|
||||||
ProfilerWidget* profilerWidget;
|
ProfilerWidget* profilerWidget;
|
||||||
MicroProfileDialog* microProfileDialog;
|
MicroProfileDialog* microProfileDialog;
|
||||||
|
|
|
@ -161,6 +161,7 @@ int main(int argc, char** argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::System& system{Core::System::GetInstance()};
|
Core::System& system{Core::System::GetInstance()};
|
||||||
|
system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
|
||||||
|
|
||||||
SCOPE_EXIT({ system.Shutdown(); });
|
SCOPE_EXIT({ system.Shutdown(); });
|
||||||
|
|
||||||
|
|
Reference in New Issue