FileMonitor.cpp
branchv_0
changeset 7 e6065118326f
child 23 42341f66de52
--- /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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <string>
+#include <stdexcept>
+#include <map>
+#include <sys/inotify.h>
+#include <string.h>
+#include <unistd.h>
+
+#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<FileMonitor::Impl> fileMonitorImpl;
+
+	virtual ~Impl();
+};
+
+WatchedFile::WatchedFile() {
+	impl = std::make_shared<Impl>();
+}
+
+WatchedFile::~WatchedFile() {
+}
+
+class FileMonitor::Impl {
+public:
+	int fd;
+	std::map<int, std::string> 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<Impl>()) {
+}
+
+FileMonitor::FileMonitor(std::shared_ptr<Impl> 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;
+}
+
+