Blame gio/fam/gfamfilemonitor.c

Packit ae235b
/*
Packit ae235b
 * Copyright © 2015 Canonical Limited
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This library is distributed in the hope that it will be useful,
Packit ae235b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ae235b
 * Lesser General Public License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General
Packit ae235b
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit ae235b
 *
Packit ae235b
 * Author: Ryan Lortie <desrt@desrt.ca>
Packit ae235b
 */
Packit ae235b
Packit ae235b
#include "config.h"
Packit ae235b
Packit ae235b
#include <gio/glocalfilemonitor.h>
Packit ae235b
#include <gio/giomodule.h>
Packit ae235b
#include "glib-private.h"
Packit ae235b
#include <glib-unix.h>
Packit ae235b
#include <fam.h>
Packit ae235b
Packit ae235b
static GMutex         fam_lock;
Packit ae235b
static gboolean       fam_initialised;
Packit ae235b
static FAMConnection  fam_connection;
Packit ae235b
static GSource       *fam_source;
Packit ae235b
Packit ae235b
#define G_TYPE_FAM_FILE_MONITOR      (g_fam_file_monitor_get_type ())
Packit ae235b
#define G_FAM_FILE_MONITOR(inst)     (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
Packit ae235b
                                      G_TYPE_FAM_FILE_MONITOR, GFamFileMonitor))
Packit ae235b
Packit ae235b
typedef GLocalFileMonitorClass GFamFileMonitorClass;
Packit ae235b
Packit ae235b
typedef struct
Packit ae235b
{
Packit ae235b
  GLocalFileMonitor parent_instance;
Packit ae235b
Packit ae235b
  FAMRequest request;
Packit ae235b
} GFamFileMonitor;
Packit ae235b
Packit ae235b
static GType g_fam_file_monitor_get_type (void);
Packit ae235b
G_DEFINE_DYNAMIC_TYPE (GFamFileMonitor, g_fam_file_monitor, G_TYPE_LOCAL_FILE_MONITOR)
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
g_fam_file_monitor_callback (gint         fd,
Packit ae235b
                             GIOCondition condition,
Packit ae235b
                             gpointer     user_data)
