1 #include "main.h"
2
3 /* don't compile if the option is not set */
4 #ifdef USE_INOTIFY
5
6 #include "Inotify.h"
7
8 #include <sys/inotify.h>
9
10 #include <errno.h>
11 #include <sys/select.h>
12
13 #define MAXLEN 16384
14
15 namespace Inotify {
16
17 std::map< int, Watch* > Watch::watch_descriptors;
18 int Watch::inotify_fd = -1;
19
create(std::string path)20 Watch * Watch::create(std::string path) {
21 // check inotify_fd; set it if it is currently unset
22 if (inotify_fd == -1) {
23 inotify_fd = inotify_init();
24 if (inotify_fd == -1) {
25 // an error occurred.
26 switch(errno) { // oh dear god.
27 case EMFILE:
28 break;
29 case ENFILE:
30 break;
31 case ENOMEM:
32 break;
33 }
34 return 0;
35 }
36 }
37 Watch * retval = new Watch(path);
38 int watch_descriptor = -1;
39 if ((watch_descriptor = inotify_add_watch(inotify_fd, path.c_str(),
40 IN_ALL_EVENTS)) == -1) {
41 return 0;
42 }
43 watch_descriptors[watch_descriptor] = retval;
44 retval->watch_descriptor = watch_descriptor;
45
46 retval->signal_deleted_self.connect(sigc::mem_fun(retval, &Watch::remove_wrap));
47
48 return retval;
49 }
50
poll(suseconds_t timeout)51 void Watch::poll(suseconds_t timeout) {
52 if (inotify_fd == -1) return;
53 // initialize the fd set for select()
54 fd_set set;
55 FD_ZERO(&set);
56 FD_SET(inotify_fd, &set);
57
58 // initialize the timeout
59 struct timeval timeval;
60 timeval.tv_sec = 0;
61 timeval.tv_usec = timeout;
62
63 int select_return = -1;
64
65 select_return = select(inotify_fd + 1, &set, NULL, NULL, &timeval);
66 if (select_return <= 0) return;
67 // something interesting happened.
68
69 char buffer[MAXLEN];
70 ssize_t size = 0;
71 size = read(inotify_fd, buffer, MAXLEN);
72 if (size <= 0) return;
73
74 // process events
75 ssize_t i = 0;
76 while(i < size) {
77 uint32_t wd = *((uint32_t*)&buffer[i]);
78 i += sizeof(uint32_t);
79 uint32_t mask = *((uint32_t*)&buffer[i]);
80 i += sizeof(uint32_t);
81 //uint32_t cookie = buffer[i];
82 i += sizeof(uint32_t);
83 uint32_t len = *((uint32_t*)&buffer[i]);
84 i += sizeof(uint32_t);
85 std::string name(&buffer[i], len);
86 i += len;
87
88 if (watch_descriptors.find(wd) == watch_descriptors.end()) continue;
89
90 Watch * watch = watch_descriptors[wd];
91
92 std::string path;
93 if (name.length() == 0) {
94 name = watch->path;
95 } else {
96 name = watch->path + "/" + name;
97 }
98
99 // you have absolutely no idea how much of a pita it was writing this
100 // out.
101 if (mask & IN_ACCESS) {
102 watch->signal_accessed.emit(name);
103 }
104 if (mask & IN_ATTRIB) {
105 watch->signal_metadata_changed.emit(name);
106 }
107 if (mask & IN_CLOSE_WRITE) {
108 watch->signal_write_closed.emit(name);
109 }
110 if (mask & IN_CLOSE_NOWRITE) {
111 watch->signal_nowrite_closed.emit(name);
112 }
113 if (mask & IN_CREATE) {
114 watch->signal_created.emit(name);
115 }
116 if (mask & IN_DELETE) {
117 watch->signal_deleted.emit(name);
118 }
119 if (mask & IN_DELETE_SELF) {
120 watch->signal_deleted_self.emit(name);
121 }
122 if (mask & IN_MODIFY) {
123 watch->signal_modified.emit(name);
124 }
125 /*if (mask & IN_MOVE_SELF) {
126 watch->signal_moved_self.emit(name);
127 }*/ // not supported in my "inotify.h" glue
128 if (mask & IN_MOVED_FROM) {
129 watch->signal_moved_from.emit(name);
130 }
131 if (mask & IN_MOVED_TO) {
132 watch->signal_moved_to.emit(name);
133 }
134 if (mask & IN_OPEN) {
135 watch->signal_opened.emit(name);
136 }
137 }
138 }
139
remove(void)140 void Watch::remove(void) {
141 inotify_rm_watch(inotify_fd, watch_descriptor);
142 watch_descriptors.erase(watch_descriptor);
143 delete this; // self aware!
144 }
145
146 }
147
148 #endif /* USE_INOTIFY */
149