summaryrefslogtreecommitdiff
path: root/src/libtracker-miner/tracker-file-notifier.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libtracker-miner/tracker-file-notifier.c')
-rw-r--r--src/libtracker-miner/tracker-file-notifier.c2184
1 files changed, 0 insertions, 2184 deletions
diff --git a/src/libtracker-miner/tracker-file-notifier.c b/src/libtracker-miner/tracker-file-notifier.c
deleted file mode 100644
index addb9c5c2..000000000
--- a/src/libtracker-miner/tracker-file-notifier.c
+++ /dev/null
@@ -1,2184 +0,0 @@
-/*
- * Copyright (C) 2011, Nokia <ivan.frade@nokia.com>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- * Author: Carlos Garnacho <carlos@lanedo.com>
- */
-
-#include "config.h"
-
-#include <libtracker-common/tracker-common.h>
-#include <libtracker-sparql/tracker-sparql.h>
-
-#include "tracker-file-notifier.h"
-#include "tracker-file-system.h"
-#include "tracker-crawler.h"
-#include "tracker-monitor.h"
-
-static GQuark quark_property_iri = 0;
-static GQuark quark_property_store_mtime = 0;
-static GQuark quark_property_filesystem_mtime = 0;
-static gboolean force_check_updated = FALSE;
-
-enum {
- PROP_0,
- PROP_INDEXING_TREE,
- PROP_DATA_PROVIDER,
- PROP_CONNECTION
-};
-
-enum {
- FILE_CREATED,
- FILE_UPDATED,
- FILE_DELETED,
- FILE_MOVED,
- DIRECTORY_STARTED,
- DIRECTORY_FINISHED,
- FINISHED,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-typedef struct {
- GFile *root;
- GFile *current_dir;
- GQueue *pending_dirs;
- GPtrArray *query_files;
- guint flags;
- guint directories_found;
- guint directories_ignored;
- guint files_found;
- guint files_ignored;
- guint current_dir_content_filtered : 1;
- guint ignore_root : 1;
-} RootData;
-
-typedef struct {
- TrackerIndexingTree *indexing_tree;
- TrackerFileSystem *file_system;
-
- TrackerSparqlConnection *connection;
- GCancellable *cancellable;
-
- TrackerCrawler *crawler;
- TrackerMonitor *monitor;
- TrackerDataProvider *data_provider;
-
- GTimer *timer;
-
- /* List of pending directory
- * trees to get data from
- */
- GList *pending_index_roots;
- RootData *current_index_root;
-
- guint stopped : 1;
-} TrackerFileNotifierPrivate;
-
-typedef struct {
- TrackerFileNotifier *notifier;
- GNode *cur_parent_node;
-
- /* Canonical copy from priv->file_system */
- GFile *cur_parent;
-} DirectoryCrawledData;
-
-static gboolean crawl_directories_start (TrackerFileNotifier *notifier);
-static void sparql_files_query_start (TrackerFileNotifier *notifier,
- GFile **files,
- guint n_files);
-
-G_DEFINE_TYPE_WITH_PRIVATE (TrackerFileNotifier, tracker_file_notifier, G_TYPE_OBJECT)
-
-static void
-tracker_file_notifier_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- TrackerFileNotifierPrivate *priv;
-
- priv = tracker_file_notifier_get_instance_private (TRACKER_FILE_NOTIFIER (object));
-
- switch (prop_id) {
- case PROP_INDEXING_TREE:
- priv->indexing_tree = g_value_dup_object (value);
- break;
- case PROP_DATA_PROVIDER:
- priv->data_provider = g_value_dup_object (value);
- break;
- case PROP_CONNECTION:
- priv->connection = g_value_dup_object (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-tracker_file_notifier_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- TrackerFileNotifierPrivate *priv;
-
- priv = tracker_file_notifier_get_instance_private (TRACKER_FILE_NOTIFIER (object));
-
- switch (prop_id) {
- case PROP_INDEXING_TREE:
- g_value_set_object (value, priv->indexing_tree);
- break;
- case PROP_DATA_PROVIDER:
- g_value_set_object (value, priv->data_provider);
- break;
- case PROP_CONNECTION:
- g_value_set_object (value, priv->connection);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static RootData *
-root_data_new (TrackerFileNotifier *notifier,
- GFile *file,
- guint flags,
- gboolean ignore_root)
-{
- RootData *data;
-
- data = g_new0 (RootData, 1);
- data->root = g_object_ref (file);
- data->pending_dirs = g_queue_new ();
- data->query_files = g_ptr_array_new_with_free_func (g_object_unref);
- data->flags = flags;
- data->ignore_root = ignore_root;
-
- g_queue_push_tail (data->pending_dirs, g_object_ref (file));
-
- return data;
-}
-
-static void
-root_data_free (RootData *data)
-{
- g_queue_free_full (data->pending_dirs, (GDestroyNotify) g_object_unref);
- g_ptr_array_unref (data->query_files);
- if (data->current_dir) {
- g_object_unref (data->current_dir);
- }
- g_object_unref (data->root);
- g_free (data);
-}
-
-/* Crawler signal handlers */
-static gboolean
-crawler_check_file_cb (TrackerCrawler *crawler,
- GFile *file,
- gpointer user_data)
-{
- TrackerFileNotifierPrivate *priv;
-
- priv = tracker_file_notifier_get_instance_private (user_data);
-
- return tracker_indexing_tree_file_is_indexable (priv->indexing_tree,
- file,
- G_FILE_TYPE_REGULAR);
-}
-
-static gboolean
-crawler_check_directory_cb (TrackerCrawler *crawler,
- GFile *directory,
- gpointer user_data)
-{
- TrackerFileNotifierPrivate *priv;
- GFile *root, *canonical;
-
- priv = tracker_file_notifier_get_instance_private (user_data);
- g_assert (priv->current_index_root != NULL);
-
- canonical = tracker_file_system_peek_file (priv->file_system, directory);
- root = tracker_indexing_tree_get_root (priv->indexing_tree, directory, NULL);
-
- /* If it's a config root itself, other than the one
- * currently processed, bypass it, it will be processed
- * when the time arrives.
- */
- if (canonical && root == canonical &&
- root != priv->current_index_root->root) {
- return FALSE;
- }
-
- return tracker_indexing_tree_file_is_indexable (priv->indexing_tree,
- directory,
- G_FILE_TYPE_DIRECTORY);
-}
-
-static gboolean
-crawler_check_directory_contents_cb (TrackerCrawler *crawler,
- GFile *parent,
- GList *children,
- gpointer user_data)
-{
- TrackerFileNotifierPrivate *priv;
- gboolean process = TRUE;
-
- priv = tracker_file_notifier_get_instance_private (user_data);
-
- /* Do not let content filter apply to configured roots themselves. This
- * is a measure to trim undesired portions of the filesystem, and if
- * the folder is configured to be indexed, it's clearly not undesired.
- */
- if (!tracker_indexing_tree_file_is_root (priv->indexing_tree, parent)) {
- process = tracker_indexing_tree_parent_is_indexable (priv->indexing_tree,
- parent, children);
- }
-
- if (process) {
- TrackerDirectoryFlags parent_flags;
- gboolean add_monitor;
-
- tracker_indexing_tree_get_root (priv->indexing_tree,
- parent, &parent_flags);
-
- add_monitor = (parent_flags & TRACKER_DIRECTORY_FLAG_MONITOR) != 0;
-
- if (add_monitor) {
- tracker_monitor_add (priv->monitor, parent);
- } else {
- tracker_monitor_remove (priv->monitor, parent);
- }
- } else {
- priv->current_index_root->current_dir_content_filtered = TRUE;
- }
-
- return process;
-}
-
-static gboolean
-file_notifier_traverse_tree_foreach (GFile *file,
- gpointer user_data)
-{
- TrackerFileNotifier *notifier;
- TrackerFileNotifierPrivate *priv;
- guint64 *store_mtime, *disk_mtime;
- GFile *current_root;
-
- notifier = user_data;
- priv = tracker_file_notifier_get_instance_private (notifier);
- current_root = priv->current_index_root->current_dir;
-
- store_mtime = tracker_file_system_steal_property (priv->file_system, file,
- quark_property_store_mtime);
- disk_mtime = tracker_file_system_steal_property (priv->file_system, file,
- quark_property_filesystem_mtime);
-
- /* If we're crawling over a subdirectory of a root index, it's been
- * already notified in the crawling op that made it processed, so avoid
- * it here again.
- */
- if (current_root == file &&
- (current_root != priv->current_index_root->root ||
- priv->current_index_root->ignore_root)) {
- g_free (store_mtime);
- g_free (disk_mtime);
- return FALSE;
- }
-
- if (store_mtime && !disk_mtime) {
- /* In store but not in disk, delete */
- g_signal_emit (notifier, signals[FILE_DELETED], 0, file);
-
- g_free (store_mtime);
- g_free (disk_mtime);
- return TRUE;
- } else if (disk_mtime && !store_mtime) {
- /* In disk but not in store, create */
- g_signal_emit (notifier, signals[FILE_CREATED], 0, file);
- } else if (store_mtime && disk_mtime && *disk_mtime != *store_mtime) {
- /* Mtime changed, update */
- g_signal_emit (notifier, signals[FILE_UPDATED], 0, file, FALSE);
- } else if (!store_mtime && !disk_mtime) {
- /* what are we doing with such file? should happen rarely,
- * only with files that we've queried, but we decided not
- * to crawl (i.e. embedded root directories, that would
- * be processed when that root is being crawled).
- */
- if (file != priv->current_index_root->root &&
- !tracker_indexing_tree_file_is_root (priv->indexing_tree, file)) {
- gchar *uri;
-
- uri = g_file_get_uri (file);
- g_debug ("File '%s' has no disk nor store mtime",
- uri);
- g_free (uri);
- }
- }
-
- g_free (store_mtime);
- g_free (disk_mtime);
-
- return FALSE;
-}
-
-static gboolean
-notifier_check_next_root (TrackerFileNotifier *notifier)
-{
- TrackerFileNotifierPrivate *priv;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- g_assert (priv->current_index_root == NULL);
-
- if (priv->pending_index_roots) {
- return crawl_directories_start (notifier);
- } else {
- g_signal_emit (notifier, signals[FINISHED], 0);
- return FALSE;
- }
-}
-
-static void
-file_notifier_traverse_tree (TrackerFileNotifier *notifier)
-{
- TrackerFileNotifierPrivate *priv;
- GFile *directory;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- g_assert (priv->current_index_root != NULL);
-
- directory = priv->current_index_root->current_dir;
-
- /* We want the directory and its direct contents, hence depth=2 */
- tracker_file_system_traverse (priv->file_system,
- directory,
- G_LEVEL_ORDER,
- file_notifier_traverse_tree_foreach,
- 2, notifier);
-}
-
-static gboolean
-file_notifier_is_directory_modified (TrackerFileNotifier *notifier,
- GFile *file)
-{
- TrackerFileNotifierPrivate *priv;
- guint64 *store_mtime, *disk_mtime;
-
- if (G_UNLIKELY (force_check_updated))
- return TRUE;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- store_mtime = tracker_file_system_get_property (priv->file_system, file,
- quark_property_store_mtime);
- disk_mtime = tracker_file_system_get_property (priv->file_system, file,
- quark_property_filesystem_mtime);
-
- return (store_mtime && disk_mtime && *disk_mtime != *store_mtime);
-}
-
-static gboolean
-file_notifier_add_node_foreach (GNode *node,
- gpointer user_data)
-{
- DirectoryCrawledData *data = user_data;
- TrackerFileNotifierPrivate *priv;
- GFileInfo *file_info;
- GFile *canonical, *file;
-
- priv = tracker_file_notifier_get_instance_private (data->notifier);
- file = node->data;
-
- if (node->parent &&
- node->parent != data->cur_parent_node) {
- data->cur_parent_node = node->parent;
- data->cur_parent = tracker_file_system_peek_file (priv->file_system,
- node->parent->data);
- } else {
- data->cur_parent_node = NULL;
- data->cur_parent = NULL;
- }
-
- file_info = tracker_crawler_get_file_info (priv->crawler, file);
-
- if (file_info) {
- GFileType file_type;
- guint64 time, *time_ptr;
-
- file_type = g_file_info_get_file_type (file_info);
-
- /* Intern file in filesystem */
- canonical = tracker_file_system_get_file (priv->file_system,
- file, file_type,
- data->cur_parent);
-
- if (priv->current_index_root->flags & TRACKER_DIRECTORY_FLAG_CHECK_MTIME) {
- time = g_file_info_get_attribute_uint64 (file_info,
- G_FILE_ATTRIBUTE_TIME_MODIFIED);
-
- time_ptr = g_new (guint64, 1);
- *time_ptr = time;
-
- tracker_file_system_set_property (priv->file_system, canonical,
- quark_property_filesystem_mtime,
- time_ptr);
- }
-
- g_object_unref (file_info);
-
- if (file_type == G_FILE_TYPE_DIRECTORY &&
- (priv->current_index_root->flags & TRACKER_DIRECTORY_FLAG_RECURSE) != 0 &&
- !G_NODE_IS_ROOT (node)) {
- /* Queue child dirs for later processing */
- g_assert (node->children == NULL);
- g_queue_push_tail (priv->current_index_root->pending_dirs,
- g_object_ref (canonical));
- }
-
- if (file == priv->current_index_root->root ||
- !tracker_indexing_tree_file_is_root (priv->indexing_tree, file)) {
- g_ptr_array_add (priv->current_index_root->query_files,
- g_object_ref (canonical));
- }
- }
-
- return FALSE;
-}
-
-static void
-crawler_directory_crawled_cb (TrackerCrawler *crawler,
- GFile *directory,
- GNode *tree,
- guint directories_found,
- guint directories_ignored,
- guint files_found,
- guint files_ignored,
- gpointer user_data)
-{
- TrackerFileNotifier *notifier;
- TrackerFileNotifierPrivate *priv;
- DirectoryCrawledData data = { 0 };
-
- notifier = data.notifier = user_data;
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- g_node_traverse (tree,
- G_PRE_ORDER,
- G_TRAVERSE_ALL,
- -1,
- file_notifier_add_node_foreach,
- &data);
-
- priv->current_index_root->directories_found += directories_found;
- priv->current_index_root->directories_ignored += directories_ignored;
- priv->current_index_root->files_found += files_found;
- priv->current_index_root->files_ignored += files_ignored;
-}
-
-static GFile *
-_insert_store_info (TrackerFileNotifier *notifier,
- GFile *file,
- GFileType file_type,
- GFile *parent,
- const gchar *iri,
- guint64 _time)
-{
- TrackerFileNotifierPrivate *priv;
- GFile *canonical;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- canonical = tracker_file_system_get_file (priv->file_system,
- file, file_type,
- parent);
- tracker_file_system_set_property (priv->file_system, canonical,
- quark_property_iri,
- g_strdup (iri));
- tracker_file_system_set_property (priv->file_system, canonical,
- quark_property_store_mtime,
- g_memdup (&_time, sizeof (guint64)));
- return canonical;
-}
-
-static void
-sparql_files_query_populate (TrackerFileNotifier *notifier,
- TrackerSparqlCursor *cursor,
- gboolean check_root)
-{
- TrackerFileNotifierPrivate *priv;
- GFile *parent = NULL;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
- GFile *file, *canonical, *root;
- const gchar *time_str, *iri;
- GError *error = NULL;
- guint64 _time;
-
- file = g_file_new_for_uri (tracker_sparql_cursor_get_string (cursor, 0, NULL));
-
- if (check_root) {
- /* If it's a config root itself, other than the one
- * currently processed, bypass it, it will be processed
- * when the time arrives.
- */
- canonical = tracker_file_system_peek_file (priv->file_system, file);
- root = tracker_indexing_tree_get_root (priv->indexing_tree, file, NULL);
-
- if (canonical && root == file && priv->current_index_root &&
- root != priv->current_index_root->root) {
- g_object_unref (file);
- continue;
- }
- }
-
- /* All files belong to the same directory */
- if (!parent)
- parent = tracker_file_system_peek_parent (priv->file_system, file);
-
- iri = tracker_sparql_cursor_get_string (cursor, 1, NULL);
- time_str = tracker_sparql_cursor_get_string (cursor, 2, NULL);
- _time = tracker_string_to_date (time_str, NULL, &error);
-
- if (error) {
- /* This should never happen. Assume that file was modified. */
- g_critical ("Getting store mtime: %s", error->message);
- g_clear_error (&error);
- _time = 0;
- }
-
- _insert_store_info (notifier, file,
- G_FILE_TYPE_UNKNOWN,
- parent, iri, _time);
- g_object_unref (file);
- }
-}
-
-static void
-sparql_contents_check_deleted (TrackerFileNotifier *notifier,
- TrackerSparqlCursor *cursor)
-{
- TrackerFileNotifierPrivate *priv;
- GFile *file, *canonical, *parent = NULL;
- const gchar *iri;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- while (tracker_sparql_cursor_next (cursor, NULL, NULL)) {
- const gchar *uri;
- gboolean is_folder;
- GFileType file_type;
-
- /* Sometimes URI can be NULL when nie:url and
- * nfo:belongsToContainer does not have a strictly 1:1
- * relationship, e.g. data containers where there is
- * only one nie:url but many nfo:belongsToContainer
- * cases.
- */
- uri = tracker_sparql_cursor_get_string (cursor, 0, NULL);
- if (!uri) {
- continue;
- }
-
- file = g_file_new_for_uri (uri);
- iri = tracker_sparql_cursor_get_string (cursor, 1, NULL);
- is_folder = tracker_sparql_cursor_get_boolean (cursor, 3);
- file_type = is_folder ? G_FILE_TYPE_DIRECTORY : G_FILE_TYPE_UNKNOWN;
- canonical = tracker_file_system_peek_file (priv->file_system, file);
-
- /* All files belong to the same directory */
- if (!parent)
- parent = tracker_file_system_peek_parent (priv->file_system, file);
-
- if (!canonical) {
- /* The file exists on the store, but not on the
- * crawled content, insert temporarily to handle
- * the delete event.
- */
- canonical = _insert_store_info (notifier, file,
- file_type,
- parent, iri, 0);
- g_signal_emit (notifier, signals[FILE_DELETED], 0, canonical);
- } else if (priv->current_index_root->current_dir_content_filtered ||
- !tracker_indexing_tree_file_is_indexable (priv->indexing_tree,
- canonical,
- file_type)) {
- /* File is there, but is not indexable anymore, remove too */
- g_signal_emit (notifier, signals[FILE_DELETED], 0, canonical);
- }
-
- g_object_unref (file);
- }
-}
-
-static gboolean
-crawl_directory_in_current_root (TrackerFileNotifier *notifier)
-{
- TrackerFileNotifierPrivate *priv;
- GFile *directory;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- if (!priv->current_index_root)
- return FALSE;
-
- directory = g_queue_pop_head (priv->current_index_root->pending_dirs);
-
- if (!directory)
- return FALSE;
-
- priv->current_index_root->current_dir = directory;
-
- if (priv->cancellable)
- g_object_unref (priv->cancellable);
- priv->cancellable = g_cancellable_new ();
-
- /* Begin crawling the directory non-recursively.
- *
- * - We receive ::check-file, ::check-directory and ::check-directory-contents signals
- * during the crawl, which control which directories are crawled and which files are
- * returned.
- * - We receive ::directory-crawled each time a directory crawl completes. This provides
- * the list of contents for a directory.
- * - We receive ::finished when the crawler completes.
- *
- */
- if (!tracker_crawler_start (priv->crawler,
- directory,
- priv->current_index_root->flags)) {
- sparql_files_query_start (notifier, &directory, 1);
- }
-
- return TRUE;
-}
-
-static void
-finish_current_directory (TrackerFileNotifier *notifier,
- gboolean interrupted)
-{
- TrackerFileNotifierPrivate *priv;
- GFile *directory;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- directory = priv->current_index_root->current_dir;
- priv->current_index_root->current_dir = NULL;
- priv->current_index_root->current_dir_content_filtered = FALSE;
-
- /* If crawling was interrupted, we take all collected info as invalid.
- * Otherwise we dispose regular files here, only directories are
- * cached once crawling has completed.
- */
- tracker_file_system_forget_files (priv->file_system,
- directory,
- interrupted ?
- G_FILE_TYPE_UNKNOWN :
- G_FILE_TYPE_REGULAR);
-
- if (interrupted || !crawl_directory_in_current_root (notifier)) {
- /* No more directories left to be crawled in the current
- * root, jump to the next one.
- */
- g_signal_emit (notifier, signals[DIRECTORY_FINISHED], 0,
- priv->current_index_root->root,
- priv->current_index_root->directories_found,
- priv->current_index_root->directories_ignored,
- priv->current_index_root->files_found,
- priv->current_index_root->files_ignored);
-
- g_info (" Notified files after %2.2f seconds",
- g_timer_elapsed (priv->timer, NULL));
- g_info (" Found %d directories, ignored %d directories",
- priv->current_index_root->directories_found,
- priv->current_index_root->directories_ignored);
- g_info (" Found %d files, ignored %d files",
- priv->current_index_root->files_found,
- priv->current_index_root->files_ignored);
-
- if (!interrupted) {
- g_clear_pointer (&priv->current_index_root, root_data_free);
- notifier_check_next_root (notifier);
- }
- }
-
- g_object_unref (directory);
-}
-
-static gboolean
-root_data_remove_directory (RootData *data,
- GFile *directory)
-{
- GList *l = data->pending_dirs->head, *next;
- GFile *file;
-
- while (l) {
- file = l->data;
- next = l->next;
-
- if (g_file_equal (file, directory) ||
- g_file_has_prefix (file, directory)) {
- g_queue_remove (data->pending_dirs, file);
- g_object_unref (file);
- }
-
- l = next;
- }
-
- return (g_file_equal (data->current_dir, directory) ||
- g_file_has_prefix (data->current_dir, directory));
-}
-
-static void
-file_notifier_current_root_check_remove_directory (TrackerFileNotifier *notifier,
- GFile *file)
-{
- TrackerFileNotifierPrivate *priv;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- if (priv->current_index_root &&
- root_data_remove_directory (priv->current_index_root, file)) {
- g_cancellable_cancel (priv->cancellable);
- tracker_crawler_stop (priv->crawler);
-
- if (!crawl_directory_in_current_root (notifier)) {
- g_clear_pointer (&priv->current_index_root, root_data_free);
- notifier_check_next_root (notifier);
- }
- }
-}
-
-/* Query for directory contents, used to look for deleted contents in those */
-static void
-sparql_contents_query_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- TrackerFileNotifier *notifier = TRACKER_FILE_NOTIFIER (user_data);
- TrackerSparqlCursor *cursor;
- GError *error = NULL;
-
- cursor = tracker_sparql_connection_query_finish (TRACKER_SPARQL_CONNECTION (object),
- result, &error);
- if (error) {
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
- g_warning ("Could not query directory contents: %s\n", error->message);
- finish_current_directory (notifier, TRUE);
- }
- goto out;
- }
-
- if (cursor) {
- sparql_contents_check_deleted (notifier, cursor);
- g_object_unref (cursor);
- }
-
- finish_current_directory (notifier, FALSE);
-
-out:
- if (error) {
- g_error_free (error);
- }
-}
-
-static gchar *
-sparql_contents_compose_query (GFile *directory)
-{
- gchar *sparql, *uri;
-
- uri = g_file_get_uri (directory);
- sparql = g_strdup_printf ("SELECT ?url ?u ?lastModified ?isFolder "
- "FROM <" TRACKER_OWN_GRAPH_URN "> {"
- " ?u nfo:belongsToContainer ?f ;"
- " nfo:fileLastModified ?lastModified ;"
- " nie:url ?url ."
- " OPTIONAL { ?u nie:mimeType ?mimeType . "
- " BIND (IF (?mimeType = \"inode/directory\", true, false) AS ?isFolder) } ."
- " ?f nie:url ?folderUrl ."
- " FILTER (?folderUrl = \"%s\")"
- "}", uri);
- g_free (uri);
-
- return sparql;
-}
-
-static void
-sparql_contents_query_start (TrackerFileNotifier *notifier,
- GFile *directory)
-{
- TrackerFileNotifierPrivate *priv;
- gchar *sparql;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- if (G_UNLIKELY (priv->connection == NULL)) {
- return;
- }
-
- sparql = sparql_contents_compose_query (directory);
- tracker_sparql_connection_query_async (priv->connection,
- sparql,
- priv->cancellable,
- sparql_contents_query_cb,
- notifier);
- g_free (sparql);
-}
-
-/* Query for file information, used on all elements found during crawling */
-static void
-sparql_files_query_cb (GObject *object,
- GAsyncResult *result,
- gpointer user_data)
-{
- TrackerFileNotifier *notifier = user_data;
- TrackerFileNotifierPrivate *priv;
- TrackerSparqlCursor *cursor;
- gboolean directory_modified;
- GError *error = NULL;
- GFile *directory;
- guint flags;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- cursor = tracker_sparql_connection_query_finish (TRACKER_SPARQL_CONNECTION (object),
- result, &error);
- if (error) {
- if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
- g_warning ("Could not query indexed files: %s\n", error->message);
- finish_current_directory (notifier, TRUE);
- }
-
- g_clear_error (&error);
- return;
- }
-
- if (cursor) {
- sparql_files_query_populate (notifier, cursor, TRUE);
- g_object_unref (cursor);
- }
-
- directory = priv->current_index_root->current_dir;
- flags = priv->current_index_root->flags;
- directory_modified = file_notifier_is_directory_modified (notifier, directory);
-
- file_notifier_traverse_tree (notifier);
-
- if ((flags & TRACKER_DIRECTORY_FLAG_CHECK_DELETED) != 0 ||
- priv->current_index_root->current_dir_content_filtered ||
- directory_modified) {
- /* The directory has updated its mtime, this means something
- * was either added or removed in the mean time. Crawling
- * will always find all newly added files. But still, we
- * must check the contents in the store to handle contents
- * having been deleted in the directory.
- */
- sparql_contents_query_start (notifier, directory);
- } else {
- finish_current_directory (notifier, FALSE);
- }
-}
-
-static gchar *
-sparql_files_compose_query (GFile **files,
- guint n_files)
-{
- GString *str;
- gchar *uri;
- gint i = 0;
-
- str = g_string_new ("SELECT ?url ?u ?lastModified "
- "FROM <" TRACKER_OWN_GRAPH_URN "> {"
- " ?u a rdfs:Resource ;"
- " nfo:fileLastModified ?lastModified ;"
- " nie:url ?url . "
- " FILTER (?url IN (");
- for (i = 0; i < n_files; i++) {
- if (i != 0)
- g_string_append_c (str, ',');
-
- uri = g_file_get_uri (files[i]);
- g_string_append_printf (str, "\"%s\"", uri);
- g_free (uri);
- }
-
- g_string_append (str, "))}");
-
- return g_string_free (str, FALSE);
-}
-
-static void
-sparql_files_query_start (TrackerFileNotifier *notifier,
- GFile **files,
- guint n_files)
-{
- TrackerFileNotifierPrivate *priv;
- gchar *sparql;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- if (G_UNLIKELY (priv->connection == NULL)) {
- return;
- }
-
- sparql = sparql_files_compose_query (files, n_files);
- tracker_sparql_connection_query_async (priv->connection,
- sparql,
- priv->cancellable,
- sparql_files_query_cb,
- notifier);
- g_free (sparql);
-}
-
-static gboolean
-crawl_directories_start (TrackerFileNotifier *notifier)
-{
- TrackerFileNotifierPrivate *priv;
- TrackerDirectoryFlags flags;
- GFile *directory;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- if (priv->current_index_root) {
- return FALSE;
- }
-
- if (!priv->pending_index_roots) {
- return FALSE;
- }
-
- if (priv->stopped) {
- return FALSE;
- }
-
- while (priv->pending_index_roots) {
- priv->current_index_root = priv->pending_index_roots->data;
- priv->pending_index_roots = g_list_delete_link (priv->pending_index_roots,
- priv->pending_index_roots);
- directory = priv->current_index_root->root;
- flags = priv->current_index_root->flags;
-
- if ((flags & TRACKER_DIRECTORY_FLAG_IGNORE) == 0 &&
- crawl_directory_in_current_root (notifier)) {
- gchar *uri;
-
- uri = g_file_get_uri (directory);
- g_info ("Processing location: '%s'", uri);
- g_free (uri);
-
- g_timer_reset (priv->timer);
- g_signal_emit (notifier, signals[DIRECTORY_STARTED], 0, directory);
-
- return TRUE;
- } else {
- /* Emit both signals for consistency */
- g_signal_emit (notifier, signals[DIRECTORY_STARTED], 0, directory);
-
- if ((flags & TRACKER_DIRECTORY_FLAG_PRESERVE) == 0) {
- g_signal_emit (notifier, signals[FILE_DELETED], 0, directory);
- }
-
- g_signal_emit (notifier, signals[DIRECTORY_FINISHED], 0,
- directory, 0, 0, 0, 0);
- }
-
- g_clear_pointer (&priv->current_index_root, root_data_free);
- }
-
- g_signal_emit (notifier, signals[FINISHED], 0);
-
- return FALSE;
-}
-
-static void
-crawler_finished_cb (TrackerCrawler *crawler,
- gboolean was_interrupted,
- gpointer user_data)
-{
- TrackerFileNotifier *notifier = user_data;
- TrackerFileNotifierPrivate *priv;
- GFile *directory;
- gboolean check_mtime;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- g_assert (priv->current_index_root != NULL);
-
- if (was_interrupted) {
- finish_current_directory (notifier, TRUE);
- return;
- }
-
- directory = priv->current_index_root->current_dir;
- check_mtime = (priv->current_index_root->flags & TRACKER_DIRECTORY_FLAG_CHECK_MTIME);
-
- if (priv->current_index_root->query_files->len > 0 && check_mtime &&
- (directory == priv->current_index_root->root ||
- tracker_file_system_get_property (priv->file_system,
- directory, quark_property_iri))) {
- sparql_files_query_start (notifier,
- (GFile**) priv->current_index_root->query_files->pdata,
- priv->current_index_root->query_files->len);
- g_ptr_array_set_size (priv->current_index_root->query_files, 0);
- } else {
- g_ptr_array_set_size (priv->current_index_root->query_files, 0);
- if (check_mtime)
- file_notifier_traverse_tree (notifier);
- finish_current_directory (notifier, FALSE);
- }
-}
-
-static gint
-find_directory_root (RootData *data,
- GFile *file)
-{
- if (data->root == file)
- return 0;
- return -1;
-}
-
-static void
-notifier_queue_root (TrackerFileNotifier *notifier,
- GFile *file,
- TrackerDirectoryFlags flags,
- gboolean ignore_root)
-{
- TrackerFileNotifierPrivate *priv;
- RootData *data;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- if (priv->current_index_root &&
- priv->current_index_root->root == file)
- return;
-
- if (g_list_find_custom (priv->pending_index_roots, file,
- (GCompareFunc) find_directory_root))
- return;
-
- data = root_data_new (notifier, file, flags, ignore_root);
-
- if (flags & TRACKER_DIRECTORY_FLAG_PRIORITY) {
- priv->pending_index_roots = g_list_prepend (priv->pending_index_roots, data);
- } else {
- priv->pending_index_roots = g_list_append (priv->pending_index_roots, data);
- }
-
- crawl_directories_start (notifier);
-}
-
-/* This function ensures to issue ::file-created for all
- * parent folders that are not yet indexed. Shouldn't happen
- * often, it is however possible if MONITOR | !CHECK_MTIME is
- * given, and file updates happen on a not previously indexed
- * directory.
- */
-static void
-tracker_file_notifier_ensure_parents (TrackerFileNotifier *notifier,
- GFile *file)
-{
- TrackerFileNotifierPrivate *priv;
- GFile *parent, *canonical;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- parent = g_file_get_parent (file);
-
- while (parent) {
- if (tracker_file_notifier_get_file_iri (notifier, parent, TRUE)) {
- g_object_unref (parent);
- break;
- }
-
- canonical = tracker_file_system_get_file (priv->file_system,
- parent,
- G_FILE_TYPE_DIRECTORY,
- NULL);
- g_object_unref (parent);
-
- g_signal_emit (notifier, signals[FILE_CREATED], 0, canonical);
-
- if (tracker_indexing_tree_file_is_root (priv->indexing_tree, canonical)) {
- break;
- }
-
- parent = g_file_get_parent (canonical);
- }
-}
-
-/* Monitor signal handlers */
-static void
-monitor_item_created_cb (TrackerMonitor *monitor,
- GFile *file,
- gboolean is_directory,
- gpointer user_data)
-{
- TrackerFileNotifier *notifier = user_data;
- TrackerFileNotifierPrivate *priv;
- GFileType file_type;
- GFile *canonical;
- gboolean indexable;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- file_type = (is_directory) ? G_FILE_TYPE_DIRECTORY : G_FILE_TYPE_REGULAR;
-
- indexable = tracker_indexing_tree_file_is_indexable (priv->indexing_tree,
- file, file_type);
-
- if (!is_directory) {
- gboolean parent_indexable;
- GList *children;
- GFile *parent;
-
- parent = g_file_get_parent (file);
-
- if (parent) {
- children = g_list_prepend (NULL, file);
- parent_indexable = tracker_indexing_tree_parent_is_indexable (priv->indexing_tree,
- parent,
- children);
- g_list_free (children);
-
- if (!parent_indexable) {
- /* New file triggered a directory content
- * filter, remove parent directory altogether
- */
- canonical = tracker_file_system_get_file (priv->file_system,
- parent, G_FILE_TYPE_DIRECTORY,
- NULL);
- g_object_unref (parent);
-
- g_object_ref (canonical);
- g_signal_emit (notifier, signals[FILE_DELETED], 0, canonical);
- file_notifier_current_root_check_remove_directory (notifier, canonical);
- tracker_file_system_forget_files (priv->file_system, canonical,
- G_FILE_TYPE_UNKNOWN);
-
- tracker_monitor_remove_recursively (priv->monitor, canonical);
-
- g_object_unref (canonical);
- return;
- }
-
- g_object_unref (parent);
- }
-
- if (!indexable)
- return;
- } else {
- TrackerDirectoryFlags flags;
-
- if (!indexable)
- return;
-
- /* If config for the directory is recursive,
- * Crawl new entire directory and add monitors
- */
- tracker_indexing_tree_get_root (priv->indexing_tree,
- file, &flags);
-
- if (flags & TRACKER_DIRECTORY_FLAG_RECURSE) {
- canonical = tracker_file_system_get_file (priv->file_system,
- file,
- file_type,
- NULL);
- notifier_queue_root (notifier, canonical, flags, TRUE);
-
- /* Fall though, we want ::file-created to be emitted
- * ASAP so it is ensured to be processed before any
- * possible monitor events we might get afterwards.
- */
- }
- }
-
- tracker_file_notifier_ensure_parents (notifier, file);
-
- /* Fetch the interned copy */
- canonical = tracker_file_system_get_file (priv->file_system,
- file, file_type, NULL);
-
- g_signal_emit (notifier, signals[FILE_CREATED], 0, canonical);
-
- if (!is_directory) {
- tracker_file_system_forget_files (priv->file_system, canonical,
- G_FILE_TYPE_REGULAR);
- }
-}
-
-static void
-monitor_item_updated_cb (TrackerMonitor *monitor,
- GFile *file,
- gboolean is_directory,
- gpointer user_data)
-{
- TrackerFileNotifier *notifier = user_data;
- TrackerFileNotifierPrivate *priv;
- GFileType file_type;
- GFile *canonical;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- file_type = (is_directory) ? G_FILE_TYPE_DIRECTORY : G_FILE_TYPE_REGULAR;
-
- if (!tracker_indexing_tree_file_is_indexable (priv->indexing_tree,
- file, file_type)) {
- /* File should not be indexed */
- return;
- }
-
- tracker_file_notifier_ensure_parents (notifier, file);
-
- /* Fetch the interned copy */
- canonical = tracker_file_system_get_file (priv->file_system,
- file, file_type, NULL);
- g_signal_emit (notifier, signals[FILE_UPDATED], 0, canonical, FALSE);
-
- if (!is_directory) {
- tracker_file_system_forget_files (priv->file_system, canonical,
- G_FILE_TYPE_REGULAR);
- }
-}
-
-static void
-monitor_item_attribute_updated_cb (TrackerMonitor *monitor,
- GFile *file,
- gboolean is_directory,
- gpointer user_data)
-{
- TrackerFileNotifier *notifier = user_data;
- TrackerFileNotifierPrivate *priv;
- GFile *canonical;
- GFileType file_type;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- file_type = (is_directory) ? G_FILE_TYPE_DIRECTORY : G_FILE_TYPE_REGULAR;
-
- if (!tracker_indexing_tree_file_is_indexable (priv->indexing_tree,
- file, file_type)) {
- /* File should not be indexed */
- return;
- }
-
- /* Fetch the interned copy */
- canonical = tracker_file_system_get_file (priv->file_system,
- file, file_type, NULL);
- g_signal_emit (notifier, signals[FILE_UPDATED], 0, canonical, TRUE);
-
- if (!is_directory) {
- tracker_file_system_forget_files (priv->file_system, canonical,
- G_FILE_TYPE_REGULAR);
- }
-}
-
-static void
-monitor_item_deleted_cb (TrackerMonitor *monitor,
- GFile *file,
- gboolean is_directory,
- gpointer user_data)
-{
- TrackerFileNotifier *notifier = user_data;
- TrackerFileNotifierPrivate *priv;
- GFile *canonical;
- GFileType file_type;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- file_type = (is_directory) ? G_FILE_TYPE_DIRECTORY : G_FILE_TYPE_REGULAR;
-
- /* Remove monitors if any */
- if (is_directory &&
- tracker_indexing_tree_file_is_root (priv->indexing_tree, file)) {
- tracker_monitor_remove_children_recursively (priv->monitor,
- file);
- } else if (is_directory) {
- tracker_monitor_remove_recursively (priv->monitor, file);
- }
-
- if (!is_directory) {
- TrackerDirectoryFlags flags;
- gboolean indexable;
- GList *children;
- GFile *parent;
-
- children = g_list_prepend (NULL, file);
- parent = g_file_get_parent (file);
-
- indexable = tracker_indexing_tree_parent_is_indexable (priv->indexing_tree,
- parent, children);
- g_list_free (children);
-
- /* note: This supposedly works, but in practice
- * won't ever happen as we don't get monitor events
- * from directories triggering a filter of type
- * TRACKER_FILTER_PARENT_DIRECTORY.
- */
- if (!indexable) {
- /* New file was triggering a directory content
- * filter, reindex parent directory altogether
- */
- canonical = tracker_file_system_get_file (priv->file_system,
- parent,
- G_FILE_TYPE_DIRECTORY,
- NULL);
- tracker_indexing_tree_get_root (priv->indexing_tree,
- canonical, &flags);
- notifier_queue_root (notifier, canonical, flags, FALSE);
- return;
- }
-
- g_object_unref (parent);
- }
-
- if (!tracker_indexing_tree_file_is_indexable (priv->indexing_tree,
- file, file_type)) {
- /* File was not indexed */
- return ;
- }
-
- /* Fetch the interned copy */
- canonical = tracker_file_system_get_file (priv->file_system,
- file, file_type, NULL);
-
- /* tracker_file_system_forget_files() might already have been
- * called on this file. In this case, the object might become
- * invalid when returning from g_signal_emit(). Take a
- * reference in order to prevent that.
- */
- g_object_ref (canonical);
- g_signal_emit (notifier, signals[FILE_DELETED], 0, canonical);
-
- file_notifier_current_root_check_remove_directory (notifier, canonical);
-
- /* Remove the file from the cache (works recursively for directories) */
- tracker_file_system_forget_files (priv->file_system,
- canonical,
- G_FILE_TYPE_UNKNOWN);
- g_object_unref (canonical);
-}
-
-static gboolean
-extension_changed (GFile *file1,
- GFile *file2)
-{
- gchar *basename1, *basename2;
- const gchar *ext1, *ext2;
- gboolean changed;
-
- basename1 = g_file_get_basename (file1);
- basename2 = g_file_get_basename (file2);
-
- ext1 = strrchr (basename1, '.');
- ext2 = strrchr (basename2, '.');
-
- changed = g_strcmp0 (ext1, ext2) != 0;
-
- g_free (basename1);
- g_free (basename2);
-
- return changed;
-}
-
-static void
-monitor_item_moved_cb (TrackerMonitor *monitor,
- GFile *file,
- GFile *other_file,
- gboolean is_directory,
- gboolean is_source_monitored,
- gpointer user_data)
-{
- TrackerFileNotifier *notifier;
- TrackerFileNotifierPrivate *priv;
- TrackerDirectoryFlags flags;
-
- notifier = user_data;
- priv = tracker_file_notifier_get_instance_private (notifier);
- tracker_indexing_tree_get_root (priv->indexing_tree, other_file, &flags);
-
- if (!is_source_monitored) {
- if (is_directory) {
- /* Remove monitors if any */
- tracker_monitor_remove_recursively (priv->monitor, file);
-
- /* If should recurse, crawl other_file, as content is "new" */
- other_file = tracker_file_system_get_file (priv->file_system,
- other_file,
- G_FILE_TYPE_DIRECTORY,
- NULL);
- notifier_queue_root (notifier, other_file, flags, FALSE);
- }
- /* else, file, do nothing */
- } else {
- gboolean source_stored, should_process_other;
- GFileType file_type;
- GFile *check_file;
-
- if (is_directory) {
- check_file = g_object_ref (file);
- } else {
- check_file = g_file_get_parent (file);
- }
-
- file_type = (is_directory) ? G_FILE_TYPE_DIRECTORY : G_FILE_TYPE_REGULAR;
-
- /* If the (parent) directory is in
- * the filesystem, file is stored
- */
- source_stored = (tracker_file_system_peek_file (priv->file_system,
- check_file) != NULL);
- should_process_other = tracker_indexing_tree_file_is_indexable (priv->indexing_tree,
- other_file,
- file_type);
- g_object_unref (check_file);
-
- file = tracker_file_system_get_file (priv->file_system,
- file, file_type,
- NULL);
- other_file = tracker_file_system_get_file (priv->file_system,
- other_file, file_type,
- NULL);
-
- /* Ref those so they are safe to use after signal emission */
- g_object_ref (file);
- g_object_ref (other_file);
-
- if (!source_stored) {
- /* Destination location should be indexed as if new */
- /* Remove monitors if any */
- if (is_directory) {
- tracker_monitor_remove_recursively (priv->monitor,
- file);
- }
-
- if (should_process_other) {
- gboolean dest_is_recursive;
- TrackerDirectoryFlags flags;
-
- tracker_indexing_tree_get_root (priv->indexing_tree, other_file, &flags);
- dest_is_recursive = (flags & TRACKER_DIRECTORY_FLAG_RECURSE) != 0;
-
- /* Source file was not stored, check dest file as new */
- if (!is_directory || !dest_is_recursive) {
- g_signal_emit (notifier, signals[FILE_CREATED], 0, other_file);
- } else if (is_directory) {
- /* Crawl dest directory */
- notifier_queue_root (notifier, other_file, flags, FALSE);
- }
- }
- /* Else, do nothing else */
- } else if (!should_process_other) {
- /* Delete original location as it moves to be non indexable */
- if (is_directory) {
- tracker_monitor_remove_recursively (priv->monitor,
- file);
- }
-
- g_signal_emit (notifier, signals[FILE_DELETED], 0, file);
- file_notifier_current_root_check_remove_directory (notifier, file);
- } else {
- /* Handle move */
- if (is_directory) {
- gboolean dest_is_recursive, source_is_recursive;
- TrackerDirectoryFlags source_flags;
-
- tracker_monitor_move (priv->monitor,
- file, other_file);
-
- tracker_indexing_tree_get_root (priv->indexing_tree,
- file, &source_flags);
- source_is_recursive = (source_flags & TRACKER_DIRECTORY_FLAG_RECURSE) != 0;
- dest_is_recursive = (flags & TRACKER_DIRECTORY_FLAG_RECURSE) != 0;
-
- if (source_is_recursive && !dest_is_recursive) {
- /* A directory is being moved from a
- * recursive location to a non-recursive
- * one, don't do anything here, and let
- * TrackerMinerFS handle it, see item_move().
- */
- } else if (!source_is_recursive && dest_is_recursive) {
- /* crawl the folder */
- notifier_queue_root (notifier, other_file, flags, TRUE);
- }
- }
-
- g_signal_emit (notifier, signals[FILE_MOVED], 0, file, other_file);
-
- if (extension_changed (file, other_file))
- g_signal_emit (notifier, signals[FILE_UPDATED], 0, other_file, FALSE);
- }
-
- tracker_file_system_forget_files (priv->file_system, file,
- G_FILE_TYPE_REGULAR);
-
- if (!is_directory) {
- tracker_file_system_forget_files (priv->file_system, other_file,
- G_FILE_TYPE_REGULAR);
- }
-
- g_object_unref (other_file);
- g_object_unref (file);
- }
-}
-
-/* Indexing tree signal handlers */
-static void
-indexing_tree_directory_added (TrackerIndexingTree *indexing_tree,
- GFile *directory,
- gpointer user_data)
-{
- TrackerFileNotifier *notifier = user_data;
- TrackerFileNotifierPrivate *priv;
- TrackerDirectoryFlags flags;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- tracker_indexing_tree_get_root (indexing_tree, directory, &flags);
-
- directory = tracker_file_system_get_file (priv->file_system, directory,
- G_FILE_TYPE_DIRECTORY, NULL);
- notifier_queue_root (notifier, directory, flags, FALSE);
-}
-
-static void
-indexing_tree_directory_updated (TrackerIndexingTree *indexing_tree,
- GFile *directory,
- gpointer user_data)
-{
- TrackerFileNotifier *notifier = user_data;
- TrackerFileNotifierPrivate *priv;
- TrackerDirectoryFlags flags;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- tracker_indexing_tree_get_root (indexing_tree, directory, &flags);
- flags |= TRACKER_DIRECTORY_FLAG_CHECK_DELETED;
-
- directory = tracker_file_system_get_file (priv->file_system, directory,
- G_FILE_TYPE_DIRECTORY, NULL);
- notifier_queue_root (notifier, directory, flags, FALSE);
-}
-
-static void
-indexing_tree_directory_removed (TrackerIndexingTree *indexing_tree,
- GFile *directory,
- gpointer user_data)
-{
- TrackerFileNotifier *notifier = user_data;
- TrackerFileNotifierPrivate *priv;
- TrackerDirectoryFlags flags;
- GList *elem;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- /* Flags are still valid at the moment of deletion */
- tracker_indexing_tree_get_root (indexing_tree, directory, &flags);
- directory = tracker_file_system_peek_file (priv->file_system, directory);
-
- if (!directory) {
- /* If the dir has no canonical copy,
- * it wasn't even told to be indexed.
- */
- return;
- }
-
- /* If the folder was being ignored, index/crawl it from scratch */
- if (flags & TRACKER_DIRECTORY_FLAG_IGNORE) {
- GFile *parent;
-
- parent = g_file_get_parent (directory);
-
- if (parent) {
- TrackerDirectoryFlags parent_flags;
-
- tracker_indexing_tree_get_root (indexing_tree,
- parent,
- &parent_flags);
-
- if (parent_flags & TRACKER_DIRECTORY_FLAG_RECURSE) {
- notifier_queue_root (notifier, directory, parent_flags, FALSE);
- } else if (tracker_indexing_tree_file_is_root (indexing_tree,
- parent)) {
- g_signal_emit (notifier, signals[FILE_CREATED],
- 0, directory);
- }
-
- g_object_unref (parent);
- }
- return;
- }
-
- if ((flags & TRACKER_DIRECTORY_FLAG_PRESERVE) == 0) {
- /* Directory needs to be deleted from the store too */
- g_signal_emit (notifier, signals[FILE_DELETED], 0, directory);
- }
-
- elem = g_list_find_custom (priv->pending_index_roots, directory,
- (GCompareFunc) find_directory_root);
-
- if (elem) {
- root_data_free (elem->data);
- priv->pending_index_roots =
- g_list_delete_link (priv->pending_index_roots, elem);
- }
-
- if (priv->current_index_root &&
- directory == priv->current_index_root->root) {
- /* Directory being currently processed */
- tracker_crawler_stop (priv->crawler);
- g_cancellable_cancel (priv->cancellable);
-
- /* If the crawler was already stopped (eg. we're at the querying
- * phase), the current index root won't be cleared.
- */
- g_clear_pointer (&priv->current_index_root, root_data_free);
- notifier_check_next_root (notifier);
- }
-
- /* Remove monitors if any */
- /* FIXME: How do we handle this with 3rd party data_providers? */
- tracker_monitor_remove_recursively (priv->monitor, directory);
-
- /* Remove all files from cache */
- tracker_file_system_forget_files (priv->file_system, directory,
- G_FILE_TYPE_UNKNOWN);
-}
-
-static void
-indexing_tree_child_updated (TrackerIndexingTree *indexing_tree,
- GFile *root,
- GFile *child,
- gpointer user_data)
-{
- TrackerFileNotifier *notifier = user_data;
- TrackerFileNotifierPrivate *priv;
- TrackerDirectoryFlags flags;
- GFileType child_type;
- GFile *canonical;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- child_type = g_file_query_file_type (child,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- NULL);
-
- if (child_type == G_FILE_TYPE_UNKNOWN)
- return;
-
- canonical = tracker_file_system_get_file (priv->file_system,
- child, child_type, NULL);
- tracker_indexing_tree_get_root (indexing_tree, child, &flags);
-
- if (child_type == G_FILE_TYPE_DIRECTORY &&
- (flags & TRACKER_DIRECTORY_FLAG_RECURSE)) {
- flags |= TRACKER_DIRECTORY_FLAG_CHECK_DELETED;
-
- notifier_queue_root (notifier, canonical, flags, FALSE);
- } else if (tracker_indexing_tree_file_is_indexable (priv->indexing_tree,
- canonical, child_type)) {
- g_signal_emit (notifier, signals[FILE_UPDATED], 0, canonical, FALSE);
- }
-}
-
-static void
-tracker_file_notifier_finalize (GObject *object)
-{
- TrackerFileNotifierPrivate *priv;
-
- priv = tracker_file_notifier_get_instance_private (TRACKER_FILE_NOTIFIER (object));
-
- if (priv->indexing_tree) {
- g_object_unref (priv->indexing_tree);
- }
-
- if (priv->data_provider) {
- g_object_unref (priv->data_provider);
- }
-
- if (priv->cancellable) {
- g_cancellable_cancel (priv->cancellable);
- g_object_unref (priv->cancellable);
- }
-
- g_object_unref (priv->crawler);
- g_object_unref (priv->monitor);
- g_object_unref (priv->file_system);
- g_clear_object (&priv->connection);
-
- g_clear_pointer (&priv->current_index_root, root_data_free);
-
- g_list_foreach (priv->pending_index_roots, (GFunc) root_data_free, NULL);
- g_list_free (priv->pending_index_roots);
- g_timer_destroy (priv->timer);
-
- G_OBJECT_CLASS (tracker_file_notifier_parent_class)->finalize (object);
-}
-
-static void
-check_disable_monitor (TrackerFileNotifier *notifier)
-{
- TrackerFileNotifierPrivate *priv;
- TrackerSparqlCursor *cursor;
- gint64 folder_count = 0;
- GError *error = NULL;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- cursor = tracker_sparql_connection_query (priv->connection,
- "SELECT COUNT(?f) { ?f a nfo:Folder }",
- NULL, &error);
-
- if (!error && tracker_sparql_cursor_next (cursor, NULL, &error)) {
- folder_count = tracker_sparql_cursor_get_integer (cursor, 0);
- tracker_sparql_cursor_close (cursor);
- }
-
- if (error) {
- g_warning ("Could not get folder count: %s\n", error->message);
- g_error_free (error);
- } else if (folder_count > tracker_monitor_get_limit (priv->monitor)) {
- /* If the folder count exceeds the monitor limit, there's
- * nothing we can do anyway to prevent possibly out of date
- * content. As it is the case no matter what we try, fully
- * embrace it instead, and disable monitors until after crawling
- * has been performed. This dramatically improves crawling time
- * as monitors are inherently expensive.
- */
- g_info ("Temporarily disabling monitors until crawling is "
- "completed. Too many folders to monitor anyway");
- tracker_monitor_set_enabled (priv->monitor, FALSE);
- }
-
- g_clear_object (&cursor);
-}
-
-static void
-tracker_file_notifier_constructed (GObject *object)
-{
- TrackerFileNotifierPrivate *priv;
- GFile *root;
-
- G_OBJECT_CLASS (tracker_file_notifier_parent_class)->constructed (object);
-
- priv = tracker_file_notifier_get_instance_private (TRACKER_FILE_NOTIFIER (object));
- g_assert (priv->indexing_tree);
-
- /* Initialize filesystem and register properties */
- root = tracker_indexing_tree_get_master_root (priv->indexing_tree);
- priv->file_system = tracker_file_system_new (root);
-
- g_signal_connect (priv->indexing_tree, "directory-added",
- G_CALLBACK (indexing_tree_directory_added), object);
- g_signal_connect (priv->indexing_tree, "directory-updated",
- G_CALLBACK (indexing_tree_directory_updated), object);
- g_signal_connect (priv->indexing_tree, "directory-removed",
- G_CALLBACK (indexing_tree_directory_removed), object);
- g_signal_connect (priv->indexing_tree, "child-updated",
- G_CALLBACK (indexing_tree_child_updated), object);
-
- /* Set up crawler */
- priv->crawler = tracker_crawler_new (priv->data_provider);
- tracker_crawler_set_file_attributes (priv->crawler,
- G_FILE_ATTRIBUTE_TIME_MODIFIED ","
- G_FILE_ATTRIBUTE_STANDARD_TYPE);
-
- g_signal_connect (priv->crawler, "check-file",
- G_CALLBACK (crawler_check_file_cb),
- object);
- g_signal_connect (priv->crawler, "check-directory",
- G_CALLBACK (crawler_check_directory_cb),
- object);
- g_signal_connect (priv->crawler, "check-directory-contents",
- G_CALLBACK (crawler_check_directory_contents_cb),
- object);
- g_signal_connect (priv->crawler, "directory-crawled",
- G_CALLBACK (crawler_directory_crawled_cb),
- object);
- g_signal_connect (priv->crawler, "finished",
- G_CALLBACK (crawler_finished_cb),
- object);
-
- check_disable_monitor (TRACKER_FILE_NOTIFIER (object));
-}
-
-static void
-tracker_file_notifier_real_finished (TrackerFileNotifier *notifier)
-{
- TrackerFileNotifierPrivate *priv;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- if (!tracker_monitor_get_enabled (priv->monitor)) {
- /* If the monitor was disabled on ::constructed (see
- * check_disable_monitor()), enable it back again.
- * This will lazily create all missing directory
- * monitors.
- */
- g_info ("Re-enabling directory monitors");
- tracker_monitor_set_enabled (priv->monitor, TRUE);
- }
-}
-
-static void
-tracker_file_notifier_class_init (TrackerFileNotifierClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = tracker_file_notifier_finalize;
- object_class->set_property = tracker_file_notifier_set_property;
- object_class->get_property = tracker_file_notifier_get_property;
- object_class->constructed = tracker_file_notifier_constructed;
-
- klass->finished = tracker_file_notifier_real_finished;
-
- signals[FILE_CREATED] =
- g_signal_new ("file-created",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (TrackerFileNotifierClass,
- file_created),
- NULL, NULL,
- NULL,
- G_TYPE_NONE,
- 1, G_TYPE_FILE);
- signals[FILE_UPDATED] =
- g_signal_new ("file-updated",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (TrackerFileNotifierClass,
- file_updated),
- NULL, NULL,
- NULL,
- G_TYPE_NONE,
- 2, G_TYPE_FILE, G_TYPE_BOOLEAN);
- signals[FILE_DELETED] =
- g_signal_new ("file-deleted",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (TrackerFileNotifierClass,
- file_deleted),
- NULL, NULL,
- NULL,
- G_TYPE_NONE,
- 1, G_TYPE_FILE);
- signals[FILE_MOVED] =
- g_signal_new ("file-moved",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (TrackerFileNotifierClass,
- file_moved),
- NULL, NULL,
- NULL,
- G_TYPE_NONE,
- 2, G_TYPE_FILE, G_TYPE_FILE);
- signals[DIRECTORY_STARTED] =
- g_signal_new ("directory-started",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (TrackerFileNotifierClass,
- directory_started),
- NULL, NULL,
- NULL,
- G_TYPE_NONE,
- 1, G_TYPE_FILE);
- signals[DIRECTORY_FINISHED] =
- g_signal_new ("directory-finished",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (TrackerFileNotifierClass,
- directory_finished),
- NULL, NULL,
- NULL,
- G_TYPE_NONE,
- 5, G_TYPE_FILE, G_TYPE_UINT,
- G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
- signals[FINISHED] =
- g_signal_new ("finished",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (TrackerFileNotifierClass,
- finished),
- NULL, NULL,
- NULL,
- G_TYPE_NONE, 0, G_TYPE_NONE);
-
- g_object_class_install_property (object_class,
- PROP_INDEXING_TREE,
- g_param_spec_object ("indexing-tree",
- "Indexing tree",
- "Indexing tree",
- TRACKER_TYPE_INDEXING_TREE,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY));
- g_object_class_install_property (object_class,
- PROP_DATA_PROVIDER,
- g_param_spec_object ("data-provider",
- "Data provider",
- "Data provider to use to crawl structures populating data, e.g. like GFileEnumerator",
- TRACKER_TYPE_DATA_PROVIDER,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY));
- g_object_class_install_property (object_class,
- PROP_CONNECTION,
- g_param_spec_object ("connection",
- "Connection",
- "Connection to use for queries",
- TRACKER_SPARQL_TYPE_CONNECTION,
- G_PARAM_READWRITE |
- G_PARAM_CONSTRUCT_ONLY));
-
- /* Initialize property quarks */
- quark_property_iri = g_quark_from_static_string ("tracker-property-iri");
- tracker_file_system_register_property (quark_property_iri, g_free);
-
- quark_property_store_mtime = g_quark_from_static_string ("tracker-property-store-mtime");
- tracker_file_system_register_property (quark_property_store_mtime,
- g_free);
-
- quark_property_filesystem_mtime = g_quark_from_static_string ("tracker-property-filesystem-mtime");
- tracker_file_system_register_property (quark_property_filesystem_mtime,
- g_free);
-
- force_check_updated = g_getenv ("TRACKER_MINER_FORCE_CHECK_UPDATED") != NULL;
-}
-
-static void
-tracker_file_notifier_init (TrackerFileNotifier *notifier)
-{
- TrackerFileNotifierPrivate *priv;
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- priv->timer = g_timer_new ();
- priv->stopped = TRUE;
-
- /* Set up monitor */
- priv->monitor = tracker_monitor_new ();
-
- g_signal_connect (priv->monitor, "item-created",
- G_CALLBACK (monitor_item_created_cb),
- notifier);
- g_signal_connect (priv->monitor, "item-updated",
- G_CALLBACK (monitor_item_updated_cb),
- notifier);
- g_signal_connect (priv->monitor, "item-attribute-updated",
- G_CALLBACK (monitor_item_attribute_updated_cb),
- notifier);
- g_signal_connect (priv->monitor, "item-deleted",
- G_CALLBACK (monitor_item_deleted_cb),
- notifier);
- g_signal_connect (priv->monitor, "item-moved",
- G_CALLBACK (monitor_item_moved_cb),
- notifier);
-}
-
-TrackerFileNotifier *
-tracker_file_notifier_new (TrackerIndexingTree *indexing_tree,
- TrackerDataProvider *data_provider,
- TrackerSparqlConnection *connection)
-{
- g_return_val_if_fail (TRACKER_IS_INDEXING_TREE (indexing_tree), NULL);
-
- return g_object_new (TRACKER_TYPE_FILE_NOTIFIER,
- "indexing-tree", indexing_tree,
- "data-provider", data_provider,
- "connection", connection,
- NULL);
-}
-
-gboolean
-tracker_file_notifier_start (TrackerFileNotifier *notifier)
-{
- TrackerFileNotifierPrivate *priv;
-
- g_return_val_if_fail (TRACKER_IS_FILE_NOTIFIER (notifier), FALSE);
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- if (priv->stopped) {
- priv->stopped = FALSE;
-
- if (priv->pending_index_roots) {
- crawl_directories_start (notifier);
- } else {
- g_signal_emit (notifier, signals[FINISHED], 0);
- }
- }
-
- return TRUE;
-}
-
-void
-tracker_file_notifier_stop (TrackerFileNotifier *notifier)
-{
- TrackerFileNotifierPrivate *priv;
-
- g_return_if_fail (TRACKER_IS_FILE_NOTIFIER (notifier));
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- if (!priv->stopped) {
- tracker_crawler_stop (priv->crawler);
-
- g_clear_pointer (&priv->current_index_root, root_data_free);
- g_cancellable_cancel (priv->cancellable);
- priv->stopped = TRUE;
- }
-}
-
-gboolean
-tracker_file_notifier_is_active (TrackerFileNotifier *notifier)
-{
- TrackerFileNotifierPrivate *priv;
-
- g_return_val_if_fail (TRACKER_IS_FILE_NOTIFIER (notifier), FALSE);
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- return priv->pending_index_roots || priv->current_index_root;
-}
-
-const gchar *
-tracker_file_notifier_get_file_iri (TrackerFileNotifier *notifier,
- GFile *file,
- gboolean force)
-{
- TrackerFileNotifierPrivate *priv;
- GFile *canonical;
- gchar *iri = NULL;
- gboolean found;
-
- g_return_val_if_fail (TRACKER_IS_FILE_NOTIFIER (notifier), NULL);
- g_return_val_if_fail (G_IS_FILE (file), NULL);
-
- priv = tracker_file_notifier_get_instance_private (notifier);
-
- if (G_UNLIKELY (priv->connection == NULL)) {
- return NULL;
- }
-
- canonical = tracker_file_system_get_file (priv->file_system,
- file,
- G_FILE_TYPE_REGULAR,
- NULL);
- if (!canonical) {
- return NULL;
- }
-
- found = tracker_file_system_get_property_full (priv->file_system,
- canonical,
- quark_property_iri,
- (gpointer *) &iri);
-
- if (found && !iri) {
- /* NULL here mean the file iri was "invalidated", the file
- * was inserted by a previous event, so it has an unknown iri,
- * and further updates are keeping the file object alive.
- *
- * When these updates are processed, they'll need fetching the
- * file IRI again, so we force here extraction for these cases.
- */
- force = TRUE;
- }
-
- if (!iri && force) {
- TrackerSparqlCursor *cursor;
- const gchar *str;
- gchar *sparql;
-
- /* Fetch data for this file synchronously */
- sparql = sparql_files_compose_query (&file, 1);
- cursor = tracker_sparql_connection_query (priv->connection,
- sparql, NULL, NULL);
- g_free (sparql);
-
- if (!cursor)
- return NULL;
-
- if (!tracker_sparql_cursor_next (cursor, NULL, NULL)) {
- g_object_unref (cursor);
- return NULL;
- }
-
- str = tracker_sparql_cursor_get_string (cursor, 1, NULL);
- iri = g_strdup (str);
- tracker_file_system_set_property (priv->file_system, canonical,
- quark_property_iri, iri);
- g_object_unref (cursor);
- }
-
- return iri;
-}
-
-static gboolean
-file_notifier_invalidate_file_iri_foreach (GFile *file,
- gpointer user_data)
-{
- TrackerFileSystem *file_system = user_data;
-
- tracker_file_system_set_property (file_system,
- file,
- quark_property_iri,
- NULL);
-
- return FALSE;
-}
-
-void
-tracker_file_notifier_invalidate_file_iri (TrackerFileNotifier *notifier,
- GFile *file,
- gboolean recursive)
-{
- TrackerFileNotifierPrivate *priv;
- GFile *canonical;
-
- g_return_if_fail (TRACKER_IS_FILE_NOTIFIER (notifier));
- g_return_if_fail (G_IS_FILE (file));
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- canonical = tracker_file_system_peek_file (priv->file_system, file);
- if (!canonical) {
- return;
- }
-
- if (!recursive) {
- /* Set a NULL iri, so we make sure to look it up afterwards */
- tracker_file_system_set_property (priv->file_system,
- canonical,
- quark_property_iri,
- NULL);
- return;
- }
-
- tracker_file_system_traverse (priv->file_system,
- canonical,
- G_PRE_ORDER,
- file_notifier_invalidate_file_iri_foreach,
- -1,
- priv->file_system);
-}
-
-GFileType
-tracker_file_notifier_get_file_type (TrackerFileNotifier *notifier,
- GFile *file)
-{
- TrackerFileNotifierPrivate *priv;
- GFile *canonical;
-
- g_return_val_if_fail (TRACKER_IS_FILE_NOTIFIER (notifier), G_FILE_TYPE_UNKNOWN);
- g_return_val_if_fail (G_IS_FILE (file), G_FILE_TYPE_UNKNOWN);
-
- priv = tracker_file_notifier_get_instance_private (notifier);
- canonical = tracker_file_system_get_file (priv->file_system,
- file,
- G_FILE_TYPE_REGULAR,
- NULL);
- if (!canonical) {
- return G_FILE_TYPE_UNKNOWN;
- }
-
- return tracker_file_system_get_file_type (priv->file_system, canonical);
-}