From 4b471f0554146463f3b82eed14ff3922a5584e9f Mon Sep 17 00:00:00 2001
From: Zach Hilman <zachhilman@gmail.com>
Date: Fri, 3 Aug 2018 11:51:48 -0400
Subject: [PATCH] core: Port core to VfsFilesystem for file access

---
 src/core/core.cpp                              |  8 ++++++--
 src/core/core.h                                | 12 ++++++++++++
 src/core/hle/service/filesystem/filesystem.cpp | 14 +++++++-------
 src/core/hle/service/filesystem/filesystem.h   |  2 +-
 src/core/hle/service/service.cpp               |  4 ++--
 src/core/hle/service/service.h                 |  7 ++++++-
 src/yuzu/game_list.cpp                         |  7 ++++---
 src/yuzu/game_list.h                           |  3 ++-
 src/yuzu/game_list_p.h                         |  3 ++-
 src/yuzu/main.cpp                              | 10 ++++++----
 src/yuzu/main.h                                |  3 +++
 src/yuzu_cmd/yuzu.cpp                          |  1 +
 12 files changed, 52 insertions(+), 22 deletions(-)

diff --git a/src/core/core.cpp b/src/core/core.cpp
index 085ba68d0..69c45c026 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -89,7 +89,7 @@ System::ResultStatus System::SingleStep() {
 }
 
 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) {
         LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
@@ -174,6 +174,10 @@ System::ResultStatus System::Init(EmuWindow& emu_window) {
 
     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");
 
     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>();
 
     Kernel::Init();
-    Service::Init(service_manager);
+    Service::Init(service_manager, virtual_filesystem);
     GDBStub::Init();
 
     renderer = VideoCore::CreateRenderer(emu_window);
diff --git a/src/core/core.h b/src/core/core.h
index c8ca4b247..7cf7ea4e1 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -17,6 +17,8 @@
 #include "core/memory.h"
 #include "core/perf_stats.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/gpu.h"
 
@@ -211,6 +213,14 @@ public:
         return debug_context;
     }
 
+    void SetFilesystem(FileSys::VirtualFilesystem vfs) {
+        virtual_filesystem = std::move(vfs);
+    }
+
+    FileSys::VirtualFilesystem GetFilesystem() const {
+        return virtual_filesystem;
+    }
+
 private:
     System();
 
@@ -225,6 +235,8 @@ private:
      */
     ResultStatus Init(EmuWindow& emu_window);
 
+    /// RealVfsFilesystem instance
+    FileSys::VirtualFilesystem virtual_filesystem;
     /// AppLoader used to load the current executing application
     std::unique_ptr<Loader::AppLoader> app_loader;
     std::unique_ptr<VideoCore::RendererBase> renderer;
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp
index 9b87e3484..5e416cde2 100644
--- a/src/core/hle/service/filesystem/filesystem.cpp
+++ b/src/core/hle/service/filesystem/filesystem.cpp
@@ -281,15 +281,15 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
     return sdmc_factory->Open();
 }
 
-void RegisterFileSystems() {
+void RegisterFileSystems(const FileSys::VirtualFilesystem& vfs) {
     romfs_factory = nullptr;
     save_data_factory = nullptr;
     sdmc_factory = nullptr;
 
-    auto nand_directory = std::make_shared<FileSys::RealVfsDirectory>(
-        FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::ReadWrite);
-    auto sd_directory = std::make_shared<FileSys::RealVfsDirectory>(
-        FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::Mode::ReadWrite);
+    auto nand_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir),
+                                             FileSys::Mode::ReadWrite);
+    auto sd_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir),
+                                           FileSys::Mode::ReadWrite);
 
     auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory));
     save_data_factory = std::move(savedata);
@@ -298,8 +298,8 @@ void RegisterFileSystems() {
     sdmc_factory = std::move(sdcard);
 }
 
-void InstallInterfaces(SM::ServiceManager& service_manager) {
-    RegisterFileSystems();
+void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs) {
+    RegisterFileSystems(vfs);
     std::make_shared<FSP_LDR>()->InstallAsService(service_manager);
     std::make_shared<FSP_PR>()->InstallAsService(service_manager);
     std::make_shared<FSP_SRV>()->InstallAsService(service_manager);
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h
index d4483daa5..462c13f20 100644
--- a/src/core/hle/service/filesystem/filesystem.h
+++ b/src/core/hle/service/filesystem/filesystem.h
@@ -36,7 +36,7 @@ ResultVal<FileSys::VirtualDir> OpenSDMC();
 // ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenBIS();
 
 /// 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
 // pointers and booleans. This makes using a VfsDirectory with switch services much easier and
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 6f286ea74..11951adaf 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -198,7 +198,7 @@ void AddNamedPort(std::string name, SharedPtr<ClientPort> port) {
 }
 
 /// 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
     // here and pass it into the respective InstallInterfaces functions.
     auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>();
@@ -221,7 +221,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) {
     EUPLD::InstallInterfaces(*sm);
     Fatal::InstallInterfaces(*sm);
     FGM::InstallInterfaces(*sm);
-    FileSystem::InstallInterfaces(*sm);
+    FileSystem::InstallInterfaces(*sm, rfs);
     Friend::InstallInterfaces(*sm);
     GRC::InstallInterfaces(*sm);
     HID::InstallInterfaces(*sm);
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 046c5e18d..8a294c0f2 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -22,6 +22,10 @@ class ServerSession;
 class HLERequestContext;
 } // namespace Kernel
 
