[tracker] Add support for tracker-3.0.

Besides the filename and path changes, these changes were needed:

- Tracker 3.3.0-alpha added a function tracker_file_get_content_identifier(),
  which is used for the content identifier. I'm only calling this function
  if we're using API version 3. (TODO: Only for 3.3.0 or later, maybe.)

- tracker_file_get_content_identifier() is part of libtracker-miners-common,
  which is statically linked into every extractor. As such, we can't simply
  dlsym() the function from libtracker_extract. (We *could* get it from one
  of the existing extractors, since they're exporting all of the symbols,
  but that's an implementation detail that could change later.)

- tracker-file-utils.c implements tracker_file_get_content_identifier().
  This file requires libblkid and (optionally) BTRFS_IOC_INO_LOOKUP.
  CMakeLists.txt now checks for those and links in libblkid.

- Add libblkid to other relevant files, plus FindBlkid.cmake.

- Rename the .rule files to 14- so they take precedence over tracker-3's
  own 15-executable.rule and 15-games.rule.
This commit is contained in:
David Korth 2024-03-29 22:53:45 -04:00
parent 57ee1bc649
commit de43b12882
13 changed files with 346 additions and 10 deletions

View File

@ -37,4 +37,5 @@ apt-get -y install \
libgsound-dev \
libgtk-3-dev \
libcairo2-dev \
libnautilus-extension-dev
libnautilus-extension-dev \
libblkid-dev

View File

@ -0,0 +1,22 @@
# Find Blkid libraries and headers.
# If found, the following variables will be defined:
# - Blkid_FOUND: System has Blkid.
# - Blkid_INCLUDE_DIRS: Blkid include directories.
# - Blkid_LIBRARIES: Blkid libraries.
# - Blkid_DEFINITIONS: Compiler switches required for using Blkid.
#
# In addition, a target Blkid::gio will be created with all of
# these definitions.
#
# References:
# - https://cmake.org/Wiki/CMake:How_To_Find_Libraries
# - http://francesco-cek.com/cmake-and-gtk-3-the-easy-way/
#
INCLUDE(FindLibraryPkgConfig)
FIND_LIBRARY_PKG_CONFIG(Blkid
blkid # pkgconfig
blkid/blkid.h # header
blkid # library
Blkid::blkid # imported target
)

3
debian/control vendored
View File

@ -33,7 +33,8 @@ Build-Depends:
gettext,
liblz4-dev,
liblzo2-dev,
libgsound-dev
libgsound-dev,
libblkid-dev
Standards-Version: 3.9.8
Homepage: https://github.com/GerbilSoft/rom-properties
Vcs-Git: https://github.com/GerbilSoft/rom-properties

View File

@ -12,6 +12,7 @@ packages:
* XFCE (GTK+ 3.x): libglib2.0-dev libgtk-3-dev libcairo2-dev libthunarx-3-dev libgsound-dev
* GNOME, MATE, Cinnamon: libglib2.0-dev libgtk-3-dev libcairo2-dev libnautilus-extension-dev libgsound-dev
* GNOME 43: libglib2.0-dev libgtk-4-dev libgdk-pixbuf2.0-dev libnautilus-extension-dev libgsound-dev
* GNOME Tracker: libblkid-dev
NOTE: On older versions of Ubuntu, some packages were different:
* Earlier than 18.04:

View File

@ -6,25 +6,34 @@ FIND_PACKAGE(GLib2 ${REQUIRE_XFCE} ${GLIB_MIN_VERSION})
FIND_PACKAGE(GObject2 ${REQUIRE_XFCE} ${GLIB_MIN_VERSION})
FIND_PACKAGE(GIO ${REQUIRE_XFCE} ${GLIB_MIN_VERSION})
FIND_PACKAGE(GIO-UNIX ${REQUIRE_XFCE} ${GLIB_MIN_VERSION})
IF(GLib2_FOUND AND GObject2_FOUND AND GIO_FOUND AND GIO-UNIX_FOUND)
FIND_PACKAGE(Blkid)
IF(GLib2_FOUND AND GObject2_FOUND AND GIO_FOUND AND GIO-UNIX_FOUND AND Blkid_FOUND)
# All required libraries were found.
ELSE(GLib2_FOUND AND GObject2_FOUND AND GIO_FOUND AND GIO-UNIX_FOUND)
ELSE(GLib2_FOUND AND GObject2_FOUND AND GIO_FOUND AND GIO-UNIX_FOUND AND Blkid_FOUND)
# A required library was not found.
# Disable the Tracker extractor.
SET(BUILD_TRACKER_EXTRACTOR OFF CACHE INTERNAL "Build the Tracker extractor module." FORCE)
ENDIF(GLib2_FOUND AND GObject2_FOUND AND GIO_FOUND AND GIO-UNIX_FOUND)
ENDIF(GLib2_FOUND AND GObject2_FOUND AND GIO_FOUND AND GIO-UNIX_FOUND AND Blkid_FOUND)
# Ensure we don't use functions not available in GLib 2.34.
ADD_DEFINITIONS(-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_34 -DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_34)
# Check if BTRFS_IOC_INO_LOOKUP is defined.
CHECK_SYMBOL_EXISTS(BTRFS_IOC_INO_LOOKUP "linux/btrfs.h" HAVE_BTRFS_IOCTL)
# Write the config.h file.
CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/config.tracker.h.in" "${CMAKE_CURRENT_BINARY_DIR}/config.tracker.h")
SET(${PROJECT_NAME}_SRCS
rp-tracker.cpp
tracker-mini.c
tracker-file-utils.c
)
SET(${PROJECT_NAME}_H
tracker-mini.h
tracker-mini-1.0.h
tracker-mini-2.0.h
tracker-file-utils.h
)
IF(BUILD_TRACKER_EXTRACTOR)
@ -46,6 +55,7 @@ IF(BUILD_TRACKER_EXTRACTOR)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE unixcommon rpsecure)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE romdata)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE GLib2::gio-unix GLib2::gio GLib2::gobject GLib2::glib)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE Blkid::blkid)
# Link in libdl if it's required for dlopen().
IF(CMAKE_DL_LIBS)
TARGET_LINK_LIBRARIES(${PROJECT_NAME} PRIVATE ${CMAKE_DL_LIBS})
@ -63,10 +73,11 @@ IF(0) #BUILD_TRACKER_EXTRACTOR)
# Rule files
# - tracker-1.0: share/tracker/extract-rules/
# - tracker-2.0: share/tracker-miners/extract-rules/
# - tracker-3.0: share/tracker3-miners/extract-rules
SET(RULE_FILES
rules/20-rp-audio.rule
rules/20-rp-rom-images.rule
rules/20-rp-textures.rule
rules/14-rp-audio.rule
rules/14-rp-rom-images.rule
rules/14-rp-textures.rule
)
INSTALL(FILES ${RULE_FILES}
DESTINATION "share/tracker-miners/extract-rules"
@ -76,4 +87,5 @@ IF(0) #BUILD_TRACKER_EXTRACTOR)
# Extractor module
# - tracker-1.0: lib/[arch]/tracker-1.0/extract-modules/libextract-[module].so
# - tracker-2.0: lib/[arch]/tracker-miners-2.0/extract-modules/libextract-[module].so
# - tracker-3.0: lib/[arch]/tracker-miners-3.0/extract-modules/libextract-[module].so
ENDIF(0) #BUILD_TRACKER_EXTRACTOR)

View File

@ -0,0 +1,12 @@
/***************************************************************************
* ROM Properties Page shell extension. (GNOME Tracker) *
* config.tracker.h.in: Tracker configuration. (source file) *
* *
* Copyright (c) 2017-2024 by David Korth. *
* SPDX-License-Identifier: GPL-2.0-or-later *
***************************************************************************/
#pragma once
/* Define to 1 if you have the btrfs `BTRFS_IOC_INO_LOOKUP` ioctl. */
#cmakedefine HAVE_BTRFS_IOCTL 1

View File

@ -7,6 +7,7 @@
***************************************************************************/
#include "tracker-mini.h"
#include "tracker-file-utils.h"
// glib: module handling
#include <gmodule.h>
@ -225,9 +226,10 @@ add_metadata_properties_v2(const RomMetaData *metaData, TrackerResource *resourc
}
}
// NOTE: The "error" parameter was added in tracker-3.0.
extern "C"
G_MODULE_EXPORT gboolean
tracker_extract_get_metadata(TrackerExtractInfo *info)
tracker_extract_get_metadata(TrackerExtractInfo *info, GError **error)
{
// Make sure the Tracker function pointers are initialized.
// TODO: ELF ctor/dtor?
@ -238,6 +240,8 @@ tracker_extract_get_metadata(TrackerExtractInfo *info)
GFile *const file = tracker_extract_pfns.v1.info.get_file(info);
if (!file) {
// TODO: Set error if Tracker 3.0.
((void)error);
return false;
}
@ -255,7 +259,6 @@ tracker_extract_get_metadata(TrackerExtractInfo *info)
TrackerSparqlBuilder *builder;
TrackerResource *resource;
};
printf("API == %d\n", rp_tracker_api);
switch (rp_tracker_api) {
default:
assert(!"Tracker API version is not supported.");
@ -268,6 +271,16 @@ tracker_extract_get_metadata(TrackerExtractInfo *info)
case 2:
resource = tracker_sparql_pfns.v2.resource._new(nullptr);
break;
case 3: {
// NOTE: Only using tracker_file_get_content_identifier() if this is API version 3.
// tracker_file_get_content_identifier() was added to Tracker 3.3.0-alpha.
// TODO: Only if we're using Tracker 3.3.0 or later?
gchar *const resource_uri = tracker_file_get_content_identifier(file, NULL, NULL);
resource = tracker_sparql_pfns.v2.resource._new(resource_uri);
g_free(resource_uri);
break;
}
}
// Determine the file type.
@ -383,6 +396,7 @@ tracker_extract_get_metadata(TrackerExtractInfo *info)
break;
case 2:
case 3:
tracker_sparql_pfns.v2.resource.add_uri(resource, "rdf:type", fileTypes[0]);
if (fileTypes[1]) {
tracker_sparql_pfns.v2.resource.add_uri(resource, "rdf:type", fileTypes[1]);
@ -409,6 +423,7 @@ tracker_extract_get_metadata(TrackerExtractInfo *info)
add_metadata_properties_v1(metaData, builder);
break;
case 2:
case 3:
add_metadata_properties_v2(metaData, resource);
break;
}

