summaryrefslogtreecommitdiff
path: root/server/src/inotify.cc
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/inotify.cc')
-rw-r--r--server/src/inotify.cc255
1 files changed, 255 insertions, 0 deletions
diff --git a/server/src/inotify.cc b/server/src/inotify.cc
new file mode 100644
index 0000000..f22e4ca
--- /dev/null
+++ b/server/src/inotify.cc
@@ -0,0 +1,255 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set et sw=2 ts=2: */
+/***************************************************************************
+ * inotify.cc
+ *
+ * Wed Jan 6 09:58:47 CET 2010
+ * Copyright 2010 Bent Bisballe Nyeng
+ * deva@aasimon.org
+ ****************************************************************************/
+
+/*
+ * This file is part of Pracro.
+ *
+ * Pracro 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Pracro 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 Pracro; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+#include "inotify.h"
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+
+#define TEST(x, m) ((x & m) == m)
+
+static std::string mask2asc(uint32_t mask)
+{
+ // printf("mask: %x\n", mask);
+ std::string str;
+ if(TEST(mask, IN_ACCESS)) str += "File was accessed (read).";
+ if(TEST(mask, IN_ATTRIB)) str += "Metadata changed (permissions, timestamps, extended attributes, etc.).";
+ if(TEST(mask, IN_CLOSE_WRITE)) str += "File opened for writing was closed.";
+ if(TEST(mask, IN_CLOSE_NOWRITE)) str += "File not opened for writing was closed.";
+ if(TEST(mask, IN_CREATE)) str += "File/directory created in watched directory.";
+ if(TEST(mask, IN_DELETE)) str += "File/directory deleted from watched directory.";
+ if(TEST(mask, IN_DELETE_SELF)) str += "Watched file/directory was itself deleted.";
+ if(TEST(mask, IN_MODIFY)) str += "File was modified.";
+ if(TEST(mask, IN_MOVE_SELF)) str += "Watched file/directory was itself moved.";
+ if(TEST(mask, IN_MOVED_FROM)) str += "File moved out of watched directory.";
+ if(TEST(mask, IN_MOVED_TO)) str += "File moved into watched directory.";
+ if(TEST(mask, IN_OPEN)) str += "File was opened.";
+ if(TEST(mask, IN_ALL_EVENTS)) str += "All the above.";
+ return str;
+}
+
+static inline bool isdir(const char *name)
+{
+ struct stat s;
+ stat(name, &s);
+ return S_ISDIR(s.st_mode);
+}
+
+INotify::Event::Event(std::string name, uint32_t mask)
+{
+ this->_name = name;
+ this->_mask = mask;
+}
+
+bool INotify::Event::isCloseEvent()
+{
+ return TEST(_mask, IN_CLOSE_WRITE) || TEST(_mask, IN_CLOSE_NOWRITE);
+}
+
+bool INotify::Event::isOpenEvent()
+{
+ return TEST(_mask, IN_OPEN) || TEST(_mask, IN_CREATE);
+}
+
+bool INotify::Event::isModifyEvent()
+{
+ return TEST(_mask, IN_MODIFY);
+}
+
+bool INotify::Event::isDeleteEvent()
+{
+ return TEST(_mask, IN_DELETE) || TEST(_mask, IN_DELETE_SELF);
+}
+
+std::string INotify::Event::name()
+{
+ return _name;
+}
+
+uint32_t INotify::Event::mask()
+{
+ return _mask;
+}
+
+INotify::INotify()
+{
+ fd = inotify_init1(O_NONBLOCK);
+ if(fd == -1) {
+ perror("Inotify init failed.\n");
+ return;
+ }
+}
+
+INotify::~INotify()
+{
+ if(fd != -1) close(fd);
+}
+
+void INotify::add(std::string name, uint32_t mask)
+{
+ int _fd = inotify_add_watch(fd, name.c_str(), mask);
+ if(_fd == -1) {
+ perror("INotify: Add watch failed!");
+ return;
+ }
+ // dirmap[fd] = name;
+}
+
+void INotify::addRecursive(std::string name, uint32_t mask)
+{
+ /*
+ int fd = this->add(name, mask);
+ return fd;
+ */
+}
+
+void INotify::readEvents()
+{
+ char buf[sizeof(struct inotify_event)];
+ ssize_t r = 0;
+ while( (r = read(fd, buf, sizeof(buf))) > 0) {
+ struct inotify_event *event = (struct inotify_event *)buf;
+ /*
+ printf("--- Event ---:\n");
+ if(event->len) printf("Name: %s\n", event->name);
+ printf("Descriptor: %d\n", event->wd);
+ printf("Events:\n%s\n", mask2asc(event->mask).c_str());
+ */
+ eventlist.push_back(Event(event->name, event->mask));
+ /*
+ // Add watch on new subfolder.
+ if(TEST(event->mask, IN_CREATE) && isdir(event->name)) {
+ std::string fullpath = dirmap[event->wd] + "/" + event->name;
+ int fd = inotify_add_watch(watch, fullpath.c_str(), IN_ALL_EVENTS);
+ dirmap[fd] = fullpath;
+ }
+ */
+ /*
+ // Remove watch on deleted subfolder.
+ if(TEST(event->mask, IN_DELETE) && isdir(event->name)) {
+ inotify_add_watch(watch, event->name, IN_ALL_EVENTS);
+ }
+ */
+ }
+}
+
+bool INotify::hasEvents()
+{
+ readEvents();
+ return eventlist.size() > 0;
+}
+
+INotify::Event INotify::getNextEvent()
+{
+ readEvents();
+ if(eventlist.size()) {
+ Event event = eventlist.front();
+ eventlist.pop_front();
+ return event;
+ }
+ return Event("", 0);
+}
+
+void INotify::remove(int fd)
+{
+ inotify_rm_watch(this->fd, fd);
+}
+
+void INotify::remove(std::string name)
+{
+ // this->remove(rlookup(map, name))
+}
+
+#ifdef TEST_INOTIFY
+//deps: debug.cc
+//cflags: -I..
+//libs:
+#include "test.h"
+
+#include <stdio.h>
+
+#define _DIR "/tmp"
+#define _FILE _DIR"/inotify_test"
+
+TEST_BEGIN;
+
+INotify inotify;
+
+// Create file
+FILE *fp = fopen(_FILE, "w");
+TEST_NOTEQUAL(fp, NULL, "Testing if able to write file");
+fprintf(fp, "something");
+fclose(fp);
+
+inotify.add(_FILE);
+
+
+// Append to file
+fp = fopen(_FILE, "a");
+TEST_NOTEQUAL(fp, NULL, "Testing if able to write file");
+TEST_TRUE(inotify.hasEvents(), "Test if the open event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isOpenEvent(), "Test if the event was an open event.");
+
+fprintf(fp, "else"); fflush(fp);
+TEST_TRUE(inotify.hasEvents(), "Test if the append event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "Test if the event was a modified event.");
+
+fclose(fp);
+TEST_TRUE(inotify.hasEvents(), "Test if the close event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isCloseEvent(), "Test if the event was a close event.");
+
+
+// Overwrite file
+fp = fopen(_FILE, "w");
+TEST_NOTEQUAL(fp, NULL, "Testing if able to write file");
+TEST_TRUE(inotify.hasEvents(), "Test if the open event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isOpenEvent(), "Test if the event was an open event.");
+
+fprintf(fp, "else"); fflush(fp);
+TEST_TRUE(inotify.hasEvents(), "Test if the append event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "Test if the event was a modified event.");
+
+fclose(fp);
+TEST_TRUE(inotify.hasEvents(), "Test if the close event was triggered.");
+TEST_TRUE(inotify.getNextEvent().isCloseEvent(), "Test if the event was a close event.");
+
+
+// Delete file
+unlink(_FILE);
+
+TEST_EQUAL(inotify.hasEvents(), true, "Test if the delete event was triggered.");
+TEST_EQUAL(inotify.getNextEvent().isDeleteEvent(), true, "Test if the event was a delete event.");
+
+mask2asc(0);
+
+TEST_END;
+
+#endif/*TEST_INOTIFY*/