Move event support in the inotify backend

This adds support for G_FILE_MONITOR_SEND_MOVED events when requested by
the user to the inotify backend. Last part to fix bug #547890.
Based heavily on a patch by Martyn Russel <martyn@lanedo.com>.
This commit is contained in:
Christian Kellner 2010-02-18 15:49:58 +01:00
parent 239af97712
commit 48f74cab39
8 changed files with 86 additions and 18 deletions

View File

@ -76,7 +76,8 @@ g_inotify_directory_monitor_constructor (GType type,
GInotifyDirectoryMonitor *inotify_monitor; GInotifyDirectoryMonitor *inotify_monitor;
const gchar *dirname = NULL; const gchar *dirname = NULL;
inotify_sub *sub = NULL; inotify_sub *sub = NULL;
gboolean ret_ih_startup; /* return value of _ih_startup, for asserting */ gboolean ret_ih_startup; /* return value of _ih_startup, for asserting */
gboolean pair_moves;
klass = G_INOTIFY_DIRECTORY_MONITOR_CLASS (g_type_class_peek (G_TYPE_INOTIFY_DIRECTORY_MONITOR)); klass = G_INOTIFY_DIRECTORY_MONITOR_CLASS (g_type_class_peek (G_TYPE_INOTIFY_DIRECTORY_MONITOR));
parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass)); parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
@ -95,7 +96,9 @@ g_inotify_directory_monitor_constructor (GType type,
ret_ih_startup = _ih_startup(); ret_ih_startup = _ih_startup();
g_assert (ret_ih_startup); g_assert (ret_ih_startup);
sub = _ih_sub_new (dirname, NULL, inotify_monitor); pair_moves = G_LOCAL_DIRECTORY_MONITOR (obj)->flags & G_FILE_MONITOR_SEND_MOVED;
sub = _ih_sub_new (dirname, NULL, pair_moves, inotify_monitor);
/* FIXME: what to do about errors here? we can't return NULL or another /* FIXME: what to do about errors here? we can't return NULL or another
* kind of error and an assertion is probably too hard */ * kind of error and an assertion is probably too hard */
g_assert (sub != NULL); g_assert (sub != NULL);

View File

@ -39,6 +39,7 @@ struct _GInotifyFileMonitor
gchar *filename; gchar *filename;
gchar *dirname; gchar *dirname;
inotify_sub *sub; inotify_sub *sub;
gboolean pair_moves;
}; };
static gboolean g_inotify_file_monitor_cancel (GFileMonitor* monitor); static gboolean g_inotify_file_monitor_cancel (GFileMonitor* monitor);
@ -90,6 +91,7 @@ g_inotify_file_monitor_constructor (GType type,
GInotifyFileMonitor *inotify_monitor; GInotifyFileMonitor *inotify_monitor;
const gchar *filename = NULL; const gchar *filename = NULL;
inotify_sub *sub = NULL; inotify_sub *sub = NULL;
gboolean pair_moves;
gboolean ret_ih_startup; /* return value of _ih_startup, for asserting */ gboolean ret_ih_startup; /* return value of _ih_startup, for asserting */
klass = G_INOTIFY_FILE_MONITOR_CLASS (g_type_class_peek (G_TYPE_INOTIFY_FILE_MONITOR)); klass = G_INOTIFY_FILE_MONITOR_CLASS (g_type_class_peek (G_TYPE_INOTIFY_FILE_MONITOR));
@ -113,7 +115,12 @@ g_inotify_file_monitor_constructor (GType type,
ret_ih_startup = _ih_startup(); ret_ih_startup = _ih_startup();
g_assert (ret_ih_startup); g_assert (ret_ih_startup);
sub = _ih_sub_new (inotify_monitor->dirname, inotify_monitor->filename, inotify_monitor); pair_moves = G_LOCAL_FILE_MONITOR (obj)->flags & G_FILE_MONITOR_SEND_MOVED;
sub = _ih_sub_new (inotify_monitor->dirname,
inotify_monitor->filename,
pair_moves,
inotify_monitor);
/* FIXME: what to do about errors here? we can't return NULL or another /* FIXME: what to do about errors here? we can't return NULL or another
* kind of error and an assertion is probably too hard */ * kind of error and an assertion is probably too hard */

View File

@ -138,6 +138,32 @@ _ih_sub_cancel (inotify_sub *sub)
return TRUE; return TRUE;
} }
static char *
_ih_fullpath_from_event (ik_event_t *event, char *dirname)
{
char *fullpath;
if (event->name)
fullpath = g_strdup_printf ("%s/%s", dirname, event->name);
else
fullpath = g_strdup_printf ("%s/", dirname);
return fullpath;
}
static gboolean
ih_event_is_paired_move (ik_event_t *event)
{
if (event->pair)
{
ik_event_t *paired = event->pair;
/* intofiy(7): IN_MOVE == IN_MOVED_FROM | IN_MOVED_TO */
return (event->mask | paired->mask) & IN_MOVE;
}
return FALSE;
}
static void static void
ih_event_callback (ik_event_t *event, ih_event_callback (ik_event_t *event,
@ -147,22 +173,33 @@ ih_event_callback (ik_event_t *event,
GFileMonitorEvent eflags; GFileMonitorEvent eflags;
GFile* parent; GFile* parent;
GFile* child; GFile* child;
GFile* other;
eflags = ih_mask_to_EventFlags (event->mask); eflags = ih_mask_to_EventFlags (event->mask);
parent = g_file_new_for_path (sub->dirname); parent = g_file_new_for_path (sub->dirname);
if (event->name) fullpath = _ih_fullpath_from_event (event, sub->dirname);
fullpath = g_strdup_printf ("%s/%s", sub->dirname, event->name);
else
fullpath = g_strdup_printf ("%s/", sub->dirname);
child = g_file_new_for_path (fullpath); child = g_file_new_for_path (fullpath);
g_free (fullpath); g_free (fullpath);
if (ih_event_is_paired_move (event) && sub->pair_moves)
{
char *parent_dir = _ip_get_path_for_wd (event->pair->wd);
fullpath = _ih_fullpath_from_event (event->pair, parent_dir);
other = g_file_new_for_path (fullpath);
g_free (fullpath);
eflags = G_FILE_MONITOR_EVENT_MOVED;
event->pair = NULL; /* prevents the paired event to be emitted as well */
}
else
other = NULL;
g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data), g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data),
child, NULL, eflags); child, other, eflags);
g_object_unref (child); g_object_unref (child);
g_object_unref (parent); g_object_unref (parent);
if (other)
g_object_unref (other);
} }
static void static void

