aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/ecore/src/lib/ecore_file/ecore_file_monitor_poll.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/ecore/src/lib/ecore_file/ecore_file_monitor_poll.c')
-rw-r--r--libraries/ecore/src/lib/ecore_file/ecore_file_monitor_poll.c339
1 files changed, 339 insertions, 0 deletions
diff --git a/libraries/ecore/src/lib/ecore_file/ecore_file_monitor_poll.c b/libraries/ecore/src/lib/ecore_file/ecore_file_monitor_poll.c
new file mode 100644
index 0000000..1f71b55
--- /dev/null
+++ b/libraries/ecore/src/lib/ecore_file/ecore_file_monitor_poll.c
@@ -0,0 +1,339 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#include <stdio.h>
6#include <string.h>
7
8#include "ecore_file_private.h"
9
10#ifdef HAVE_POLL
11
12/*
13 * TODO:
14 * - Implement recursive as an option!
15 * - Keep whole path or just name of file? (Memory or CPU...)
16 * - Remove requests without files?
17 * - Change poll time
18 */
19
20typedef struct _Ecore_File_Monitor_Poll Ecore_File_Monitor_Poll;
21
22#define ECORE_FILE_MONITOR_POLL(x) ((Ecore_File_Monitor_Poll *)(x))
23
24struct _Ecore_File_Monitor_Poll
25{
26 Ecore_File_Monitor monitor;
27 int mtime;
28 unsigned char deleted;
29};
30
31#define ECORE_FILE_INTERVAL_MIN 1.0
32#define ECORE_FILE_INTERVAL_STEP 0.5
33#define ECORE_FILE_INTERVAL_MAX 5.0
34
35static double _interval = ECORE_FILE_INTERVAL_MIN;
36static Ecore_Timer *_timer = NULL;
37static Ecore_File_Monitor *_monitors = NULL;
38static int _lock = 0;
39
40static Eina_Bool _ecore_file_monitor_poll_handler(void *data);
41static void _ecore_file_monitor_poll_check(Ecore_File_Monitor *em);
42static int _ecore_file_monitor_poll_checking(Ecore_File_Monitor *em, char *name);
43
44int
45ecore_file_monitor_poll_init(void)
46{
47 return 1;
48}
49
50int
51ecore_file_monitor_poll_shutdown(void)
52{
53 while(_monitors)
54 ecore_file_monitor_poll_del(_monitors);
55
56 if (_timer)
57 {
58 ecore_timer_del(_timer);
59 _timer = NULL;
60 }
61 return 1;
62}
63
64Ecore_File_Monitor *
65ecore_file_monitor_poll_add(const char *path,
66 void (*func) (void *data, Ecore_File_Monitor *em,
67 Ecore_File_Event event,
68 const char *path),
69 void *data)
70{
71 Ecore_File_Monitor *em;
72 size_t len;
73
74 if (!path) return NULL;
75 if (!func) return NULL;
76
77 em = calloc(1, sizeof(Ecore_File_Monitor_Poll));
78 if (!em) return NULL;
79
80 if (!_timer)
81 _timer = ecore_timer_add(_interval, _ecore_file_monitor_poll_handler, NULL);
82 else
83 ecore_timer_interval_set(_timer, ECORE_FILE_INTERVAL_MIN);
84
85 em->path = strdup(path);
86 len = strlen(em->path);
87 if (em->path[len - 1] == '/' && strcmp(em->path, "/"))
88 em->path[len - 1] = 0;
89
90 em->func = func;
91 em->data = data;
92
93 ECORE_FILE_MONITOR_POLL(em)->mtime = ecore_file_mod_time(em->path);
94 _monitors = ECORE_FILE_MONITOR(eina_inlist_append(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em)));
95
96 if (ecore_file_exists(em->path))
97 {
98 if (ecore_file_is_dir(em->path))
99 {
100 /* Check for subdirs */
101 Eina_List *files;
102 char *file;
103
104 files = ecore_file_ls(em->path);
105 EINA_LIST_FREE(files, file)
106 {
107 Ecore_File *f;
108 char buf[PATH_MAX];
109
110 f = calloc(1, sizeof(Ecore_File));
111 if (!f)
112 {
113 free(file);
114 continue;
115 }
116
117 snprintf(buf, sizeof(buf), "%s/%s", em->path, file);
118 f->name = file;
119 f->mtime = ecore_file_mod_time(buf);
120 f->is_dir = ecore_file_is_dir(buf);
121 em->files = (Ecore_File *) eina_inlist_append(EINA_INLIST_GET(em->files), EINA_INLIST_GET(f));
122 }
123 }
124 }
125 else
126 {
127 ecore_file_monitor_poll_del(em);
128 return NULL;
129 }
130
131 return em;
132}
133
134void
135ecore_file_monitor_poll_del(Ecore_File_Monitor *em)
136{
137 Ecore_File *l;
138
139 if (_lock)
140 {
141 ECORE_FILE_MONITOR_POLL(em)->deleted = 1;
142 return;
143 }
144
145 /* Remove files */
146 /*It's possible there weren't any files to monitor, so check if the list is init*/
147 if (em->files)
148 {
149 for (l = em->files; l;)
150 {
151 Ecore_File *file = l;
152
153 l = (Ecore_File *) EINA_INLIST_GET(l)->next;
154 free(file->name);
155 free(file);
156 }
157 }
158
159 if (_monitors)
160 _monitors = ECORE_FILE_MONITOR(eina_inlist_remove(EINA_INLIST_GET(_monitors), EINA_INLIST_GET(em)));
161
162 free(em->path);
163 free(em);
164
165 if (_timer)
166 {
167 if (!_monitors)
168 {
169 ecore_timer_del(_timer);
170 _timer = NULL;
171 }
172 else
173 ecore_timer_interval_set(_timer, ECORE_FILE_INTERVAL_MIN);
174 }
175}
176
177static Eina_Bool
178_ecore_file_monitor_poll_handler(void *data __UNUSED__)
179{
180 Ecore_File_Monitor *l;
181
182 _interval += ECORE_FILE_INTERVAL_STEP;
183
184 _lock = 1;
185 EINA_INLIST_FOREACH(_monitors, l)
186 _ecore_file_monitor_poll_check(l);
187 _lock = 0;
188
189 if (_interval > ECORE_FILE_INTERVAL_MAX)
190 _interval = ECORE_FILE_INTERVAL_MAX;
191 ecore_timer_interval_set(_timer, _interval);
192
193 for (l = _monitors; l;)
194 {
195 Ecore_File_Monitor *em = l;
196
197 l = ECORE_FILE_MONITOR(EINA_INLIST_GET(l)->next);
198 if (ECORE_FILE_MONITOR_POLL(em)->deleted)
199 ecore_file_monitor_del(em);
200 }
201 return ECORE_CALLBACK_RENEW;
202}
203
204static void
205_ecore_file_monitor_poll_check(Ecore_File_Monitor *em)
206{
207 int mtime;
208
209 mtime = ecore_file_mod_time(em->path);
210 if (mtime < ECORE_FILE_MONITOR_POLL(em)->mtime)
211 {
212 Ecore_File *l;
213 Ecore_File_Event event;
214
215 /* Notify all files deleted */
216 for (l = em->files; l;)
217 {
218 Ecore_File *f = l;
219 char buf[PATH_MAX];
220
221 l = (Ecore_File *) EINA_INLIST_GET(l)->next;
222
223 snprintf(buf, sizeof(buf), "%s/%s", em->path, f->name);
224 if (f->is_dir)
225 event = ECORE_FILE_EVENT_DELETED_DIRECTORY;
226 else
227 event = ECORE_FILE_EVENT_DELETED_FILE;
228 em->func(em->data, em, event, buf);
229 free(f->name);
230 free(f);
231 }
232 em->files = NULL;
233 em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path);
234 _interval = ECORE_FILE_INTERVAL_MIN;
235 }
236 else
237 {
238 Ecore_File *l;
239
240 /* Check for changed files */
241 for (l = em->files; l;)
242 {
243 Ecore_File *f = l;
244 char buf[PATH_MAX];
245 int mt;
246 Ecore_File_Event event;
247
248 l = (Ecore_File *) EINA_INLIST_GET(l)->next;
249
250 snprintf(buf, sizeof(buf), "%s/%s", em->path, f->name);
251 mt = ecore_file_mod_time(buf);
252 if (mt < f->mtime)
253 {
254 if (f->is_dir)
255 event = ECORE_FILE_EVENT_DELETED_DIRECTORY;
256 else
257 event = ECORE_FILE_EVENT_DELETED_FILE;
258
259 em->func(em->data, em, event, buf);
260 em->files = (Ecore_File *) eina_inlist_remove(EINA_INLIST_GET(em->files), EINA_INLIST_GET(f));
261 free(f->name);
262 free(f);
263 _interval = ECORE_FILE_INTERVAL_MIN;
264 }
265 else if ((mt > f->mtime) && !(f->is_dir))
266 {
267 em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, buf);
268 _interval = ECORE_FILE_INTERVAL_MIN;
269 f->mtime = mt;
270 }
271 else
272 f->mtime = mt;
273 }
274
275 /* Check for new files */
276 if (ECORE_FILE_MONITOR_POLL(em)->mtime < mtime)
277 {
278 Eina_List *files;
279 Eina_List *fl;
280 char *file;
281
282 /* Files have been added or removed */
283 files = ecore_file_ls(em->path);
284 if (files)
285 {
286 /* Are we a directory? We should check first, rather than rely on null here*/
287 EINA_LIST_FOREACH(files, fl, file)
288 {
289 Ecore_File *f;
290 char buf[PATH_MAX];
291 Ecore_File_Event event;
292
293 if (_ecore_file_monitor_poll_checking(em, file))
294 continue;
295
296 snprintf(buf, sizeof(buf), "%s/%s", em->path, file);
297 f = calloc(1, sizeof(Ecore_File));
298 if (!f)
299 continue;
300
301 f->name = strdup(file);
302 f->mtime = ecore_file_mod_time(buf);
303 f->is_dir = ecore_file_is_dir(buf);
304 if (f->is_dir)
305 event = ECORE_FILE_EVENT_CREATED_DIRECTORY;
306 else
307 event = ECORE_FILE_EVENT_CREATED_FILE;
308 em->func(em->data, em, event, buf);
309 em->files = (Ecore_File *) eina_inlist_append(EINA_INLIST_GET(em->files), EINA_INLIST_GET(f));
310 }
311 while (files)
312 {
313 file = eina_list_data_get(files);
314 free(file);
315 files = eina_list_remove_list(files, files);
316 }
317 }
318
319 if (!ecore_file_is_dir(em->path))
320 em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, em->path);
321 _interval = ECORE_FILE_INTERVAL_MIN;
322 }
323 }
324 ECORE_FILE_MONITOR_POLL(em)->mtime = mtime;
325}
326
327static int
328_ecore_file_monitor_poll_checking(Ecore_File_Monitor *em, char *name)
329{
330 Ecore_File *l;
331
332 EINA_INLIST_FOREACH(em->files, l)
333 {
334 if (!strcmp(l->name, name))
335 return 1;
336 }
337 return 0;
338}
339#endif