Move event support in the inotify backend
authorChristian Kellner <gicmo@gnome.org>
Thu, 18 Feb 2010 14:49:58 +0000 (15:49 +0100)
committerChristian Kellner <gicmo@gnome.org>
Thu, 18 Feb 2010 14:50:26 +0000 (15:50 +0100)
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
gio/inotify/ginotifyfilemonitor.c
gio/inotify/inotify-helper.c
gio/inotify/inotify-kernel.c
gio/inotify/inotify-path.c
gio/inotify/inotify-path.h
gio/inotify/inotify-sub.c
gio/inotify/inotify-sub.h

index f6fcde7f72e662f360fc4880d308f934334ebf3c..dcc97a0d0aa87d2060e78b2f207ac678d1096c9c 100644 (file)
@@ -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);
index 8e572ca705faf1919319c8f42405e0409b7f522f..f87f07943b2ba91239197e9f5f2ad8a29db0d0f5 100644 (file)
@@ -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 */
index 14c60b7d0ba78889f29af62966b7822eab2d18b9..5572f0d88b1eb3f8d15e133fe57231be38b8a3b8 100644 (file)
@@ -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
index 6e559a7b8b7e47629456d20b85f5836e46cfafcf..d6385f9394539cb269dfc7009ec387efa3d5bb8f 100644 (file)
@@ -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;
index 33275989c755a1b930592686c87d76f9720b6a14..9ff20c8eb0a308f78f9429a3a4f50129374d7fe9 100644 (file)
@@ -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;
+}
index c613b9f82dc0cbf7d16f8709ba806738404bd0da..327dc70a376b115a716ef7458f6527c0c25f83fb 100644 (file)
@@ -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
index 2b71c930da14c648a964bc16ffd99f9735a22d93..fa2e934a7f1e2aad2de82749cdc6849d9a256ac9 100644 (file)
@@ -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;
index 36561e74c7aa300a26bc419320e858755903664f..7c9b08769e78b986a11b9828ac3958c5fa4acfe3 100644 (file)
@@ -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 */