From 62aeb9b9b26377967adba4915e744dd8d3104af7 Mon Sep 17 00:00:00 2001 From: deva Date: Thu, 7 Jan 2010 08:38:29 +0000 Subject: More work on inotify wrapper. Now the tests at least make sence. --- server/src/inotify.cc | 152 +++++++++++++++++++++++++++++++++----------------- server/src/inotify.h | 1 + 2 files changed, 102 insertions(+), 51 deletions(-) diff --git a/server/src/inotify.cc b/server/src/inotify.cc index f22e4ca..e1d47d1 100644 --- a/server/src/inotify.cc +++ b/server/src/inotify.cc @@ -36,23 +36,36 @@ #define TEST(x, m) ((x & m) == m) +#define STEST(x, m) (TEST(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."; + + str += STEST(mask, IN_ACCESS); + str += STEST(mask, IN_ATTRIB); + str += STEST(mask, IN_CLOSE_WRITE); + str += STEST(mask, IN_CLOSE_NOWRITE); + str += STEST(mask, IN_CREATE); + str += STEST(mask, IN_DELETE); + str += STEST(mask, IN_DELETE_SELF); + str += STEST(mask, IN_MODIFY); + str += STEST(mask, IN_MOVE_SELF); + str += STEST(mask, IN_MOVED_FROM); + str += STEST(mask, IN_MOVED_TO); + str += STEST(mask, IN_OPEN); + str += STEST(mask, IN_ALL_EVENTS); + str += STEST(mask, IN_CLOSE); + str += STEST(mask, IN_MOVE); + str += STEST(mask, IN_DONT_FOLLOW); + str += STEST(mask, IN_MASK_ADD); + str += STEST(mask, IN_ONESHOT); + str += STEST(mask, IN_ONLYDIR); + str += STEST(mask, IN_IGNORED); + str += STEST(mask, IN_ISDIR); + str += STEST(mask, IN_Q_OVERFLOW); + str += STEST(mask, IN_UNMOUNT); + return str; } @@ -67,6 +80,12 @@ INotify::Event::Event(std::string name, uint32_t mask) { this->_name = name; this->_mask = mask; + + printf("[%s]\n", mask2asc(_mask).c_str()); +} +bool INotify::Event::isAttributeChangeEvent() +{ + return TEST(_mask, IN_ATTRIB); } bool INotify::Event::isCloseEvent() @@ -115,6 +134,17 @@ INotify::~INotify() void INotify::add(std::string name, uint32_t mask) { + // Extra mask bitflags: + //IN_DONT_FOLLOW (since Linux 2.6.15) + // Don't dereference pathname if it is a symbolic link. + //IN_MASK_ADD + // Add (OR) events to watch mask for this pathname if it already + // exists (instead of replacing mask). + //IN_ONESHOT + // Monitor pathname for one event, then remove from watch list. + //IN_ONLYDIR (since Linux 2.6.15) + // Only watch pathname if it is a directory. + int _fd = inotify_add_watch(fd, name.c_str(), mask); if(_fd == -1) { perror("INotify: Add watch failed!"); @@ -131,49 +161,61 @@ void INotify::addRecursive(std::string name, uint32_t mask) */ } -void INotify::readEvents() +bool INotify::hasEvents() { - 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; + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + fd_set fset; + int ret; + FD_ZERO(&fset); + FD_SET(fd, &fset); + ret = select (fd+1, &fset, NULL, NULL, &tv); + switch(ret) { + case -1: + if(errno == EINTR) { + // Interrupt } - */ - /* - // Remove watch on deleted subfolder. - if(TEST(event->mask, IN_DELETE) && isdir(event->name)) { - inotify_add_watch(watch, event->name, IN_ALL_EVENTS); + break; + + case 0: + // Timeout + break; + + default: + if(FD_ISSET(fd, &fset)) { + // Ready read + return true; } - */ } -} -bool INotify::hasEvents() -{ - readEvents(); - return eventlist.size() > 0; + return false; } INotify::Event INotify::getNextEvent() { - readEvents(); - if(eventlist.size()) { - Event event = eventlist.front(); - eventlist.pop_front(); - return event; + char buf[1024]; + ssize_t r = read(fd, buf, sizeof(struct inotify_event)); + if(r == sizeof(struct inotify_event)) { + struct inotify_event *event = (struct inotify_event *)buf; + if(event->len) read(fd, buf + sizeof(struct inotify_event), event->len); + switch(event->mask) { + case IN_IGNORED: + //Watch was removed explicitly (inotify_rm_watch(2)) or automatically + // (file was deleted, or file system was unmounted). + case IN_ISDIR: + //Subject of this event is a directory. + case IN_Q_OVERFLOW: + //Event queue overflowed (wd is -1 for this event). + case IN_UNMOUNT: + //File system containing watched object was unmounted. + break; + default: + break; + } + + return Event(event->name, event->mask); } return Event("", 0); } @@ -230,11 +272,16 @@ TEST_TRUE(inotify.getNextEvent().isCloseEvent(), "Test if the event was a close // Overwrite file fp = fopen(_FILE, "w"); TEST_NOTEQUAL(fp, NULL, "Testing if able to write file"); + +// Open for write initially empties the file content, thus provoking a changed event. +TEST_TRUE(inotify.hasEvents(), "Test if the modified event was triggered."); +TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "Test if the event was a modified event."); + 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.hasEvents(), "Test if the write event was triggered."); TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "Test if the event was a modified event."); fclose(fp); @@ -245,10 +292,13 @@ TEST_TRUE(inotify.getNextEvent().isCloseEvent(), "Test if the event was a close // Delete file unlink(_FILE); +// Unlink initially counts down the link counter, which provokes an attributes changed event. 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."); +TEST_EQUAL(inotify.getNextEvent().isAttributeChangeEvent(), true, "Test if the event was an attribute change event."); -mask2asc(0); +// Since the linkcount should now be zero, the file should be deleted. +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."); TEST_END; diff --git a/server/src/inotify.h b/server/src/inotify.h index f6126ed..a2503b3 100644 --- a/server/src/inotify.h +++ b/server/src/inotify.h @@ -41,6 +41,7 @@ public: public: Event(std::string name, uint32_t mask); + bool isAttributeChangeEvent(); bool isOpenEvent(); bool isCloseEvent(); bool isModifyEvent(); -- cgit v1.2.3