registry: Use plugin directory from the build system for relocateable Windows builds
[platform/upstream/gstreamer.git] / gst / gstregistry.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *                    2005 David A. Schleef <ds@schleef.org>
5  *
6  * gstregistry.c: handle registry
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 /**
25  * SECTION:gstregistry
26  * @title: GstRegistry
27  * @short_description: Abstract base class for management of #GstPlugin objects
28  * @see_also: #GstPlugin, #GstPluginFeature
29  *
30  * One registry holds the metadata of a set of plugins.
31  *
32  * <emphasis role="bold">Design:</emphasis>
33  *
34  * The #GstRegistry object is a list of plugins and some functions for dealing
35  * with them. Each #GstPlugin is matched 1-1 with a file on disk, and may or may
36  * not be loaded at a given time.
37  *
38  * The primary source, at all times, of plugin information is each plugin file
39  * itself. Thus, if an application wants information about a particular plugin,
40  * or wants to search for a feature that satisfies given criteria, the primary
41  * means of doing so is to load every plugin and look at the resulting
42  * information that is gathered in the default registry. Clearly, this is a time
43  * consuming process, so we cache information in the registry file. The format
44  * and location of the cache file is internal to gstreamer.
45  *
46  * On startup, plugins are searched for in the plugin search path. The following
47  * locations are checked in this order:
48  *
49  * * location from --gst-plugin-path commandline option.
50  * * the GST_PLUGIN_PATH environment variable.
51  * * the GST_PLUGIN_SYSTEM_PATH environment variable.
52  * * default locations (if GST_PLUGIN_SYSTEM_PATH is not set).
53  *   Those default locations are:
54  *   `$XDG_DATA_HOME/gstreamer-$GST_API_VERSION/plugins/`
55  *   and `$prefix/libs/gstreamer-$GST_API_VERSION/`.
56  *   [$XDG_DATA_HOME](http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html) defaults to
57  *   `$HOME/.local/share`.
58  *
59  * The registry cache file is loaded from
60  * `$XDG_CACHE_HOME/gstreamer-$GST_API_VERSION/registry-$ARCH.bin`
61  * (where $XDG_CACHE_HOME defaults to `$HOME/.cache`) or the file listed in the `GST_REGISTRY`
62  * env var. One reason to change the registry location is for testing.
63  *
64  * For each plugin that is found in the plugin search path, there could be 3
65  * possibilities for cached information:
66  *
67  *   * the cache may not contain information about a given file.
68  *   * the cache may have stale information.
69  *   * the cache may have current information.
70  *
71  * In the first two cases, the plugin is loaded and the cache updated. In
72  * addition to these cases, the cache may have entries for plugins that are not
73  * relevant to the current process. These are marked as not available to the
74  * current process. If the cache is updated for whatever reason, it is marked
75  * dirty.
76  *
77  * A dirty cache is written out at the end of initialization. Each entry is
78  * checked to make sure the information is minimally valid. If not, the entry is
79  * simply dropped.
80  *
81  * ## Implementation notes:
82  *
83  * The "cache" and "registry" are different concepts and can represent
84  * different sets of plugins. For various reasons, at init time, the cache is
85  * stored in the default registry, and plugins not relevant to the current
86  * process are marked with the %GST_PLUGIN_FLAG_CACHED bit. These plugins are
87  * removed at the end of initialization.
88  */
89
90 #ifdef HAVE_CONFIG_H
91 #include "config.h"
92 #endif
93 #include "gstconfig.h"
94 #include "gst_private.h"
95 #include <glib.h>
96 #include <sys/types.h>
97 #include <sys/stat.h>
98 #ifdef HAVE_UNISTD_H
99 #include <unistd.h>
100 #endif
101 #include <errno.h>
102 #include <stdio.h>
103 #include <string.h>
104
105 /* For g_stat () */
106 #include <glib/gstdio.h>
107
108 #include "gstinfo.h"
109 #include "gsterror.h"
110 #include "gstregistry.h"
111 #include "gstdeviceproviderfactory.h"
112
113 #include "gstpluginloader.h"
114
115 #include "gst-i18n-lib.h"
116
117 #include "gst.h"
118 #include "glib-compat-private.h"
119
120 #ifdef G_OS_WIN32
121 #include <windows.h>
122 extern HMODULE _priv_gst_dll_handle;
123 #endif
124
125 #define GST_CAT_DEFAULT GST_CAT_REGISTRY
126
127 struct _GstRegistryPrivate
128 {
129   GList *plugins;
130   GList *features;
131
132   guint n_plugins;
133 #if 0
134   GList *paths;
135 #endif
136
137   int cache_file;
138
139   /* hash to speedup _lookup_feature_locked() */
140   GHashTable *feature_hash;
141   /* hash to speedup _lookup */
142   GHashTable *basename_hash;
143
144   /* updated whenever the feature list changes */
145   guint32 cookie;
146   /* speedup for searching features */
147   GList *element_factory_list;
148   guint32 efl_cookie;
149   GList *typefind_factory_list;
150   guint32 tfl_cookie;
151   GList *device_provider_factory_list;
152   guint32 dmfl_cookie;
153 };
154
155 /* the one instance of the default registry and the mutex protecting the
156  * variable. */
157 static GMutex _gst_registry_mutex;
158 static GstRegistry *_gst_registry_default = NULL;
159
160 /* defaults */
161 #define DEFAULT_FORK TRUE
162
163 /* control the behaviour of registry rebuild */
164 static gboolean _gst_enable_registry_fork = DEFAULT_FORK;
165 /* List of plugins that need preloading/reloading after scanning registry */
166 extern GSList *_priv_gst_preload_plugins;
167
168 #ifndef GST_DISABLE_REGISTRY
169 /* Set to TRUE to disable registry, behaves similar to GST_DISABLE_REGISTRY */
170 gboolean _priv_gst_disable_registry = FALSE;
171 /*set to TRUE when registry needn't to be updated */
172 gboolean _priv_gst_disable_registry_update = FALSE;
173 extern GList *_priv_gst_plugin_paths;
174
175 /* Set to TRUE when the registry cache should be disabled */
176 gboolean _gst_disable_registry_cache = FALSE;
177
178 static gboolean __registry_reuse_plugin_scanner = TRUE;
179 #endif
180
181 /* Element signals and args */
182 enum
183 {
184   PLUGIN_ADDED,
185   FEATURE_ADDED,
186   LAST_SIGNAL
187 };
188
189 static void gst_registry_finalize (GObject * object);
190
191 static guint gst_registry_signals[LAST_SIGNAL] = { 0 };
192
193 static GstPluginFeature *gst_registry_lookup_feature_locked (GstRegistry *
194     registry, const char *name);
195 static GstPlugin *gst_registry_lookup_bn_locked (GstRegistry * registry,
196     const char *basename);
197
198 #define gst_registry_parent_class parent_class
199 G_DEFINE_TYPE_WITH_PRIVATE (GstRegistry, gst_registry, GST_TYPE_OBJECT);
200
201 static void
202 gst_registry_class_init (GstRegistryClass * klass)
203 {
204   GObjectClass *gobject_class;
205
206   gobject_class = (GObjectClass *) klass;
207
208   /**
209    * GstRegistry::plugin-added:
210    * @registry: the registry that emitted the signal
211    * @plugin: the plugin that has been added
212    *
213    * Signals that a plugin has been added to the registry (possibly
214    * replacing a previously-added one by the same name)
215    */
216   gst_registry_signals[PLUGIN_ADDED] =
217       g_signal_new ("plugin-added", G_TYPE_FROM_CLASS (klass),
218       G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
219       G_TYPE_NONE, 1, GST_TYPE_PLUGIN);
220
221   /**
222    * GstRegistry::feature-added:
223    * @registry: the registry that emitted the signal
224    * @feature: the feature that has been added
225    *
226    * Signals that a feature has been added to the registry (possibly
227    * replacing a previously-added one by the same name)
228    */
229   gst_registry_signals[FEATURE_ADDED] =
230       g_signal_new ("feature-added", G_TYPE_FROM_CLASS (klass),
231       G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
232       G_TYPE_NONE, 1, GST_TYPE_PLUGIN_FEATURE);
233
234   gobject_class->finalize = gst_registry_finalize;
235 }
236
237 static void
238 gst_registry_init (GstRegistry * registry)
239 {
240   registry->priv = gst_registry_get_instance_private (registry);
241   registry->priv->feature_hash = g_hash_table_new (g_str_hash, g_str_equal);
242   registry->priv->basename_hash = g_hash_table_new (g_str_hash, g_str_equal);
243 }
244
245 static void
246 gst_registry_finalize (GObject * object)
247 {
248   GstRegistry *registry = GST_REGISTRY (object);
249   GList *plugins, *p;
250   GList *features, *f;
251
252   plugins = registry->priv->plugins;
253   registry->priv->plugins = NULL;
254   registry->priv->n_plugins = 0;
255
256   GST_DEBUG_OBJECT (registry, "registry finalize");
257   p = plugins;
258   while (p) {
259     GstPlugin *plugin = p->data;
260
261     if (plugin) {
262       GST_LOG_OBJECT (registry, "removing plugin %s",
263           gst_plugin_get_name (plugin));
264       gst_object_unref (plugin);
265     }
266     p = g_list_next (p);
267   }
268   g_list_free (plugins);
269
270   features = registry->priv->features;
271   registry->priv->features = NULL;
272
273   f = features;
274   while (f) {
275     GstPluginFeature *feature = f->data;
276
277     if (feature) {
278       GST_LOG_OBJECT (registry, "removing feature %p (%s)", feature,
279           GST_OBJECT_NAME (feature));
280       gst_object_unparent (GST_OBJECT_CAST (feature));
281     }
282     f = g_list_next (f);
283   }
284   g_list_free (features);
285
286   g_hash_table_destroy (registry->priv->feature_hash);
287   registry->priv->feature_hash = NULL;
288   g_hash_table_destroy (registry->priv->basename_hash);
289   registry->priv->basename_hash = NULL;
290
291   if (registry->priv->element_factory_list) {
292     GST_DEBUG_OBJECT (registry, "Cleaning up cached element factory list");
293     gst_plugin_feature_list_free (registry->priv->element_factory_list);
294   }
295
296   if (registry->priv->typefind_factory_list) {
297     GST_DEBUG_OBJECT (registry, "Cleaning up cached typefind factory list");
298     gst_plugin_feature_list_free (registry->priv->typefind_factory_list);
299   }
300
301   if (registry->priv->device_provider_factory_list) {
302     GST_DEBUG_OBJECT (registry,
303         "Cleaning up cached device provider factory list");
304     gst_plugin_feature_list_free (registry->priv->device_provider_factory_list);
305   }
306
307   G_OBJECT_CLASS (parent_class)->finalize (object);
308 }
309
310 /**
311  * gst_registry_get:
312  *
313  * Retrieves the singleton plugin registry. The caller does not own a
314  * reference on the registry, as it is alive as long as GStreamer is
315  * initialized.
316  *
317  * Returns: (transfer none): the #GstRegistry.
318  */
319 GstRegistry *
320 gst_registry_get (void)
321 {
322   GstRegistry *registry;
323
324   g_mutex_lock (&_gst_registry_mutex);
325   if (G_UNLIKELY (!_gst_registry_default)) {
326     _gst_registry_default = g_object_new (GST_TYPE_REGISTRY, NULL);
327     gst_object_ref_sink (GST_OBJECT_CAST (_gst_registry_default));
328   }
329   registry = _gst_registry_default;
330   g_mutex_unlock (&_gst_registry_mutex);
331
332   return registry;
333 }
334
335 #if 0
336 /**
337  * gst_registry_add_path:
338  * @registry: the registry to add the path to
339  * @path: the path to add to the registry
340  *
341  * Add the given path to the registry. The syntax of the
342  * path is specific to the registry. If the path has already been
343  * added, do nothing.
344  */
345 void
346 gst_registry_add_path (GstRegistry * registry, const gchar * path)
347 {
348   g_return_if_fail (GST_IS_REGISTRY (registry));
349   g_return_if_fail (path != NULL);
350
351   if (strlen (path) == 0)
352     goto empty_path;
353
354   GST_OBJECT_LOCK (registry);
355   if (g_list_find_custom (registry->priv->paths, path, (GCompareFunc) strcmp))
356     goto was_added;
357
358   GST_INFO ("Adding plugin path: \"%s\"", path);
359   registry->priv->paths =
360       g_list_append (registry->priv->paths, g_strdup (path));
361   GST_OBJECT_UNLOCK (registry);
362
363   return;
364
365 empty_path:
366   {
367     GST_INFO ("Ignoring empty plugin path");
368     return;
369   }
370 was_added:
371   {
372     g_warning ("path %s already added to registry", path);
373     GST_OBJECT_UNLOCK (registry);
374     return;
375   }
376 }
377
378 /**
379  * gst_registry_get_path_list:
380  * @registry: the registry to get the pathlist of
381  *
382  * Get the list of paths for the given registry.
383  *
384  * Returns: (transfer container) (element-type char*): A #GList of paths as
385  *     strings. g_list_free after use.
386  *
387  * MT safe.
388  */
389 GList *
390 gst_registry_get_path_list (GstRegistry * registry)
391 {
392   GList *list;
393
394   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
395
396   GST_OBJECT_LOCK (registry);
397   /* We don't need to copy the strings, because they won't be deleted
398    * as long as the GstRegistry is around */
399   list = g_list_copy (registry->priv->paths);
400   GST_OBJECT_UNLOCK (registry);
401
402   return list;
403 }
404 #endif
405
406 /**
407  * gst_registry_add_plugin:
408  * @registry: the registry to add the plugin to
409  * @plugin: (transfer floating): the plugin to add
410  *
411  * Add the plugin to the registry. The plugin-added signal will be emitted.
412  *
413  * @plugin's reference count will be incremented, and any floating
414  * reference will be removed (see gst_object_ref_sink())
415  *
416  * Returns: %TRUE on success.
417  *
418  * MT safe.
419  */
420 gboolean
421 gst_registry_add_plugin (GstRegistry * registry, GstPlugin * plugin)
422 {
423   GstPlugin *existing_plugin;
424
425   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
426   g_return_val_if_fail (GST_IS_PLUGIN (plugin), FALSE);
427
428   GST_OBJECT_LOCK (registry);
429   if (G_LIKELY (plugin->basename)) {
430     /* we have a basename, see if we find the plugin */
431     existing_plugin =
432         gst_registry_lookup_bn_locked (registry, plugin->basename);
433     if (existing_plugin) {
434       GST_DEBUG_OBJECT (registry,
435           "Replacing existing plugin \"%s\" %p with new plugin %p for filename \"%s\"",
436           GST_STR_NULL (existing_plugin->filename), existing_plugin, plugin,
437           GST_STR_NULL (plugin->filename));
438       /* If the new plugin is blacklisted and the existing one isn't cached, do not
439        * accept if it's from a different location than the existing one */
440       if (GST_OBJECT_FLAG_IS_SET (plugin, GST_PLUGIN_FLAG_BLACKLISTED) &&
441           strcmp (plugin->filename, existing_plugin->filename)) {
442         GST_WARNING_OBJECT (registry,
443             "Not replacing plugin because new one (%s) is blacklisted but for a different location than existing one (%s)",
444             plugin->filename, existing_plugin->filename);
445         /* Keep reference counting consistent */
446         gst_object_ref_sink (plugin);
447         gst_object_unref (plugin);
448         GST_OBJECT_UNLOCK (registry);
449         return FALSE;
450       }
451       registry->priv->plugins =
452           g_list_remove (registry->priv->plugins, existing_plugin);
453       --registry->priv->n_plugins;
454       if (G_LIKELY (existing_plugin->basename))
455         g_hash_table_remove (registry->priv->basename_hash,
456             existing_plugin->basename);
457       gst_object_unref (existing_plugin);
458     }
459   }
460
461   GST_DEBUG_OBJECT (registry, "adding plugin %p for filename \"%s\"",
462       plugin, GST_STR_NULL (plugin->filename));
463
464   registry->priv->plugins = g_list_prepend (registry->priv->plugins, plugin);
465   ++registry->priv->n_plugins;
466
467   if (G_LIKELY (plugin->basename))
468     g_hash_table_replace (registry->priv->basename_hash, plugin->basename,
469         plugin);
470
471   gst_object_ref_sink (plugin);
472   GST_OBJECT_UNLOCK (registry);
473
474   GST_LOG_OBJECT (registry, "emitting plugin-added for filename \"%s\"",
475       GST_STR_NULL (plugin->filename));
476   g_signal_emit (registry, gst_registry_signals[PLUGIN_ADDED], 0, plugin);
477
478   return TRUE;
479 }
480
481 static void
482 gst_registry_remove_features_for_plugin_unlocked (GstRegistry * registry,
483     GstPlugin * plugin)
484 {
485   GList *f;
486
487   g_return_if_fail (GST_IS_REGISTRY (registry));
488   g_return_if_fail (GST_IS_PLUGIN (plugin));
489
490   /* Remove all features for this plugin */
491   f = registry->priv->features;
492   while (f != NULL) {
493     GList *next = g_list_next (f);
494     GstPluginFeature *feature = f->data;
495
496     if (G_UNLIKELY (feature && feature->plugin == plugin)) {
497       GST_DEBUG_OBJECT (registry, "removing feature %p (%s) for plugin %p (%s)",
498           feature, gst_plugin_feature_get_name (feature), plugin,
499           plugin->desc.name);
500
501       registry->priv->features =
502           g_list_delete_link (registry->priv->features, f);
503       g_hash_table_remove (registry->priv->feature_hash,
504           GST_OBJECT_NAME (feature));
505       gst_object_unparent (GST_OBJECT_CAST (feature));
506     }
507     f = next;
508   }
509   registry->priv->cookie++;
510 }
511
512 /**
513  * gst_registry_remove_plugin:
514  * @registry: the registry to remove the plugin from
515  * @plugin: (transfer none): the plugin to remove
516  *
517  * Remove the plugin from the registry.
518  *
519  * MT safe.
520  */
521 void
522 gst_registry_remove_plugin (GstRegistry * registry, GstPlugin * plugin)
523 {
524   g_return_if_fail (GST_IS_REGISTRY (registry));
525   g_return_if_fail (GST_IS_PLUGIN (plugin));
526
527   GST_DEBUG_OBJECT (registry, "removing plugin %p (%s)",
528       plugin, gst_plugin_get_name (plugin));
529
530   GST_OBJECT_LOCK (registry);
531   registry->priv->plugins = g_list_remove (registry->priv->plugins, plugin);
532   --registry->priv->n_plugins;
533   if (G_LIKELY (plugin->basename))
534     g_hash_table_remove (registry->priv->basename_hash, plugin->basename);
535   gst_registry_remove_features_for_plugin_unlocked (registry, plugin);
536   GST_OBJECT_UNLOCK (registry);
537   gst_object_unref (plugin);
538 }
539
540 /**
541  * gst_registry_add_feature:
542  * @registry: the registry to add the plugin to
543  * @feature: (transfer floating): the feature to add
544  *
545  * Add the feature to the registry. The feature-added signal will be emitted.
546  *
547  * @feature's reference count will be incremented, and any floating
548  * reference will be removed (see gst_object_ref_sink())
549  *
550  * Returns: %TRUE on success.
551  *
552  * MT safe.
553  */
554 gboolean
555 gst_registry_add_feature (GstRegistry * registry, GstPluginFeature * feature)
556 {
557   GstPluginFeature *existing_feature;
558
559   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
560   g_return_val_if_fail (GST_IS_PLUGIN_FEATURE (feature), FALSE);
561   g_return_val_if_fail (GST_OBJECT_NAME (feature) != NULL, FALSE);
562   g_return_val_if_fail (feature->plugin_name != NULL, FALSE);
563
564   GST_OBJECT_LOCK (registry);
565   existing_feature = gst_registry_lookup_feature_locked (registry,
566       GST_OBJECT_NAME (feature));
567   if (G_UNLIKELY (existing_feature)) {
568     GST_DEBUG_OBJECT (registry, "replacing existing feature %p (%s)",
569         existing_feature, GST_OBJECT_NAME (feature));
570     /* Remove the existing feature from the list now, before we insert the new
571      * one, but don't unref yet because the hash is still storing a reference to
572      * it. */
573     registry->priv->features =
574         g_list_remove (registry->priv->features, existing_feature);
575   }
576
577   GST_DEBUG_OBJECT (registry, "adding feature %p (%s)", feature,
578       GST_OBJECT_NAME (feature));
579
580   registry->priv->features = g_list_prepend (registry->priv->features, feature);
581   g_hash_table_replace (registry->priv->feature_hash, GST_OBJECT_NAME (feature),
582       feature);
583
584   if (G_UNLIKELY (existing_feature)) {
585     /* We unref now. No need to remove the feature name from the hash table, it
586      * got replaced by the new feature */
587     gst_object_unparent (GST_OBJECT_CAST (existing_feature));
588   }
589
590   gst_object_set_parent (GST_OBJECT_CAST (feature), GST_OBJECT_CAST (registry));
591
592   registry->priv->cookie++;
593   GST_OBJECT_UNLOCK (registry);
594
595   GST_LOG_OBJECT (registry, "emitting feature-added for %s",
596       GST_OBJECT_NAME (feature));
597   g_signal_emit (registry, gst_registry_signals[FEATURE_ADDED], 0, feature);
598
599   return TRUE;
600 }
601
602 /**
603  * gst_registry_remove_feature:
604  * @registry: the registry to remove the feature from
605  * @feature: (transfer none): the feature to remove
606  *
607  * Remove the feature from the registry.
608  *
609  * MT safe.
610  */
611 void
612 gst_registry_remove_feature (GstRegistry * registry, GstPluginFeature * feature)
613 {
614   g_return_if_fail (GST_IS_REGISTRY (registry));
615   g_return_if_fail (GST_IS_PLUGIN_FEATURE (feature));
616
617   GST_DEBUG_OBJECT (registry, "removing feature %p (%s)",
618       feature, gst_plugin_feature_get_name (feature));
619
620   GST_OBJECT_LOCK (registry);
621   registry->priv->features = g_list_remove (registry->priv->features, feature);
622   g_hash_table_remove (registry->priv->feature_hash, GST_OBJECT_NAME (feature));
623   registry->priv->cookie++;
624   GST_OBJECT_UNLOCK (registry);
625
626   gst_object_unparent ((GstObject *) feature);
627 }
628
629 /**
630  * gst_registry_plugin_filter:
631  * @registry: registry to query
632  * @filter: (scope call): the filter to use
633  * @first: only return first match
634  * @user_data: (closure): user data passed to the filter function
635  *
636  * Runs a filter against all plugins in the registry and returns a #GList with
637  * the results. If the first flag is set, only the first match is
638  * returned (as a list with a single object).
639  * Every plugin is reffed; use gst_plugin_list_free() after use, which
640  * will unref again.
641  *
642  * Returns: (transfer full) (element-type Gst.Plugin): a #GList of #GstPlugin.
643  *     Use gst_plugin_list_free() after usage.
644  *
645  * MT safe.
646  */
647 GList *
648 gst_registry_plugin_filter (GstRegistry * registry,
649     GstPluginFilter filter, gboolean first, gpointer user_data)
650 {
651   GstPlugin **plugins;
652   GList *walk, *list = NULL;
653   guint n_plugins, i;
654
655   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
656
657   GST_OBJECT_LOCK (registry);
658   n_plugins = registry->priv->n_plugins;
659   plugins = g_newa (GstPlugin *, n_plugins + 1);
660   for (walk = registry->priv->plugins, i = 0; walk != NULL; walk = walk->next)
661     plugins[i++] = gst_object_ref (walk->data);
662   GST_OBJECT_UNLOCK (registry);
663
664   for (i = 0; i < n_plugins; ++i) {
665     if (filter == NULL || filter (plugins[i], user_data)) {
666       list = g_list_prepend (list, gst_object_ref (plugins[i]));
667
668       if (first)
669         break;
670     }
671   }
672
673   for (i = 0; i < n_plugins; ++i)
674     gst_object_unref (plugins[i]);
675
676   return list;
677 }
678
679 typedef struct
680 {
681   const gchar *name;
682   GType type;
683 } GstTypeNameData;
684
685 static gboolean
686 gst_plugin_feature_type_name_filter (GstPluginFeature * feature,
687     GstTypeNameData * data)
688 {
689   g_assert (GST_IS_PLUGIN_FEATURE (feature));
690
691   return ((data->type == 0 || data->type == G_OBJECT_TYPE (feature)) &&
692       (data->name == NULL || !strcmp (data->name, GST_OBJECT_NAME (feature))));
693 }
694
695 /* returns TRUE if the list was changed
696  *
697  * Must be called with the object lock taken */
698 static gboolean
699 gst_registry_get_feature_list_or_create (GstRegistry * registry,
700     GList ** previous, guint32 * cookie, GType type)
701 {
702   gboolean res = FALSE;
703   GstRegistryPrivate *priv = registry->priv;
704
705   if (G_UNLIKELY (!*previous || priv->cookie != *cookie)) {
706     GstTypeNameData data;
707     const GList *walk;
708
709     if (*previous) {
710       gst_plugin_feature_list_free (*previous);
711       *previous = NULL;
712     }
713
714     data.type = type;
715     data.name = NULL;
716
717     for (walk = registry->priv->features; walk != NULL; walk = walk->next) {
718       GstPluginFeature *feature = walk->data;
719
720       if (gst_plugin_feature_type_name_filter (feature, &data)) {
721         *previous = g_list_prepend (*previous, gst_object_ref (feature));
722       }
723     }
724
725     *cookie = priv->cookie;
726     res = TRUE;
727   }
728
729   return res;
730 }
731
732 static gint
733 type_find_factory_rank_cmp (const GstPluginFeature * fac1,
734     const GstPluginFeature * fac2)
735 {
736   if (G_LIKELY (fac1->rank != fac2->rank))
737     return fac2->rank - fac1->rank;
738
739   /* to make the order in which things happen more deterministic,
740    * sort by name when the ranks are the same. */
741   return strcmp (GST_OBJECT_NAME (fac1), GST_OBJECT_NAME (fac2));
742 }
743
744 static GList *
745 gst_registry_get_element_factory_list (GstRegistry * registry)
746 {
747   GList *list;
748
749   GST_OBJECT_LOCK (registry);
750
751   gst_registry_get_feature_list_or_create (registry,
752       &registry->priv->element_factory_list, &registry->priv->efl_cookie,
753       GST_TYPE_ELEMENT_FACTORY);
754
755   /* Return reffed copy */
756   list = gst_plugin_feature_list_copy (registry->priv->element_factory_list);
757
758   GST_OBJECT_UNLOCK (registry);
759
760   return list;
761 }
762
763 static GList *
764 gst_registry_get_typefind_factory_list (GstRegistry * registry)
765 {
766   GList *list;
767
768   GST_OBJECT_LOCK (registry);
769
770   if (G_UNLIKELY (gst_registry_get_feature_list_or_create (registry,
771               &registry->priv->typefind_factory_list,
772               &registry->priv->tfl_cookie, GST_TYPE_TYPE_FIND_FACTORY)))
773     registry->priv->typefind_factory_list =
774         g_list_sort (registry->priv->typefind_factory_list,
775         (GCompareFunc) type_find_factory_rank_cmp);
776
777   /* Return reffed copy */
778   list = gst_plugin_feature_list_copy (registry->priv->typefind_factory_list);
779
780   GST_OBJECT_UNLOCK (registry);
781
782   return list;
783 }
784
785
786 static GList *
787 gst_registry_get_device_provider_factory_list (GstRegistry * registry)
788 {
789   GList *list;
790
791   GST_OBJECT_LOCK (registry);
792
793   gst_registry_get_feature_list_or_create (registry,
794       &registry->priv->device_provider_factory_list,
795       &registry->priv->dmfl_cookie, GST_TYPE_DEVICE_PROVIDER_FACTORY);
796
797   /* Return reffed copy */
798   list =
799       gst_plugin_feature_list_copy (registry->
800       priv->device_provider_factory_list);
801
802   GST_OBJECT_UNLOCK (registry);
803
804   return list;
805 }
806
807 /**
808  * gst_registry_feature_filter:
809  * @registry: registry to query
810  * @filter: (scope call): the filter to use
811  * @first: only return first match
812  * @user_data: (closure): user data passed to the filter function
813  *
814  * Runs a filter against all features of the plugins in the registry
815  * and returns a GList with the results.
816  * If the first flag is set, only the first match is
817  * returned (as a list with a single object).
818  *
819  * Returns: (transfer full) (element-type Gst.PluginFeature): a #GList of
820  *     #GstPluginFeature. Use gst_plugin_feature_list_free() after usage.
821  *
822  * MT safe.
823  */
824 GList *
825 gst_registry_feature_filter (GstRegistry * registry,
826     GstPluginFeatureFilter filter, gboolean first, gpointer user_data)
827 {
828   GstPluginFeature **features;
829   GList *walk, *list = NULL;
830   guint n_features, i;
831
832   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
833
834   GST_OBJECT_LOCK (registry);
835   n_features = g_hash_table_size (registry->priv->feature_hash);
836   features = g_newa (GstPluginFeature *, n_features + 1);
837   for (walk = registry->priv->features, i = 0; walk != NULL; walk = walk->next)
838     features[i++] = gst_object_ref (walk->data);
839   GST_OBJECT_UNLOCK (registry);
840
841   for (i = 0; i < n_features; ++i) {
842     if (filter == NULL || filter (features[i], user_data)) {
843       list = g_list_prepend (list, gst_object_ref (features[i]));
844
845       if (first)
846         break;
847     }
848   }
849
850   for (i = 0; i < n_features; ++i)
851     gst_object_unref (features[i]);
852
853   return list;
854 }
855
856 static gboolean
857 gst_registry_plugin_name_filter (GstPlugin * plugin, const gchar * name)
858 {
859   return (plugin->desc.name && !strcmp (plugin->desc.name, name));
860 }
861
862 /**
863  * gst_registry_find_plugin:
864  * @registry: the registry to search
865  * @name: the plugin name to find
866  *
867  * Find the plugin with the given name in the registry.
868  * The plugin will be reffed; caller is responsible for unreffing.
869  *
870  * Returns: (transfer full) (nullable): the plugin with the given name
871  *     or %NULL if the plugin was not found. gst_object_unref() after
872  *     usage.
873  *
874  * MT safe.
875  */
876 GstPlugin *
877 gst_registry_find_plugin (GstRegistry * registry, const gchar * name)
878 {
879   GList *walk;
880   GstPlugin *result = NULL;
881
882   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
883   g_return_val_if_fail (name != NULL, NULL);
884
885   walk = gst_registry_plugin_filter (registry,
886       (GstPluginFilter) gst_registry_plugin_name_filter, TRUE, (gpointer) name);
887   if (walk) {
888     result = GST_PLUGIN_CAST (walk->data);
889
890     gst_object_ref (result);
891     gst_plugin_list_free (walk);
892   }
893
894   return result;
895 }
896
897 /**
898  * gst_registry_find_feature:
899  * @registry: the registry to search
900  * @name: the pluginfeature name to find
901  * @type: the pluginfeature type to find
902  *
903  * Find the pluginfeature with the given name and type in the registry.
904  *
905  * Returns: (transfer full) (nullable): the pluginfeature with the
906  *     given name and type or %NULL if the plugin was not
907  *     found. gst_object_unref() after usage.
908  *
909  * MT safe.
910  */
911 GstPluginFeature *
912 gst_registry_find_feature (GstRegistry * registry, const gchar * name,
913     GType type)
914 {
915   GstPluginFeature *feature = NULL;
916
917   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
918   g_return_val_if_fail (name != NULL, NULL);
919   g_return_val_if_fail (g_type_is_a (type, GST_TYPE_PLUGIN_FEATURE), NULL);
920
921   feature = gst_registry_lookup_feature (registry, name);
922   if (feature && !g_type_is_a (G_TYPE_FROM_INSTANCE (feature), type)) {
923     gst_object_unref (feature);
924     feature = NULL;
925   }
926
927   return feature;
928 }
929
930 /**
931  * gst_registry_get_feature_list:
932  * @registry: a #GstRegistry
933  * @type: a #GType.
934  *
935  * Retrieves a #GList of #GstPluginFeature of @type.
936  *
937  * Returns: (transfer full) (element-type Gst.PluginFeature): a #GList of
938  *     #GstPluginFeature of @type. Use gst_plugin_feature_list_free() after use
939  *
940  * MT safe.
941  */
942 GList *
943 gst_registry_get_feature_list (GstRegistry * registry, GType type)
944 {
945   GstTypeNameData data;
946
947   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
948   g_return_val_if_fail (g_type_is_a (type, GST_TYPE_PLUGIN_FEATURE), NULL);
949
950   /* Speed up */
951   if (type == GST_TYPE_ELEMENT_FACTORY)
952     return gst_registry_get_element_factory_list (registry);
953   else if (type == GST_TYPE_TYPE_FIND_FACTORY)
954     return gst_registry_get_typefind_factory_list (registry);
955   else if (type == GST_TYPE_DEVICE_PROVIDER_FACTORY)
956     return gst_registry_get_device_provider_factory_list (registry);
957
958   data.type = type;
959   data.name = NULL;
960
961   return gst_registry_feature_filter (registry,
962       (GstPluginFeatureFilter) gst_plugin_feature_type_name_filter,
963       FALSE, &data);
964 }
965
966 /**
967  * gst_registry_get_plugin_list:
968  * @registry: the registry to search
969  *
970  * Get a copy of all plugins registered in the given registry. The refcount
971  * of each element in the list in incremented.
972  *
973  * Returns: (transfer full) (element-type Gst.Plugin): a #GList of #GstPlugin.
974  *     Use gst_plugin_list_free() after usage.
975  *
976  * MT safe.
977  */
978 GList *
979 gst_registry_get_plugin_list (GstRegistry * registry)
980 {
981   GList *list;
982   GList *g;
983
984   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
985
986   GST_OBJECT_LOCK (registry);
987   list = g_list_copy (registry->priv->plugins);
988   for (g = list; g; g = g->next) {
989     gst_object_ref (GST_PLUGIN_CAST (g->data));
990   }
991   GST_OBJECT_UNLOCK (registry);
992
993   return list;
994 }
995
996 static GstPluginFeature *
997 gst_registry_lookup_feature_locked (GstRegistry * registry, const char *name)
998 {
999   return g_hash_table_lookup (registry->priv->feature_hash, name);
1000 }
1001
1002 /**
1003  * gst_registry_lookup_feature:
1004  * @registry: a #GstRegistry
1005  * @name: a #GstPluginFeature name
1006  *
1007  * Find a #GstPluginFeature with @name in @registry.
1008  *
1009  * Returns: (transfer full): a #GstPluginFeature with its refcount incremented,
1010  *     use gst_object_unref() after usage.
1011  *
1012  * MT safe.
1013  */
1014 GstPluginFeature *
1015 gst_registry_lookup_feature (GstRegistry * registry, const char *name)
1016 {
1017   GstPluginFeature *feature;
1018
1019   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
1020   g_return_val_if_fail (name != NULL, NULL);
1021
1022   GST_OBJECT_LOCK (registry);
1023   feature = gst_registry_lookup_feature_locked (registry, name);
1024   if (feature)
1025     gst_object_ref (feature);
1026   GST_OBJECT_UNLOCK (registry);
1027
1028   return feature;
1029 }
1030
1031 static GstPlugin *
1032 gst_registry_lookup_bn_locked (GstRegistry * registry, const char *basename)
1033 {
1034   return g_hash_table_lookup (registry->priv->basename_hash, basename);
1035 }
1036
1037 static GstPlugin *
1038 gst_registry_lookup_bn (GstRegistry * registry, const char *basename)
1039 {
1040   GstPlugin *plugin;
1041
1042   GST_OBJECT_LOCK (registry);
1043   plugin = gst_registry_lookup_bn_locked (registry, basename);
1044   if (plugin)
1045     gst_object_ref (plugin);
1046   GST_OBJECT_UNLOCK (registry);
1047
1048   return plugin;
1049 }
1050
1051 /**
1052  * gst_registry_lookup:
1053  * @registry: the registry to look up in
1054  * @filename: the name of the file to look up
1055  *
1056  * Look up a plugin in the given registry with the given filename.
1057  * If found, plugin is reffed.
1058  *
1059  * Returns: (transfer full) (nullable): the #GstPlugin if found, or
1060  *     %NULL if not.  gst_object_unref() after usage.
1061  */
1062 GstPlugin *
1063 gst_registry_lookup (GstRegistry * registry, const char *filename)
1064 {
1065   GstPlugin *plugin;
1066   gchar *basename;
1067
1068   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
1069   g_return_val_if_fail (filename != NULL, NULL);
1070
1071   basename = g_path_get_basename (filename);
1072   if (G_UNLIKELY (basename == NULL))
1073     return NULL;
1074
1075   plugin = gst_registry_lookup_bn (registry, basename);
1076
1077   g_free (basename);
1078
1079   return plugin;
1080 }
1081
1082 typedef enum
1083 {
1084   REGISTRY_SCAN_HELPER_NOT_STARTED = 0,
1085   REGISTRY_SCAN_HELPER_DISABLED,
1086   REGISTRY_SCAN_HELPER_RUNNING
1087 } GstRegistryScanHelperState;
1088
1089 typedef struct
1090 {
1091   GstRegistry *registry;
1092   GstRegistryScanHelperState helper_state;
1093   GstPluginLoader *helper;
1094   gboolean changed;
1095 } GstRegistryScanContext;
1096
1097 static void
1098 init_scan_context (GstRegistryScanContext * context, GstRegistry * registry)
1099 {
1100   gboolean do_fork;
1101
1102   context->registry = registry;
1103
1104   /* see if forking is enabled and set up the scan helper state accordingly */
1105   do_fork = _gst_enable_registry_fork;
1106   if (do_fork) {
1107     const gchar *fork_env;
1108
1109     /* forking enabled, see if it is disabled with an env var */
1110     if ((fork_env = g_getenv ("GST_REGISTRY_FORK"))) {
1111       /* fork enabled for any value different from "no" */
1112       do_fork = strcmp (fork_env, "no") != 0;
1113     }
1114   }
1115
1116   if (do_fork)
1117     context->helper_state = REGISTRY_SCAN_HELPER_NOT_STARTED;
1118   else
1119     context->helper_state = REGISTRY_SCAN_HELPER_DISABLED;
1120
1121   context->helper = NULL;
1122   context->changed = FALSE;
1123 }
1124
1125 static void
1126 clear_scan_context (GstRegistryScanContext * context)
1127 {
1128   if (context->helper) {
1129     context->changed |= _priv_gst_plugin_loader_funcs.destroy (context->helper);
1130     context->helper = NULL;
1131   }
1132 }
1133
1134 static gboolean
1135 gst_registry_scan_plugin_file (GstRegistryScanContext * context,
1136     const gchar * filename, off_t file_size, time_t file_mtime)
1137 {
1138   gboolean changed = FALSE;
1139   GstPlugin *newplugin = NULL;
1140
1141 #ifdef G_OS_WIN32
1142   /* Disable external plugin loader on Windows until it is ported properly. */
1143   context->helper_state = REGISTRY_SCAN_HELPER_DISABLED;
1144 #endif
1145
1146
1147   /* Have a plugin to load - see if the scan-helper needs starting */
1148   if (context->helper_state == REGISTRY_SCAN_HELPER_NOT_STARTED) {
1149     GST_DEBUG ("Starting plugin scanner for file %s", filename);
1150     context->helper = _priv_gst_plugin_loader_funcs.create (context->registry);
1151     if (context->helper != NULL)
1152       context->helper_state = REGISTRY_SCAN_HELPER_RUNNING;
1153     else {
1154       GST_WARNING ("Failed starting plugin scanner. Scanning in-process");
1155       context->helper_state = REGISTRY_SCAN_HELPER_DISABLED;
1156     }
1157   }
1158
1159   if (context->helper_state == REGISTRY_SCAN_HELPER_RUNNING) {
1160     GST_DEBUG ("Using scan-helper to load plugin %s", filename);
1161     if (!_priv_gst_plugin_loader_funcs.load (context->helper,
1162             filename, file_size, file_mtime)) {
1163       g_warning ("External plugin loader failed. This most likely means that "
1164           "the plugin loader helper binary was not found or could not be run. "
1165           "You might need to set the GST_PLUGIN_SCANNER environment variable "
1166           "if your setup is unusual. This should normally not be required "
1167           "though.");
1168       context->helper_state = REGISTRY_SCAN_HELPER_DISABLED;
1169     }
1170   }
1171
1172   /* Check if the helper is disabled (or just got disabled above) */
1173   if (context->helper_state == REGISTRY_SCAN_HELPER_DISABLED) {
1174     /* Load plugin the old fashioned way... */
1175
1176     /* We don't use a GError here because a failure to load some shared
1177      * objects as plugins is normal (particularly in the uninstalled case)
1178      */
1179     newplugin = _priv_gst_plugin_load_file_for_registry (filename,
1180         context->registry, NULL);
1181   }
1182
1183   if (newplugin) {
1184     GST_DEBUG_OBJECT (context->registry, "marking new plugin %p as registered",
1185         newplugin);
1186     newplugin->registered = TRUE;
1187     gst_object_unref (newplugin);
1188     changed = TRUE;
1189   }
1190 #ifndef GST_DISABLE_REGISTRY
1191   if (!__registry_reuse_plugin_scanner) {
1192     clear_scan_context (context);
1193     context->helper_state = REGISTRY_SCAN_HELPER_NOT_STARTED;
1194   }
1195 #endif
1196
1197   return changed;
1198 }
1199
1200 static gboolean
1201 is_blacklisted_directory (const gchar * dirent)
1202 {
1203   /* hotdoc private folder can contain many files and it slows down
1204    * the discovery for nothing */
1205   if (g_str_has_prefix (dirent, "hotdoc-private-"))
1206     return TRUE;
1207
1208   if (G_LIKELY (dirent[0] != '.'))
1209     return FALSE;
1210
1211   /* skip the .debug directory, these contain elf files that are not
1212    * useful or worse, can crash dlopen () */
1213   if (strcmp (dirent, ".debug") == 0)
1214     return TRUE;
1215
1216   /* can also skip .git and .deps dirs, those won't contain useful files.
1217    * This speeds up scanning a bit in uninstalled setups. */
1218   if (strcmp (dirent, ".git") == 0 || strcmp (dirent, ".deps") == 0)
1219     return TRUE;
1220
1221   return FALSE;
1222 }
1223
1224 static gboolean
1225 gst_registry_scan_path_level (GstRegistryScanContext * context,
1226     const gchar * path, int level)
1227 {
1228   GDir *dir;
1229   const gchar *dirent;
1230   gchar *filename;
1231   GstPlugin *plugin;
1232   gboolean changed = FALSE;
1233
1234   dir = g_dir_open (path, 0, NULL);
1235   if (!dir)
1236     return FALSE;
1237
1238   while ((dirent = g_dir_read_name (dir))) {
1239     GStatBuf file_status;
1240
1241     filename = g_build_filename (path, dirent, NULL);
1242     if (g_stat (filename, &file_status) < 0) {
1243       /* Plugin will be removed from cache after the scan completes if it
1244        * is still marked 'cached' */
1245       g_free (filename);
1246       continue;
1247     }
1248
1249     if (file_status.st_mode & S_IFDIR) {
1250       if (G_UNLIKELY (is_blacklisted_directory (dirent))) {
1251         GST_TRACE_OBJECT (context->registry, "ignoring %s directory", dirent);
1252         g_free (filename);
1253         continue;
1254       }
1255       /* FIXME 2.0: Don't recurse into directories, this behaviour
1256        * is inconsistent with other PATH environment variables
1257        */
1258       if (level > 0) {
1259         GST_LOG_OBJECT (context->registry, "recursing into directory %s",
1260             filename);
1261         changed |= gst_registry_scan_path_level (context, filename, level - 1);
1262       } else {
1263         GST_LOG_OBJECT (context->registry, "not recursing into directory %s, "
1264             "recursion level too deep", filename);
1265       }
1266       g_free (filename);
1267       continue;
1268     }
1269     if (!(file_status.st_mode & S_IFREG)) {
1270       GST_TRACE_OBJECT (context->registry, "%s is not a regular file, ignoring",
1271           filename);
1272       g_free (filename);
1273       continue;
1274     }
1275     if (!g_str_has_suffix (dirent, "." G_MODULE_SUFFIX)
1276 #ifdef GST_EXTRA_MODULE_SUFFIX
1277         && !g_str_has_suffix (dirent, GST_EXTRA_MODULE_SUFFIX)
1278 #endif
1279         ) {
1280       GST_TRACE_OBJECT (context->registry,
1281           "extension is not recognized as module file, ignoring file %s",
1282           filename);
1283       g_free (filename);
1284       continue;
1285     }
1286
1287     GST_LOG_OBJECT (context->registry, "file %s looks like a possible module",
1288         filename);
1289
1290     /* try to avoid unnecessary plugin-move pain */
1291     if (g_str_has_prefix (dirent, "libgstvalve") ||
1292         g_str_has_prefix (dirent, "libgstselector")) {
1293       GST_WARNING_OBJECT (context->registry, "ignoring old plugin %s which "
1294           "has been merged into the corelements plugin", filename);
1295       /* Plugin will be removed from cache after the scan completes if it
1296        * is still marked 'cached' */
1297       g_free (filename);
1298       continue;
1299     }
1300
1301     /* plug-ins are considered unique by basename; if the given name
1302      * was already seen by the registry, we ignore it */
1303     plugin = gst_registry_lookup_bn (context->registry, dirent);
1304     if (plugin) {
1305       gboolean env_vars_changed, deps_changed = FALSE;
1306
1307       if (plugin->registered) {
1308         GST_DEBUG_OBJECT (context->registry,
1309             "plugin already registered from path \"%s\"",
1310             GST_STR_NULL (plugin->filename));
1311         g_free (filename);
1312         gst_object_unref (plugin);
1313         continue;
1314       }
1315
1316       env_vars_changed = _priv_plugin_deps_env_vars_changed (plugin);
1317
1318       /* If a file with a certain basename is seen on a different path,
1319        * update the plugin to ensure the registry cache will reflect up
1320        * to date information */
1321
1322       if (plugin->file_mtime == file_status.st_mtime &&
1323           plugin->file_size == file_status.st_size && !env_vars_changed &&
1324           !(deps_changed = _priv_plugin_deps_files_changed (plugin)) &&
1325           !strcmp (plugin->filename, filename)) {
1326         GST_LOG_OBJECT (context->registry, "file %s cached", filename);
1327         GST_OBJECT_FLAG_UNSET (plugin, GST_PLUGIN_FLAG_CACHED);
1328         GST_LOG_OBJECT (context->registry,
1329             "marking plugin %p as registered as %s", plugin, filename);
1330         plugin->registered = TRUE;
1331       } else {
1332         GST_INFO_OBJECT (context->registry, "cached info for %s is stale",
1333             filename);
1334         GST_DEBUG_OBJECT (context->registry, "mtime %" G_GINT64_FORMAT " != %"
1335             G_GINT64_FORMAT " or size %" G_GINT64_FORMAT " != %"
1336             G_GINT64_FORMAT " or external dependency env_vars changed: %d or"
1337             " external dependencies changed: %d or old path %s != new path %s",
1338             (gint64) plugin->file_mtime, (gint64) file_status.st_mtime,
1339             (gint64) plugin->file_size, (gint64) file_status.st_size,
1340             env_vars_changed, deps_changed, plugin->filename, filename);
1341         gst_registry_remove_plugin (context->registry, plugin);
1342         changed |= gst_registry_scan_plugin_file (context, filename,
1343             file_status.st_size, file_status.st_mtime);
1344       }
1345       gst_object_unref (plugin);
1346
1347     } else {
1348       GST_DEBUG_OBJECT (context->registry, "file %s not yet in registry",
1349           filename);
1350       changed |= gst_registry_scan_plugin_file (context, filename,
1351           file_status.st_size, file_status.st_mtime);
1352     }
1353
1354     g_free (filename);
1355   }
1356
1357   g_dir_close (dir);
1358
1359   return changed;
1360 }
1361
1362 static gboolean
1363 gst_registry_scan_path_internal (GstRegistryScanContext * context,
1364     const gchar * path)
1365 {
1366   gboolean changed;
1367
1368   GST_DEBUG_OBJECT (context->registry, "scanning path %s", path);
1369   changed = gst_registry_scan_path_level (context, path, 10);
1370
1371   GST_DEBUG_OBJECT (context->registry, "registry changed in path %s: %d", path,
1372       changed);
1373   return changed;
1374 }
1375
1376 /**
1377  * gst_registry_scan_path:
1378  * @registry: the registry to add found plugins to
1379  * @path: (type filename): the path to scan
1380  *
1381  * Scan the given path for plugins to add to the registry. The syntax of the
1382  * path is specific to the registry.
1383  *
1384  * Returns: %TRUE if registry changed
1385  */
1386 gboolean
1387 gst_registry_scan_path (GstRegistry * registry, const gchar * path)
1388 {
1389   GstRegistryScanContext context;
1390   gboolean result;
1391
1392   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
1393   g_return_val_if_fail (path != NULL, FALSE);
1394
1395   init_scan_context (&context, registry);
1396
1397   result = gst_registry_scan_path_internal (&context, path);
1398
1399   clear_scan_context (&context);
1400   result |= context.changed;
1401
1402   return result;
1403 }
1404
1405 static gboolean
1406 _gst_plugin_feature_filter_plugin_name (GstPluginFeature * feature,
1407     gpointer user_data)
1408 {
1409   return (strcmp (feature->plugin_name, (gchar *) user_data) == 0);
1410 }
1411
1412 /**
1413  * gst_registry_get_feature_list_by_plugin:
1414  * @registry: a #GstRegistry.
1415  * @name: a plugin name.
1416  *
1417  * Retrieves a #GList of features of the plugin with name @name.
1418  *
1419  * Returns: (transfer full) (element-type Gst.PluginFeature): a #GList of
1420  *     #GstPluginFeature. Use gst_plugin_feature_list_free() after usage.
1421  */
1422 GList *
1423 gst_registry_get_feature_list_by_plugin (GstRegistry * registry,
1424     const gchar * name)
1425 {
1426   g_return_val_if_fail (GST_IS_REGISTRY (registry), NULL);
1427   g_return_val_if_fail (name != NULL, NULL);
1428
1429   return gst_registry_feature_filter (registry,
1430       _gst_plugin_feature_filter_plugin_name, FALSE, (gpointer) name);
1431 }
1432
1433 /* Unref and delete the default registry */
1434 void
1435 _priv_gst_registry_cleanup (void)
1436 {
1437   GstRegistry *registry;
1438
1439   g_mutex_lock (&_gst_registry_mutex);
1440   if ((registry = _gst_registry_default) != NULL) {
1441     _gst_registry_default = NULL;
1442   }
1443   g_mutex_unlock (&_gst_registry_mutex);
1444
1445   /* unref outside of the lock because we can. */
1446   if (registry)
1447     gst_object_unref (registry);
1448 }
1449
1450 /**
1451  * gst_registry_check_feature_version:
1452  * @registry: a #GstRegistry
1453  * @feature_name: the name of the feature (e.g. "oggdemux")
1454  * @min_major: the minimum major version number
1455  * @min_minor: the minimum minor version number
1456  * @min_micro: the minimum micro version number
1457  *
1458  * Checks whether a plugin feature by the given name exists in
1459  * @registry and whether its version is at least the
1460  * version required.
1461  *
1462  * Returns: %TRUE if the feature could be found and the version is
1463  * the same as the required version or newer, and %FALSE otherwise.
1464  */
1465 gboolean
1466 gst_registry_check_feature_version (GstRegistry * registry,
1467     const gchar * feature_name, guint min_major, guint min_minor,
1468     guint min_micro)
1469 {
1470   GstPluginFeature *feature;
1471   gboolean ret = FALSE;
1472
1473   g_return_val_if_fail (feature_name != NULL, FALSE);
1474
1475   GST_DEBUG ("Looking up plugin feature '%s'", feature_name);
1476
1477   feature = gst_registry_lookup_feature (registry, feature_name);
1478   if (feature) {
1479     ret = gst_plugin_feature_check_version (feature, min_major, min_minor,
1480         min_micro);
1481     gst_object_unref (feature);
1482   } else {
1483     GST_DEBUG ("Could not find plugin feature '%s'", feature_name);
1484   }
1485
1486   return ret;
1487 }
1488
1489 static void
1490 load_plugin_func (gpointer data, gpointer user_data)
1491 {
1492   GstPlugin *plugin;
1493   const gchar *filename;
1494   GError *err = NULL;
1495
1496   filename = (const gchar *) data;
1497   GST_DEBUG ("Pre-loading plugin %s", filename);
1498
1499   plugin = gst_plugin_load_file (filename, &err);
1500
1501   if (plugin) {
1502     GST_INFO ("Loaded plugin: \"%s\"", filename);
1503
1504     gst_registry_add_plugin (gst_registry_get (), plugin);
1505   } else {
1506     if (err) {
1507       /* Report error to user, and free error */
1508       GST_ERROR ("Failed to load plugin: %s", err->message);
1509       g_error_free (err);
1510     } else {
1511       GST_WARNING ("Failed to load plugin: \"%s\"", filename);
1512     }
1513   }
1514 }
1515
1516 #ifndef GST_DISABLE_REGISTRY
1517 /* Unref all plugins marked 'cached', to clear old plugins that no
1518  * longer exist. Returns %TRUE if any plugins were removed */
1519 static gboolean
1520 gst_registry_remove_cache_plugins (GstRegistry * registry)
1521 {
1522   GList *g;
1523   GList *g_next;
1524   GstPlugin *plugin;
1525   gboolean changed = FALSE;
1526
1527   g_return_val_if_fail (GST_IS_REGISTRY (registry), FALSE);
1528
1529   GST_OBJECT_LOCK (registry);
1530
1531   GST_DEBUG_OBJECT (registry, "removing cached plugins");
1532   g = registry->priv->plugins;
1533   while (g) {
1534     g_next = g->next;
1535     plugin = g->data;
1536     if (GST_OBJECT_FLAG_IS_SET (plugin, GST_PLUGIN_FLAG_CACHED)) {
1537       GST_DEBUG_OBJECT (registry, "removing cached plugin \"%s\"",
1538           GST_STR_NULL (plugin->filename));
1539       registry->priv->plugins = g_list_delete_link (registry->priv->plugins, g);
1540       --registry->priv->n_plugins;
1541       if (G_LIKELY (plugin->basename))
1542         g_hash_table_remove (registry->priv->basename_hash, plugin->basename);
1543       gst_registry_remove_features_for_plugin_unlocked (registry, plugin);
1544       gst_object_unref (plugin);
1545       changed = TRUE;
1546     }
1547     g = g_next;
1548   }
1549
1550   GST_OBJECT_UNLOCK (registry);
1551
1552   return changed;
1553 }
1554
1555 typedef enum
1556 {
1557   REGISTRY_SCAN_AND_UPDATE_FAILURE = 0,
1558   REGISTRY_SCAN_AND_UPDATE_SUCCESS_NOT_CHANGED,
1559   REGISTRY_SCAN_AND_UPDATE_SUCCESS_UPDATED
1560 } GstRegistryScanAndUpdateResult;
1561
1562 /*
1563  * scan_and_update_registry:
1564  * @default_registry: the #GstRegistry
1565  * @registry_file: registry filename
1566  * @write_changes: write registry if it has changed?
1567  *
1568  * Scans for registry changes and eventually updates the registry cache.
1569  *
1570  * Return: %REGISTRY_SCAN_AND_UPDATE_FAILURE if the registry could not scanned
1571  *         or updated, %REGISTRY_SCAN_AND_UPDATE_SUCCESS_NOT_CHANGED if the
1572  *         registry is clean and %REGISTRY_SCAN_AND_UPDATE_SUCCESS_UPDATED if
1573  *         it has been updated and the cache needs to be re-read.
1574  */
1575 static GstRegistryScanAndUpdateResult
1576 scan_and_update_registry (GstRegistry * default_registry,
1577     const gchar * registry_file, gboolean write_changes, GError ** error)
1578 {
1579   const gchar *plugin_path;
1580   gboolean changed = FALSE;
1581   GList *l;
1582   GstRegistryScanContext context;
1583
1584   GST_INFO ("Validating plugins from registry cache: %s", registry_file);
1585
1586   init_scan_context (&context, default_registry);
1587
1588   /* It sounds tempting to just compare the mtime of directories with the mtime
1589    * of the registry cache, but it does not work. It would not catch updated
1590    * plugins, which might bring more or less features.
1591    */
1592
1593   /* scan paths specified via --gst-plugin-path */
1594   GST_DEBUG ("scanning paths added via --gst-plugin-path");
1595   for (l = _priv_gst_plugin_paths; l != NULL; l = l->next) {
1596     GST_INFO ("Scanning plugin path: \"%s\"", (gchar *) l->data);
1597     changed |= gst_registry_scan_path_internal (&context, (gchar *) l->data);
1598   }
1599   /* keep plugin_paths around in case a re-scan is forced later on */
1600
1601   /* GST_PLUGIN_PATH specifies a list of directories to scan for
1602    * additional plugins.  These take precedence over the system plugins */
1603   plugin_path = g_getenv ("GST_PLUGIN_PATH_1_0");
1604   if (plugin_path == NULL)
1605     plugin_path = g_getenv ("GST_PLUGIN_PATH");
1606   if (plugin_path) {
1607     char **list;
1608     int i;
1609
1610     GST_DEBUG ("GST_PLUGIN_PATH set to %s", plugin_path);
1611     list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0);
1612     for (i = 0; list[i]; i++) {
1613       changed |= gst_registry_scan_path_internal (&context, list[i]);
1614     }
1615     g_strfreev (list);
1616   } else {
1617     GST_DEBUG ("GST_PLUGIN_PATH not set");
1618   }
1619
1620   /* GST_PLUGIN_SYSTEM_PATH specifies a list of plugins that are always
1621    * loaded by default.  If not set, this defaults to the system-installed
1622    * path, and the plugins installed in the user's home directory */
1623   plugin_path = g_getenv ("GST_PLUGIN_SYSTEM_PATH_1_0");
1624   if (plugin_path == NULL)
1625     plugin_path = g_getenv ("GST_PLUGIN_SYSTEM_PATH");
1626   if (plugin_path == NULL) {
1627     char *home_plugins;
1628
1629     GST_DEBUG ("GST_PLUGIN_SYSTEM_PATH not set");
1630
1631     /* plugins in the user's home directory take precedence over
1632      * system-installed ones */
1633     home_plugins = g_build_filename (g_get_user_data_dir (),
1634         "gstreamer-" GST_API_VERSION, "plugins", NULL);
1635
1636     GST_DEBUG ("scanning home plugins %s", home_plugins);
1637     changed |= gst_registry_scan_path_internal (&context, home_plugins);
1638     g_free (home_plugins);
1639
1640     /* add the main (installed) library path */
1641
1642 #ifdef G_OS_WIN32
1643     {
1644       char *base_dir;
1645       char *dir;
1646
1647       base_dir =
1648           g_win32_get_package_installation_directory_of_module
1649           (_priv_gst_dll_handle);
1650
1651       dir = g_build_filename (base_dir, GST_PLUGIN_SUBDIR,
1652           "gstreamer-" GST_API_VERSION, NULL);
1653       GST_DEBUG ("scanning DLL dir %s", dir);
1654
1655       changed |= gst_registry_scan_path_internal (&context, dir);
1656
1657       g_free (dir);
1658       g_free (base_dir);
1659     }
1660 #else
1661     GST_DEBUG ("scanning main plugins %s", PLUGINDIR);
1662     changed |= gst_registry_scan_path_internal (&context, PLUGINDIR);
1663 #endif
1664   } else {
1665     gchar **list;
1666     gint i;
1667
1668     GST_DEBUG ("GST_PLUGIN_SYSTEM_PATH set to %s", plugin_path);
1669     list = g_strsplit (plugin_path, G_SEARCHPATH_SEPARATOR_S, 0);
1670     for (i = 0; list[i]; i++) {
1671       changed |= gst_registry_scan_path_internal (&context, list[i]);
1672     }
1673     g_strfreev (list);
1674   }
1675
1676   clear_scan_context (&context);
1677   changed |= context.changed;
1678
1679   /* Remove cached plugins so stale info is cleared. */
1680   changed |= gst_registry_remove_cache_plugins (default_registry);
1681
1682   if (!changed) {
1683     GST_INFO ("Registry cache has not changed");
1684     return REGISTRY_SCAN_AND_UPDATE_SUCCESS_NOT_CHANGED;
1685   }
1686
1687   if (!write_changes) {
1688     GST_INFO ("Registry cache changed, but writing is disabled. Not writing.");
1689     return REGISTRY_SCAN_AND_UPDATE_FAILURE;
1690   }
1691
1692   GST_INFO ("Registry cache changed. Writing new registry cache");
1693   if (!priv_gst_registry_binary_write_cache (default_registry,
1694           default_registry->priv->plugins, registry_file)) {
1695     g_set_error (error, GST_CORE_ERROR, GST_CORE_ERROR_FAILED,
1696         _("Error writing registry cache to %s: %s"),
1697         registry_file, g_strerror (errno));
1698     return REGISTRY_SCAN_AND_UPDATE_FAILURE;
1699   }
1700
1701   GST_INFO ("Registry cache written successfully");
1702   return REGISTRY_SCAN_AND_UPDATE_SUCCESS_UPDATED;
1703 }
1704
1705 static gboolean
1706 ensure_current_registry (GError ** error)
1707 {
1708   gchar *registry_file;
1709   GstRegistry *default_registry;
1710   gboolean ret = TRUE;
1711   gboolean do_update = TRUE;
1712   gboolean have_cache = TRUE;
1713
1714   default_registry = gst_registry_get ();
1715
1716   registry_file = g_strdup (g_getenv ("GST_REGISTRY_1_0"));
1717   if (registry_file == NULL)
1718     registry_file = g_strdup (g_getenv ("GST_REGISTRY"));
1719   if (registry_file == NULL) {
1720     registry_file = g_build_filename (g_get_user_cache_dir (),
1721         "gstreamer-" GST_API_VERSION, "registry." TARGET_CPU ".bin", NULL);
1722   }
1723
1724   if (!_gst_disable_registry_cache) {
1725     GST_INFO ("reading registry cache: %s", registry_file);
1726     have_cache = priv_gst_registry_binary_read_cache (default_registry,
1727         registry_file);
1728     /* Only ever read the registry cache once, then disable it for
1729      * subsequent updates during the program lifetime */
1730     _gst_disable_registry_cache = TRUE;
1731   }
1732
1733   if (have_cache) {
1734     do_update = !_priv_gst_disable_registry_update;
1735     if (do_update) {
1736       const gchar *update_env;
1737
1738       if ((update_env = g_getenv ("GST_REGISTRY_UPDATE"))) {
1739         /* do update for any value different from "no" */
1740         do_update = (strcmp (update_env, "no") != 0);
1741       }
1742     }
1743   }
1744
1745   if (do_update) {
1746     const gchar *reuse_env;
1747
1748     if ((reuse_env = g_getenv ("GST_REGISTRY_REUSE_PLUGIN_SCANNER"))) {
1749       /* do reuse for any value different from "no" */
1750       __registry_reuse_plugin_scanner = (strcmp (reuse_env, "no") != 0);
1751     }
1752     /* now check registry */
1753     GST_DEBUG ("Updating registry cache");
1754     scan_and_update_registry (default_registry, registry_file, TRUE, error);
1755   } else {
1756     GST_DEBUG ("Not updating registry cache (disabled)");
1757   }
1758
1759   g_free (registry_file);
1760   GST_INFO ("registry reading and updating done, result = %d", ret);
1761
1762   return ret;
1763 }
1764 #endif /* GST_DISABLE_REGISTRY */
1765
1766 /**
1767  * gst_registry_fork_is_enabled:
1768  *
1769  * By default GStreamer will perform scanning and rebuilding of the
1770  * registry file using a helper child process.
1771  *
1772  * Applications might want to disable this behaviour with the
1773  * gst_registry_fork_set_enabled() function, in which case new plugins
1774  * are scanned (and loaded) into the application process.
1775  *
1776  * Returns: %TRUE if GStreamer will use the child helper process when
1777  * rebuilding the registry.
1778  */
1779 gboolean
1780 gst_registry_fork_is_enabled (void)
1781 {
1782   return _gst_enable_registry_fork;
1783 }
1784
1785 /**
1786  * gst_registry_fork_set_enabled:
1787  * @enabled: whether rebuilding the registry can use a temporary child helper process.
1788  *
1789  * Applications might want to disable/enable spawning of a child helper process
1790  * when rebuilding the registry. See gst_registry_fork_is_enabled() for more
1791  * information.
1792  */
1793 void
1794 gst_registry_fork_set_enabled (gboolean enabled)
1795 {
1796   _gst_enable_registry_fork = enabled;
1797 }
1798
1799 /**
1800  * gst_update_registry:
1801  *
1802  * Forces GStreamer to re-scan its plugin paths and update the default
1803  * plugin registry.
1804  *
1805  * Applications will almost never need to call this function, it is only
1806  * useful if the application knows new plugins have been installed (or old
1807  * ones removed) since the start of the application (or, to be precise, the
1808  * first call to gst_init()) and the application wants to make use of any
1809  * newly-installed plugins without restarting the application.
1810  *
1811  * Applications should assume that the registry update is neither atomic nor
1812  * thread-safe and should therefore not have any dynamic pipelines running
1813  * (including the playbin and decodebin elements) and should also not create
1814  * any elements or access the GStreamer registry while the update is in
1815  * progress.
1816  *
1817  * Note that this function may block for a significant amount of time.
1818  *
1819  * Returns: %TRUE if the registry has been updated successfully (does not
1820  *          imply that there were changes), otherwise %FALSE.
1821  */
1822 gboolean
1823 gst_update_registry (void)
1824 {
1825   gboolean res;
1826
1827 #ifndef GST_DISABLE_REGISTRY
1828   if (!_priv_gst_disable_registry) {
1829     GError *err = NULL;
1830
1831     res = ensure_current_registry (&err);
1832     if (err) {
1833       GST_WARNING ("registry update failed: %s", err->message);
1834       g_error_free (err);
1835     } else {
1836       GST_LOG ("registry update succeeded");
1837     }
1838   } else {
1839     GST_INFO ("registry update disabled by environment");
1840     res = TRUE;
1841   }
1842
1843 #else
1844   GST_WARNING ("registry update failed: %s", "registry disabled");
1845   res = TRUE;
1846 #endif /* GST_DISABLE_REGISTRY */
1847
1848   if (_priv_gst_preload_plugins) {
1849     GST_DEBUG ("Preloading indicated plugins...");
1850     g_slist_foreach (_priv_gst_preload_plugins, load_plugin_func, NULL);
1851   }
1852
1853   return res;
1854 }
1855
1856 /**
1857  * gst_registry_get_feature_list_cookie:
1858  * @registry: the registry
1859  *
1860  * Returns the registry's feature list cookie. This changes
1861  * every time a feature is added or removed from the registry.
1862  *
1863  * Returns: the feature list cookie.
1864  */
1865 guint32
1866 gst_registry_get_feature_list_cookie (GstRegistry * registry)
1867 {
1868   g_return_val_if_fail (GST_IS_REGISTRY (registry), 0);
1869
1870   return registry->priv->cookie;
1871 }