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