1 #include <sys/inotify.h>
2 #include <linux/limits.h>
3 #include <msp/core/algorithm.h>
4 #include <msp/core/systemerror.h>
5 #include <msp/io/handle_private.h>
6 #include "filemonitor.h"
7 #include "filemonitor_platform.h"
18 set_events(IO::P_INPUT);
26 int INotify::add_watch(const FS::Path &path, int ev)
28 int ret = inotify_add_watch(*fd, path.c_str(), ev);
30 throw system_error("inotify_add_watch");
34 void INotify::remove_watch(int wd)
36 int ret = inotify_rm_watch(*fd, wd);
38 throw system_error("inotify_rm_watch");
41 size_t INotify::do_write(const char *, size_t)
43 check_access(IO::M_WRITE);
47 size_t INotify::do_read(char *buf, size_t size)
49 return IO::sys_read(fd, buf, size);
53 void FileMonitor::platform_use_event_dispatcher()
55 event_disp->add(priv->inotify);
58 void FileMonitor::prepare_file(MonitoredFile &file)
60 file.tag = priv->inotify.add_watch(file.path, IN_MODIFY|IN_CLOSE_WRITE|IN_DELETE_SELF);
63 void FileMonitor::cleanup_file(MonitoredFile &file)
66 priv->inotify.remove_watch(file.tag);
69 void FileMonitor::tick()
74 if(!first && !IO::poll(priv->inotify, IO::P_INPUT, Time::zero))
78 priv->events_available();
82 void FileMonitor::tick(const Time::TimeDelta &timeout)
84 if(IO::poll(priv->inotify, IO::P_INPUT, timeout))
89 FileMonitor::Private::Private(FileMonitor &m):
92 inotify.signal_data_available.connect(sigc::mem_fun(this, &Private::events_available));
95 void FileMonitor::Private::events_available()
97 vector<FS::Path> changed_files;
98 char event_buf[sizeof(struct inotify_event)+NAME_MAX+1];
99 unsigned len = inotify.read(event_buf, sizeof(event_buf));
100 for(unsigned i=0; i<len; )
102 struct inotify_event *event = reinterpret_cast<struct inotify_event *>(event_buf+i);
103 auto j = find_member(monitor.files, event->wd, &MonitoredFile::tag);
104 if(j!=monitor.files.end())
106 if(event->mask&IN_MODIFY)
108 if(((event->mask&IN_CLOSE_WRITE) && j->modified) || (event->mask&IN_DELETE_SELF))
111 changed_files.push_back(j->path);
113 if(event->mask&IN_IGNORED)
116 i += sizeof(struct inotify_event)+event->len;
119 for(const FS::Path &p: changed_files)
120 monitor.signal_file_modified.emit(p);
122 for(auto j=monitor.files.begin(); j!=monitor.files.end(); )
125 monitor.files.erase(j++);