[tracker-miners/wip/carlosg/better-stable-ids] libtracker-miners-common: Use better stable filesystem identifiers
- From: Carlos Garnacho <carlosg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker-miners/wip/carlosg/better-stable-ids] libtracker-miners-common: Use better stable filesystem identifiers
- Date: Sat, 15 Jan 2022 22:35:15 +0000 (UTC)
commit 32cacca4a615ae345cd51937f4c3d78003a0bee7
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 | 169 +++++++++++++++++++++-
4 files changed, 165 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..f9b3475f8 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,170 @@ 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;
+ gchar *id;
+ UnixMountInfo mount;
+
+ devname = g_unix_mount_get_device_path (entry);
+ id = 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 = 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 +895,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]