/* * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2 */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include "ecore_file_private.h" #ifdef HAVE_POLL /* * TODO: * - Implement recursive as an option! * - Keep whole path or just name of file? (Memory or CPU...) * - Remove requests without files? * - Change poll time */ typedef struct _Ecore_File_Monitor_Poll Ecore_File_Monitor_Poll; typedef struct _Ecore_File Ecore_File; #define ECORE_FILE_MONITOR_POLL(x) ((Ecore_File_Monitor_Poll *)(x)) struct _Ecore_File_Monitor_Poll { Ecore_File_Monitor monitor; int mtime; unsigned char deleted; }; struct _Ecore_File { Ecore_List2 __list_data; char *name; int mtime; unsigned char is_dir; }; #define ECORE_FILE_INTERVAL_MIN 1.0 #define ECORE_FILE_INTERVAL_STEP 0.5 #define ECORE_FILE_INTERVAL_MAX 5.0 static double _interval = ECORE_FILE_INTERVAL_MIN; static Ecore_Timer *_timer = NULL; static Ecore_List2 *_monitors = NULL; static int _lock = 0; static int _ecore_file_monitor_poll_handler(void *data); static void _ecore_file_monitor_poll_check(Ecore_File_Monitor *em); static int _ecore_file_monitor_poll_checking(Ecore_File_Monitor *em, char *name); int ecore_file_monitor_poll_init(void) { return 1; } int ecore_file_monitor_poll_shutdown(void) { Ecore_List2 *l; for (l = _monitors; l;) { Ecore_File_Monitor *em; em = ECORE_FILE_MONITOR(l); l = l->next; ecore_file_monitor_poll_del(em); } if (_timer) { ecore_timer_del(_timer); _timer = NULL; } return 1; } Ecore_File_Monitor * ecore_file_monitor_poll_add(const char *path, void (*func) (void *data, Ecore_File_Monitor *em, Ecore_File_Event event, const char *path), void *data) { Ecore_File_Monitor *em; int len; if (!path) return NULL; if (!func) return NULL; em = calloc(1, sizeof(Ecore_File_Monitor_Poll)); if (!em) return NULL; if (!_timer) _timer = ecore_timer_add(_interval, _ecore_file_monitor_poll_handler, NULL); else ecore_timer_interval_set(_timer, ECORE_FILE_INTERVAL_MIN); em->path = strdup(path); len = strlen(em->path); if (em->path[len - 1] == '/' && strcmp(em->path, "/")) em->path[len - 1] = 0; em->func = func; em->data = data; ECORE_FILE_MONITOR_POLL(em)->mtime = ecore_file_mod_time(em->path); if (ecore_file_exists(em->path)) { if (ecore_file_is_dir(em->path)) { /* Check for subdirs */ Eina_List *files; char *file; files = ecore_file_ls(em->path); EINA_LIST_FREE(files, file) { Ecore_File *f; char buf[PATH_MAX]; f = calloc(1, sizeof(Ecore_File)); if (!f) { free(file); continue; } snprintf(buf, sizeof(buf), "%s/%s", em->path, file); f->name = file; f->mtime = ecore_file_mod_time(buf); f->is_dir = ecore_file_is_dir(buf); em->files = _ecore_list2_append(em->files, f); } } } else { ecore_file_monitor_poll_del(em); return NULL; } _monitors = _ecore_list2_append(_monitors, em); return em; } void ecore_file_monitor_poll_del(Ecore_File_Monitor *em) { Ecore_List2 *l; if (_lock) { ECORE_FILE_MONITOR_POLL(em)->deleted = 1; return; } /* Remove files */ /*It's possible there weren't any files to monitor, so check if the list is init*/ if (em->files) { for (l = em->files; l;) { Ecore_File *file; file = (Ecore_File *)l; l = l->next; free(file->name); free(file); } } _monitors = _ecore_list2_remove(_monitors, em); free(em->path); free(em); if (_timer) { if (!_monitors) { ecore_timer_del(_timer); _timer = NULL; } else ecore_timer_interval_set(_timer, ECORE_FILE_INTERVAL_MIN); } } static int _ecore_file_monitor_poll_handler(void *data __UNUSED__) { Ecore_List2 *l; _interval += ECORE_FILE_INTERVAL_STEP; _lock = 1; for (l = _monitors; l; l = l->next) { Ecore_File_Monitor *em; em = ECORE_FILE_MONITOR(l); _ecore_file_monitor_poll_check(em); } _lock = 0; if (_interval > ECORE_FILE_INTERVAL_MAX) _interval = ECORE_FILE_INTERVAL_MAX; ecore_timer_interval_set(_timer, _interval); for (l = _monitors; l;) { Ecore_File_Monitor *em; em = ECORE_FILE_MONITOR(l); l = l->next; if (ECORE_FILE_MONITOR_POLL(em)->deleted) ecore_file_monitor_del(em); } return 1; } static void _ecore_file_monitor_poll_check(Ecore_File_Monitor *em) { int mtime; int is_dir; mtime = ecore_file_mod_time(em->path); is_dir = ecore_file_is_dir(em->path); if (mtime < ECORE_FILE_MONITOR_POLL(em)->mtime) { Ecore_List2 *l; Ecore_File_Event event; /* Notify all files deleted */ for (l = em->files; l;) { Ecore_File *f; char buf[PATH_MAX]; f = (Ecore_File *)l; l = l->next; snprintf(buf, sizeof(buf), "%s/%s", em->path, f->name); if (f->is_dir) event = ECORE_FILE_EVENT_DELETED_DIRECTORY; else event = ECORE_FILE_EVENT_DELETED_FILE; em->func(em->data, em, event, buf); free(f->name); free(f); } em->files = NULL; em->func(em->data, em, ECORE_FILE_EVENT_DELETED_SELF, em->path); _interval = ECORE_FILE_INTERVAL_MIN; } else { Ecore_List2 *l; /* Check for changed files */ for (l = em->files; l;) { Ecore_File *f; char buf[PATH_MAX]; int mtime; Ecore_File_Event event; f = (Ecore_File *)l; l = l->next; snprintf(buf, sizeof(buf), "%s/%s", em->path, f->name); mtime = ecore_file_mod_time(buf); if (mtime < f->mtime) { if (f->is_dir) event = ECORE_FILE_EVENT_DELETED_DIRECTORY; else event = ECORE_FILE_EVENT_DELETED_FILE; em->func(em->data, em, event, buf); em->files = _ecore_list2_remove(em->files, f); free(f->name); free(f); _interval = ECORE_FILE_INTERVAL_MIN; } else if ((mtime > f->mtime) && !(f->is_dir)) { em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, buf); _interval = ECORE_FILE_INTERVAL_MIN; f->mtime = mtime; } else f->mtime = mtime; } /* Check for new files */ if (ECORE_FILE_MONITOR_POLL(em)->mtime < mtime) { Eina_List *files; Eina_List *l; char *file; /* Files have been added or removed */ files = ecore_file_ls(em->path); if (files) { /* Are we a directory? We should check first, rather than rely on null here*/ EINA_LIST_FOREACH(files, l, file) { Ecore_File *f; char buf[PATH_MAX]; Ecore_File_Event event; if (_ecore_file_monitor_poll_checking(em, file)) continue; snprintf(buf, sizeof(buf), "%s/%s", em->path, file); f = calloc(1, sizeof(Ecore_File)); if (!f) continue; f->name = strdup(file); f->mtime = ecore_file_mod_time(buf); f->is_dir = ecore_file_mod_time(buf); if (f->is_dir) event = ECORE_FILE_EVENT_CREATED_DIRECTORY; else event = ECORE_FILE_EVENT_CREATED_FILE; em->func(em->data, em, event, buf); em->files = _ecore_list2_append(em->files, f); } while (files) { file = eina_list_data_get(files); free(file); files = eina_list_remove_list(files, files); } } if (!ecore_file_is_dir(em->path)) em->func(em->data, em, ECORE_FILE_EVENT_MODIFIED, em->path); _interval = ECORE_FILE_INTERVAL_MIN; } } ECORE_FILE_MONITOR_POLL(em)->mtime = mtime; } static int _ecore_file_monitor_poll_checking(Ecore_File_Monitor *em, char *name) { Ecore_List2 *l; for (l = em->files; l; l = l->next) { Ecore_File *f; f = (Ecore_File *)l; if (!strcmp(f->name, name)) return 1; } return 0; } #endif