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
{
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);
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)
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;
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 ;
}
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);
}
}
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;
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);
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();
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,
{
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);
+}