View File

@ -32,9 +32,9 @@
#include <sys/inotify.h> #include <sys/inotify.h>
/* Timings for pairing MOVED_TO / MOVED_FROM events */ /* Timings for pairing MOVED_TO / MOVED_FROM events */
#define PROCESS_EVENTS_TIME 1000 /* milliseconds (1 hz) */ #define PROCESS_EVENTS_TIME 1000 /* 1 millisecond (1 hz) */
#define DEFAULT_HOLD_UNTIL_TIME 0 /* 0 millisecond */ #define DEFAULT_HOLD_UNTIL_TIME 0 /* 0 millisecond */
#define MOVE_HOLD_UNTIL_TIME 0 /* 0 milliseconds */ #define MOVE_HOLD_UNTIL_TIME 500 /* 500 microseconds or 0.5 milliseconds */
static int inotify_instance_fd = -1; static int inotify_instance_fd = -1;
static GQueue *events_to_process = NULL; static GQueue *events_to_process = NULL;

View File

@ -420,3 +420,21 @@ ip_event_callback (ik_event_t *event)
_ik_event_free (event); _ik_event_free (event);
} }
const char *
_ip_get_path_for_wd (gint32 wd)
{
GList *dir_list;
ip_watched_dir_t *dir;
g_assert (wd >= 0);
dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER (wd));
if (dir_list)
{
dir = dir_list->data;
if (dir)
return dir->path;
}
return NULL;
}

View File

@ -26,8 +26,8 @@
#include "inotify-kernel.h" #include "inotify-kernel.h"
#include "inotify-sub.h" #include "inotify-sub.h"
gboolean _ip_startup (void (*event_cb)(ik_event_t *event, inotify_sub *sub)); gboolean _ip_startup (void (*event_cb)(ik_event_t *event, inotify_sub *sub));
gboolean _ip_start_watching (inotify_sub *sub); gboolean _ip_start_watching (inotify_sub *sub);
gboolean _ip_stop_watching (inotify_sub *sub); gboolean _ip_stop_watching (inotify_sub *sub);
const char * _ip_get_path_for_wd (gint32 wd);
#endif #endif

View File

@ -46,7 +46,8 @@ dup_dirname (const gchar *dirname)
inotify_sub* inotify_sub*
_ih_sub_new (const gchar *dirname, _ih_sub_new (const gchar *dirname,
const gchar *filename, const gchar *filename,
gboolean pair_moves,
gpointer user_data) gpointer user_data)
{ {
inotify_sub *sub = NULL; inotify_sub *sub = NULL;
@ -54,8 +55,9 @@ _ih_sub_new (const gchar *dirname,
sub = g_new0 (inotify_sub, 1); sub = g_new0 (inotify_sub, 1);
sub->dirname = dup_dirname (dirname); sub->dirname = dup_dirname (dirname);
sub->filename = g_strdup (filename); sub->filename = g_strdup (filename);
sub->pair_moves = pair_moves;
sub->user_data = user_data; sub->user_data = user_data;
IS_W ("new subscription for %s being setup\n", sub->dirname); IS_W ("new subscription for %s being setup\n", sub->dirname);
return sub; return sub;

View File

@ -30,9 +30,10 @@ typedef struct
gchar* filename; gchar* filename;
gboolean cancelled; gboolean cancelled;
gpointer user_data; gpointer user_data;
gboolean pair_moves;
} inotify_sub; } inotify_sub;
inotify_sub* _ih_sub_new (const gchar* dirname, const gchar* filename, gpointer user_data); inotify_sub* _ih_sub_new (const gchar* dirname, const gchar* filename, gboolean pair_moves, gpointer user_data);
void _ih_sub_free (inotify_sub* sub); void _ih_sub_free (inotify_sub* sub);
#endif /* __INOTIFY_SUB_H */ #endif /* __INOTIFY_SUB_H */