View File

@ -2,3 +2,4 @@
ModulePath=libextract-rom-properties.so
MimeTypes=audio/prs.sid;audio/x-adx;audio/x-bcstm;audio/x-bcwav;audio/x-bfstm;audio/x-brstm;audio/x-gbr;audio/x-gbs;audio/x-minipsf;audio/x-nsf;audio/x-psf;audio/x-sap;audio/x-sndh;audio/x-spc;audio/x-vgm;
FallbackRdfTypes=nfo:Audio;
Graph=tracker:Audio

View File

@ -2,3 +2,4 @@
ModulePath=libextract-rom-properties.so
MimeTypes=application/pkix-cert;application/vnd.nintendo.nitro.rom;application/vnd.nintendo.snes.rom;application/x-agb-rom;application/x-atari-7800-rom;application/x-atari-lynx-rom;application/x-c128-cartridge;application/x-c64-cartridge;application/x-cbm2-cartridge;application/x-colecovision-rom;application/x-ctr-cci;application/x-fds-disk;application/x-game-com-rom;application/x-gameboy-advance-rom;application/x-gameboy-color-rom;application/x-gameboy-rom;application/x-gamegear-rom;application/x-gba-rom;application/x-genesis-32x-rom;application/x-genesis-rom;application/x-intellivision-rom;application/x-n64-rom;application/x-neo-geo-pocket-color-rom;application/x-neo-geo-pocket-rom;application/x-nes-rom;application/x-nintendo-3ds-firm;application/x-nintendo-3ds-rom;application/x-nintendo-ds-rom;application/x-nintendo-dsi-rom;application/x-plus4-cartridge;application/x-pokemon-mini-rom;application/x-satellaview-rom;application/x-sega-pico-rom;application/x-sega-teradrive-rom;application/x-sms-rom;application/x-snes-rom;application/x-sufami-turbo-rom;application/x-vic20-cartridge;application/x-virtual-boy-rom;application/x-wonderswan-color-rom;application/x-wonderswan-rom;image/x-3ds;model/x.stl-binary;
FallbackRdfTypes=nfo:Software;
Graph=tracker:Software

