From 482cd4be0bb29fba070473fa1a00580e06635ae4 Mon Sep 17 00:00:00 2001 From: skilion Date: Thu, 10 Sep 2015 23:05:15 +0200 Subject: [PATCH] wp on monitor --- src/monitor.d | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 src/monitor.d diff --git a/src/monitor.d b/src/monitor.d new file mode 100644 index 00000000..df5ad49f --- /dev/null +++ b/src/monitor.d @@ -0,0 +1,148 @@ +import core.stdc.errno: errno; +import core.stdc.string: strerror; +import core.sys.linux.sys.inotify; +import core.sys.posix.poll; +import core.sys.posix.unistd; +import std.file, std.stdio, std.string; + +// relevant inotify events +private immutable uint32_t mask = IN_ATTRIB | IN_CLOSE_WRITE | IN_CREATE | + IN_DELETE | IN_MOVE_SELF | IN_MOVE | IN_IGNORED | IN_Q_OVERFLOW; + +class MonitorException: Exception +{ + this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) + { + super(makeErrorMsg(msg), file, line, next); + } + + this(string msg, Throwable next, string file = __FILE__, size_t line = __LINE__) + { + super(makeErrorMsg(msg), file, line, next); + } + + private string makeErrorMsg(string msg) + { + return msg ~ " :" ~ fromStringz(strerror(errno())).idup; + } +} + +struct Monitor +{ + // inotify file descriptor + private int fd; + // map every watch descriptor to their dir + private string[int] dirs; + // map the inotify cookies of move_from events to their path + private string[int] moveFromPaths; + // buffer to receive the inotify events + private void[] buffer; + + void function(string path) onDirCreated; + void function(string path) onDirDeleted; + void function(string path) onFileChanged; + void function(string path) onFileDeleted; + + @disable this(this); + + void init() + { + fd = inotify_init(); + if (fd == -1) throw new MonitorException("inotify_init failed"); + buffer = new void[10000]; + } + + void shutdown() + { + if (fd > 0) close(fd); + } + + void add(string path) + { + int wd = inotify_add_watch(fd, toStringz(path), mask); + if (wd == -1) throw new MonitorException("inotify_add_watch failed"); + dirs[wd] = path ~ "/"; + writeln("Monitor directory: ", path); + } + + void addRecursive(string path) + { + add(path); + foreach(DirEntry entry; dirEntries(path, SpanMode.breadth, false)) { + if (entry.isDir) add(entry.name); + } + } + + // remove a watch descriptor + private void remove(int wd) + { + assert(wd in dirs); + int ret = inotify_rm_watch(fd, wd); + if (ret == -1) throw new MonitorException("inotify_rm_watch failed"); + writeln("Monitored directory removed: ", dirs[wd]); + dirs.remove(wd); + } + + // return the file path from an inotify event + private string getPath(const(inotify_event)* event) + { + string path = dirs[event.wd]; + if (event.len > 0) path ~= fromStringz(event.name.ptr); + return path; + } + + void update() + { + pollfd[1] fds; + fds[0].fd = fd; + fds[0].events = POLLIN; + int ret = poll(fds.ptr, 1, 15); + if (ret == -1) throw new MonitorException("poll failed"); + else if (ret == 0) return; // no events available + + assert(fds[0].revents & POLLIN); + size_t length = read(fds[0].fd, buffer.ptr, buffer.length); + if (length == -1) throw new MonitorException("read failed"); + + int i = 0; + while ( i < length ) { + inotify_event *event = cast(inotify_event*) &buffer[i]; + if (event.mask & IN_IGNORED) { + writeln(dirs); + writeln("ignored ", event.wd); + // forget the path associated to the watch descriptor + dirs.remove(event.wd); + } else if (event.mask & IN_Q_OVERFLOW) { + writeln("Inotify overflow, events missing"); + } else if (event.mask & IN_MOVED_FROM) { + string path = getPath(event); + moveFromPaths[event.cookie] = path; + writeln("moved from ", path); + } else if (event.mask & IN_MOVED_TO) { + string path = getPath(event); + writeln("moved to ", path); + if (event.mask & IN_ISDIR) addRecursive(path); + } else { + if (event.mask & IN_ISDIR) { + if (event.mask & IN_CREATE) { + string path = getPath(event); + writeln("Directory created: ", path); + add(path); + } else if (event.mask & IN_DELETE) { + string path = getPath(event); + writeln("Directory deleted: ", path); + } + } else { + if (event.mask & IN_ATTRIB || event.mask & IN_CLOSE_WRITE) { + string path = getPath(event); + writeln("File changed: ", path); + } else if (event.mask & IN_DELETE) { + string path = getPath(event); + writeln("File deleted: ", path); + } + } + } + i += inotify_event.sizeof + event.len; + } + } +}