From 7d59c2743d4c63f9e6c83de6a245f9bf3b3c2902 Mon Sep 17 00:00:00 2001 From: iwubcode Date: Sun, 2 Mar 2025 23:57:13 -0600 Subject: [PATCH] Common: Add class 'FilesystemWatcher' that is used to watch paths and receive callbacks about filesystem level events for anything under that path --- Source/Core/Common/CMakeLists.txt | 3 ++ Source/Core/Common/FilesystemWatcher.cpp | 67 ++++++++++++++++++++++++ Source/Core/Common/FilesystemWatcher.h | 47 +++++++++++++++++ Source/Core/DolphinLib.props | 2 + 4 files changed, 119 insertions(+) create mode 100644 Source/Core/Common/FilesystemWatcher.cpp create mode 100644 Source/Core/Common/FilesystemWatcher.h diff --git a/Source/Core/Common/CMakeLists.txt b/Source/Core/Common/CMakeLists.txt index bbc3721a19..6d1b6908f3 100644 --- a/Source/Core/Common/CMakeLists.txt +++ b/Source/Core/Common/CMakeLists.txt @@ -64,6 +64,8 @@ add_library(common FatFsUtil.h FileSearch.cpp FileSearch.h + FilesystemWatcher.cpp + FilesystemWatcher.h FileUtil.cpp FileUtil.h FixedSizeQueue.h @@ -184,6 +186,7 @@ PRIVATE FatFs Iconv::Iconv spng::spng + watcher ${VTUNE_LIBRARIES} ) diff --git a/Source/Core/Common/FilesystemWatcher.cpp b/Source/Core/Common/FilesystemWatcher.cpp new file mode 100644 index 0000000000..646e2467ed --- /dev/null +++ b/Source/Core/Common/FilesystemWatcher.cpp @@ -0,0 +1,67 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "Common/FilesystemWatcher.h" + +#include + +#include "Common/Logging/Log.h" +#include "Common/StringUtil.h" + +namespace Common +{ +FilesystemWatcher::FilesystemWatcher() = default; +FilesystemWatcher::~FilesystemWatcher() = default; + +void FilesystemWatcher::Watch(const std::string& path) +{ + const auto [iter, inserted] = m_watched_paths.try_emplace(path, nullptr); + if (inserted) + { + iter->second = std::make_unique(path, [this](wtr::event e) { + const auto watched_path = PathToString(e.path_name); + if (e.path_type == wtr::event::path_type::watcher) + { + if (watched_path.starts_with('e')) + ERROR_LOG_FMT(COMMON, "Filesystem watcher: '{}'", watched_path); + else if (watched_path.starts_with('w')) + WARN_LOG_FMT(COMMON, "Filesystem watcher: '{}'", watched_path); + return; + } + + if (e.effect_type == wtr::event::effect_type::create) + { + const auto path = WithUnifiedPathSeparators(watched_path); + PathAdded(path); + } + else if (e.effect_type == wtr::event::effect_type::modify) + { + const auto path = WithUnifiedPathSeparators(watched_path); + PathModified(path); + } + else if (e.effect_type == wtr::event::effect_type::rename) + { + if (!e.associated) + { + WARN_LOG_FMT(COMMON, "Rename on path '{}' seen without association!", watched_path); + return; + } + + const auto old_path = WithUnifiedPathSeparators(watched_path); + const auto new_path = WithUnifiedPathSeparators(PathToString(e.associated->path_name)); + PathRenamed(old_path, new_path); + } + else if (e.effect_type == wtr::event::effect_type::destroy) + { + const auto path = WithUnifiedPathSeparators(watched_path); + PathDeleted(path); + } + }); + } +} + +void FilesystemWatcher::Unwatch(const std::string& path) +{ + m_watched_paths.erase(path); +} +} // namespace Common diff --git a/Source/Core/Common/FilesystemWatcher.h b/Source/Core/Common/FilesystemWatcher.h new file mode 100644 index 0000000000..ad1c822e2b --- /dev/null +++ b/Source/Core/Common/FilesystemWatcher.h @@ -0,0 +1,47 @@ +// Copyright 2025 Dolphin Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include +#include +#include + +namespace wtr +{ +inline namespace watcher +{ +class watch; +} +} // namespace wtr + +namespace Common +{ +// A class that can watch a path and receive callbacks +// when files or directories underneath that path receive events +class FilesystemWatcher +{ +public: + FilesystemWatcher(); + virtual ~FilesystemWatcher(); + + void Watch(const std::string& path); + void Unwatch(const std::string& path); + +private: + // A new file or folder was added to one of the watched paths + virtual void PathAdded(std::string_view path) {} + + // A file or folder was modified in one of the watched paths + virtual void PathModified(std::string_view path) {} + + // A file or folder was renamed in one of the watched paths + virtual void PathRenamed(std::string_view old_path, std::string_view new_path) {} + + // A file or folder was deleted in one of the watched paths + virtual void PathDeleted(std::string_view path) {} + + std::map> m_watched_paths; +}; +} // namespace Common diff --git a/Source/Core/DolphinLib.props b/Source/Core/DolphinLib.props index b21f1791d4..931207fbce 100644 --- a/Source/Core/DolphinLib.props +++ b/Source/Core/DolphinLib.props @@ -59,6 +59,7 @@ + @@ -813,6 +814,7 @@ +