diff --git a/legacy/eio/src/lib/Eio.h b/legacy/eio/src/lib/Eio.h index afe3adfaa9..08f5e2249b 100644 --- a/legacy/eio/src/lib/Eio.h +++ b/legacy/eio/src/lib/Eio.h @@ -274,18 +274,19 @@ static inline Eina_Bool eio_file_is_lnk(const struct stat *stat); EAPI extern int EIO_MONITOR_FILE_CREATED; /**< Notify creation of a new file in a watched directory */ EAPI extern int EIO_MONITOR_FILE_DELETED; /**< Notify destruction of a watched file or in a watched directory */ EAPI extern int EIO_MONITOR_FILE_MODIFIED; /**< Notify modification of a file in a watched directory */ -EAPI extern int EIO_MONITOR_FILE_START; /**< Notify starting to watch on a file */ -EAPI extern int EIO_MONITOR_FILE_STOP; /**< Notify that Eio stopped watching on a file (because of all watcher beeing deleted or the file itself has been deleted */ +EAPI extern int EIO_MONITOR_FILE_CLOSED; /**< Notify closing of a file in a watched directory */ EAPI extern int EIO_MONITOR_DIRECTORY_CREATED; /**< Notify creation of a new directory in a watched directory */ EAPI extern int EIO_MONITOR_DIRECTORY_DELETED; /**< Notify destruction of a watched directory or in a watched directory */ EAPI extern int EIO_MONITOR_DIRECTORY_MODIFIED; /**< Notify modification of a directory in a watched directory */ -EAPI extern int EIO_MONITOR_DIRECTORY_START; /**< Notify the starting processus of watching a directory */ -EAPI extern int EIO_MONITOR_DIRECTORY_STOP; /**< Notify that Eio stopped watching on a directory (due to destruction of the directory or due to all watcher beeing deleted */ +EAPI extern int EIO_MONITOR_DIRECTORY_CLOSED; /**< Notify closing of a directory in a watched directory */ +EAPI extern int EIO_MONITOR_SELF_RENAME; /**< Notify that Eio monitored path has been renamed, an error could happen just after if the renamed path doesn't exist */ +EAPI extern int EIO_MONITOR_SELF_DELETED; /**< Notify that Eio monitored path has been removed */ EAPI extern int EIO_MONITOR_ERROR; /**< Notify that during operation the pointed monitor failed and will no longer work. eio_monitor_del is required on it. */ typedef struct _Eio_Monitor Eio_Monitor; typedef struct _Eio_Monitor_Error Eio_Monitor_Error; +typedef struct _Eio_Monitor_Event Eio_Monitor_Event; struct _Eio_Monitor_Error { @@ -293,6 +294,12 @@ struct _Eio_Monitor_Error int error; }; +struct _Eio_Monitor_Event +{ + Eio_Monitor *monitor; + const char *filename; +}; + EAPI Eio_Monitor *eio_monitor_add(const char *path); EAPI Eio_Monitor *eio_monitor_stringshared_add(const char *path); EAPI void eio_monitor_del(Eio_Monitor *monitor); diff --git a/legacy/eio/src/lib/eio_inotify.c b/legacy/eio/src/lib/eio_inotify.c index 16feb8c8f5..1e2e301311 100644 --- a/legacy/eio/src/lib/eio_inotify.c +++ b/legacy/eio/src/lib/eio_inotify.c @@ -53,10 +53,86 @@ _eio_inotify_del(void *data) free(emb); } +typedef struct _Eio_Inotify_Table Eio_Inotify_Table; +struct _Eio_Inotify_Table +{ + int mask; + int *ev_file_code; + int *ev_dir_code; +}; + +#define EIO_INOTIFY_LINE(Ino, Ef, Ed) \ + { Ino, &EIO_MONITOR_##Ef, &EIO_MONITOR_##Ed } + +static const Eio_Inotify_Table match[] = { + EIO_INOTIFY_LINE(IN_ATTRIB, FILE_MODIFIED, DIRECTORY_MODIFIED), + EIO_INOTIFY_LINE(IN_CLOSE_WRITE, FILE_CLOSED, DIRECTORY_CLOSED), + EIO_INOTIFY_LINE(IN_MODIFY, FILE_MODIFIED, DIRECTORY_MODIFIED), + EIO_INOTIFY_LINE(IN_MOVED_FROM, FILE_DELETED, DIRECTORY_DELETED), + EIO_INOTIFY_LINE(IN_MOVED_TO, FILE_CREATED, DIRECTORY_CREATED), + EIO_INOTIFY_LINE(IN_DELETE, FILE_DELETED, DIRECTORY_DELETED), + EIO_INOTIFY_LINE(IN_CREATE, FILE_CREATED, DIRECTORY_CREATED), + EIO_INOTIFY_LINE(IN_DELETE_SELF, SELF_DELETED, SELF_DELETED), + EIO_INOTIFY_LINE(IN_MOVE_SELF, SELF_DELETED, SELF_DELETED), + EIO_INOTIFY_LINE(IN_UNMOUNT, SELF_DELETED, SELF_DELETED) +}; + +static void +_eio_inotify_events(Eio_Monitor_Backend *backend, const char *file, int mask) +{ + char *tmp; + unsigned int length; + unsigned int tmp_length; + unsigned int i; + Eina_Bool is_dir; + + length = file ? strlen(file) : 0; + tmp_length = eina_stringshare_strlen(backend->parent->path) + length + 2; + tmp = alloca(sizeof (char) * tmp_length); + + snprintf(tmp, tmp_length, length ? "%s/%s" : "%s", + backend->parent->path, file); + + is_dir = !!(mask & IN_ISDIR); + + for (i = 0; i < sizeof (match) / sizeof (Eio_Inotify_Table); ++i) + if (match[i].mask & mask) + { + _eio_monitor_send(backend->parent, tmp, is_dir ? *match[i].ev_dir_code : *match[i].ev_file_code); + } + + /* special case for IN_IGNORED */ + if (mask & IN_IGNORED) + { + _eio_monitor_rename(backend->parent, tmp); + } +} + static Eina_Bool _eio_inotify_handler(void *data, Ecore_Fd_Handler *fdh) { - return EINA_TRUE; + Eio_Monitor_Backend *backend; + unsigned char buffer[16384]; + struct inotify_event *event; + int i = 0; + int event_size; + ssize_t size; + + size = read(ecore_main_fd_handler_fd_get(fdh), buffer, sizeof(buffer)); + while (i < size) + { + event = (struct inotify_event *)&buffer[i]; + event_size = sizeof(struct inotify_event) + event->len; + i += event_size; + + backend = eina_hash_find(_inotify_monitors, &event->wd); + if (!backend) continue ; + if (!backend->parent) continue ; + + _eio_inotify_events(backend, (event->len ? event->name : NULL), event->mask); + } + + return ECORE_CALLBACK_RENEW; } void eio_monitor_backend_init(void) diff --git a/legacy/eio/src/lib/eio_monitor.c b/legacy/eio/src/lib/eio_monitor.c index a7b5f5af28..6b7e206081 100644 --- a/legacy/eio/src/lib/eio_monitor.c +++ b/legacy/eio/src/lib/eio_monitor.c @@ -24,13 +24,13 @@ EAPI int EIO_MONITOR_ERROR; EAPI int EIO_MONITOR_FILE_CREATED; EAPI int EIO_MONITOR_FILE_DELETED; EAPI int EIO_MONITOR_FILE_MODIFIED; -EAPI int EIO_MONITOR_FILE_START; -EAPI int EIO_MONITOR_FILE_STOP; +EAPI int EIO_MONITOR_FILE_CLOSED; EAPI int EIO_MONITOR_DIRECTORY_CREATED; EAPI int EIO_MONITOR_DIRECTORY_DELETED; EAPI int EIO_MONITOR_DIRECTORY_MODIFIED; -EAPI int EIO_MONITOR_DIRECTORY_START; -EAPI int EIO_MONITOR_DIRECTORY_STOP; +EAPI int EIO_MONITOR_DIRECTORY_CLOSED; +EAPI int EIO_MONITOR_SELF_RENAME; +EAPI int EIO_MONITOR_SELF_DELETED; static Eina_Hash *_eio_monitors = NULL; static pid_t _monitor_pid = -1; @@ -42,10 +42,13 @@ _eio_monitor_del(void *data) if (monitor->exist) eio_file_cancel(monitor->exist); - if (!monitor->fallback) - eio_monitor_backend_del(monitor); - else - eio_monitor_fallback_del(monitor); + if (monitor->backend) + { + if (!monitor->fallback) + eio_monitor_backend_del(monitor); + else + eio_monitor_fallback_del(monitor); + } if (monitor->refcount > 0) return ; @@ -55,13 +58,30 @@ _eio_monitor_del(void *data) } static void -_eio_monitor_cleanup_cb(void *user_data, __UNUSED__ void *func_data) +_eio_monitor_unref(Eio_Monitor *monitor) +{ + monitor->refcount--; + + if (monitor->refcount <= 0) + eina_hash_del(_eio_monitors, monitor->path, monitor); +} + +static void +_eio_monitor_error_cleanup_cb(void *user_data, __UNUSED__ void *func_data) { Eio_Monitor_Error *ev = user_data; - ev->monitor->refcount--; + _eio_monitor_unref(ev->monitor); + free(ev); +} - _eio_monitor_del(ev->monitor); +static void +_eio_monitor_event_cleanup_cb(void *user_data, __UNUSED__ void *func_data) +{ + Eio_Monitor_Event *ev = user_data; + + _eio_monitor_unref(ev->monitor); + eina_stringshare_del(ev->filename); free(ev); } @@ -84,16 +104,9 @@ _eio_monitor_stat_cb(void *data, __UNUSED__ Eio_File *handler, __UNUSED__ const } static void -_eio_monitor_error_cb(void *data, Eio_File *handler, int error) +_eio_monitor_error(Eio_Monitor *monitor, int error) { Eio_Monitor_Error *ev; - Eio_Monitor *monitor = data; - - monitor->error = error; - monitor->exist = NULL; - monitor->refcount--; - - if (monitor->refcount == 0) goto on_empty; ev = calloc(1, sizeof (Eio_Monitor_Error)); if (!ev) return ; @@ -102,7 +115,23 @@ _eio_monitor_error_cb(void *data, Eio_File *handler, int error) ev->monitor->refcount++; ev->error = error; - ecore_event_add(EIO_MONITOR_ERROR, ev, _eio_monitor_cleanup_cb, NULL); + ecore_event_add(EIO_MONITOR_ERROR, ev, _eio_monitor_error_cleanup_cb, NULL); +} + +static void +_eio_monitor_error_cb(void *data, Eio_File *handler, int error) +{ + Eio_Monitor *monitor = data; + + monitor->error = error; + monitor->exist = NULL; + monitor->refcount--; + + if (monitor->refcount == 0) goto on_empty; + + _eio_monitor_error(monitor, error); + + return ; on_empty: eina_hash_del(_eio_monitors, monitor->path, monitor); @@ -112,16 +141,16 @@ void eio_monitor_init(void) { EIO_MONITOR_ERROR = ecore_event_type_new(); + EIO_MONITOR_SELF_RENAME = ecore_event_type_new(); + EIO_MONITOR_SELF_DELETED = ecore_event_type_new(); EIO_MONITOR_FILE_CREATED = ecore_event_type_new(); EIO_MONITOR_FILE_DELETED = ecore_event_type_new(); EIO_MONITOR_FILE_MODIFIED = ecore_event_type_new(); - EIO_MONITOR_FILE_START = ecore_event_type_new(); - EIO_MONITOR_FILE_STOP = ecore_event_type_new(); + EIO_MONITOR_FILE_CLOSED = ecore_event_type_new(); EIO_MONITOR_DIRECTORY_CREATED = ecore_event_type_new(); EIO_MONITOR_DIRECTORY_DELETED = ecore_event_type_new(); EIO_MONITOR_DIRECTORY_MODIFIED = ecore_event_type_new(); - EIO_MONITOR_DIRECTORY_START = ecore_event_type_new(); - EIO_MONITOR_DIRECTORY_STOP = ecore_event_type_new(); + EIO_MONITOR_DIRECTORY_CLOSED = ecore_event_type_new(); eio_monitor_backend_init(); eio_monitor_fallback_init(); @@ -174,6 +203,7 @@ eio_monitor_stringshared_add(const char *path) monitor->backend = NULL; // This is needed to avoid race condition monitor->path = eina_stringshare_ref(path); monitor->fallback = EINA_FALSE; + monitor->rename = EINA_FALSE; monitor->refcount = 1; monitor->exist = eio_file_direct_stat(monitor->path, @@ -204,3 +234,58 @@ eio_monitor_path_get(Eio_Monitor *monitor) { return monitor->path; } + +void +_eio_monitor_send(Eio_Monitor *monitor, const char *filename, int event_code) +{ + Eio_Monitor_Event *ev; + + ev = calloc(1, sizeof (Eio_Monitor_Event)); + if (!ev) return ; + + ev->monitor = monitor; + ev->monitor->refcount++; + ev->filename = eina_stringshare_add(filename); + + ecore_event_add(event_code, ev, _eio_monitor_event_cleanup_cb, NULL); +} + +void +_eio_monitor_rename(Eio_Monitor *monitor, const char *newpath) +{ + const char *tmp; + + /* destroy old state */ + if (monitor->exist) eio_file_cancel(monitor->exist); + + if (monitor->backend) + { + if (!monitor->fallback) + eio_monitor_backend_del(monitor); + else + eio_monitor_fallback_del(monitor); + } + + /* rename */ + tmp = monitor->path; + monitor->path = eina_stringshare_add(newpath); + eina_hash_move(_eio_monitors, tmp, monitor->path); + eina_stringshare_del(tmp); + + /* That means death (cmp pointer and not content) */ + if (tmp == monitor->path) + { + _eio_monitor_error(monitor, -1); + return ; + } + + /* restart */ + monitor->rename = EINA_TRUE; + monitor->exist = eio_file_direct_stat(monitor->path, + _eio_monitor_stat_cb, + _eio_monitor_error_cb, + monitor); + + /* and notify the app */ + _eio_monitor_send(monitor, newpath, EIO_MONITOR_SELF_RENAME); +} diff --git a/legacy/eio/src/lib/eio_private.h b/legacy/eio/src/lib/eio_private.h index 62bb18cb8f..220554777e 100644 --- a/legacy/eio/src/lib/eio_private.h +++ b/legacy/eio/src/lib/eio_private.h @@ -143,7 +143,6 @@ struct _Eio_File_Move struct _Eio_Dir_Copy { Eio_File_Progress progress; - Eio_Filter_Direct_Cb filter_cb; Eina_List *files; @@ -171,6 +170,7 @@ struct _Eio_Monitor int error; Eina_Bool fallback : 1; + Eina_Bool rename : 1; }; /* Be aware that ecore_thread_run could call cancel_cb if something goes wrong. */ @@ -220,4 +220,7 @@ void eio_monitor_fallback_add(Eio_Monitor *monitor); void eio_monitor_backend_del(Eio_Monitor *monitor); void eio_monitor_fallback_del(Eio_Monitor *monitor); +void _eio_monitor_send(Eio_Monitor *monitor, const char *filename, int event_code); +void _eio_monitor_rename(Eio_Monitor *monitor, const char *newpath); + #endif