aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ecore/src/lib/ecore_file/ecore_file_monitor_inotify.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ecore/src/lib/ecore_file/ecore_file_monitor_inotify.c')
-rw-r--r--libraries/ecore/src/lib/ecore_file/ecore_file_monitor_inotify.c369
1 files changed, 369 insertions, 0 deletions
diff --git a/libraries/ecore/src/lib/ecore_file/ecore_file_monitor_inotify.c b/libraries/ecore/src/lib/ecore_file/ecore_file_monitor_inotify.c
new file mode 100644
index 0000000..c3533ad
--- /dev/null
+++ b/libraries/ecore/src/lib/ecore_file/ecore_file_monitor_inotify.c
@@ -0,0 +1,369 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdio.h>
6#include <string.h>
7#include <sys/types.h>
8#include <unistd.h>
9
10#include "ecore_file_private.h"
11
12/*
13 * TODO:
14 *
15 * - Listen to these events:
16 * IN_ACCESS, IN_ATTRIB, IN_CLOSE_WRITE, IN_CLOSE_NOWRITE, IN_OPEN
17 * - Read all events first, then call the callbacks. This will prevent several
18 * callbacks with the typic save cycle (delete file, new file)
19 * - Listen to IN_IGNORED, emitted when the watch is removed
20 */
21
22#ifdef HAVE_INOTIFY
23
24#ifdef HAVE_SYS_INOTIFY
25# include <sys/inotify.h>
26#else
27# include <asm/unistd.h>
28# include <linux/inotify.h>
29#endif
30
31#ifndef HAVE_SYS_INOTIFY
32static inline int inotify_init(void);
33static inline int inotify_add_watch(int fd, const char *name, __u32 mask);
34static inline int inotify_rm_watch(int fd, __u32 wd);
35#endif
36
37
38typedef struct _Ecore_File_Monitor_Inotify Ecore_File_Monitor_Inotify;
39
40#define ECORE_FILE_MONITOR_INOTIFY(x) ((Ecore_File_Monitor_Inotify *)(x))
41
42struct _Ecore_File_Monitor_Inotify
43{
44 Ecore_File_Monitor monitor;
45 int wd;
46};
47
48static Ecore_Fd_Handler *_fdh = NULL;
49static Ecore_File_Monitor *_monitors = NULL;
50static pid_t _inotify_fd_pid = -1;
51
52static Eina_Bool _ecore_file_monitor_inotify_handler(void *data, Ecore_Fd_Handler *fdh);
53static Ecore_File_Monitor *_ecore_file_monitor_inotify_monitor_find(int wd);
54static void _ecore_file_monitor_inotify_events(Ecore_File_Monitor *em, char *file, int mask);
55static int _ecore_file_monitor_inotify_monitor(Ecore_File_Monitor *em, const char *path);
56#if 0
57static void _ecore_file_monitor_inotify_print(char *file, int mask);
58#endif
59
60int
61ecore_file_monitor_inotify_init(void)
62{
63 int fd;
64
65 fd = inotify_init();
66 if (fd < 0)
67 return 0;
68
69 _fdh = ecore_main_fd_handler_add(fd, ECORE_FD_READ, _ecore_file_monitor_inotify_handler,
70 NULL, NULL, NULL);
71 if (!_fdh)
72 {
73 close(fd);
74 return 0;
75 }
76
77 _inotify_fd_pid = getpid();
78 return 1;
79}
80
81int
82ecore_file_monitor_inotify_shutdown(void)
83{
84 int fd;
85
86 while(_monitors)
87 ecore_file_monitor_inotify_del(_monitors);
88
89 if (_fdh)
90 {
91 fd = ecore_main_fd_handler_fd_get(_fdh);
92 ecore_main_fd_handler_del(_fdh);
93 close(fd);
94 }
95 _inotify_fd_pid = -1;
96 return 1;
97}
98
99Ecore_File_Monitor *
100ecore_file_monitor_inotify_add(const char *path,
101 void (*func) (void *data, Ecore_File_Monitor *em,
102 Ecore_File_Event event,
103 const char *path),
104 void *data)
105{
106 Ecore_File_Monitor *em;
107 int len;
108
109 if (_inotify_fd_pid == -1) return NULL;
110
111 if (_inotify_fd_pid != getpid())
112 {
113 ecore_file_monitor_inotify_shutdown();
114 ecore_file_monitor_inotify_init();
115 }
116
117 em = calloc(1, sizeof(Ecore_File_Monitor_Inotify));
118 if (!em) return NULL;
119
120 em->func = func;
121 em->data = data;
122
123 em->path = strdup(path);
124 len = strlen(em->path);
125 if (em->path[len - 1] == '/' && strcmp(em->path, "/"))
126 em->path[len - 1] = 0;
127
128 _monitors = ECORE_FILE_MONITOR(eina_inlist_append(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em)));
129
130 if (ecore_file_exists(em->path))
131 {
132 if (!_ecore_file_monitor_inotify_monitor(em, em->path))
133 return NULL;
134 }
135 else
136 {
137 ecore_file_monitor_inotify_del(em);
138 return NULL;
139 }
140
141 return em;
142}
143
144void
145ecore_file_monitor_inotify_del(Ecore_File_Monitor *em)
146{
147 int fd;
148
149 if (_monitors)
150 _monitors = ECORE_FILE_MONITOR(eina_inlist_remove(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em)));
151
152 fd = ecore_main_fd_handler_fd_get(_fdh);
153 if (ECORE_FILE_MONITOR_INOTIFY(em)->wd)
154 inotify_rm_watch(fd, ECORE_FILE_MONITOR_INOTIFY(em)->wd);
155 free(em->path);
156 free(em);
157}
158
159static Eina_Bool
160_ecore_file_monitor_inotify_handler(void *data __UNUSED__, Ecore_Fd_Handler *fdh)
161{
162 Ecore_File_Monitor *em;
163 char buffer[16384];
164 struct inotify_event *event;
165 int i = 0;
166 int event_size;
167 ssize_t size;
168
169 size = read(ecore_main_fd_handler_fd_get(fdh), buffer, sizeof(buffer));
170 while (i < size)
171 {
172 event = (struct inotify_event *)&buffer[i];
173 event_size = sizeof(struct inotify_event) + event->len;
174 i += event_size;
175
176 em = _ecore_file_monitor_inotify_monitor_find(event->wd);
177 if (!em) continue;
178
179 _ecore_file_monitor_inotify_events(em, (event->len ? event->name : NULL), event->mask);
180 }
181
182 return ECORE_CALLBACK_RENEW;
183}
184
185static Ecore_File_Monitor *
186_ecore_file_monitor_inotify_monitor_find(int wd)
187{
188 Ecore_File_Monitor *l;
189
190 EINA_INLIST_FOREACH(_monitors, l)
191 {
192 if (ECORE_FILE_MONITOR_INOTIFY(l)->wd == wd)
193 return l;
194 }
195 return NULL;
196}
197
198static void
199_ecore_file_monitor_inotify_events(Ecore_File_Monitor *em, char *file, int mask)
200{
201 char buf[PATH_MAX];
202 int isdir;
203
204 if ((file) && (file[0]))
205 snprintf(buf, sizeof(buf), "%s/%s", em->path, file);
206 else
207 strcpy(buf, em->path);
208 isdir = mask & IN_ISDIR;
209
210#if 0
211 _ecore_file_monitor_inotify_print(buf, mask);
212#endif
213
214 if (mask & IN_ATTRIB)
215 {
216 em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, buf);
217 }
218 if (mask & IN_CLOSE_WRITE)
219 {
220 if (!isdir)
221 em->func(em->data, em, ECORE_FILE_EVENT_CLOSED, buf);
222 }
223 if (mask & IN_MODIFY)
224 {
225 if (!isdir)
226 em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, buf);
227 }
228 if (mask & IN_MOVED_FROM)
229 {
230 if (isdir)
231 em->func(em->data, em, ECORE_FILE_EVENT_DELETED_DIRECTORY, buf);
232 else
233 em->func(em->data, em, ECORE_FILE_EVENT_DELETED_FILE, buf);
234 }
235 if (mask & IN_MOVED_TO)
236 {
237 if (isdir)
238 em->func(em->data, em, ECORE_FILE_EVENT_CREATED_DIRECTORY, buf);
239 else
240 em->func(em->data, em, ECORE_FILE_EVENT_CREATED_FILE, buf);
241 }
242 if (mask & IN_DELETE)
243 {
244 if (isdir)
245 em->func(em->data, em, ECORE_FILE_EVENT_DELETED_DIRECTORY, buf);
246 else
247 em->func(em->data, em, ECORE_FILE_EVENT_DELETED_FILE, buf);
248 }
249 if (mask & IN_CREATE)
250 {
251 if (isdir)
252 em->func(em->data, em, ECORE_FILE_EVENT_CREATED_DIRECTORY, buf);
253 else
254 em->func(em->data, em, ECORE_FILE_EVENT_CREATED_FILE, buf);
255 }
256 if (mask & IN_DELETE_SELF)
257 {
258 em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path);
259 }
260 if (mask & IN_MOVE_SELF)
261 {
262 /* We just call delete. The dir is gone... */
263 em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path);
264 }
265 if (mask & IN_UNMOUNT)
266 {
267 /* We just call delete. The dir is gone... */
268 em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path);
269 }
270 if (mask & IN_IGNORED)
271 {
272 /* The watch is removed. If the file name still exists monitor the new one,
273 * else delete it */
274 if (ecore_file_exists(em->path))
275 {
276 if (!_ecore_file_monitor_inotify_monitor(em, em->path))
277 em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path);
278 }
279 else
280 em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path);
281 }
282}
283
284static int
285_ecore_file_monitor_inotify_monitor(Ecore_File_Monitor *em, const char *path)
286{
287 int mask =
288 IN_ATTRIB |
289 IN_CLOSE_WRITE |
290 IN_MOVED_FROM |
291 IN_MOVED_TO |
292 IN_DELETE |
293 IN_CREATE |
294 IN_MODIFY |
295 IN_DELETE_SELF |
296 IN_MOVE_SELF |
297 IN_UNMOUNT;
298
299 ECORE_FILE_MONITOR_INOTIFY(em)->wd =
300 inotify_add_watch(ecore_main_fd_handler_fd_get(_fdh), path, mask);
301 if (ECORE_FILE_MONITOR_INOTIFY(em)->wd < 0)
302 {
303 ERR("inotify_add_watch error");
304 ecore_file_monitor_inotify_del(em);
305 return 0;
306 }
307 return 1;
308}
309
310#ifndef HAVE_SYS_INOTIFY
311static inline int
312inotify_init(void)
313{
314 return syscall(__NR_inotify_init);
315}
316
317static inline int
318inotify_add_watch(int fd, const char *name, __u32 mask)
319{
320 return syscall(__NR_inotify_add_watch, fd, name, mask);
321}
322
323static inline int
324inotify_rm_watch(int fd, __u32 wd)
325{
326 return syscall(__NR_inotify_rm_watch, fd, wd);
327}
328#endif
329
330#if 0
331static void
332_ecore_file_monitor_inotify_print(char *file, int mask)
333{
334 const char *type;
335
336 if (mask & IN_ISDIR)
337 type = "dir";
338 else
339 type = "file";
340
341 if (mask & IN_ACCESS)
342 INF("Inotify accessed %s: %s", type, file);
343 if (mask & IN_MODIFY)
344 INF("Inotify modified %s: %s", type, file);
345 if (mask & IN_ATTRIB)
346 INF("Inotify attributes %s: %s", type, file);
347 if (mask & IN_CLOSE_WRITE)
348 INF("Inotify close write %s: %s", type, file);
349 if (mask & IN_CLOSE_NOWRITE)
350 INF("Inotify close write %s: %s", type, file);
351 if (mask & IN_OPEN)
352 INF("Inotify open %s: %s", type, file);
353 if (mask & IN_MOVED_FROM)
354 INF("Inotify moved from %s: %s", type, file);
355 if (mask & IN_MOVED_TO)
356 INF("Inotify moved to %s: %s", type, file);
357 if (mask & IN_DELETE)
358 INF("Inotify delete %s: %s", type, file);
359 if (mask & IN_CREATE)
360 INF("Inotify create %s: %s", type, file);
361 if (mask & IN_DELETE_SELF)
362 INF("Inotify delete self %s: %s", type, file);
363 if (mask & IN_MOVE_SELF)
364 INF("Inotify move self %s: %s", type, file);
365 if (mask & IN_UNMOUNT)
366 INF("Inotify unmount %s: %s", type, file);
367}
368#endif
369#endif /* HAVE_INOTIFY */