Blame gio/inotify/inotify-path.c

Packit ae235b
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 8 -*- */
Packit ae235b
Packit ae235b
/* inotify-path.c - GVFS Monitor based on inotify.
Packit ae235b
Packit ae235b
   Copyright (C) 2006 John McCutchan
Packit ae235b
   Copyright (C) 2009 Codethink 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 Public License
Packit ae235b
   along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit ae235b
Packit ae235b
   Authors:
Packit ae235b
		 John McCutchan <john@johnmccutchan.com>
Packit ae235b
                 Ryan Lortie <desrt@desrt.ca>
Packit ae235b
*/
Packit ae235b
Packit ae235b
#include "config.h"
Packit ae235b
Packit ae235b
/* Don't put conflicting kernel types in the global namespace: */
Packit ae235b
#define __KERNEL_STRICT_NAMES
Packit ae235b
Packit ae235b
#include <sys/inotify.h>
Packit ae235b
#include <string.h>
Packit ae235b
#include <glib.h>
Packit ae235b
#include "inotify-kernel.h"
Packit ae235b
#include "inotify-path.h"
Packit ae235b
#include "inotify-missing.h"
Packit ae235b
Packit ae235b
#define IP_INOTIFY_DIR_MASK (IN_MODIFY|IN_ATTRIB|IN_MOVED_FROM|IN_MOVED_TO|IN_DELETE|IN_CREATE|IN_DELETE_SELF|IN_UNMOUNT|IN_MOVE_SELF|IN_CLOSE_WRITE)
Packit ae235b
Packit ae235b
#define IP_INOTIFY_FILE_MASK (IN_MODIFY|IN_ATTRIB|IN_CLOSE_WRITE)
Packit ae235b
Packit ae235b
/* Older libcs don't have this */
Packit ae235b
#ifndef IN_ONLYDIR
Packit ae235b
#define IN_ONLYDIR 0  
Packit ae235b
#endif
Packit ae235b
Packit ae235b
typedef struct ip_watched_file_s {
Packit ae235b
  gchar *filename;
Packit ae235b
  gchar *path;
Packit ae235b
  gint32 wd;
Packit ae235b
Packit ae235b
  GList *subs;
Packit ae235b
} ip_watched_file_t;
Packit ae235b
Packit ae235b
typedef struct ip_watched_dir_s {
Packit ae235b
  char *path;
Packit ae235b
  /* TODO: We need to maintain a tree of watched directories
Packit ae235b
   * so that we can deliver move/delete events to sub folders.
Packit ae235b
   * Or the application could do it...
Packit ae235b
   */
Packit ae235b
  struct ip_watched_dir_s* parent;
Packit ae235b
  GList*	 children;
Packit ae235b
Packit ae235b
  /* basename -> ip_watched_file_t
Packit ae235b
   * Maps basename to a ip_watched_file_t if the file is currently
Packit ae235b
   * being directly watched for changes (ie: 'hardlinks' mode).
Packit ae235b
   */
Packit ae235b
  GHashTable *files_hash;
Packit ae235b
Packit ae235b
  /* Inotify state */
Packit ae235b
  gint32 wd;
Packit ae235b
  
Packit ae235b
  /* List of inotify subscriptions */
Packit ae235b
  GList *subs;
Packit ae235b
} ip_watched_dir_t;
Packit ae235b
Packit ae235b
static gboolean     ip_debug_enabled = FALSE;
Packit ae235b
#define IP_W if (ip_debug_enabled) g_warning
Packit ae235b
Packit ae235b
/* path -> ip_watched_dir */
Packit ae235b
static GHashTable * path_dir_hash = NULL;
Packit ae235b
/* inotify_sub * -> ip_watched_dir *
Packit ae235b
 *
Packit ae235b
 * Each subscription is attached to a watched directory or it is on
Packit ae235b
 * the missing list
Packit ae235b
 */
Packit ae235b
static GHashTable * sub_dir_hash = NULL;
Packit ae235b
/* This hash holds GLists of ip_watched_dir_t *'s
Packit ae235b
 * We need to hold a list because symbolic links can share
Packit ae235b
 * the same wd
Packit ae235b
 */