View File

@ -2,3 +2,4 @@
ModulePath=libextract-rom-properties.so
MimeTypes=application/tga;application/x-targa;application/x-tga;image/astc;image/ktx2;image/ktx;image/targa;image/tga;image/vnd.ms-dds;image/vnd.valve.source.texture;image/x-dds;image/x-didj-texture;image/x-godot-ctex;image/x-godot-stex;image/x-icb;image/x-pvr;image/x-sega-gvr;image/x-sega-pvr;image/x-sega-pvrx;image/x-sega-svr;image/x-targa;image/x-tga;image/x-vtf3;image/x-vtf;image/x-xbox-xpr0;
FallbackRdfTypes=nfo:Image;nfo:RasterImage;
Graph=tracker:Pictures

View File

@ -0,0 +1,232 @@
/***************************************************************************
* ROM Properties Page shell extension. (GNOME Tracker) *
* tracker-file-utils.h: File utilities from tracker-miners-3.6.2. *
* *
* Copyright (C) 2006, Jamie McCracken <jamiemcc@gnome.org> *
* Copyright (C) 2008, Nokia <ivan.frade@nokia.com> *
* SPDX-License-Identifier: LGPL-2.1-or-later *
***************************************************************************/
// These functions are used by Tracker's own extractor modules,
// but are not exported by libtracker_extractor. They're part of
// libtracker-miners-common, which is statically-linked.
#include "config.tracker.h"
#include "tracker-file-utils.h"
#include <gio/gunixmounts.h>
#include <blkid.h>
#ifdef HAVE_BTRFS_IOCTL
# include <linux/btrfs.h>
# include <sys/ioctl.h>
# define BTRFS_ROOT_INODE 256
#endif
// C includes
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
// NOTE: The following features have been disabled compatibility with older glib:
// - g_autofree (2.44)
// - g_unix_mount_monitor_get() (2.44)
typedef struct {
GFile *file;
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 = (const UnixMountInfo*)a, *info_b = (const UnixMountInfo*)b;
return g_strcmp0 (info_a->mount_point, info_b->mount_point);
}
static void
clear_mount_info (gpointer user_data)
{
UnixMountInfo *info = (UnixMountInfo*)user_data;
g_object_unref (info->file);
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 = (GUnixMountEntry*)l->data;
const gchar *devname;
/*g_autofree*/ gchar *id = NULL/*, *subvol = NULL*/;
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)
continue;
mount.mount_point = g_strdup (g_unix_mount_get_mount_path (entry));
mount.file = g_file_new_for_path (mount.mount_point);
//mount.id = g_steal_pointer (&id);
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 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;
gint i;
cache = tracker_unix_mount_cache_get ();
g_rw_lock_reader_lock (&cache->lock);
for (i = (gint) cache->mounts->len - 1; i >= 0; i--) {
UnixMountInfo *info = &g_array_index (cache->mounts, UnixMountInfo, i);
if (g_file_equal (file, info->file) ||
g_file_has_prefix (file, info->file)) {
id = info->id;
break;
}
}
g_rw_lock_reader_unlock (&cache->lock);
return id;
}
#ifdef HAVE_BTRFS_IOCTL
static gchar *
tracker_file_get_btrfs_subvolume_id (GFile *file)
{
struct btrfs_ioctl_ino_lookup_args args = {
.treeid = 0,
.objectid = BTRFS_ROOT_INODE,
};
/*g_autofree*/ gchar *path = NULL;
int fd, ret;
path = g_file_get_path (file);
if (!path)
return NULL;
fd = open (path, O_RDONLY);
g_free (path);
if (fd < 0)
return NULL;
ret = ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args);
close (fd);
if (ret < 0)
return NULL;
return g_strdup_printf ("%" G_GUINT64_FORMAT, (guint64) args.treeid);
}
#endif
gchar *
tracker_file_get_content_identifier (GFile *file, GFileInfo *info, const gchar *suffix)
{
const gchar *id;
/*g_autofree*/ gchar *inode = NULL, *str = NULL, *subvolume = NULL;
if (info) {
g_object_ref (info);
} else {
info = g_file_query_info (file,
G_FILE_ATTRIBUTE_ID_FILESYSTEM ","
G_FILE_ATTRIBUTE_UNIX_INODE,
G_FILE_QUERY_INFO_NONE,
NULL,
NULL);
if (!info)
return NULL;
}
id = tracker_unix_mount_cache_lookup_filesystem_id (file);
if (!id) {
id = g_file_info_get_attribute_string (info,
G_FILE_ATTRIBUTE_ID_FILESYSTEM);
}
inode = g_file_info_get_attribute_as_string (info, G_FILE_ATTRIBUTE_UNIX_INODE);
#ifdef HAVE_BTRFS_IOCTL
subvolume = tracker_file_get_btrfs_subvolume_id (file);
#endif
/* Format:
* 'urn:fileid:' [fsid] (':' [subvolumeid])? ':' [inode] ('/' [suffix])?
*/
str = g_strconcat ("urn:fileid:", id,
subvolume ? ":" : "",
subvolume ? subvolume : "",
":", inode,
suffix ? "/" : NULL,
suffix, NULL);
g_object_unref (info);
g_free (inode);
g_free (subvolume);
//return g_steal_pointer(&str);
return str;
}

