[tracker-miners/wip/carlosg/better-stable-ids] libtracker-miners-common: Use better stable filesystem identifiers




commit 9e2da12914cef5a868b799ab63629071ca5fea6e
Author: Carlos Garnacho <carlosg gnome org>
Date:   Fri Jan 14 16:57:05 2022 +0100

    libtracker-miners-common: Use better stable filesystem identifiers
    
    Our new stable identifiers come in the `urn:fileid:$FS_ID:$INODE/$SUFFIX`
    format, where $FS_ID is a stable identifier for the filesystem. We
    currently use G_FILE_ATTRIBUTE_ID_FILESYSTEM for that, but that may differ
    in some circumstances, e.g. removable mounts inserted in different order.
    
    Try harder at obtaining a stable identifier for the filesystem, that will
    not change on these runtime conditions. We prefer identifiers in this
    order:
    
    - If the mount entry node is an actual partition (e.g. /dev/sda3), look
      up the filesystem UUID with blkid
    - If the mount entry points to a non-physical partition (e.g.
      /dev/mapper/luks-$UUID, or $HOST:$FOLDER with NFS), the mount entry
      device name is used.
    - If none of these are found (e.g. tmpfs), we still resort to
      G_FILE_ATTRIBUTE_ID_FILESYSTEM.
    
    These identifiers are cached for all available mount entries in mtab
    for fast lookups, and are updated on mount entry changes.

 meson.build                                       |   1 +
 src/libtracker-miner/tracker-miner-fs.c           |   2 +-
 src/libtracker-miners-common/meson.build          |   2 +-
 src/libtracker-miners-common/tracker-file-utils.c | 168 +++++++++++++++++++++-
 4 files changed, 164 insertions(+), 9 deletions(-)