Packit ae235b
static GHashTable * wd_dir_hash = NULL;
Packit ae235b
/* This hash holds GLists of ip_watched_file_t *'s
Packit ae235b
 * We need to hold a list because links can share
Packit ae235b
 * the same wd
Packit ae235b
 */
Packit ae235b
static GHashTable * wd_file_hash = NULL;
Packit ae235b
Packit ae235b
static ip_watched_dir_t *ip_watched_dir_new  (const char       *path,
Packit ae235b
					      int               wd);
Packit ae235b
static void              ip_watched_dir_free (ip_watched_dir_t *dir);
Packit ae235b
static gboolean          ip_event_callback   (ik_event_t       *event);
Packit ae235b
Packit ae235b
Packit ae235b
static gboolean (*event_callback)(ik_event_t *event, inotify_sub *sub, gboolean file_event);
Packit ae235b
Packit ae235b
gboolean
Packit ae235b
_ip_startup (gboolean (*cb)(ik_event_t *event, inotify_sub *sub, gboolean file_event))
Packit ae235b
{
Packit ae235b
  static gboolean initialized = FALSE;
Packit ae235b
  static gboolean result = FALSE;
Packit ae235b
  
Packit ae235b
  if (initialized == TRUE)
Packit ae235b
    return result;
Packit ae235b
Packit ae235b
  event_callback = cb;
Packit ae235b
  result = _ik_startup (ip_event_callback);
Packit ae235b
Packit ae235b
  if (!result)
Packit ae235b
    return FALSE;
Packit ae235b
Packit ae235b
  path_dir_hash = g_hash_table_new (g_str_hash, g_str_equal);
Packit ae235b
  sub_dir_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
Packit ae235b
  wd_dir_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
Packit ae235b
  wd_file_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
Packit ae235b
  
Packit ae235b
  initialized = TRUE;
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_map_path_dir (const char       *path, 
Packit ae235b
                 ip_watched_dir_t *dir)
Packit ae235b
{
Packit ae235b
  g_assert (path && dir);
Packit ae235b
  g_hash_table_insert (path_dir_hash, dir->path, dir);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_map_sub_dir (inotify_sub      *sub, 
Packit ae235b
                ip_watched_dir_t *dir)
Packit ae235b
{
Packit ae235b
  /* Associate subscription and directory */
Packit ae235b
  g_assert (dir && sub);
Packit ae235b
  g_hash_table_insert (sub_dir_hash, sub, dir);
Packit ae235b
  dir->subs = g_list_prepend (dir->subs, sub);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_map_wd_dir (gint32            wd, 
Packit ae235b
               ip_watched_dir_t *dir)
Packit ae235b
{
Packit ae235b
  GList *dir_list;
Packit ae235b
  
Packit ae235b
  g_assert (wd >= 0 && dir);
Packit ae235b
  dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER (wd));
Packit ae235b
  dir_list = g_list_prepend (dir_list, dir);
Packit ae235b
  g_hash_table_replace (wd_dir_hash, GINT_TO_POINTER (dir->wd), dir_list);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_map_wd_file (gint32             wd,
Packit ae235b
                ip_watched_file_t *file)
Packit ae235b
{
Packit ae235b
  GList *file_list;
Packit ae235b
Packit ae235b
  g_assert (wd >= 0 && file);
Packit ae235b
  file_list = g_hash_table_lookup (wd_file_hash, GINT_TO_POINTER (wd));
Packit ae235b
  file_list = g_list_prepend (file_list, file);
Packit ae235b
  g_hash_table_replace (wd_file_hash, GINT_TO_POINTER (wd), file_list);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_unmap_wd_file (gint32             wd,
Packit ae235b
                  ip_watched_file_t *file)
Packit ae235b
{
Packit ae235b
  GList *file_list = g_hash_table_lookup (wd_file_hash, GINT_TO_POINTER (wd));
Packit ae235b
Packit ae235b
  if (!file_list)
Packit ae235b
    return;
Packit ae235b
Packit ae235b
  g_assert (wd >= 0 && file);
Packit ae235b
  file_list = g_list_remove (file_list, file);
Packit ae235b
  if (file_list == NULL)
Packit ae235b
    g_hash_table_remove (wd_file_hash, GINT_TO_POINTER (wd));
Packit ae235b
  else
Packit ae235b
    g_hash_table_replace (wd_file_hash, GINT_TO_POINTER (wd), file_list);
Packit ae235b
}
Packit ae235b
Packit ae235b
Packit ae235b
static ip_watched_file_t *
Packit ae235b
ip_watched_file_new (const gchar *dirname,
Packit ae235b
                     const gchar *filename)
Packit ae235b
{
Packit ae235b
  ip_watched_file_t *file;
Packit ae235b
Packit ae235b
  file = g_new0 (ip_watched_file_t, 1);
Packit ae235b
  file->path = g_strjoin ("/", dirname, filename, NULL);
Packit ae235b
  file->filename = g_strdup (filename);
Packit ae235b
  file->wd = -1;
Packit ae235b
Packit ae235b
  return file;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_watched_file_free (ip_watched_file_t *file)
Packit ae235b
{
Packit ae235b
  g_assert (file->subs == NULL);
Packit ae235b
  g_free (file->filename);
Packit ae235b
  g_free (file->path);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_watched_file_add_sub (ip_watched_file_t *file,
Packit ae235b
                         inotify_sub       *sub)
Packit ae235b
{
Packit ae235b
  file->subs = g_list_prepend (file->subs, sub);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_watched_file_start (ip_watched_file_t *file)
Packit ae235b
{
Packit ae235b
  if (file->wd < 0)
Packit ae235b
    {
Packit ae235b
      gint err;
Packit ae235b
Packit ae235b
      file->wd = _ik_watch (file->path,
Packit ae235b
                            IP_INOTIFY_FILE_MASK,
Packit ae235b
                            &err;;
Packit ae235b
Packit ae235b
      if (file->wd >= 0)
Packit ae235b
        ip_map_wd_file (file->wd, file);
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_watched_file_stop (ip_watched_file_t *file)
Packit ae235b
{
Packit ae235b
  if (file->wd >= 0)
Packit ae235b
    {
Packit ae235b
      _ik_ignore (file->path, file->wd);
Packit ae235b
      ip_unmap_wd_file (file->wd, file);
Packit ae235b
      file->wd = -1;
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
gboolean
Packit ae235b
_ip_start_watching (inotify_sub *sub)
Packit ae235b
{
Packit ae235b
  gint32 wd;
Packit ae235b
  int err;
Packit ae235b
  ip_watched_dir_t *dir;
Packit ae235b
  
Packit ae235b
  g_assert (sub);
Packit ae235b
  g_assert (!sub->cancelled);
Packit ae235b
  g_assert (sub->dirname);
Packit ae235b
  
Packit ae235b
  IP_W ("Starting to watch %s\n", sub->dirname);
Packit ae235b
  dir = g_hash_table_lookup (path_dir_hash, sub->dirname);
Packit ae235b
Packit ae235b
  if (dir == NULL)
Packit ae235b
    {
Packit ae235b
      IP_W ("Trying to add inotify watch ");
Packit ae235b
      wd = _ik_watch (sub->dirname, IP_INOTIFY_DIR_MASK|IN_ONLYDIR, &err;;
Packit ae235b
      if (wd < 0)
Packit ae235b
        {
Packit ae235b
          IP_W ("Failed\n");
Packit ae235b
          return FALSE;
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          /* Create new watched directory and associate it with the
Packit ae235b
           * wd hash and path hash
Packit ae235b
           */
Packit ae235b
          IP_W ("Success\n");
Packit ae235b
          dir = ip_watched_dir_new (sub->dirname, wd);
Packit ae235b
          ip_map_wd_dir (wd, dir);
Packit ae235b
          ip_map_path_dir (sub->dirname, dir);
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    IP_W ("Already watching\n");
Packit ae235b
Packit ae235b
  if (sub->hardlinks)
Packit ae235b
    {
Packit ae235b
      ip_watched_file_t *file;
Packit ae235b
Packit ae235b
      file = g_hash_table_lookup (dir->files_hash, sub->filename);
Packit ae235b
Packit ae235b
      if (file == NULL)
Packit ae235b
        {
Packit ae235b
          file = ip_watched_file_new (sub->dirname, sub->filename);
Packit ae235b
          g_hash_table_insert (dir->files_hash, file->filename, file);
Packit ae235b
        }
Packit ae235b
Packit ae235b
      ip_watched_file_add_sub (file, sub);
Packit ae235b
      ip_watched_file_start (file);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  ip_map_sub_dir (sub, dir);
Packit ae235b
  
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_unmap_path_dir (const char       *path, 
Packit ae235b
                   ip_watched_dir_t *dir)
Packit ae235b
{
Packit ae235b
  g_assert (path && dir);
Packit ae235b
  g_hash_table_remove (path_dir_hash, dir->path);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_unmap_wd_dir (gint32            wd, 
Packit ae235b
                 ip_watched_dir_t *dir)
Packit ae235b
{
Packit ae235b
  GList *dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER (wd));
Packit ae235b
  
Packit ae235b
  if (!dir_list)
Packit ae235b
    return;
Packit ae235b
  
Packit ae235b
  g_assert (wd >= 0 && dir);
Packit ae235b
  dir_list = g_list_remove (dir_list, dir);
Packit ae235b
  if (dir_list == NULL) 
Packit ae235b
    g_hash_table_remove (wd_dir_hash, GINT_TO_POINTER (dir->wd));
Packit ae235b
  else
Packit ae235b
    g_hash_table_replace (wd_dir_hash, GINT_TO_POINTER (dir->wd), dir_list);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_unmap_wd (gint32 wd)
Packit ae235b
{
Packit ae235b
  GList *dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER (wd));
Packit ae235b
  if (!dir_list)
Packit ae235b
    return;
Packit ae235b
  g_assert (wd >= 0);
Packit ae235b
  g_hash_table_remove (wd_dir_hash, GINT_TO_POINTER (wd));
Packit ae235b
  g_list_free (dir_list);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_unmap_sub_dir (inotify_sub      *sub,
Packit ae235b
                  ip_watched_dir_t *dir)
Packit ae235b
{
Packit ae235b
  g_assert (sub && dir);
Packit ae235b
  g_hash_table_remove (sub_dir_hash, sub);
Packit ae235b
  dir->subs = g_list_remove (dir->subs, sub);
Packit ae235b
Packit ae235b
  if (sub->hardlinks)
Packit ae235b
    {
Packit ae235b
      ip_watched_file_t *file;
Packit ae235b
Packit ae235b
      file = g_hash_table_lookup (dir->files_hash, sub->filename);
Packit ae235b
      file->subs = g_list_remove (file->subs, sub);
Packit ae235b
Packit ae235b
      if (file->subs == NULL)
Packit ae235b
        {
Packit ae235b
          g_hash_table_remove (dir->files_hash, sub->filename);
Packit ae235b
          ip_watched_file_stop (file);
Packit ae235b
          ip_watched_file_free (file);
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
 }
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_unmap_all_subs (ip_watched_dir_t *dir)
Packit ae235b
{
Packit ae235b
  while (dir->subs != NULL)
Packit ae235b
    ip_unmap_sub_dir (dir->subs->data, dir);
Packit ae235b
}
Packit ae235b
Packit ae235b
gboolean
Packit ae235b
_ip_stop_watching (inotify_sub *sub)
Packit ae235b
{
Packit ae235b
  ip_watched_dir_t *dir = NULL;
Packit ae235b
  
Packit ae235b
  dir = g_hash_table_lookup (sub_dir_hash, sub);
Packit ae235b
  if (!dir) 
Packit ae235b
    return TRUE;
Packit ae235b
  
Packit ae235b
  ip_unmap_sub_dir (sub, dir);
Packit ae235b
  
Packit ae235b
  /* No one is subscribing to this directory any more */
Packit ae235b
  if (dir->subs == NULL)
Packit ae235b
    {
Packit ae235b
      _ik_ignore (dir->path, dir->wd);
Packit ae235b
      ip_unmap_wd_dir (dir->wd, dir);
Packit ae235b
      ip_unmap_path_dir (dir->path, dir);
Packit ae235b
      ip_watched_dir_free (dir);
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
Packit ae235b
static ip_watched_dir_t *
Packit ae235b
ip_watched_dir_new (const char *path, 
Packit ae235b
                    gint32      wd)
Packit ae235b
{
Packit ae235b
  ip_watched_dir_t *dir = g_new0 (ip_watched_dir_t, 1);
Packit ae235b
  
Packit ae235b
  dir->path = g_strdup (path);
Packit ae235b
  dir->files_hash = g_hash_table_new (g_str_hash, g_str_equal);
Packit ae235b
  dir->wd = wd;
Packit ae235b
  
Packit ae235b
  return dir;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_watched_dir_free (ip_watched_dir_t *dir)
Packit ae235b
{
Packit ae235b
  g_assert_cmpint (g_hash_table_size (dir->files_hash), ==, 0);
Packit ae235b
  g_assert (dir->subs == NULL);
Packit ae235b
  g_free (dir->path);
Packit ae235b
  g_hash_table_unref (dir->files_hash);
Packit ae235b
  g_free (dir);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
ip_wd_delete (gpointer data, 
Packit ae235b
              gpointer user_data)
Packit ae235b
{
Packit ae235b
  ip_watched_dir_t *dir = data;
Packit ae235b
  GList *l = NULL;
Packit ae235b
  
Packit ae235b
  for (l = dir->subs; l; l = l->next)
Packit ae235b
    {
Packit ae235b
      inotify_sub *sub = l->data;
Packit ae235b
      /* Add subscription to missing list */
Packit ae235b
      _im_add (sub);
Packit ae235b
    }
Packit ae235b
  ip_unmap_all_subs (dir);
Packit ae235b
  /* Unassociate the path and the directory */
Packit ae235b
  ip_unmap_path_dir (dir->path, dir);
Packit ae235b
  ip_watched_dir_free (dir);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
ip_event_dispatch (GList      *dir_list, 
Packit ae235b
                   GList      *file_list,
Packit ae235b
                   ik_event_t *event)
Packit ae235b
{
Packit ae235b
  gboolean interesting = FALSE;
Packit ae235b
Packit ae235b
  GList *l;
Packit ae235b
  
Packit ae235b
  if (!event)
Packit ae235b
    return FALSE;
Packit ae235b
Packit ae235b
  for (l = dir_list; l; l = l->next)
Packit ae235b
    {
Packit ae235b
      GList *subl;
Packit ae235b
      ip_watched_dir_t *dir = l->data;
Packit ae235b
      
Packit ae235b
      for (subl = dir->subs; subl; subl = subl->next)
Packit ae235b
	{
Packit ae235b
	  inotify_sub *sub = subl->data;
Packit ae235b
	  
Packit ae235b
	  /* If the subscription and the event
Packit ae235b
	   * contain a filename and they don't
Packit ae235b
	   * match, we don't deliver this event.
Packit ae235b
	   */
Packit ae235b
	  if (sub->filename &&
Packit ae235b
	      event->name &&
Packit ae235b
	      strcmp (sub->filename, event->name) &&
Packit ae235b
              (!event->pair || !event->pair->name || strcmp (sub->filename, event->pair->name)))
Packit ae235b
	    continue;
Packit ae235b
	  
Packit ae235b
	  /* If the subscription has a filename
Packit ae235b
	   * but this event doesn't, we don't
Packit ae235b
	   * deliver this event.
Packit ae235b
	   */
Packit ae235b
	  if (sub->filename && !event->name)
Packit ae235b
	    continue;
Packit ae235b
	  
Packit ae235b
	  /* If we're also watching the file directly
Packit ae235b
	   * don't report events that will also be
Packit ae235b
	   * reported on the file itself.
Packit ae235b
	   */
Packit ae235b
	  if (sub->hardlinks)
Packit ae235b
	    {
Packit ae235b
	      event->mask &= ~IP_INOTIFY_FILE_MASK;
Packit ae235b
	      if (!event->mask)
Packit ae235b
		continue;
Packit ae235b
	    }
Packit ae235b
	  
Packit ae235b
	  /* FIXME: We might need to synthesize
Packit ae235b
	   * DELETE/UNMOUNT events when
Packit ae235b
	   * the filename doesn't match
Packit ae235b
	   */
Packit ae235b
	  
Packit ae235b
	  interesting |= event_callback (event, sub, FALSE);
Packit ae235b
Packit ae235b
          if (sub->hardlinks)
Packit ae235b
            {
Packit ae235b
              ip_watched_file_t *file;
Packit ae235b
Packit ae235b
              file = g_hash_table_lookup (dir->files_hash, sub->filename);
Packit ae235b
Packit ae235b
              if (file != NULL)
Packit ae235b
                {
Packit ae235b
                  if (event->mask & (IN_MOVED_FROM | IN_DELETE))
Packit ae235b
                    ip_watched_file_stop (file);
Packit ae235b
Packit ae235b
                  if (event->mask & (IN_MOVED_TO | IN_CREATE))
Packit ae235b
                    ip_watched_file_start (file);
Packit ae235b
                }
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  for (l = file_list; l; l = l->next)
Packit ae235b
    {
Packit ae235b
      ip_watched_file_t *file = l->data;
Packit ae235b
      GList *subl;
Packit ae235b
Packit ae235b
      for (subl = file->subs; subl; subl = subl->next)
Packit ae235b
        {
Packit ae235b
	  inotify_sub *sub = subl->data;
Packit ae235b
Packit ae235b
	  interesting |= event_callback (event, sub, TRUE);
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return interesting;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
ip_event_callback (ik_event_t *event)
Packit ae235b
{
Packit ae235b
  gboolean interesting = FALSE;
Packit ae235b
  GList* dir_list = NULL;
Packit ae235b
  GList *file_list = NULL;
Packit ae235b
Packit ae235b
  /* We can ignore the IGNORED events. Likewise, if the event queue overflowed,
Packit ae235b
   * there is not much we can do to recover. */
Packit ae235b
  if (event->mask & (IN_IGNORED | IN_Q_OVERFLOW))
Packit ae235b
    {
Packit ae235b
      _ik_event_free (event);
Packit ae235b
      return TRUE;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER (event->wd));
Packit ae235b
  file_list = g_hash_table_lookup (wd_file_hash, GINT_TO_POINTER (event->wd));
Packit ae235b
Packit ae235b
  if (event->mask & IP_INOTIFY_DIR_MASK)
Packit ae235b
    interesting |= ip_event_dispatch (dir_list, file_list, event);
Packit ae235b
Packit ae235b
  /* Only deliver paired events if the wds are separate */
Packit ae235b
  if (event->pair && event->pair->wd != event->wd)
Packit ae235b
    {
Packit ae235b
      dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER (event->pair->wd));
Packit ae235b
      file_list = g_hash_table_lookup (wd_file_hash, GINT_TO_POINTER (event->pair->wd));
Packit ae235b
Packit ae235b
      if (event->pair->mask & IP_INOTIFY_DIR_MASK)
Packit ae235b
        interesting |= ip_event_dispatch (dir_list, file_list, event->pair);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  /* We have to manage the missing list
Packit ae235b
   * when we get an event that means the
Packit ae235b
   * file has been deleted/moved/unmounted.
Packit ae235b
   */
Packit ae235b
  if (event->mask & IN_DELETE_SELF ||
Packit ae235b
      event->mask & IN_MOVE_SELF ||
Packit ae235b
      event->mask & IN_UNMOUNT)
Packit ae235b
    {
Packit ae235b
      /* Add all subscriptions to missing list */
Packit ae235b
      g_list_foreach (dir_list, ip_wd_delete, NULL);
Packit ae235b
      /* Unmap all directories attached to this wd */
Packit ae235b
      ip_unmap_wd (event->wd);
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  _ik_event_free (event);
Packit ae235b
Packit ae235b
  return interesting;
Packit ae235b
}
Packit ae235b
Packit ae235b
const char *
Packit ae235b
_ip_get_path_for_wd (gint32 wd)
Packit ae235b
{
Packit ae235b
  GList *dir_list;
Packit ae235b
  ip_watched_dir_t *dir;
Packit ae235b
Packit ae235b
  g_assert (wd >= 0);
Packit ae235b
  dir_list = g_hash_table_lookup (wd_dir_hash, GINT_TO_POINTER (wd));
Packit ae235b
  if (dir_list)
Packit ae235b
    {
Packit ae235b
      dir = dir_list->data;
Packit ae235b
      if (dir)
Packit ae235b
	return dir->path;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return NULL;
Packit ae235b
}