summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/src/inotify.cc152
-rw-r--r--server/src/inotify.h1
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();