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