diff options
Diffstat (limited to 'src/libtracker-miner/tracker-monitor.c')
-rw-r--r-- | src/libtracker-miner/tracker-monitor.c | 1139 |
1 files changed, 0 insertions, 1139 deletions
diff --git a/src/libtracker-miner/tracker-monitor.c b/src/libtracker-miner/tracker-monitor.c deleted file mode 100644 index f87a5b672..000000000 --- a/src/libtracker-miner/tracker-monitor.c +++ /dev/null @@ -1,1139 +0,0 @@ -/* - * Copyright (C) 2009, Nokia <ivan.frade@nokia.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "config.h" - -#include <stdlib.h> -#include <string.h> -#include <gio/gio.h> - -#if defined (__OpenBSD__) || defined (__FreeBSD__) || defined (__NetBSD__) || defined (__APPLE__) -#include <sys/types.h> -#include <sys/time.h> -#include <sys/resource.h> -#define TRACKER_MONITOR_KQUEUE -#endif - -#include "tracker-monitor.h" - -/* The life time of an item in the cache */ -#define CACHE_LIFETIME_SECONDS 1 - -typedef struct TrackerMonitorPrivate TrackerMonitorPrivate; - -struct TrackerMonitorPrivate { - GHashTable *monitors; - - gboolean enabled; - - guint monitor_limit; - gboolean monitor_limit_warned; - guint monitors_ignored; - - /* For FAM, the _CHANGES_DONE event is not signalled, so we - * have to just use the _CHANGED event instead. - */ - gboolean use_changed_event; - - GHashTable *cached_events; - - TrackerIndexingTree *tree; -}; - -typedef struct { - GFile *file; - gchar *file_uri; - GFile *other_file; - gchar *other_file_uri; - gboolean is_directory; - GTimeVal start_time; - guint32 event_type; - gboolean expirable; -} EventData; - -enum { - ITEM_CREATED, - ITEM_UPDATED, - ITEM_ATTRIBUTE_UPDATED, - ITEM_DELETED, - ITEM_MOVED, - LAST_SIGNAL -}; - -enum { - PROP_0, - PROP_ENABLED -}; - -static void tracker_monitor_finalize (GObject *object); -static void tracker_monitor_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void tracker_monitor_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static guint get_kqueue_limit (void); -static guint get_inotify_limit (void); -static GFileMonitor * directory_monitor_new (TrackerMonitor *monitor, - GFile *file); -static void directory_monitor_cancel (GFileMonitor *dir_monitor); - - -static void emit_signal_for_event (TrackerMonitor *monitor, - GFileMonitorEvent type, - gboolean is_directory, - GFile *file, - GFile *other_file); -static gboolean monitor_cancel_recursively (TrackerMonitor *monitor, - GFile *file); - -static guint signals[LAST_SIGNAL] = { 0, }; - -G_DEFINE_TYPE_WITH_PRIVATE (TrackerMonitor, tracker_monitor, G_TYPE_OBJECT) - -static void -tracker_monitor_class_init (TrackerMonitorClass *klass) -{ - GObjectClass *object_class; - - object_class = G_OBJECT_CLASS (klass); - - object_class->finalize = tracker_monitor_finalize; - object_class->set_property = tracker_monitor_set_property; - object_class->get_property = tracker_monitor_get_property; - - signals[ITEM_CREATED] = - g_signal_new ("item-created", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_OBJECT, - G_TYPE_BOOLEAN); - signals[ITEM_UPDATED] = - g_signal_new ("item-updated", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_OBJECT, - G_TYPE_BOOLEAN); - signals[ITEM_ATTRIBUTE_UPDATED] = - g_signal_new ("item-attribute-updated", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_OBJECT, - G_TYPE_BOOLEAN); - signals[ITEM_DELETED] = - g_signal_new ("item-deleted", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - NULL, - G_TYPE_NONE, - 2, - G_TYPE_OBJECT, - G_TYPE_BOOLEAN); - signals[ITEM_MOVED] = - g_signal_new ("item-moved", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, NULL, - NULL, - G_TYPE_NONE, - 4, - G_TYPE_OBJECT, - G_TYPE_OBJECT, - G_TYPE_BOOLEAN, - G_TYPE_BOOLEAN); - - g_object_class_install_property (object_class, - PROP_ENABLED, - g_param_spec_boolean ("enabled", - "Enabled", - "Enabled", - TRUE, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); -} - -static void -tracker_monitor_init (TrackerMonitor *object) -{ - TrackerMonitorPrivate *priv; - GFile *file; - GFileMonitor *monitor; - GError *error = NULL; - - priv = tracker_monitor_get_instance_private (object); - - /* By default we enable monitoring */ - priv->enabled = TRUE; - - /* Create monitors table for this module */ - priv->monitors = - g_hash_table_new_full (g_file_hash, - (GEqualFunc) g_file_equal, - (GDestroyNotify) g_object_unref, - (GDestroyNotify) directory_monitor_cancel); - - priv->cached_events = - g_hash_table_new_full (g_file_hash, - (GEqualFunc) g_file_equal, - g_object_unref, - NULL); - - /* For the first monitor we get the type and find out if we - * are using inotify, FAM, polling, etc. - */ - file = g_file_new_for_path (g_get_home_dir ()); - monitor = g_file_monitor_directory (file, - G_FILE_MONITOR_WATCH_MOVES, - NULL, - &error); - - if (error) { - g_critical ("Could not create sample directory monitor: %s", error->message); - g_error_free (error); - - /* Guessing limit... */ - priv->monitor_limit = 100; - } else { - GType monitor_backend; - const gchar *name; - - monitor_backend = G_OBJECT_TYPE (monitor); - - /* We use the name because the type itself is actually - * private and not available publically. Note this is - * subject to change, but unlikely of course. - */ - name = g_type_name (monitor_backend); - - /* Set limits based on backend... */ - if (strcmp (name, "GInotifyDirectoryMonitor") == 0 || - strcmp (name, "GInotifyFileMonitor") == 0) { - /* Using inotify */ - g_debug ("Monitor backend is Inotify"); - - /* Setting limit based on kernel - * settings in /proc... - */ - priv->monitor_limit = get_inotify_limit (); - - /* We don't use 100% of the monitors, we allow other - * applications to have at least 500 or so to use - * between them selves. This only - * applies to inotify because it is a - * user shared resource. - */ - priv->monitor_limit -= 500; - - /* Make sure we don't end up with a - * negative maximum. - */ - priv->monitor_limit = MAX (priv->monitor_limit, 0); - } - else if (strcmp (name, "GKqueueDirectoryMonitor") == 0 || - strcmp (name, "GKqueueFileMonitor") == 0) { - /* Using kqueue(2) */ - g_debug ("Monitor backend is kqueue"); - - priv->monitor_limit = get_kqueue_limit (); - } - else if (strcmp (name, "GFamDirectoryMonitor") == 0) { - /* Using Fam */ - g_debug ("Monitor backend is Fam"); - - /* Setting limit to an arbitary limit - * based on testing - */ - priv->monitor_limit = 400; - priv->use_changed_event = TRUE; - } - else if (strcmp (name, "GWin32DirectoryMonitor") == 0) { - /* Using Windows */ - g_debug ("Monitor backend is Windows"); - - /* Guessing limit... */ - priv->monitor_limit = 8192; - } - else { - /* Unknown */ - g_warning ("Monitor backend:'%s' is unhandled. Monitoring will be disabled", - name); - priv->enabled = FALSE; - } - - g_file_monitor_cancel (monitor); - g_object_unref (monitor); - } - - g_object_unref (file); - - if (priv->enabled) - g_debug ("Monitor limit is %d", priv->monitor_limit); -} - -static void -tracker_monitor_finalize (GObject *object) -{ - TrackerMonitorPrivate *priv; - - priv = tracker_monitor_get_instance_private (TRACKER_MONITOR (object)); - - g_hash_table_unref (priv->cached_events); - g_hash_table_unref (priv->monitors); - - G_OBJECT_CLASS (tracker_monitor_parent_class)->finalize (object); -} - -static void -tracker_monitor_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - switch (prop_id) { - case PROP_ENABLED: - tracker_monitor_set_enabled (TRACKER_MONITOR (object), - g_value_get_boolean (value)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static void -tracker_monitor_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - TrackerMonitorPrivate *priv; - - priv = tracker_monitor_get_instance_private (TRACKER_MONITOR (object)); - - switch (prop_id) { - case PROP_ENABLED: - g_value_set_boolean (value, priv->enabled); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - } -} - -static guint -get_kqueue_limit (void) -{ - guint limit = 400; - -#ifdef TRACKER_MONITOR_KQUEUE - struct rlimit rl; - if (getrlimit (RLIMIT_NOFILE, &rl) == 0) { - rl.rlim_cur = rl.rlim_max; - } else { - return limit; - } - - if (setrlimit(RLIMIT_NOFILE, &rl) == 0) - limit = (rl.rlim_cur * 90) / 100; -#endif /* TRACKER_MONITOR_KQUEUE */ - - return limit; -} - -static guint -get_inotify_limit (void) -{ - GError *error = NULL; - const gchar *filename; - gchar *contents = NULL; - guint limit; - - filename = "/proc/sys/fs/inotify/max_user_watches"; - - if (!g_file_get_contents (filename, - &contents, - NULL, - &error)) { - g_warning ("Couldn't get INotify monitor limit from:'%s', %s", - filename, - error ? error->message : "no error given"); - g_clear_error (&error); - - /* Setting limit to an arbitary limit */ - limit = 8192; - } else { - limit = atoi (contents); - g_free (contents); - } - - return limit; -} - -static gboolean -check_is_directory (TrackerMonitor *monitor, - GFile *file) -{ - GFileType file_type; - - file_type = g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL); - - if (file_type == G_FILE_TYPE_DIRECTORY) - return TRUE; - - if (file_type == G_FILE_TYPE_UNKNOWN) { - TrackerMonitorPrivate *priv; - - priv = tracker_monitor_get_instance_private (monitor); - - /* Whatever it was, it's gone. Check the monitors - * hashtable to know whether it was a directory - * we knew about - */ - if (g_hash_table_lookup (priv->monitors, file) != NULL) - return TRUE; - } - - return FALSE; -} - -gboolean -tracker_monitor_move (TrackerMonitor *monitor, - GFile *old_file, - GFile *new_file) -{ - TrackerMonitorPrivate *priv; - GHashTableIter iter; - GHashTable *new_monitors; - gchar *old_prefix; - gpointer iter_file, iter_file_monitor; - guint items_moved = 0; - - priv = tracker_monitor_get_instance_private (monitor); - - /* So this is tricky. What we have to do is: - * - * 1) Add all monitors for the new_file directory hierarchy - * 2) Then remove the monitors for old_file - * - * This order is necessary because inotify can reuse watch - * descriptors, and libinotify will remove handles - * asynchronously on IN_IGNORE, so the opposite sequence - * may possibly remove valid, just added, monitors. - */ - new_monitors = g_hash_table_new_full (g_file_hash, - (GEqualFunc) g_file_equal, - (GDestroyNotify) g_object_unref, - NULL); - old_prefix = g_file_get_path (old_file); - - /* Find out which subdirectories should have a file monitor added */ - g_hash_table_iter_init (&iter, priv->monitors); - while (g_hash_table_iter_next (&iter, &iter_file, &iter_file_monitor)) { - GFile *f; - gchar *old_path, *new_path; - gchar *new_prefix; - gchar *p; - - if (!g_file_has_prefix (iter_file, old_file) && - !g_file_equal (iter_file, old_file)) { - continue; - } - - old_path = g_file_get_path (iter_file); - p = strstr (old_path, old_prefix); - - if (!p || strcmp (p, old_prefix) == 0) { - g_free (old_path); - continue; - } - - /* Move to end of prefix */ - p += strlen (old_prefix) + 1; - - /* Check this is not the end of the string */ - if (*p == '\0') { - g_free (old_path); - continue; - } - - new_prefix = g_file_get_path (new_file); - new_path = g_build_path (G_DIR_SEPARATOR_S, new_prefix, p, NULL); - g_free (new_prefix); - - f = g_file_new_for_path (new_path); - g_free (new_path); - - if (!g_hash_table_lookup (new_monitors, f)) { - g_hash_table_insert (new_monitors, f, GINT_TO_POINTER (1)); - } else { - g_object_unref (f); - } - - g_free (old_path); - items_moved++; - } - - /* Add a new monitor for the top level directory */ - tracker_monitor_add (monitor, new_file); - - /* Add a new monitor for all subdirectories */ - g_hash_table_iter_init (&iter, new_monitors); - while (g_hash_table_iter_next (&iter, &iter_file, NULL)) { - tracker_monitor_add (monitor, iter_file); - g_hash_table_iter_remove (&iter); - } - - /* Remove the monitor for the old top level directory hierarchy */ - tracker_monitor_remove_recursively (monitor, old_file); - - g_hash_table_unref (new_monitors); - g_free (old_prefix); - - return items_moved > 0; -} - -static const gchar * -monitor_event_to_string (GFileMonitorEvent event_type) -{ - switch (event_type) { - case G_FILE_MONITOR_EVENT_CHANGED: - return "G_FILE_MONITOR_EVENT_CHANGED"; - case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: - return "G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT"; - case G_FILE_MONITOR_EVENT_DELETED: - return "G_FILE_MONITOR_EVENT_DELETED"; - case G_FILE_MONITOR_EVENT_CREATED: - return "G_FILE_MONITOR_EVENT_CREATED"; - case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED: - return "G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED"; - case G_FILE_MONITOR_EVENT_PRE_UNMOUNT: - return "G_FILE_MONITOR_EVENT_PRE_UNMOUNT"; - case G_FILE_MONITOR_EVENT_UNMOUNTED: - return "G_FILE_MONITOR_EVENT_UNMOUNTED"; - case G_FILE_MONITOR_EVENT_MOVED: - return "G_FILE_MONITOR_EVENT_MOVED"; - case G_FILE_MONITOR_EVENT_RENAMED: - return "G_FILE_MONITOR_EVENT_RENAMED"; - case G_FILE_MONITOR_EVENT_MOVED_IN: - return "G_FILE_MONITOR_EVENT_MOVED_IN"; - case G_FILE_MONITOR_EVENT_MOVED_OUT: - return "G_FILE_MONITOR_EVENT_MOVED_OUT"; - break; - } - - return "unknown"; -} - -static void -emit_signal_for_event (TrackerMonitor *monitor, - GFileMonitorEvent type, - gboolean is_directory, - GFile *file, - GFile *other_file) -{ - /* Note that in any case we should be moving the monitors - * here to the new place, as the new place may be ignored. - * We should leave this to the upper layers. But one thing - * we must do is actually CANCEL all these monitors. */ - if (is_directory && - (type == G_FILE_MONITOR_EVENT_MOVED || - type == G_FILE_MONITOR_EVENT_DELETED)) { - monitor_cancel_recursively (monitor, file); - } - - switch (type) { - case G_FILE_MONITOR_EVENT_CREATED: - g_signal_emit (monitor, - signals[ITEM_CREATED], 0, - file, is_directory); - break; - case G_FILE_MONITOR_EVENT_CHANGED: - g_signal_emit (monitor, - signals[ITEM_UPDATED], 0, - file, is_directory); - break; - case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED: - g_signal_emit (monitor, - signals[ITEM_ATTRIBUTE_UPDATED], 0, - file, is_directory); - break; - case G_FILE_MONITOR_EVENT_DELETED: - g_signal_emit (monitor, - signals[ITEM_DELETED], 0, - file, is_directory); - break; - case G_FILE_MONITOR_EVENT_MOVED: - g_signal_emit (monitor, - signals[ITEM_MOVED], 0, - file, other_file, is_directory, TRUE); - break; - default: - g_warning ("Trying to emit monitor signal with unhandled event %d", - type); - break; - } -} - -static void -flush_cached_event (TrackerMonitor *monitor, - GFile *file, - gboolean is_directory) -{ - gpointer value = NULL; - TrackerMonitorPrivate *priv; - - priv = tracker_monitor_get_instance_private (monitor); - - if (g_hash_table_lookup_extended (priv->cached_events, - file, NULL, &value)) { - GFileMonitorEvent prev_event_type = GPOINTER_TO_UINT (value); - - g_hash_table_remove (priv->cached_events, file); - emit_signal_for_event (monitor, prev_event_type, - is_directory, file, NULL); - } -} - -static void -cache_event (TrackerMonitor *monitor, - GFile *file, - GFileMonitorEvent event_type) -{ - TrackerMonitorPrivate *priv; - - priv = tracker_monitor_get_instance_private (monitor); - - if (g_hash_table_lookup_extended (priv->cached_events, file, - NULL, NULL)) - return; - - g_hash_table_insert (priv->cached_events, - g_object_ref (file), - GUINT_TO_POINTER (event_type)); -} - -static void -monitor_event_cb (GFileMonitor *file_monitor, - GFile *file, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer user_data) -{ - TrackerMonitor *monitor; - gchar *file_uri; - gchar *other_file_uri; - gboolean is_directory = FALSE; - TrackerMonitorPrivate *priv; - gpointer value; - - monitor = user_data; - priv = tracker_monitor_get_instance_private (monitor); - - if (G_UNLIKELY (!priv->enabled)) { - g_debug ("Silently dropping monitor event, monitor disabled for now"); - return; - } - - /* Get URIs as paths may not be in UTF-8 */ - file_uri = g_file_get_uri (file); - - if (!other_file) { - is_directory = check_is_directory (monitor, file); - - other_file_uri = NULL; - g_debug ("Received monitor event:%d (%s) for %s:'%s'", - event_type, - monitor_event_to_string (event_type), - is_directory ? "directory" : "file", - file_uri); - } else { - if (event_type == G_FILE_MONITOR_EVENT_RENAMED || - event_type == G_FILE_MONITOR_EVENT_MOVED_OUT) { - is_directory = check_is_directory (monitor, other_file); - } else if (event_type == G_FILE_MONITOR_EVENT_MOVED_IN) { - is_directory = check_is_directory (monitor, file); - } - - other_file_uri = g_file_get_uri (other_file); - g_debug ("Received monitor event:%d (%s) for files '%s'->'%s'", - event_type, - monitor_event_to_string (event_type), - file_uri, - other_file_uri); - } - - switch (event_type) { - case G_FILE_MONITOR_EVENT_CREATED: - case G_FILE_MONITOR_EVENT_CHANGED: - if (!priv->use_changed_event) { - cache_event (monitor, file, event_type); - } else { - emit_signal_for_event (monitor, event_type, - is_directory, file, NULL); - } - break; - case G_FILE_MONITOR_EVENT_DELETED: - if (g_hash_table_lookup_extended (priv->cached_events, - file, NULL, &value) && - GPOINTER_TO_UINT (value) == G_FILE_MONITOR_EVENT_CREATED) { - /* Consume both the cached CREATED event and this one */ - g_hash_table_remove (priv->cached_events, file); - break; - } - - /* In any case, cached events are stale */ - g_hash_table_remove (priv->cached_events, file); - - /* Fall through */ - case G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED: - emit_signal_for_event (monitor, event_type, - is_directory, file, NULL); - break; - case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: - flush_cached_event (monitor, file, is_directory); - break; - case G_FILE_MONITOR_EVENT_MOVED_IN: - if (other_file) { - /* Both MOVED_IN and MOVE_OUT are fine points to emit - * ::item-moved when source/dest are known. We choose - * to emit it here, and ignore the MOVE_OUT. - */ - emit_signal_for_event (monitor, - G_FILE_MONITOR_EVENT_MOVED, - is_directory, - other_file, file); - } else { - /* No known origin, treat as a new file */ - emit_signal_for_event (monitor, - G_FILE_MONITOR_EVENT_CREATED, - is_directory, - file, NULL); - } - break; - case G_FILE_MONITOR_EVENT_MOVED_OUT: - if (!other_file) { - /* No known destination. Treat as remove */ - emit_signal_for_event (monitor, - G_FILE_MONITOR_EVENT_DELETED, - is_directory, - file, NULL); - } - break; - case G_FILE_MONITOR_EVENT_RENAMED: - emit_signal_for_event (monitor, - G_FILE_MONITOR_EVENT_MOVED, - is_directory, file, other_file); - break; - case G_FILE_MONITOR_EVENT_MOVED: - g_warn_if_reached (); - break; - case G_FILE_MONITOR_EVENT_PRE_UNMOUNT: - case G_FILE_MONITOR_EVENT_UNMOUNTED: - break; - } - - g_free (file_uri); - g_free (other_file_uri); -} - -static GFileMonitor * -directory_monitor_new (TrackerMonitor *monitor, - GFile *file) -{ - GFileMonitor *file_monitor; - GError *error = NULL; - - file_monitor = g_file_monitor_directory (file, - G_FILE_MONITOR_WATCH_MOVES, - NULL, - &error); - - if (error) { - gchar *uri; - - uri = g_file_get_uri (file); - g_warning ("Could not add monitor for path:'%s', %s", - uri, error->message); - - g_error_free (error); - g_free (uri); - - return NULL; - } - - g_signal_connect (file_monitor, "changed", - G_CALLBACK (monitor_event_cb), - monitor); - - return file_monitor; -} - -static void -directory_monitor_cancel (GFileMonitor *monitor) -{ - if (monitor) { - g_file_monitor_cancel (G_FILE_MONITOR (monitor)); - g_object_unref (monitor); - } -} - -TrackerMonitor * -tracker_monitor_new (void) -{ - return g_object_new (TRACKER_TYPE_MONITOR, NULL); -} - -gboolean -tracker_monitor_get_enabled (TrackerMonitor *monitor) -{ - TrackerMonitorPrivate *priv; - - g_return_val_if_fail (TRACKER_IS_MONITOR (monitor), FALSE); - - priv = tracker_monitor_get_instance_private (monitor); - - return priv->enabled; -} - -void -tracker_monitor_set_enabled (TrackerMonitor *monitor, - gboolean enabled) -{ - TrackerMonitorPrivate *priv; - GList *keys, *k; - - g_return_if_fail (TRACKER_IS_MONITOR (monitor)); - - priv = tracker_monitor_get_instance_private (monitor); - - /* Don't replace all monitors if we are already - * enabled/disabled. - */ - if (priv->enabled == enabled) { - return; - } - - priv->enabled = enabled; - g_object_notify (G_OBJECT (monitor), "enabled"); - - keys = g_hash_table_get_keys (priv->monitors); - - /* Update state on all monitored dirs */ - for (k = keys; k != NULL; k = k->next) { - GFile *file; - - file = k->data; - - if (enabled) { - GFileMonitor *dir_monitor; - - dir_monitor = directory_monitor_new (monitor, file); - g_hash_table_replace (priv->monitors, - g_object_ref (file), dir_monitor); - } else { - /* Remove monitor */ - g_hash_table_replace (priv->monitors, - g_object_ref (file), NULL); - } - } - - g_list_free (keys); -} - -gboolean -tracker_monitor_add (TrackerMonitor *monitor, - GFile *file) -{ - TrackerMonitorPrivate *priv; - GFileMonitor *dir_monitor = NULL; - gchar *uri; - - g_return_val_if_fail (TRACKER_IS_MONITOR (monitor), FALSE); - g_return_val_if_fail (G_IS_FILE (file), FALSE); - - priv = tracker_monitor_get_instance_private (monitor); - - if (g_hash_table_lookup (priv->monitors, file)) { - return TRUE; - } - - /* Cap the number of monitors */ - if (g_hash_table_size (priv->monitors) >= priv->monitor_limit) { - priv->monitors_ignored++; - - if (!priv->monitor_limit_warned) { - g_warning ("The maximum number of monitors to set (%d) " - "has been reached, not adding any new ones", - priv->monitor_limit); - priv->monitor_limit_warned = TRUE; - } - - return FALSE; - } - - uri = g_file_get_uri (file); - - if (priv->enabled) { - /* We don't check if a file exists or not since we might want - * to monitor locations which don't exist yet. - * - * Also, we assume ALL paths passed are directories. - */ - dir_monitor = directory_monitor_new (monitor, file); - - if (!dir_monitor) { - g_warning ("Could not add monitor for path:'%s'", - uri); - g_free (uri); - return FALSE; - } - } - - /* NOTE: it is ok to add a NULL file_monitor, when our - * enabled/disabled state changes, we iterate all keys and - * add or remove monitors. - */ - g_hash_table_insert (priv->monitors, - g_object_ref (file), - dir_monitor); - - g_debug ("Added monitor for path:'%s', total monitors:%d", - uri, - g_hash_table_size (priv->monitors)); - - g_free (uri); - - return TRUE; -} - -gboolean -tracker_monitor_remove (TrackerMonitor *monitor, - GFile *file) -{ - TrackerMonitorPrivate *priv; - gboolean removed; - - g_return_val_if_fail (TRACKER_IS_MONITOR (monitor), FALSE); - g_return_val_if_fail (G_IS_FILE (file), FALSE); - - priv = tracker_monitor_get_instance_private (monitor); - removed = g_hash_table_remove (priv->monitors, file); - - if (removed) { - gchar *uri; - - uri = g_file_get_uri (file); - g_debug ("Removed monitor for path:'%s', total monitors:%d", - uri, - g_hash_table_size (priv->monitors)); - - g_free (uri); - } - - return removed; -} - -/* If @is_strict is %TRUE, return %TRUE iff @file is a child of @prefix. - * If @is_strict is %FALSE, additionally return %TRUE if @file equals @prefix. - */ -static gboolean -file_has_maybe_strict_prefix (GFile *file, - GFile *prefix, - gboolean is_strict) -{ - return (g_file_has_prefix (file, prefix) || - (!is_strict && g_file_equal (file, prefix))); -} - -static gboolean -remove_recursively (TrackerMonitor *monitor, - GFile *file, - gboolean remove_top_level) -{ - TrackerMonitorPrivate *priv; - GHashTableIter iter; - gpointer iter_file, iter_file_monitor; - guint items_removed = 0; - gchar *uri; - - g_return_val_if_fail (TRACKER_IS_MONITOR (monitor), FALSE); - g_return_val_if_fail (G_IS_FILE (file), FALSE); - - priv = tracker_monitor_get_instance_private (monitor); - - g_hash_table_iter_init (&iter, priv->monitors); - while (g_hash_table_iter_next (&iter, &iter_file, &iter_file_monitor)) { - if (!file_has_maybe_strict_prefix (iter_file, file, - !remove_top_level)) { - continue; - } - - g_hash_table_iter_remove (&iter); - items_removed++; - } - - uri = g_file_get_uri (file); - g_debug ("Removed all monitors %srecursively for path:'%s', " - "total monitors:%d", - !remove_top_level ? "(except top level) " : "", - uri, g_hash_table_size (priv->monitors)); - g_free (uri); - - if (items_removed > 0) { - /* We reset this because now it is possible we have limit - 1 */ - priv->monitor_limit_warned = FALSE; - return TRUE; - } - - return FALSE; -} - -gboolean -tracker_monitor_remove_recursively (TrackerMonitor *monitor, - GFile *file) -{ - return remove_recursively (monitor, file, TRUE); -} - -gboolean -tracker_monitor_remove_children_recursively (TrackerMonitor *monitor, - GFile *file) -{ - return remove_recursively (monitor, file, FALSE); -} - -static gboolean -monitor_cancel_recursively (TrackerMonitor *monitor, - GFile *file) -{ - TrackerMonitorPrivate *priv; - GHashTableIter iter; - gpointer iter_file, iter_file_monitor; - guint items_cancelled = 0; - - priv = tracker_monitor_get_instance_private (monitor); - - g_hash_table_iter_init (&iter, priv->monitors); - while (g_hash_table_iter_next (&iter, &iter_file, &iter_file_monitor)) { - gchar *uri; - - if (!g_file_has_prefix (iter_file, file) && - !g_file_equal (iter_file, file)) { - continue; - } - - uri = g_file_get_uri (iter_file); - g_file_monitor_cancel (G_FILE_MONITOR (iter_file_monitor)); - g_debug ("Cancelled monitor for path:'%s'", uri); - g_free (uri); - - items_cancelled++; - } - - return items_cancelled > 0; -} - -gboolean -tracker_monitor_is_watched (TrackerMonitor *monitor, - GFile *file) -{ - TrackerMonitorPrivate *priv; - - g_return_val_if_fail (TRACKER_IS_MONITOR (monitor), FALSE); - g_return_val_if_fail (G_IS_FILE (file), FALSE); - - priv = tracker_monitor_get_instance_private (monitor); - - return g_hash_table_lookup (priv->monitors, file) != NULL; -} - -gboolean -tracker_monitor_is_watched_by_string (TrackerMonitor *monitor, - const gchar *path) -{ - TrackerMonitorPrivate *priv; - GFile *file; - gboolean watched; - - g_return_val_if_fail (TRACKER_IS_MONITOR (monitor), FALSE); - g_return_val_if_fail (path != NULL, FALSE); - - priv = tracker_monitor_get_instance_private (monitor); - - file = g_file_new_for_path (path); - watched = g_hash_table_lookup (priv->monitors, file) != NULL; - g_object_unref (file); - - return watched; -} - -guint -tracker_monitor_get_count (TrackerMonitor *monitor) -{ - TrackerMonitorPrivate *priv; - - g_return_val_if_fail (TRACKER_IS_MONITOR (monitor), 0); - - priv = tracker_monitor_get_instance_private (monitor); - - return g_hash_table_size (priv->monitors); -} - -guint -tracker_monitor_get_ignored (TrackerMonitor *monitor) -{ - TrackerMonitorPrivate *priv; - - g_return_val_if_fail (TRACKER_IS_MONITOR (monitor), 0); - - priv = tracker_monitor_get_instance_private (monitor); - - return priv->monitors_ignored; -} - -guint -tracker_monitor_get_limit (TrackerMonitor *monitor) -{ - TrackerMonitorPrivate *priv; - - g_return_val_if_fail (TRACKER_IS_MONITOR (monitor), 0); - - priv = tracker_monitor_get_instance_private (monitor); - - return priv->monitor_limit; -} |