[glib/wip/mount-watcher] 'gio watch' works now



commit 32e9a005eba1265fc2a1b73135cfa933683f1dcd
Author: Ryan Lortie <desrt desrt ca>
Date:   Wed Jan 14 23:35:28 2015 -0500

    'gio watch' works now
    
    ...and it found some issues worth fixing

 gio/Makefile.am              |    7 +-
 gio/gio.c                    |  228 ++++++++++++++++++++++++++++++++++++++----
 gio/glocalfilemonitor.c      |   13 ++-
 gio/inotify/inotify-kernel.c |    6 +-
 gio/inotify/inotify-path.c   |    2 +-
 5 files changed, 233 insertions(+), 23 deletions(-)
---
diff --git a/gio/Makefile.am b/gio/Makefile.am
index 044a954..17a8ed4 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -691,7 +691,12 @@ gio.def: libgio-2.0.la
 gio-2.0.lib: libgio-2.0.la gio.def
        $(AM_V_GEN) lib.exe -machine:@LIB_EXE_MACHINE_FLAG@ -name:libgio-2.0-$(LT_CURRENT_MINUS_AGE).dll 
-def:$(builddir)/gio.def -out:$@
 
-bin_PROGRAMS = gio-querymodules glib-compile-schemas glib-compile-resources gsettings
+bin_PROGRAMS = gio gio-querymodules glib-compile-schemas glib-compile-resources gsettings
+
+gio_LDADD = libgio-2.0.la                      \
+       $(top_builddir)/gobject/libgobject-2.0.la       \
+       $(top_builddir)/glib/libglib-2.0.la             \
+       $(NULL)
 
 glib_compile_resources_LDADD = libgio-2.0.la           \
        $(top_builddir)/gobject/libgobject-2.0.la       \
diff --git a/gio/gio.c b/gio/gio.c
index 83b94a0..0f06649 100644
--- a/gio/gio.c
+++ b/gio/gio.c
@@ -1,28 +1,179 @@
-#include <gio.h>
-
+#include <gio/gio.h>
 
+static gchar **gio_watch_dirs;
+static gchar **gio_watch_files;
+static gchar **gio_watch_direct;
+static gchar **gio_watch_silent;
+static gchar **gio_watch_default;
+static gboolean gio_watch_no_moves;
+static gboolean gio_watch_mounts;
 
 static const GOptionEntry gio_watch_entries[] = {
-  { "dir", 'd', 0, G_OPTION_ARG_NONE, &gio_watch_dir,
-      "Force use of a directory monitor (default: depends on type)" },
-  { "file", 'f', 0, G_OPTION_ARG_NONE, &gio_watch_file,
-      "Force use of a file monitor (default: depends on type)" },
-  { "watch-hardlinks", 'h', 0, G_OPTION_ARG_NONE, &gio_watch_hardlinks,
-      "Monitor changes made via hard links (implies --file)" },
+  { "dir", 'd', 0, G_OPTION_ARG_FILENAME_ARRAY, &gio_watch_dirs,
+      "Monitor a directory (default: depends on type)", "FILENAME" },
+  { "file", 'f', 0, G_OPTION_ARG_FILENAME_ARRAY, &gio_watch_files,
+      "Monitor a file (default: depends on type)", "FILENAME" },
+  { "direct", 'D', 0, G_OPTION_ARG_FILENAME_ARRAY, &gio_watch_direct,
+      "Monitor a file directly (notices changes made via hardlinks)", "FILENAME" },
+  { "silent", 's', 0, G_OPTION_ARG_FILENAME_ARRAY, &gio_watch_silent,
+      "Monitors a file directly, but doesn't report changes", "FILENAME" },
   { "no-moves", 'n', 0, G_OPTION_ARG_NONE, &gio_watch_no_moves,
       "Report moves and renames as simple deleted/created events" },
+  { "mounts", 'm', 0, G_OPTION_ARG_NONE, &gio_watch_mounts,
+      "Watch for mount events" },
+  { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &gio_watch_default },
   { NULL }
 };
 
