From 4afb05d0cc35f36ea145768f052755554d9494fc Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 8 Aug 2018 17:39:00 -0400 Subject: fsp_srv: Emplace entries first when building index instead of emplacing last The current way were doing it would require copying a 768 character buffer (part of the Entry struct) to the new element in the vector. Given it's a plain array, std::move won't eliminate that. Instead, we can emplace an instance directly into the destination buffer and then fill it out, avoiding the need to perform any unnecessary copies. Given this is done in a loop, we can request the destination to allocate all of the necessary memory ahead of time, avoiding the need to potentially keep reallocating over and over on every few insertions into the vector. --- src/core/hle/service/filesystem/fsp_srv.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src/core/hle/service/filesystem') diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index e7ffb6bd1..4110e67b4 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -193,13 +193,14 @@ private: template static void BuildEntryIndex(std::vector& entries, const std::vector& new_data, FileSys::EntryType type) { + entries.reserve(entries.size() + new_data.size()); + for (const auto& new_entry : new_data) { - FileSys::Entry entry; + auto& entry = entries.emplace_back(); entry.filename[0] = '\0'; std::strncat(entry.filename, new_entry->GetName().c_str(), FileSys::FILENAME_LENGTH - 1); entry.type = type; entry.file_size = new_entry->GetSize(); - entries.emplace_back(std::move(entry)); } } -- cgit v1.2.3 From 7353cfc7813c960e7fdb0b33829865c606f98c84 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 8 Aug 2018 17:49:57 -0400 Subject: fsp_srv: Use std::string_view's copy() function instead of strncpy() Given elements inserted into a vector are zeroed out, we can just copy MAX_LEN - 1 elements and the data will already be properly null terminated. --- src/core/file_sys/directory.h | 12 +++++++++--- src/core/hle/service/filesystem/fsp_srv.cpp | 6 +----- 2 files changed, 10 insertions(+), 8 deletions(-) (limited to 'src/core/hle/service/filesystem') diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h index 213ce1826..3759e743a 100644 --- a/src/core/file_sys/directory.h +++ b/src/core/file_sys/directory.h @@ -4,8 +4,9 @@ #pragma once -#include #include +#include +#include #include "common/common_funcs.h" #include "common/common_types.h" @@ -21,9 +22,14 @@ enum EntryType : u8 { // Structure of a directory entry, from // http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry -const size_t FILENAME_LENGTH = 0x300; struct Entry { - char filename[FILENAME_LENGTH]; + Entry(std::string_view view, EntryType entry_type, u64 entry_size) + : type{entry_type}, file_size{entry_size} { + const size_t copy_size = view.copy(filename, std::size(filename) - 1); + filename[copy_size] = '\0'; + } + + char filename[0x300]; INSERT_PADDING_BYTES(4); EntryType type; INSERT_PADDING_BYTES(3); diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 4110e67b4..1470f9017 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -196,11 +196,7 @@ static void BuildEntryIndex(std::vector& entries, const std::vec entries.reserve(entries.size() + new_data.size()); for (const auto& new_entry : new_data) { - auto& entry = entries.emplace_back(); - entry.filename[0] = '\0'; - std::strncat(entry.filename, new_entry->GetName().c_str(), FileSys::FILENAME_LENGTH - 1); - entry.type = type; - entry.file_size = new_entry->GetSize(); + entries.emplace_back(new_entry->GetName(), type, new_entry->GetSize()); } } -- cgit v1.2.3 From b36dee364e37c4b3295288d206f81dd6f1a03480 Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 3 Aug 2018 11:44:40 -0400 Subject: filesystem: Remove unnecessary if conditions --- src/core/hle/service/filesystem/filesystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/core/hle/service/filesystem') diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index e17d637e4..9b87e3484 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -59,7 +59,7 @@ ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const { std::string path(FileUtil::SanitizePath(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... return RESULT_SUCCESS; } -- cgit v1.2.3 From 4b471f0554146463f3b82eed14ff3922a5584e9f Mon Sep 17 00:00:00 2001 From: Zach Hilman Date: Fri, 3 Aug 2018 11:51:48 -0400 Subject: 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(-) (limited to 'src/core/hle/service/filesystem') 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(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(); + current_process = Kernel::Process::Create("main"); cpu_barrier = std::make_shared(); @@ -186,7 +190,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window) { service_manager = std::make_shared(); 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 app_loader; std::unique_ptr 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 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( - FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::ReadWrite); - auto sd_directory = std::make_shared( - 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(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()->InstallAsService(service_manager); std::make_shared()->InstallAsService(service_manager); std::make_shared()->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 OpenSDMC(); // ResultVal> 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 port) { } /// Initialize ServiceManager -void Init(std::shared_ptr& sm) { +void Init(std::shared_ptr& 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(); @@ -221,7 +221,7 @@ void Init(std::shared_ptr& 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); +void Init(std::shared_ptr& sm, + const std::shared_ptr& 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 = - Loader::GetLoader(std::make_shared(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()) { 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 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()); SCOPE_EXIT({ system.Shutdown(); }); -- cgit v1.2.3