diff -r fd93a46db15b -r e6065118326f FileMonitor.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/FileMonitor.cpp Sat Dec 02 15:02:56 2023 +0100 @@ -0,0 +1,127 @@ +/** + * ShaderShark + * Copyright © 2023 František Kučera (Frantovo.cz, GlobalCode.info) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "FileMonitor.h" + +void checkError(bool hasError, const std::string& message) { + if (hasError) throw std::logic_error(message + strerror(errno)); +} + +class WatchedFile::Impl { +public: + int fd; + int wd; + std::string fileName; + uint32_t mask; + std::shared_ptr fileMonitorImpl; + + virtual ~Impl(); +}; + +WatchedFile::WatchedFile() { + impl = std::make_shared(); +} + +WatchedFile::~WatchedFile() { +} + +class FileMonitor::Impl { +public: + int fd; + std::map fileNames; + + void unwatch(int wd) { + int result = inotify_rm_watch(fd, wd); + checkError(result < 0, "unable to stop monitoring a file: "); + fileNames.erase(wd); + } + + virtual ~Impl() { + close(fd); + } + +}; + +FileMonitor::FileMonitor() : FileMonitor(std::make_shared()) { +} + +FileMonitor::FileMonitor(std::shared_ptr impl) { + this->impl = impl; + impl->fd = inotify_init1(IN_NONBLOCK); + checkError(impl->fd < 0, "unable to initialize FileMonitor: "); +} + +FileMonitor::~FileMonitor() { +} + +int FileMonitor::getFD() const { + return impl->fd; +} + +WatchedFile FileMonitor::watch(const std::string& fileName) { + return watch(fileName, IN_CLOSE_WRITE); +} + +WatchedFile FileMonitor::watch(const std::string& fileName, uint32_t mask) { + int wd = inotify_add_watch(impl->fd, fileName.c_str(), mask); + checkError(wd < 0, "unable to monitor a file: "); + impl->fileNames[wd] = fileName; + WatchedFile wf; + wf.impl->fd = impl->fd; + wf.impl->wd = wd; + wf.impl->fileMonitorImpl = impl; + wf.impl->fileName = fileName; + wf.impl->mask = mask; + return wf; +} + +bool FileMonitor::readEvent(FileEvent& event) { + struct inotify_event rawEvent; + int result = ::read(impl->fd, &rawEvent, sizeof (rawEvent)); + if (result == sizeof (rawEvent)) { + event.fileName = impl->fileNames[rawEvent.wd]; + event.mask = rawEvent.mask; + return true; + } else { + return false; + } +} + +WatchedFile::Impl::~Impl() { + fileMonitorImpl->unwatch(wd); +} + +FileMonitor WatchedFile::getFileMonitor() const { + return FileMonitor(impl->fileMonitorImpl); +} + +std::string WatchedFile::getFileName() const { + return impl->fileName; +} + +uint32_t WatchedFile::getMask() const { + return impl->mask; +} + +