[glib] Move event support in the inotify backend



commit 48f74cab395044a07e1220440cdc816db01b9984
Author: Christian Kellner <gicmo gnome org>
Date:   Thu Feb 18 15:49:58 2010 +0100

    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>.

 gio/inotify/ginotifydirectorymonitor.c |    7 +++-
 gio/inotify/ginotifyfilemonitor.c      |    9 +++++-
 gio/inotify/inotify-helper.c           |   49 ++++++++++++++++++++++++++++----
 gio/inotify/inotify-kernel.c           |    4 +-
 gio/inotify/inotify-path.c             |   18 +++++++++++
 gio/inotify/inotify-path.h             |    8 ++--
 gio/inotify/inotify-sub.c              |    6 ++-
 gio/inotify/inotify-sub.h              |    3 +-
 8 files changed, 86 insertions(+), 18 deletions(-)
---
diff --git a/gio/inotify/ginotifydirectorymonitor.c b/gio/inotify/ginotifydirectorymonitor.c
index f6fcde7..dcc97a0 100644
--- a/gio/inotify/ginotifydirectorymonitor.c
+++ b/gio/inotify/ginotifydirectorymonitor.c
@@ -76,7 +76,8 @@ g_inotify_directory_monitor_constructor (GType type,
   GInotifyDirectoryMonitor *inotify_monitor;
   const gchar *dirname = 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));
   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();
   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
    * kind of error and an assertion is probably too hard */
   g_assert (sub != NULL);
diff --git a/gio/inotify/ginotifyfilemonitor.c b/gio/inotify/ginotifyfilemonitor.c
index 8e572ca..f87f079 100644
--- a/gio/inotify/ginotifyfilemonitor.c
+++ b/gio/inotify/ginotifyfilemonitor.c
@@ -39,6 +39,7 @@ struct _GInotifyFileMonitor
   gchar *filename;
   gchar *dirname;
   inotify_sub *sub;
+  gboolean pair_moves;
 };
 
 static gboolean g_inotify_file_monitor_cancel (GFileMonitor* monitor);
@@ -90,6 +91,7 @@ g_inotify_file_monitor_constructor (GType                  type,
   GInotifyFileMonitor *inotify_monitor;
   const gchar *filename = NULL;
   inotify_sub *sub = NULL;
+  gboolean pair_moves;
   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));
@@ -113,7 +115,12 @@ g_inotify_file_monitor_constructor (GType                  type,
   ret_ih_startup = _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
    * kind of error and an assertion is probably too hard */
diff --git a/gio/inotify/inotify-helper.c b/gio/inotify/inotify-helper.c
index 14c60b7..5572f0d 100644
--- a/gio/inotify/inotify-helper.c
+++ b/gio/inotify/inotify-helper.c
@@ -138,6 +138,32 @@ _ih_sub_cancel (inotify_sub *sub)
   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
 ih_event_callback (ik_event_t  *event, 
@@ -147,22 +173,33 @@ ih_event_callback (ik_event_t  *event,
   GFileMonitorEvent eflags;
   GFile* parent;
   GFile* child;
+  GFile* other;
   
   eflags = ih_mask_to_EventFlags (event->mask);
   parent = g_file_new_for_path (sub->dirname);
-  if (event->name)
-    fullpath = g_strdup_printf ("%s/%s", sub->dirname, event->name);
-  else
-    fullpath = g_strdup_printf ("%s/", sub->dirname);
-  
+  fullpath = _ih_fullpath_from_event (event, sub->dirname);
   child = g_file_new_for_path (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),
-			     child, NULL, eflags);
+			     child, other, eflags);
 
   g_object_unref (child);
   g_object_unref (parent);
+  if (other)
+    g_object_unref (other);
 }
 
 static void
diff --git a/gio/inotify/inotify-kernel.c b/gio/inotify/inotify-kernel.c
index 6e559a7..d6385f9 100644
--- a/gio/inotify/inotify-kernel.c
+++ b/gio/inotify/inotify-kernel.c
@@ -32,9 +32,9 @@
 #include <sys/inotify.h>
 
 /* 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 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 GQueue *events_to_process = NULL;
diff --git a/gio/inotify/inotify-path.c b/gio/inotify/inotify-path.c
index 3327598..9ff20c8 100644
--- a/gio/inotify/inotify-path.c
+++ b/gio/inotify/inotify-path.c
@@ -420,3 +420,21 @@ ip_event_callback (ik_event_t *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;
+}
diff --git a/gio/inotify/inotify-path.h b/gio/inotify/inotify-path.h
index c613b9f..327dc70 100644
--- a/gio/inotify/inotify-path.h
+++ b/gio/inotify/inotify-path.h
@@ -26,8 +26,8 @@
 #include "inotify-kernel.h"
 #include "inotify-sub.h"
 
-gboolean _ip_startup (void (*event_cb)(ik_event_t *event, inotify_sub *sub));
-gboolean _ip_start_watching (inotify_sub *sub);
-gboolean _ip_stop_watching  (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_stop_watching  (inotify_sub *sub);
+const char * _ip_get_path_for_wd (gint32 wd);
 #endif
diff --git a/gio/inotify/inotify-sub.c b/gio/inotify/inotify-sub.c
index 2b71c93..fa2e934 100644
--- a/gio/inotify/inotify-sub.c
+++ b/gio/inotify/inotify-sub.c
@@ -46,7 +46,8 @@ dup_dirname (const gchar *dirname)
 
 inotify_sub*
 _ih_sub_new (const gchar *dirname, 
-             const gchar *filename, 
+             const gchar *filename,
+	     gboolean     pair_moves,
              gpointer     user_data)
 {
   inotify_sub *sub = NULL;
@@ -54,8 +55,9 @@ _ih_sub_new (const gchar *dirname,
   sub = g_new0 (inotify_sub, 1);
   sub->dirname = dup_dirname (dirname);
   sub->filename = g_strdup (filename);
+  sub->pair_moves = pair_moves;
   sub->user_data = user_data;
-  
+
   IS_W ("new subscription for %s being setup\n", sub->dirname);
   
   return sub;
diff --git a/gio/inotify/inotify-sub.h b/gio/inotify/inotify-sub.h
index 36561e7..7c9b087 100644
--- a/gio/inotify/inotify-sub.h
+++ b/gio/inotify/inotify-sub.h
@@ -30,9 +30,10 @@ typedef struct
 	gchar*   filename;
 	gboolean cancelled;
 	gpointer user_data;
+        gboolean pair_moves;
 } 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);
 
 #endif /* __INOTIFY_SUB_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]