/* * Copyright (C) 2014 Carlos Garnacho * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "config.h" #include #include #include #include "tracker-decorator-private.h" #include "tracker-decorator-fs.h" /** * SECTION:tracker-decorator-fs * @short_description: Filesystem implementation for TrackerDecorator * @include: libtracker-miner/tracker-miner.h * @title: TrackerDecoratorFS * @see_also: #TrackerDecorator * * #TrackerDecoratorFS is used to handle extended metadata extraction * for resources on file systems that are mounted or unmounted. **/ typedef struct _TrackerDecoratorFSPrivate TrackerDecoratorFSPrivate; struct _TrackerDecoratorFSPrivate { GVolumeMonitor *volume_monitor; }; static GInitableIface *parent_initable_iface; static void tracker_decorator_fs_initable_iface_init (GInitableIface *iface); G_DEFINE_ABSTRACT_TYPE_WITH_CODE (TrackerDecoratorFS, tracker_decorator_fs, TRACKER_TYPE_DECORATOR, G_ADD_PRIVATE (TrackerDecoratorFS) G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, tracker_decorator_fs_initable_iface_init)) static void tracker_decorator_fs_finalize (GObject *object) { TrackerDecoratorFSPrivate *priv; priv = TRACKER_DECORATOR_FS (object)->priv; if (priv->volume_monitor) g_object_unref (priv->volume_monitor); G_OBJECT_CLASS (tracker_decorator_fs_parent_class)->finalize (object); } static void tracker_decorator_fs_class_init (TrackerDecoratorFSClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = tracker_decorator_fs_finalize; } static void process_files_cb (GObject *object, GAsyncResult *result, gpointer user_data) { TrackerSparqlConnection *conn; TrackerSparqlCursor *cursor; GError *error = NULL; conn = TRACKER_SPARQL_CONNECTION (object); cursor = tracker_sparql_connection_query_finish (conn, result, &error); if (error) { g_critical ("Could not check files on mount point for missing metadata: %s", error->message); g_error_free (error); return; } while (tracker_sparql_cursor_next (cursor, NULL, NULL)) { gint id = tracker_sparql_cursor_get_integer (cursor, 0); gint class_name_id = tracker_sparql_cursor_get_integer (cursor, 1); tracker_decorator_prepend_id (TRACKER_DECORATOR (user_data), id, class_name_id); } g_object_unref (cursor); } static void remove_files_cb (GObject *object, GAsyncResult *result, gpointer user_data) { TrackerSparqlConnection *conn; TrackerSparqlCursor *cursor; GError *error = NULL; conn = TRACKER_SPARQL_CONNECTION (object); cursor = tracker_sparql_connection_query_finish (conn, result, &error); if (error) { g_critical ("Could not remove files on mount point with missing metadata: %s", error->message); g_error_free (error); return; } while (tracker_sparql_cursor_next (cursor, NULL, NULL)) { gint id = tracker_sparql_cursor_get_integer (cursor, 0); tracker_decorator_delete_id (TRACKER_DECORATOR (user_data), id); } g_object_unref (cursor); } static void _tracker_decorator_query_append_rdf_type_filter (TrackerDecorator *decorator, GString *query) { const gchar **class_names; gint i = 0; class_names = tracker_decorator_get_class_names (decorator); if (!class_names || !*class_names) return; g_string_append (query, "&& ?type IN ("); while (class_names[i]) { if (i != 0) g_string_append (query, ","); g_string_append (query, class_names[i]); i++; } g_string_append (query, ") "); } static void check_files (TrackerDecorator *decorator, const gchar *mount_point_urn, gboolean available, GAsyncReadyCallback callback) { TrackerSparqlConnection *sparql_conn; const gchar *data_source; GString *query; data_source = tracker_decorator_get_data_source (decorator); query = g_string_new ("SELECT tracker:id(?urn) tracker:id(?type) { ?urn "); if (mount_point_urn) { g_string_append_printf (query, " nie:dataSource <%s> ;", mount_point_urn); } g_string_append (query, " a nfo:FileDataObject ;" " a ?type ."); g_string_append_printf (query, "FILTER (! EXISTS { ?urn nie:dataSource <%s> } ", data_source); _tracker_decorator_query_append_rdf_type_filter (decorator, query); if (available) g_string_append (query, "&& BOUND(tracker:available(?urn))"); g_string_append (query, ")}"); sparql_conn = tracker_miner_get_connection (TRACKER_MINER (decorator)); tracker_sparql_connection_query_async (sparql_conn, query->str, NULL, callback, decorator); g_string_free (query, TRUE); } static inline gchar * mount_point_get_uuid (GMount *mount) { GVolume *volume; gchar *uuid = NULL; volume = g_mount_get_volume (mount); if (volume) { uuid = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_UUID); if (!uuid) { gchar *mount_name; mount_name = g_mount_get_name (mount); uuid = g_compute_checksum_for_string (G_CHECKSUM_MD5, mount_name, -1); g_free (mount_name); } g_object_unref (volume); } return uuid; } static void mount_point_added_cb (GVolumeMonitor *monitor, GMount *mount, gpointer user_data) { gchar *uuid; gchar *urn; uuid = mount_point_get_uuid (mount); urn = g_strdup_printf (TRACKER_PREFIX_DATASOURCE_URN "%s", uuid); check_files (user_data, urn, TRUE, process_files_cb); g_free (urn); g_free (uuid); } static void mount_point_removed_cb (GVolumeMonitor *monitor, GMount *mount, gpointer user_data) { gchar *uuid; gchar *urn; uuid = mount_point_get_uuid (mount); urn = g_strdup_printf (TRACKER_PREFIX_DATASOURCE_URN "%s", uuid); _tracker_decorator_invalidate_cache (user_data); check_files (user_data, urn, FALSE, remove_files_cb); g_free (urn); g_free (uuid); } static gboolean tracker_decorator_fs_iface_init (GInitable *initable, GCancellable *cancellable, GError **error) { TrackerDecoratorFSPrivate *priv; priv = TRACKER_DECORATOR_FS (initable)->priv; priv->volume_monitor = g_volume_monitor_get (); g_signal_connect_object (priv->volume_monitor, "mount-added", G_CALLBACK (mount_point_added_cb), initable, 0); g_signal_connect_object (priv->volume_monitor, "mount-pre-unmount", G_CALLBACK (mount_point_removed_cb), initable, 0); g_signal_connect_object (priv->volume_monitor, "mount-removed", G_CALLBACK (mount_point_removed_cb), initable, 0); return parent_initable_iface->init (initable, cancellable, error); } static void tracker_decorator_fs_initable_iface_init (GInitableIface *iface) { parent_initable_iface = g_type_interface_peek_parent (iface); iface->init = tracker_decorator_fs_iface_init; } static void tracker_decorator_fs_init (TrackerDecoratorFS *decorator) { decorator->priv = tracker_decorator_fs_get_instance_private (decorator); } /** * tracker_decorator_fs_prepend_file: * @decorator: a #TrackerDecoratorFS * @file: a #GFile to process * * Prepends a file for processing. * * Returns: the tracker:id of the element corresponding to the file * * Since: 1.2 **/ gint tracker_decorator_fs_prepend_file (TrackerDecoratorFS *decorator, GFile *file) { TrackerSparqlConnection *sparql_conn; TrackerSparqlCursor *cursor; gchar *query, *uri; gint id, class_id; g_return_val_if_fail (TRACKER_IS_DECORATOR_FS (decorator), 0); g_return_val_if_fail (G_IS_FILE (file), 0); uri = g_file_get_uri (file); query = g_strdup_printf ("SELECT tracker:id(?urn) tracker:id(?type) {" " ?urn a ?type; nie:url \"%s\" " "}", uri); g_free (uri); sparql_conn = tracker_miner_get_connection (TRACKER_MINER (decorator)); cursor = tracker_sparql_connection_query (sparql_conn, query, NULL, NULL); g_free (query); if (!cursor) return 0; if (!tracker_sparql_cursor_next (cursor, NULL, NULL)) { g_object_unref (cursor); return 0; } id = tracker_sparql_cursor_get_integer (cursor, 0); class_id = tracker_sparql_cursor_get_integer (cursor, 1); tracker_decorator_prepend_id (TRACKER_DECORATOR (decorator), id, class_id); g_object_unref (cursor); return id; }