diff options
Diffstat (limited to 'src/lib/eio/eio_monitor_inotify.c')
-rw-r--r-- | src/lib/eio/eio_monitor_inotify.c | 273 |
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 | |||
38 | typedef struct _Eio_Inotify_Table Eio_Inotify_Table; | ||
39 | |||
40 | struct _Eio_Inotify_Table | ||
41 | { | ||
42 | int mask; | ||
43 | int *ev_file_code; | ||
44 | int *ev_dir_code; | ||
45 | }; | ||
46 | |||
47 | struct _Eio_Monitor_Backend | ||
48 | { | ||
49 | Eio_Monitor *parent; | ||
50 | |||
51 | int hwnd; | ||
52 | }; | ||
53 | |||
54 | static Ecore_Fd_Handler *_inotify_fdh = NULL; | ||
55 | static Eina_Hash *_inotify_monitors = NULL; | ||
56 | |||
57 | #define EIO_INOTIFY_LINE(Ino, Ef, Ed) \ | ||
58 | { Ino, &EIO_MONITOR_##Ef, &EIO_MONITOR_##Ed } | ||
59 | |||
60 | static 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 | ||
74 | static inline int | ||
75 | inotify_init(void) | ||
76 | { | ||
77 | return syscall(__NR_inotify_init); | ||
78 | } | ||
79 | |||
80 | static inline int | ||
81 | inotify_add_watch(int fd, const char *name, __u32 mask) | ||
82 | { | ||
83 | return syscall(__NR_inotify_add_watch, fd, name, mask); | ||
84 | } | ||
85 | |||
86 | static inline int | ||
87 | inotify_rm_watch(int fd, __u32 wd) | ||
88 | { | ||
89 | return syscall(__NR_inotify_rm_watch, fd, wd); | ||
90 | } | ||
91 | #endif | ||
92 | |||
93 | static 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 | |||
109 | static 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 | |||
140 | static 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 | |||
184 | void 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 | |||
202 | void 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 | |||
217 | void 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 | |||
259 | void 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 | *============================================================================*/ | ||