eio: add inotify backend and fix api.
authorCedric BAIL <cedric.bail@free.fr>
Wed, 27 Apr 2011 10:27:07 +0000 (10:27 +0000)
committerCedric BAIL <cedric.bail@free.fr>
Wed, 27 Apr 2011 10:27:07 +0000 (10:27 +0000)
Note: API/ABI of Eio_Monitor could be considered usable and need feedback.
Still lacking of proper fallback and windows port.

SVN revision: 58953

legacy/eio/src/lib/Eio.h
legacy/eio/src/lib/eio_inotify.c
legacy/eio/src/lib/eio_monitor.c
legacy/eio/src/lib/eio_private.h

index afe3adfaa9009938b64479616f44b861d3849302..08f5e2249b2163bad65d27190ad9a56b9ebad53e 100644 (file)
@@ -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);
index 16feb8c8f5da95cd64c450a2929a9f72cceca688..1e2e301311b9f76cd7bb76998f4c086de081a8d3 100644 (file)
@@ -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)
index a7b5f5af288fb808abd07ce4b5268788b4516de1..6b7e2060816298ccba05789ded8eb4f24980d707 100644 (file)
@@ -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);
+}
+
+static void
+_eio_monitor_event_cleanup_cb(void *user_data, __UNUSED__ void *func_data)
+{
+   Eio_Monitor_Event *ev = user_data;
 
-   _eio_monitor_del(ev->monitor);
+   _eio_monitor_unref(ev->monitor);
+   eina_stringshare_del(ev->filename);
    free(ev);
 }
 
@@ -84,9 +104,23 @@ _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;
+
+   ev = calloc(1, sizeof (Eio_Monitor_Error));
+   if (!ev) return ;
+
+   ev->monitor = monitor;
+   ev->monitor->refcount++;
+   ev->error = error;
+
+   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;
@@ -95,14 +129,9 @@ _eio_monitor_error_cb(void *data, Eio_File *handler, int error)
 
    if (monitor->refcount == 0) goto on_empty;
 
-   ev = calloc(1, sizeof (Eio_Monitor_Error));
-   if (!ev) return ;
-
-   ev->monitor = monitor;
-   ev->monitor->refcount++;
-   ev->error = error;
+   _eio_monitor_error(monitor, error);
 
-   ecore_event_add(EIO_MONITOR_ERROR, ev, _eio_monitor_cleanup_cb, NULL);
+   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);
+}
index 62bb18cb8f6ea4a0b99a77270e915968c9a17728..220554777ec3edcd0e8f080c37f822fe82d93178 100644 (file)
@@ -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