summaryrefslogtreecommitdiff
path: root/src/lib/eio/eio_monitor.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/eio/eio_monitor.c')
-rw-r--r--src/lib/eio/eio_monitor.c351
1 files changed, 351 insertions, 0 deletions
diff --git a/src/lib/eio/eio_monitor.c b/src/lib/eio/eio_monitor.c
new file mode 100644
index 0000000..0b4df98
--- /dev/null
+++ b/src/lib/eio/eio_monitor.c
@@ -0,0 +1,351 @@
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/*============================================================================*
24 * Local *
25 *============================================================================*/
26
27/**
28 * @cond LOCAL
29 */
30
31static Eina_Hash *_eio_monitors = NULL;
32static pid_t _monitor_pid = -1;
33
34static void
35_eio_monitor_free(Eio_Monitor *monitor)
36{
37 if (!monitor->delete_me)
38 eina_hash_del(_eio_monitors, monitor->path, monitor);
39
40 if (monitor->exist) eio_file_cancel(monitor->exist);
41
42 if (monitor->backend)
43 {
44 if (!monitor->fallback)
45 eio_monitor_backend_del(monitor);
46 else
47 eio_monitor_fallback_del(monitor);
48 }
49
50 eina_stringshare_del(monitor->path);
51 free(monitor);
52}
53
54static void
55_eio_monitor_error_cleanup_cb(EINA_UNUSED void *user_data, void *func_data)
56{
57 Eio_Monitor_Error *ev = func_data;
58
59 EINA_REFCOUNT_UNREF(ev->monitor)
60 _eio_monitor_free(ev->monitor);
61 free(ev);
62}
63
64static void
65_eio_monitor_event_cleanup_cb(EINA_UNUSED void *user_data, void *func_data)
66{
67 Eio_Monitor_Event *ev = func_data;
68
69 EINA_REFCOUNT_UNREF(ev->monitor)
70 _eio_monitor_free(ev->monitor);
71 eina_stringshare_del(ev->filename);
72 free(ev);
73}
74
75static void
76_eio_monitor_stat_cb(void *data, EINA_UNUSED Eio_File *handler, EINA_UNUSED const Eina_Stat *st)
77{
78 Eio_Monitor *monitor = data;
79
80 monitor->exist = NULL;
81
82 if (EINA_REFCOUNT_GET(monitor) > 1)
83 eio_monitor_backend_add(monitor);
84
85 EINA_REFCOUNT_UNREF(monitor)
86 _eio_monitor_free(monitor);
87}
88
89static void
90_eio_monitor_error(Eio_Monitor *monitor, int error)
91{
92 Eio_Monitor_Error *ev;
93
94 ev = calloc(1, sizeof (Eio_Monitor_Error));
95 if (!ev) return ;
96
97 ev->monitor = monitor;
98 EINA_REFCOUNT_REF(ev->monitor);
99 ev->error = error;
100
101 ecore_event_add(EIO_MONITOR_ERROR, ev, _eio_monitor_error_cleanup_cb, NULL);
102}
103
104static void
105_eio_monitor_error_cb(void *data, Eio_File *handler EINA_UNUSED, int error)
106{
107 Eio_Monitor *monitor = data;
108
109 monitor->error = error;
110 monitor->exist = NULL;
111
112 if (EINA_REFCOUNT_GET(monitor) >= 1)
113 _eio_monitor_error(monitor, error);
114
115 EINA_REFCOUNT_UNREF(monitor)
116 _eio_monitor_free(monitor);
117
118 return ;
119}
120
121/**
122 * @endcond
123 */
124
125/*============================================================================*
126 * Global *
127 *============================================================================*/
128
129/**
130 * @cond LOCAL
131 */
132
133void
134eio_monitor_init(void)
135{
136 EIO_MONITOR_ERROR = ecore_event_type_new();
137 EIO_MONITOR_SELF_RENAME = ecore_event_type_new();
138 EIO_MONITOR_SELF_DELETED = ecore_event_type_new();
139 EIO_MONITOR_FILE_CREATED = ecore_event_type_new();
140 EIO_MONITOR_FILE_DELETED = ecore_event_type_new();
141 EIO_MONITOR_FILE_MODIFIED = ecore_event_type_new();
142 EIO_MONITOR_FILE_CLOSED = ecore_event_type_new();
143 EIO_MONITOR_DIRECTORY_CREATED = ecore_event_type_new();
144 EIO_MONITOR_DIRECTORY_DELETED = ecore_event_type_new();
145 EIO_MONITOR_DIRECTORY_MODIFIED = ecore_event_type_new();
146 EIO_MONITOR_DIRECTORY_CLOSED = ecore_event_type_new();
147
148 eio_monitor_backend_init();
149 eio_monitor_fallback_init();
150
151 _eio_monitors = eina_hash_stringshared_new(NULL);
152 /* FIXME: this check is optional, but if it is kept then failure should be handled more gracefully */
153 if (!_eio_monitors) abort();
154
155 _monitor_pid = getpid();
156}
157
158void
159eio_monitor_shutdown(void)
160{
161 Eina_Iterator *it;
162 Eio_Monitor *monitor;
163
164 it = eina_hash_iterator_data_new(_eio_monitors);
165 EINA_ITERATOR_FOREACH(it, monitor)
166 {
167 if (monitor->exist)
168 {
169 eio_file_cancel(monitor->exist);
170 monitor->exist = NULL;
171 }
172 monitor->delete_me = EINA_TRUE;
173 }
174 eina_iterator_free(it);
175 eina_hash_free(_eio_monitors);
176
177 eio_monitor_backend_shutdown();
178 eio_monitor_fallback_shutdown();
179
180 _monitor_pid = -1;
181}
182
183void
184_eio_monitor_send(Eio_Monitor *monitor, const char *filename, int event_code)
185{
186 Eio_Monitor_Event *ev;
187
188 ev = calloc(1, sizeof (Eio_Monitor_Event));
189 if (!ev) return ;
190
191 ev->monitor = monitor;
192 EINA_REFCOUNT_REF(ev->monitor);
193 ev->filename = eina_stringshare_add(filename);
194
195 ecore_event_add(event_code, ev, _eio_monitor_event_cleanup_cb, NULL);
196}
197
198void
199_eio_monitor_rename(Eio_Monitor *monitor, const char *newpath)
200{
201 const char *tmp;
202
203 /* destroy old state */
204 if (monitor->exist) eio_file_cancel(monitor->exist);
205
206 if (monitor->backend)
207 {
208 if (!monitor->fallback)
209 eio_monitor_backend_del(monitor);
210 else
211 eio_monitor_fallback_del(monitor);
212 }
213
214 /* rename */
215 tmp = monitor->path;
216 monitor->path = eina_stringshare_add(newpath);
217 eina_hash_move(_eio_monitors, tmp, monitor->path);
218 eina_stringshare_del(tmp);
219
220 /* That means death (cmp pointer and not content) */
221 if (tmp == monitor->path)
222 {
223 _eio_monitor_error(monitor, -1);
224 return ;
225 }
226
227 EINA_REFCOUNT_REF(monitor); /* as we spawn a thread for this monitor, we need to refcount specifically for it */
228
229 /* restart */
230 monitor->rename = EINA_TRUE;
231 monitor->exist = eio_file_direct_stat(monitor->path,
232 _eio_monitor_stat_cb,
233 _eio_monitor_error_cb,
234 monitor);
235
236 /* FIXME: probably should handle this more gracefully */
237 if (!monitor->exist) abort();
238 /* and notify the app */
239 _eio_monitor_send(monitor, newpath, EIO_MONITOR_SELF_RENAME);
240}
241
242/**
243 * @endcond
244 */
245
246
247/*============================================================================*
248 * API *
249 *============================================================================*/
250
251EAPI int EIO_MONITOR_ERROR;
252EAPI int EIO_MONITOR_FILE_CREATED;
253EAPI int EIO_MONITOR_FILE_DELETED;
254EAPI int EIO_MONITOR_FILE_MODIFIED;
255EAPI int EIO_MONITOR_FILE_CLOSED;
256EAPI int EIO_MONITOR_DIRECTORY_CREATED;
257EAPI int EIO_MONITOR_DIRECTORY_DELETED;
258EAPI int EIO_MONITOR_DIRECTORY_MODIFIED;
259EAPI int EIO_MONITOR_DIRECTORY_CLOSED;
260EAPI int EIO_MONITOR_SELF_RENAME;
261EAPI int EIO_MONITOR_SELF_DELETED;
262
263EAPI Eio_Monitor *
264eio_monitor_add(const char *path)
265{
266 const char *tmp;
267 Eio_Monitor *ret;
268
269 tmp = eina_stringshare_add(path);
270 ret = eio_monitor_stringshared_add(tmp);
271 eina_stringshare_del(tmp);
272 return ret;
273}
274
275EAPI Eio_Monitor *
276eio_monitor_stringshared_add(const char *path)
277{
278 Eio_Monitor *monitor;
279 struct stat st;
280
281 if (_monitor_pid == -1) return NULL;
282
283 if (_monitor_pid != getpid())
284 {
285 eio_monitor_shutdown();
286 eio_monitor_init();
287 }
288
289 if (stat(path, &st) != 0)
290 {
291 INF("monitored path not found");
292 return NULL;
293 }
294
295 monitor = eina_hash_find(_eio_monitors, path);
296
297 if (monitor)
298 {
299 if (st.st_mtime != monitor->mtime)
300 {
301 monitor->delete_me = EINA_TRUE;
302 eina_hash_del(_eio_monitors, monitor->path, monitor);
303 }
304 else
305 {
306 EINA_REFCOUNT_REF(monitor);
307 return monitor;
308 }
309 }
310
311 monitor = malloc(sizeof (Eio_Monitor));
312 if (!monitor) return NULL;
313
314 monitor->mtime = st.st_mtime;
315 monitor->backend = NULL; // This is needed to avoid race condition
316 monitor->path = eina_stringshare_ref(path);
317 monitor->fallback = EINA_FALSE;
318 monitor->rename = EINA_FALSE;
319 monitor->delete_me = EINA_FALSE;
320
321 EINA_REFCOUNT_INIT(monitor);
322 EINA_REFCOUNT_REF(monitor); /* as we spawn a thread for this monitor, we need to refcount specifically for it */
323
324 monitor->exist = eio_file_direct_stat(monitor->path,
325 _eio_monitor_stat_cb,
326 _eio_monitor_error_cb,
327 monitor);
328 if (!monitor->exist)
329 {
330 _eio_monitor_free(monitor);
331 return NULL;
332 }
333
334 eina_hash_direct_add(_eio_monitors, path, monitor);
335
336 return monitor;
337}
338
339EAPI void
340eio_monitor_del(Eio_Monitor *monitor)
341{
342 EINA_REFCOUNT_UNREF(monitor)
343 _eio_monitor_free(monitor);
344}
345
346EAPI const char *
347eio_monitor_path_get(Eio_Monitor *monitor)
348{
349 EINA_SAFETY_ON_NULL_RETURN_VAL(monitor, NULL);
350 return monitor->path;
351}