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