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