+static void
+gio_watch_callback (GFileMonitor      *monitor,
+                    GFile             *child,
+                    GFile             *other,
+                    GFileMonitorEvent  event_type,
+                    gpointer           user_data)
+{
+  gchar *child_str;
+  gchar *other_str;
+
+  g_assert (child);
+
+  if (g_file_is_native (child))
+    child_str = g_file_get_path (child);
+  else
+    child_str = g_file_get_uri (child);
+
+  if (other)
+    {
+      if (g_file_is_native (other))
+        other_str = g_file_get_path (other);
+      else
+        other_str = g_file_get_uri (other);
+    }
+  else
+    other_str = g_strdup ("(none)");
+
+  g_print ("%s: ", (gchar *) user_data);
+  switch (event_type)
+    {
+    case G_FILE_MONITOR_EVENT_CHANGED:
+      g_assert (!other);
+      g_print ("%s: changed", child_str);
+      break;
+    case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
+      g_assert (!other);
+      g_print ("%s: changes done", child_str);
+      break;
+    case G_FILE_MONITOR_EVENT_DELETED:
+      g_assert (!other);
+      g_print ("%s: deleted", child_str);
+      break;
+    case G_FILE_MONITOR_EVENT_CREATED:
+      g_assert (!other);
+      g_print ("%s: created", child_str);
+      break;
+    case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED:
+      g_assert (!other);
+      g_print ("%s: attributes changed", child_str);
+      break;
+    case G_FILE_MONITOR_EVENT_PRE_UNMOUNT:
+      g_assert (!other);
+      g_print ("%s: pre-unmount", child_str);
+      break;
+    case G_FILE_MONITOR_EVENT_UNMOUNTED:
+      g_assert (!other);
+      g_print ("%s: unmounted", child_str);
+      break;
+    case G_FILE_MONITOR_EVENT_MOVED_IN:
+      g_print ("%s: moved in", child_str);
+      if (other)
+        g_print (" (from %s)", other_str);
+      break;
+    case G_FILE_MONITOR_EVENT_MOVED_OUT:
+      g_print ("%s: moved out", child_str);
+      if (other)
+        g_print (" (to %s)", other_str);
+      break;
+    case G_FILE_MONITOR_EVENT_RENAMED:
+      g_assert (other);
+      g_print ("%s: renamed to %s\n", child_str, other_str);
+      break;
+
+    case G_FILE_MONITOR_EVENT_MOVED:
+    default:
+      g_assert_not_reached ();
+    }
+
+  g_free (child_str);
+  g_free (other_str);
+  g_print ("\n");
+}
+
+typedef enum
+{
+  WATCH_DIR,
+  WATCH_FILE,
+  WATCH_AUTO
+} WatchType;
+
+static gboolean
+add_watch (const gchar       *cmdline,
+           WatchType          watch_type,
+           GFileMonitorFlags  flags,
+           gboolean           connect_handler)
+{
+  GFileMonitor *monitor = NULL;
+  GError *error = NULL;
+  GFile *file;
+
+  file = g_file_new_for_commandline_arg (cmdline);
+
+  if (watch_type == WATCH_AUTO)
+    {
+      GFileInfo *info;
+      guint32 type;
+
+      info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TYPE, G_FILE_QUERY_INFO_NONE, NULL, &error);
+      if (!info)
+        goto err;
+
+      type = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_STANDARD_TYPE);
+      watch_type = (type == G_FILE_TYPE_DIRECTORY) ? WATCH_DIR : WATCH_FILE;
+    }
+
+  if (watch_type == WATCH_DIR)
+    monitor = g_file_monitor_directory (file, flags, NULL, &error);
+  else
+    monitor = g_file_monitor (file, flags, NULL, &error);
+
+  if (!monitor)
+    goto err;
+
+  if (connect_handler)
+    g_signal_connect (monitor, "changed", G_CALLBACK (gio_watch_callback), g_strdup (cmdline));
+
+  monitor = NULL; /* leak */
+
+  return TRUE;
+
+err:
+  g_printerr ("error: %s: %s", cmdline, error->message);
+  g_error_free (error);
+
+  return FALSE;
+}
+
 static int
 gio_watch (int     argc,
            gchar **argv)
 {
   GOptionContext *context;
-  GError **error = NULL;
+  GError *error = NULL;
+  GFileMonitorFlags flags;
+  guint total = 0;
+  guint i;
 
-  context = g_option_context_new ("- monitor files and directories");
-  g_option_context_add_main_entries (context, &gio_watch_entries, NULL);
+  context = g_option_context_new ("FILENAMES... - monitor files and directories");
+  g_option_context_add_main_entries (context, gio_watch_entries, NULL);
   if (!g_option_context_parse (context, &argc, &argv, &error))
     {
       g_printerr ("option parsing failed: %s\n", error->message);
@@ -30,16 +181,57 @@ gio_watch (int     argc,
       return 1;
     }
 
-  gio_watch_file |= gio_watch_hardlinks;
+  flags = (gio_watch_no_moves ? 0 : G_FILE_MONITOR_WATCH_MOVES) |
+          (gio_watch_mounts ? G_FILE_MONITOR_WATCH_MOUNTS : 0);
 
-  if (gio_watch_file && gio_watch_dir)
+  if (gio_watch_dirs)
     {
-      g_printerr ("can only specify one of --dir and --file (or --watch-hardlinks)");
-      return 1;
+      for (i = 0; gio_watch_dirs[i]; i++)
+        if (!add_watch (gio_watch_dirs[i], WATCH_DIR, flags, TRUE))
+          return 1;
+      total++;
+    }
+
+  if (gio_watch_files)
+    {
+      for (i = 0; gio_watch_files[i]; i++)
+        if (!add_watch (gio_watch_files[i], WATCH_FILE, flags, TRUE))
+          return 1;
+      total++;
     }
 
-  if (argv[1])
+  if (gio_watch_direct)
+    {
+      for (i = 0; gio_watch_direct[i]; i++)
+        if (!add_watch (gio_watch_direct[i], WATCH_FILE, flags | G_FILE_MONITOR_WATCH_HARD_LINKS, TRUE))
+          return 1;
+      total++;
+    }
+
+  if (gio_watch_silent)
+    {
+      for (i = 0; gio_watch_silent[i]; i++)
+        if (!add_watch (gio_watch_silent[i], WATCH_FILE, flags | G_FILE_MONITOR_WATCH_HARD_LINKS, FALSE))
+          return 1;
+      total++;
+    }
+
+  if (gio_watch_default)
+    {
+      for (i = 0; gio_watch_default[i]; i++)
+        if (!add_watch (gio_watch_default[i], WATCH_AUTO, flags, TRUE))
+          return 1;
+      total++;
+    }
+
+  if (!total)
+    {
+      g_printerr ("error: must give at least one file to monitor\n");
+      return 1;
+    }
 
+  while (TRUE)
+    g_main_context_iteration (NULL, TRUE);
 }
 
 int
@@ -55,8 +247,8 @@ main (int    argc,
 
     }
 
-  cmd = g_strconcat (argv[0], " ", argv[1]);
+  cmd = g_strconcat (argv[0], " ", argv[1], NULL);
   argv[1] = cmd;
 
-  gio_watch (argv + 2);
+  return gio_watch (argc - 1, argv + 1);
 }