Packit ae235b
{
Packit ae235b
  gint64 now = g_source_get_time (fam_source);
Packit ae235b
Packit ae235b
  g_mutex_lock (&fam_lock);
Packit ae235b
Packit ae235b
  while (FAMPending (&fam_connection))
Packit ae235b
    {
Packit ae235b
      const gchar *child;
Packit ae235b
      FAMEvent ev;
Packit ae235b
Packit ae235b
      if (FAMNextEvent (&fam_connection, &ev) != 1)
Packit ae235b
        {
Packit ae235b
          /* The daemon died.  We're in a really bad situation now
Packit ae235b
           * because we potentially have a bunch of request structures
Packit ae235b
           * outstanding which no longer make any sense to anyone.
Packit ae235b
           *
Packit ae235b
           * The best thing that we can do is do nothing.  Notification
Packit ae235b
           * won't work anymore for this process.
Packit ae235b
           */
Packit ae235b
          g_mutex_unlock (&fam_lock);
Packit ae235b
Packit ae235b
          g_warning ("Lost connection to FAM (file monitoring) service.  Expect no further file monitor events.");
Packit ae235b
Packit ae235b
          return FALSE;
Packit ae235b
        }
Packit ae235b
Packit ae235b
      /* We expect ev.filename to be a relative path for children in a
Packit ae235b
       * monitored directory, and an absolute path for a monitored file
Packit ae235b
       * or the directory itself.
Packit ae235b
       */
Packit ae235b
      if (ev.filename[0] != '/')
Packit ae235b
        child = ev.filename;
Packit ae235b
      else
Packit ae235b
        child = NULL;
Packit ae235b
Packit ae235b
      switch (ev.code)
Packit ae235b
        {
Packit ae235b
        case FAMAcknowledge:
Packit ae235b
          g_source_unref (ev.userdata);
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case FAMChanged:
Packit ae235b
          g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_CHANGED, child, NULL, NULL, now);
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case FAMDeleted:
Packit ae235b
          g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_DELETED, child, NULL, NULL, now);
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        case FAMCreated:
Packit ae235b
          g_file_monitor_source_handle_event (ev.userdata, G_FILE_MONITOR_EVENT_CREATED, child, NULL, NULL, now);
Packit ae235b
          break;
Packit ae235b
Packit ae235b
        default:
Packit ae235b
          /* unknown type */
Packit ae235b
          break;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_mutex_unlock (&fam_lock);
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
g_fam_file_monitor_is_supported (void)
Packit ae235b
{
Packit ae235b
  g_mutex_lock (&fam_lock);
Packit ae235b
Packit ae235b
  if (!fam_initialised)
Packit ae235b
    {
Packit ae235b
      fam_initialised = FAMOpen2 (&fam_connection, "GLib GIO") == 0;
Packit ae235b
Packit ae235b
      if (fam_initialised)
Packit ae235b
        {
Packit ae235b
#ifdef HAVE_FAM_NO_EXISTS
Packit ae235b
          /* This is a gamin extension that avoids sending all the
Packit ae235b
           * Exists event for dir monitors
Packit ae235b
           */
Packit ae235b
          FAMNoExists (&fam_connection);
Packit ae235b
#endif
Packit ae235b
Packit ae235b
          fam_source = g_unix_fd_source_new (FAMCONNECTION_GETFD (&fam_connection), G_IO_IN);
Packit ae235b
          g_source_set_callback (fam_source, (GSourceFunc) g_fam_file_monitor_callback, NULL, NULL);
Packit ae235b
          g_source_attach (fam_source, GLIB_PRIVATE_CALL(g_get_worker_context) ());
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_mutex_unlock (&fam_lock);
Packit ae235b
Packit ae235b
  return fam_initialised;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
g_fam_file_monitor_cancel (GFileMonitor *monitor)
Packit ae235b
{
Packit ae235b
  GFamFileMonitor *gffm = G_FAM_FILE_MONITOR (monitor);
Packit ae235b
Packit ae235b
  g_mutex_lock (&fam_lock);
Packit ae235b
Packit ae235b
  g_assert (fam_initialised);
Packit ae235b
Packit ae235b
  FAMCancelMonitor (&fam_connection, &gffm->request);
Packit ae235b
Packit ae235b
  g_mutex_unlock (&fam_lock);
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_fam_file_monitor_start (GLocalFileMonitor  *local_monitor,
Packit ae235b
                          const gchar        *dirname,
Packit ae235b
                          const gchar        *basename,
Packit ae235b
                          const gchar        *filename,
Packit ae235b
                          GFileMonitorSource *source)
Packit ae235b
{
Packit ae235b
  GFamFileMonitor *gffm = G_FAM_FILE_MONITOR (local_monitor);
Packit ae235b
Packit ae235b
  g_mutex_lock (&fam_lock);
Packit ae235b
Packit ae235b
  g_assert (fam_initialised);
Packit ae235b
Packit ae235b
  g_source_ref ((GSource *) source);
Packit ae235b
Packit ae235b
  if (dirname)
Packit ae235b
    FAMMonitorDirectory (&fam_connection, dirname, &gffm->request, source);
Packit ae235b
  else
Packit ae235b
    FAMMonitorFile (&fam_connection, filename, &gffm->request, source);
Packit ae235b
Packit ae235b
  g_mutex_unlock (&fam_lock);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_fam_file_monitor_init (GFamFileMonitor* monitor)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_fam_file_monitor_class_init (GFamFileMonitorClass *class)
Packit ae235b
{
Packit ae235b
  GFileMonitorClass *file_monitor_class = G_FILE_MONITOR_CLASS (class);
Packit ae235b
Packit ae235b
  class->is_supported = g_fam_file_monitor_is_supported;
Packit ae235b
  class->start = g_fam_file_monitor_start;
Packit ae235b
  file_monitor_class->cancel = g_fam_file_monitor_cancel;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_fam_file_monitor_class_finalize (GFamFileMonitorClass *class)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
void
Packit ae235b
g_io_module_load (GIOModule *module)
Packit ae235b
{
Packit ae235b
  g_type_module_use (G_TYPE_MODULE (module));
Packit ae235b
Packit ae235b
  g_fam_file_monitor_register_type (G_TYPE_MODULE (module));
Packit ae235b
Packit ae235b
  g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
Packit ae235b
                                 G_TYPE_FAM_FILE_MONITOR, "fam", 10);
Packit ae235b
Packit ae235b
  g_io_extension_point_implement (G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
Packit ae235b
                                 G_TYPE_FAM_FILE_MONITOR, "fam", 10);
Packit ae235b
}
Packit ae235b
Packit ae235b
void
Packit ae235b
g_io_module_unload (GIOModule *module)
Packit ae235b
{
Packit ae235b
  g_assert_not_reached ();
Packit ae235b
}
Packit ae235b
Packit ae235b
char **
Packit ae235b
g_io_module_query (void)
Packit ae235b
{
Packit ae235b
  char *eps[] = {
Packit ae235b
    G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME,
Packit ae235b
    G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME,
Packit ae235b
    NULL
Packit ae235b
  };
Packit ae235b
Packit ae235b
  return g_strdupv (eps);
Packit ae235b
}