From 79660f2fe96acdf2a6b28453b575f1e28ece250d Mon Sep 17 00:00:00 2001 From: Silent Date: Mon, 24 Oct 2022 02:35:00 +0200 Subject: [PATCH] Fix FileWatcher (#18216) --- src/openrct2/core/FileWatcher.cpp | 34 ++++++++++++------------- src/openrct2/core/FileWatcher.h | 10 +++++--- src/openrct2/scripting/ScriptEngine.cpp | 10 ++++---- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/openrct2/core/FileWatcher.cpp b/src/openrct2/core/FileWatcher.cpp index 7943d103ed..c38a0263cb 100644 --- a/src/openrct2/core/FileWatcher.cpp +++ b/src/openrct2/core/FileWatcher.cpp @@ -20,6 +20,7 @@ # include #endif +#include "../core/Path.hpp" #include "../core/String.hpp" #include "FileSystem.hpp" #include "FileWatcher.h" @@ -81,20 +82,20 @@ FileWatcher::WatchDescriptor::~WatchDescriptor() } #endif -FileWatcher::FileWatcher(const std::string& directoryPath) +FileWatcher::FileWatcher(u8string_view directoryPath) { #ifdef _WIN32 - _path = directoryPath; - _directoryHandle = CreateFileA( - directoryPath.c_str(), FILE_LIST_DIRECTORY, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, - nullptr); + _path = fs::u8path(directoryPath); + _directoryHandle = CreateFileW( + String::ToWideChar(directoryPath).c_str(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr); if (_directoryHandle == INVALID_HANDLE_VALUE) { - throw std::runtime_error("Unable to open directory '" + directoryPath + "'"); + throw std::runtime_error("Unable to open directory '" + u8string(directoryPath) + "'"); } #elif defined(__linux__) _fileDesc.Initialise(); - _watchDescs.emplace_back(_fileDesc.Fd, directoryPath); + _watchDescs.emplace_back(_fileDesc.Fd, u8string(directoryPath)); for (auto& p : fs::recursive_directory_iterator(directoryPath)) { if (p.status().type() == fs::file_type::directory) @@ -105,21 +106,22 @@ FileWatcher::FileWatcher(const std::string& directoryPath) #else throw std::runtime_error("FileWatcher not supported on this platform."); #endif - _watchThread = std::thread(std::bind(&FileWatcher::WatchDirectory, this)); + _watchThread = std::thread(&FileWatcher::WatchDirectory, this); } FileWatcher::~FileWatcher() { #ifdef _WIN32 CancelIoEx(_directoryHandle, nullptr); + _watchThread.join(); CloseHandle(_directoryHandle); #elif defined(__linux__) _finished = true; + _watchThread.join(); _fileDesc.Close(); #else return; #endif - _watchThread.join(); } void FileWatcher::WatchDirectory() @@ -131,8 +133,7 @@ void FileWatcher::WatchDirectory() _directoryHandle, eventData.data(), static_cast(eventData.size()), TRUE, FILE_NOTIFY_CHANGE_LAST_WRITE, &bytesReturned, nullptr, nullptr)) { - auto onFileChanged = OnFileChanged; - if (onFileChanged) + if (bytesReturned != 0 && OnFileChanged) { FILE_NOTIFY_INFORMATION* notifyInfo; size_t offset = 0; @@ -141,10 +142,9 @@ void FileWatcher::WatchDirectory() notifyInfo = reinterpret_cast(eventData.data() + offset); offset += notifyInfo->NextEntryOffset; - std::wstring fileNameW(notifyInfo->FileName, notifyInfo->FileNameLength / sizeof(wchar_t)); - auto fileName = String::ToUtf8(fileNameW); - auto path = fs::path(_path) / fs::path(fileName); - onFileChanged(path.u8string()); + std::wstring_view fileNameW(notifyInfo->FileName, notifyInfo->FileNameLength / sizeof(wchar_t)); + auto path = _path / fs::path(fileNameW); + OnFileChanged(path.u8string()); } while (notifyInfo->NextEntryOffset != 0); } } @@ -175,9 +175,7 @@ void FileWatcher::WatchDirectory() [wd](const WatchDescriptor& watchDesc) { return wd == watchDesc.Wd; }); if (findResult != _watchDescs.end()) { - auto directory = findResult->Path; - auto path = fs::path(directory) / fs::path(e->name); - onFileChanged(path); + onFileChanged(Path::Combine(findResult->Path, e->name)); } } offset += sizeof(inotify_event) + e->len; diff --git a/src/openrct2/core/FileWatcher.h b/src/openrct2/core/FileWatcher.h index 17f1e9f3c1..8fcc0f5a2c 100644 --- a/src/openrct2/core/FileWatcher.h +++ b/src/openrct2/core/FileWatcher.h @@ -9,12 +9,16 @@ #pragma once +#include "String.hpp" + #include #include #include #include #ifdef _WIN32 +# include "FileSystem.hpp" + typedef void* HANDLE; #endif @@ -26,7 +30,7 @@ class FileWatcher private: std::thread _watchThread; #if defined(_WIN32) - std::string _path; + fs::path _path; HANDLE _directoryHandle{}; #elif defined(__linux__) struct FileDescriptor @@ -53,9 +57,9 @@ private: #endif public: - std::function OnFileChanged; + std::function OnFileChanged; - FileWatcher(const std::string& directoryPath); + FileWatcher(u8string_view directoryPath); ~FileWatcher(); private: diff --git a/src/openrct2/scripting/ScriptEngine.cpp b/src/openrct2/scripting/ScriptEngine.cpp index e2407c27be..76eee91c90 100644 --- a/src/openrct2/scripting/ScriptEngine.cpp +++ b/src/openrct2/scripting/ScriptEngine.cpp @@ -771,8 +771,8 @@ void ScriptEngine::SetupHotReloading() if (Path::DirectoryExists(base)) { _pluginFileWatcher = std::make_unique(base); - _pluginFileWatcher->OnFileChanged = [this](const std::string& path) { - std::lock_guard guard(_changedPluginFilesMutex); + _pluginFileWatcher->OnFileChanged = [this](u8string_view path) { + std::lock_guard guard(_changedPluginFilesMutex); _changedPluginFiles.emplace(path); }; _hotReloadingInitialised = true; @@ -799,10 +799,10 @@ void ScriptEngine::DoAutoReloadPluginCheck() void ScriptEngine::AutoReloadPlugins() { - if (_changedPluginFiles.size() > 0) + if (!_changedPluginFiles.empty()) { - std::lock_guard guard(_changedPluginFilesMutex); - for (auto& path : _changedPluginFiles) + std::lock_guard guard(_changedPluginFilesMutex); + for (const auto& path : _changedPluginFiles) { auto findResult = std::find_if(_plugins.begin(), _plugins.end(), [&path](const std::shared_ptr& plugin) { return Path::Equals(path, plugin->GetPath());