diff options
Diffstat (limited to 'src/miners/fs/tracker-miner-files.c')
-rw-r--r-- | src/miners/fs/tracker-miner-files.c | 3557 |
1 files changed, 0 insertions, 3557 deletions
diff --git a/src/miners/fs/tracker-miner-files.c b/src/miners/fs/tracker-miner-files.c deleted file mode 100644 index 87eb6ae11..000000000 --- a/src/miners/fs/tracker-miner-files.c +++ /dev/null @@ -1,3557 +0,0 @@ -/* - * Copyright (C) 2008, Nokia <ivan.frade@nokia.com> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include "config.h" - -#include <sys/statvfs.h> -#include <fcntl.h> -#ifdef __linux__ -#include <sys/ioctl.h> -#include <linux/msdos_fs.h> -#endif /* __linux__ */ -#include <unistd.h> - -#include <glib/gi18n.h> -#include <glib/gstdio.h> - -#include <gio/gio.h> -#include <gio/gunixfdlist.h> -#include <gio/gunixinputstream.h> - -#include <libtracker-common/tracker-common.h> -#include <libtracker-sparql/tracker-ontologies.h> -#include <libtracker-extract/tracker-extract.h> - -#include <libtracker-data/tracker-db-manager.h> - -#include "tracker-power.h" -#include "tracker-miner-files.h" -#include "tracker-config.h" -#include "tracker-storage.h" -#include "tracker-extract-watchdog.h" -#include "tracker-thumbnailer.h" - -#define DISK_SPACE_CHECK_FREQUENCY 10 -#define SECONDS_PER_DAY 86400 - -/* Stamp files to know crawling/indexing state */ -#define FIRST_INDEX_FILENAME "first-index.txt" -#define LAST_CRAWL_FILENAME "last-crawl.txt" -#define NEED_MTIME_CHECK_FILENAME "no-need-mtime-check.txt" - -#define TRACKER_MINER_FILES_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRACKER_TYPE_MINER_FILES, TrackerMinerFilesPrivate)) - -static GQuark miner_files_error_quark = 0; - -typedef struct ProcessFileData ProcessFileData; - -struct ProcessFileData { - TrackerMinerFiles *miner; - TrackerSparqlBuilder *sparql; - GCancellable *cancellable; - GFile *file; - gchar *mime_type; - GTask *task; -}; - -struct TrackerMinerFilesPrivate { - TrackerConfig *config; - TrackerStorage *storage; - TrackerExtractWatchdog *extract_watchdog; - - GVolumeMonitor *volume_monitor; - - GSList *index_recursive_directories; - GSList *index_single_directories; - - guint disk_space_check_id; - gboolean disk_space_pause; - - gboolean low_battery_pause; - -#if defined(HAVE_UPOWER) || defined(HAVE_HAL) - TrackerPower *power; -#endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */ - gulong finished_handler; - - GDBusConnection *connection; - - GQuark quark_mount_point_uuid; - - guint force_recheck_id; - - gboolean mtime_check; - gboolean index_removable_devices; - gboolean index_optical_discs; - guint volumes_changed_id; - - gboolean mount_points_initialized; - - guint stale_volumes_check_id; - - GList *extraction_queue; - - TrackerThumbnailer *thumbnailer; - - GHashTable *writeback_tasks; - gboolean paused_for_writeback; -}; - -typedef struct { - GMainLoop *main_loop; - TrackerMiner *miner; -} ThumbnailMoveData; - -enum { - VOLUME_MOUNTED_IN_STORE = 1 << 0, - VOLUME_MOUNTED = 1 << 1 -}; - -enum { - PROP_0, - PROP_CONFIG -}; - -enum { - WRITEBACK, - N_SIGNALS -}; - -static guint signals[N_SIGNALS] = { 0 }; - -static void miner_files_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); -static void miner_files_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void miner_files_finalize (GObject *object); -static void miner_files_initable_iface_init (GInitableIface *iface); -static gboolean miner_files_initable_init (GInitable *initable, - GCancellable *cancellable, - GError **error); -static void mount_pre_unmount_cb (GVolumeMonitor *volume_monitor, - GMount *mount, - TrackerMinerFiles *mf); - -static void mount_point_added_cb (TrackerStorage *storage, - const gchar *uuid, - const gchar *mount_point, - const gchar *mount_name, - gboolean removable, - gboolean optical, - gpointer user_data); -static void mount_point_removed_cb (TrackerStorage *storage, - const gchar *uuid, - const gchar *mount_point, - gpointer user_data); -#if defined(HAVE_UPOWER) || defined(HAVE_HAL) -static void check_battery_status (TrackerMinerFiles *fs); -static void battery_status_cb (GObject *object, - GParamSpec *pspec, - gpointer user_data); -static void index_on_battery_cb (GObject *object, - GParamSpec *pspec, - gpointer user_data); -#endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */ -static void init_mount_points (TrackerMinerFiles *miner); -static void init_stale_volume_removal (TrackerMinerFiles *miner); -static void disk_space_check_start (TrackerMinerFiles *mf); -static void disk_space_check_stop (TrackerMinerFiles *mf); -static void low_disk_space_limit_cb (GObject *gobject, - GParamSpec *arg1, - gpointer user_data); -static void index_recursive_directories_cb (GObject *gobject, - GParamSpec *arg1, - gpointer user_data); -static void index_single_directories_cb (GObject *gobject, - GParamSpec *arg1, - gpointer user_data); -static gboolean miner_files_force_recheck_idle (gpointer user_data); -static void trigger_recheck_cb (GObject *gobject, - GParamSpec *arg1, - gpointer user_data); -static void index_volumes_changed_cb (GObject *gobject, - GParamSpec *arg1, - gpointer user_data); -static gboolean miner_files_process_file (TrackerMinerFS *fs, - GFile *file, - GTask *task); -static gboolean miner_files_process_file_attributes (TrackerMinerFS *fs, - GFile *file, - GTask *task); -static gchar * miner_files_remove_children (TrackerMinerFS *fs, - GFile *file); -static gchar * miner_files_remove_file (TrackerMinerFS *fs, - GFile *file); -static gchar * miner_files_move_file (TrackerMinerFS *fs, - GFile *file, - GFile *source_file, - gboolean recursive); -static void miner_files_finished (TrackerMinerFS *fs, - gdouble elapsed, - gint directories_found, - gint directories_ignored, - gint files_found, - gint files_ignored); -static void miner_finished_cb (TrackerMinerFS *fs, - gdouble seconds_elapsed, - guint total_directories_found, - guint total_directories_ignored, - guint total_files_found, - guint total_files_ignored, - gpointer user_data); - -static gboolean miner_files_in_removable_media_remove_by_type (TrackerMinerFiles *miner, - TrackerStorageType type); -static void miner_files_in_removable_media_remove_by_date (TrackerMinerFiles *miner, - const gchar *date); - -static void miner_files_add_removable_or_optical_directory (TrackerMinerFiles *mf, - const gchar *mount_path, - const gchar *uuid); - -static void miner_files_update_filters (TrackerMinerFiles *files); - - -static GInitableIface* miner_files_initable_parent_iface; - -G_DEFINE_TYPE_WITH_CODE (TrackerMinerFiles, tracker_miner_files, TRACKER_TYPE_MINER_FS, - G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, - miner_files_initable_iface_init)); - -static void -sync_writeback_pause_state (TrackerMinerFiles *mf) -{ - guint n_writeback_tasks = g_hash_table_size (mf->private->writeback_tasks); - - if (n_writeback_tasks > 0 && !mf->private->paused_for_writeback) { - tracker_miner_pause (TRACKER_MINER (mf)); - mf->private->paused_for_writeback = TRUE; - } else if (n_writeback_tasks == 0 && mf->private->paused_for_writeback) { - mf->private->paused_for_writeback = FALSE; - tracker_miner_resume (TRACKER_MINER (mf)); - } -} - -static void -writeback_remove_recursively (TrackerMinerFiles *mf, - GFile *file) -{ - GHashTableIter iter; - GFile *writeback_file; - - if (g_hash_table_size (mf->private->writeback_tasks) == 0) - return; - - /* Remove and cancel writeback tasks in this directory */ - g_hash_table_iter_init (&iter, mf->private->writeback_tasks); - while (g_hash_table_iter_next (&iter, (gpointer*) &writeback_file, NULL)) { - if (g_file_equal (writeback_file, file) || - g_file_has_prefix (writeback_file, file)) { - g_hash_table_iter_remove (&iter); - } - } - - sync_writeback_pause_state (mf); -} - -static gboolean -miner_files_filter_event (TrackerMinerFS *fs, - TrackerMinerFSEventType type, - GFile *file, - GFile *source_file) -{ - TrackerMinerFiles *mf = TRACKER_MINER_FILES (fs); - GCancellable *cancellable; - - switch (type) { - case TRACKER_MINER_FS_EVENT_CREATED: - break; - case TRACKER_MINER_FS_EVENT_UPDATED: - /* If the file is in the writeback task pool, this is the - * file update applying it, so the event should be filtered - * out. - */ - if (g_hash_table_lookup_extended (mf->private->writeback_tasks, file, - NULL, (gpointer*) &cancellable)) { - if (!cancellable) { - /* The task was already notified, we can remove - * it now, so later updates will be processed. - */ - g_hash_table_remove (mf->private->writeback_tasks, file); - sync_writeback_pause_state (mf); - } - - /* There is a writeback task, pending or satisfied. - * Either way, this update should be ignored. - */ - return TRUE; - } - break; - case TRACKER_MINER_FS_EVENT_DELETED: - writeback_remove_recursively (mf, file); - break; - case TRACKER_MINER_FS_EVENT_MOVED: - /* If the origin file is also being written back, - * cancel it as this is an external operation. - */ - writeback_remove_recursively (mf, source_file); - break; - } - - return FALSE; -} - -static void -tracker_miner_files_class_init (TrackerMinerFilesClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - TrackerMinerFSClass *miner_fs_class = TRACKER_MINER_FS_CLASS (klass); - - object_class->finalize = miner_files_finalize; - object_class->get_property = miner_files_get_property; - object_class->set_property = miner_files_set_property; - - miner_fs_class->process_file = miner_files_process_file; - miner_fs_class->process_file_attributes = miner_files_process_file_attributes; - miner_fs_class->finished = miner_files_finished; - miner_fs_class->remove_file = miner_files_remove_file; - miner_fs_class->remove_children = miner_files_remove_children; - miner_fs_class->move_file = miner_files_move_file; - miner_fs_class->filter_event = miner_files_filter_event; - - /** - * TrackerMinerFiles::writeback-file: - * @miner: the #TrackerMinerFiles - * @file: a #GFile - * @rdf_types: the set of RDF types - * @results: (element-type GStrv): a set of results prepared by the preparation query - * @cancellable: a #GCancellable - * - * The ::writeback-file signal is emitted whenever a file must be written - * back - * - * Returns: %TRUE on success, %FALSE otherwise - **/ - signals[WRITEBACK] = - g_signal_new ("writeback", - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - 0, NULL, - NULL, - NULL, - G_TYPE_NONE, - 4, - G_TYPE_FILE, - G_TYPE_STRV, - G_TYPE_PTR_ARRAY, - G_TYPE_CANCELLABLE); - - g_object_class_install_property (object_class, - PROP_CONFIG, - g_param_spec_object ("config", - "Config", - "Config", - TRACKER_TYPE_CONFIG, - G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); - - g_type_class_add_private (klass, sizeof (TrackerMinerFilesPrivate)); - - miner_files_error_quark = g_quark_from_static_string ("TrackerMinerFiles"); -} - -static void -cancel_and_unref (gpointer data) -{ - GCancellable *cancellable = data; - - if (cancellable) { - g_cancellable_cancel (cancellable); - g_object_unref (cancellable); - } -} - -static void -tracker_miner_files_init (TrackerMinerFiles *mf) -{ - TrackerMinerFilesPrivate *priv; - - priv = mf->private = TRACKER_MINER_FILES_GET_PRIVATE (mf); - - priv->storage = tracker_storage_new (); - - g_signal_connect (priv->storage, "mount-point-added", - G_CALLBACK (mount_point_added_cb), - mf); - - g_signal_connect (priv->storage, "mount-point-removed", - G_CALLBACK (mount_point_removed_cb), - mf); - -#if defined(HAVE_UPOWER) || defined(HAVE_HAL) - priv->power = tracker_power_new (); - - g_signal_connect (priv->power, "notify::on-low-battery", - G_CALLBACK (battery_status_cb), - mf); - g_signal_connect (priv->power, "notify::on-battery", - G_CALLBACK (battery_status_cb), - mf); -#endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */ - - priv->finished_handler = g_signal_connect_after (mf, "finished", - G_CALLBACK (miner_finished_cb), - NULL); - - priv->volume_monitor = g_volume_monitor_get (); - g_signal_connect (priv->volume_monitor, "mount-pre-unmount", - G_CALLBACK (mount_pre_unmount_cb), - mf); - - priv->mtime_check = TRUE; - priv->quark_mount_point_uuid = g_quark_from_static_string ("tracker-mount-point-uuid"); - - priv->writeback_tasks = g_hash_table_new_full (g_file_hash, - (GEqualFunc) g_file_equal, - NULL, cancel_and_unref); -} - -static void -miner_files_initable_iface_init (GInitableIface *iface) -{ - miner_files_initable_parent_iface = g_type_interface_peek_parent (iface); - iface->init = miner_files_initable_init; -} - -static gboolean -miner_files_initable_init (GInitable *initable, - GCancellable *cancellable, - GError **error) -{ - TrackerMinerFiles *mf; - TrackerMinerFS *fs; - TrackerIndexingTree *indexing_tree; - TrackerDirectoryFlags flags; - GError *inner_error = NULL; - GSList *mounts = NULL; - GSList *dirs; - GSList *m; - - /* Chain up parent's initable callback before calling child's one */ - if (!miner_files_initable_parent_iface->init (initable, cancellable, &inner_error)) { - g_propagate_error (error, inner_error); - return FALSE; - } - - mf = TRACKER_MINER_FILES (initable); - fs = TRACKER_MINER_FS (initable); - indexing_tree = tracker_miner_fs_get_indexing_tree (fs); - tracker_indexing_tree_set_filter_hidden (indexing_tree, TRUE); - g_signal_connect_swapped (indexing_tree, "directory-removed", - G_CALLBACK (writeback_remove_recursively), mf); - - miner_files_update_filters (mf); - - /* Set up extractor and signals */ - mf->private->connection = g_bus_get_sync (TRACKER_IPC_BUS, NULL, &inner_error); - if (!mf->private->connection) { - g_propagate_error (error, inner_error); - g_prefix_error (error, - "Could not connect to the D-Bus session bus. "); - return FALSE; - } - - /* We must have a configuration setup here */ - if (G_UNLIKELY (!mf->private->config)) { - g_set_error (error, - TRACKER_MINER_ERROR, - 0, - "No config set for miner %s", - G_OBJECT_TYPE_NAME (mf)); - return FALSE; - } - - /* Setup mount points, we MUST have config set up before we - * init mount points because the config is used in that - * function. - */ - mf->private->index_removable_devices = tracker_config_get_index_removable_devices (mf->private->config); - - /* Note that if removable devices not indexed, optical discs - * will also never be indexed */ - mf->private->index_optical_discs = (mf->private->index_removable_devices ? - tracker_config_get_index_optical_discs (mf->private->config) : - FALSE); - - init_mount_points (mf); - - /* If this happened AFTER we have initialized mount points, initialize - * stale volume removal now. */ - if (mf->private->mount_points_initialized) { - init_stale_volume_removal (mf); - } - - if (mf->private->index_removable_devices) { - /* Get list of roots for removable devices (excluding optical) */ - mounts = tracker_storage_get_device_roots (mf->private->storage, - TRACKER_STORAGE_REMOVABLE, - TRUE); - } - - if (mf->private->index_optical_discs) { - /* Get list of roots for removable+optical devices */ - m = tracker_storage_get_device_roots (mf->private->storage, - TRACKER_STORAGE_OPTICAL | TRACKER_STORAGE_REMOVABLE, - TRUE); - mounts = g_slist_concat (mounts, m); - } - -#if defined(HAVE_UPOWER) || defined(HAVE_HAL) - check_battery_status (mf); -#endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */ - - g_message ("Setting up directories to iterate from config (IndexSingleDirectory)"); - - /* Fill in directories to inspect */ - dirs = tracker_config_get_index_single_directories (mf->private->config); - - /* Copy in case of config changes */ - mf->private->index_single_directories = tracker_gslist_copy_with_string_data (dirs); - - for (; dirs; dirs = dirs->next) { - GFile *file; - - /* Do some simple checks for silly locations */ - if (strcmp (dirs->data, "/dev") == 0 || - strcmp (dirs->data, "/lib") == 0 || - strcmp (dirs->data, "/proc") == 0 || - strcmp (dirs->data, "/sys") == 0) { - continue; - } - - if (g_str_has_prefix (dirs->data, g_get_tmp_dir ())) { - continue; - } - - /* Make sure we don't crawl volumes. */ - if (mounts) { - gboolean found = FALSE; - - for (m = mounts; m && !found; m = m->next) { - found = strcmp (m->data, dirs->data) == 0; - } - - if (found) { - g_message (" Duplicate found:'%s' - same as removable device path", - (gchar*) dirs->data); - continue; - } - } - - g_message (" Adding:'%s'", (gchar*) dirs->data); - - file = g_file_new_for_path (dirs->data); - - flags = TRACKER_DIRECTORY_FLAG_NONE; - - if (tracker_config_get_enable_monitors (mf->private->config)) { - flags |= TRACKER_DIRECTORY_FLAG_MONITOR; - } - - if (mf->private->mtime_check) { - flags |= TRACKER_DIRECTORY_FLAG_CHECK_MTIME; - } - - tracker_indexing_tree_add (indexing_tree, file, flags); - g_object_unref (file); - } - - g_message ("Setting up directories to iterate from config (IndexRecursiveDirectory)"); - - dirs = tracker_config_get_index_recursive_directories (mf->private->config); - - /* Copy in case of config changes */ - mf->private->index_recursive_directories = tracker_gslist_copy_with_string_data (dirs); - - for (; dirs; dirs = dirs->next) { - GFile *file; - - /* Do some simple checks for silly locations */ - if (strcmp (dirs->data, "/dev") == 0 || - strcmp (dirs->data, "/lib") == 0 || - strcmp (dirs->data, "/proc") == 0 || - strcmp (dirs->data, "/sys") == 0) { - continue; - } - - if (g_str_has_prefix (dirs->data, g_get_tmp_dir ())) { - continue; - } - - /* Make sure we don't crawl volumes. */ - if (mounts) { - gboolean found = FALSE; - - for (m = mounts; m && !found; m = m->next) { - found = strcmp (m->data, dirs->data) == 0; - } - - if (found) { - g_message (" Duplicate found:'%s' - same as removable device path", - (gchar*) dirs->data); - continue; - } - } - - g_message (" Adding:'%s'", (gchar*) dirs->data); - - file = g_file_new_for_path (dirs->data); - - flags = TRACKER_DIRECTORY_FLAG_RECURSE; - - if (tracker_config_get_enable_monitors (mf->private->config)) { - flags |= TRACKER_DIRECTORY_FLAG_MONITOR; - } - - if (mf->private->mtime_check) { - flags |= TRACKER_DIRECTORY_FLAG_CHECK_MTIME; - } - - tracker_indexing_tree_add (indexing_tree, file, flags); - g_object_unref (file); - } - - /* Add mounts */ - g_message ("Setting up directories to iterate from devices/discs"); - - if (!mf->private->index_removable_devices) { - g_message (" Removable devices are disabled in the config"); - - /* Make sure we don't have any resource in a volume of the given type */ - miner_files_in_removable_media_remove_by_type (mf, TRACKER_STORAGE_REMOVABLE); - } - - if (!mf->private->index_optical_discs) { - g_message (" Optical discs are disabled in the config"); - - /* Make sure we don't have any resource in a volume of the given type */ - miner_files_in_removable_media_remove_by_type (mf, TRACKER_STORAGE_REMOVABLE | TRACKER_STORAGE_OPTICAL); - } - - for (m = mounts; m; m = m->next) { - miner_files_add_removable_or_optical_directory (mf, - (gchar *) m->data, - NULL); - } - - /* We want to get notified when config changes */ - - g_signal_connect (mf->private->config, "notify::low-disk-space-limit", - G_CALLBACK (low_disk_space_limit_cb), - mf); - g_signal_connect (mf->private->config, "notify::index-recursive-directories", - G_CALLBACK (index_recursive_directories_cb), - mf); - g_signal_connect (mf->private->config, "notify::index-single-directories", - G_CALLBACK (index_single_directories_cb), - mf); - g_signal_connect (mf->private->config, "notify::ignored-directories", - G_CALLBACK (trigger_recheck_cb), - mf); - g_signal_connect (mf->private->config, "notify::ignored-directories-with-content", - G_CALLBACK (trigger_recheck_cb), - mf); - g_signal_connect (mf->private->config, "notify::ignored-files", - G_CALLBACK (trigger_recheck_cb), - mf); - g_signal_connect (mf->private->config, "notify::enable-monitors", - G_CALLBACK (trigger_recheck_cb), - mf); - g_signal_connect (mf->private->config, "notify::index-removable-devices", - G_CALLBACK (index_volumes_changed_cb), - mf); - g_signal_connect (mf->private->config, "notify::index-optical-discs", - G_CALLBACK (index_volumes_changed_cb), - mf); - g_signal_connect (mf->private->config, "notify::removable-days-threshold", - G_CALLBACK (index_volumes_changed_cb), - mf); - -#if defined(HAVE_UPOWER) || defined(HAVE_HAL) - - g_signal_connect (mf->private->config, "notify::index-on-battery", - G_CALLBACK (index_on_battery_cb), - mf); - g_signal_connect (mf->private->config, "notify::index-on-battery-first-time", - G_CALLBACK (index_on_battery_cb), - mf); - -#endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */ - - g_slist_foreach (mounts, (GFunc) g_free, NULL); - g_slist_free (mounts); - - disk_space_check_start (mf); - - mf->private->extract_watchdog = tracker_extract_watchdog_new (); - mf->private->thumbnailer = tracker_thumbnailer_new (); - - return TRUE; -} - -static void -miner_files_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - TrackerMinerFilesPrivate *priv; - - priv = TRACKER_MINER_FILES_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_CONFIG: - priv->config = g_value_dup_object (value); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -miner_files_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - TrackerMinerFilesPrivate *priv; - - priv = TRACKER_MINER_FILES_GET_PRIVATE (object); - - switch (prop_id) { - case PROP_CONFIG: - g_value_set_object (value, priv->config); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -miner_files_finalize (GObject *object) -{ - TrackerMinerFiles *mf; - TrackerMinerFilesPrivate *priv; - - mf = TRACKER_MINER_FILES (object); - priv = mf->private; - - g_clear_object (&priv->extract_watchdog); - - if (priv->config) { - g_signal_handlers_disconnect_by_func (priv->config, - low_disk_space_limit_cb, - NULL); - g_object_unref (priv->config); - } - - disk_space_check_stop (TRACKER_MINER_FILES (object)); - - if (priv->index_recursive_directories) { - g_slist_foreach (priv->index_recursive_directories, (GFunc) g_free, NULL); - g_slist_free (priv->index_recursive_directories); - } - - if (priv->index_single_directories) { - g_slist_foreach (priv->index_single_directories, (GFunc) g_free, NULL); - g_slist_free (priv->index_single_directories); - } - -#if defined(HAVE_UPOWER) || defined(HAVE_HAL) - if (priv->power) { - g_object_unref (priv->power); - } -#endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */ - - if (priv->storage) { - g_object_unref (priv->storage); - } - - if (priv->volume_monitor) { - g_signal_handlers_disconnect_by_func (priv->volume_monitor, - mount_pre_unmount_cb, - object); - g_object_unref (priv->volume_monitor); - } - - if (priv->force_recheck_id) { - g_source_remove (priv->force_recheck_id); - priv->force_recheck_id = 0; - } - - if (priv->stale_volumes_check_id) { - g_source_remove (priv->stale_volumes_check_id); - priv->stale_volumes_check_id = 0; - } - - if (priv->thumbnailer) { - g_object_unref (priv->thumbnailer); - } - - g_list_free (priv->extraction_queue); - g_hash_table_destroy (priv->writeback_tasks); - - G_OBJECT_CLASS (tracker_miner_files_parent_class)->finalize (object); -} - -static void -ensure_mount_point_exists (TrackerMinerFiles *miner, - GFile *mount_point, - GString *accumulator) -{ - gchar *iri; - gchar *uri; - - uri = g_file_get_uri (mount_point); - - /* Query the store for the URN of the mount point */ - iri = tracker_miner_fs_query_urn (TRACKER_MINER_FS (miner), - mount_point); - - if (iri) { - /* If exists, just return, nothing else to do */ - g_message ("Mount point '%s' already exists in store: '%s'", - uri, iri); - g_free (iri); - } else { - /* If it doesn't exist, we need to create it */ - g_message ("Mount point '%s' does not exist in store, need to create it", - uri); - - /* Create a nfo:Folder for the mount point */ - g_string_append_printf (accumulator, - "INSERT SILENT INTO <" TRACKER_OWN_GRAPH_URN "> {" - " _:file a nfo:FileDataObject, nie:InformationElement, nfo:Folder ; " - " nie:isStoredAs _:file ; " - " nie:url \"%s\" ; " - " nie:mimeType \"inode/directory\" ; " - " nfo:fileLastModified \"1981-06-05T02:20:00Z\" . " - "}", - uri); - } - - g_free (uri); -} - -static void -set_up_mount_point_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - TrackerSparqlConnection *connection = TRACKER_SPARQL_CONNECTION (source); - gchar *removable_device_urn = user_data; - GError *error = NULL; - - tracker_sparql_connection_update_finish (connection, result, &error); - - if (error) { - g_critical ("Could not set mount point in database '%s', %s", - removable_device_urn, - error->message); - g_error_free (error); - } - - g_free (removable_device_urn); -} - -static void -set_up_mount_point_type (TrackerMinerFiles *miner, - const gchar *removable_device_urn, - gboolean removable, - gboolean optical, - GString *accumulator) -{ - if (!accumulator) { - return; - } - - g_debug ("Mount point type being set in DB for URN '%s'", - removable_device_urn); - - g_string_append_printf (accumulator, - "DELETE { <%s> tracker:isRemovable ?unknown } WHERE { <%s> a tracker:Volume; tracker:isRemovable ?unknown } ", - removable_device_urn, removable_device_urn); - - g_string_append_printf (accumulator, - "INSERT INTO <" TRACKER_OWN_GRAPH_URN "> { <%s> a tracker:Volume; tracker:isRemovable %s } ", - removable_device_urn, removable ? "true" : "false"); - - g_string_append_printf (accumulator, - "DELETE { <%s> tracker:isOptical ?unknown } WHERE { <%s> a tracker:Volume; tracker:isOptical ?unknown } ", - removable_device_urn, removable_device_urn); - - g_string_append_printf (accumulator, - "INSERT INTO <" TRACKER_OWN_GRAPH_URN "> { <%s> a tracker:Volume; tracker:isOptical %s } ", - removable_device_urn, optical ? "true" : "false"); -} - -static void -set_up_mount_point (TrackerMinerFiles *miner, - const gchar *removable_device_urn, - const gchar *mount_point, - const gchar *mount_name, - gboolean mounted, - GString *accumulator) -{ - GString *queries; - - queries = g_string_new (NULL); - - if (mounted) { - g_debug ("Mount point state (MOUNTED) being set in DB for URN '%s' (mount_point: %s)", - removable_device_urn, - mount_point ? mount_point : "unknown"); - - if (mount_point) { - GFile *file; - gchar *uri; - - file = g_file_new_for_path (mount_point); - uri = g_file_get_uri (file); - - /* Before assigning a nfo:FileDataObject as tracker:mountPoint for - * the volume, make sure the nfo:FileDataObject exists in the store */ - ensure_mount_point_exists (miner, file, queries); - - g_string_append_printf (queries, - "DELETE { " - " <%s> tracker:mountPoint ?u " - "} WHERE { " - " ?u a nfo:FileDataObject; " - " nie:url \"%s\" " - "} ", - removable_device_urn, uri); - - g_string_append_printf (queries, - "DELETE { <%s> a rdfs:Resource } " - "INSERT { " - " <%s> a tracker:Volume; " - " tracker:mountPoint ?u " - "} WHERE { " - " ?u a nfo:FileDataObject; " - " nie:url \"%s\" " - "} ", - removable_device_urn, removable_device_urn, uri); - - g_object_unref (file); - g_free (uri); - } - - g_string_append_printf (queries, - "DELETE { <%s> tracker:isMounted ?unknown } WHERE { <%s> a tracker:Volume; tracker:isMounted ?unknown } ", - removable_device_urn, removable_device_urn); - - if (mount_name) { - g_string_append_printf (queries, - "INSERT INTO <" TRACKER_OWN_GRAPH_URN "> { <%s> a tracker:Volume; tracker:isMounted true; nie:title \"%s\" } ", - removable_device_urn, mount_name); - } else { - g_string_append_printf (queries, - "INSERT INTO <" TRACKER_OWN_GRAPH_URN "> { <%s> a tracker:Volume; tracker:isMounted true } ", - removable_device_urn); - } - - g_string_append_printf (queries, - "INSERT { GRAPH <" TRACKER_OWN_GRAPH_URN "> { ?do tracker:available true } } WHERE { ?do nie:dataSource <%s> } ", - removable_device_urn); - } else { - gchar *now; - - g_debug ("Mount point state (UNMOUNTED) being set in DB for URN '%s'", - removable_device_urn); - - now = tracker_date_to_string (time (NULL)); - - g_string_append_printf (queries, - "DELETE { <%s> tracker:unmountDate ?unknown } WHERE { <%s> a tracker:Volume; tracker:unmountDate ?unknown } ", - removable_device_urn, removable_device_urn); - - g_string_append_printf (queries, - "INSERT INTO <" TRACKER_OWN_GRAPH_URN "> { <%s> a tracker:Volume; tracker:unmountDate \"%s\" } ", - removable_device_urn, now); - - g_string_append_printf (queries, - "DELETE { <%s> tracker:isMounted ?unknown } WHERE { <%s> a tracker:Volume; tracker:isMounted ?unknown } ", - removable_device_urn, removable_device_urn); - - g_string_append_printf (queries, - "INSERT INTO <" TRACKER_OWN_GRAPH_URN "> { <%s> a tracker:Volume; tracker:isMounted false } ", - removable_device_urn); - - g_string_append_printf (queries, - "DELETE { ?do tracker:available true } WHERE { ?do nie:dataSource <%s> } ", - removable_device_urn); - - g_free (now); - } - - if (accumulator) { - g_string_append_printf (accumulator, "%s ", queries->str); - } else { - tracker_sparql_connection_update_async (tracker_miner_get_connection (TRACKER_MINER (miner)), - queries->str, - G_PRIORITY_LOW, - NULL, - set_up_mount_point_cb, - g_strdup (removable_device_urn)); - } - - g_string_free (queries, TRUE); -} - -static void -init_mount_points_cb (GObject *source, - GAsyncResult *result, - gpointer user_data) -{ - GError *error = NULL; - - tracker_sparql_connection_update_finish (TRACKER_SPARQL_CONNECTION (source), - result, - &error); - - if (error) { - g_critical ("Could not initialize currently active mount points: %s", - error->message); - g_error_free (error); - } else { - /* Mount points correctly initialized */ - (TRACKER_MINER_FILES (user_data))->private->mount_points_initialized = TRUE; - /* If this happened AFTER we have a proper config, initialize - * stale volume removal now. */ - if ((TRACKER_MINER_FILES (user_data))->private->config) { - init_stale_volume_removal (TRACKER_MINER_FILES (user_data)); - } - } -} - -static void -init_mount_points (TrackerMinerFiles *miner_files) -{ - TrackerMiner *miner = TRACKER_MINER (miner_files); - TrackerMinerFilesPrivate *priv; - GHashTable *volumes; - GHashTableIter iter; - gpointer key, value; - GString *accumulator; - GError *error = NULL; - TrackerSparqlCursor *cursor; - GSList *uuids, *u; - - g_debug ("Initializing mount points..."); - - /* First, get all mounted volumes, according to tracker-store (SYNC!) */ - cursor = tracker_sparql_connection_query (tracker_miner_get_connection (miner), - "SELECT ?v WHERE { ?v a tracker:Volume ; tracker:isMounted true }", - NULL, &error); - if (error) { - g_critical ("Could not obtain the mounted volumes: %s", error->message); - g_error_free (error); - return; - } - - priv = TRACKER_MINER_FILES_GET_PRIVATE (miner); - - volumes = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, - NULL); - - - /* Make sure the root partition is always set to mounted, as GIO won't - * report it as a proper mount */ - g_hash_table_insert (volumes, - g_strdup (TRACKER_DATASOURCE_URN_NON_REMOVABLE_MEDIA), - GINT_TO_POINTER (VOLUME_MOUNTED)); - - while (tracker_sparql_cursor_next (cursor, NULL, NULL)) { - gint state; - const gchar *urn; - - state = VOLUME_MOUNTED_IN_STORE; - - urn = tracker_sparql_cursor_get_string (cursor, 0, NULL); - - if (!urn) - continue; - - if (strcmp (urn, TRACKER_DATASOURCE_URN_NON_REMOVABLE_MEDIA) == 0) { - /* Report non-removable media to be mounted by HAL as well */ - state |= VOLUME_MOUNTED; - } - - g_hash_table_replace (volumes, g_strdup (urn), GINT_TO_POINTER (state)); - } - - g_object_unref (cursor); - - /* Then, get all currently mounted non-REMOVABLE volumes, according to GIO */ - uuids = tracker_storage_get_device_uuids (priv->storage, 0, TRUE); - for (u = uuids; u; u = u->next) { - const gchar *uuid; - gchar *non_removable_device_urn; - gint state; - - uuid = u->data; - non_removable_device_urn = g_strdup_printf (TRACKER_PREFIX_DATASOURCE_URN "%s", uuid); - - state = GPOINTER_TO_INT (g_hash_table_lookup (volumes, non_removable_device_urn)); - state |= VOLUME_MOUNTED; - - g_hash_table_replace (volumes, non_removable_device_urn, GINT_TO_POINTER (state)); - } - - g_slist_foreach (uuids, (GFunc) g_free, NULL); - g_slist_free (uuids); - - /* Then, get all currently mounted REMOVABLE volumes, according to GIO */ - if (priv->index_removable_devices) { - uuids = tracker_storage_get_device_uuids (priv->storage, TRACKER_STORAGE_REMOVABLE, FALSE); - for (u = uuids; u; u = u->next) { - const gchar *uuid; - gchar *removable_device_urn; - gint state; - - uuid = u->data; - removable_device_urn = g_strdup_printf (TRACKER_PREFIX_DATASOURCE_URN "%s", uuid); - - state = GPOINTER_TO_INT (g_hash_table_lookup (volumes, removable_device_urn)); - state |= VOLUME_MOUNTED; - - g_hash_table_replace (volumes, removable_device_urn, GINT_TO_POINTER (state)); - } - - g_slist_foreach (uuids, (GFunc) g_free, NULL); - g_slist_free (uuids); - } - - accumulator = g_string_new (NULL); - g_hash_table_iter_init (&iter, volumes); - - /* Finally, set up volumes based on the composed info */ - while (g_hash_table_iter_next (&iter, &key, &value)) { - const gchar *urn = key; - gint state = GPOINTER_TO_INT (value); - - if ((state & VOLUME_MOUNTED) && - !(state & VOLUME_MOUNTED_IN_STORE)) { - const gchar *mount_point = NULL; - TrackerStorageType type = 0; - - /* Note: is there any case where the urn doesn't have our - * datasource prefix? */ - if (g_str_has_prefix (urn, TRACKER_PREFIX_DATASOURCE_URN)) { - const gchar *uuid; - - uuid = urn + strlen (TRACKER_PREFIX_DATASOURCE_URN); - mount_point = tracker_storage_get_mount_point_for_uuid (priv->storage, uuid); - type = tracker_storage_get_type_for_uuid (priv->storage, uuid); - } - - if (urn) { - if (mount_point) { - g_debug ("Mount point state incorrect in DB for URN '%s', " - "currently it is mounted on '%s'", - urn, - mount_point); - } else { - g_debug ("Mount point state incorrect in DB for URN '%s', " - "currently it is mounted", - urn); - } - - /* Set mount point state */ - set_up_mount_point (TRACKER_MINER_FILES (miner), - urn, - mount_point, - NULL, - TRUE, - accumulator); - - /* Set mount point type */ - set_up_mount_point_type (TRACKER_MINER_FILES (miner), - urn, - TRACKER_STORAGE_TYPE_IS_REMOVABLE (type), - TRACKER_STORAGE_TYPE_IS_OPTICAL (type), - accumulator); - - if (mount_point) { - TrackerIndexingTree *indexing_tree; - TrackerDirectoryFlags flags; - GFile *file; - - indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (miner)); - flags = TRACKER_DIRECTORY_FLAG_RECURSE | - TRACKER_DIRECTORY_FLAG_CHECK_MTIME | - TRACKER_DIRECTORY_FLAG_PRESERVE; - - if (tracker_config_get_enable_monitors (miner_files->private->config)) { - flags |= TRACKER_DIRECTORY_FLAG_MONITOR; - } - - /* Add the current mount point as reported to have incorrect - * state. We will force mtime checks on this mount points, - * even if no-mtime-check-needed was set. */ - file = g_file_new_for_path (mount_point); - if (tracker_miner_files_is_file_eligible (miner_files, file)) { - tracker_indexing_tree_add (indexing_tree, - file, - flags); - } - g_object_unref (file); - } - } - } else if (!(state & VOLUME_MOUNTED) && - (state & VOLUME_MOUNTED_IN_STORE)) { - if (urn) { - g_debug ("Mount point state incorrect in DB for URN '%s', " - "currently it is NOT mounted", - urn); - set_up_mount_point (TRACKER_MINER_FILES (miner), - urn, - NULL, - NULL, - FALSE, - accumulator); - /* There's no need to force mtime check in these inconsistent - * mount points, as they are not mounted right now. */ - } - } - } - - if (accumulator->str[0] != '\0') { - tracker_sparql_connection_update_async (tracker_miner_get_connection (miner), - accumulator->str, - G_PRIORITY_LOW, - NULL, - init_mount_points_cb, - miner); - } else { - /* Note. Not initializing stale volume removal timeout because - * we do not have the configuration setup yet */ - (TRACKER_MINER_FILES (miner))->private->mount_points_initialized = TRUE; - } - - g_string_free (accumulator, TRUE); - g_hash_table_unref (volumes); -} - -static gboolean -cleanup_stale_removable_volumes_cb (gpointer user_data) -{ - TrackerMinerFiles *miner = TRACKER_MINER_FILES (user_data); - gint n_days_threshold; - time_t n_days_ago; - gchar *n_days_ago_as_string; - - n_days_threshold = tracker_config_get_removable_days_threshold (miner->private->config); - - if (n_days_threshold == 0) - return TRUE; - - n_days_ago = (time (NULL) - (SECONDS_PER_DAY * n_days_threshold)); - n_days_ago_as_string = tracker_date_to_string (n_days_ago); - - g_message ("Running stale volumes check..."); - - miner_files_in_removable_media_remove_by_date (miner, n_days_ago_as_string); - - g_free (n_days_ago_as_string); - - return TRUE; -} - -static void -init_stale_volume_removal (TrackerMinerFiles *miner) -{ - /* If disabled, make sure we don't do anything */ - if (tracker_config_get_removable_days_threshold (miner->private->config) == 0) { - g_message ("Stale volume check is disabled"); - return; - } - - /* Run right away the first check */ - cleanup_stale_removable_volumes_cb (miner); - - g_message ("Initializing stale volume check timeout..."); - - /* Then, setup new timeout event every day */ - miner->private->stale_volumes_check_id = - g_timeout_add_seconds (SECONDS_PER_DAY + 1, - cleanup_stale_removable_volumes_cb, - miner); -} - - -static void -mount_point_removed_cb (TrackerStorage *storage, - const gchar *uuid, - const gchar *mount_point, - gpointer user_data) -{ - TrackerMinerFiles *miner = user_data; - TrackerIndexingTree *indexing_tree; - gchar *urn; - GFile *mount_point_file; - - urn = g_strdup_printf (TRACKER_PREFIX_DATASOURCE_URN "%s", uuid); - g_debug ("Mount point removed for URN '%s'", urn); - - mount_point_file = g_file_new_for_path (mount_point); - - /* Tell TrackerMinerFS to skip monitoring everything under the mount - * point (in case there was no pre-unmount notification) */ - indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (miner)); - tracker_indexing_tree_remove (indexing_tree, mount_point_file); - - /* Set mount point status in tracker-store */ - set_up_mount_point (miner, urn, mount_point, NULL, FALSE, NULL); - - g_free (urn); - g_object_unref (mount_point_file); -} - -static void -mount_point_added_cb (TrackerStorage *storage, - const gchar *uuid, - const gchar *mount_point, - const gchar *mount_name, - gboolean removable, - gboolean optical, - gpointer user_data) -{ - TrackerMinerFiles *miner = user_data; - TrackerMinerFilesPrivate *priv; - gchar *urn; - GString *queries; - - priv = TRACKER_MINER_FILES_GET_PRIVATE (miner); - - urn = g_strdup_printf (TRACKER_PREFIX_DATASOURCE_URN "%s", uuid); - g_message ("Mount point added for URN '%s'", urn); - - if (removable && !priv->index_removable_devices) { - g_message (" Not crawling, removable devices disabled in config"); - } else if (optical && !priv->index_optical_discs) { - g_message (" Not crawling, optical devices discs disabled in config"); - } else if (!removable && !optical) { - TrackerIndexingTree *indexing_tree; - TrackerDirectoryFlags flags; - GFile *mount_point_file; - GSList *l; - - mount_point_file = g_file_new_for_path (mount_point); - indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (miner)); - - /* Check if one of the recursively indexed locations is in - * the mounted path, or if the mounted path is inside - * a recursively indexed directory... */ - for (l = tracker_config_get_index_recursive_directories (miner->private->config); - l; - l = g_slist_next (l)) { - GFile *config_file; - - config_file = g_file_new_for_path (l->data); - flags = TRACKER_DIRECTORY_FLAG_RECURSE | - TRACKER_DIRECTORY_FLAG_CHECK_MTIME | - TRACKER_DIRECTORY_FLAG_PRESERVE; - - if (tracker_config_get_enable_monitors (miner->private->config)) { - flags |= TRACKER_DIRECTORY_FLAG_MONITOR; - } - - if (g_file_equal (config_file, mount_point_file) || - g_file_has_prefix (config_file, mount_point_file)) { - /* If the config path is contained inside the mount path, - * then add the config path to re-check */ - g_message (" Re-check of configured path '%s' needed (recursively)", - (gchar *) l->data); - tracker_indexing_tree_add (indexing_tree, - config_file, - flags); - } else if (g_file_has_prefix (mount_point_file, config_file)) { - /* If the mount path is contained inside the config path, - * then add the mount path to re-check */ - g_message (" Re-check of path '%s' needed (inside configured path '%s')", - mount_point, - (gchar *) l->data); - tracker_indexing_tree_add (indexing_tree, - config_file, - flags); - } - g_object_unref (config_file); - } - - /* Check if one of the non-recursively indexed locations is in - * the mount path... */ - for (l = tracker_config_get_index_single_directories (miner->private->config); - l; - l = g_slist_next (l)) { - GFile *config_file; - - flags = TRACKER_DIRECTORY_FLAG_CHECK_MTIME; - - if (tracker_config_get_enable_monitors (miner->private->config)) { - flags |= TRACKER_DIRECTORY_FLAG_MONITOR; - } - - config_file = g_file_new_for_path (l->data); - if (g_file_equal (config_file, mount_point_file) || - g_file_has_prefix (config_file, mount_point_file)) { - g_message (" Re-check of configured path '%s' needed (non-recursively)", - (gchar *) l->data); - tracker_indexing_tree_add (indexing_tree, - config_file, - flags); - } - g_object_unref (config_file); - } - - g_object_unref (mount_point_file); - } else { - g_message (" Adding directories in removable/optical media to crawler's queue"); - miner_files_add_removable_or_optical_directory (miner, - mount_point, - uuid); - } - - queries = g_string_new (""); - set_up_mount_point (miner, urn, mount_point, mount_name, TRUE, queries); - set_up_mount_point_type (miner, urn, removable, optical, queries); - tracker_sparql_connection_update_async (tracker_miner_get_connection (TRACKER_MINER (miner)), - queries->str, - G_PRIORITY_LOW, - NULL, - set_up_mount_point_cb, - g_strdup (urn)); - g_string_free (queries, TRUE); - g_free (urn); -} - -#if defined(HAVE_UPOWER) || defined(HAVE_HAL) - -static void -set_up_throttle (TrackerMinerFiles *mf, - gboolean enable) -{ - gdouble throttle; - gint config_throttle; - - config_throttle = tracker_config_get_throttle (mf->private->config); - throttle = (1.0 / 20) * config_throttle; - - if (enable) { - throttle += 0.25; - } - - throttle = CLAMP (throttle, 0, 1); - - g_debug ("Setting new throttle to %0.3f", throttle); - tracker_miner_fs_set_throttle (TRACKER_MINER_FS (mf), throttle); -} - -static void -check_battery_status (TrackerMinerFiles *mf) -{ - gboolean on_battery, on_low_battery; - gboolean should_pause = FALSE; - gboolean should_throttle = FALSE; - - on_low_battery = tracker_power_get_on_low_battery (mf->private->power); - on_battery = tracker_power_get_on_battery (mf->private->power); - - if (!on_battery) { - g_message ("Running on AC power"); - should_pause = FALSE; - should_throttle = FALSE; - } else if (on_low_battery) { - g_message ("Running on LOW Battery, pausing"); - should_pause = TRUE; - should_throttle = TRUE; - } else { - should_throttle = TRUE; - - /* Check if miner should be paused based on configuration */ - if (!tracker_config_get_index_on_battery (mf->private->config)) { - if (!tracker_config_get_index_on_battery_first_time (mf->private->config)) { - g_message ("Running on battery, but not enabled, pausing"); - should_pause = TRUE; - } else if (tracker_miner_files_get_first_index_done ()) { - g_message ("Running on battery and first-time index " - "already done, pausing"); - should_pause = TRUE; - } else { - g_message ("Running on battery, but first-time index not " - "already finished, keeping on"); - } - } else { - g_message ("Running on battery"); - } - } - - if (should_pause) { - /* Don't try to pause again */ - if (!mf->private->low_battery_pause) { - mf->private->low_battery_pause = TRUE; - tracker_miner_pause (TRACKER_MINER (mf)); - } - } else { - /* Don't try to resume again */ - if (mf->private->low_battery_pause) { - tracker_miner_resume (TRACKER_MINER (mf)); - mf->private->low_battery_pause = FALSE; - } - } - - set_up_throttle (mf, should_throttle); -} - -/* Called when battery status change is detected */ -static void -battery_status_cb (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - TrackerMinerFiles *mf = user_data; - - check_battery_status (mf); -} - -/* Called when battery-related configuration change is detected */ -static void -index_on_battery_cb (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - TrackerMinerFiles *mf = user_data; - - check_battery_status (mf); -} - -#endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */ - -/* Called when mining has finished the first time */ -static void -miner_finished_cb (TrackerMinerFS *fs, - gdouble seconds_elapsed, - guint total_directories_found, - guint total_directories_ignored, - guint total_files_found, - guint total_files_ignored, - gpointer user_data) -{ - TrackerMinerFiles *mf = TRACKER_MINER_FILES (fs); - - /* Create stamp file if not already there */ - if (!tracker_miner_files_get_first_index_done ()) { - tracker_miner_files_set_first_index_done (TRUE); - } - - /* And remove the signal handler so that it's not - * called again */ - if (mf->private->finished_handler) { - g_signal_handler_disconnect (fs, mf->private->finished_handler); - mf->private->finished_handler = 0; - } - -#if defined(HAVE_UPOWER) || defined(HAVE_HAL) - check_battery_status (mf); -#endif /* defined(HAVE_UPOWER) || defined(HAVE_HAL) */ -} - -static void -mount_pre_unmount_cb (GVolumeMonitor *volume_monitor, - GMount *mount, - TrackerMinerFiles *mf) -{ - TrackerIndexingTree *indexing_tree; - GFile *mount_root; - gchar *uri; - - mount_root = g_mount_get_root (mount); - uri = g_file_get_uri (mount_root); - g_message ("Pre-unmount requested for '%s'", uri); - - indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (mf)); - tracker_indexing_tree_remove (indexing_tree, mount_root); - g_object_unref (mount_root); - - g_free (uri); -} - -static gboolean -disk_space_check (TrackerMinerFiles *mf) -{ - gint limit; - gchar *data_dir; - gdouble remaining; - - limit = tracker_config_get_low_disk_space_limit (mf->private->config); - - if (limit < 1) { - return FALSE; - } - - /* Get % of remaining space in the partition where the cache is */ - data_dir = g_build_filename (g_get_user_cache_dir (), "tracker", NULL); - remaining = tracker_file_system_get_remaining_space_percentage (data_dir); - g_free (data_dir); - - if (remaining <= limit) { - g_message ("WARNING: Available disk space (%lf%%) is below " - "configured threshold for acceptable working (%d%%)", - remaining, limit); - return TRUE; - } - - return FALSE; -} - -static gboolean -disk_space_check_cb (gpointer user_data) -{ - TrackerMinerFiles *mf = user_data; - - if (disk_space_check (mf)) { - /* Don't try to pause again */ - if (!mf->private->disk_space_pause) { - mf->private->disk_space_pause = TRUE; - tracker_miner_pause (TRACKER_MINER (mf)); - } - } else { - /* Don't try to resume again */ - if (mf->private->disk_space_pause) { - tracker_miner_resume (TRACKER_MINER (mf)); - mf->private->disk_space_pause = FALSE; - } - } - - return TRUE; -} - -static void -disk_space_check_start (TrackerMinerFiles *mf) -{ - gint limit; - - if (mf->private->disk_space_check_id != 0) { - return; - } - - limit = tracker_config_get_low_disk_space_limit (mf->private->config); - - if (limit != -1) { - g_message ("Starting disk space check for every %d seconds", - DISK_SPACE_CHECK_FREQUENCY); - mf->private->disk_space_check_id = - g_timeout_add_seconds (DISK_SPACE_CHECK_FREQUENCY, - disk_space_check_cb, - mf); - - /* Call the function now too to make sure we have an - * initial value too! - */ - disk_space_check_cb (mf); - } else { - g_message ("Not setting disk space, configuration is set to -1 (disabled)"); - } -} - -static void -disk_space_check_stop (TrackerMinerFiles *mf) -{ - if (mf->private->disk_space_check_id) { - g_message ("Stopping disk space check"); - g_source_remove (mf->private->disk_space_check_id); - mf->private->disk_space_check_id = 0; - } -} - -static void -low_disk_space_limit_cb (GObject *gobject, - GParamSpec *arg1, - gpointer user_data) -{ - TrackerMinerFiles *mf = user_data; - - disk_space_check_cb (mf); -} - -static void -indexing_tree_update_filter (TrackerIndexingTree *indexing_tree, - TrackerFilterType filter, - GSList *new_elems) -{ - tracker_indexing_tree_clear_filters (indexing_tree, filter); - - while (new_elems) { - tracker_indexing_tree_add_filter (indexing_tree, filter, - new_elems->data); - new_elems = new_elems->next; - } -} - -static void -miner_files_update_filters (TrackerMinerFiles *files) -{ - TrackerIndexingTree *indexing_tree; - GSList *list; - - indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (files)); - - /* Ignored files */ - list = tracker_config_get_ignored_files (files->private->config); - indexing_tree_update_filter (indexing_tree, TRACKER_FILTER_FILE, list); - - /* Ignored directories */ - list = tracker_config_get_ignored_directories (files->private->config); - indexing_tree_update_filter (indexing_tree, - TRACKER_FILTER_DIRECTORY, - list); - - /* Directories with content */ - list = tracker_config_get_ignored_directories_with_content (files->private->config); - indexing_tree_update_filter (indexing_tree, - TRACKER_FILTER_PARENT_DIRECTORY, - list); -} - -static void -update_directories_from_new_config (TrackerMinerFS *mf, - GSList *new_dirs, - GSList *old_dirs, - gboolean recurse) -{ - TrackerMinerFilesPrivate *priv; - TrackerDirectoryFlags flags = 0; - TrackerIndexingTree *indexing_tree; - GSList *sl; - - priv = TRACKER_MINER_FILES_GET_PRIVATE (mf); - indexing_tree = tracker_miner_fs_get_indexing_tree (mf); - - g_message ("Updating %s directories changed from configuration", - recurse ? "recursive" : "single"); - - /* First remove all directories removed from the config */ - for (sl = old_dirs; sl; sl = sl->next) { - const gchar *path; - - path = sl->data; - - /* If we are not still in the list, remove the dir */ - if (!tracker_string_in_gslist (path, new_dirs)) { - GFile *file; - - g_message (" Removing directory: '%s'", path); - - file = g_file_new_for_path (path); - - /* First, remove the preserve flag, it might be - * set on configuration directories within mount - * points, as data should be persistent across - * unmounts. - */ - tracker_indexing_tree_get_root (indexing_tree, - file, &flags); - - if ((flags & TRACKER_DIRECTORY_FLAG_PRESERVE) != 0) { - flags &= ~(TRACKER_DIRECTORY_FLAG_PRESERVE); - tracker_indexing_tree_add (indexing_tree, - file, flags); - } - - /* Fully remove item (monitors and from store), - * now that there's no preserve flag. - */ - tracker_indexing_tree_remove (indexing_tree, file); - g_object_unref (file); - } - } - - flags = TRACKER_DIRECTORY_FLAG_NONE; - - if (recurse) { - flags |= TRACKER_DIRECTORY_FLAG_RECURSE; - } - - if (tracker_config_get_enable_monitors (priv->config)) { - flags |= TRACKER_DIRECTORY_FLAG_MONITOR; - } - - if (priv->mtime_check) { - flags |= TRACKER_DIRECTORY_FLAG_CHECK_MTIME; - } - - /* Second add directories which are new */ - for (sl = new_dirs; sl; sl = sl->next) { - const gchar *path; - - path = sl->data; - - /* If we are now in the list, add the dir */ - if (!tracker_string_in_gslist (path, old_dirs)) { - GFile *file; - - g_message (" Adding directory:'%s'", path); - - file = g_file_new_for_path (path); - tracker_indexing_tree_add (indexing_tree, file, flags); - g_object_unref (file); - } - } -} - -static void -index_recursive_directories_cb (GObject *gobject, - GParamSpec *arg1, - gpointer user_data) -{ - TrackerMinerFilesPrivate *private; - GSList *new_dirs, *old_dirs; - - private = TRACKER_MINER_FILES_GET_PRIVATE (user_data); - - new_dirs = tracker_config_get_index_recursive_directories (private->config); - old_dirs = private->index_recursive_directories; - - update_directories_from_new_config (TRACKER_MINER_FS (user_data), - new_dirs, - old_dirs, - TRUE); - - /* Re-set the stored config in case it changes again */ - if (private->index_recursive_directories) { - g_slist_foreach (private->index_recursive_directories, (GFunc) g_free, NULL); - g_slist_free (private->index_recursive_directories); - } - - private->index_recursive_directories = tracker_gslist_copy_with_string_data (new_dirs); -} - -static void -index_single_directories_cb (GObject *gobject, - GParamSpec *arg1, - gpointer user_data) -{ - TrackerMinerFilesPrivate *private; - GSList *new_dirs, *old_dirs; - - private = TRACKER_MINER_FILES_GET_PRIVATE (user_data); - - new_dirs = tracker_config_get_index_single_directories (private->config); - old_dirs = private->index_single_directories; - - update_directories_from_new_config (TRACKER_MINER_FS (user_data), - new_dirs, - old_dirs, - FALSE); - - /* Re-set the stored config in case it changes again */ - if (private->index_single_directories) { - g_slist_foreach (private->index_single_directories, (GFunc) g_free, NULL); - g_slist_free (private->index_single_directories); - } - - private->index_single_directories = tracker_gslist_copy_with_string_data (new_dirs); -} - -static gboolean -miner_files_force_recheck_idle (gpointer user_data) -{ - TrackerMinerFiles *miner_files = user_data; - TrackerIndexingTree *indexing_tree; - GList *roots, *l; - - miner_files_update_filters (miner_files); - - indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (miner_files)); - roots = tracker_indexing_tree_list_roots (indexing_tree); - - for (l = roots; l; l = l->next) { - GFile *root = l->data; - - tracker_indexing_tree_notify_update (indexing_tree, root, FALSE); - } - - miner_files->private->force_recheck_id = 0; - g_list_free (roots); - - return FALSE; -} - -static void -trigger_recheck_cb (GObject *gobject, - GParamSpec *arg1, - gpointer user_data) -{ - TrackerMinerFiles *mf = user_data; - - g_message ("Ignored content related configuration changed, checking index..."); - - if (mf->private->force_recheck_id == 0) { - /* Set idle so multiple changes in the config lead to one recheck */ - mf->private->force_recheck_id = - g_idle_add (miner_files_force_recheck_idle, mf); - } -} - -static gboolean -index_volumes_changed_idle (gpointer user_data) -{ - TrackerMinerFiles *mf = user_data; - GSList *mounts_removed = NULL; - GSList *mounts_added = NULL; - gboolean new_index_removable_devices; - gboolean new_index_optical_discs; - - g_message ("Volume related configuration changed, updating..."); - - /* Read new config values. Note that if removable devices is FALSE, - * optical discs will also always be FALSE. */ - new_index_removable_devices = tracker_config_get_index_removable_devices (mf->private->config); - new_index_optical_discs = (new_index_removable_devices ? - tracker_config_get_index_optical_discs (mf->private->config) : - FALSE); - - /* Removable devices config changed? */ - if (mf->private->index_removable_devices != new_index_removable_devices) { - GSList *m; - - /* Get list of roots for currently mounted removable devices - * (excluding optical) */ - m = tracker_storage_get_device_roots (mf->private->storage, - TRACKER_STORAGE_REMOVABLE, - TRUE); - /* Set new config value */ - mf->private->index_removable_devices = new_index_removable_devices; - - if (mf->private->index_removable_devices) { - /* If previously not indexing and now indexing, need to re-check - * current mounted volumes, add new monitors and index new files - */ - mounts_added = m; - } else { - /* If previously indexing and now not indexing, need to re-check - * current mounted volumes, remove monitors and remove all resources - * from the store belonging to a removable device - */ - mounts_removed = m; - - /* And now, single sparql update to remove all resources - * corresponding to removable devices (includes those - * not currently mounted) */ - miner_files_in_removable_media_remove_by_type (mf, TRACKER_STORAGE_REMOVABLE); - } - } - - /* Optical discs config changed? */ - if (mf->private->index_optical_discs != new_index_optical_discs) { - GSList *m; - - /* Get list of roots for removable devices (excluding optical) */ - m = tracker_storage_get_device_roots (mf->private->storage, - TRACKER_STORAGE_REMOVABLE | TRACKER_STORAGE_OPTICAL, - TRUE); - - /* Set new config value */ - mf->private->index_optical_discs = new_index_optical_discs; - - if (mf->private->index_optical_discs) { - /* If previously not indexing and now indexing, need to re-check - * current mounted volumes, add new monitors and index new files - */ - mounts_added = g_slist_concat (mounts_added, m); - } else { - /* If previously indexing and now not indexing, need to re-check - * current mounted volumes, remove monitors and remove all resources - * from the store belonging to a optical disc - */ - mounts_removed = g_slist_concat (mounts_removed, m); - - /* And now, single sparql update to remove all resources - * corresponding to removable+optical devices (includes those - * not currently mounted) */ - miner_files_in_removable_media_remove_by_type (mf, TRACKER_STORAGE_REMOVABLE | TRACKER_STORAGE_OPTICAL); - } - } - - /* Tell TrackerMinerFS to stop monitoring the given removed mount paths, if any */ - if (mounts_removed) { - TrackerIndexingTree *indexing_tree; - GSList *sl; - - indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (mf)); - - for (sl = mounts_removed; sl; sl = g_slist_next (sl)) { - GFile *mount_point_file; - - mount_point_file = g_file_new_for_path (sl->data); - tracker_indexing_tree_remove (indexing_tree, - mount_point_file); - g_object_unref (mount_point_file); - } - - g_slist_foreach (mounts_removed, (GFunc) g_free, NULL); - g_slist_free (mounts_removed); - } - - /* Tell TrackerMinerFS to start monitoring the given added mount paths, if any */ - if (mounts_added) { - GSList *sl; - - for (sl = mounts_added; sl; sl = g_slist_next (sl)) { - miner_files_add_removable_or_optical_directory (mf, - (gchar *) sl->data, - NULL); - } - - g_slist_foreach (mounts_added, (GFunc) g_free, NULL); - g_slist_free (mounts_added); - } - - mf->private->volumes_changed_id = 0; - - /* Check if the stale volume removal configuration changed from enabled to disabled - * or from disabled to enabled */ - if (tracker_config_get_removable_days_threshold (mf->private->config) == 0 && - mf->private->stale_volumes_check_id != 0) { - /* From having the check enabled to having it disabled, remove the timeout */ - g_debug (" Stale volume removal now disabled, removing timeout"); - g_source_remove (mf->private->stale_volumes_check_id); - mf->private->stale_volumes_check_id = 0; - } else if (tracker_config_get_removable_days_threshold (mf->private->config) > 0 && - mf->private->stale_volumes_check_id == 0) { - g_debug (" Stale volume removal now enabled, initializing timeout"); - /* From having the check disabled to having it enabled, so fire up the - * timeout. */ - init_stale_volume_removal (TRACKER_MINER_FILES (mf)); - } - - return FALSE; -} - -static void -index_volumes_changed_cb (GObject *gobject, - GParamSpec *arg1, - gpointer user_data) -{ - TrackerMinerFiles *miner_files = user_data; - - if (miner_files->private->volumes_changed_id == 0) { - /* Set idle so multiple changes in the config lead to one check */ - miner_files->private->volumes_changed_id = - g_idle_add (index_volumes_changed_idle, miner_files); - } -} - -static const gchar * -miner_files_get_file_urn (TrackerMinerFiles *miner, - GFile *file, - gboolean *is_iri) -{ - const gchar *urn; - - urn = tracker_miner_fs_get_urn (TRACKER_MINER_FS (miner), file); - *is_iri = TRUE; - - if (!urn) { - /* This is a new insertion, use anonymous URNs to store files */ - urn = "_:file"; - *is_iri = FALSE; - } - - return urn; -} - -static void -miner_files_add_to_datasource (TrackerMinerFiles *mf, - GFile *file, - TrackerSparqlBuilder *sparql) -{ - TrackerMinerFilesPrivate *priv; - const gchar *removable_device_uuid; - gchar *removable_device_urn, *uri; - const gchar *urn; - gboolean is_iri; - - priv = TRACKER_MINER_FILES_GET_PRIVATE (mf); - uri = g_file_get_uri (file); - - removable_device_uuid = tracker_storage_get_uuid_for_file (priv->storage, file); - - if (removable_device_uuid) { - removable_device_urn = g_strdup_printf (TRACKER_PREFIX_DATASOURCE_URN "%s", - removable_device_uuid); - } else { - removable_device_urn = g_strdup (TRACKER_DATASOURCE_URN_NON_REMOVABLE_MEDIA); - } - - urn = miner_files_get_file_urn (mf, file, &is_iri); - - if (is_iri) { - tracker_sparql_builder_subject_iri (sparql, urn); - } else { - tracker_sparql_builder_subject (sparql, urn); - } - - tracker_sparql_builder_predicate (sparql, "a"); - tracker_sparql_builder_object (sparql, "nfo:FileDataObject"); - - tracker_sparql_builder_predicate (sparql, "nie:dataSource"); - tracker_sparql_builder_object_iri (sparql, removable_device_urn); - - tracker_sparql_builder_predicate (sparql, "tracker:available"); - tracker_sparql_builder_object_boolean (sparql, TRUE); - - g_free (removable_device_urn); - g_free (uri); -} - -static void -miner_files_add_rdf_types (TrackerSparqlBuilder *sparql, - GFile *file, - const gchar *mime_type) -{ - GStrv rdf_types; - gint i = 0; - - rdf_types = tracker_extract_module_manager_get_fallback_rdf_types (mime_type); - - if (!rdf_types) - return; - - if (rdf_types[0]) { - tracker_sparql_builder_predicate (sparql, "a"); - - while (rdf_types[i]) { - tracker_sparql_builder_object (sparql, rdf_types[i]); - i++; - } - } - - g_strfreev (rdf_types); -} - -static void -process_file_data_free (ProcessFileData *data) -{ - g_object_unref (data->miner); - g_object_unref (data->sparql); - g_object_unref (data->cancellable); - g_object_unref (data->file); - g_object_unref (data->task); - g_free (data->mime_type); - g_slice_free (ProcessFileData, data); -} - -static void -sparql_builder_finish (ProcessFileData *data, - const gchar *preupdate, - const gchar *postupdate, - const gchar *sparql, - const gchar *where) -{ - const gchar *uuid; - - if (sparql && *sparql) { - gboolean is_iri; - const gchar *urn; - - urn = miner_files_get_file_urn (data->miner, data->file, &is_iri); - - if (is_iri) { - gchar *str; - - str = g_strdup_printf ("<%s>", urn); - tracker_sparql_builder_append (data->sparql, str); - g_free (str); - } else { - tracker_sparql_builder_append (data->sparql, urn); - } - - tracker_sparql_builder_append (data->sparql, sparql); - } - - tracker_sparql_builder_graph_close (data->sparql); - tracker_sparql_builder_insert_close (data->sparql); - - if (where && *where) { - tracker_sparql_builder_where_open (data->sparql); - tracker_sparql_builder_append (data->sparql, where); - tracker_sparql_builder_where_close (data->sparql); - } - - /* Prepend preupdate queries */ - if (preupdate && *preupdate) { - tracker_sparql_builder_prepend (data->sparql, preupdate); - } - - /* Append postupdate */ - if (postupdate && *postupdate) { - tracker_sparql_builder_append (data->sparql, postupdate); - } - - uuid = g_object_get_qdata (G_OBJECT (data->file), - data->miner->private->quark_mount_point_uuid); - - /* File represents a mount point */ - if (G_UNLIKELY (uuid)) { - GString *queries; - gchar *removable_device_urn, *uri; - - removable_device_urn = g_strdup_printf (TRACKER_PREFIX_DATASOURCE_URN "%s", uuid); - uri = g_file_get_uri (G_FILE (data->file)); - queries = g_string_new (""); - - g_string_append_printf (queries, - "DELETE { " - " <%s> tracker:mountPoint ?unknown " - "} WHERE { " - " <%s> a tracker:Volume; " - " tracker:mountPoint ?unknown " - "} ", - removable_device_urn, removable_device_urn); - - g_string_append_printf (queries, - "INSERT { GRAPH <%s> {" - " <%s> a tracker:Volume; " - " tracker:mountPoint ?u " - "} } WHERE { " - " ?u a nfo:FileDataObject; " - " nie:url \"%s\" " - "} ", - removable_device_urn, removable_device_urn, uri); - - tracker_sparql_builder_append (data->sparql, queries->str); - g_string_free (queries, TRUE); - g_free (removable_device_urn); - g_free (uri); - } -} - -static void -process_file_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - TrackerMinerFilesPrivate *priv; - TrackerSparqlBuilder *sparql; - ProcessFileData *data; - const gchar *mime_type, *urn, *parent_urn; - GFileInfo *file_info; - guint64 time_; - GFile *file, *parent; - gchar *uri; - GError *error = NULL; - gboolean is_iri; - gboolean is_directory; - - data = user_data; - file = G_FILE (object); - sparql = data->sparql; - file_info = g_file_query_info_finish (file, result, &error); - priv = TRACKER_MINER_FILES (data->miner)->private; - - if (error) { - /* Something bad happened, notify about the error */ - tracker_miner_fs_notify_finish (TRACKER_MINER_FS (data->miner), data->task, NULL, error); - priv->extraction_queue = g_list_remove (priv->extraction_queue, data); - process_file_data_free (data); - return; - } - - uri = g_file_get_uri (file); - mime_type = g_file_info_get_content_type (file_info); - urn = miner_files_get_file_urn (TRACKER_MINER_FILES (data->miner), file, &is_iri); - - data->mime_type = g_strdup (mime_type); - - if (is_iri) { - gchar *delete_properties_sparql; - - /* Update: delete all statements inserted by miner except: - * - rdf:type statements as they could cause implicit deletion of user data - * - nie:contentCreated so it persists across updates - * - * Additionally, delete also nie:url as it might have been set by 3rd parties, - * and it's used to know whether a file is known to tracker or not. - */ - delete_properties_sparql = - g_strdup_printf ("DELETE {" - " GRAPH <%s> {" - " <%s> ?p ?o" - " } " - "} " - "WHERE {" - " GRAPH <%s> {" - " <%s> ?p ?o" - " FILTER (?p != rdf:type && ?p != nie:contentCreated)" - " } " - "} " - "DELETE {" - " <%s> nie:url ?o" - "} WHERE {" - " <%s> nie:url ?o" - "}", - TRACKER_OWN_GRAPH_URN, urn, - TRACKER_OWN_GRAPH_URN, urn, - urn, urn); - - tracker_sparql_builder_prepend (sparql, delete_properties_sparql); - g_free (delete_properties_sparql); - } - - tracker_sparql_builder_insert_silent_open (sparql, NULL); - tracker_sparql_builder_graph_open (sparql, TRACKER_OWN_GRAPH_URN); - - if (is_iri) { - tracker_sparql_builder_subject_iri (sparql, urn); - } else { - tracker_sparql_builder_subject (sparql, urn); - } - - tracker_sparql_builder_predicate (sparql, "a"); - tracker_sparql_builder_object (sparql, "nfo:FileDataObject"); - tracker_sparql_builder_object (sparql, "nie:InformationElement"); - - is_directory = (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY ? - TRUE : FALSE); - if (is_directory) { - tracker_sparql_builder_object (sparql, "nfo:Folder"); - } - - parent = g_file_get_parent (file); - parent_urn = tracker_miner_fs_query_urn (TRACKER_MINER_FS (data->miner), parent); - g_object_unref (parent); - - if (parent_urn) { - tracker_sparql_builder_predicate (sparql, "nfo:belongsToContainer"); - tracker_sparql_builder_object_iri (sparql, parent_urn); - } - - tracker_sparql_builder_predicate (sparql, "nfo:fileName"); - tracker_sparql_builder_object_string (sparql, g_file_info_get_display_name (file_info)); - - tracker_sparql_builder_predicate (sparql, "nfo:fileSize"); - tracker_sparql_builder_object_int64 (sparql, g_file_info_get_size (file_info)); - - time_ = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_MODIFIED); - tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified"); - tracker_sparql_builder_object_date (sparql, (time_t *) &time_); - - time_ = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_ACCESS); - tracker_sparql_builder_predicate (sparql, "nfo:fileLastAccessed"); - tracker_sparql_builder_object_date (sparql, (time_t *) &time_); - - /* Laying the link between the IE and the DO. We use IE = DO */ - tracker_sparql_builder_predicate (sparql, "nie:isStoredAs"); - if (is_iri) { - tracker_sparql_builder_object_iri (sparql, urn); - } else { - tracker_sparql_builder_object (sparql, urn); - } - - /* The URL of the DataObject (because IE = DO, this is correct) */ - tracker_sparql_builder_predicate (sparql, "nie:url"); - tracker_sparql_builder_object_string (sparql, uri); - - tracker_sparql_builder_predicate (sparql, "nie:mimeType"); - tracker_sparql_builder_object_string (sparql, mime_type); - - miner_files_add_to_datasource (data->miner, file, sparql); - - miner_files_add_rdf_types (sparql, file, mime_type); - - sparql_builder_finish (data, NULL, NULL, NULL, NULL); - tracker_miner_fs_notify_finish (TRACKER_MINER_FS (data->miner), data->task, - tracker_sparql_builder_get_result (sparql), - NULL); - - priv->extraction_queue = g_list_remove (priv->extraction_queue, data); - process_file_data_free (data); - - g_object_unref (file_info); - g_free (uri); -} - -static gboolean -miner_files_process_file (TrackerMinerFS *fs, - GFile *file, - GTask *task) -{ - TrackerMinerFilesPrivate *priv; - ProcessFileData *data; - const gchar *attrs; - - data = g_slice_new0 (ProcessFileData); - data->miner = g_object_ref (fs); - data->cancellable = g_object_ref (g_task_get_cancellable (task)); - data->sparql = tracker_sparql_builder_new_update (); - data->file = g_object_ref (file); - data->task = g_object_ref (task); - - priv = TRACKER_MINER_FILES (fs)->private; - priv->extraction_queue = g_list_prepend (priv->extraction_queue, data); - - attrs = G_FILE_ATTRIBUTE_STANDARD_TYPE "," - G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," - G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," - G_FILE_ATTRIBUTE_STANDARD_SIZE "," - G_FILE_ATTRIBUTE_TIME_MODIFIED "," - G_FILE_ATTRIBUTE_TIME_ACCESS; - - g_file_query_info_async (file, - attrs, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - G_PRIORITY_DEFAULT, - data->cancellable, - process_file_cb, - data); - - return TRUE; -} - -static void -process_file_attributes_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - TrackerSparqlBuilder *sparql; - ProcessFileData *data; - const gchar *urn; - GFileInfo *file_info; - guint64 time_; - GFile *file; - gchar *uri; - GError *error = NULL; - gboolean is_iri; - - data = user_data; - file = G_FILE (object); - sparql = data->sparql; - file_info = g_file_query_info_finish (file, result, &error); - - if (error) { - /* Something bad happened, notify about the error */ - tracker_miner_fs_notify_finish (TRACKER_MINER_FS (data->miner), data->task, NULL, error); - process_file_data_free (data); - return; - } - - uri = g_file_get_uri (file); - urn = miner_files_get_file_urn (TRACKER_MINER_FILES (data->miner), file, &is_iri); - - /* We MUST have an IRI in attributes updating */ - if (!is_iri) { - error = g_error_new_literal (miner_files_error_quark, - 0, - "Received request to update attributes but no IRI available!"); - /* Notify about the error */ - tracker_miner_fs_notify_finish (TRACKER_MINER_FS (data->miner), data->task, NULL, error); - process_file_data_free (data); - return; - } - - /* Update nfo:fileLastModified */ - tracker_sparql_builder_delete_open (sparql, NULL); - tracker_sparql_builder_subject_iri (sparql, urn); - tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified"); - tracker_sparql_builder_object_variable (sparql, "lastmodified"); - tracker_sparql_builder_delete_close (sparql); - tracker_sparql_builder_where_open (sparql); - tracker_sparql_builder_subject_iri (sparql, urn); - tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified"); - tracker_sparql_builder_object_variable (sparql, "lastmodified"); - tracker_sparql_builder_where_close (sparql); - tracker_sparql_builder_insert_open (sparql, NULL); - tracker_sparql_builder_graph_open (sparql, TRACKER_OWN_GRAPH_URN); - tracker_sparql_builder_subject_iri (sparql, urn); - time_ = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_MODIFIED); - tracker_sparql_builder_predicate (sparql, "nfo:fileLastModified"); - tracker_sparql_builder_object_date (sparql, (time_t *) &time_); - tracker_sparql_builder_graph_close (sparql); - tracker_sparql_builder_insert_close (sparql); - - /* Update nfo:fileLastAccessed */ - tracker_sparql_builder_delete_open (sparql, NULL); - tracker_sparql_builder_subject_iri (sparql, urn); - tracker_sparql_builder_predicate (sparql, "nfo:fileLastAccessed"); - tracker_sparql_builder_object_variable (sparql, "lastaccessed"); - tracker_sparql_builder_delete_close (sparql); - tracker_sparql_builder_where_open (sparql); - tracker_sparql_builder_subject_iri (sparql, urn); - tracker_sparql_builder_predicate (sparql, "nfo:fileLastAccessed"); - tracker_sparql_builder_object_variable (sparql, "lastaccessed"); - tracker_sparql_builder_where_close (sparql); - tracker_sparql_builder_insert_open (sparql, NULL); - tracker_sparql_builder_graph_open (sparql, TRACKER_OWN_GRAPH_URN); - tracker_sparql_builder_subject_iri (sparql, urn); - time_ = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_ACCESS); - tracker_sparql_builder_predicate (sparql, "nfo:fileLastAccessed"); - tracker_sparql_builder_object_date (sparql, (time_t *) &time_); - tracker_sparql_builder_graph_close (sparql); - tracker_sparql_builder_insert_close (sparql); - - /* Delete data sources from other miners/decorators */ - tracker_sparql_builder_delete_open (sparql, NULL); - tracker_sparql_builder_subject_iri (sparql, urn); - tracker_sparql_builder_predicate (sparql, "nie:dataSource"); - tracker_sparql_builder_object_variable (sparql, "datasource"); - tracker_sparql_builder_delete_close (sparql); - tracker_sparql_builder_where_open (sparql); - tracker_sparql_builder_subject_iri (sparql, urn); - tracker_sparql_builder_predicate (sparql, "nie:dataSource"); - tracker_sparql_builder_object_variable (sparql, "datasource"); - tracker_sparql_builder_where_close (sparql); - - g_object_unref (file_info); - g_free (uri); - - /* Notify about the success */ - tracker_miner_fs_notify_finish (TRACKER_MINER_FS (data->miner), data->task, - tracker_sparql_builder_get_result (sparql), - NULL); - - process_file_data_free (data); -} - -static gboolean -miner_files_process_file_attributes (TrackerMinerFS *fs, - GFile *file, - GTask *task) -{ - ProcessFileData *data; - const gchar *attrs; - - data = g_slice_new0 (ProcessFileData); - data->miner = g_object_ref (fs); - data->cancellable = g_object_ref (g_task_get_cancellable (task)); - data->sparql = tracker_sparql_builder_new_update (); - data->file = g_object_ref (file); - data->task = g_object_ref (task); - - /* Query only attributes that may change in an ATTRIBUTES_UPDATED event */ - attrs = G_FILE_ATTRIBUTE_TIME_MODIFIED "," - G_FILE_ATTRIBUTE_TIME_ACCESS; - - g_file_query_info_async (file, - attrs, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - G_PRIORITY_DEFAULT, - data->cancellable, - process_file_attributes_cb, - data); - - return TRUE; -} - -static void -miner_files_finished (TrackerMinerFS *fs, - gdouble elapsed, - gint directories_found, - gint directories_ignored, - gint files_found, - gint files_ignored) -{ - TrackerMinerFilesPrivate *priv = TRACKER_MINER_FILES (fs)->private; - - if (priv->thumbnailer) - tracker_thumbnailer_send (priv->thumbnailer); - - tracker_miner_files_set_last_crawl_done (TRUE); -} - -static gchar * -create_delete_sparql (GFile *file, - gboolean delete_self, - gboolean delete_children) -{ - GString *sparql; - gchar *uri; - - g_return_val_if_fail (delete_self || delete_children, NULL); - - uri = g_file_get_uri (file); - sparql = g_string_new ("DELETE {" - " ?f a rdfs:Resource . " - " ?ie a rdfs:Resource " - "} WHERE {" - " ?f a rdfs:Resource ; " - " nie:url ?u . " - " ?ie nie:isStoredAs ?f . " - " FILTER ("); - - if (delete_self) - g_string_append_printf (sparql, "?u = \"%s\" ", uri); - - if (delete_children) { - if (delete_self) - g_string_append (sparql, " || "); - - g_string_append_printf (sparql, "STRSTARTS (?u, \"%s/\")", uri); - } - - g_string_append (sparql, ")}"); - g_free (uri); - - return g_string_free (sparql, FALSE); -} - -static gchar * -miner_files_remove_children (TrackerMinerFS *fs, - GFile *file) -{ - return create_delete_sparql (file, FALSE, TRUE); -} - -static gchar * -miner_files_remove_file (TrackerMinerFS *fs, - GFile *file) -{ - TrackerMinerFilesPrivate *priv = TRACKER_MINER_FILES (fs)->private; - - if (priv->thumbnailer) { - gchar *uri; - - uri = g_file_get_uri (file); - tracker_thumbnailer_remove_add (priv->thumbnailer, uri, NULL); - g_free (uri); - } - - return create_delete_sparql (file, TRUE, TRUE); -} - -static void -move_thumbnails_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - ThumbnailMoveData *data = user_data; - TrackerMinerFilesPrivate *priv = TRACKER_MINER_FILES (data->miner)->private; - GError *error = NULL; - - TrackerSparqlCursor *cursor = tracker_sparql_connection_query_finish (TRACKER_SPARQL_CONNECTION (object), result, &error); - - if (error) { - g_critical ("Could move thumbnails: %s", error->message); - g_error_free (error); - } else { - while (tracker_sparql_cursor_next (cursor, NULL, NULL)) { - const gchar *src, *dst, *mimetype; - - src = tracker_sparql_cursor_get_string (cursor, 0, NULL); - dst = tracker_sparql_cursor_get_string (cursor, 1, NULL); - mimetype = tracker_sparql_cursor_get_string (cursor, 2, NULL); - - if (priv->thumbnailer) { - tracker_thumbnailer_move_add (priv->thumbnailer, - src, mimetype, dst); - } - } - } - - g_object_unref (cursor); - g_main_loop_quit (data->main_loop); -} - -static gchar * -miner_files_move_file (TrackerMinerFS *fs, - GFile *file, - GFile *source_file, - gboolean recursive) -{ - TrackerMinerFilesPrivate *priv = TRACKER_MINER_FILES (fs)->private; - GString *sparql = g_string_new (NULL); - const gchar *new_parent_iri; - gchar *uri, *source_uri, *display_name; - gchar *source_iri; - gchar *path, *basename; - GFile *new_parent; - - uri = g_file_get_uri (file); - source_uri = g_file_get_uri (source_file); - source_iri = tracker_miner_fs_query_urn (fs, source_file); - - if (priv->thumbnailer) { - GFileInfo *file_info; - - file_info = g_file_query_info (file, - G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - NULL, NULL); - tracker_thumbnailer_move_add (priv->thumbnailer, source_uri, - g_file_info_get_content_type (file_info), - uri); - g_object_unref (file_info); - - if (recursive) { - ThumbnailMoveData move_data; - gchar *query; - - g_debug ("Moving thumbnails within '%s'", uri); - - /* Push all moved files to thumbnailer */ - move_data.main_loop = g_main_loop_new (NULL, FALSE); - move_data.miner = TRACKER_MINER (fs); - - query = g_strdup_printf ("SELECT ?url ?new_url nie:mimeType(?u) {" - " ?u a rdfs:Resource ;" - " nie:url ?url ." - " BIND (CONCAT (\"%s/\", SUBSTR (?url, STRLEN (\"%s/\") + 1)) AS ?new_url) ." - " FILTER (STRSTARTS (?url, \"%s/\"))" - "}", - uri, source_uri, source_uri); - - tracker_sparql_connection_query_async (tracker_miner_get_connection (TRACKER_MINER (fs)), - query, - NULL, - move_thumbnails_cb, - &move_data); - - g_main_loop_run (move_data.main_loop); - g_main_loop_unref (move_data.main_loop); - g_free (query); - } - } - - path = g_file_get_path (file); - basename = g_filename_display_basename (path); - display_name = tracker_sparql_escape_string (basename); - g_free (basename); - g_free (path); - - g_string_append_printf (sparql, - "DELETE { " - " <%s> nfo:fileName ?f ; " - " nie:url ?u ; " - " nie:isStoredAs ?s ; " - " nfo:belongsToContainer ?b" - "} WHERE { " - " <%s> nfo:fileName ?f ; " - " nie:url ?u ; " - " nie:isStoredAs ?s . " - " OPTIONAL { <%s> nfo:belongsToContainer ?b }" - "} ", - source_iri, source_iri, source_iri); - - /* Get new parent information */ - new_parent = g_file_get_parent (file); - new_parent_iri = tracker_miner_fs_query_urn (fs, new_parent); - - g_string_append_printf (sparql, - "INSERT INTO <" TRACKER_OWN_GRAPH_URN "> {" - " <%s> nfo:fileName \"%s\" ; " - " nie:url \"%s\" ; " - " nie:isStoredAs <%s> ", - source_iri, display_name, uri, source_iri); - - if (new_parent && new_parent_iri) { - g_string_append_printf (sparql, "; nfo:belongsToContainer \"%s\"", - new_parent_iri); - } - - g_string_append (sparql, "}"); - - if (recursive) { - g_string_append_printf (sparql, - " DELETE {" - " ?u nie:url ?url " - "} INSERT { " - " GRAPH <" TRACKER_OWN_GRAPH_URN "> {" - " ?u nie:url ?new_url " - " }" - "} WHERE {" - " ?u a rdfs:Resource;" - " nie:url ?url ." - " BIND (CONCAT (\"%s/\", SUBSTR (?url, STRLEN (\"%s/\") + 1)) AS ?new_url) ." - " FILTER (STRSTARTS (?url, \"%s/\"))" - "} ", - uri, source_uri, source_uri); - } - - g_free (uri); - g_free (source_uri); - g_free (display_name); - g_clear_object (&new_parent); - - return g_string_free (sparql, FALSE); -} - -TrackerMiner * -tracker_miner_files_new (TrackerConfig *config, - GError **error) -{ - return g_initable_new (TRACKER_TYPE_MINER_FILES, - NULL, - error, - "root", NULL, - "config", config, - "processing-pool-wait-limit", 10, - "processing-pool-ready-limit", 100, - NULL); -} - -gboolean -tracker_miner_files_check_file (GFile *file, - GSList *ignored_file_paths, - GSList *ignored_file_patterns) -{ - GSList *l; - gchar *basename; - gchar *path; - gboolean should_process; - - should_process = FALSE; - basename = NULL; - path = NULL; - - if (tracker_file_is_hidden (file)) { - /* Ignore hidden files */ - goto done; - } - - path = g_file_get_path (file); - - for (l = ignored_file_paths; l; l = l->next) { - if (strcmp (l->data, path) == 0) { - goto done; - } - } - - basename = g_file_get_basename (file); - - for (l = ignored_file_patterns; l; l = l->next) { - if (g_pattern_match_string (l->data, basename)) { - goto done; - } - } - - should_process = TRUE; - -done: - g_free (basename); - g_free (path); - - return should_process; -} - -gboolean -tracker_miner_files_check_directory (GFile *file, - GSList *index_recursive_directories, - GSList *index_single_directories, - GSList *ignored_directory_paths, - GSList *ignored_directory_patterns) -{ - GSList *l; - gchar *basename; - gchar *path; - gboolean should_process; - gboolean is_hidden; - - should_process = FALSE; - basename = NULL; - - path = g_file_get_path (file); - - /* First we check the GIO hidden check. This does a number of - * things for us which is good (like checking ".foo" dirs). - */ - is_hidden = tracker_file_is_hidden (file); - -#ifdef __linux__ - /* Second we check if the file is on FAT and if the hidden - * attribute is set. GIO does this but ONLY on a Windows OS, - * not for Windows files under a Linux OS, so we have to check - * anyway. - */ - if (!is_hidden) { - int fd; - - fd = g_open (path, O_RDONLY, 0); - if (fd != -1) { - __u32 attrs; - - if (ioctl (fd, FAT_IOCTL_GET_ATTRIBUTES, &attrs) == 0) { - is_hidden = attrs & ATTR_HIDDEN ? TRUE : FALSE; - } - - close (fd); - } - } -#endif /* __linux__ */ - - if (is_hidden) { - /* FIXME: We need to check if the file is actually a - * config specified location before blanket ignoring - * all hidden files. - */ - if (tracker_string_in_gslist (path, index_recursive_directories)) { - should_process = TRUE; - } - - if (tracker_string_in_gslist (path, index_single_directories)) { - should_process = TRUE; - } - - /* Ignore hidden dirs */ - goto done; - } - - for (l = ignored_directory_paths; l; l = l->next) { - if (strcmp (l->data, path) == 0) { - goto done; - } - } - - basename = g_file_get_basename (file); - - for (l = ignored_directory_patterns; l; l = l->next) { - if (g_pattern_match_string (l->data, basename)) { - goto done; - } - } - - /* Check module directory ignore patterns */ - should_process = TRUE; - -done: - g_free (basename); - g_free (path); - - return should_process; -} - -gboolean -tracker_miner_files_check_directory_contents (GFile *parent, - GList *children, - GSList *ignored_content) -{ - GSList *l; - - if (!ignored_content) { - return TRUE; - } - - while (children) { - gchar *basename; - - basename = g_file_get_basename (children->data); - - for (l = ignored_content; l; l = l->next) { - if (g_strcmp0 (basename, l->data) == 0) { - gchar *parent_uri; - - parent_uri = g_file_get_uri (parent); - /* g_debug ("Directory '%s' ignored since it contains a file named '%s'", */ - /* parent_uri, basename); */ - - g_free (parent_uri); - g_free (basename); - - return FALSE; - } - } - - children = children->next; - g_free (basename); - } - - return TRUE; -} - -gboolean -tracker_miner_files_monitor_directory (GFile *file, - gboolean enable_monitors, - GSList *directories_to_check) -{ - if (!enable_monitors) { - return FALSE; - } - - /* We'll only get this signal for the directories where check_directory() - * and check_directory_contents() returned TRUE, so by default we want - * these directories to be indexed. */ - - return TRUE; -} - -static void -remove_files_in_removable_media_cb (GObject *object, - GAsyncResult *result, - gpointer user_data) -{ - GError *error = NULL; - - tracker_sparql_connection_update_finish (TRACKER_SPARQL_CONNECTION (object), result, &error); - - if (error) { - g_critical ("Could not remove files in volumes: %s", error->message); - g_error_free (error); - } -} - -static gboolean -miner_files_in_removable_media_remove_by_type (TrackerMinerFiles *miner, - TrackerStorageType type) -{ - gboolean removable; - gboolean optical; - - removable = TRACKER_STORAGE_TYPE_IS_REMOVABLE (type); - optical = TRACKER_STORAGE_TYPE_IS_OPTICAL (type); - - /* Only remove if any of the flags was TRUE */ - if (removable || optical) { - GString *queries; - - g_debug (" Removing all resources in store from %s ", - optical ? "optical discs" : "removable devices"); - - queries = g_string_new (""); - - /* Delete all resources where nie:dataSource is a volume - * of the given type */ - g_string_append_printf (queries, - "DELETE { " - " ?f a rdfs:Resource . " - " ?ie a rdfs:Resource " - "} WHERE { " - " ?v a tracker:Volume ; " - " tracker:isRemovable %s ; " - " tracker:isOptical %s . " - " ?f nie:dataSource ?v . " - " ?ie nie:isStoredAs ?f " - "}", - removable ? "true" : "false", - optical ? "true" : "false"); - - tracker_sparql_connection_update_async (tracker_miner_get_connection (TRACKER_MINER (miner)), - queries->str, - G_PRIORITY_LOW, - NULL, - remove_files_in_removable_media_cb, - NULL); - - g_string_free (queries, TRUE); - - return TRUE; - } - - return FALSE; -} - -static void -miner_files_in_removable_media_remove_by_date (TrackerMinerFiles *miner, - const gchar *date) -{ - GString *queries; - - g_debug (" Removing all resources in store from removable or " - "optical devices not mounted after '%s'", - date); - - queries = g_string_new (""); - - /* Delete all resources where nie:dataSource is a volume - * which was last unmounted before the given date */ - g_string_append_printf (queries, - "DELETE { " - " ?f a rdfs:Resource . " - " ?ie a rdfs:Resource " - "} WHERE { " - " ?v a tracker:Volume ; " - " tracker:isRemovable true ; " - " tracker:isMounted false ; " - " tracker:unmountDate ?d . " - " ?f nie:dataSource ?v . " - " ?ie nie:isStoredAs ?f " - " FILTER ( ?d < \"%s\") " - "}", - date); - - tracker_sparql_connection_update_async (tracker_miner_get_connection (TRACKER_MINER (miner)), - queries->str, - G_PRIORITY_LOW, - NULL, - remove_files_in_removable_media_cb, - NULL); - - g_string_free (queries, TRUE); -} - -static void -miner_files_add_removable_or_optical_directory (TrackerMinerFiles *mf, - const gchar *mount_path, - const gchar *uuid) -{ - TrackerIndexingTree *indexing_tree; - TrackerDirectoryFlags flags; - GFile *mount_point_file; - - mount_point_file = g_file_new_for_path (mount_path); - - /* UUID may be NULL, and if so, get it */ - if (!uuid) { - uuid = tracker_storage_get_uuid_for_file (mf->private->storage, - mount_point_file); - if (!uuid) { - g_critical ("Couldn't get UUID for mount point '%s'", - mount_path); - g_object_unref (mount_point_file); - return; - } - } - - indexing_tree = tracker_miner_fs_get_indexing_tree (TRACKER_MINER_FS (mf)); - flags = TRACKER_DIRECTORY_FLAG_RECURSE | - TRACKER_DIRECTORY_FLAG_CHECK_MTIME | - TRACKER_DIRECTORY_FLAG_PRESERVE | - TRACKER_DIRECTORY_FLAG_PRIORITY; - - if (tracker_config_get_enable_monitors (mf->private->config)) { - flags |= TRACKER_DIRECTORY_FLAG_MONITOR; - } - - g_object_set_qdata_full (G_OBJECT (mount_point_file), - mf->private->quark_mount_point_uuid, - g_strdup (uuid), - (GDestroyNotify) g_free); - - g_message (" Adding removable/optical: '%s'", mount_path); - tracker_indexing_tree_add (indexing_tree, - mount_point_file, - flags); - g_object_unref (mount_point_file); -} - -gboolean -tracker_miner_files_is_file_eligible (TrackerMinerFiles *miner, - GFile *file) -{ - TrackerConfig *config; - GFile *dir; - GFileInfo *file_info; - gboolean is_dir; - - file_info = g_file_query_info (file, - G_FILE_ATTRIBUTE_STANDARD_TYPE, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - NULL, NULL); - - if (!file_info) { - /* file does not exist */ - return FALSE; - } - - is_dir = (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY); - g_object_unref (file_info); - - g_object_get (miner, - "config", &config, - NULL); - - if (is_dir) { - dir = g_object_ref (file); - } else { - if (!tracker_miner_files_check_file (file, - tracker_config_get_ignored_file_paths (config), - tracker_config_get_ignored_file_patterns (config))) { - /* file is not eligible to be indexed */ - g_object_unref (config); - return FALSE; - } - - dir = g_file_get_parent (file); - } - - if (dir) { - gboolean found = FALSE; - GSList *l; - - if (!tracker_miner_files_check_directory (dir, - tracker_config_get_index_recursive_directories (config), - tracker_config_get_index_single_directories (config), - tracker_config_get_ignored_directory_paths (config), - tracker_config_get_ignored_directory_patterns (config))) { - /* file is not eligible to be indexed */ - g_object_unref (dir); - g_object_unref (config); - return FALSE; - } - - l = tracker_config_get_index_recursive_directories (config); - - while (l && !found) { - GFile *config_dir; - - config_dir = g_file_new_for_path ((gchar *) l->data); - - if (g_file_equal (dir, config_dir) || - g_file_has_prefix (dir, config_dir)) { - found = TRUE; - } - - g_object_unref (config_dir); - l = l->next; - } - - l = tracker_config_get_index_single_directories (config); - - while (l && !found) { - GFile *config_dir; - - config_dir = g_file_new_for_path ((gchar *) l->data); - - if (g_file_equal (dir, config_dir)) { - found = TRUE; - } - - g_object_unref (config_dir); - l = l->next; - } - - g_object_unref (dir); - - if (!found) { - /* file is not eligible to be indexed */ - g_object_unref (config); - return FALSE; - } - } - - g_object_unref (config); - - /* file is eligible to be indexed */ - return TRUE; -} - -inline static gchar * -get_first_index_filename (void) -{ - return g_build_filename (g_get_user_cache_dir (), - "tracker", - FIRST_INDEX_FILENAME, - NULL); -} - -/** - * tracker_miner_files_get_first_index_done: - * - * Check if first full index of files was already done. - * - * Returns: %TRUE if a first full index have been done, %FALSE otherwise. - **/ -gboolean -tracker_miner_files_get_first_index_done (void) -{ - gboolean exists; - gchar *filename; - - filename = get_first_index_filename (); - exists = g_file_test (filename, G_FILE_TEST_EXISTS); - g_free (filename); - - return exists; -} - -/** - * tracker_miner_files_set_first_index_done: - * - * Set the status of the first full index of files. Should be set to - * %FALSE if the index was never done or if a reindex is needed. When - * the index is completed, should be set to %TRUE. - **/ -void -tracker_miner_files_set_first_index_done (gboolean done) -{ - gboolean already_exists; - gchar *filename; - - filename = get_first_index_filename (); - already_exists = g_file_test (filename, G_FILE_TEST_EXISTS); - - if (done && !already_exists) { - GError *error = NULL; - - /* If done, create stamp file if not already there */ - if (!g_file_set_contents (filename, PACKAGE_VERSION, -1, &error)) { - g_warning (" Could not create file:'%s' failed, %s", - filename, - error->message); - g_error_free (error); - } else { - g_info (" First index file:'%s' created", filename); - } - } else if (!done && already_exists) { - /* If NOT done, remove stamp file */ - g_info (" Removing first index file:'%s'", filename); - - if (g_remove (filename)) { - g_warning (" Could not remove file:'%s': %m", - filename); - } - } - - g_free (filename); -} - -static inline gchar * -get_last_crawl_filename (void) -{ - return g_build_filename (g_get_user_cache_dir (), - "tracker", - LAST_CRAWL_FILENAME, - NULL); -} - -/** - * tracker_miner_files_get_last_crawl_done: - * - * Check when last crawl was performed. - * - * Returns: time_t() value when last crawl occurred, otherwise 0. - **/ -guint64 -tracker_miner_files_get_last_crawl_done (void) -{ - gchar *filename; - gchar *content; - guint64 then; - - filename = get_last_crawl_filename (); - - if (!g_file_get_contents (filename, &content, NULL, NULL)) { - g_info (" No previous timestamp, crawling forced"); - return 0; - } - - then = g_ascii_strtoull (content, NULL, 10); - g_free (content); - - return then; -} - -/** - * tracker_miner_files_set_last_crawl_done: - * - * Set the status of the first full index of files. Should be set to - * %FALSE if the index was never done or if a reindex is needed. When - * the index is completed, should be set to %TRUE. - **/ -void -tracker_miner_files_set_last_crawl_done (gboolean done) -{ - gboolean already_exists; - gchar *filename; - - filename = get_last_crawl_filename (); - already_exists = g_file_test (filename, G_FILE_TEST_EXISTS); - - if (done && !already_exists) { - GError *error = NULL; - gchar *content; - - content = g_strdup_printf ("%" G_GUINT64_FORMAT, (guint64) time (NULL)); - - /* If done, create stamp file if not already there */ - if (!g_file_set_contents (filename, content, -1, &error)) { - g_warning (" Could not create file:'%s' failed, %s", - filename, - error->message); - g_error_free (error); - } else { - g_info (" Last crawl file:'%s' created", filename); - } - - g_free (content); - } else if (!done && already_exists) { - /* If NOT done, remove stamp file */ - g_info (" Removing last crawl file:'%s'", filename); - - if (g_remove (filename)) { - g_warning (" Could not remove file:'%s': %m", - filename); - } - } - - g_free (filename); -} - -inline static gchar * -get_need_mtime_check_filename (void) -{ - return g_build_filename (g_get_user_cache_dir (), - "tracker", - NEED_MTIME_CHECK_FILENAME, - NULL); -} - -/** - * tracker_miner_files_get_need_mtime_check: - * - * Check if the miner-fs was cleanly shutdown or not. - * - * Returns: %TRUE if we need to check mtimes for directories against - * the database on the next start for the miner-fs, %FALSE otherwise. - **/ -gboolean -tracker_miner_files_get_need_mtime_check (void) -{ - gboolean exists; - gchar *filename; - - filename = get_need_mtime_check_filename (); - exists = g_file_test (filename, G_FILE_TEST_EXISTS); - g_free (filename); - - /* Existence of the file means we cleanly shutdown before and - * don't need to do the mtime check again on this start. - */ - return !exists; -} - -/** - * tracker_miner_files_set_need_mtime_check: - * @needed: a #gboolean - * - * If the next start of miner-fs should perform a full mtime check - * against each directory found and those in the database (for - * complete synchronisation), then @needed should be #TRUE, otherwise - * #FALSE. - * - * Creates a file in $HOME/.cache/tracker/ if an mtime check is not - * needed. The idea behind this is that a check is forced if the file - * is not cleaned up properly on shutdown (i.e. due to a crash or any - * other uncontrolled shutdown reason). - **/ -void -tracker_miner_files_set_need_mtime_check (gboolean needed) -{ - gboolean already_exists; - gchar *filename; - - filename = get_need_mtime_check_filename (); - already_exists = g_file_test (filename, G_FILE_TEST_EXISTS); - - /* !needed = add file - * needed = remove file - */ - if (!needed && !already_exists) { - GError *error = NULL; - - /* Create stamp file if not already there */ - if (!g_file_set_contents (filename, PACKAGE_VERSION, -1, &error)) { - g_warning (" Could not create file:'%s' failed, %s", - filename, - error->message); - g_error_free (error); - } else { - g_info (" Need mtime check file:'%s' created", filename); - } - } else if (needed && already_exists) { - /* Remove stamp file */ - g_info (" Removing need mtime check file:'%s'", filename); - - if (g_remove (filename)) { - g_warning (" Could not remove file:'%s': %m", - filename); - } - } - - g_free (filename); -} - -void -tracker_miner_files_set_mtime_checking (TrackerMinerFiles *mf, - gboolean mtime_check) -{ - mf->private->mtime_check = mtime_check; -} - -void -tracker_miner_files_writeback_file (TrackerMinerFiles *mf, - GFile *file, - GStrv rdf_types, - GPtrArray *results) -{ - GCancellable *cancellable; - - if (!g_hash_table_contains (mf->private->writeback_tasks, file)) { - cancellable = g_cancellable_new (); - g_hash_table_insert (mf->private->writeback_tasks, file, cancellable); - sync_writeback_pause_state (mf); - g_signal_emit (mf, signals[WRITEBACK], 0, file, rdf_types, - results, cancellable); - } -} - -/** - * tracker_miner_files_writeback_notify: - * @fs: a #TrackerMinerFS - * @file: a #GFile - * @error: a #GError with the error that happened during processing, or %NULL. - * - * Notifies @fs that all writing back on @file has been finished, if any error - * happened during file data processing, it should be passed in @error, else - * that parameter will contain %NULL to reflect success. - **/ -void -tracker_miner_files_writeback_notify (TrackerMinerFiles *mf, - GFile *file, - const GError *error) -{ - GCancellable *cancellable; - - g_return_if_fail (TRACKER_IS_MINER_FILES (mf)); - g_return_if_fail (G_IS_FILE (file)); - - cancellable = g_hash_table_lookup (mf->private->writeback_tasks, file); - - if (!cancellable) - return; - - if (error) { - gchar *uri = g_file_get_uri (file); - g_warning ("Writeback on %s got error: %s\n", - uri, error->message); - g_free (uri); - } - - /* Drop the cancellable, it will be detected on the next file - * update in miner_files_filter_event(). - */ - g_hash_table_steal (mf->private->writeback_tasks, file); - g_hash_table_insert (mf->private->writeback_tasks, file, NULL); - g_object_unref (cancellable); -} |