(root)/
glib-2.79.0/
gio/
giomodule.c
       1  /* GIO - GLib Input, Output and Streaming Library
       2   * 
       3   * Copyright (C) 2006-2007 Red Hat, Inc.
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   *
       7   * This library is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public
       9   * License as published by the Free Software Foundation; either
      10   * version 2.1 of the License, or (at your option) any later version.
      11   *
      12   * This library is distributed in the hope that it will be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15   * Lesser General Public License for more details.
      16   *
      17   * You should have received a copy of the GNU Lesser General
      18   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19   *
      20   * Author: Alexander Larsson <alexl@redhat.com>
      21   */
      22  
      23  #include "config.h"
      24  
      25  /* For the #GDesktopAppInfoLookup macros; since macro deprecation is implemented
      26   * in the preprocessor, we need to define this before including glib.h*/
      27  #ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
      28  #define GLIB_DISABLE_DEPRECATION_WARNINGS
      29  #endif
      30  
      31  #include <string.h>
      32  
      33  #include "giomodule.h"
      34  #include "giomodule-priv.h"
      35  #include "glib-private.h"
      36  #include "glocalfilemonitor.h"
      37  #include "gnativevolumemonitor.h"
      38  #include "gproxyresolver.h"
      39  #include "gproxy.h"
      40  #include "gsettingsbackendinternal.h"
      41  #include "ghttpproxy.h"
      42  #include "gsocks4proxy.h"
      43  #include "gsocks4aproxy.h"
      44  #include "gsocks5proxy.h"
      45  #include "gtlsbackend.h"
      46  #include "gvfs.h"
      47  #include "gnotificationbackend.h"
      48  #include "ginitable.h"
      49  #include "gnetworkmonitor.h"
      50  #include "gdebugcontroller.h"
      51  #include "gdebugcontrollerdbus.h"
      52  #include "gmemorymonitor.h"
      53  #include "gmemorymonitorportal.h"
      54  #include "gmemorymonitordbus.h"
      55  #include "gpowerprofilemonitor.h"
      56  #include "gpowerprofilemonitordbus.h"
      57  #include "gpowerprofilemonitorportal.h"
      58  #ifdef G_OS_WIN32
      59  #include "gregistrysettingsbackend.h"
      60  #include "giowin32-priv.h"
      61  #endif
      62  #include <glib/gstdio.h>
      63  
      64  #if defined(G_OS_UNIX) && !defined(__APPLE__)
      65  #include "gdesktopappinfo.h"
      66  #endif
      67  #ifdef HAVE_COCOA
      68  #include "gosxappinfo.h"
      69  #endif
      70  
      71  #ifdef __APPLE__
      72  #include <AvailabilityMacros.h>
      73  #endif
      74  
      75  #define __GLIB_H_INSIDE__
      76  #include "gconstructor.h"
      77  #undef __GLIB_H_INSIDE__
      78  
      79  /**
      80   * GIOModule:
      81   *
      82   * Provides an interface and default functions for loading and unloading 
      83   * modules. This is used internally to make GIO extensible, but can also
      84   * be used by others to implement module loading.
      85   */
      86  
      87  /**
      88   * GIOExtensionPoint:
      89   *
      90   * `GIOExtensionPoint` provides a mechanism for modules to extend the
      91   * functionality of the library or application that loaded it in an 
      92   * organized fashion.
      93   *
      94   * An extension point is identified by a name, and it may optionally
      95   * require that any implementation must be of a certain type (or derived
      96   * thereof). Use [func@Gio.IOExtensionPoint.register] to register an
      97   * extension point, and [method@Gio.IOExtensionPoint.set_required_type] to
      98   * set a required type.
      99   *
     100   * A module can implement an extension point by specifying the
     101   * [type@GObject.Type] that implements the functionality. Additionally, each
     102   * implementation of an extension point has a name, and a priority. Use
     103   * [func@Gio.IOExtensionPoint.implement] to implement an extension point.
     104   * 
     105   * ```c
     106   * GIOExtensionPoint *ep;
     107   *
     108   * // Register an extension point
     109   * ep = g_io_extension_point_register ("my-extension-point");
     110   * g_io_extension_point_set_required_type (ep, MY_TYPE_EXAMPLE);
     111   * ```
     112   *
     113   * ```c
     114   * // Implement an extension point
     115   * G_DEFINE_TYPE (MyExampleImpl, my_example_impl, MY_TYPE_EXAMPLE)
     116   * g_io_extension_point_implement ("my-extension-point",
     117   *                                 my_example_impl_get_type (),
     118   *                                 "my-example",
     119   *                                 10);
     120   * ```
     121   *
     122   *  It is up to the code that registered the extension point how
     123   *  it uses the implementations that have been associated with it.
     124   *  Depending on the use case, it may use all implementations, or
     125   *  only the one with the highest priority, or pick a specific
     126   *  one by name.
     127   *
     128   *  To avoid opening all modules just to find out what extension
     129   *  points they implement, GIO makes use of a caching mechanism,
     130   *  see [gio-querymodules](gio-querymodules.html).
     131   *  You are expected to run this command after installing a
     132   *  GIO module.
     133   *
     134   *  The `GIO_EXTRA_MODULES` environment variable can be used to
     135   *  specify additional directories to automatically load modules
     136   *  from. This environment variable has the same syntax as the
     137   *  `PATH`. If two modules have the same base name in different
     138   *  directories, then the latter one will be ignored. If additional
     139   *  directories are specified GIO will load modules from the built-in
     140   *  directory last.
     141   */
     142  
     143  /**
     144   * GIOModuleScope:
     145   *
     146   * Represents a scope for loading IO modules. A scope can be used for blocking
     147   * duplicate modules, or blocking a module you don't want to load.
     148   *
     149   * The scope can be used with g_io_modules_load_all_in_directory_with_scope()
     150   * or g_io_modules_scan_all_in_directory_with_scope().
     151   *
     152   * Since: 2.30
     153   */
     154  struct _GIOModuleScope {
     155    GIOModuleScopeFlags flags;
     156    GHashTable *basenames;
     157  };
     158  
     159  /**
     160   * g_io_module_scope_new:
     161   * @flags: flags for the new scope
     162   *
     163   * Create a new scope for loading of IO modules. A scope can be used for
     164   * blocking duplicate modules, or blocking a module you don't want to load.
     165   *
     166   * Specify the %G_IO_MODULE_SCOPE_BLOCK_DUPLICATES flag to block modules
     167   * which have the same base name as a module that has already been seen
     168   * in this scope.
     169   *
     170   * Returns: (transfer full): the new module scope
     171   *
     172   * Since: 2.30
     173   */
     174  GIOModuleScope *
     175  g_io_module_scope_new (GIOModuleScopeFlags flags)
     176  {
     177    GIOModuleScope *scope = g_new0 (GIOModuleScope, 1);
     178    scope->flags = flags;
     179    scope->basenames = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
     180    return scope;
     181  }
     182  
     183  /**
     184   * g_io_module_scope_free:
     185   * @scope: a module loading scope
     186   *
     187   * Free a module scope.
     188   *
     189   * Since: 2.30
     190   */
     191  void
     192  g_io_module_scope_free (GIOModuleScope *scope)
     193  {
     194    if (!scope)
     195      return;
     196    g_hash_table_destroy (scope->basenames);
     197    g_free (scope);
     198  }
     199  
     200  /**
     201   * g_io_module_scope_block:
     202   * @scope: a module loading scope
     203   * @basename: the basename to block
     204   *
     205   * Block modules with the given @basename from being loaded when
     206   * this scope is used with g_io_modules_scan_all_in_directory_with_scope()
     207   * or g_io_modules_load_all_in_directory_with_scope().
     208   *
     209   * Since: 2.30
     210   */
     211  void
     212  g_io_module_scope_block (GIOModuleScope *scope,
     213                           const gchar    *basename)
     214  {
     215    gchar *key;
     216  
     217    g_return_if_fail (scope != NULL);
     218    g_return_if_fail (basename != NULL);
     219  
     220    key = g_strdup (basename);
     221    g_hash_table_add (scope->basenames, key);
     222  }
     223  
     224  static gboolean
     225  _g_io_module_scope_contains (GIOModuleScope *scope,
     226                               const gchar    *basename)
     227  {
     228    return g_hash_table_contains (scope->basenames, basename);
     229  }
     230  
     231  struct _GIOModule {
     232    GTypeModule parent_instance;
     233  
     234    gchar       *filename;
     235    GModule     *library;
     236    gboolean     initialized; /* The module was loaded at least once */
     237  
     238    void (* load)   (GIOModule *module);
     239    void (* unload) (GIOModule *module);
     240  };
     241  
     242  struct _GIOModuleClass
     243  {
     244    GTypeModuleClass parent_class;
     245  
     246  };
     247  
     248  static void      g_io_module_finalize      (GObject      *object);
     249  static gboolean  g_io_module_load_module   (GTypeModule  *gmodule);
     250  static void      g_io_module_unload_module (GTypeModule  *gmodule);
     251  
     252  /**
     253   * GIOExtension:
     254   *
     255   * #GIOExtension is an opaque data structure and can only be accessed
     256   * using the following functions.
     257   */
     258  struct _GIOExtension {
     259    char *name;
     260    GType type;
     261    gint priority;
     262  };
     263  
     264  struct _GIOExtensionPoint {
     265    GType required_type;
     266    char *name;
     267    GList *extensions;
     268    GList *lazy_load_modules;
     269  };
     270  
     271  static GHashTable *extension_points = NULL;
     272  G_LOCK_DEFINE_STATIC(extension_points);
     273  
     274  G_DEFINE_TYPE (GIOModule, g_io_module, G_TYPE_TYPE_MODULE)
     275  
     276  static void
     277  g_io_module_class_init (GIOModuleClass *class)
     278  {
     279    GObjectClass     *object_class      = G_OBJECT_CLASS (class);
     280    GTypeModuleClass *type_module_class = G_TYPE_MODULE_CLASS (class);
     281  
     282    object_class->finalize     = g_io_module_finalize;
     283  
     284    type_module_class->load    = g_io_module_load_module;
     285    type_module_class->unload  = g_io_module_unload_module;
     286  }
     287  
     288  static void
     289  g_io_module_init (GIOModule *module)
     290  {
     291  }
     292  
     293  static void
     294  g_io_module_finalize (GObject *object)
     295  {
     296    GIOModule *module = G_IO_MODULE (object);
     297  
     298    g_free (module->filename);
     299  
     300    G_OBJECT_CLASS (g_io_module_parent_class)->finalize (object);
     301  }
     302  
     303  static gboolean
     304  load_symbols (GIOModule *module)
     305  {
     306    gchar *name;
     307    gchar *load_symname;
     308    gchar *unload_symname;
     309    gboolean ret;
     310  
     311    name = _g_io_module_extract_name (module->filename);
     312    load_symname = g_strconcat ("g_io_", name, "_load", NULL);
     313    unload_symname = g_strconcat ("g_io_", name, "_unload", NULL);
     314  
     315    ret = g_module_symbol (module->library,
     316                           load_symname,
     317                           (gpointer) &module->load) &&
     318          g_module_symbol (module->library,
     319                           unload_symname,
     320                           (gpointer) &module->unload);
     321  
     322    if (!ret)
     323      {
     324        /* Fallback to old names */
     325        ret = g_module_symbol (module->library,
     326                               "g_io_module_load",
     327                               (gpointer) &module->load) &&
     328              g_module_symbol (module->library,
     329                               "g_io_module_unload",
     330                               (gpointer) &module->unload);
     331      }
     332  
     333    g_free (name);
     334    g_free (load_symname);
     335    g_free (unload_symname);
     336  
     337    return ret;
     338  }
     339  
     340  static gboolean
     341  g_io_module_load_module (GTypeModule *gmodule)
     342  {
     343    GIOModule *module = G_IO_MODULE (gmodule);
     344    GError *error = NULL;
     345  
     346    if (!module->filename)
     347      {
     348        g_warning ("GIOModule path not set");
     349        return FALSE;
     350      }
     351  
     352    module->library = g_module_open_full (module->filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL, &error);
     353  
     354    if (!module->library)
     355      {
     356        g_printerr ("%s\n", error->message);
     357        g_clear_error (&error);
     358        return FALSE;
     359      }
     360  
     361    /* Make sure that the loaded library contains the required methods */
     362    if (!load_symbols (module))
     363      {
     364        g_printerr ("%s\n", g_module_error ());
     365        g_module_close (module->library);
     366  
     367        return FALSE;
     368      }
     369  
     370    /* Initialize the loaded module */
     371    module->load (module);
     372    module->initialized = TRUE;
     373  
     374    return TRUE;
     375  }
     376  
     377  static void
     378  g_io_module_unload_module (GTypeModule *gmodule)
     379  {
     380    GIOModule *module = G_IO_MODULE (gmodule);
     381  
     382    module->unload (module);
     383  
     384    g_module_close (module->library);
     385    module->library = NULL;
     386  
     387    module->load   = NULL;
     388    module->unload = NULL;
     389  }
     390  
     391  /**
     392   * g_io_module_new:
     393   * @filename: (type filename): filename of the shared library module.
     394   * 
     395   * Creates a new GIOModule that will load the specific
     396   * shared library when in use.
     397   * 
     398   * Returns: a #GIOModule from given @filename, 
     399   * or %NULL on error.
     400   **/
     401  GIOModule *
     402  g_io_module_new (const gchar *filename)
     403  {
     404    GIOModule *module;
     405  
     406    g_return_val_if_fail (filename != NULL, NULL);
     407  
     408    module = g_object_new (G_IO_TYPE_MODULE, NULL);
     409    module->filename = g_strdup (filename);
     410  
     411    return module;
     412  }
     413  
     414  static gboolean
     415  is_valid_module_name (const gchar        *basename,
     416                        GIOModuleScope     *scope)
     417  {
     418    gboolean result;
     419  
     420  #if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
     421    #if defined(__APPLE__)
     422    if (!g_str_has_prefix (basename, "lib") ||
     423        !(g_str_has_suffix (basename, ".so") ||
     424          g_str_has_suffix (basename, ".dylib")))
     425      return FALSE;
     426    #else
     427    if (!g_str_has_prefix (basename, "lib") ||
     428        !g_str_has_suffix (basename, ".so"))
     429      return FALSE;
     430    #endif
     431  #else
     432    if (!g_str_has_suffix (basename, ".dll"))
     433      return FALSE;
     434  #endif
     435  
     436    result = TRUE;
     437    if (scope)
     438      {
     439        result = _g_io_module_scope_contains (scope, basename) ? FALSE : TRUE;
     440        if (result && (scope->flags & G_IO_MODULE_SCOPE_BLOCK_DUPLICATES))
     441          g_io_module_scope_block (scope, basename);
     442      }
     443  
     444    return result;
     445  }
     446  
     447  
     448  /**
     449   * g_io_modules_scan_all_in_directory_with_scope:
     450   * @dirname: (type filename): pathname for a directory containing modules
     451   *     to scan.
     452   * @scope: a scope to use when scanning the modules
     453   *
     454   * Scans all the modules in the specified directory, ensuring that
     455   * any extension point implemented by a module is registered.
     456   *
     457   * This may not actually load and initialize all the types in each
     458   * module, some modules may be lazily loaded and initialized when
     459   * an extension point it implements is used with e.g.
     460   * g_io_extension_point_get_extensions() or
     461   * g_io_extension_point_get_extension_by_name().
     462   *
     463   * If you need to guarantee that all types are loaded in all the modules,
     464   * use g_io_modules_load_all_in_directory().
     465   *
     466   * Since: 2.30
     467   **/
     468  void
     469  g_io_modules_scan_all_in_directory_with_scope (const char     *dirname,
     470                                                 GIOModuleScope *scope)
     471  {
     472    const gchar *name;
     473    char *filename;
     474    GDir *dir;
     475    GStatBuf statbuf;
     476    char *data;
     477    time_t cache_time;
     478    GHashTable *cache;
     479  
     480    if (!g_module_supported ())
     481      return;
     482  
     483    dir = g_dir_open (dirname, 0, NULL);
     484    if (!dir)
     485      return;
     486  
     487    filename = g_build_filename (dirname, "giomodule.cache", NULL);
     488  
     489    cache = NULL;
     490    cache_time = 0;
     491    if (g_stat (filename, &statbuf) == 0 &&
     492        g_file_get_contents (filename, &data, NULL, NULL))
     493      {
     494        char **lines;
     495        int i;
     496  
     497        /* cache_time is the time the cache file was created; we also take
     498         * into account the change time because in ostree based systems, all
     499         * system file have mtime equal to epoch 0.
     500         *
     501         * Any file that has a ctime before this was created then and not modified
     502         * since then (userspace can't change ctime). Its possible to change the
     503         * ctime forward without changing the file content, by e.g.  chmoding the
     504         * file, but this is uncommon and will only cause us to not use the cache
     505         * so will not cause bugs.
     506         */
     507        cache_time = MAX(statbuf.st_mtime, statbuf.st_ctime);
     508  
     509        lines = g_strsplit (data, "\n", -1);
     510        g_free (data);
     511  
     512        for (i = 0;  lines[i] != NULL; i++)
     513  	{
     514  	  char *line = lines[i];
     515  	  char *file;
     516  	  char *colon;
     517  	  char **strv_extension_points;
     518  
     519  	  if (line[0] == '#')
     520  	    continue;
     521  
     522  	  colon = strchr (line, ':');
     523  	  if (colon == NULL || line == colon)
     524  	    continue; /* Invalid line, ignore */
     525  
     526  	  *colon = 0; /* terminate filename */
     527  	  file = g_strdup (line);
     528  	  colon++; /* after colon */
     529  
     530  	  while (g_ascii_isspace (*colon))
     531  	    colon++;
     532  
     533            if (G_UNLIKELY (!cache))
     534              cache = g_hash_table_new_full (g_str_hash, g_str_equal,
     535                                             g_free, (GDestroyNotify)g_strfreev);
     536  
     537  	  strv_extension_points = g_strsplit (colon, ",", -1);
     538  	  g_hash_table_insert (cache, file, strv_extension_points);
     539  	}
     540        g_strfreev (lines);
     541      }
     542  
     543    while ((name = g_dir_read_name (dir)))
     544      {
     545        if (is_valid_module_name (name, scope))
     546  	{
     547  	  GIOExtensionPoint *extension_point;
     548  	  GIOModule *module;
     549  	  gchar *path;
     550  	  char **strv_extension_points = NULL;
     551  	  int i;
     552  
     553  	  path = g_build_filename (dirname, name, NULL);
     554  	  module = g_io_module_new (path);
     555  
     556            if (cache)
     557              strv_extension_points = g_hash_table_lookup (cache, name);
     558  
     559  	  if (strv_extension_points != NULL &&
     560  	      g_stat (path, &statbuf) == 0 &&
     561  	      statbuf.st_ctime <= cache_time)
     562  	    {
     563  	      /* Lazy load/init the library when first required */
     564  	      for (i = 0; strv_extension_points[i] != NULL; i++)
     565  		{
     566  		  extension_point =
     567  		    g_io_extension_point_register (strv_extension_points[i]);
     568  		  extension_point->lazy_load_modules =
     569  		    g_list_prepend (extension_point->lazy_load_modules,
     570  				    module);
     571  		}
     572  	    }
     573  	  else
     574  	    {
     575  	      /* Try to load and init types */
     576  	      if (g_type_module_use (G_TYPE_MODULE (module)))
     577  		{
     578  		  g_type_module_unuse (G_TYPE_MODULE (module)); /* Unload */
     579  		  /* module must remain alive, because the type system keeps weak refs */
     580  		  g_ignore_leak (module);
     581  		}
     582  	      else
     583  		{
     584  		  g_printerr ("Failed to load module: %s\n", path);
     585  		  g_object_unref (module);
     586  		}
     587  	    }
     588  
     589  	  g_free (path);
     590  	}
     591      }
     592  
     593    g_dir_close (dir);
     594  
     595    if (cache)
     596      g_hash_table_destroy (cache);
     597  
     598    g_free (filename);
     599  }
     600  
     601  /**
     602   * g_io_modules_scan_all_in_directory:
     603   * @dirname: (type filename): pathname for a directory containing modules
     604   *     to scan.
     605   *
     606   * Scans all the modules in the specified directory, ensuring that
     607   * any extension point implemented by a module is registered.
     608   *
     609   * This may not actually load and initialize all the types in each
     610   * module, some modules may be lazily loaded and initialized when
     611   * an extension point it implements is used with e.g.
     612   * g_io_extension_point_get_extensions() or
     613   * g_io_extension_point_get_extension_by_name().
     614   *
     615   * If you need to guarantee that all types are loaded in all the modules,
     616   * use g_io_modules_load_all_in_directory().
     617   *
     618   * Since: 2.24
     619   **/
     620  void
     621  g_io_modules_scan_all_in_directory (const char *dirname)
     622  {
     623    g_io_modules_scan_all_in_directory_with_scope (dirname, NULL);
     624  }
     625  
     626  /**
     627   * g_io_modules_load_all_in_directory_with_scope:
     628   * @dirname: (type filename): pathname for a directory containing modules
     629   *     to load.
     630   * @scope: a scope to use when scanning the modules.
     631   *
     632   * Loads all the modules in the specified directory.
     633   *
     634   * If don't require all modules to be initialized (and thus registering
     635   * all gtypes) then you can use g_io_modules_scan_all_in_directory()
     636   * which allows delayed/lazy loading of modules.
     637   *
     638   * Returns: (element-type GIOModule) (transfer full): a list of #GIOModules loaded
     639   *      from the directory,
     640   *      All the modules are loaded into memory, if you want to
     641   *      unload them (enabling on-demand loading) you must call
     642   *      g_type_module_unuse() on all the modules. Free the list
     643   *      with g_list_free().
     644   *
     645   * Since: 2.30
     646   **/
     647  GList *
     648  g_io_modules_load_all_in_directory_with_scope (const char     *dirname,
     649                                                 GIOModuleScope *scope)
     650  {
     651    const gchar *name;
     652    GDir        *dir;
     653    GList *modules;
     654  
     655    if (!g_module_supported ())
     656      return NULL;
     657  
     658    dir = g_dir_open (dirname, 0, NULL);
     659    if (!dir)
     660      return NULL;
     661  
     662    modules = NULL;
     663    while ((name = g_dir_read_name (dir)))
     664      {
     665        if (is_valid_module_name (name, scope))
     666          {
     667            GIOModule *module;
     668            gchar     *path;
     669  
     670            path = g_build_filename (dirname, name, NULL);
     671            module = g_io_module_new (path);
     672  
     673            if (!g_type_module_use (G_TYPE_MODULE (module)))
     674              {
     675                g_printerr ("Failed to load module: %s\n", path);
     676                g_object_unref (module);
     677                g_free (path);
     678                continue;
     679              }
     680  	  
     681            g_free (path);
     682  
     683            modules = g_list_prepend (modules, module);
     684          }
     685      }
     686    
     687    g_dir_close (dir);
     688  
     689    return modules;
     690  }
     691  
     692  /**
     693   * g_io_modules_load_all_in_directory:
     694   * @dirname: (type filename): pathname for a directory containing modules
     695   *     to load.
     696   *
     697   * Loads all the modules in the specified directory.
     698   *
     699   * If don't require all modules to be initialized (and thus registering
     700   * all gtypes) then you can use g_io_modules_scan_all_in_directory()
     701   * which allows delayed/lazy loading of modules.
     702   *
     703   * Returns: (element-type GIOModule) (transfer full): a list of #GIOModules loaded
     704   *      from the directory,
     705   *      All the modules are loaded into memory, if you want to
     706   *      unload them (enabling on-demand loading) you must call
     707   *      g_type_module_unuse() on all the modules. Free the list
     708   *      with g_list_free().
     709   **/
     710  GList *
     711  g_io_modules_load_all_in_directory (const char *dirname)
     712  {
     713    return g_io_modules_load_all_in_directory_with_scope (dirname, NULL);
     714  }
     715  
     716  static gpointer
     717  try_class (GIOExtension *extension,
     718             guint         is_supported_offset)
     719  {
     720    GType type = g_io_extension_get_type (extension);
     721    typedef gboolean (*verify_func) (void);
     722    gpointer class;
     723  
     724    class = g_type_class_ref (type);
     725    if (!is_supported_offset || (* G_STRUCT_MEMBER(verify_func, class, is_supported_offset)) ())
     726      return class;
     727  
     728    g_type_class_unref (class);
     729    return NULL;
     730  }
     731  
     732  static void
     733  print_help (const char        *envvar,
     734              GIOExtensionPoint *ep)
     735  {
     736    g_print ("Supported arguments for %s environment variable:\n", envvar);
     737  
     738    if (g_io_extension_point_get_extensions (ep) == NULL)
     739      g_print (" (none)\n");
     740    else
     741      {
     742        GList *l;
     743        GIOExtension *extension;
     744        gsize width = 0;
     745  
     746        for (l = g_io_extension_point_get_extensions (ep); l; l = l->next)
     747          {
     748            extension = l->data;
     749            width = MAX (width, strlen (g_io_extension_get_name (extension)));
     750          }
     751  
     752        for (l = g_io_extension_point_get_extensions (ep); l; l = l->next)
     753          {
     754            extension = l->data;
     755  
     756            g_print (" %*s - %d\n", (int) MIN (width, G_MAXINT),
     757                     g_io_extension_get_name (extension),
     758                     g_io_extension_get_priority (extension));
     759          }
     760      }
     761  }
     762  
     763  /**
     764   * _g_io_module_get_default_type:
     765   * @extension_point: the name of an extension point
     766   * @envvar: (nullable): the name of an environment variable to
     767   *     override the default implementation.
     768   * @is_supported_offset: a vtable offset, or zero
     769   *
     770   * Retrieves the default class implementing @extension_point.
     771   *
     772   * If @envvar is not %NULL, and the environment variable with that
     773   * name is set, then the implementation it specifies will be tried
     774   * first. After that, or if @envvar is not set, all other
     775   * implementations will be tried in order of decreasing priority.
     776   *
     777   * If @is_supported_offset is non-zero, then it is the offset into the
     778   * class vtable at which there is a function that takes no arguments and
     779   * returns a boolean.  This function will be called on each candidate
     780   * implementation to check if it is actually usable or not.
     781   *
     782   * The result is cached after it is generated the first time, and
     783   * the function is thread-safe.
     784   *
     785   * Returns: (transfer none): the type to instantiate to implement
     786   *     @extension_point, or %G_TYPE_INVALID if there are no usable
     787   *     implementations.
     788   */
     789  GType
     790  _g_io_module_get_default_type (const gchar *extension_point,
     791                                 const gchar *envvar,
     792                                 guint        is_supported_offset)
     793  {
     794    static GRecMutex default_modules_lock;
     795    static GHashTable *default_modules;
     796    const char *use_this;
     797    GList *l;
     798    GIOExtensionPoint *ep;
     799    GIOExtension *extension, *preferred;
     800    gpointer impl;
     801  
     802    g_rec_mutex_lock (&default_modules_lock);
     803    if (default_modules)
     804      {
     805        gpointer key;
     806  
     807        if (g_hash_table_lookup_extended (default_modules, extension_point, &key, &impl))
     808          {
     809            g_rec_mutex_unlock (&default_modules_lock);
     810            return impl ? G_OBJECT_CLASS_TYPE (impl) : G_TYPE_INVALID;
     811          }
     812      }
     813    else
     814      {
     815        default_modules = g_hash_table_new (g_str_hash, g_str_equal);
     816      }
     817  
     818    _g_io_modules_ensure_loaded ();
     819    ep = g_io_extension_point_lookup (extension_point);
     820  
     821    if (!ep)
     822      {
     823        g_warn_if_reached ();
     824        g_rec_mutex_unlock (&default_modules_lock);
     825        return G_TYPE_INVALID;
     826      }
     827  
     828    /* It’s OK to query the environment here, even when running as setuid, because
     829     * it only allows a choice between existing already-loaded modules. No new
     830     * code is loaded based on the environment variable value. */
     831    use_this = envvar ? g_getenv (envvar) : NULL;
     832    if (g_strcmp0 (use_this, "help") == 0)
     833      {
     834        print_help (envvar, ep);
     835        use_this = NULL;
     836      }
     837  
     838    if (use_this)
     839      {
     840        preferred = g_io_extension_point_get_extension_by_name (ep, use_this);
     841        if (preferred)
     842          {
     843            impl = try_class (preferred, is_supported_offset);
     844            if (impl)
     845              goto done;
     846          }
     847        else
     848          g_warning ("Can't find module '%s' specified in %s", use_this, envvar);
     849      }
     850    else
     851      preferred = NULL;
     852  
     853    for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
     854      {
     855        extension = l->data;
     856        if (extension == preferred)
     857          continue;
     858  
     859        impl = try_class (extension, is_supported_offset);
     860        if (impl)
     861          goto done;
     862      }
     863  
     864    impl = NULL;
     865  
     866   done:
     867    g_hash_table_insert (default_modules, g_strdup (extension_point), impl);
     868    g_rec_mutex_unlock (&default_modules_lock);
     869  
     870    return impl ? G_OBJECT_CLASS_TYPE (impl) : G_TYPE_INVALID;
     871  }
     872  
     873  static gpointer
     874  try_implementation (const char           *extension_point,
     875                      GIOExtension         *extension,
     876  		    GIOModuleVerifyFunc   verify_func)
     877  {
     878    GType type = g_io_extension_get_type (extension);
     879    gpointer impl;
     880  
     881    if (g_type_is_a (type, G_TYPE_INITABLE))
     882      {
     883        GError *error = NULL;
     884  
     885        impl = g_initable_new (type, NULL, &error, NULL);
     886        if (impl)
     887          return impl;
     888  
     889        g_debug ("Failed to initialize %s (%s) for %s: %s",
     890                 g_io_extension_get_name (extension),
     891                 g_type_name (type),
     892                 extension_point,
     893                 error ? error->message : "");
     894        g_clear_error (&error);
     895        return NULL;
     896      }
     897    else
     898      {
     899        impl = g_object_new (type, NULL);
     900        if (!verify_func || verify_func (impl))
     901  	return impl;
     902  
     903        g_object_unref (impl);
     904        return NULL;
     905      }
     906  }
     907  
     908  static void
     909  weak_ref_free (GWeakRef *weak_ref)
     910  {
     911    g_weak_ref_clear (weak_ref);
     912    g_free (weak_ref);
     913  }
     914  
     915  /**
     916   * _g_io_module_get_default:
     917   * @extension_point: the name of an extension point
     918   * @envvar: (nullable): the name of an environment variable to
     919   *     override the default implementation.
     920   * @verify_func: (nullable): a function to call to verify that
     921   *     a given implementation is usable in the current environment.
     922   *
     923   * Retrieves the default object implementing @extension_point.
     924   *
     925   * If @envvar is not %NULL, and the environment variable with that
     926   * name is set, then the implementation it specifies will be tried
     927   * first. After that, or if @envvar is not set, all other
     928   * implementations will be tried in order of decreasing priority.
     929   *
     930   * If an extension point implementation implements #GInitable, then
     931   * that implementation will only be used if it initializes
     932   * successfully. Otherwise, if @verify_func is not %NULL, then it will
     933   * be called on each candidate implementation after construction, to
     934   * check if it is actually usable or not.
     935   *
     936   * The result is cached after it is generated the first time (but the cache does
     937   * not keep a strong reference to the object), and
     938   * the function is thread-safe.
     939   *
     940   * Returns: (transfer full) (nullable): an object implementing
     941   *     @extension_point, or %NULL if there are no usable
     942   *     implementations.
     943   */
     944  gpointer
     945  _g_io_module_get_default (const gchar         *extension_point,
     946  			  const gchar         *envvar,
     947  			  GIOModuleVerifyFunc  verify_func)
     948  {
     949    static GRecMutex default_modules_lock;
     950    static GHashTable *default_modules;
     951    const char *use_this;
     952    GList *l;
     953    GIOExtensionPoint *ep;
     954    GIOExtension *extension = NULL, *preferred;
     955    gpointer impl, value;
     956    GWeakRef *impl_weak_ref = NULL;
     957  
     958    g_rec_mutex_lock (&default_modules_lock);
     959    if (default_modules)
     960      {
     961        if (g_hash_table_lookup_extended (default_modules, extension_point,
     962                                          NULL, &value))
     963          {
     964            /* Don’t debug here, since we’re returning a cached object which was
     965             * already printed earlier. */
     966            impl_weak_ref = value;
     967            impl = g_weak_ref_get (impl_weak_ref);
     968  
     969            /* If the object has been finalised (impl == NULL), fall through and
     970             * instantiate a new one. */
     971            if (impl != NULL)
     972              {
     973                g_rec_mutex_unlock (&default_modules_lock);
     974                return g_steal_pointer (&impl);
     975              }
     976          }
     977      }
     978    else
     979      {
     980        default_modules = g_hash_table_new_full (g_str_hash, g_str_equal,
     981                                                 g_free, (GDestroyNotify) weak_ref_free);
     982      }
     983  
     984    _g_io_modules_ensure_loaded ();
     985    ep = g_io_extension_point_lookup (extension_point);
     986  
     987    if (!ep)
     988      {
     989        g_debug ("%s: Failed to find extension point ‘%s’",
     990                 G_STRFUNC, extension_point);
     991        g_warn_if_reached ();
     992        g_rec_mutex_unlock (&default_modules_lock);
     993        return NULL;
     994      }
     995  
     996    /* It’s OK to query the environment here, even when running as setuid, because
     997     * it only allows a choice between existing already-loaded modules. No new
     998     * code is loaded based on the environment variable value. */
     999    use_this = envvar ? g_getenv (envvar) : NULL;
    1000    if (g_strcmp0 (use_this, "help") == 0)
    1001      {
    1002        print_help (envvar, ep);
    1003        use_this = NULL;
    1004      }
    1005  
    1006    if (use_this)
    1007      {
    1008        preferred = g_io_extension_point_get_extension_by_name (ep, use_this);
    1009        if (preferred)
    1010  	{
    1011  	  impl = try_implementation (extension_point, preferred, verify_func);
    1012  	  extension = preferred;
    1013  	  if (impl)
    1014  	    goto done;
    1015  	}
    1016        else
    1017          g_warning ("Can't find module '%s' specified in %s", use_this, envvar);
    1018      }
    1019    else
    1020      preferred = NULL;
    1021  
    1022    for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
    1023      {
    1024        extension = l->data;
    1025        if (extension == preferred)
    1026  	continue;
    1027  
    1028        impl = try_implementation (extension_point, extension, verify_func);
    1029        if (impl)
    1030  	goto done;
    1031      }
    1032  
    1033    impl = NULL;
    1034  
    1035   done:
    1036    if (impl_weak_ref == NULL)
    1037      {
    1038        impl_weak_ref = g_new0 (GWeakRef, 1);
    1039        g_weak_ref_init (impl_weak_ref, impl);
    1040        g_hash_table_insert (default_modules, g_strdup (extension_point),
    1041                             g_steal_pointer (&impl_weak_ref));
    1042      }
    1043    else
    1044      {
    1045        g_weak_ref_set (impl_weak_ref, impl);
    1046      }
    1047  
    1048    g_rec_mutex_unlock (&default_modules_lock);
    1049  
    1050    if (impl != NULL)
    1051      {
    1052        g_assert (extension != NULL);
    1053        g_debug ("%s: Found default implementation %s (%s) for ‘%s’",
    1054                 G_STRFUNC, g_io_extension_get_name (extension),
    1055                 G_OBJECT_TYPE_NAME (impl), extension_point);
    1056      }
    1057    else
    1058      g_debug ("%s: Failed to find default implementation for ‘%s’",
    1059               G_STRFUNC, extension_point);
    1060  
    1061    return g_steal_pointer (&impl);
    1062  }
    1063  
    1064  extern GType g_inotify_file_monitor_get_type (void);
    1065  extern GType g_kqueue_file_monitor_get_type (void);
    1066  extern GType g_win32_file_monitor_get_type (void);
    1067  
    1068  extern GType _g_unix_volume_monitor_get_type (void);
    1069  extern GType _g_local_vfs_get_type (void);
    1070  
    1071  extern GType _g_win32_volume_monitor_get_type (void);
    1072  extern GType _g_winhttp_vfs_get_type (void);
    1073  
    1074  extern GType _g_dummy_proxy_resolver_get_type (void);
    1075  extern GType _g_dummy_tls_backend_get_type (void);
    1076  extern GType g_network_monitor_base_get_type (void);
    1077  #ifdef HAVE_NETLINK
    1078  extern GType _g_network_monitor_netlink_get_type (void);
    1079  extern GType _g_network_monitor_nm_get_type (void);
    1080  #endif
    1081  
    1082  extern GType g_debug_controller_dbus_get_type (void);
    1083  extern GType g_memory_monitor_dbus_get_type (void);
    1084  extern GType g_memory_monitor_portal_get_type (void);
    1085  extern GType g_memory_monitor_win32_get_type (void);
    1086  extern GType g_power_profile_monitor_dbus_get_type (void);
    1087  
    1088  #ifdef G_OS_UNIX
    1089  extern GType g_fdo_notification_backend_get_type (void);
    1090  extern GType g_gtk_notification_backend_get_type (void);
    1091  extern GType g_portal_notification_backend_get_type (void);
    1092  extern GType g_proxy_resolver_portal_get_type (void);
    1093  extern GType g_network_monitor_portal_get_type (void);
    1094  #endif
    1095  
    1096  #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
    1097  extern GType g_cocoa_notification_backend_get_type (void);
    1098  #endif
    1099  
    1100  #ifdef G_PLATFORM_WIN32
    1101  extern GType g_win32_notification_backend_get_type (void);
    1102  
    1103  #include <windows.h>
    1104  extern GType _g_win32_network_monitor_get_type (void);
    1105  
    1106  static HMODULE gio_dll = NULL;
    1107  
    1108  #ifndef GLIB_STATIC_COMPILATION
    1109  
    1110  BOOL WINAPI DllMain (HINSTANCE hinstDLL,
    1111                       DWORD     fdwReason,
    1112                       LPVOID    lpvReserved);
    1113  
    1114  BOOL WINAPI
    1115  DllMain (HINSTANCE hinstDLL,
    1116  	 DWORD     fdwReason,
    1117  	 LPVOID    lpvReserved)
    1118  {
    1119    if (fdwReason == DLL_PROCESS_ATTACH)
    1120      {
    1121        gio_dll = hinstDLL;
    1122        gio_win32_appinfo_init (FALSE);
    1123      }
    1124  
    1125    return TRUE;
    1126  }
    1127  
    1128  #elif defined(G_HAS_CONSTRUCTORS) /* && G_PLATFORM_WIN32 && GLIB_STATIC_COMPILATION */
    1129  extern void glib_win32_init (void);
    1130  extern void gobject_win32_init (void);
    1131  
    1132  #ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
    1133  #pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(giomodule_init_ctor)
    1134  #endif
    1135  
    1136  G_DEFINE_CONSTRUCTOR (giomodule_init_ctor)
    1137  
    1138  static void
    1139  giomodule_init_ctor (void)
    1140  {
    1141    /* When built dynamically, module initialization is done through DllMain
    1142     * function which is called when the dynamic library is loaded by the glib
    1143     * module AFTER loading gobject. So, in dynamic configuration glib and
    1144     * gobject are always initialized BEFORE gio.
    1145     *
    1146     * When built statically, initialization mechanism relies on hooking
    1147     * functions to the CRT section directly at compilation time. As we don't
    1148     * control how each compilation unit will be built and in which order, we
    1149     * obtain the same kind of issue as the "static initialization order fiasco".
    1150     * In this case, we must ensure explicitly that glib and gobject are always
    1151     * well initialized BEFORE gio.
    1152     */
    1153    glib_win32_init ();
    1154    gobject_win32_init ();
    1155    gio_win32_appinfo_init (FALSE);
    1156  }
    1157  
    1158  #else /* G_PLATFORM_WIN32 && GLIB_STATIC_COMPILATION && !G_HAS_CONSTRUCTORS */
    1159  #error Your platform/compiler is missing constructor support
    1160  #endif /* GLIB_STATIC_COMPILATION */
    1161  
    1162  void *
    1163  _g_io_win32_get_module (void)
    1164  {
    1165    if (!gio_dll)
    1166      GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
    1167                         GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
    1168                         (LPCWSTR) _g_io_win32_get_module,
    1169                         &gio_dll);
    1170    return gio_dll;
    1171  }
    1172  
    1173  #endif /* G_PLATFORM_WIN32 */
    1174  
    1175  void
    1176  _g_io_modules_ensure_extension_points_registered (void)
    1177  {
    1178    static gsize registered_extensions = FALSE;
    1179    GIOExtensionPoint *ep;
    1180  
    1181    if (g_once_init_enter (&registered_extensions))
    1182      {
    1183  #if defined(G_OS_UNIX) && !defined(__APPLE__)
    1184  #if !GLIB_CHECK_VERSION (3, 0, 0)
    1185        ep = g_io_extension_point_register (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
    1186        g_io_extension_point_set_required_type (ep, G_TYPE_DESKTOP_APP_INFO_LOOKUP);
    1187  #endif
    1188  #endif
    1189  
    1190        ep = g_io_extension_point_register (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME);
    1191        g_io_extension_point_set_required_type (ep, G_TYPE_LOCAL_FILE_MONITOR);
    1192  
    1193        ep = g_io_extension_point_register (G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME);
    1194        g_io_extension_point_set_required_type (ep, G_TYPE_LOCAL_FILE_MONITOR);
    1195  
    1196        ep = g_io_extension_point_register (G_VOLUME_MONITOR_EXTENSION_POINT_NAME);
    1197        g_io_extension_point_set_required_type (ep, G_TYPE_VOLUME_MONITOR);
    1198        
    1199        ep = g_io_extension_point_register (G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME);
    1200        g_io_extension_point_set_required_type (ep, G_TYPE_NATIVE_VOLUME_MONITOR);
    1201        
    1202        ep = g_io_extension_point_register (G_VFS_EXTENSION_POINT_NAME);
    1203        g_io_extension_point_set_required_type (ep, G_TYPE_VFS);
    1204  
    1205        ep = g_io_extension_point_register ("gsettings-backend");
    1206        g_io_extension_point_set_required_type (ep, G_TYPE_OBJECT);
    1207  
    1208        ep = g_io_extension_point_register (G_PROXY_RESOLVER_EXTENSION_POINT_NAME);
    1209        g_io_extension_point_set_required_type (ep, G_TYPE_PROXY_RESOLVER);
    1210  
    1211        ep = g_io_extension_point_register (G_PROXY_EXTENSION_POINT_NAME);
    1212        g_io_extension_point_set_required_type (ep, G_TYPE_PROXY);
    1213  
    1214        ep = g_io_extension_point_register (G_TLS_BACKEND_EXTENSION_POINT_NAME);
    1215        g_io_extension_point_set_required_type (ep, G_TYPE_TLS_BACKEND);
    1216  
    1217        ep = g_io_extension_point_register (G_NETWORK_MONITOR_EXTENSION_POINT_NAME);
    1218        g_io_extension_point_set_required_type (ep, G_TYPE_NETWORK_MONITOR);
    1219  
    1220        ep = g_io_extension_point_register (G_NOTIFICATION_BACKEND_EXTENSION_POINT_NAME);
    1221        g_io_extension_point_set_required_type (ep, G_TYPE_NOTIFICATION_BACKEND);
    1222  
    1223        ep = g_io_extension_point_register (G_DEBUG_CONTROLLER_EXTENSION_POINT_NAME);
    1224        g_io_extension_point_set_required_type (ep, G_TYPE_DEBUG_CONTROLLER);
    1225  
    1226        ep = g_io_extension_point_register (G_MEMORY_MONITOR_EXTENSION_POINT_NAME);
    1227        g_io_extension_point_set_required_type (ep, G_TYPE_MEMORY_MONITOR);
    1228  
    1229        ep = g_io_extension_point_register (G_POWER_PROFILE_MONITOR_EXTENSION_POINT_NAME);
    1230        g_io_extension_point_set_required_type (ep, G_TYPE_POWER_PROFILE_MONITOR);
    1231  
    1232        g_once_init_leave (&registered_extensions, TRUE);
    1233      }
    1234  }
    1235  
    1236  static gchar *
    1237  get_gio_module_dir (void)
    1238  {
    1239    gchar *module_dir;
    1240    gboolean is_setuid = GLIB_PRIVATE_CALL (g_check_setuid) ();
    1241  
    1242    /* If running as setuid, loading modules from an arbitrary directory
    1243     * controlled by the unprivileged user who is running the program could allow
    1244     * for execution of arbitrary code (in constructors in modules).
    1245     * Don’t allow it.
    1246     *
    1247     * If a setuid program somehow needs to load additional GIO modules, it should
    1248     * explicitly call g_io_modules_scan_all_in_directory(). */
    1249    module_dir = !is_setuid ? g_strdup (g_getenv ("GIO_MODULE_DIR")) : NULL;
    1250    if (module_dir == NULL)
    1251      {
    1252  #ifdef G_OS_WIN32
    1253        gchar *install_dir;
    1254  
    1255        install_dir = g_win32_get_package_installation_directory_of_module (gio_dll);
    1256        module_dir = g_build_filename (install_dir,
    1257                                       "lib", "gio", "modules",
    1258                                       NULL);
    1259        g_free (install_dir);
    1260  #else
    1261        module_dir = g_strdup (GIO_MODULE_DIR);
    1262  #ifdef __APPLE__
    1263  #include "TargetConditionals.h"
    1264  /* Only auto-relocate on macOS, not watchOS etc; older macOS SDKs only define TARGET_OS_MAC */
    1265  #if (defined (TARGET_OS_OSX) && TARGET_OS_OSX) || \
    1266       (!defined (TARGET_OS_OSX) && defined (TARGET_OS_MAC) && TARGET_OS_MAC)
    1267  #include <dlfcn.h>
    1268        {
    1269          g_autofree gchar *path = NULL;
    1270          g_autofree gchar *possible_dir = NULL;
    1271          Dl_info info;
    1272  
    1273          if (dladdr (get_gio_module_dir, &info))
    1274            {
    1275              /* Gets path to the PREFIX/lib directory */
    1276              path = g_path_get_dirname (info.dli_fname);
    1277              possible_dir = g_build_filename (path, "gio", "modules", NULL);
    1278              if (g_file_test (possible_dir, G_FILE_TEST_IS_DIR))
    1279                {
    1280                  g_free (module_dir);
    1281                  module_dir = g_steal_pointer (&possible_dir);
    1282                }
    1283            }
    1284        }
    1285  #endif
    1286  #endif
    1287  #endif
    1288      }
    1289  
    1290    return module_dir;
    1291  }
    1292  
    1293  void
    1294  _g_io_modules_ensure_loaded (void)
    1295  {
    1296    static gsize loaded_dirs = FALSE;
    1297    const char *module_path;
    1298    GIOModuleScope *scope;
    1299  
    1300    _g_io_modules_ensure_extension_points_registered ();
    1301  
    1302    if (g_once_init_enter (&loaded_dirs))
    1303      {
    1304        gboolean is_setuid = GLIB_PRIVATE_CALL (g_check_setuid) ();
    1305        gchar *module_dir;
    1306  
    1307        scope = g_io_module_scope_new (G_IO_MODULE_SCOPE_BLOCK_DUPLICATES);
    1308  
    1309        /* First load any overrides, extras (but not if running as setuid!) */
    1310        module_path = !is_setuid ? g_getenv ("GIO_EXTRA_MODULES") : NULL;
    1311        if (module_path)
    1312  	{
    1313  	  gchar **paths;
    1314  	  int i;
    1315  
    1316  	  paths = g_strsplit (module_path, G_SEARCHPATH_SEPARATOR_S, 0);
    1317  
    1318  	  for (i = 0; paths[i] != NULL; i++)
    1319  	    {
    1320  	      g_io_modules_scan_all_in_directory_with_scope (paths[i], scope);
    1321  	    }
    1322  
    1323  	  g_strfreev (paths);
    1324  	}
    1325  
    1326        /* Then load the compiled in path */
    1327        module_dir = get_gio_module_dir ();
    1328  
    1329        g_io_modules_scan_all_in_directory_with_scope (module_dir, scope);
    1330        g_free (module_dir);
    1331  
    1332        g_io_module_scope_free (scope);
    1333  
    1334        /* Initialize types from built-in "modules" */
    1335        g_type_ensure (g_null_settings_backend_get_type ());
    1336        g_type_ensure (g_memory_settings_backend_get_type ());
    1337        g_type_ensure (g_keyfile_settings_backend_get_type ());
    1338        g_type_ensure (g_power_profile_monitor_dbus_get_type ());
    1339  #if defined(HAVE_INOTIFY_INIT1)
    1340        g_type_ensure (g_inotify_file_monitor_get_type ());
    1341  #endif
    1342  #if defined(HAVE_KQUEUE)
    1343        g_type_ensure (g_kqueue_file_monitor_get_type ());
    1344  #endif
    1345  #ifdef G_OS_WIN32
    1346        g_type_ensure (_g_win32_volume_monitor_get_type ());
    1347        g_type_ensure (g_win32_file_monitor_get_type ());
    1348        g_type_ensure (g_registry_settings_backend_get_type ());
    1349  #endif
    1350  #ifdef HAVE_COCOA
    1351        g_type_ensure (g_nextstep_settings_backend_get_type ());
    1352        g_type_ensure (g_osx_app_info_get_type ());
    1353  #endif
    1354  #ifdef G_OS_UNIX
    1355        g_type_ensure (_g_unix_volume_monitor_get_type ());
    1356        g_type_ensure (g_debug_controller_dbus_get_type ());
    1357        g_type_ensure (g_fdo_notification_backend_get_type ());
    1358        g_type_ensure (g_gtk_notification_backend_get_type ());
    1359        g_type_ensure (g_portal_notification_backend_get_type ());
    1360        g_type_ensure (g_memory_monitor_dbus_get_type ());
    1361        g_type_ensure (g_memory_monitor_portal_get_type ());
    1362        g_type_ensure (g_network_monitor_portal_get_type ());
    1363        g_type_ensure (g_power_profile_monitor_portal_get_type ());
    1364        g_type_ensure (g_proxy_resolver_portal_get_type ());
    1365  #endif
    1366  #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
    1367        g_type_ensure (g_cocoa_notification_backend_get_type ());
    1368  #endif
    1369  #ifdef G_OS_WIN32
    1370        g_type_ensure (g_win32_notification_backend_get_type ());
    1371        g_type_ensure (_g_winhttp_vfs_get_type ());
    1372        g_type_ensure (g_memory_monitor_win32_get_type ());
    1373  #endif
    1374        g_type_ensure (_g_local_vfs_get_type ());
    1375        g_type_ensure (_g_dummy_proxy_resolver_get_type ());
    1376        g_type_ensure (_g_http_proxy_get_type ());
    1377        g_type_ensure (_g_https_proxy_get_type ());
    1378        g_type_ensure (_g_socks4a_proxy_get_type ());
    1379        g_type_ensure (_g_socks4_proxy_get_type ());
    1380        g_type_ensure (_g_socks5_proxy_get_type ());
    1381        g_type_ensure (_g_dummy_tls_backend_get_type ());
    1382        g_type_ensure (g_network_monitor_base_get_type ());
    1383  #ifdef HAVE_NETLINK
    1384        g_type_ensure (_g_network_monitor_netlink_get_type ());
    1385        g_type_ensure (_g_network_monitor_nm_get_type ());
    1386  #endif
    1387  #ifdef G_OS_WIN32
    1388        g_type_ensure (_g_win32_network_monitor_get_type ());
    1389  #endif
    1390  
    1391        g_once_init_leave (&loaded_dirs, TRUE);
    1392      }
    1393  }
    1394  
    1395  static void
    1396  g_io_extension_point_free (GIOExtensionPoint *ep)
    1397  {
    1398    g_free (ep->name);
    1399    g_free (ep);
    1400  }
    1401  
    1402  /**
    1403   * g_io_extension_point_register:
    1404   * @name: The name of the extension point
    1405   *
    1406   * Registers an extension point.
    1407   *
    1408   * Returns: (transfer none): the new #GIOExtensionPoint. This object is
    1409   *    owned by GIO and should not be freed.
    1410   */
    1411  GIOExtensionPoint *
    1412  g_io_extension_point_register (const char *name)
    1413  {
    1414    GIOExtensionPoint *ep;
    1415    
    1416    G_LOCK (extension_points);
    1417    if (extension_points == NULL)
    1418      extension_points = g_hash_table_new_full (g_str_hash,
    1419  					      g_str_equal,
    1420  					      NULL,
    1421  					      (GDestroyNotify)g_io_extension_point_free);
    1422  
    1423    ep = g_hash_table_lookup (extension_points, name);
    1424    if (ep != NULL)
    1425      {
    1426        G_UNLOCK (extension_points);
    1427        return ep;
    1428      }
    1429  
    1430    ep = g_new0 (GIOExtensionPoint, 1);
    1431    ep->name = g_strdup (name);
    1432    
    1433    g_hash_table_insert (extension_points, ep->name, ep);
    1434    
    1435    G_UNLOCK (extension_points);
    1436  
    1437    return ep;
    1438  }
    1439  
    1440  /**
    1441   * g_io_extension_point_lookup:
    1442   * @name: the name of the extension point
    1443   *
    1444   * Looks up an existing extension point.
    1445   *
    1446   * Returns: (transfer none): the #GIOExtensionPoint, or %NULL if there
    1447   *    is no registered extension point with the given name.
    1448   */
    1449  GIOExtensionPoint *
    1450  g_io_extension_point_lookup (const char *name)
    1451  {
    1452    GIOExtensionPoint *ep;
    1453  
    1454    G_LOCK (extension_points);
    1455    ep = NULL;
    1456    if (extension_points != NULL)
    1457      ep = g_hash_table_lookup (extension_points, name);
    1458    
    1459    G_UNLOCK (extension_points);
    1460  
    1461    return ep;
    1462    
    1463  }
    1464  
    1465  /**
    1466   * g_io_extension_point_set_required_type:
    1467   * @extension_point: a #GIOExtensionPoint
    1468   * @type: the #GType to require
    1469   *
    1470   * Sets the required type for @extension_point to @type. 
    1471   * All implementations must henceforth have this type.
    1472   */
    1473  void
    1474  g_io_extension_point_set_required_type (GIOExtensionPoint *extension_point,
    1475  					GType              type)
    1476  {
    1477    extension_point->required_type = type;
    1478  }
    1479  
    1480  /**
    1481   * g_io_extension_point_get_required_type:
    1482   * @extension_point: a #GIOExtensionPoint
    1483   *
    1484   * Gets the required type for @extension_point.
    1485   *
    1486   * Returns: the #GType that all implementations must have, 
    1487   *   or %G_TYPE_INVALID if the extension point has no required type
    1488   */
    1489  GType
    1490  g_io_extension_point_get_required_type (GIOExtensionPoint *extension_point)
    1491  {
    1492    return extension_point->required_type;
    1493  }
    1494  
    1495  static void
    1496  lazy_load_modules (GIOExtensionPoint *extension_point)
    1497  {
    1498    GIOModule *module;
    1499    GList *l;
    1500  
    1501    for (l = extension_point->lazy_load_modules; l != NULL; l = l->next)
    1502      {
    1503        module = l->data;
    1504  
    1505        if (!module->initialized)
    1506  	{
    1507  	  if (g_type_module_use (G_TYPE_MODULE (module)))
    1508  	    g_type_module_unuse (G_TYPE_MODULE (module)); /* Unload */
    1509  	  else
    1510  	    g_printerr ("Failed to load module: %s\n",
    1511  			module->filename);
    1512  	}
    1513      }
    1514  }
    1515  
    1516  /**
    1517   * g_io_extension_point_get_extensions:
    1518   * @extension_point: a #GIOExtensionPoint
    1519   *
    1520   * Gets a list of all extensions that implement this extension point.
    1521   * The list is sorted by priority, beginning with the highest priority.
    1522   *
    1523   * Returns: (element-type GIOExtension) (transfer none): a #GList of
    1524   *     #GIOExtensions. The list is owned by GIO and should not be
    1525   *     modified.
    1526   */
    1527  GList *
    1528  g_io_extension_point_get_extensions (GIOExtensionPoint *extension_point)
    1529  {
    1530    g_return_val_if_fail (extension_point != NULL, NULL);
    1531  
    1532    lazy_load_modules (extension_point);
    1533    return extension_point->extensions;
    1534  }
    1535  
    1536  /**
    1537   * g_io_extension_point_get_extension_by_name:
    1538   * @extension_point: a #GIOExtensionPoint
    1539   * @name: the name of the extension to get
    1540   *
    1541   * Finds a #GIOExtension for an extension point by name.
    1542   *
    1543   * Returns: (transfer none): the #GIOExtension for @extension_point that has the
    1544   *    given name, or %NULL if there is no extension with that name
    1545   */
    1546  GIOExtension *
    1547  g_io_extension_point_get_extension_by_name (GIOExtensionPoint *extension_point,
    1548  					    const char        *name)
    1549  {
    1550    GList *l;
    1551  
    1552    g_return_val_if_fail (name != NULL, NULL);
    1553  
    1554    lazy_load_modules (extension_point);
    1555    for (l = extension_point->extensions; l != NULL; l = l->next)
    1556      {
    1557        GIOExtension *e = l->data;
    1558  
    1559        if (e->name != NULL &&
    1560  	  strcmp (e->name, name) == 0)
    1561  	return e;
    1562      }
    1563    
    1564    return NULL;
    1565  }
    1566  
    1567  static gint
    1568  extension_prio_compare (gconstpointer  a,
    1569  			gconstpointer  b)
    1570  {
    1571    const GIOExtension *extension_a = a, *extension_b = b;
    1572  
    1573    if (extension_a->priority > extension_b->priority)
    1574      return -1;
    1575  
    1576    if (extension_b->priority > extension_a->priority)
    1577      return 1;
    1578  
    1579    return 0;
    1580  }
    1581  
    1582  /**
    1583   * g_io_extension_point_implement:
    1584   * @extension_point_name: the name of the extension point
    1585   * @type: the #GType to register as extension 
    1586   * @extension_name: the name for the extension
    1587   * @priority: the priority for the extension
    1588   *
    1589   * Registers @type as extension for the extension point with name
    1590   * @extension_point_name. 
    1591   *
    1592   * If @type has already been registered as an extension for this 
    1593   * extension point, the existing #GIOExtension object is returned.
    1594   *
    1595   * Returns: (transfer none): a #GIOExtension object for #GType
    1596   */
    1597  GIOExtension *
    1598  g_io_extension_point_implement (const char *extension_point_name,
    1599  				GType       type,
    1600  				const char *extension_name,
    1601  				gint        priority)
    1602  {
    1603    GIOExtensionPoint *extension_point;
    1604    GIOExtension *extension;
    1605    GList *l;
    1606  
    1607    g_return_val_if_fail (extension_point_name != NULL, NULL);
    1608  
    1609    extension_point = g_io_extension_point_lookup (extension_point_name);
    1610    if (extension_point == NULL)
    1611      {
    1612        g_warning ("Tried to implement non-registered extension point %s", extension_point_name);
    1613        return NULL;
    1614      }
    1615    
    1616    if (extension_point->required_type != 0 &&
    1617        !g_type_is_a (type, extension_point->required_type))
    1618      {
    1619        g_warning ("Tried to register an extension of the type %s to extension point %s. "
    1620  		 "Expected type is %s.",
    1621  		 g_type_name (type),
    1622  		 extension_point_name, 
    1623  		 g_type_name (extension_point->required_type));
    1624        return NULL;
    1625      }      
    1626  
    1627    /* It's safe to register the same type multiple times */
    1628    for (l = extension_point->extensions; l != NULL; l = l->next)
    1629      {
    1630        extension = l->data;
    1631        if (extension->type == type)
    1632  	return extension;
    1633      }
    1634    
    1635    extension = g_slice_new0 (GIOExtension);
    1636    extension->type = type;
    1637    extension->name = g_strdup (extension_name);
    1638    extension->priority = priority;
    1639    
    1640    extension_point->extensions = g_list_insert_sorted (extension_point->extensions,
    1641  						      extension, extension_prio_compare);
    1642    
    1643    return extension;
    1644  }
    1645  
    1646  /**
    1647   * g_io_extension_ref_class:
    1648   * @extension: a #GIOExtension
    1649   *
    1650   * Gets a reference to the class for the type that is 
    1651   * associated with @extension.
    1652   *
    1653   * Returns: (transfer full): the #GTypeClass for the type of @extension
    1654   */
    1655  GTypeClass *
    1656  g_io_extension_ref_class (GIOExtension *extension)
    1657  {
    1658    return g_type_class_ref (extension->type);
    1659  }
    1660  
    1661  /**
    1662   * g_io_extension_get_type:
    1663   * @extension: a #GIOExtension
    1664   *
    1665   * Gets the type associated with @extension.
    1666   *
    1667   * Returns: the type of @extension
    1668   */
    1669  GType
    1670  g_io_extension_get_type (GIOExtension *extension)
    1671  {
    1672    return extension->type;
    1673  }
    1674  
    1675  /**
    1676   * g_io_extension_get_name:
    1677   * @extension: a #GIOExtension
    1678   *
    1679   * Gets the name under which @extension was registered.
    1680   *
    1681   * Note that the same type may be registered as extension
    1682   * for multiple extension points, under different names.
    1683   *
    1684   * Returns: the name of @extension.
    1685   */
    1686  const char *
    1687  g_io_extension_get_name (GIOExtension *extension)
    1688  {
    1689    return extension->name;
    1690  }
    1691  
    1692  /**
    1693   * g_io_extension_get_priority:
    1694   * @extension: a #GIOExtension
    1695   *
    1696   * Gets the priority with which @extension was registered.
    1697   *
    1698   * Returns: the priority of @extension
    1699   */
    1700  gint
    1701  g_io_extension_get_priority (GIOExtension *extension)
    1702  {
    1703    return extension->priority;
    1704  }