1 #include <sys/inotify.h>
2 #include <msp/core/systemerror.h>
3 #include <msp/io/handle_private.h>
4 #include "filemonitor.h"
5 #include "filemonitor_platform.h"
16 set_events(IO::P_INPUT);
24 int INotify::add_watch(const FS::Path &path, int ev)
26 int ret = inotify_add_watch(*fd, path.c_str(), ev);
28 throw system_error("inotify_add_watch");
32 void INotify::remove_watch(int wd)
34 int ret = inotify_rm_watch(*fd, wd);
36 throw system_error("inotify_rm_watch");
39 unsigned INotify::do_write(const char *, unsigned)
41 check_access(IO::M_WRITE);
45 unsigned INotify::do_read(char *buf, unsigned size)
47 return IO::sys_read(fd, buf, size);
51 void FileMonitor::platform_use_event_dispatcher()
53 event_disp->add(priv->inotify);
56 void FileMonitor::prepare_file(MonitoredFile &file)
58 file.tag = priv->inotify.add_watch(file.path, IN_MODIFY|IN_CLOSE_WRITE|IN_DELETE_SELF);
61 void FileMonitor::cleanup_file(MonitoredFile &file)
64 priv->inotify.remove_watch(file.tag);
67 void FileMonitor::tick()
72 if(!first && !IO::poll(priv->inotify, IO::P_INPUT, Time::zero))
76 priv->events_available();
80 void FileMonitor::tick(const Time::TimeDelta &timeout)
82 if(IO::poll(priv->inotify, IO::P_INPUT, timeout))
87 FileMonitor::Private::Private(FileMonitor &m):
90 inotify.signal_data_available.connect(sigc::mem_fun(this, &Private::events_available));
93 void FileMonitor::Private::events_available()
95 vector<FS::Path> changed_files;
96 char event_buf[sizeof(struct inotify_event)+NAME_MAX+1];
97 unsigned len = inotify.read(event_buf, sizeof(event_buf));
98 for(unsigned i=0; i<len; )
100 struct inotify_event *event = reinterpret_cast<struct inotify_event *>(event_buf+i);
101 for(vector<MonitoredFile>::iterator j=monitor.files.begin(); j!=monitor.files.end(); ++j)
102 if(j->tag==event->wd)
104 if(event->mask&IN_MODIFY)
106 if(((event->mask&IN_CLOSE_WRITE) && j->modified) || (event->mask&IN_DELETE_SELF))
109 changed_files.push_back(j->path);
111 if(event->mask&IN_IGNORED)
115 i += sizeof(struct inotify_event)+event->len;
118 for(vector<FS::Path>::const_iterator i=changed_files.begin(); i!=changed_files.end(); ++i)
119 monitor.signal_file_modified.emit(*i);
121 for(vector<MonitoredFile>::iterator j=monitor.files.begin(); j!=monitor.files.end(); )
124 monitor.files.erase(j++);