---
diff --git a/meson.build b/meson.build
index ae2b497cd..907574b05 100644
--- a/meson.build
+++ b/meson.build
@@ -84,6 +84,7 @@ libxml2 = dependency('libxml-2.0', version: '>= 2.6', required: get_option('xml'
 poppler = dependency('poppler-glib', version: '>= 0.16.0', required: get_option('pdf'))
 totem_plparser = dependency('totem-plparser', required: get_option('playlist'))
 upower = dependency('upower-glib', version: '>= 0.9.0', required: false)
+blkid = dependency('blkid', required: true)
 
 libgif = cc.find_library('gif', required: get_option('gif'))
 libmath = cc.find_library('m', required: false)
diff --git a/src/libtracker-miner/tracker-miner-fs.c b/src/libtracker-miner/tracker-miner-fs.c
index f7b2023ce..9adf448a4 100644
--- a/src/libtracker-miner/tracker-miner-fs.c
+++ b/src/libtracker-miner/tracker-miner-fs.c
@@ -1969,7 +1969,7 @@ tracker_miner_fs_get_folder_urn (TrackerMinerFS *fs,
        info = g_file_query_info (file,
                                  G_FILE_ATTRIBUTE_STANDARD_TYPE ","
                                  G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN ","
-                                 G_FILE_ATTRIBUTE_ID_FILE,
+                                 G_FILE_ATTRIBUTE_UNIX_INODE,
                                  G_FILE_QUERY_INFO_NONE,
                                  NULL,
                                  NULL);
diff --git a/src/libtracker-miners-common/meson.build b/src/libtracker-miners-common/meson.build
index 06e91d870..3536748e1 100644
--- a/src/libtracker-miners-common/meson.build
+++ b/src/libtracker-miners-common/meson.build
@@ -27,7 +27,7 @@ tracker_miners_common_sources = [
 
 tracker_miners_common_dependencies = [glib, gio, gio_unix, libmath]
 
-tracker_miners_common_private_dependencies = [charset_library]
+tracker_miners_common_private_dependencies = [charset_library, blkid]
 if libseccomp.found()
   tracker_miners_common_private_dependencies += [libseccomp]
 endif
diff --git a/src/libtracker-miners-common/tracker-file-utils.c 
b/src/libtracker-miners-common/tracker-file-utils.c
index 78064e714..81ec2439b 100644
--- a/src/libtracker-miners-common/tracker-file-utils.c
+++ b/src/libtracker-miners-common/tracker-file-utils.c
@@ -34,9 +34,12 @@
 #include <sys/statfs.h>
 #endif
 
+#include <blkid.h>
+
 #include <glib.h>
 #include <glib/gstdio.h>
 #include <gio/gio.h>
+#include <gio/gunixmounts.h>
 
 #include "tracker-file-utils.h"
 #include "tracker-type-utils.h"
@@ -721,19 +724,169 @@ tracker_filename_casecmp_without_extension (const gchar *a,
        return g_ascii_strncasecmp (a, b, len_a) == 0;
 }
 
+typedef struct {
+       gchar *mount_point;
+       gchar *id;
+} UnixMountInfo;
+
+typedef struct {
+       GUnixMountMonitor *monitor;
+       blkid_cache id_cache;
+       GArray *mounts;
+       GRWLock lock;
+} TrackerUnixMountCache;
+
+static gint
+sort_by_mount (gconstpointer a,
+              gconstpointer b)
+{
+       const UnixMountInfo *info_a =a, *info_b = b;
+
+       return g_strcmp0 (info_a->mount_point, info_b->mount_point);
+}
+
+static void
+clear_mount_info (gpointer user_data)
+{
+       UnixMountInfo *info = user_data;
+
+       g_free (info->mount_point);
+       g_free (info->id);
+}
+
+static void
+update_mounts (TrackerUnixMountCache *cache)
+{
+       GList *mounts;
+       const GList *l;
+
+       g_rw_lock_writer_lock (&cache->lock);
+
+       g_array_set_size (cache->mounts, 0);
+
+       mounts = g_unix_mounts_get (NULL);
+
+       for (l = mounts; l; l = l->next) {
+               GUnixMountEntry *entry = l->data;
+               const gchar *devname, *id;
+               UnixMountInfo mount;
+
+               devname = g_unix_mount_get_device_path (entry);
+               id = g_strdup (blkid_get_tag_value (cache->id_cache, "UUID", devname));
+               if (!id && strchr (devname, G_DIR_SEPARATOR) != NULL)
+                       id = g_strdup (devname);
+
+               if (!id) {
+                       GFileInfo *info;
+                       GFile *file;
+
+                       file = g_file_new_for_path (g_unix_mount_get_mount_path (entry));
+                       info = g_file_query_info (file,
+                                                 G_FILE_ATTRIBUTE_ID_FILESYSTEM,
+                                                 G_FILE_QUERY_INFO_NONE,
+                                                 NULL, NULL);
+                       if (info) {
+                               id = g_strdup (g_file_info_get_attribute_string (info,
+                                                                                
G_FILE_ATTRIBUTE_ID_FILESYSTEM));
+                               g_object_unref (info);
+                       }
+
+                       g_object_unref (file);
+               }
+
+               if (!id)
+                       continue;
+
+               mount.mount_point = g_strdup (g_unix_mount_get_mount_path (entry));
+               mount.id = g_strdup (id);
+               g_array_append_val (cache->mounts, mount);
+       }
+
+       g_array_sort (cache->mounts, sort_by_mount);
+
+       g_rw_lock_writer_unlock (&cache->lock);
+       g_list_free_full (mounts, (GDestroyNotify) g_unix_mount_free);
+}
+
+static void
+on_mounts_changed (GUnixMountMonitor *monitor,
+                  gpointer           user_data)
+{
+       TrackerUnixMountCache *cache = user_data;
+
+       update_mounts (cache);
+}
+
+static TrackerUnixMountCache *
+tracker_unix_mount_cache_get (void)
+{
+       static TrackerUnixMountCache *cache = NULL;
+       TrackerUnixMountCache *obj;
+
+       if (cache == NULL) {
+               obj = g_new0 (TrackerUnixMountCache, 1);
+               g_rw_lock_init (&obj->lock);
+               obj->monitor = g_unix_mount_monitor_get ();
+               obj->mounts = g_array_new (FALSE, FALSE, sizeof (UnixMountInfo));
+               g_array_set_clear_func (obj->mounts, clear_mount_info);
+
+               blkid_get_cache (&obj->id_cache, NULL);
+
+               g_signal_connect (obj->monitor, "mounts-changed",
+                                 G_CALLBACK (on_mounts_changed), obj);
+               update_mounts (obj);
+               cache = obj;
+       }
+
+       return cache;
+}
+
+static const gchar *
+tracker_unix_mount_cache_lookup_filesystem_id (GFile *file)
+{
+       TrackerUnixMountCache *cache;
+       const gchar *id = NULL;
+       gchar *path;
+       gint i;
+
+       cache = tracker_unix_mount_cache_get ();
+
+       g_rw_lock_reader_lock (&cache->lock);
+
+       path = g_file_get_path (file);
+
+       for (i = (gint) cache->mounts->len - 1; i >= 0; i--) {
+               UnixMountInfo *info = &g_array_index (cache->mounts, UnixMountInfo, i);
+               int len = strlen (info->mount_point);
+
+               if (strncmp (info->mount_point, path, len) != 0)
+                       continue;
+               if (path[len] != '\0' && path[len] != G_DIR_SEPARATOR)
+                       continue;
+
+               id = info->id;
+               break;
+       }
+
+       g_rw_lock_reader_unlock (&cache->lock);
+       g_free (path);
+
+       return id;
+}
+
 gchar *
 tracker_file_get_content_identifier (GFile       *file,
                                      GFileInfo   *info,
                                      const gchar *suffix)
 {
        const gchar *id;
-       gchar *str;
+       gchar *inode, *str;
 
        if (info) {
                g_object_ref (info);
        } else {
                info = g_file_query_info (file,
-                                         G_FILE_ATTRIBUTE_ID_FILE,
+                                         G_FILE_ATTRIBUTE_UNIX_INODE,
                                          G_FILE_QUERY_INFO_NONE,
                                          NULL,
                                          NULL);
@@ -741,14 +894,15 @@ tracker_file_get_content_identifier (GFile       *file,
                        return NULL;
        }
 
-       id = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILE);
+       id = tracker_unix_mount_cache_lookup_filesystem_id (file);
+       inode = g_file_info_get_attribute_as_string (info, G_FILE_ATTRIBUTE_UNIX_INODE);
 
-       if (suffix)
-               str = g_strconcat ("urn:fileid:", id, "/", suffix, NULL);
-       else
-               str = g_strconcat ("urn:fileid:", id, NULL);
+       str = g_strconcat ("urn:fileid:", id, ":", inode,
+                          suffix ? "/" : NULL,
+                          suffix, NULL);
 
        g_object_unref (info);
+       g_free (inode);
 
        return str;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]