View File

@ -0,0 +1,22 @@
/***************************************************************************
* ROM Properties Page shell extension. (GNOME Tracker) *
* tracker-file-utils.h: File utilities from tracker-miners-3.6.2. *
* *
* Copyright (C) 2006, Jamie McCracken <jamiemcc@gnome.org> *
* Copyright (C) 2008, Nokia <ivan.frade@nokia.com> *
* SPDX-License-Identifier: LGPL-2.1-or-later *
***************************************************************************/
// These functions are used by Tracker's own extractor modules,
// but are not exported by libtracker_extractor. They're part of
// libtracker-miners-common, which is statically-linked.
#pragma once
#include <glib.h>
#include <gio/gio.h>
G_BEGIN_DECLS
gchar *tracker_file_get_content_identifier(GFile *file, GFileInfo *info, const gchar *suffix);
G_END_DECLS

View File

@ -10,6 +10,7 @@
// do not install headers for libtracker-extract.
#include "tracker-mini.h"
#include "tracker-file-utils.h"
// C includes
#include <dlfcn.h>
@ -153,6 +154,20 @@ int rp_tracker_init_pfn(void)
return 0;
}
// Check for Tracker 3.0.
libtracker_sparql_so = dlopen("libtracker-sparql-3.0.so.0", RTLD_NOW | RTLD_LOCAL);
libtracker_extract_so = dlopen("libtracker-extract.so", RTLD_NOW | RTLD_LOCAL);
if (libtracker_sparql_so && libtracker_extract_so) {
// Found Tracker 3.0.
// NOTE: Functions are essentially the same as 2.0.
init_tracker_v2();
rp_tracker_api = 3;
return 0;
}
// Clear dlopen() pointers and try again.
close_modules();
// Check for Tracker 2.0.
libtracker_sparql_so = dlopen("libtracker-sparql-2.0.so.0", RTLD_NOW | RTLD_LOCAL);
libtracker_extract_so = dlopen("libtracker-extract.so.0", RTLD_NOW | RTLD_LOCAL);