diff options
author | deva <deva> | 2010-01-14 10:59:24 +0000 |
---|---|---|
committer | deva <deva> | 2010-01-14 10:59:24 +0000 |
commit | d34d398bc624521d969efab8eb1150c4a6cdeef0 (patch) | |
tree | 9e2e3bf86a1e020a0b82c24b23c4fe92eedb19e9 | |
parent | 86a2a3b7450913dc5d5c4f55254aee5239f290b0 (diff) |
Almost finished the inotify wrapper. It still needs more tests. Made MacroList work recursive, added watch through inotify (also recursive).
-rw-r--r-- | server/src/Makefile.am | 1 | ||||
-rw-r--r-- | server/src/inotify.cc | 372 | ||||
-rw-r--r-- | server/src/inotify.h | 40 | ||||
-rw-r--r-- | server/src/macrolist.cc | 116 | ||||
-rw-r--r-- | server/src/macrolist.h | 8 |
5 files changed, 465 insertions, 72 deletions
diff --git a/server/src/Makefile.am b/server/src/Makefile.am index 8d6e347..efe1413 100644 --- a/server/src/Makefile.am +++ b/server/src/Makefile.am @@ -59,6 +59,7 @@ macrotool_SOURCES = \ configurationparser.cc \ database.cc \ exception.cc \ + inotify.cc \ log.cc \ macroheaderparser.cc \ macrolist.cc \ diff --git a/server/src/inotify.cc b/server/src/inotify.cc index e1d47d1..7834327 100644 --- a/server/src/inotify.cc +++ b/server/src/inotify.cc @@ -27,15 +27,21 @@ */ #include "inotify.h" +#include "debug.h" + #include <sys/stat.h> #include <errno.h> #include <stdio.h> #include <unistd.h> #include <sys/socket.h> #include <fcntl.h> +#include <stdlib.h> +#include <dirent.h> +#include <string.h> #define TEST(x, m) ((x & m) == m) +#ifdef WITH_DEBUG #define STEST(x, m) (TEST(x, m)?#m" ":"") static std::string mask2asc(uint32_t mask) @@ -54,13 +60,16 @@ static std::string mask2asc(uint32_t mask) 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); @@ -68,6 +77,7 @@ static std::string mask2asc(uint32_t mask) return str; } +#endif static inline bool isdir(const char *name) { @@ -76,13 +86,23 @@ static inline bool isdir(const char *name) return S_ISDIR(s.st_mode); } -INotify::Event::Event(std::string name, uint32_t mask) +INotify::Event::Event(struct inotify_event *event, std::string name) { this->_name = name; - this->_mask = mask; + if(event) { + this->_mask = event->mask; + this->_file = event->name; + } else { + this->_mask = 0; + this->_file = ""; + } - printf("[%s]\n", mask2asc(_mask).c_str()); + PRACRO_DEBUG(inotify, "Event [%s] %s (%s)\n", + mask2asc(_mask).c_str(), + _name.c_str(), + _file.c_str()); } + bool INotify::Event::isAttributeChangeEvent() { return TEST(_mask, IN_ATTRIB); @@ -90,12 +110,27 @@ bool INotify::Event::isAttributeChangeEvent() bool INotify::Event::isCloseEvent() { - return TEST(_mask, IN_CLOSE_WRITE) || TEST(_mask, IN_CLOSE_NOWRITE); + return isCloseWriteEvent() || isCloseNoWriteEvent(); +} + +bool INotify::Event::isCloseWriteEvent() +{ + return TEST(_mask, IN_CLOSE_WRITE); +} + +bool INotify::Event::isCloseNoWriteEvent() +{ + return TEST(_mask, IN_CLOSE_NOWRITE); +} + +bool INotify::Event::isCreateEvent() +{ + return TEST(_mask, IN_CREATE); } bool INotify::Event::isOpenEvent() { - return TEST(_mask, IN_OPEN) || TEST(_mask, IN_CREATE); + return TEST(_mask, IN_OPEN); } bool INotify::Event::isModifyEvent() @@ -103,9 +138,39 @@ bool INotify::Event::isModifyEvent() return TEST(_mask, IN_MODIFY); } +bool INotify::Event::isAccessEvent() +{ + return TEST(_mask, IN_ACCESS); +} + bool INotify::Event::isDeleteEvent() { - return TEST(_mask, IN_DELETE) || TEST(_mask, IN_DELETE_SELF); + return TEST(_mask, IN_DELETE); +} + +bool INotify::Event::isDeleteSelfEvent() +{ + return TEST(_mask, IN_DELETE_SELF); +} + +bool INotify::Event::isIgnoredEvent() +{ + return TEST(_mask, IN_IGNORED); +} + +bool INotify::Event::isMoveSelfEvent() +{ + return TEST(_mask, IN_MOVE_SELF); +} + +bool INotify::Event::isMovedFromEvent() +{ + return TEST(_mask, IN_MOVED_FROM); +} + +bool INotify::Event::isMovedToEvent() +{ + return TEST(_mask, IN_MOVED_TO); } std::string INotify::Event::name() @@ -113,6 +178,11 @@ std::string INotify::Event::name() return _name; } +std::string INotify::Event::file() +{ + return _file; +} + uint32_t INotify::Event::mask() { return _mask; @@ -120,8 +190,8 @@ uint32_t INotify::Event::mask() INotify::INotify() { - fd = inotify_init1(O_NONBLOCK); - if(fd == -1) { + ifd = inotify_init1(O_NONBLOCK); + if(ifd == -1) { perror("Inotify init failed.\n"); return; } @@ -129,10 +199,10 @@ INotify::INotify() INotify::~INotify() { - if(fd != -1) close(fd); + if(ifd != -1) close(ifd); } -void INotify::add(std::string name, uint32_t mask) +void INotify::addFile(std::string name, uint32_t mask) { // Extra mask bitflags: //IN_DONT_FOLLOW (since Linux 2.6.15) @@ -145,24 +215,132 @@ void INotify::add(std::string name, uint32_t mask) //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) { + int wd = inotify_add_watch(ifd, name.c_str(), mask); + if(wd == -1) { perror("INotify: Add watch failed!"); return; } - // dirmap[fd] = name; + + Watch w; + w.mask = mask; + w.name = name; + w.depth = WATCH_SINGLE; + dirmap[wd] = w; } -void INotify::addRecursive(std::string name, uint32_t mask) +static inline bool isdir(std::string name) { - /* - int fd = this->add(name, mask); - return fd; - */ + struct stat s; + stat(name.c_str(), &s); + return S_ISDIR(s.st_mode); +} + +void INotify::addDirectory(std::string name, depth_t depth, uint32_t mask) +{ + PRACRO_DEBUG(inotify, "Adding dir: %s\n", name.c_str()); + + int depth_mask = 0; + if(depth == WATCH_DEEP || depth == WATCH_DEEP_FOLLOW) { + depth_mask = IN_CREATE; // We need to watch for create in order to catch + // creation of new subdirs. + + DIR *dir = opendir(name.c_str()); + if(!dir) { + PRACRO_ERR(inotify, "Could not open directory: %s - %s\n", + name.c_str(), strerror(errno)); + return; + } + + struct dirent *dirent; + while( (dirent = readdir(dir)) != NULL ) { + + if(std::string(dirent->d_name) == "." || std::string(dirent->d_name) == "..") + continue; + + PRACRO_DEBUG(inotify, "Add entry?: %s\n", dirent->d_name); + + if(isdir(name+"/"+dirent->d_name)) addDirectory(name+"/"+dirent->d_name, depth, mask); + } + + closedir(dir); + } + + int wd = inotify_add_watch(ifd, name.c_str(), mask | IN_ONLYDIR | depth_mask); + if(wd == -1) { + perror("INotify: Add watch failed!"); + return; + } + + Watch w; + w.mask = mask; + w.name = name; + w.depth = depth; + dirmap[wd] = w; +} + +void INotify::remove(int wd) +{ + if(inotify_rm_watch(ifd, wd) == -1) { + perror("inotify_rm_watch failed"); + return; + } + dirmap.erase(wd); +} + +void INotify::remove(std::string name) +{ + std::map<int, Watch>::iterator i = dirmap.begin(); + while(i != dirmap.end()) { + Watch w = i->second; + if(w.name == name) this->remove(i->first); + i++; + } +} + +void INotify::readEvents() +{ + size_t size = 64; + char *buf = (char*)malloc(size); + + ssize_t r; + while( ((r = read(ifd, buf, size)) == -1 && errno == EINVAL) || r == 0 ) { + fprintf(stderr, "Doubling buffer size: %d\n", size); + size *= 2; + buf = (char*)realloc(buf, size); + } + + int p = 0; + while(p < r) { + struct inotify_event *event = (struct inotify_event*)(buf + p); + p += sizeof(struct inotify_event) + event->len; + + // TODO: We need to figure out what the new filename/destination is... + if(TEST(event->mask, IN_MOVE_SELF)) dirmap[event->wd].name = "????????"; + + if(dirmap[event->wd].depth == WATCH_DEEP_FOLLOW && + TEST(event->mask, IN_CREATE) && + TEST(event->mask, IN_ISDIR)) + addDirectory(dirmap[event->wd].name + "/" + event->name, + dirmap[event->wd].depth, dirmap[event->wd].mask); + + if(TEST(event->mask, IN_CREATE) && !TEST(dirmap[event->wd].mask, IN_CREATE)) { + // Ignore this event, it was not requested by the user. + } else { + eventlist.push_back(INotify::Event(event, dirmap[event->wd].name)); + } + + if(TEST(event->mask, IN_IGNORED)) dirmap.erase(event->wd); + } + + free(buf); } bool INotify::hasEvents() { + readEvents(); + return eventlist.size() > 0; + +#if 0 struct timeval tv; tv.tv_sec = 0; tv.tv_usec = 0; @@ -170,8 +348,8 @@ bool INotify::hasEvents() fd_set fset; int ret; FD_ZERO(&fset); - FD_SET(fd, &fset); - ret = select (fd+1, &fset, NULL, NULL, &tv); + FD_SET(ifd, &fset); + ret = select (ifd+1, &fset, NULL, NULL, &tv); switch(ret) { case -1: if(errno == EINTR) { @@ -184,23 +362,36 @@ bool INotify::hasEvents() break; default: - if(FD_ISSET(fd, &fset)) { + if(FD_ISSET(ifd, &fset)) { // Ready read return true; } } return false; +#endif } INotify::Event INotify::getNextEvent() { - char buf[1024]; - ssize_t r = read(fd, buf, sizeof(struct inotify_event)); + readEvents(); + if(eventlist.size() == 0) return Event(NULL, ""); + Event e = eventlist.front(); + eventlist.pop_front(); + return e; + +#if 0 + struct inotify_event event; + ssize_t r = read(ifd, &event, sizeof(struct inotify_event)); + if(r != sizeof(struct inotify_event) && r != -1) 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) { + char *name = NULL; + if(event.len) { + name = (char*)malloc(event.len); + if(read(ifd, name, event.len) != (int)event.len) printf("\n\nFUXK!\n\n"); + } + + switch(event.mask) { case IN_IGNORED: //Watch was removed explicitly (inotify_rm_watch(2)) or automatically // (file was deleted, or file system was unmounted). @@ -215,19 +406,13 @@ INotify::Event INotify::getNextEvent() break; } - return Event(event->name, event->mask); + if(TEST(event.mask, IN_IGNORED)) dirmap.erase(event.wd); + Event e((name!=NULL)?name:"", event.mask); + if(name) free(name); + return e; } 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)) +#endif } #ifdef TEST_INOTIFY @@ -238,25 +423,45 @@ void INotify::remove(std::string name) #include <stdio.h> -#define _DIR "/tmp" -#define _FILE _DIR"/inotify_test" +#define _BASEDIR "/tmp" +#define _DIR _BASEDIR"/inotify_test_dir" +#define _FILE _BASEDIR"/inotify_test" TEST_BEGIN; +pracro_debug_parse("+all"); + INotify inotify; // Create file FILE *fp = fopen(_FILE, "w"); -TEST_NOTEQUAL(fp, NULL, "Testing if able to write file"); +if(!fp) TEST_FATAL("Unable to write to the file"); fprintf(fp, "something"); fclose(fp); -inotify.add(_FILE); +inotify.addFile(_FILE); + +TEST_MSG("Positive tests on file watch."); + +// Append to file +fp = fopen(_FILE, "r"); +if(!fp) TEST_FATAL("Unable to read from the 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."); + +char buf[32]; +fread(buf, sizeof(buf), 1, fp); +TEST_TRUE(inotify.hasEvents(), "Test if the read event was triggered."); +TEST_TRUE(inotify.getNextEvent().isAccessEvent(), "Test if the event was a access event."); + +fclose(fp); +TEST_TRUE(inotify.hasEvents(), "Test if the close event was triggered."); +TEST_TRUE(inotify.getNextEvent().isCloseNoWriteEvent(), "Test if the event was a close-nowrite event."); // Append to file fp = fopen(_FILE, "a"); -TEST_NOTEQUAL(fp, NULL, "Testing if able to write file"); +if(!fp) TEST_FATAL("Unable to write to the 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."); @@ -266,12 +471,12 @@ TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "Test if the event was a modif 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."); +TEST_TRUE(inotify.getNextEvent().isCloseWriteEvent(), "Test if the event was a close event."); // Overwrite file fp = fopen(_FILE, "w"); -TEST_NOTEQUAL(fp, NULL, "Testing if able to write file"); +if(!fp) TEST_FATAL("Unable to write to the 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."); @@ -286,19 +491,86 @@ TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "Test if the event was a modif 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."); +TEST_TRUE(inotify.getNextEvent().isCloseWriteEvent(), "Test if the event was a close event."); +// Rename file +rename(_FILE, _FILE"2"); +TEST_TRUE(inotify.hasEvents(), "Test if the rename event was triggered."); +TEST_TRUE(inotify.getNextEvent().isMoveSelfEvent(), "Test if the event was a move self event."); // Delete file -unlink(_FILE); +unlink(_FILE"2"); // 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().isAttributeChangeEvent(), true, "Test if the event was an attribute change event."); +TEST_TRUE(inotify.hasEvents(), "Test if the delete event was triggered."); +TEST_TRUE(inotify.getNextEvent().isAttributeChangeEvent(), "Test if the event was an attribute change event."); // 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_TRUE(inotify.hasEvents(), "Test if the delete event was triggered."); +TEST_TRUE(inotify.getNextEvent().isDeleteSelfEvent(), "Test if the event was a delete self event."); + +// Watch is removed upon delete. +//inotify.remove(_FILE); + +TEST_TRUE(inotify.hasEvents(), "Test if the delete event triggered an ignored event."); +TEST_TRUE(inotify.getNextEvent().isIgnoredEvent(), "Test if the event was an ignored event."); + +// Create file again +fp = fopen(_FILE, "w"); +if(!fp) TEST_FATAL("Unable to write to the file"); +fprintf(fp, "something"); +fclose(fp); + +inotify.addFile(_FILE); +inotify.remove(_FILE); + +TEST_TRUE(inotify.hasEvents(), "Test if the call to remove triggered an ignored event."); +TEST_TRUE(inotify.getNextEvent().isIgnoredEvent(), "Test if the event was an ignored event."); + +// Delete file +unlink(_FILE); +inotify.getNextEvent(); +TEST_FALSE(inotify.hasEvents(), "Test if the delete event was ignored."); + +TEST_FALSE(inotify.hasEvents(), "Test if the event queue is now empty."); + +TEST_MSG("Positive tests on directory watch."); + +if(mkdir(_DIR, 0777) == -1) TEST_FATAL("Could not create test dir."); +inotify.addDirectory(_DIR, WATCH_DEEP_FOLLOW); + +// Create file again +fp = fopen(_DIR"/file1", "w"); +if(!fp) TEST_FATAL("Unable to write to the file"); +fprintf(fp, "something"); +fclose(fp); + +TEST_TRUE(inotify.hasEvents(), "Test if the file creation triggered events."); +TEST_TRUE(inotify.getNextEvent().isCreateEvent(), "..."); +TEST_TRUE(inotify.getNextEvent().isOpenEvent(), "..."); +TEST_TRUE(inotify.getNextEvent().isModifyEvent(), "..."); +TEST_TRUE(inotify.getNextEvent().isCloseWriteEvent(), "..."); + +rename(_DIR"/file1", _DIR"/file2"); +TEST_TRUE(inotify.hasEvents(), "Test if the file renaming triggered events."); +TEST_TRUE(inotify.getNextEvent().isMovedFromEvent(), "..."); +TEST_TRUE(inotify.getNextEvent().isMovedToEvent(), "..."); + +unlink(_DIR"/file2"); + +if(mkdir(_DIR"/dir", 0777) == -1) TEST_FATAL("Could not create test dir."); + +if(mkdir(_DIR"/dir/anotherdir", 0777) == -1) TEST_FATAL("Could not create test dir."); + +while(inotify.hasEvents()) inotify.getNextEvent(); + +rmdir(_DIR"/dir/anotherdir"); + +rmdir(_DIR"/dir"); + +rmdir(_DIR); + +while(inotify.hasEvents()) inotify.getNextEvent(); TEST_END; diff --git a/server/src/inotify.h b/server/src/inotify.h index a2503b3..5199055 100644 --- a/server/src/inotify.h +++ b/server/src/inotify.h @@ -35,42 +35,70 @@ #include <map> #include <list> +typedef enum { + WATCH_SINGLE, // Watch only the specified directory. + WATCH_DEEP, // Watch all current subdirs as well + WATCH_DEEP_FOLLOW // Watch all current subdir as well as subdirs + // being created after the watch is initiated +} depth_t; + + class INotify { public: class Event { public: - Event(std::string name, uint32_t mask); + Event(struct inotify_event *event, std::string name); bool isAttributeChangeEvent(); + bool isCreateEvent(); bool isOpenEvent(); bool isCloseEvent(); + bool isCloseWriteEvent(); + bool isCloseNoWriteEvent(); bool isModifyEvent(); + bool isAccessEvent(); bool isDeleteEvent(); + bool isDeleteSelfEvent(); + bool isIgnoredEvent(); + bool isMoveSelfEvent(); + bool isMovedFromEvent(); + bool isMovedToEvent(); std::string name(); + std::string file(); uint32_t mask(); private: std::string _name; + std::string _file; uint32_t _mask; }; INotify(); ~INotify(); - void add(std::string name, uint32_t mask = IN_ALL_EVENTS); + void addFile(std::string name, uint32_t mask = IN_ALL_EVENTS); + void addDirectory(std::string name, + depth_t depth = WATCH_SINGLE, + uint32_t mask = IN_ALL_EVENTS); void remove(std::string name); void remove(int fd); - void addRecursive(std::string name, uint32_t mask = IN_ALL_EVENTS); - bool hasEvents(); Event getNextEvent(); private: + class Watch { + public: + std::string name; + uint32_t mask; + depth_t depth; + }; + void readEvents(); - int fd; - std::map<int, std::string> dirmap; + + int ifd; + std::map<int, Watch> dirmap; std::list<Event> eventlist; }; diff --git a/server/src/macrolist.cc b/server/src/macrolist.cc index 0d0916d..89abfe8 100644 --- a/server/src/macrolist.cc +++ b/server/src/macrolist.cc @@ -33,6 +33,24 @@ #include "debug.h" #include "macroheaderparser.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +static inline bool isdir(std::string name) +{ + struct stat s; + stat(name.c_str(), &s); + return S_ISDIR(s.st_mode); +} + +static inline bool isfile(std::string name) +{ + struct stat s; + stat(name.c_str(), &s); + return S_ISREG(s.st_mode); +} + static std::vector<std::string> listdir(std::string path) { std::vector<std::string> files; @@ -45,11 +63,21 @@ static std::vector<std::string> listdir(std::string path) struct dirent *d; while((d = readdir(dir)) != 0) { - //if(d->d_type == DT_DIR) { - std::string name = d->d_name; - if(name.length() >= 4 && name.substr(name.length() - 4) == ".xml") - files.push_back(name); - //} + if(std::string(d->d_name) == "." || std::string(d->d_name) == "..") continue; + + PRACRO_DEBUG(macrolist, "d_name: %s - d_type: %d\n", d->d_name, d->d_type); + + if(isdir(path + "/" + d->d_name)) { + std::vector<std::string> sub = listdir(path + "/" + d->d_name); + files.insert(files.end(), sub.begin(), sub.end()); + continue; + } + + if(isfile(path + "/" + d->d_name)) { + std::string name = d->d_name; + if(name.length() >= 4 && name.substr(name.length() - 4) == ".xml") + files.push_back(path + "/" + name); + } } closedir(dir); @@ -60,18 +88,16 @@ MacroList::MacroList(std::string macropath) { MutexAutolock lock(mutex); + inotify.addDirectory(macropath, WATCH_DEEP_FOLLOW, + IN_CLOSE_WRITE | + IN_MOVED_FROM | IN_MOVED_TO | IN_MOVE_SELF | + IN_DELETE | IN_DELETE_SELF); + this->macropath = macropath; std::vector<std::string> macros = listdir(macropath); std::vector<std::string>::iterator i = macros.begin(); while(i != macros.end()) { - MacroHeaderParser parser(macropath + "/" + *i); - try { - parser.parse(); - Macro *macro = parser.getMacro(); - (*this)[macro->attributes["name"]][VersionStr(macro->attributes["version"])] = *i; - } catch(Exception &e) { - PRACRO_WARN(macrolist, "Skipping %s: %s\n", i->c_str(), e.what()); - } + addFile(*i); i++; } @@ -91,19 +117,77 @@ MacroList::MacroList(std::string macropath) } } +bool MacroList::removeFile(std::string file) +{ + // Check if the file is already in the tree. + iterator i = begin(); + while(i != end()) { + MacroListItem::iterator j = i->second.begin(); + while(j != i->second.end()) { + if(file == j->second) { + PRACRO_DEBUG(macrolist, "Removing file: %s\n", file.c_str()); + i->second.erase(j->first); + /* + if(i->second.size() == 0) erase(i->first); + */ + return true; + } + j++; + } + i++; + } + + return false; +} + +void MacroList::addFile(std::string file) +{ + PRACRO_DEBUG(macrolist, "Adding file: %s\n", file.c_str()); + MacroHeaderParser parser(file); + try { + parser.parse(); + Macro *macro = parser.getMacro(); + (*this)[macro->attributes["name"]][VersionStr(macro->attributes["version"])] = file; + } catch(Exception &e) { + PRACRO_WARN(macrolist, "Skipping %s: %s\n", file.c_str(), e.what()); + } +} + +void MacroList::updateFile(std::string file) +{ + removeFile(file); + addFile(file); +} + +void MacroList::updateList() +{ + while(inotify.hasEvents()) { + INotify::Event event = inotify.getNextEvent(); + if(event.isCloseWriteEvent()) updateFile(event.name()+"/"+event.file()); + if(event.isMovedFromEvent()) removeFile(event.name()+"/"+event.file()); + if(event.isMovedToEvent()) updateFile(event.name()+"/"+event.file()); + if(event.isDeleteEvent()) removeFile(event.name()+"/"+event.file()); + + if(event.isMoveSelfEvent()) {/* TODO: what to do here? */} + if(event.isDeleteSelfEvent()) {/* TODO: what to do here? */} + } +} + std::string MacroList::getLatestVersion(std::string macro) throw(Exception) { MutexAutolock lock(mutex); + updateList(); + if(find(macro) == end()) throw Exception("Macro ["+macro+"] does not exist"); MacroListItem mli = (*this)[macro]; - if(mli.size() == 0) return ""; + if(mli.size() == 0) throw Exception("Macro ["+macro+"] does not exist"); PRACRO_DEBUG(macrolist, "Search for %s - found %s v%s\n", macro.c_str(), - (macropath + "/" + mli.begin()->second).c_str(), + mli.begin()->second.c_str(), ((std::string)mli.begin()->first).c_str()); - return macropath + "/" + mli.begin()->second; + return mli.begin()->second; } #ifdef TEST_MACROLIST diff --git a/server/src/macrolist.h b/server/src/macrolist.h index 6460f8b..4c73ded 100644 --- a/server/src/macrolist.h +++ b/server/src/macrolist.h @@ -33,6 +33,8 @@ #include "versionstr.h" #include "mutex.h" +#include "inotify.h" + #include "exception.h" /** @@ -67,7 +69,13 @@ public: std::string getLatestVersion(std::string macro) throw(Exception); private: + bool removeFile(std::string file); + void addFile(std::string file); + void updateFile(std::string file); + void updateList(); + Mutex mutex; + INotify inotify; std::string macropath; }; |