diff --git a/gio/glocalfilemonitor.c b/gio/glocalfilemonitor.c
index 1029d72..44b24a6 100644
--- a/gio/glocalfilemonitor.c
+++ b/gio/glocalfilemonitor.c
@@ -287,6 +287,15 @@ g_file_monitor_source_send_event (GFileMonitorSource *fms,
   g_file_monitor_source_queue_event (fms, event_type, child, other);
 }
 
+static void
+g_file_monitor_source_send_synthetic_created (GFileMonitorSource *fms,
+                                              const gchar        *child)
+{
+  g_file_monitor_source_file_changes_done (fms, child);
+  g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CREATED, child, NULL);
+  g_file_monitor_source_queue_event (fms, G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT, child, NULL);
+}
+
 static gboolean
 is_basename (const gchar *name)
 {
@@ -338,7 +347,7 @@ g_file_monitor_source_handle_event (GFileMonitorSource *fms,
       if (fms->flags & G_FILE_MONITOR_WATCH_MOVES)
         g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_MOVED_IN, child, other);
       else
-        g_file_monitor_source_file_created (fms, child, event_time);
+        g_file_monitor_source_send_synthetic_created (fms, child);
       break;
 
     case G_FILE_MONITOR_EVENT_MOVED_OUT:
@@ -374,7 +383,7 @@ g_file_monitor_source_handle_event (GFileMonitorSource *fms,
       else
         {
           g_file_monitor_source_send_event (fms, G_FILE_MONITOR_EVENT_DELETED, child, NULL);
-          g_file_monitor_source_file_created (fms, child, event_time);
+          g_file_monitor_source_send_synthetic_created (fms, child);
         }
       break;
 
diff --git a/gio/inotify/inotify-kernel.c b/gio/inotify/inotify-kernel.c
index 3efe628..305b5c8 100644
--- a/gio/inotify/inotify-kernel.c
+++ b/gio/inotify/inotify-kernel.c
@@ -72,7 +72,10 @@ void
 _ik_event_free (ik_event_t *event)
 {
   if (event->pair)
-    _ik_event_free (event->pair);
+    {
+      event->pair->pair = NULL;
+      _ik_event_free (event->pair);
+    }
 
   g_free (event->name);
   g_free (event);
@@ -148,6 +151,7 @@ ik_source_try_to_pair_head (InotifyKernelSource *iks)
           g_queue_remove (&iks->queue, candidate);
           candidate->is_second_in_pair = TRUE;
           head->pair = candidate;
+          candidate->pair = head;
           return;
         }
     }
diff --git a/gio/inotify/inotify-path.c b/gio/inotify/inotify-path.c
index 42cd878..830f514 100644
--- a/gio/inotify/inotify-path.c
+++ b/gio/inotify/inotify-path.c
@@ -547,7 +547,7 @@ ip_event_callback (ik_event_t *event)
       file_list = g_hash_table_lookup (wd_file_hash, GINT_TO_POINTER (event->pair->wd));
 
       if (event->pair->mask & IP_INOTIFY_DIR_MASK)
-        ip_event_dispatch (dir_list, file_list, event);
+        ip_event_dispatch (dir_list, file_list, event->pair);
     }
 
   /* We have to manage the missing list


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