From b1268fe3acfa11e69dc909e8d9cceffe6745e452 Mon Sep 17 00:00:00 2001 From: deva Date: Thu, 7 Jan 2010 07:14:33 +0000 Subject: Initial code for inotify wrapper class. --- server/src/inotify.cc | 255 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 server/src/inotify.cc (limited to 'server/src/inotify.cc') 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 +#include +#include +#include +#include +#include + +#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 + +#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*/ -- cgit v1.2.3