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