summaryrefslogtreecommitdiff
path: root/src/lib/eio/eio_monitor_inotify.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/eio/eio_monitor_inotify.c')
-rw-r--r--src/lib/eio/eio_monitor_inotify.c273
1 files changed, 273 insertions, 0 deletions
diff --git a/src/lib/eio/eio_monitor_inotify.c b/src/lib/eio/eio_monitor_inotify.c
new file mode 100644
index 0000000..66abe9c
--- /dev/null
+++ b/src/lib/eio/eio_monitor_inotify.c
@@ -0,0 +1,273 @@
1/* EIO - EFL data type library
2 * Copyright (C) 2011 Enlightenment Developers:
3 * Cedric Bail <cedric.bail@free.fr>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library;
17 * if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "eio_private.h"
21#include "Eio.h"
22
23#ifdef HAVE_SYS_INOTIFY
24# include <sys/inotify.h>
25#else
26# include <asm/unistd.h>
27# include <linux/inotify.h>
28#endif
29
30/*============================================================================*
31 * Local *
32 *============================================================================*/
33
34/**
35 * @cond LOCAL
36 */
37
38typedef struct _Eio_Inotify_Table Eio_Inotify_Table;
39
40struct _Eio_Inotify_Table
41{
42 int mask;
43 int *ev_file_code;
44 int *ev_dir_code;
45};
46
47struct _Eio_Monitor_Backend
48{
49 Eio_Monitor *parent;
50
51 int hwnd;
52};
53
54static Ecore_Fd_Handler *_inotify_fdh = NULL;
55static Eina_Hash *_inotify_monitors = NULL;
56
57#define EIO_INOTIFY_LINE(Ino, Ef, Ed) \
58 { Ino, &EIO_MONITOR_##Ef, &EIO_MONITOR_##Ed }
59
60static const Eio_Inotify_Table match[] = {
61 EIO_INOTIFY_LINE(IN_ATTRIB, FILE_MODIFIED, DIRECTORY_MODIFIED),
62 EIO_INOTIFY_LINE(IN_CLOSE_WRITE, FILE_CLOSED, DIRECTORY_CLOSED),
63 EIO_INOTIFY_LINE(IN_MODIFY, FILE_MODIFIED, DIRECTORY_MODIFIED),
64 EIO_INOTIFY_LINE(IN_MOVED_FROM, FILE_DELETED, DIRECTORY_DELETED),
65 EIO_INOTIFY_LINE(IN_MOVED_TO, FILE_CREATED, DIRECTORY_CREATED),
66 EIO_INOTIFY_LINE(IN_DELETE, FILE_DELETED, DIRECTORY_DELETED),
67 EIO_INOTIFY_LINE(IN_CREATE, FILE_CREATED, DIRECTORY_CREATED),
68 EIO_INOTIFY_LINE(IN_DELETE_SELF, SELF_DELETED, SELF_DELETED),
69 EIO_INOTIFY_LINE(IN_MOVE_SELF, SELF_DELETED, SELF_DELETED),
70 EIO_INOTIFY_LINE(IN_UNMOUNT, SELF_DELETED, SELF_DELETED)
71};
72
73#ifndef HAVE_SYS_INOTIFY
74static inline int
75inotify_init(void)
76{
77 return syscall(__NR_inotify_init);
78}
79
80static inline int
81inotify_add_watch(int fd, const char *name, __u32 mask)
82{
83 return syscall(__NR_inotify_add_watch, fd, name, mask);
84}
85
86static inline int
87inotify_rm_watch(int fd, __u32 wd)
88{
89 return syscall(__NR_inotify_rm_watch, fd, wd);
90}
91#endif
92
93static void
94_eio_inotify_del(void *data)
95{
96 Eio_Monitor_Backend *emb = data;
97 int fd;
98
99 if (emb->hwnd)
100 {
101 fd = ecore_main_fd_handler_fd_get(_inotify_fdh);
102 inotify_rm_watch(fd, emb->hwnd);
103 emb->hwnd = 0;
104 }
105
106 free(emb);
107}
108
109static void
110_eio_inotify_events(Eio_Monitor_Backend *backend, const char *file, int mask)
111{
112 char *tmp;
113 unsigned int length;
114 unsigned int tmp_length;
115 unsigned int i;
116 Eina_Bool is_dir;
117
118 length = file ? strlen(file) : 0;
119 tmp_length = eina_stringshare_strlen(backend->parent->path) + length + 2;
120 tmp = alloca(sizeof (char) * tmp_length);
121
122 snprintf(tmp, tmp_length, length ? "%s/%s" : "%s",
123 backend->parent->path, file);
124
125 is_dir = !!(mask & IN_ISDIR);
126
127 for (i = 0; i < sizeof (match) / sizeof (Eio_Inotify_Table); ++i)
128 if (match[i].mask & mask)
129 {
130 _eio_monitor_send(backend->parent, tmp, is_dir ? *match[i].ev_dir_code : *match[i].ev_file_code);
131 }
132
133 /* special case for IN_IGNORED */
134 if (mask & IN_IGNORED)
135 {
136 _eio_monitor_rename(backend->parent, tmp);
137 }
138}
139
140static Eina_Bool
141_eio_inotify_handler(void *data EINA_UNUSED, Ecore_Fd_Handler *fdh)
142{
143 Eio_Monitor_Backend *backend;
144 unsigned char buffer[16384];
145 struct inotify_event *event;
146 int i = 0;
147 int event_size;
148 ssize_t size;
149
150 size = read(ecore_main_fd_handler_fd_get(fdh), buffer, sizeof(buffer));
151 while (i < size)
152 {
153 event = (struct inotify_event *)&buffer[i];
154 event_size = sizeof(struct inotify_event) + event->len;
155 i += event_size;
156
157 backend = eina_hash_find(_inotify_monitors, &event->wd);
158 if (!backend) continue ;
159 if (!backend->parent) continue ;
160
161 _eio_inotify_events(backend, (event->len ? event->name : NULL), event->mask);
162 }
163
164 return ECORE_CALLBACK_RENEW;
165}
166
167/**
168 * @endcond
169 */
170
171
172/*============================================================================*
173 * Global *
174 *============================================================================*/
175
176/**
177 * @cond LOCAL
178 */
179
180/**
181 * @endcond
182 */
183
184void eio_monitor_backend_init(void)
185{
186 int fd;
187
188 fd = inotify_init();
189 if (fd < 0)
190 return ;
191
192 _inotify_fdh = ecore_main_fd_handler_add(fd, ECORE_FD_READ, _eio_inotify_handler, NULL, NULL, NULL);
193 if (!_inotify_fdh)
194 {
195 close(fd);
196 return ;
197 }
198
199 _inotify_monitors = eina_hash_int32_new(_eio_inotify_del);
200}
201
202void eio_monitor_backend_shutdown(void)
203{
204 int fd;
205
206 if (!_inotify_fdh) return ;
207
208 eina_hash_free(_inotify_monitors);
209
210 fd = ecore_main_fd_handler_fd_get(_inotify_fdh);
211 ecore_main_fd_handler_del(_inotify_fdh);
212 _inotify_fdh = NULL;
213
214 close(fd);
215}
216
217void eio_monitor_backend_add(Eio_Monitor *monitor)
218{
219 Eio_Monitor_Backend *backend;
220 int mask =
221 IN_ATTRIB |
222 IN_CLOSE_WRITE |
223 IN_MOVED_FROM |
224 IN_MOVED_TO |
225 IN_DELETE |
226 IN_CREATE |
227 IN_MODIFY |
228 IN_DELETE_SELF |
229 IN_MOVE_SELF |
230 IN_UNMOUNT;
231
232 if (!_inotify_fdh)
233 {
234 eio_monitor_fallback_add(monitor);
235 return;
236 }
237
238 backend = calloc(1, sizeof (Eio_Monitor_Backend));
239 if (!backend)
240 {
241 eio_monitor_fallback_add(monitor);
242 return;
243 }
244
245 backend->parent = monitor;
246 backend->hwnd = inotify_add_watch(ecore_main_fd_handler_fd_get(_inotify_fdh), monitor->path, mask);
247 if (!backend->hwnd)
248 {
249 eio_monitor_fallback_add(monitor);
250 free(backend);
251 return;
252 }
253
254 monitor->backend = backend;
255
256 eina_hash_direct_add(_inotify_monitors, &backend->hwnd, backend);
257}
258
259void eio_monitor_backend_del(Eio_Monitor *monitor)
260{
261 if (!_inotify_fdh)
262 eio_monitor_fallback_del(monitor);
263
264 if (!monitor->backend) return ;
265
266 eina_hash_del(_inotify_monitors, &monitor->backend->hwnd, monitor->backend);
267 monitor->backend = NULL;
268}
269
270
271/*============================================================================*
272 * API *
273 *============================================================================*/