+namespace FileSys {
+struct VfsFilesystem;
+}
+
 namespace Service {
 
 namespace SM {
@@ -177,7 +181,8 @@ private:
 };
 
 /// 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
 void Shutdown();
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp
index 5f47f5a2b..e150a0684 100644
--- a/src/yuzu/game_list.cpp
+++ b/src/yuzu/game_list.cpp
@@ -197,7 +197,8 @@ void GameList::onFilterCloseClicked() {
     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);
     connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory);
 
@@ -341,7 +342,7 @@ void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) {
 
     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::Finished, this, &GameList::DonePopulating,
@@ -436,7 +437,7 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
         if (!is_dir &&
             (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) {
             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 ||
                              loader->GetFileType() == Loader::FileType::Error) &&
                             !UISettings::values.show_unknown))
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h
index 3bc14f07f..afe624b32 100644
--- a/src/yuzu/game_list.h
+++ b/src/yuzu/game_list.h
@@ -59,7 +59,7 @@ public:
         QToolButton* button_filter_close = nullptr;
     };
 
-    explicit GameList(GMainWindow* parent = nullptr);
+    explicit GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent = nullptr);
     ~GameList() override;
 
     void clearFilter();
@@ -90,6 +90,7 @@ private:
     void PopupContextMenu(const QPoint& menu_location);
     void RefreshGameDirectory();
 
+    FileSys::VirtualFilesystem vfs;
     SearchField* search_field;
     GMainWindow* main_window = nullptr;
     QVBoxLayout* layout = nullptr;
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h
index a22025e67..49a3f6181 100644
--- a/src/yuzu/game_list_p.h
+++ b/src/yuzu/game_list_p.h
@@ -139,7 +139,7 @@ class GameListWorker : public QObject, public QRunnable {
     Q_OBJECT
 
 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) {}
 
 public slots:
@@ -163,6 +163,7 @@ signals:
     void Finished(QStringList watch_list);
 
 private:
+    FileSys::VirtualFilesystem vfs;
     QStringList watch_list;
     QString dir_path;
     bool deep_scan;
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp
index a6241e63e..f7812a392 100644
--- a/src/yuzu/main.cpp
+++ b/src/yuzu/main.cpp
@@ -24,6 +24,7 @@
 #include "common/string_util.h"
 #include "core/core.h"
 #include "core/crypto/key_manager.h"
+#include "core/file_sys/vfs_real.h"
 #include "core/gdbstub/gdbstub.h"
 #include "core/loader/loader.h"
 #include "core/settings.h"
@@ -81,9 +82,9 @@ static void ShowCalloutMessage(const QString& message, CalloutFlag flag) {
 
 void GMainWindow::ShowCallouts() {}
 
-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();
 
@@ -132,7 +133,7 @@ void GMainWindow::InitializeWidgets() {
     render_window = new GRenderWindow(this, emu_thread.get());
     render_window->hide();
 
-    game_list = new GameList(this);
+    game_list = new GameList(vfs, this);
     ui.horizontalLayout->addWidget(game_list);
 
     // Create status bar
@@ -406,6 +407,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
     }
 
     Core::System& system{Core::System::GetInstance()};
+    system.SetFilesystem(vfs);
 
     system.SetGPUDebugContext(debug_context);
 
diff --git a/src/yuzu/main.h b/src/yuzu/main.h
index 6e335b8f8..74487c58c 100644
--- a/src/yuzu/main.h
+++ b/src/yuzu/main.h
@@ -161,6 +161,9 @@ private:
     bool emulation_running = false;
     std::unique_ptr<EmuThread> emu_thread;
 
+    // FS
+    FileSys::VirtualFilesystem vfs;
+
     // Debugger panes
     ProfilerWidget* profilerWidget;
     MicroProfileDialog* microProfileDialog;
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp
index d637dbd0c..0605c92e3 100644
--- a/src/yuzu_cmd/yuzu.cpp
+++ b/src/yuzu_cmd/yuzu.cpp
@@ -161,6 +161,7 @@ int main(int argc, char** argv) {
     }
 
     Core::System& system{Core::System::GetInstance()};
+    system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>());
 
     SCOPE_EXIT({ system.Shutdown(); });