tracker-0.16.2/src/miners/fs/tracker-miner-files.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found tracker-miner-files.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
   1 /*
   2  * Copyright (C) 2008, Nokia <ivan.frade@nokia.com>
   3  *
   4  * This library is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) any later version.
   8  *
   9  * This library is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU General Public
  15  * License along with this library; if not, write to the
  16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17  * Boston, MA  02110-1301, USA.
  18  */
  19 
  20 #include "config.h"
  21 
  22 #include <sys/statvfs.h>
  23 #include <fcntl.h>
  24 #ifdef __linux__
  25 #include <sys/ioctl.h>
  26 #include <linux/msdos_fs.h>
  27 #endif /* __linux__ */
  28 #include <unistd.h>
  29 
  30 #include <glib/gi18n.h>
  31 #include <glib/gstdio.h>
  32 
  33 #include <gio/gio.h>
  34 #include <gio/gunixfdlist.h>
  35 #include <gio/gunixinputstream.h>
  36 
  37 #include <libtracker-common/tracker-date-time.h>
  38 #include <libtracker-common/tracker-ontologies.h>
  39 #include <libtracker-common/tracker-type-utils.h>
  40 #include <libtracker-common/tracker-utils.h>
  41 #include <libtracker-common/tracker-file-utils.h>
  42 
  43 #include <libtracker-data/tracker-db-manager.h>
  44 
  45 #include <libtracker-extract/tracker-module-manager.h>
  46 #include <libtracker-extract/tracker-extract-client.h>
  47 
  48 #include "tracker-power.h"
  49 #include "tracker-miner-files.h"
  50 #include "tracker-config.h"
  51 #include "tracker-marshal.h"
  52 
  53 #define DISK_SPACE_CHECK_FREQUENCY 10
  54 #define SECONDS_PER_DAY 86400
  55 
  56 #define TRACKER_MINER_FILES_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRACKER_TYPE_MINER_FILES, TrackerMinerFilesPrivate))
  57 
  58 static GQuark miner_files_error_quark = 0;
  59 
  60 typedef struct ProcessFileData ProcessFileData;
  61 
  62 struct ProcessFileData {
  63 	TrackerMinerFiles *miner;
  64 	TrackerSparqlBuilder *sparql;
  65 	GCancellable *cancellable;
  66 	GFile *file;
  67 	gchar *mime_type;
  68 };
  69 
  70 struct TrackerMinerFilesPrivate {
  71 	TrackerConfig *config;
  72 	TrackerStorage *storage;
  73 
  74 	GVolumeMonitor *volume_monitor;
  75 
  76 	GSList *index_recursive_directories;
  77 	GSList *index_single_directories;
  78 
  79 	guint disk_space_check_id;
  80 	guint disk_space_pause_cookie;
  81 
  82 	guint low_battery_pause_cookie;
  83 
  84 #if defined(HAVE_UPOWER) || defined(HAVE_HAL)
  85 	TrackerPower *power;
  86 #endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */
  87 	gulong finished_handler;
  88 
  89 	GDBusConnection *connection;
  90 
  91 	GQuark quark_mount_point_uuid;
  92 
  93 	guint force_recheck_id;
  94 
  95 	gboolean index_removable_devices;
  96 	gboolean index_optical_discs;
  97 	guint volumes_changed_id;
  98 
  99 	gboolean mount_points_initialized;
 100 
 101 	guint stale_volumes_check_id;
 102 
 103 	guint failed_extraction_pause_cookie;
 104 	GList *extraction_queue;
 105 	GList *failed_extraction_queue;
 106 
 107 	gboolean failsafe_extraction;
 108 };
 109 
 110 enum {
 111 	VOLUME_MOUNTED_IN_STORE = 1 << 0,
 112 	VOLUME_MOUNTED = 1 << 1
 113 };
 114 
 115 enum {
 116 	PROP_0,
 117 	PROP_CONFIG
 118 };
 119 
 120 static void        miner_files_set_property             (GObject              *object,
 121                                                          guint                 param_id,
 122                                                          const GValue         *value,
 123                                                          GParamSpec           *pspec);
 124 static void        miner_files_get_property             (GObject              *object,
 125                                                          guint                 param_id,
 126                                                          GValue               *value,
 127                                                          GParamSpec           *pspec);
 128 static void        miner_files_finalize                 (GObject              *object);
 129 static void        miner_files_initable_iface_init      (GInitableIface       *iface);
 130 static gboolean    miner_files_initable_init            (GInitable            *initable,
 131                                                          GCancellable         *cancellable,
 132                                                          GError              **error);
 133 static void        mount_pre_unmount_cb                 (GVolumeMonitor       *volume_monitor,
 134                                                          GMount               *mount,
 135                                                          TrackerMinerFiles    *mf);
 136 
 137 static void        mount_point_added_cb                 (TrackerStorage       *storage,
 138                                                          const gchar          *uuid,
 139                                                          const gchar          *mount_point,
 140                                                          const gchar          *mount_name,
 141                                                          gboolean              removable,
 142                                                          gboolean              optical,
 143                                                          gpointer              user_data);
 144 static void        mount_point_removed_cb               (TrackerStorage       *storage,
 145                                                          const gchar          *uuid,
 146                                                          const gchar          *mount_point,
 147                                                          gpointer              user_data);
 148 #if defined(HAVE_UPOWER) || defined(HAVE_HAL)
 149 static void        check_battery_status                 (TrackerMinerFiles    *fs);
 150 static void        battery_status_cb                    (GObject              *object,
 151                                                          GParamSpec           *pspec,
 152                                                          gpointer              user_data);
 153 static void        index_on_battery_cb                  (GObject    *object,
 154                                                          GParamSpec *pspec,
 155                                                          gpointer    user_data);
 156 #endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */
 157 static void        init_mount_points                    (TrackerMinerFiles    *miner);
 158 static void        init_stale_volume_removal            (TrackerMinerFiles    *miner);
 159 static void        disk_space_check_start               (TrackerMinerFiles    *mf);
 160 static void        disk_space_check_stop                (TrackerMinerFiles    *mf);
 161 static void        low_disk_space_limit_cb              (GObject              *gobject,
 162                                                          GParamSpec           *arg1,
 163                                                          gpointer              user_data);
 164 static void        index_recursive_directories_cb       (GObject              *gobject,
 165                                                          GParamSpec           *arg1,
 166                                                          gpointer              user_data);
 167 static void        index_single_directories_cb          (GObject              *gobject,
 168                                                          GParamSpec           *arg1,
 169                                                          gpointer              user_data);
 170 static gboolean    miner_files_force_recheck_idle       (gpointer user_data);
 171 static void        trigger_recheck_cb                   (GObject              *gobject,
 172                                                          GParamSpec           *arg1,
 173                                                          gpointer              user_data);
 174 static void        index_volumes_changed_cb             (GObject              *gobject,
 175                                                          GParamSpec           *arg1,
 176                                                          gpointer              user_data);
 177 static gboolean    miner_files_process_file             (TrackerMinerFS       *fs,
 178                                                          GFile                *file,
 179                                                          TrackerSparqlBuilder *sparql,
 180                                                          GCancellable         *cancellable);
 181 static gboolean    miner_files_process_file_attributes  (TrackerMinerFS       *fs,
 182                                                          GFile                *file,
 183                                                          TrackerSparqlBuilder *sparql,
 184                                                          GCancellable         *cancellable);
 185 static gboolean    miner_files_ignore_next_update_file  (TrackerMinerFS       *fs,
 186                                                          GFile                *file,
 187                                                          TrackerSparqlBuilder *sparql,
 188                                                          GCancellable         *cancellable);
 189 static void        miner_files_finished                 (TrackerMinerFS       *fs);
 190 
 191 static void        miner_finished_cb                    (TrackerMinerFS *fs,
 192                                                          gdouble         seconds_elapsed,
 193                                                          guint           total_directories_found,
 194                                                          guint           total_directories_ignored,
 195                                                          guint           total_files_found,
 196                                                          guint           total_files_ignored,
 197                                                          gpointer        user_data);
 198 
 199 static gboolean    miner_files_in_removable_media_remove_by_type  (TrackerMinerFiles  *miner,
 200                                                                    TrackerStorageType  type);
 201 static void        miner_files_in_removable_media_remove_by_date  (TrackerMinerFiles  *miner,
 202                                                                    const gchar        *date);
 203 
 204 static void        miner_files_add_removable_or_optical_directory (TrackerMinerFiles *mf,
 205                                                                    const gchar       *mount_path,
 206                                                                    const gchar       *uuid);
 207 
 208 static void        extractor_process_failsafe                     (TrackerMinerFiles *miner);
 209 
 210 static void        miner_files_update_filters                     (TrackerMinerFiles *files);
 211 
 212 
 213 static GInitableIface* miner_files_initable_parent_iface;
 214 
 215 G_DEFINE_TYPE_WITH_CODE (TrackerMinerFiles, tracker_miner_files, TRACKER_TYPE_MINER_FS,
 216                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
 217                                                 miner_files_initable_iface_init));
 218 
 219 static void
 220 tracker_miner_files_class_init (TrackerMinerFilesClass *klass)
 221 {
 222 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 223 	TrackerMinerFSClass *miner_fs_class = TRACKER_MINER_FS_CLASS (klass);
 224 
 225 	object_class->finalize = miner_files_finalize;
 226 	object_class->get_property = miner_files_get_property;
 227 	object_class->set_property = miner_files_set_property;
 228 
 229 	miner_fs_class->process_file = miner_files_process_file;
 230 	miner_fs_class->process_file_attributes = miner_files_process_file_attributes;
 231 	miner_fs_class->ignore_next_update_file = miner_files_ignore_next_update_file;
 232 	miner_fs_class->finished = miner_files_finished;
 233 
 234 	g_object_class_install_property (object_class,
 235 	                                 PROP_CONFIG,
 236 	                                 g_param_spec_object ("config",
 237 	                                                      "Config",
 238 	                                                      "Config",
 239 	                                                      TRACKER_TYPE_CONFIG,
 240 	                                                      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 241 
 242 	g_type_class_add_private (klass, sizeof (TrackerMinerFilesPrivate));
 243 
 244 	miner_files_error_quark = g_quark_from_static_string ("TrackerMinerFiles");
 245 }
 246 
 247 static void
 248 tracker_miner_files_init (TrackerMinerFiles *mf)
 249 {
 250 	TrackerMinerFilesPrivate *priv;
 251 
 252 	priv = mf->private = TRACKER_MINER_FILES_GET_PRIVATE (mf);
 253 
 254 	priv->storage = tracker_storage_new ();
 255 
 256 	g_signal_connect (priv->storage, "mount-point-added",
 257 	                  G_CALLBACK (mount_point_added_cb),
 258 	                  mf);
 259 
 260 	g_signal_connect (priv->storage, "mount-point-removed",
 261 	                  G_CALLBACK (mount_point_removed_cb),
 262 	                  mf);
 263 
 264 #if defined(HAVE_UPOWER) || defined(HAVE_HAL)
 265 	priv->power = tracker_power_new ();
 266 
 267 	g_signal_connect (priv->power, "notify::on-low-battery",
 268 	                  G_CALLBACK (battery_status_cb),
 269 	                  mf);
 270 	g_signal_connect (priv->power, "notify::on-battery",
 271 	                  G_CALLBACK (battery_status_cb),
 272 	                  mf);
 273 #endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */
 274 
 275 	priv->finished_handler = g_signal_connect_after (mf, "finished",
 276 	                                                 G_CALLBACK (miner_finished_cb),
 277 	                                                 NULL);
 278 
 279 	priv->volume_monitor = g_volume_monitor_get ();
 280 	g_signal_connect (priv->volume_monitor, "mount-pre-unmount",
 281 	                  G_CALLBACK (mount_pre_unmount_cb),
 282 	                  mf);
 283 
 284 	priv->quark_mount_point_uuid = g_quark_from_static_string ("tracker-mount-point-uuid");
 285 }
 286 
 287 static void
 288 miner_files_initable_iface_init (GInitableIface *iface)
 289 {
 290 	miner_files_initable_parent_iface = g_type_interface_peek_parent (iface);
 291 	iface->init = miner_files_initable_init;
 292 }
 293 
 294 static gboolean
 295 miner_files_initable_init (GInitable     *initable,
 296                            GCancellable  *cancellable,
 297                            GError       **error)
 298 {
 299 	TrackerMinerFiles *mf;
 300 	TrackerMinerFS *fs;
 301 	TrackerIndexingTree *indexing_tree;
 302 	TrackerDirectoryFlags flags;
 303 	GError *inner_error = NULL;
 304 	GSList *mounts = NULL;
 305 	GSList *dirs;
 306 	GSList *m;
 307 
 308 	mf = TRACKER_MINER_FILES (initable);
 309 	fs = TRACKER_MINER_FS (initable);
 310 	indexing_tree = tracker_miner_fs_get_indexing_tree (fs);
 311 	tracker_indexing_tree_set_filter_hidden (indexing_tree, TRUE);
 312 
 313 	miner_files_update_filters (mf);
 314 
 315 	/* Chain up parent's initable callback before calling child's one */
 316 	if (!miner_files_initable_parent_iface->init (initable, cancellable, &inner_error)) {
 317 		g_propagate_error (error, inner_error);
 318 		return FALSE;
 319 	}
 320 
 321 	/* Set up extractor and signals */
 322 	mf->private->connection =  g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &inner_error);
 323 	if (!mf->private->connection) {
 324 		g_propagate_error (error, inner_error);
 325 		g_prefix_error (error,
 326 		                "Could not connect to the D-Bus session bus. ");
 327 		return FALSE;
 328 	}
 329 
 330 	/* Setup mount points */
 331 	init_mount_points (mf);
 332 
 333 	/* We must have a configuration setup here */
 334 	if (G_UNLIKELY (!mf->private->config)) {
 335 		g_set_error (error,
 336 		             TRACKER_MINER_ERROR,
 337 		             0,
 338 		             "No config set for miner %s",
 339 		             G_OBJECT_TYPE_NAME (mf));
 340 		return FALSE;
 341 	}
 342 
 343 	/* If this happened AFTER we have initialized mount points, initialize
 344 	 * stale volume removal now. */
 345 	if (mf->private->mount_points_initialized) {
 346 		init_stale_volume_removal (mf);
 347 	}
 348 
 349 	/* Setup initial flag for removable devices */
 350 	mf->private->index_removable_devices = tracker_config_get_index_removable_devices (mf->private->config);
 351 	if (mf->private->index_removable_devices) {
 352 		/* Get list of roots for removable devices (excluding optical) */
 353 		mounts = tracker_storage_get_device_roots (mf->private->storage,
 354 		                                           TRACKER_STORAGE_REMOVABLE,
 355 		                                           TRUE);
 356 	}
 357 
 358 	/* Setup initial flag for optical discs. Note that if removable devices not indexed,
 359 	 * optical discs will also never be indexed */
 360 	mf->private->index_optical_discs = (mf->private->index_removable_devices ?
 361 	                                    tracker_config_get_index_optical_discs (mf->private->config) :
 362 	                                    FALSE);
 363 	if (mf->private->index_optical_discs) {
 364 		/* Get list of roots for removable+optical devices */
 365 		m = tracker_storage_get_device_roots (mf->private->storage,
 366 		                                      TRACKER_STORAGE_OPTICAL | TRACKER_STORAGE_REMOVABLE,
 367 		                                      TRUE);
 368 		mounts = g_slist_concat (mounts, m);
 369 	}
 370 
 371 #if defined(HAVE_UPOWER) || defined(HAVE_HAL)
 372 	check_battery_status (mf);
 373 #endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */
 374 
 375 	g_message ("Setting up directories to iterate from config (IndexSingleDirectory)");
 376 
 377 	/* Fill in directories to inspect */
 378 	dirs = tracker_config_get_index_single_directories (mf->private->config);
 379 
 380 	/* Copy in case of config changes */
 381 	mf->private->index_single_directories = tracker_gslist_copy_with_string_data (dirs);
 382 
 383 	for (; dirs; dirs = dirs->next) {
 384 		GFile *file;
 385 
 386 		/* Do some simple checks for silly locations */
 387 		if (strcmp (dirs->data, "/dev") == 0 ||
 388 		    strcmp (dirs->data, "/lib") == 0 ||
 389 		    strcmp (dirs->data, "/proc") == 0 ||
 390 		    strcmp (dirs->data, "/sys") == 0) {
 391 			continue;
 392 		}
 393 
 394 		if (g_str_has_prefix (dirs->data, g_get_tmp_dir ())) {
 395 			continue;
 396 		}
 397 
 398 		/* Make sure we don't crawl volumes. */
 399 		if (mounts) {
 400 			gboolean found = FALSE;
 401 
 402 			for (m = mounts; m && !found; m = m->next) {
 403 				found = strcmp (m->data, dirs->data) == 0;
 404 			}
 405 
 406 			if (found) {
 407 				g_message ("  Duplicate found:'%s' - same as removable device path",
 408 				           (gchar*) dirs->data);
 409 				continue;
 410 			}
 411 		}
 412 
 413 		g_message ("  Adding:'%s'", (gchar*) dirs->data);
 414 
 415 		file = g_file_new_for_path (dirs->data);
 416 
 417 		flags = TRACKER_DIRECTORY_FLAG_NONE;
 418 
 419 		if (tracker_config_get_enable_monitors (mf->private->config)) {
 420 			flags |= TRACKER_DIRECTORY_FLAG_MONITOR;
 421 		}
 422 
 423 		if (tracker_miner_fs_get_mtime_checking (TRACKER_MINER_FS (mf))) {
 424 			flags |= TRACKER_DIRECTORY_FLAG_CHECK_MTIME;
 425 		}
 426 
 427 		tracker_indexing_tree_add (indexing_tree, file, flags);
 428 		g_object_unref (file);
 429 	}
 430 
 431 	g_message ("Setting up directories to iterate from config (IndexRecursiveDirectory)");
 432 
 433 	dirs = tracker_config_get_index_recursive_directories (mf->private->config);
 434 
 435 	/* Copy in case of config changes */
 436 	mf->private->index_recursive_directories = tracker_gslist_copy_with_string_data (dirs);
 437 
 438 	for (; dirs; dirs = dirs->next) {
 439 		GFile *file;
 440 
 441 		/* Do some simple checks for silly locations */
 442 		if (strcmp (dirs->data, "/dev") == 0 ||
 443 		    strcmp (dirs->data, "/lib") == 0 ||
 444 		    strcmp (dirs->data, "/proc") == 0 ||
 445 		    strcmp (dirs->data, "/sys") == 0) {
 446 			continue;
 447 		}
 448 
 449 		if (g_str_has_prefix (dirs->data, g_get_tmp_dir ())) {
 450 			continue;
 451 		}
 452 
 453 		/* Make sure we don't crawl volumes. */
 454 		if (mounts) {
 455 			gboolean found = FALSE;
 456 
 457 			for (m = mounts; m && !found; m = m->next) {
 458 				found = strcmp (m->data, dirs->data) == 0;
 459 			}
 460 
 461 			if (found) {
 462 				g_message ("  Duplicate found:'%s' - same as removable device path",
 463 				           (gchar*) dirs->data);
 464 				continue;
 465 			}
 466 		}
 467 
 468 		g_message ("  Adding:'%s'", (gchar*) dirs->data);
 469 
 470 		file = g_file_new_for_path (dirs->data);
 471 
 472 		flags = TRACKER_DIRECTORY_FLAG_RECURSE;
 473 
 474 		if (tracker_config_get_enable_monitors (mf->private->config)) {
 475 			flags |= TRACKER_DIRECTORY_FLAG_MONITOR;
 476 		}
 477 
 478 		if (tracker_miner_fs_get_mtime_checking (TRACKER_MINER_FS (mf))) {
 479 			flags |= TRACKER_DIRECTORY_FLAG_CHECK_MTIME;
 480 		}
 481 
 482 		tracker_indexing_tree_add (indexing_tree, file, flags);
 483 		g_object_unref (file);
 484 	}
 485 
 486 	/* Add mounts */
 487 	g_message ("Setting up directories to iterate from devices/discs");
 488 
 489 	if (!mf->private->index_removable_devices) {
 490 		g_message ("  Removable devices are disabled in the config");
 491 
 492 		/* Make sure we don't have any resource in a volume of the given type */
 493 		miner_files_in_removable_media_remove_by_type (mf, TRACKER_STORAGE_REMOVABLE);
 494 	}
 495 
 496 	if (!mf->private->index_optical_discs) {
 497 		g_message ("  Optical discs are disabled in the config");
 498 
 499 		/* Make sure we don't have any resource in a volume of the given type */
 500 		miner_files_in_removable_media_remove_by_type (mf, TRACKER_STORAGE_REMOVABLE | TRACKER_STORAGE_OPTICAL);
 501 	}
 502 
 503 	for (m = mounts; m; m = m->next) {
 504 		miner_files_add_removable_or_optical_directory (mf,
 505 		                                                (gchar *) m->data,
 506 		                                                NULL);
 507 	}
 508 
 509 	/* We want to get notified when config changes */
 510 
 511 	g_signal_connect (mf->private->config, "notify::low-disk-space-limit",
 512 	                  G_CALLBACK (low_disk_space_limit_cb),
 513 	                  mf);
 514 	g_signal_connect (mf->private->config, "notify::index-recursive-directories",
 515 	                  G_CALLBACK (index_recursive_directories_cb),
 516 	                  mf);
 517 	g_signal_connect (mf->private->config, "notify::index-single-directories",
 518 	                  G_CALLBACK (index_single_directories_cb),
 519 	                  mf);
 520 	g_signal_connect (mf->private->config, "notify::ignored-directories",
 521 	                  G_CALLBACK (trigger_recheck_cb),
 522 	                  mf);
 523 	g_signal_connect (mf->private->config, "notify::ignored-directories-with-content",
 524 	                  G_CALLBACK (trigger_recheck_cb),
 525 	                  mf);
 526 	g_signal_connect (mf->private->config, "notify::ignored-files",
 527 	                  G_CALLBACK (trigger_recheck_cb),
 528 	                  mf);
 529 	g_signal_connect (mf->private->config, "notify::index-removable-devices",
 530 	                  G_CALLBACK (index_volumes_changed_cb),
 531 	                  mf);
 532 	g_signal_connect (mf->private->config, "notify::index-optical-discs",
 533 	                  G_CALLBACK (index_volumes_changed_cb),
 534 	                  mf);
 535 	g_signal_connect (mf->private->config, "notify::removable-days-threshold",
 536 	                  G_CALLBACK (index_volumes_changed_cb),
 537 	                  mf);
 538 
 539 #if defined(HAVE_UPOWER) || defined(HAVE_HAL)
 540 
 541 	g_signal_connect (mf->private->config, "notify::index-on-battery",
 542 	                  G_CALLBACK (index_on_battery_cb),
 543 	                  mf);
 544 	g_signal_connect (mf->private->config, "notify::index-on-battery-first-time",
 545 	                  G_CALLBACK (index_on_battery_cb),
 546 	                  mf);
 547 
 548 #endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */
 549 
 550 	g_slist_foreach (mounts, (GFunc) g_free, NULL);
 551 	g_slist_free (mounts);
 552 
 553 	disk_space_check_start (mf);
 554 
 555 	return TRUE;
 556 }
 557 
 558 static void
 559 miner_files_set_property (GObject      *object,
 560                           guint         prop_id,
 561                           const GValue *value,
 562                           GParamSpec   *pspec)
 563 {
 564 	TrackerMinerFilesPrivate *priv;
 565 
 566 	priv = TRACKER_MINER_FILES_GET_PRIVATE (object);
 567 
 568 	switch (prop_id) {
 569 	case PROP_CONFIG:
 570 		priv->config = g_value_dup_object (value);
 571 		break;
 572 	default:
 573 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 574 		break;
 575 	}
 576 }
 577 
 578 static void
 579 miner_files_get_property (GObject    *object,
 580                           guint       prop_id,
 581                           GValue     *value,
 582                           GParamSpec *pspec)
 583 {
 584 	TrackerMinerFilesPrivate *priv;
 585 
 586 	priv = TRACKER_MINER_FILES_GET_PRIVATE (object);
 587 
 588 	switch (prop_id) {
 589 	case PROP_CONFIG:
 590 		g_value_set_object (value, priv->config);
 591 		break;
 592 	default:
 593 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 594 		break;
 595 	}
 596 }
 597 
 598 static void
 599 miner_files_finalize (GObject *object)
 600 {
 601 	TrackerMinerFiles *mf;
 602 	TrackerMinerFilesPrivate *priv;
 603 
 604 	mf = TRACKER_MINER_FILES (object);
 605 	priv = mf->private;
 606 
 607 	if (priv->config) {
 608 		g_signal_handlers_disconnect_by_func (priv->config,
 609 		                                      low_disk_space_limit_cb,
 610 		                                      NULL);
 611 		g_object_unref (priv->config);
 612 	}
 613 
 614 	disk_space_check_stop (TRACKER_MINER_FILES (object));
 615 
 616 	if (priv->index_recursive_directories) {
 617 		g_slist_foreach (priv->index_recursive_directories, (GFunc) g_free, NULL);
 618 		g_slist_free (priv->index_recursive_directories);
 619 	}
 620 
 621 	if (priv->index_single_directories) {
 622 		g_slist_foreach (priv->index_single_directories, (GFunc) g_free, NULL);
 623 		g_slist_free (priv->index_single_directories);
 624 	}
 625 
 626 #if defined(HAVE_UPOWER) || defined(HAVE_HAL)
 627 	if (priv->power) {
 628 		g_object_unref (priv->power);
 629 	}
 630 #endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */
 631 
 632 	if (priv->storage) {
 633 		g_object_unref (priv->storage);
 634 	}
 635 
 636 	if (priv->volume_monitor) {
 637 		g_signal_handlers_disconnect_by_func (priv->volume_monitor,
 638 		                                      mount_pre_unmount_cb,
 639 		                                      object);
 640 		g_object_unref (priv->volume_monitor);
 641 	}
 642 
 643 	if (priv->force_recheck_id) {
 644 		g_source_remove (priv->force_recheck_id);
 645 		priv->force_recheck_id = 0;
 646 	}
 647 
 648 	if (priv->stale_volumes_check_id) {
 649 		g_source_remove (priv->stale_volumes_check_id);
 650 		priv->stale_volumes_check_id = 0;
 651 	}
 652 
 653 	g_list_free (priv->extraction_queue);
 654 	g_list_free (priv->failed_extraction_queue);
 655 
 656 	G_OBJECT_CLASS (tracker_miner_files_parent_class)->finalize (object);
 657 }
 658 
 659 static void
 660 ensure_mount_point_exists (TrackerMinerFiles *miner,
 661                            GFile             *mount_point,
 662                            GString           *accumulator)
 663 {
 664 	gchar *iri;
 665 	gchar *uri;
 666 
 667 	uri = g_file_get_uri (mount_point);
 668 
 669 	/* Query the store for the URN of the mount point */
 670 	iri = tracker_miner_fs_query_urn (TRACKER_MINER_FS (miner),
 671 	                                  mount_point);
 672 
 673 	if (iri) {
 674 		/* If exists, just return, nothing else to do */
 675 		g_message ("Mount point '%s' already exists in store: '%s'",
 676 		           uri, iri);
 677 		g_free (iri);
 678 	} else {
 679 		/* If it doesn't exist, we need to create it */
 680 		g_message ("Mount point '%s' does not exist in store, need to create it",
 681 		           uri);
 682 
 683 		/* Create a nfo:Folder for the mount point */
 684 		g_string_append_printf (accumulator,
 685 		                        "INSERT SILENT INTO <" TRACKER_MINER_FS_GRAPH_URN "> {"
 686 		                        " _:file a nfo:FileDataObject, nie:InformationElement, nfo:Folder ; "
 687 		                        "        nie:isStoredAs _:file ; "
 688 		                        "        nie:url \"%s\" ; "
 689 		                        "        nie:mimeType \"inode/directory\" ; "
 690 		                        "        nfo:fileLastModified \"1981-06-05T02:20:00Z\" . "
 691 		                        "}",
 692 		                        uri);
 693 	}
 694 
 695 	g_free (uri);
 696 }
 697 
 698 static void
 699 set_up_mount_point_cb (GObject      *source,
 700                        GAsyncResult *result,
 701                        gpointer      user_data)
 702 {
 703 	TrackerSparqlConnection *connection = TRACKER_SPARQL_CONNECTION (source);
 704 	gchar *removable_device_urn = user_data;
 705 	GError *error = NULL;
 706 
 707 	tracker_sparql_connection_update_finish (connection, result, &error);
 708 
 709 	if (error) {
 710 		g_critical ("Could not set mount point in database '%s', %s",
 711 		            removable_device_urn,
 712 		            error->message);
 713 		g_error_free (error);
 714 	}
 715 
 716 	g_free (removable_device_urn);
 717 }
 718 
 719 static void
 720 set_up_mount_point_type (TrackerMinerFiles *miner,
 721                          const gchar       *removable_device_urn,
 722                          gboolean           removable,
 723                          gboolean           optical,
 724                          GString           *accumulator)
 725 {
 726 	if (!accumulator) {
 727 		return;
 728 	}
 729 
 730 	g_debug ("Mount point type being set in DB for URN '%s'",
 731 	         removable_device_urn);
 732 
 733 	g_string_append_printf (accumulator,
 734 	                        "DELETE { <%s> tracker:isRemovable ?unknown } WHERE { <%s> a tracker:Volume; tracker:isRemovable ?unknown } ",
 735 	                        removable_device_urn, removable_device_urn);
 736 
 737 	g_string_append_printf (accumulator,
 738 	                        "INSERT INTO <%s> { <%s> a tracker:Volume; tracker:isRemovable %s } ",
 739 	                        removable_device_urn, removable_device_urn, removable ? "true" : "false");
 740 
 741 	g_string_append_printf (accumulator,
 742 	                        "DELETE { <%s> tracker:isOptical ?unknown } WHERE { <%s> a tracker:Volume; tracker:isOptical ?unknown } ",
 743 	                        removable_device_urn, removable_device_urn);
 744 
 745 	g_string_append_printf (accumulator,
 746 	                        "INSERT INTO <%s> { <%s> a tracker:Volume; tracker:isOptical %s } ",
 747 	                        removable_device_urn, removable_device_urn, optical ? "true" : "false");
 748 }
 749 
 750 static void
 751 set_up_mount_point (TrackerMinerFiles *miner,
 752                     const gchar       *removable_device_urn,
 753                     const gchar       *mount_point,
 754                     const gchar       *mount_name,
 755                     gboolean           mounted,
 756                     GString           *accumulator)
 757 {
 758 	GString *queries;
 759 
 760 	queries = g_string_new (NULL);
 761 
 762 	if (mounted) {
 763 		g_debug ("Mount point state (MOUNTED) being set in DB for URN '%s' (mount_point: %s)",
 764 		         removable_device_urn,
 765 		         mount_point ? mount_point : "unknown");
 766 
 767 		if (mount_point) {
 768 			GFile *file;
 769 			gchar *uri;
 770 
 771 			file = g_file_new_for_path (mount_point);
 772 			uri = g_file_get_uri (file);
 773 
 774 			/* Before assigning a nfo:FileDataObject as tracker:mountPoint for
 775 			 * the volume, make sure the nfo:FileDataObject exists in the store */
 776 			ensure_mount_point_exists (miner, file, queries);
 777 
 778 			g_string_append_printf (queries,
 779 			                        "DELETE { "
 780 			                        "  <%s> tracker:mountPoint ?u "
 781 			                        "} WHERE { "
 782 			                        "  ?u a nfo:FileDataObject; "
 783 			                        "     nie:url \"%s\" "
 784 			                        "} ",
 785 			                        removable_device_urn, uri);
 786 
 787 			g_string_append_printf (queries,
 788 			                        "DELETE { <%s> a rdfs:Resource }  "
 789 			                        "INSERT { "
 790 			                        "  <%s> a tracker:Volume; "
 791 			                        "       tracker:mountPoint ?u "
 792 			                        "} WHERE { "
 793 			                        "  ?u a nfo:FileDataObject; "
 794 			                        "     nie:url \"%s\" "
 795 			                        "} ",
 796 			                        removable_device_urn, removable_device_urn, uri);
 797 
 798 			g_object_unref (file);
 799 			g_free (uri);
 800 		}
 801 
 802 		g_string_append_printf (queries,
 803 		                        "DELETE { <%s> tracker:isMounted ?unknown } WHERE { <%s> a tracker:Volume; tracker:isMounted ?unknown } ",
 804 		                        removable_device_urn, removable_device_urn);
 805 
 806                 if (mount_name) {
 807                         g_string_append_printf (queries,
 808                                                 "INSERT INTO <%s> { <%s> a tracker:Volume; tracker:isMounted true; nie:title \"%s\" } ",
 809                                                 removable_device_urn, removable_device_urn, mount_name);
 810                 } else {
 811                         g_string_append_printf (queries,
 812                                                 "INSERT INTO <%s> { <%s> a tracker:Volume; tracker:isMounted true } ",
 813                                                 removable_device_urn, removable_device_urn);
 814                 }
 815 
 816                 g_string_append_printf (queries,
 817                                         "INSERT { GRAPH <%s> { ?do tracker:available true } } WHERE { ?do nie:dataSource <%s> } ",
 818                                         removable_device_urn, removable_device_urn);
 819 	} else {
 820 		gchar *now;
 821 
 822 		g_debug ("Mount point state (UNMOUNTED) being set in DB for URN '%s'",
 823 		         removable_device_urn);
 824 
 825 		now = tracker_date_to_string (time (NULL));
 826 
 827 		g_string_append_printf (queries,
 828 		                        "DELETE { <%s> tracker:unmountDate ?unknown } WHERE { <%s> a tracker:Volume; tracker:unmountDate ?unknown } ",
 829 		                        removable_device_urn, removable_device_urn);
 830 
 831 		g_string_append_printf (queries,
 832 		                        "INSERT INTO <%s> { <%s> a tracker:Volume; tracker:unmountDate \"%s\" } ",
 833 		                        removable_device_urn, removable_device_urn, now);
 834 
 835 		g_string_append_printf (queries,
 836 		                        "DELETE { <%s> tracker:isMounted ?unknown } WHERE { <%s> a tracker:Volume; tracker:isMounted ?unknown } ",
 837 		                        removable_device_urn, removable_device_urn);
 838 
 839 		g_string_append_printf (queries,
 840 		                        "INSERT INTO <%s> { <%s> a tracker:Volume; tracker:isMounted false } ",
 841 		                        removable_device_urn, removable_device_urn);
 842 
 843 		g_string_append_printf (queries,
 844 		                        "DELETE { ?do tracker:available true } WHERE { ?do nie:dataSource <%s> } ",
 845 		                        removable_device_urn);
 846 
 847 		g_free (now);
 848 	}
 849 
 850 	if (accumulator) {
 851 		g_string_append_printf (accumulator, "%s ", queries->str);
 852 	} else {
 853 		tracker_sparql_connection_update_async (tracker_miner_get_connection (TRACKER_MINER (miner)),
 854 		                                        queries->str,
 855 		                                        G_PRIORITY_LOW,
 856 		                                        NULL,
 857 		                                        set_up_mount_point_cb,
 858 		                                        g_strdup (removable_device_urn));
 859 	}
 860 
 861 	g_string_free (queries, TRUE);
 862 }
 863 
 864 static void
 865 init_mount_points_cb (GObject      *source,
 866                       GAsyncResult *result,
 867                       gpointer      user_data)
 868 {
 869 	GError *error = NULL;
 870 
 871 	tracker_sparql_connection_update_finish (TRACKER_SPARQL_CONNECTION (source),
 872 	                                         result,
 873 	                                         &error);
 874 
 875 	if (error) {
 876 		g_critical ("Could not initialize currently active mount points: %s",
 877 		            error->message);
 878 		g_error_free (error);
 879 	} else {
 880 		/* Mount points correctly initialized */
 881 		(TRACKER_MINER_FILES (user_data))->private->mount_points_initialized = TRUE;
 882 		/* If this happened AFTER we have a proper config, initialize
 883 		 * stale volume removal now. */
 884 		if ((TRACKER_MINER_FILES (user_data))->private->config) {
 885 			init_stale_volume_removal (TRACKER_MINER_FILES (user_data));
 886 		}
 887 	}
 888 }
 889 
 890 static void
 891 init_mount_points (TrackerMinerFiles *miner_files)
 892 {
 893 	TrackerMiner *miner = TRACKER_MINER (miner_files);
 894 	TrackerMinerFilesPrivate *priv;
 895 	GHashTable *volumes;
 896 	GHashTableIter iter;
 897 	gpointer key, value;
 898 	GString *accumulator;
 899 	GError *error = NULL;
 900 	TrackerSparqlCursor *cursor;
 901 	GSList *uuids, *u;
 902 
 903 	g_debug ("Initializing mount points...");
 904 
 905 	/* First, get all mounted volumes, according to tracker-store (SYNC!) */
 906 	cursor = tracker_sparql_connection_query (tracker_miner_get_connection (miner),
 907 	                                          "SELECT ?v WHERE { ?v a tracker:Volume ; tracker:isMounted true }",
 908 	                                          NULL, &error);
 909 	if (error) {
 910 		g_critical ("Could not obtain the mounted volumes: %s", error->message);
 911 		g_error_free (error);
 912 		return;
 913 	}
 914 
 915 	priv = TRACKER_MINER_FILES_GET_PRIVATE (miner);
 916 
 917 	volumes = g_hash_table_new_full (g_str_hash, g_str_equal,
 918 	                                 (GDestroyNotify) g_free,
 919 	                                 NULL);
 920 
 921 
 922 	/* Make sure the root partition is always set to mounted, as GIO won't
 923 	 * report it as a proper mount */
 924 	g_hash_table_insert (volumes,
 925 	                     g_strdup (TRACKER_NON_REMOVABLE_MEDIA_DATASOURCE_URN),
 926 	                     GINT_TO_POINTER (VOLUME_MOUNTED));
 927 
 928 	while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
 929 		gint state;
 930 		const gchar *urn;
 931 
 932 		state = VOLUME_MOUNTED_IN_STORE;
 933 
 934 		urn = tracker_sparql_cursor_get_string (cursor, 0, NULL);
 935 
 936 		if (strcmp (urn, TRACKER_NON_REMOVABLE_MEDIA_DATASOURCE_URN) == 0) {
 937 			/* Report non-removable media to be mounted by HAL as well */
 938 			state |= VOLUME_MOUNTED;
 939 		}
 940 
 941 		g_hash_table_replace (volumes, g_strdup (urn), GINT_TO_POINTER (state));
 942 	}
 943 
 944 	g_object_unref (cursor);
 945 
 946 	/* Then, get all currently mounted non-REMOVABLE volumes, according to GIO */
 947 	uuids = tracker_storage_get_device_uuids (priv->storage, 0, TRUE);
 948 	for (u = uuids; u; u = u->next) {
 949 		const gchar *uuid;
 950 		gchar *non_removable_device_urn;
 951 		gint state;
 952 
 953 		uuid = u->data;
 954 		non_removable_device_urn = g_strdup_printf (TRACKER_DATASOURCE_URN_PREFIX "%s", uuid);
 955 
 956 		state = GPOINTER_TO_INT (g_hash_table_lookup (volumes, non_removable_device_urn));
 957 		state |= VOLUME_MOUNTED;
 958 
 959 		g_hash_table_replace (volumes, non_removable_device_urn, GINT_TO_POINTER (state));
 960 	}
 961 
 962 	g_slist_foreach (uuids, (GFunc) g_free, NULL);
 963 	g_slist_free (uuids);
 964 
 965 	/* Then, get all currently mounted REMOVABLE volumes, according to GIO */
 966 	if (priv->index_removable_devices) {
 967 		uuids = tracker_storage_get_device_uuids (priv->storage, TRACKER_STORAGE_REMOVABLE, FALSE);
 968 		for (u = uuids; u; u = u->next) {
 969 			const gchar *uuid;
 970 			gchar *removable_device_urn;
 971 			gint state;
 972 
 973 			uuid = u->data;
 974 			removable_device_urn = g_strdup_printf (TRACKER_DATASOURCE_URN_PREFIX "%s", uuid);
 975 
 976 			state = GPOINTER_TO_INT (g_hash_table_lookup (volumes, removable_device_urn));
 977 			state |= VOLUME_MOUNTED;
 978 
 979 			g_hash_table_replace (volumes, removable_device_urn, GINT_TO_POINTER (state));
 980 		}
 981 
 982 		g_slist_foreach (uuids, (GFunc) g_free, NULL);
 983 		g_slist_free (uuids);
 984 	}
 985 
 986 	accumulator = g_string_new (NULL);
 987 	g_hash_table_iter_init (&iter, volumes);
 988 
 989 	/* Finally, set up volumes based on the composed info */
 990 	while (g_hash_table_iter_next (&iter, &key, &value)) {
 991 		const gchar *urn = key;
 992 		gint state = GPOINTER_TO_INT (value);
 993 
 994 		if ((state & VOLUME_MOUNTED) &&
 995 		    !(state & VOLUME_MOUNTED_IN_STORE)) {
 996 			const gchar *mount_point = NULL;
 997 			TrackerStorageType type = 0;
 998 
 999 			/* Note: is there any case where the urn doesn't have our
1000 			 *  datasource prefix? */
1001 			if (g_str_has_prefix (urn, TRACKER_DATASOURCE_URN_PREFIX)) {
1002 				const gchar *uuid;
1003 
1004 				uuid = urn + strlen (TRACKER_DATASOURCE_URN_PREFIX);
1005 				mount_point = tracker_storage_get_mount_point_for_uuid (priv->storage, uuid);
1006 				type = tracker_storage_get_type_for_uuid (priv->storage, uuid);
1007 			}
1008 
1009 			if (urn) {
1010 				if (mount_point) {
1011 					g_debug ("Mount point state incorrect in DB for URN '%s', "
1012 					         "currently it is mounted on '%s'",
1013 					         urn,
1014 					         mount_point);
1015 				} else {
1016 					g_debug ("Mount point state incorrect in DB for URN '%s', "
1017 					         "currently it is mounted",
1018 					         urn);
1019 				}
1020 
1021 				/* Set mount point state */
1022 				set_up_mount_point (TRACKER_MINER_FILES (miner),
1023 				                    urn,
1024 				                    mount_point,
1025                                                     NULL,
1026 				                    TRUE,
1027 				                    accumulator);
1028 
1029 				/* Set mount point type */
1030 				set_up_mount_point_type (TRACKER_MINER_FILES (miner),
1031 				                         urn,
1032 				                         TRACKER_STORAGE_TYPE_IS_REMOVABLE (type),
1033 				                         TRACKER_STORAGE_TYPE_IS_OPTICAL (type),
1034 				                         accumulator);
1035 
1036 				if (mount_point) {
1037 					TrackerIndexingTree *indexing_tree;
1038 					TrackerDirectoryFlags flags;
1039 					GFile *file;
1040 
1041 					indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (miner));
1042 					flags = TRACKER_DIRECTORY_FLAG_RECURSE |
1043 						TRACKER_DIRECTORY_FLAG_CHECK_MTIME |
1044 						TRACKER_DIRECTORY_FLAG_PRESERVE;
1045 
1046 					if (tracker_config_get_enable_monitors (miner_files->private->config)) {
1047 						flags |= TRACKER_DIRECTORY_FLAG_MONITOR;
1048 					}
1049 
1050 					/* Add the current mount point as reported to have incorrect
1051 					 * state. We will force mtime checks on this mount points,
1052 					 * even if no-mtime-check-needed was set. */
1053 					file = g_file_new_for_path (mount_point);
1054 					if (tracker_miner_files_is_file_eligible (miner_files, file)) {
1055 						tracker_indexing_tree_add (indexing_tree,
1056 									   file,
1057 									   flags);
1058 					}
1059 					g_object_unref (file);
1060 				}
1061 			}
1062 		} else if (!(state & VOLUME_MOUNTED) &&
1063 		           (state & VOLUME_MOUNTED_IN_STORE)) {
1064 			if (urn) {
1065 				g_debug ("Mount point state incorrect in DB for URN '%s', "
1066 				         "currently it is NOT mounted",
1067 				         urn);
1068 				set_up_mount_point (TRACKER_MINER_FILES (miner),
1069 				                    urn,
1070 				                    NULL,
1071                                                     NULL,
1072 				                    FALSE,
1073 				                    accumulator);
1074 				/* There's no need to force mtime check in these inconsistent
1075 				 * mount points, as they are not mounted right now. */
1076 			}
1077 		}
1078 	}
1079 
1080 	if (accumulator->str[0] != '\0') {
1081 		tracker_sparql_connection_update_async (tracker_miner_get_connection (miner),
1082 		                                        accumulator->str,
1083 		                                        G_PRIORITY_LOW,
1084 		                                        NULL,
1085 		                                        init_mount_points_cb,
1086 		                                        miner);
1087 	} else {
1088 		/* Note. Not initializing stale volume removal timeout because
1089 		 * we do not have the configuration setup yet */
1090 		(TRACKER_MINER_FILES (miner))->private->mount_points_initialized = TRUE;
1091 	}
1092 
1093 	g_string_free (accumulator, TRUE);
1094 	g_hash_table_unref (volumes);
1095 }
1096 
1097 static gboolean
1098 cleanup_stale_removable_volumes_cb (gpointer user_data)
1099 {
1100 	TrackerMinerFiles *miner = TRACKER_MINER_FILES (user_data);
1101 	gint n_days_threshold;
1102 	time_t n_days_ago;
1103 	gchar *n_days_ago_as_string;
1104 
1105 	n_days_threshold = tracker_config_get_removable_days_threshold (miner->private->config);
1106 
1107 	if (n_days_threshold == 0)
1108 		return TRUE;
1109 
1110 	n_days_ago = (time (NULL) - (SECONDS_PER_DAY * n_days_threshold));
1111 	n_days_ago_as_string = tracker_date_to_string (n_days_ago);
1112 
1113 	g_message ("Running stale volumes check...");
1114 
1115 	miner_files_in_removable_media_remove_by_date (miner, n_days_ago_as_string);
1116 
1117 	g_free (n_days_ago_as_string);
1118 
1119 	return TRUE;
1120 }
1121 
1122 static void
1123 init_stale_volume_removal (TrackerMinerFiles *miner)
1124 {
1125 	/* If disabled, make sure we don't do anything */
1126 	if (tracker_config_get_removable_days_threshold (miner->private->config) == 0) {
1127 		g_message ("Stale volume check is disabled");
1128 		return;
1129 	}
1130 
1131 	/* Run right away the first check */
1132 	cleanup_stale_removable_volumes_cb (miner);
1133 
1134 	g_message ("Initializing stale volume check timeout...");
1135 
1136 	/* Then, setup new timeout event every day */
1137 	miner->private->stale_volumes_check_id =
1138 		g_timeout_add_seconds (SECONDS_PER_DAY + 1,
1139 		                       cleanup_stale_removable_volumes_cb,
1140 		                       miner);
1141 }
1142 
1143 
1144 static void
1145 mount_point_removed_cb (TrackerStorage *storage,
1146                         const gchar    *uuid,
1147                         const gchar    *mount_point,
1148                         gpointer        user_data)
1149 {
1150 	TrackerMinerFiles *miner = user_data;
1151 	TrackerIndexingTree *indexing_tree;
1152 	gchar *urn;
1153 	GFile *mount_point_file;
1154 
1155 	urn = g_strdup_printf (TRACKER_DATASOURCE_URN_PREFIX "%s", uuid);
1156 	g_debug ("Mount point removed for URN '%s'", urn);
1157 
1158 	mount_point_file = g_file_new_for_path (mount_point);
1159 
1160 	/* Notify extractor about cancellation of all tasks under the mount point */
1161 	tracker_extract_client_cancel_for_prefix (mount_point_file);
1162 
1163 	/* Tell TrackerMinerFS to skip monitoring everything under the mount
1164 	 *  point (in case there was no pre-unmount notification) */
1165 	indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (miner));
1166 	tracker_indexing_tree_remove (indexing_tree, mount_point_file);
1167 
1168 	/* Set mount point status in tracker-store */
1169 	set_up_mount_point (miner, urn, mount_point, NULL, FALSE, NULL);
1170 
1171 	g_free (urn);
1172 	g_object_unref (mount_point_file);
1173 }
1174 
1175 static void
1176 mount_point_added_cb (TrackerStorage *storage,
1177                       const gchar    *uuid,
1178                       const gchar    *mount_point,
1179                       const gchar    *mount_name,
1180                       gboolean        removable,
1181                       gboolean        optical,
1182                       gpointer        user_data)
1183 {
1184 	TrackerMinerFiles *miner = user_data;
1185 	TrackerMinerFilesPrivate *priv;
1186 	gchar *urn;
1187 	GString *queries;
1188 
1189 	priv = TRACKER_MINER_FILES_GET_PRIVATE (miner);
1190 
1191 	urn = g_strdup_printf (TRACKER_DATASOURCE_URN_PREFIX "%s", uuid);
1192 	g_message ("Mount point added for URN '%s'", urn);
1193 
1194 	if (removable && !priv->index_removable_devices) {
1195 		g_message ("  Not crawling, removable devices disabled in config");
1196 	} else if (optical && !priv->index_optical_discs) {
1197 		g_message ("  Not crawling, optical devices discs disabled in config");
1198 	} else if (!removable && !optical) {
1199 		TrackerIndexingTree *indexing_tree;
1200 		TrackerDirectoryFlags flags;
1201 		GFile *mount_point_file;
1202 		GSList *l;
1203 
1204 		mount_point_file = g_file_new_for_path (mount_point);
1205 		indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (miner));
1206 
1207 		/* Check if one of the recursively indexed locations is in
1208 		 *   the mounted path, or if the mounted path is inside
1209 		 *   a recursively indexed directory... */
1210 		for (l = tracker_config_get_index_recursive_directories (miner->private->config);
1211 		     l;
1212 		     l = g_slist_next (l)) {
1213 			GFile *config_file;
1214 
1215 			config_file = g_file_new_for_path (l->data);
1216 			flags = TRACKER_DIRECTORY_FLAG_RECURSE |
1217 				TRACKER_DIRECTORY_FLAG_CHECK_MTIME |
1218 				TRACKER_DIRECTORY_FLAG_PRESERVE;
1219 
1220 			if (tracker_config_get_enable_monitors (miner->private->config)) {
1221 				flags |= TRACKER_DIRECTORY_FLAG_MONITOR;
1222 			}
1223 
1224 			if (g_file_equal (config_file, mount_point_file) ||
1225 			    g_file_has_prefix (config_file, mount_point_file)) {
1226 				/* If the config path is contained inside the mount path,
1227 				 *  then add the config path to re-check */
1228 				g_message ("  Re-check of configured path '%s' needed (recursively)",
1229 				           (gchar *) l->data);
1230 				tracker_indexing_tree_add (indexing_tree,
1231 							   config_file,
1232 							   flags);
1233 			} else if (g_file_has_prefix (mount_point_file, config_file)) {
1234 				/* If the mount path is contained inside the config path,
1235 				 *  then add the mount path to re-check */
1236 				g_message ("  Re-check of path '%s' needed (inside configured path '%s')",
1237 				           mount_point,
1238 				           (gchar *) l->data);
1239 				tracker_indexing_tree_add (indexing_tree,
1240 							   config_file,
1241 							   flags);
1242 			}
1243 			g_object_unref (config_file);
1244 		}
1245 
1246 		/* Check if one of the non-recursively indexed locations is in
1247 		 *  the mount path... */
1248 		for (l = tracker_config_get_index_single_directories (miner->private->config);
1249 		     l;
1250 		     l = g_slist_next (l)) {
1251 			GFile *config_file;
1252 
1253 			flags = TRACKER_DIRECTORY_FLAG_CHECK_MTIME;
1254 
1255 			if (tracker_config_get_enable_monitors (miner->private->config)) {
1256 				flags |= TRACKER_DIRECTORY_FLAG_MONITOR;
1257 			}
1258 
1259 			config_file = g_file_new_for_path (l->data);
1260 			if (g_file_equal (config_file, mount_point_file) ||
1261 			    g_file_has_prefix (config_file, mount_point_file)) {
1262 				g_message ("  Re-check of configured path '%s' needed (non-recursively)",
1263 				           (gchar *) l->data);
1264 				tracker_indexing_tree_add (indexing_tree,
1265 							   config_file,
1266 							   flags);
1267 			}
1268 			g_object_unref (config_file);
1269 		}
1270 
1271 		g_object_unref (mount_point_file);
1272 	} else {
1273 		g_message ("  Adding directories in removable/optical media to crawler's queue");
1274 		miner_files_add_removable_or_optical_directory (miner,
1275 		                                                mount_point,
1276 		                                                uuid);
1277 	}
1278 
1279 	queries = g_string_new ("");
1280 	set_up_mount_point (miner, urn, mount_point, mount_name, TRUE, queries);
1281 	set_up_mount_point_type (miner, urn, removable, optical, queries);
1282 	tracker_sparql_connection_update_async (tracker_miner_get_connection (TRACKER_MINER (miner)),
1283 	                                        queries->str,
1284 	                                        G_PRIORITY_LOW,
1285 	                                        NULL,
1286 	                                        set_up_mount_point_cb,
1287 	                                        g_strdup (urn));
1288 	g_string_free (queries, TRUE);
1289 	g_free (urn);
1290 }
1291 
1292 #if defined(HAVE_UPOWER) || defined(HAVE_HAL)
1293 
1294 static void
1295 set_up_throttle (TrackerMinerFiles *mf,
1296                  gboolean           enable)
1297 {
1298 	gdouble throttle;
1299 	gint config_throttle;
1300 
1301 	config_throttle = tracker_config_get_throttle (mf->private->config);
1302 	throttle = (1.0 / 20) * config_throttle;
1303 
1304 	if (enable) {
1305 		throttle += 0.25;
1306 	}
1307 
1308 	throttle = CLAMP (throttle, 0, 1);
1309 
1310 	g_debug ("Setting new throttle to %0.3f", throttle);
1311 	tracker_miner_fs_set_throttle (TRACKER_MINER_FS (mf), throttle);
1312 }
1313 
1314 static void
1315 check_battery_status (TrackerMinerFiles *mf)
1316 {
1317 	gboolean on_battery, on_low_battery;
1318 	gboolean should_pause = FALSE;
1319 	gboolean should_throttle = FALSE;
1320 
1321 	on_low_battery = tracker_power_get_on_low_battery (mf->private->power);
1322 	on_battery = tracker_power_get_on_battery (mf->private->power);
1323 
1324 	if (!on_battery) {
1325 		g_message ("Running on AC power");
1326 		should_pause = FALSE;
1327 		should_throttle = FALSE;
1328 	} else if (on_low_battery) {
1329 		g_message ("Running on LOW Battery, pausing");
1330 		should_pause = TRUE;
1331 		should_throttle = TRUE;
1332 	} else {
1333 		should_throttle = TRUE;
1334 
1335 		/* Check if miner should be paused based on configuration */
1336 		if (!tracker_config_get_index_on_battery (mf->private->config)) {
1337 			if (!tracker_config_get_index_on_battery_first_time (mf->private->config)) {
1338 				g_message ("Running on battery, but not enabled, pausing");
1339 				should_pause = TRUE;
1340 			} else if (tracker_db_manager_get_first_index_done ()) {
1341 				g_message ("Running on battery and first-time index "
1342 				           "already done, pausing");
1343 				should_pause = TRUE;
1344 			} else {
1345 				g_message ("Running on battery, but first-time index not "
1346 				           "already finished, keeping on");
1347 			}
1348 		} else {
1349 			g_message ("Running on battery");
1350 		}
1351 	}
1352 
1353 	if (should_pause) {
1354 		/* Don't try to pause again */
1355 		if (mf->private->low_battery_pause_cookie == 0) {
1356 			mf->private->low_battery_pause_cookie =
1357 				tracker_miner_pause (TRACKER_MINER (mf),
1358 				                     _("Low battery"),
1359 				                     NULL);
1360 		}
1361 	} else {
1362 		/* Don't try to resume again */
1363 		if (mf->private->low_battery_pause_cookie != 0) {
1364 			tracker_miner_resume (TRACKER_MINER (mf),
1365 			                      mf->private->low_battery_pause_cookie,
1366 			                      NULL);
1367 			mf->private->low_battery_pause_cookie = 0;
1368 		}
1369 	}
1370 
1371 	set_up_throttle (mf, should_throttle);
1372 }
1373 
1374 /* Called when battery status change is detected */
1375 static void
1376 battery_status_cb (GObject    *object,
1377                    GParamSpec *pspec,
1378                    gpointer    user_data)
1379 {
1380 	TrackerMinerFiles *mf = user_data;
1381 
1382 	check_battery_status (mf);
1383 }
1384 
1385 /* Called when battery-related configuration change is detected */
1386 static void
1387 index_on_battery_cb (GObject    *object,
1388                      GParamSpec *pspec,
1389                      gpointer    user_data)
1390 {
1391 	TrackerMinerFiles *mf = user_data;
1392 
1393 	check_battery_status (mf);
1394 }
1395 
1396 #endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */
1397 
1398 /* Called when mining has finished the first time */
1399 static void
1400 miner_finished_cb (TrackerMinerFS *fs,
1401                    gdouble         seconds_elapsed,
1402                    guint           total_directories_found,
1403                    guint           total_directories_ignored,
1404                    guint           total_files_found,
1405                    guint           total_files_ignored,
1406                    gpointer        user_data)
1407 {
1408 	TrackerMinerFiles *mf = TRACKER_MINER_FILES (fs);
1409 
1410 	/* Create stamp file if not already there */
1411 	if (!tracker_db_manager_get_first_index_done ()) {
1412 		tracker_db_manager_set_first_index_done (TRUE);
1413 	}
1414 
1415 	/* And remove the signal handler so that it's not
1416 	 *  called again */
1417 	if (mf->private->finished_handler) {
1418 		g_signal_handler_disconnect (fs, mf->private->finished_handler);
1419 		mf->private->finished_handler = 0;
1420 	}
1421 
1422 #if defined(HAVE_UPOWER) || defined(HAVE_HAL)
1423 	check_battery_status (mf);
1424 #endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */
1425 }
1426 
1427 static void
1428 mount_pre_unmount_cb (GVolumeMonitor    *volume_monitor,
1429                       GMount            *mount,
1430                       TrackerMinerFiles *mf)
1431 {
1432 	TrackerIndexingTree *indexing_tree;
1433 	GFile *mount_root;
1434 	gchar *uri;
1435 
1436 	mount_root = g_mount_get_root (mount);
1437 	uri = g_file_get_uri (mount_root);
1438 	g_message ("Pre-unmount requested for '%s'", uri);
1439 
1440 	indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (mf));
1441 	tracker_indexing_tree_remove (indexing_tree, mount_root);
1442 	g_object_unref (mount_root);
1443 
1444 	g_free (uri);
1445 }
1446 
1447 static gboolean
1448 disk_space_check (TrackerMinerFiles *mf)
1449 {
1450 	gint limit;
1451 	gchar *data_dir;
1452 	gdouble remaining;
1453 
1454 	limit = tracker_config_get_low_disk_space_limit (mf->private->config);
1455 
1456 	if (limit < 1) {
1457 		return FALSE;
1458 	}
1459 
1460 	/* Get % of remaining space in the partition where the cache is */
1461 	data_dir = g_build_filename (g_get_user_cache_dir (), "tracker", NULL);
1462 	remaining = tracker_file_system_get_remaining_space_percentage (data_dir);
1463 	g_free (data_dir);
1464 
1465 	if (remaining <= limit) {
1466 		g_message ("WARNING: Available disk space (%lf%%) is below "
1467 		           "configured threshold for acceptable working (%d%%)",
1468 		           remaining, limit);
1469 		return TRUE;
1470 	}
1471 
1472 	return FALSE;
1473 }
1474 
1475 static gboolean
1476 disk_space_check_cb (gpointer user_data)
1477 {
1478 	TrackerMinerFiles *mf = user_data;
1479 
1480 	if (disk_space_check (mf)) {
1481 		/* Don't try to pause again */
1482 		if (mf->private->disk_space_pause_cookie == 0) {
1483 			mf->private->disk_space_pause_cookie =
1484 				tracker_miner_pause (TRACKER_MINER (mf),
1485 				                     _("Low disk space"),
1486 				                     NULL);
1487 		}
1488 	} else {
1489 		/* Don't try to resume again */
1490 		if (mf->private->disk_space_pause_cookie != 0) {
1491 			tracker_miner_resume (TRACKER_MINER (mf),
1492 			                      mf->private->disk_space_pause_cookie,
1493 			                      NULL);
1494 			mf->private->disk_space_pause_cookie = 0;
1495 		}
1496 	}
1497 
1498 	return TRUE;
1499 }
1500 
1501 static void
1502 disk_space_check_start (TrackerMinerFiles *mf)
1503 {
1504 	gint limit;
1505 
1506 	if (mf->private->disk_space_check_id != 0) {
1507 		return;
1508 	}
1509 
1510 	limit = tracker_config_get_low_disk_space_limit (mf->private->config);
1511 
1512 	if (limit != -1) {
1513 		g_message ("Starting disk space check for every %d seconds",
1514 		           DISK_SPACE_CHECK_FREQUENCY);
1515 		mf->private->disk_space_check_id =
1516 			g_timeout_add_seconds (DISK_SPACE_CHECK_FREQUENCY,
1517 			                       disk_space_check_cb,
1518 			                       mf);
1519 
1520 		/* Call the function now too to make sure we have an
1521 		 * initial value too!
1522 		 */
1523 		disk_space_check_cb (mf);
1524 	} else {
1525 		g_message ("Not setting disk space, configuration is set to -1 (disabled)");
1526 	}
1527 }
1528 
1529 static void
1530 disk_space_check_stop (TrackerMinerFiles *mf)
1531 {
1532 	if (mf->private->disk_space_check_id) {
1533 		g_message ("Stopping disk space check");
1534 		g_source_remove (mf->private->disk_space_check_id);
1535 		mf->private->disk_space_check_id = 0;
1536 	}
1537 }
1538 
1539 static void
1540 low_disk_space_limit_cb (GObject    *gobject,
1541                          GParamSpec *arg1,
1542                          gpointer    user_data)
1543 {
1544 	TrackerMinerFiles *mf = user_data;
1545 
1546 	disk_space_check_cb (mf);
1547 }
1548 
1549 static void
1550 indexing_tree_update_filter (TrackerIndexingTree *indexing_tree,
1551 			     TrackerFilterType    filter,
1552 			     GSList              *new_elems)
1553 {
1554 	tracker_indexing_tree_clear_filters (indexing_tree, filter);
1555 
1556 	while (new_elems) {
1557 		tracker_indexing_tree_add_filter (indexing_tree, filter,
1558 						  new_elems->data);
1559 		new_elems = new_elems->next;
1560 	}
1561 }
1562 
1563 static void
1564 miner_files_update_filters (TrackerMinerFiles *files)
1565 {
1566 	TrackerIndexingTree *indexing_tree;
1567 	GSList *list;
1568 
1569 	indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (files));
1570 
1571 	/* Ignored files */
1572 	list = tracker_config_get_ignored_files (files->private->config);
1573 	indexing_tree_update_filter (indexing_tree, TRACKER_FILTER_FILE, list);
1574 
1575 	/* Ignored directories */
1576 	list = tracker_config_get_ignored_directories (files->private->config);
1577 	indexing_tree_update_filter (indexing_tree,
1578 				     TRACKER_FILTER_DIRECTORY,
1579 				     list);
1580 
1581 	/* Directories with content */
1582 	list = tracker_config_get_ignored_directories_with_content (files->private->config);
1583 	indexing_tree_update_filter (indexing_tree,
1584 				     TRACKER_FILTER_PARENT_DIRECTORY,
1585 				     list);
1586 }
1587 
1588 static void
1589 update_directories_from_new_config (TrackerMinerFS *mf,
1590                                     GSList         *new_dirs,
1591                                     GSList         *old_dirs,
1592                                     gboolean        recurse)
1593 {
1594 	TrackerMinerFilesPrivate *priv;
1595 	TrackerDirectoryFlags flags = 0;
1596 	TrackerIndexingTree *indexing_tree;
1597 	GSList *sl;
1598 
1599 	priv = TRACKER_MINER_FILES_GET_PRIVATE (mf);
1600 	indexing_tree = tracker_miner_fs_get_indexing_tree (mf);
1601 
1602 	g_message ("Updating %s directories changed from configuration",
1603 	           recurse ? "recursive" : "single");
1604 
1605 	/* First remove all directories removed from the config */
1606 	for (sl = old_dirs; sl; sl = sl->next) {
1607 		const gchar *path;
1608 
1609 		path = sl->data;
1610 
1611 		/* If we are not still in the list, remove the dir */
1612 		if (!tracker_string_in_gslist (path, new_dirs)) {
1613 			GFile *file;
1614 
1615 			g_message ("  Removing directory: '%s'", path);
1616 
1617 			file = g_file_new_for_path (path);
1618 
1619 			/* First, remove the preserve flag, it might be
1620 			 * set on configuration directories within mount
1621 			 * points, as data should be persistent across
1622 			 * unmounts.
1623 			 */
1624 			tracker_indexing_tree_get_root (indexing_tree,
1625 							file, &flags);
1626 
1627 			if ((flags & TRACKER_DIRECTORY_FLAG_PRESERVE) != 0) {
1628 				flags &= ~(TRACKER_DIRECTORY_FLAG_PRESERVE);
1629 				tracker_indexing_tree_add (indexing_tree,
1630 							   file, flags);
1631 			}
1632 
1633 			/* Fully remove item (monitors and from store),
1634 			 * now that there's no preserve flag.
1635 			 */
1636 			tracker_indexing_tree_remove (indexing_tree, file);
1637 			g_object_unref (file);
1638 		}
1639 	}
1640 
1641 	flags = TRACKER_DIRECTORY_FLAG_NONE;
1642 
1643 	if (recurse) {
1644 		flags |= TRACKER_DIRECTORY_FLAG_RECURSE;
1645 	}
1646 
1647 	if (tracker_config_get_enable_monitors (priv->config)) {
1648 		flags |= TRACKER_DIRECTORY_FLAG_MONITOR;
1649 	}
1650 
1651 	if (tracker_miner_fs_get_mtime_checking (TRACKER_MINER_FS (mf))) {
1652 		flags |= TRACKER_DIRECTORY_FLAG_CHECK_MTIME;
1653 	}
1654 
1655 	/* Second add directories which are new */
1656 	for (sl = new_dirs; sl; sl = sl->next) {
1657 		const gchar *path;
1658 
1659 		path = sl->data;
1660 
1661 		/* If we are now in the list, add the dir */
1662 		if (!tracker_string_in_gslist (path, old_dirs)) {
1663 			GFile *file;
1664 
1665 			g_message ("  Adding directory:'%s'", path);
1666 
1667 			file = g_file_new_for_path (path);
1668 			tracker_indexing_tree_add (indexing_tree, file, flags);
1669 			g_object_unref (file);
1670 		}
1671 	}
1672 }
1673 
1674 static void
1675 index_recursive_directories_cb (GObject    *gobject,
1676                                 GParamSpec *arg1,
1677                                 gpointer    user_data)
1678 {
1679 	TrackerMinerFilesPrivate *private;
1680 	GSList *new_dirs, *old_dirs;
1681 
1682 	private = TRACKER_MINER_FILES_GET_PRIVATE (user_data);
1683 
1684 	new_dirs = tracker_config_get_index_recursive_directories (private->config);
1685 	old_dirs = private->index_recursive_directories;
1686 
1687 	update_directories_from_new_config (TRACKER_MINER_FS (user_data),
1688 	                                    new_dirs,
1689 	                                    old_dirs,
1690 	                                    TRUE);
1691 
1692 	/* Re-set the stored config in case it changes again */
1693 	if (private->index_recursive_directories) {
1694 		g_slist_foreach (private->index_recursive_directories, (GFunc) g_free, NULL);
1695 		g_slist_free (private->index_recursive_directories);
1696 	}
1697 
1698 	private->index_recursive_directories = tracker_gslist_copy_with_string_data (new_dirs);
1699 }
1700 
1701 static void
1702 index_single_directories_cb (GObject    *gobject,
1703                              GParamSpec *arg1,
1704                              gpointer    user_data)
1705 {
1706 	TrackerMinerFilesPrivate *private;
1707 	GSList *new_dirs, *old_dirs;
1708 
1709 	private = TRACKER_MINER_FILES_GET_PRIVATE (user_data);
1710 
1711 	new_dirs = tracker_config_get_index_single_directories (private->config);
1712 	old_dirs = private->index_single_directories;
1713 
1714 	update_directories_from_new_config (TRACKER_MINER_FS (user_data),
1715 	                                    new_dirs,
1716 	                                    old_dirs,
1717 	                                    FALSE);
1718 
1719 	/* Re-set the stored config in case it changes again */
1720 	if (private->index_single_directories) {
1721 		g_slist_foreach (private->index_single_directories, (GFunc) g_free, NULL);
1722 		g_slist_free (private->index_single_directories);
1723 	}
1724 
1725 	private->index_single_directories = tracker_gslist_copy_with_string_data (new_dirs);
1726 }
1727 
1728 static gboolean
1729 miner_files_force_recheck_idle (gpointer user_data)
1730 {
1731 	TrackerMinerFiles *miner_files = user_data;
1732 	TrackerIndexingTree *indexing_tree;
1733 	GList *roots, *l;
1734 
1735 	miner_files_update_filters (miner_files);
1736 
1737 	indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (miner_files));
1738 	roots = tracker_indexing_tree_list_roots (indexing_tree);
1739 
1740 	for (l = roots; l; l = l->next)	{
1741 		GFile *root = l->data;
1742 
1743 		g_signal_emit_by_name (indexing_tree, "directory-updated", root);
1744 	}
1745 
1746 	miner_files->private->force_recheck_id = 0;
1747 	g_list_free (roots);
1748 
1749 	return FALSE;
1750 }
1751 
1752 static void
1753 trigger_recheck_cb (GObject    *gobject,
1754                     GParamSpec *arg1,
1755                     gpointer    user_data)
1756 {
1757 	TrackerMinerFiles *mf = user_data;
1758 
1759 	g_message ("Ignored content related configuration changed, checking index...");
1760 
1761 	if (mf->private->force_recheck_id == 0) {
1762 		/* Set idle so multiple changes in the config lead to one recheck */
1763 		mf->private->force_recheck_id =
1764 			g_idle_add (miner_files_force_recheck_idle, mf);
1765 	}
1766 }
1767 
1768 static gboolean
1769 index_volumes_changed_idle (gpointer user_data)
1770 {
1771 	TrackerMinerFiles *mf = user_data;
1772 	GSList *mounts_removed = NULL;
1773 	GSList *mounts_added = NULL;
1774 	gboolean new_index_removable_devices;
1775 	gboolean new_index_optical_discs;
1776 
1777 	g_message ("Volume related configuration changed, updating...");
1778 
1779 	/* Read new config values. Note that if removable devices is FALSE,
1780 	 * optical discs will also always be FALSE. */
1781 	new_index_removable_devices = tracker_config_get_index_removable_devices (mf->private->config);
1782 	new_index_optical_discs = (new_index_removable_devices ?
1783 	                           tracker_config_get_index_optical_discs (mf->private->config) :
1784 	                           FALSE);
1785 
1786 	/* Removable devices config changed? */
1787 	if (mf->private->index_removable_devices != new_index_removable_devices) {
1788 		GSList *m;
1789 
1790 		/* Get list of roots for currently mounted removable devices
1791 		 * (excluding optical) */
1792 		m = tracker_storage_get_device_roots (mf->private->storage,
1793 		                                      TRACKER_STORAGE_REMOVABLE,
1794 		                                      TRUE);
1795 		/* Set new config value */
1796 		mf->private->index_removable_devices = new_index_removable_devices;
1797 
1798 		if (mf->private->index_removable_devices) {
1799 			/* If previously not indexing and now indexing, need to re-check
1800 			 * current mounted volumes, add new monitors and index new files
1801 			 */
1802 			mounts_added = m;
1803 		} else {
1804 			/* If previously indexing and now not indexing, need to re-check
1805 			 * current mounted volumes, remove monitors and remove all resources
1806 			 * from the store belonging to a removable device
1807 			 */
1808 			mounts_removed = m;
1809 
1810 			/* And now, single sparql update to remove all resources
1811 			 * corresponding to removable devices (includes those
1812 			 * not currently mounted) */
1813 			miner_files_in_removable_media_remove_by_type (mf, TRACKER_STORAGE_REMOVABLE);
1814 		}
1815 	}
1816 
1817 	/* Optical discs config changed? */
1818 	if (mf->private->index_optical_discs != new_index_optical_discs) {
1819 		GSList *m;
1820 
1821 		/* Get list of roots for removable devices (excluding optical) */
1822 		m = tracker_storage_get_device_roots (mf->private->storage,
1823 		                                      TRACKER_STORAGE_REMOVABLE | TRACKER_STORAGE_OPTICAL,
1824 		                                      TRUE);
1825 
1826 		/* Set new config value */
1827 		mf->private->index_optical_discs = new_index_optical_discs;
1828 
1829 		if (mf->private->index_optical_discs) {
1830 			/* If previously not indexing and now indexing, need to re-check
1831 			 * current mounted volumes, add new monitors and index new files
1832 			 */
1833 			mounts_added = g_slist_concat (mounts_added, m);
1834 		} else {
1835 			/* If previously indexing and now not indexing, need to re-check
1836 			 * current mounted volumes, remove monitors and remove all resources
1837 			 * from the store belonging to a optical disc
1838 			 */
1839 			mounts_removed = g_slist_concat (mounts_removed, m);
1840 
1841 			/* And now, single sparql update to remove all resources
1842 			 * corresponding to removable+optical devices (includes those
1843 			 * not currently mounted) */
1844 			miner_files_in_removable_media_remove_by_type (mf, TRACKER_STORAGE_REMOVABLE | TRACKER_STORAGE_OPTICAL);
1845 		}
1846 	}
1847 
1848 	/* Tell TrackerMinerFS to stop monitoring the given removed mount paths, if any */
1849 	if (mounts_removed) {
1850 		TrackerIndexingTree *indexing_tree;
1851 		GSList *sl;
1852 
1853 		indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (mf));
1854 
1855 		for (sl = mounts_removed; sl; sl = g_slist_next (sl)) {
1856 			GFile *mount_point_file;
1857 
1858 			mount_point_file = g_file_new_for_path (sl->data);
1859 			tracker_indexing_tree_remove (indexing_tree,
1860 						      mount_point_file);
1861 			g_object_unref (mount_point_file);
1862 		}
1863 
1864 		g_slist_foreach (mounts_removed, (GFunc) g_free, NULL);
1865 		g_slist_free (mounts_removed);
1866 	}
1867 
1868 	/* Tell TrackerMinerFS to start monitoring the given added mount paths, if any */
1869 	if (mounts_added) {
1870 		GSList *sl;
1871 
1872 		for (sl = mounts_added; sl; sl = g_slist_next (sl)) {
1873 			miner_files_add_removable_or_optical_directory (mf,
1874 			                                                (gchar *) sl->data,
1875 			                                                NULL);
1876 		}
1877 
1878 		g_slist_foreach (mounts_added, (GFunc) g_free, NULL);
1879 		g_slist_free (mounts_added);
1880 	}
1881 
1882 	mf->private->volumes_changed_id = 0;
1883 
1884 	/* Check if the stale volume removal configuration changed from enabled to disabled
1885 	 * or from disabled to enabled */
1886 	if (tracker_config_get_removable_days_threshold (mf->private->config) == 0 &&
1887 	    mf->private->stale_volumes_check_id != 0) {
1888 		/* From having the check enabled to having it disabled, remove the timeout */
1889 		g_debug ("  Stale volume removal now disabled, removing timeout");
1890 		g_source_remove (mf->private->stale_volumes_check_id);
1891 		mf->private->stale_volumes_check_id = 0;
1892 	} else if (tracker_config_get_removable_days_threshold (mf->private->config) > 0 &&
1893 	           mf->private->stale_volumes_check_id == 0) {
1894 		g_debug ("  Stale volume removal now enabled, initializing timeout");
1895 		/* From having the check disabled to having it enabled, so fire up the
1896 		 * timeout. */
1897 		init_stale_volume_removal (TRACKER_MINER_FILES (mf));
1898 	}
1899 
1900 	return FALSE;
1901 }
1902 
1903 static void
1904 index_volumes_changed_cb (GObject    *gobject,
1905                           GParamSpec *arg1,
1906                           gpointer    user_data)
1907 {
1908 	TrackerMinerFiles *miner_files = user_data;
1909 
1910 	if (miner_files->private->volumes_changed_id == 0) {
1911 		/* Set idle so multiple changes in the config lead to one check */
1912 		miner_files->private->volumes_changed_id =
1913 			g_idle_add (index_volumes_changed_idle, miner_files);
1914 	}
1915 }
1916 
1917 static const gchar *
1918 miner_files_get_file_urn (TrackerMinerFiles *miner,
1919                           GFile             *file,
1920                           gboolean          *is_iri)
1921 {
1922 	const gchar *urn;
1923 
1924 	urn = tracker_miner_fs_get_urn (TRACKER_MINER_FS (miner), file);
1925 	*is_iri = TRUE;
1926 
1927 	if (!urn) {
1928 		/* This is a new insertion, use anonymous URNs to store files */
1929 		urn = "_:file";
1930 		*is_iri = FALSE;
1931 	}
1932 
1933 	return urn;
1934 }
1935 
1936 static void
1937 miner_files_add_to_datasource (TrackerMinerFiles    *mf,
1938                                GFile                *file,
1939                                TrackerSparqlBuilder *sparql)
1940 {
1941 	TrackerMinerFilesPrivate *priv;
1942 	const gchar *removable_device_uuid;
1943 	gchar *removable_device_urn, *uri;
1944 	const gchar *urn;
1945 	gboolean is_iri;
1946 
1947 	priv = TRACKER_MINER_FILES_GET_PRIVATE (mf);
1948 	uri = g_file_get_uri (file);
1949 
1950 	removable_device_uuid = tracker_storage_get_uuid_for_file (priv->storage, file);
1951 
1952 	if (removable_device_uuid) {
1953 		removable_device_urn = g_strdup_printf (TRACKER_DATASOURCE_URN_PREFIX "%s",
1954 		                                        removable_device_uuid);
1955 	} else {
1956 		removable_device_urn = g_strdup (TRACKER_NON_REMOVABLE_MEDIA_DATASOURCE_URN);
1957 	}
1958 
1959 	urn = miner_files_get_file_urn (mf, file, &is_iri);
1960 
1961 	if (is_iri) {
1962 		tracker_sparql_builder_subject_iri (sparql, urn);
1963 	} else {
1964 		tracker_sparql_builder_subject (sparql, urn);
1965 	}
1966 
1967 	tracker_sparql_builder_predicate (sparql, "a");
1968 	tracker_sparql_builder_object (sparql, "nfo:FileDataObject");
1969 
1970 	tracker_sparql_builder_predicate (sparql, "nie:dataSource");
1971 	tracker_sparql_builder_object_iri (sparql, removable_device_urn);
1972 
1973 	tracker_sparql_builder_predicate (sparql, "tracker:available");
1974 	tracker_sparql_builder_object_boolean (sparql, TRUE);
1975 
1976 	g_free (removable_device_urn);
1977 	g_free (uri);
1978 }
1979 
1980 static void
1981 process_file_data_free (ProcessFileData *data)
1982 {
1983 	g_object_unref (data->miner);
1984 	g_object_unref (data->sparql);
1985 	g_object_unref (data->cancellable);
1986 	g_object_unref (data->file);
1987 	g_free (data->mime_type);
1988 	g_slice_free (ProcessFileData, data);
1989 }
1990 
1991 static void
1992 sparql_builder_finish (ProcessFileData *data,
1993                        const gchar     *preupdate,
1994                        const gchar     *postupdate,
1995                        const gchar     *sparql,
1996                        const gchar     *where)
1997 {
1998 	const gchar *uuid;
1999 
2000 	if (sparql && *sparql) {
2001 		gboolean is_iri;
2002 		const gchar *urn;
2003 
2004 		urn = miner_files_get_file_urn (data->miner, data->file, &is_iri);
2005 
2006 		if (is_iri) {
2007 			gchar *str;
2008 
2009 			str = g_strdup_printf ("<%s>", urn);
2010 			tracker_sparql_builder_append (data->sparql, str);
2011 			g_free (str);
2012 		} else {
2013 			tracker_sparql_builder_append (data->sparql, urn);
2014 		}
2015 
2016 		tracker_sparql_builder_append (data->sparql, sparql);
2017 	}
2018 
2019 	tracker_sparql_builder_graph_close (data->sparql);
2020 	tracker_sparql_builder_insert_close (data->sparql);
2021 
2022 	if (where && *where) {
2023 		tracker_sparql_builder_where_open (data->sparql);
2024 		tracker_sparql_builder_append (data->sparql, where);
2025 		tracker_sparql_builder_where_close (data->sparql);
2026 	}
2027 
2028 	/* Prepend preupdate queries */
2029 	if (preupdate && *preupdate) {
2030 		tracker_sparql_builder_prepend (data->sparql, preupdate);
2031 	}
2032 
2033 	/* Append postupdate */
2034 	if (postupdate && *postupdate) {
2035 		tracker_sparql_builder_append (data->sparql, postupdate);
2036 	}
2037 
2038 	uuid = g_object_get_qdata (G_OBJECT (data->file),
2039 	                           data->miner->private->quark_mount_point_uuid);
2040 
2041 	/* File represents a mount point */
2042 	if (G_UNLIKELY (uuid)) {
2043 		GString *queries;
2044 		gchar *removable_device_urn, *uri;
2045 
2046 		removable_device_urn = g_strdup_printf (TRACKER_DATASOURCE_URN_PREFIX "%s", uuid);
2047 		uri = g_file_get_uri (G_FILE (data->file));
2048 		queries = g_string_new ("");
2049 
2050 		g_string_append_printf (queries,
2051 		                        "DELETE { "
2052 		                        "  <%s> tracker:mountPoint ?unknown "
2053 		                        "} WHERE { "
2054 		                        "  <%s> a tracker:Volume; "
2055 		                        "       tracker:mountPoint ?unknown "
2056 		                        "} ",
2057 		                        removable_device_urn, removable_device_urn);
2058 
2059 		g_string_append_printf (queries,
2060 		                        "INSERT { GRAPH <%s> {"
2061 		                        "  <%s> a tracker:Volume; "
2062 		                        "       tracker:mountPoint ?u "
2063 		                        "} } WHERE { "
2064 		                        "  ?u a nfo:FileDataObject; "
2065 		                        "     nie:url \"%s\" "
2066 		                        "} ",
2067 		                        removable_device_urn, removable_device_urn, uri);
2068 
2069 		tracker_sparql_builder_append (data->sparql, queries->str);
2070 		g_string_free (queries, TRUE);
2071 		g_free (removable_device_urn);
2072 		g_free (uri);
2073 	}
2074 }
2075 
2076 static void
2077 extractor_get_failsafe_metadata_cb (GObject      *object,
2078                                     GAsyncResult *res,
2079                                     gpointer      user_data)
2080 {
2081 	ProcessFileData *data = user_data;
2082 	TrackerMinerFiles *miner = data->miner;
2083 	TrackerMinerFilesPrivate *priv = miner->private;
2084 	const gchar *preupdate, *postupdate, *sparql, *where;
2085 	TrackerExtractInfo *info;
2086 	GError *error = NULL;
2087 	gchar *uri;
2088 
2089 	info = tracker_extract_client_get_metadata_finish (G_FILE (object), res, &error);
2090 	preupdate = postupdate = sparql = where = NULL;
2091 
2092 	if (error) {
2093 		GStrv types;
2094 
2095 		uri = g_file_get_uri (data->file);
2096 		g_warning ("  Got second extraction DBus error on '%s'. "
2097 			   "Adding only non-embedded metadata to the SparQL, "
2098 			   "the error was: %s",
2099 			   uri, error->message);
2100 		g_error_free (error);
2101 		g_free (uri);
2102 
2103 		types = tracker_extract_module_manager_get_fallback_rdf_types (data->mime_type);
2104 
2105 		if (types && types[0] != NULL) {
2106 			guint i;
2107 			GString *str = g_string_new (" a ");
2108 			for (i = 0; types[i] != NULL; i++) {
2109 				if (i != 0) {
2110 					g_string_append_c (str, ',');
2111 				}
2112 				g_string_append (str, types[i]);
2113 			}
2114 			g_string_append (str, " .");
2115 			sparql = g_string_free (str, FALSE);
2116 		}
2117 
2118 		g_strfreev (types);
2119 
2120 	} else {
2121 		TrackerSparqlBuilder *builder;
2122 
2123 		g_debug ("  Extraction succeeded the second time");
2124 
2125 		builder = tracker_extract_info_get_preupdate_builder (info);
2126 		preupdate = tracker_sparql_builder_get_result (builder);
2127 
2128 		builder = tracker_extract_info_get_postupdate_builder (info);
2129 		postupdate = tracker_sparql_builder_get_result (builder);
2130 
2131 		builder = tracker_extract_info_get_metadata_builder (info);
2132 		sparql = tracker_sparql_builder_get_result (builder);
2133 
2134 		where = tracker_extract_info_get_where_clause (info);
2135 	}
2136 
2137 	sparql_builder_finish (data, preupdate, postupdate, sparql, where);
2138 
2139 	/* Notify success even if the extraction failed
2140 	 * again, so we get the essential data in the store.
2141 	 */
2142 	tracker_miner_fs_file_notify (TRACKER_MINER_FS (miner), data->file, NULL);
2143 
2144 	priv->failed_extraction_queue = g_list_remove (priv->failed_extraction_queue, data);
2145 	process_file_data_free (data);
2146 
2147 	/* Get on to the next failed extraction, or resume miner */
2148 	extractor_process_failsafe (miner);
2149 }
2150 
2151 /* This function processes failed files one by one,
2152  * the function will be called after each operation
2153  * is finished, so elements are processed linearly.
2154  */
2155 static void
2156 extractor_process_failsafe (TrackerMinerFiles *miner)
2157 {
2158 	TrackerMinerFilesPrivate *priv;
2159 	ProcessFileData *data;
2160 
2161 	priv = miner->private;
2162 
2163 	if (priv->failed_extraction_queue) {
2164 		gchar *uri;
2165 
2166 		data = priv->failed_extraction_queue->data;
2167 
2168 		uri = g_file_get_uri (data->file);
2169 		g_message ("Performing failsafe extraction on '%s'", uri);
2170 		g_free (uri);
2171 
2172 		tracker_extract_client_get_metadata (data->file,
2173 		                                     data->mime_type,
2174 		                                     TRACKER_MINER_FS_GRAPH_URN,
2175 		                                     data->cancellable,
2176 		                                     extractor_get_failsafe_metadata_cb,
2177 		                                     data);
2178 	} else {
2179 		g_debug ("Failsafe extraction finished. Resuming miner...");
2180 
2181 		if (priv->failed_extraction_pause_cookie != 0) {
2182 			tracker_miner_resume (TRACKER_MINER (miner),
2183 			                      priv->failed_extraction_pause_cookie,
2184 			                      NULL);
2185 
2186 			priv->failed_extraction_pause_cookie = 0;
2187 		}
2188 
2189 		priv->failsafe_extraction = FALSE;
2190 	}
2191 }
2192 
2193 static void
2194 extractor_check_process_failsafe (TrackerMinerFiles *miner)
2195 {
2196 	TrackerMinerFilesPrivate *priv;
2197 
2198 	priv = miner->private;
2199 
2200 	if (priv->failsafe_extraction) {
2201 		/* already on failsafe extraction */
2202 		return;
2203 	}
2204 
2205 	if (priv->extraction_queue ||
2206 	    !priv->failed_extraction_queue) {
2207 		/* No reasons (yet) to start failsafe extraction */
2208 		return;
2209 	}
2210 
2211 	priv->failsafe_extraction = TRUE;
2212 	extractor_process_failsafe (miner);
2213 }
2214 
2215 static void
2216 extractor_get_embedded_metadata_cb (GObject      *object,
2217                                     GAsyncResult *res,
2218                                     gpointer      user_data)
2219 {
2220 	TrackerMinerFilesPrivate *priv;
2221 	TrackerMinerFiles *miner;
2222 	ProcessFileData *data = user_data;
2223 	TrackerSparqlBuilder *preupdate, *postupdate, *sparql;
2224 	const gchar *where;
2225 	TrackerExtractInfo *info;
2226 	GError *error = NULL;
2227 
2228 	miner = data->miner;
2229 	priv = miner->private;
2230 	priv->extraction_queue = g_list_remove (priv->extraction_queue, data);
2231 	info = tracker_extract_client_get_metadata_finish (G_FILE (object), res, &error);
2232 
2233 	if (error) {
2234 		if (error->code == G_DBUS_ERROR_NO_REPLY ||
2235 		    error->code == G_DBUS_ERROR_TIMEOUT ||
2236 		    error->code == G_DBUS_ERROR_TIMED_OUT) {
2237 			gchar *uri;
2238 
2239 			uri = g_file_get_uri (data->file);
2240 			g_warning ("  Got extraction DBus error on '%s': %s", uri, error->message);
2241 
2242 			if (priv->failed_extraction_pause_cookie != 0) {
2243 				priv->failed_extraction_pause_cookie =
2244 					tracker_miner_pause (TRACKER_MINER (data->miner),
2245 					                     _("Extractor error, performing "
2246 					                       "failsafe embedded metadata extraction"),
2247 					                     NULL);
2248 			}
2249 
2250 			priv->failed_extraction_queue = g_list_prepend (priv->failed_extraction_queue, data);
2251 			g_free (uri);
2252 		} else {
2253 			sparql_builder_finish (data, NULL, NULL, NULL, NULL);
2254 
2255 			/* Something bad happened, notify about the error */
2256 			tracker_miner_fs_file_notify (TRACKER_MINER_FS (data->miner), data->file, error);
2257 			process_file_data_free (data);
2258 		}
2259 
2260 		g_error_free (error);
2261 	} else {
2262 		preupdate = tracker_extract_info_get_preupdate_builder (info);
2263 		postupdate = tracker_extract_info_get_postupdate_builder (info);
2264 		sparql = tracker_extract_info_get_metadata_builder (info);
2265 		where = tracker_extract_info_get_where_clause (info);
2266 
2267 		sparql_builder_finish (data,
2268 		                       tracker_sparql_builder_get_result (preupdate),
2269 		                       tracker_sparql_builder_get_result (postupdate),
2270 		                       tracker_sparql_builder_get_result (sparql),
2271 		                       where);
2272 
2273 		/* Notify about the success */
2274 		tracker_miner_fs_file_notify (TRACKER_MINER_FS (data->miner), data->file, NULL);
2275 
2276 		process_file_data_free (data);
2277 	}
2278 
2279 	/* Wait until there are no pending extraction requests
2280 	 * before starting failsafe extraction process.
2281 	 */
2282 	extractor_check_process_failsafe (miner);
2283 }
2284 
2285 static void
2286 process_file_cb (GObject      *object,
2287                  GAsyncResult *result,
2288                  gpointer      user_data)
2289 {
2290 	TrackerMinerFilesPrivate *priv;
2291 	TrackerSparqlBuilder *sparql;
2292 	ProcessFileData *data;
2293 	const gchar *mime_type, *urn, *parent_urn;
2294 	GFileInfo *file_info;
2295 	guint64 time_;
2296 	GFile *file;
2297 	gchar *uri;
2298 	GError *error = NULL;
2299 	gboolean is_iri;
2300 	gboolean is_directory;
2301 
2302 	data = user_data;
2303 	file = G_FILE (object);
2304 	sparql = data->sparql;
2305 	file_info = g_file_query_info_finish (file, result, &error);
2306 	priv = TRACKER_MINER_FILES (data->miner)->private;
2307 
2308 	if (error) {
2309 		/* Something bad happened, notify about the error */
2310 		tracker_miner_fs_file_notify (TRACKER_MINER_FS (data->miner), file, error);
2311 		priv->extraction_queue = g_list_remove (priv->extraction_queue, data);
2312 		process_file_data_free (data);
2313 		g_error_free (error);
2314 
2315 		return;
2316 	}
2317 
2318 	uri = g_file_get_uri (file);
2319 	mime_type = g_file_info_get_content_type (file_info);
2320 	urn = miner_files_get_file_urn (TRACKER_MINER_FILES (data->miner), file, &is_iri);
2321 
2322 	data->mime_type = g_strdup (mime_type);
2323 
2324 	tracker_sparql_builder_insert_silent_open (sparql, NULL);
2325 	tracker_sparql_builder_graph_open (sparql, TRACKER_MINER_FS_GRAPH_URN);
2326 
2327 	if (is_iri) {
2328 		tracker_sparql_builder_subject_iri (sparql, urn);
2329 	} else {
2330 		tracker_sparql_builder_subject (sparql, urn);
2331 	}
2332 
2333 	tracker_sparql_builder_predicate (sparql, "a");
2334 	tracker_sparql_builder_object (sparql, "nfo:FileDataObject");
2335 	tracker_sparql_builder_object (sparql, "nie:InformationElement");
2336 
2337 	is_directory = (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY ?
2338 	                TRUE : FALSE);
2339 	if (is_directory) {
2340 		tracker_sparql_builder_object (sparql, "nfo:Folder");
2341 	}
2342 
2343 	parent_urn = tracker_miner_fs_get_parent_urn (TRACKER_MINER_FS (data->miner), file);
2344 
2345 	if (parent_urn) {
2346 		tracker_sparql_builder_predicate (sparql, "nfo:belongsToContainer");
2347 		tracker_sparql_builder_object_iri (sparql, parent_urn);
2348 	}
2349 
2350 	tracker_sparql_builder_predicate (sparql, "nfo:fileName");
2351 	tracker_sparql_builder_object_string (sparql, g_file_info_get_display_name (file_info));
2352 
2353 	tracker_sparql_builder_predicate (sparql, "nfo:fileSize");
2354 	tracker_sparql_builder_object_int64 (sparql, g_file_info_get_size (file_info));
2355 
2356 	time_ = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
2357 	tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified");
2358 	tracker_sparql_builder_object_date (sparql, (time_t *) &time_);
2359 
2360 	time_ = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_ACCESS);
2361 	tracker_sparql_builder_predicate (sparql, "nfo:fileLastAccessed");
2362 	tracker_sparql_builder_object_date (sparql, (time_t *) &time_);
2363 
2364 	/* Laying the link between the IE and the DO. We use IE = DO */
2365 	tracker_sparql_builder_predicate (sparql, "nie:isStoredAs");
2366 	if (is_iri) {
2367 		tracker_sparql_builder_object_iri (sparql, urn);
2368 	} else {
2369 		tracker_sparql_builder_object (sparql, urn);
2370 	}
2371 
2372 	/* The URL of the DataObject (because IE = DO, this is correct) */
2373 	tracker_sparql_builder_predicate (sparql, "nie:url");
2374 	tracker_sparql_builder_object_string (sparql, uri);
2375 
2376 	tracker_sparql_builder_predicate (sparql, "nie:mimeType");
2377 	tracker_sparql_builder_object_string (sparql, mime_type);
2378 
2379 	miner_files_add_to_datasource (data->miner, file, sparql);
2380 
2381 	if (tracker_extract_module_manager_mimetype_is_handled (mime_type)) {
2382 		/* Next step, if handled by the extractor, get embedded metadata */
2383 		tracker_extract_client_get_metadata (data->file,
2384 		                                     mime_type,
2385 		                                     TRACKER_MINER_FS_GRAPH_URN,
2386 		                                     data->cancellable,
2387 		                                     extractor_get_embedded_metadata_cb,
2388 		                                     data);
2389 	} else {
2390 		/* Otherwise, don't request embedded metadata extraction. */
2391 		g_debug ("Avoiding embedded metadata request for uri '%s'", uri);
2392 		sparql_builder_finish (data, NULL, NULL, NULL, NULL);
2393 		tracker_miner_fs_file_notify (TRACKER_MINER_FS (data->miner), data->file, NULL);
2394 
2395 		priv->extraction_queue = g_list_remove (priv->extraction_queue, data);
2396 		extractor_check_process_failsafe (data->miner);
2397 		process_file_data_free (data);
2398 	}
2399 
2400 	g_object_unref (file_info);
2401 	g_free (uri);
2402 }
2403 
2404 static gboolean
2405 miner_files_process_file (TrackerMinerFS       *fs,
2406                           GFile                *file,
2407                           TrackerSparqlBuilder *sparql,
2408                           GCancellable         *cancellable)
2409 {
2410 	TrackerMinerFilesPrivate *priv;
2411 	ProcessFileData *data;
2412 	const gchar *attrs;
2413 
2414 	data = g_slice_new0 (ProcessFileData);
2415 	data->miner = g_object_ref (fs);
2416 	data->cancellable = g_object_ref (cancellable);
2417 	data->sparql = g_object_ref (sparql);
2418 	data->file = g_object_ref (file);
2419 
2420 	priv = TRACKER_MINER_FILES (fs)->private;
2421 	priv->extraction_queue = g_list_prepend (priv->extraction_queue, data);
2422 
2423 	attrs = G_FILE_ATTRIBUTE_STANDARD_TYPE ","
2424 		G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
2425 		G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
2426 		G_FILE_ATTRIBUTE_STANDARD_SIZE ","
2427 		G_FILE_ATTRIBUTE_TIME_MODIFIED ","
2428 		G_FILE_ATTRIBUTE_TIME_ACCESS;
2429 
2430 	g_file_query_info_async (file,
2431 	                         attrs,
2432 	                         G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2433 	                         G_PRIORITY_DEFAULT,
2434 	                         cancellable,
2435 	                         process_file_cb,
2436 	                         data);
2437 
2438 	return TRUE;
2439 }
2440 
2441 static void
2442 process_file_attributes_cb (GObject      *object,
2443                             GAsyncResult *result,
2444                             gpointer      user_data)
2445 {
2446 	TrackerSparqlBuilder *sparql;
2447 	ProcessFileData *data;
2448 	const gchar *urn;
2449 	GFileInfo *file_info;
2450 	guint64 time_;
2451 	GFile *file;
2452 	gchar *uri;
2453 	GError *error = NULL;
2454 	gboolean is_iri;
2455 
2456 	data = user_data;
2457 	file = G_FILE (object);
2458 	sparql = data->sparql;
2459 	file_info = g_file_query_info_finish (file, result, &error);
2460 
2461 	if (error) {
2462 		/* Something bad happened, notify about the error */
2463 		tracker_miner_fs_file_notify (TRACKER_MINER_FS (data->miner), file, error);
2464 		process_file_data_free (data);
2465 		g_error_free (error);
2466 		return;
2467 	}
2468 
2469 	uri = g_file_get_uri (file);
2470 	urn = miner_files_get_file_urn (TRACKER_MINER_FILES (data->miner), file, &is_iri);
2471 
2472 	/* We MUST have an IRI in attributes updating */
2473 	if (!is_iri) {
2474 		error = g_error_new_literal (miner_files_error_quark,
2475 		                             0,
2476 		                             "Received request to update attributes but no IRI available!");
2477 		/* Notify about the error */
2478 		tracker_miner_fs_file_notify (TRACKER_MINER_FS (data->miner), file, error);
2479 		process_file_data_free (data);
2480 		g_error_free (error);
2481 		return;
2482 	}
2483 
2484 	/* Update nfo:fileLastModified */
2485 	tracker_sparql_builder_delete_open (sparql, NULL);
2486 	tracker_sparql_builder_subject_iri (sparql, urn);
2487 	tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified");
2488 	tracker_sparql_builder_object_variable (sparql, "lastmodified");
2489 	tracker_sparql_builder_delete_close (sparql);
2490 	tracker_sparql_builder_where_open (sparql);
2491 	tracker_sparql_builder_subject_iri (sparql, urn);
2492 	tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified");
2493 	tracker_sparql_builder_object_variable (sparql, "lastmodified");
2494 	tracker_sparql_builder_where_close (sparql);
2495 	tracker_sparql_builder_insert_open (sparql, NULL);
2496 	tracker_sparql_builder_graph_open (sparql, TRACKER_MINER_FS_GRAPH_URN);
2497 	tracker_sparql_builder_subject_iri (sparql, urn);
2498 	time_ = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
2499 	tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified");
2500 	tracker_sparql_builder_object_date (sparql, (time_t *) &time_);
2501 	tracker_sparql_builder_graph_close (sparql);
2502 	tracker_sparql_builder_insert_close (sparql);
2503 
2504 	/* Update nfo:fileLastAccessed */
2505 	tracker_sparql_builder_delete_open (sparql, NULL);
2506 	tracker_sparql_builder_subject_iri (sparql, urn);
2507 	tracker_sparql_builder_predicate (sparql, "nfo:fileLastAccessed");
2508 	tracker_sparql_builder_object_variable (sparql, "lastaccessed");
2509 	tracker_sparql_builder_delete_close (sparql);
2510 	tracker_sparql_builder_where_open (sparql);
2511 	tracker_sparql_builder_subject_iri (sparql, urn);
2512 	tracker_sparql_builder_predicate (sparql, "nfo:fileLastAccessed");
2513 	tracker_sparql_builder_object_variable (sparql, "lastaccessed");
2514 	tracker_sparql_builder_where_close (sparql);
2515 	tracker_sparql_builder_insert_open (sparql, NULL);
2516 	tracker_sparql_builder_graph_open (sparql, TRACKER_MINER_FS_GRAPH_URN);
2517 	tracker_sparql_builder_subject_iri (sparql, urn);
2518 	time_ = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_ACCESS);
2519 	tracker_sparql_builder_predicate (sparql, "nfo:fileLastAccessed");
2520 	tracker_sparql_builder_object_date (sparql, (time_t *) &time_);
2521 	tracker_sparql_builder_graph_close (sparql);
2522 	tracker_sparql_builder_insert_close (sparql);
2523 
2524 	g_object_unref (file_info);
2525 	g_free (uri);
2526 
2527 	/* Notify about the success */
2528 	tracker_miner_fs_file_notify (TRACKER_MINER_FS (data->miner), data->file, NULL);
2529 
2530 	process_file_data_free (data);
2531 }
2532 
2533 static gboolean
2534 miner_files_process_file_attributes (TrackerMinerFS       *fs,
2535                                      GFile                *file,
2536                                      TrackerSparqlBuilder *sparql,
2537                                      GCancellable         *cancellable)
2538 {
2539 	ProcessFileData *data;
2540 	const gchar *attrs;
2541 
2542 	data = g_slice_new0 (ProcessFileData);
2543 	data->miner = g_object_ref (fs);
2544 	data->cancellable = g_object_ref (cancellable);
2545 	data->sparql = g_object_ref (sparql);
2546 	data->file = g_object_ref (file);
2547 
2548 	/* Query only attributes that may change in an ATTRIBUTES_UPDATED event */
2549 	attrs = G_FILE_ATTRIBUTE_TIME_MODIFIED ","
2550 		G_FILE_ATTRIBUTE_TIME_ACCESS;
2551 
2552 	g_file_query_info_async (file,
2553 	                         attrs,
2554 	                         G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2555 	                         G_PRIORITY_DEFAULT,
2556 	                         cancellable,
2557 	                         process_file_attributes_cb,
2558 	                         data);
2559 
2560 	return TRUE;
2561 }
2562 
2563 static gboolean
2564 miner_files_ignore_next_update_file (TrackerMinerFS       *fs,
2565                                      GFile                *file,
2566                                      TrackerSparqlBuilder *sparql,
2567                                      GCancellable         *cancellable)
2568 {
2569 	const gchar *attrs;
2570 	const gchar *mime_type;
2571 	GFileInfo *file_info;
2572 	guint64 time_;
2573 	gchar *uri;
2574 	GError *error = NULL;
2575 
2576 	attrs = G_FILE_ATTRIBUTE_STANDARD_TYPE ","
2577 		G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
2578 		G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME ","
2579 		G_FILE_ATTRIBUTE_STANDARD_SIZE ","
2580 		G_FILE_ATTRIBUTE_TIME_MODIFIED ","
2581 		G_FILE_ATTRIBUTE_TIME_ACCESS;
2582 
2583 	file_info = g_file_query_info (file, attrs,
2584 	                               G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2585 	                               cancellable, &error);
2586 
2587 	if (error) {
2588 		g_warning ("Can't ignore-next-update: '%s'", error->message);
2589 		g_clear_error (&error);
2590 		return FALSE;
2591 	}
2592 
2593 	uri = g_file_get_uri (file);
2594 	mime_type = g_file_info_get_content_type (file_info);
2595 
2596 	/* For ignore-next-update we only write a few properties back. These properties
2597 	 * should NEVER be marked as tracker:writeback in the ontology! (else you break
2598 	 * the tracker-writeback feature) */
2599 
2600 	tracker_sparql_builder_insert_silent_open (sparql, TRACKER_MINER_FS_GRAPH_URN);
2601 
2602 	tracker_sparql_builder_subject_variable (sparql, "urn");
2603 	tracker_sparql_builder_predicate (sparql, "a");
2604 	tracker_sparql_builder_object (sparql, "nfo:FileDataObject");
2605 
2606 	tracker_sparql_builder_predicate (sparql, "nfo:fileSize");
2607 	tracker_sparql_builder_object_int64 (sparql, g_file_info_get_size (file_info));
2608 
2609 	time_ = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
2610 	tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified");
2611 	tracker_sparql_builder_object_date (sparql, (time_t *) &time_);
2612 
2613 	time_ = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_ACCESS);
2614 	tracker_sparql_builder_predicate (sparql, "nfo:fileLastAccessed");
2615 	tracker_sparql_builder_object_date (sparql, (time_t *) &time_);
2616 
2617 	tracker_sparql_builder_predicate (sparql, "nie:mimeType");
2618 	tracker_sparql_builder_object_string (sparql, mime_type);
2619 
2620 	tracker_sparql_builder_insert_close (sparql);
2621 
2622 	tracker_sparql_builder_where_open (sparql);
2623 
2624 	tracker_sparql_builder_subject_variable (sparql, "urn");
2625 	tracker_sparql_builder_predicate (sparql, "nie:url");
2626 	tracker_sparql_builder_object_string (sparql, uri);
2627 
2628 	tracker_sparql_builder_where_close (sparql);
2629 
2630 	g_object_unref (file_info);
2631 	g_free (uri);
2632 
2633 	return TRUE;
2634 }
2635 
2636 static void
2637 miner_files_finished (TrackerMinerFS *fs)
2638 {
2639 	tracker_db_manager_set_last_crawl_done (TRUE);
2640 }
2641 
2642 TrackerMiner *
2643 tracker_miner_files_new (TrackerConfig  *config,
2644                          GError        **error)
2645 {
2646 	return g_initable_new (TRACKER_TYPE_MINER_FILES,
2647 	                       NULL,
2648 	                       error,
2649 	                       "name", "Files",
2650 	                       "config", config,
2651 	                       "processing-pool-wait-limit", 10,
2652 	                       "processing-pool-ready-limit", 100,
2653 	                       NULL);
2654 }
2655 
2656 gboolean
2657 tracker_miner_files_check_file (GFile  *file,
2658                                 GSList *ignored_file_paths,
2659                                 GSList *ignored_file_patterns)
2660 {
2661 	GSList *l;
2662 	gchar *basename;
2663 	gchar *path;
2664 	gboolean should_process;
2665 
2666 	should_process = FALSE;
2667 	basename = NULL;
2668 	path = NULL;
2669 
2670 	if (tracker_file_is_hidden (file)) {
2671 		/* Ignore hidden files */
2672 		goto done;
2673 	}
2674 
2675 	path = g_file_get_path (file);
2676 
2677 	for (l = ignored_file_paths; l; l = l->next) {
2678 		if (strcmp (l->data, path) == 0) {
2679 			goto done;
2680 		}
2681 	}
2682 
2683 	basename = g_file_get_basename (file);
2684 
2685 	for (l = ignored_file_patterns; l; l = l->next) {
2686 		if (g_pattern_match_string (l->data, basename)) {
2687 			goto done;
2688 		}
2689 	}
2690 
2691 	should_process = TRUE;
2692 
2693 done:
2694 	g_free (basename);
2695 	g_free (path);
2696 
2697 	return should_process;
2698 }
2699 
2700 gboolean
2701 tracker_miner_files_check_directory (GFile  *file,
2702                                      GSList *index_recursive_directories,
2703                                      GSList *index_single_directories,
2704                                      GSList *ignored_directory_paths,
2705                                      GSList *ignored_directory_patterns)
2706 {
2707 	GSList *l;
2708 	gchar *basename;
2709 	gchar *path;
2710 	gboolean should_process;
2711 	gboolean is_hidden;
2712 
2713 	should_process = FALSE;
2714 	basename = NULL;
2715 
2716 	path = g_file_get_path (file);
2717 
2718 	/* First we check the GIO hidden check. This does a number of
2719 	 * things for us which is good (like checking ".foo" dirs).
2720 	 */
2721 	is_hidden = tracker_file_is_hidden (file);
2722 
2723 #ifdef __linux__
2724 	/* Second we check if the file is on FAT and if the hidden
2725 	 * attribute is set. GIO does this but ONLY on a Windows OS,
2726 	 * not for Windows files under a Linux OS, so we have to check
2727 	 * anyway.
2728 	 */
2729 	if (!is_hidden) {
2730 		int fd;
2731 
2732 		fd = g_open (path, O_RDONLY, 0);
2733 		if (fd != -1) {
2734 			__u32 attrs;
2735 
2736 			if (ioctl (fd, FAT_IOCTL_GET_ATTRIBUTES, &attrs) == 0) {
2737 				is_hidden = attrs & ATTR_HIDDEN ? TRUE : FALSE;
2738 			}
2739 
2740 			close (fd);
2741 		}
2742 	}
2743 #endif /* __linux__ */
2744 
2745 	if (is_hidden) {
2746 		/* FIXME: We need to check if the file is actually a
2747 		 * config specified location before blanket ignoring
2748 		 * all hidden files.
2749 		 */
2750 		if (tracker_string_in_gslist (path, index_recursive_directories)) {
2751 			should_process = TRUE;
2752 		}
2753 
2754 		if (tracker_string_in_gslist (path, index_single_directories)) {
2755 			should_process = TRUE;
2756 		}
2757 
2758 		/* Ignore hidden dirs */
2759 		goto done;
2760 	}
2761 
2762 	for (l = ignored_directory_paths; l; l = l->next) {
2763 		if (strcmp (l->data, path) == 0) {
2764 			goto done;
2765 		}
2766 	}
2767 
2768 	basename = g_file_get_basename (file);
2769 
2770 	for (l = ignored_directory_patterns; l; l = l->next) {
2771 		if (g_pattern_match_string (l->data, basename)) {
2772 			goto done;
2773 		}
2774 	}
2775 
2776 	/* Check module directory ignore patterns */
2777 	should_process = TRUE;
2778 
2779 done:
2780 	g_free (basename);
2781 	g_free (path);
2782 
2783 	return should_process;
2784 }
2785 
2786 gboolean
2787 tracker_miner_files_check_directory_contents (GFile  *parent,
2788                                               GList  *children,
2789                                               GSList *ignored_content)
2790 {
2791 	GSList *l;
2792 
2793 	if (!ignored_content) {
2794 		return TRUE;
2795 	}
2796 
2797 	while (children) {
2798 		gchar *basename;
2799 
2800 		basename = g_file_get_basename (children->data);
2801 
2802 		for (l = ignored_content; l; l = l->next) {
2803 			if (g_strcmp0 (basename, l->data) == 0) {
2804 				gchar *parent_uri;
2805 
2806 				parent_uri = g_file_get_uri (parent);
2807 				/* g_debug ("Directory '%s' ignored since it contains a file named '%s'", */
2808 				/*          parent_uri, basename); */
2809 
2810 				g_free (parent_uri);
2811 				g_free (basename);
2812 
2813 				return FALSE;
2814 			}
2815 		}
2816 
2817 		children = children->next;
2818 		g_free (basename);
2819 	}
2820 
2821 	return TRUE;
2822 }
2823 
2824 gboolean
2825 tracker_miner_files_monitor_directory (GFile    *file,
2826                                        gboolean  enable_monitors,
2827                                        GSList   *directories_to_check)
2828 {
2829 	if (!enable_monitors) {
2830 		return FALSE;
2831 	}
2832 
2833 	/* We'll only get this signal for the directories where check_directory()
2834 	 * and check_directory_contents() returned TRUE, so by default we want
2835 	 * these directories to be indexed. */
2836 
2837 	return TRUE;
2838 }
2839 
2840 static void
2841 remove_files_in_removable_media_cb (GObject      *object,
2842                                     GAsyncResult *result,
2843                                     gpointer      user_data)
2844 {
2845 	GError *error = NULL;
2846 
2847 	tracker_sparql_connection_update_finish (TRACKER_SPARQL_CONNECTION (object), result, &error);
2848 
2849 	if (error) {
2850 		g_critical ("Could not remove files in volumes: %s", error->message);
2851 		g_error_free (error);
2852 	}
2853 }
2854 
2855 static gboolean
2856 miner_files_in_removable_media_remove_by_type (TrackerMinerFiles  *miner,
2857                                                TrackerStorageType  type)
2858 {
2859 	gboolean removable;
2860 	gboolean optical;
2861 
2862 	removable = TRACKER_STORAGE_TYPE_IS_REMOVABLE (type);
2863 	optical = TRACKER_STORAGE_TYPE_IS_OPTICAL (type);
2864 
2865 	/* Only remove if any of the flags was TRUE */
2866 	if (removable || optical) {
2867 		GString *queries;
2868 
2869 		g_debug ("  Removing all resources in store from %s ",
2870 		         optical ? "optical discs" : "removable devices");
2871 
2872 		queries = g_string_new ("");
2873 
2874 		/* Delete all resources where nie:dataSource is a volume
2875 		 * of the given type */
2876 		g_string_append_printf (queries,
2877 		                        "DELETE { "
2878 		                        "  ?f a rdfs:Resource . "
2879 		                        "  ?ie a rdfs:Resource "
2880 		                        "} WHERE { "
2881 		                        "  ?v a tracker:Volume ; "
2882 		                        "     tracker:isRemovable %s ; "
2883 		                        "     tracker:isOptical %s . "
2884 		                        "  ?f nie:dataSource ?v . "
2885 		                        "  ?ie nie:isStoredAs ?f "
2886 		                        "}",
2887 		                        removable ? "true" : "false",
2888 		                        optical ? "true" : "false");
2889 
2890 		tracker_sparql_connection_update_async (tracker_miner_get_connection (TRACKER_MINER (miner)),
2891 		                                        queries->str,
2892 		                                        G_PRIORITY_LOW,
2893 		                                        NULL,
2894 		                                        remove_files_in_removable_media_cb,
2895 		                                        NULL);
2896 
2897 		g_string_free (queries, TRUE);
2898 
2899 		return TRUE;
2900 	}
2901 
2902 	return FALSE;
2903 }
2904 
2905 static void
2906 miner_files_in_removable_media_remove_by_date (TrackerMinerFiles  *miner,
2907                                                const gchar        *date)
2908 {
2909 	GString *queries;
2910 
2911 	g_debug ("  Removing all resources in store from removable or "
2912 	         "optical devices not mounted after '%s'",
2913 	         date);
2914 
2915 	queries = g_string_new ("");
2916 
2917 	/* Delete all resources where nie:dataSource is a volume
2918 	 * which was last unmounted before the given date */
2919 	g_string_append_printf (queries,
2920 	                        "DELETE { "
2921 	                        "  ?f a rdfs:Resource . "
2922 	                        "  ?ie a rdfs:Resource "
2923 	                        "} WHERE { "
2924 	                        "  ?v a tracker:Volume ; "
2925 	                        "     tracker:isRemovable true ; "
2926 	                        "     tracker:isMounted false ; "
2927 	                        "     tracker:unmountDate ?d . "
2928 	                        "  ?f nie:dataSource ?v . "
2929 	                        "  ?ie nie:isStoredAs ?f "
2930 	                        "  FILTER ( ?d < \"%s\") "
2931 	                        "}",
2932 	                        date);
2933 
2934 	tracker_sparql_connection_update_async (tracker_miner_get_connection (TRACKER_MINER (miner)),
2935 	                                        queries->str,
2936 	                                        G_PRIORITY_LOW,
2937 	                                        NULL,
2938 	                                        remove_files_in_removable_media_cb,
2939 	                                        NULL);
2940 
2941 	g_string_free (queries, TRUE);
2942 }
2943 
2944 static void
2945 miner_files_add_removable_or_optical_directory (TrackerMinerFiles *mf,
2946                                                 const gchar       *mount_path,
2947                                                 const gchar       *uuid)
2948 {
2949 	TrackerIndexingTree *indexing_tree;
2950 	TrackerDirectoryFlags flags;
2951 	GFile *mount_point_file;
2952 
2953 	mount_point_file = g_file_new_for_path (mount_path);
2954 
2955 	/* UUID may be NULL, and if so, get it */
2956 	if (!uuid) {
2957 		uuid = tracker_storage_get_uuid_for_file (mf->private->storage,
2958 		                                          mount_point_file);
2959 		if (!uuid) {
2960 			g_critical ("Couldn't get UUID for mount point '%s'",
2961 			            mount_path);
2962 			g_object_unref (mount_point_file);
2963 			return;
2964 		}
2965 	}
2966 
2967 	indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (mf));
2968 	flags = TRACKER_DIRECTORY_FLAG_RECURSE |
2969 		TRACKER_DIRECTORY_FLAG_CHECK_MTIME |
2970 		TRACKER_DIRECTORY_FLAG_PRESERVE;
2971 
2972 	if (tracker_config_get_enable_monitors (mf->private->config)) {
2973 		flags |= TRACKER_DIRECTORY_FLAG_MONITOR;
2974 	}
2975 
2976 	g_object_set_qdata_full (G_OBJECT (mount_point_file),
2977 	                         mf->private->quark_mount_point_uuid,
2978 	                         g_strdup (uuid),
2979 	                         (GDestroyNotify) g_free);
2980 
2981 	g_message ("  Adding removable/optical: '%s'", mount_path);
2982 	tracker_indexing_tree_add (indexing_tree,
2983 				   mount_point_file,
2984 				   flags);
2985 	g_object_unref (mount_point_file);
2986 }
2987 
2988 gboolean
2989 tracker_miner_files_is_file_eligible (TrackerMinerFiles *miner,
2990                                       GFile             *file)
2991 {
2992 	TrackerConfig *config;
2993 	GFile *dir;
2994 	GFileInfo *file_info;
2995 	gboolean is_dir;
2996 
2997 	file_info = g_file_query_info (file,
2998 	                               G_FILE_ATTRIBUTE_STANDARD_TYPE,
2999 	                               G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
3000 	                               NULL, NULL);
3001 
3002 	if (!file_info) {
3003 		/* file does not exist */
3004 		return FALSE;
3005 	}
3006 
3007 	is_dir = (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY);
3008 	g_object_unref (file_info);
3009 
3010 	g_object_get (miner,
3011 	              "config", &config,
3012 	              NULL);
3013 
3014 	if (is_dir) {
3015 		dir = g_object_ref (file);
3016 	} else {
3017 		if (!tracker_miner_files_check_file (file,
3018 		                                     tracker_config_get_ignored_file_paths (config),
3019 		                                     tracker_config_get_ignored_file_patterns (config))) {
3020 			/* file is not eligible to be indexed */
3021 			g_object_unref (config);
3022 			return FALSE;
3023 		}
3024 
3025 		dir = g_file_get_parent (file);
3026 	}
3027 
3028 	if (dir) {
3029 		gboolean found = FALSE;
3030 		GSList *l;
3031 
3032 		if (!tracker_miner_files_check_directory (dir,
3033 		                                          tracker_config_get_index_recursive_directories (config),
3034 		                                          tracker_config_get_index_single_directories (config),
3035 		                                          tracker_config_get_ignored_directory_paths (config),
3036 		                                          tracker_config_get_ignored_directory_patterns (config))) {
3037 			/* file is not eligible to be indexed */
3038 			g_object_unref (dir);
3039 			g_object_unref (config);
3040 			return FALSE;
3041 		}
3042 
3043 		l = tracker_config_get_index_recursive_directories (config);
3044 
3045 		while (l && !found) {
3046 			GFile *config_dir;
3047 
3048 			config_dir = g_file_new_for_path ((gchar *) l->data);
3049 
3050 			if (g_file_equal (dir, config_dir) ||
3051 			    g_file_has_prefix (dir, config_dir)) {
3052 				found = TRUE;
3053 			}
3054 
3055 			g_object_unref (config_dir);
3056 			l = l->next;
3057 		}
3058 
3059 		l = tracker_config_get_index_single_directories (config);
3060 
3061 		while (l && !found) {
3062 			GFile *config_dir;
3063 
3064 			config_dir = g_file_new_for_path ((gchar *) l->data);
3065 
3066 			if (g_file_equal (dir, config_dir)) {
3067 				found = TRUE;
3068 			}
3069 
3070 			g_object_unref (config_dir);
3071 			l = l->next;
3072 		}
3073 
3074 		g_object_unref (dir);
3075 
3076 		if (!found) {
3077 			/* file is not eligible to be indexed */
3078 			g_object_unref (config);
3079 			return FALSE;
3080 		}
3081 	}
3082 
3083 	g_object_unref (config);
3084 
3085 	/* file is eligible to be indexed */
3086 	return TRUE;
3087 }