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 */
149struct _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 */
169GIOModuleScope *
170g_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 (hash_func: g_str_hash, key_equal_func: g_str_equal, key_destroy_func: 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 */
186void
187g_io_module_scope_free (GIOModuleScope *scope)
188{
189 if (!scope)
190 return;
191 g_hash_table_destroy (hash_table: scope->basenames);
192 g_free (mem: 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 */
206void
207g_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 (str: basename);
216 g_hash_table_add (hash_table: scope->basenames, key);
217}
218
219static gboolean
220_g_io_module_scope_contains (GIOModuleScope *scope,
221 const gchar *basename)
222{
223 return g_hash_table_contains (hash_table: scope->basenames, key: basename);
224}
225
226struct _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
237struct _GIOModuleClass
238{
239 GTypeModuleClass parent_class;
240
241};
242
243static void g_io_module_finalize (GObject *object);
244static gboolean g_io_module_load_module (GTypeModule *gmodule);
245static 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 */
253struct _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 */
265struct _GIOExtensionPoint {
266 GType required_type;
267 char *name;
268 GList *extensions;
269 GList *lazy_load_modules;
270};
271
272static GHashTable *extension_points = NULL;
273G_LOCK_DEFINE_STATIC(extension_points);
274
275G_DEFINE_TYPE (GIOModule, g_io_module, G_TYPE_TYPE_MODULE)
276
277static void
278g_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
289static void
290g_io_module_init (GIOModule *module)
291{
292}
293
294static void
295g_io_module_finalize (GObject *object)
296{
297 GIOModule *module = G_IO_MODULE (object);
298
299 g_free (mem: module->filename);
300
301 G_OBJECT_CLASS (g_io_module_parent_class)->finalize (object);
302}
303
304static gboolean
305load_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 (filename: module->filename);
313 load_symname = g_strconcat (string1: "g_io_", name, "_load", NULL);
314 unload_symname = g_strconcat (string1: "g_io_", name, "_unload", NULL);
315
316 ret = g_module_symbol (module: module->library,
317 symbol_name: load_symname,
318 symbol: (gpointer) &module->load) &&
319 g_module_symbol (module: module->library,
320 symbol_name: unload_symname,
321 symbol: (gpointer) &module->unload);
322
323 if (!ret)
324 {
325 /* Fallback to old names */
326 ret = g_module_symbol (module: module->library,
327 symbol_name: "g_io_module_load",
328 symbol: (gpointer) &module->load) &&
329 g_module_symbol (module: module->library,
330 symbol_name: "g_io_module_unload",
331 symbol: (gpointer) &module->unload);
332 }
333
334 g_free (mem: name);
335 g_free (mem: load_symname);
336 g_free (mem: unload_symname);
337
338 return ret;
339}
340
341static gboolean
342g_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 (file_name: module->filename, flags: G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
353
354 if (!module->library)
355 {
356 g_printerr (format: "%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 (format: "%s\n", g_module_error ());
364 g_module_close (module: 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
376static void
377g_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: 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 **/
400GIOModule *
401g_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 (str: filename);
409
410 return module;
411}
412
413static gboolean
414is_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 (str: basename, prefix: "lib") ||
421 !g_str_has_suffix (str: basename, suffix: ".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 **/
460void
461g_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 (path: dirname, flags: 0, NULL);
476 if (!dir)
477 return;
478
479 filename = g_build_filename (first_element: dirname, "giomodule.cache", NULL);
480
481 cache = NULL;
482 cache_time = 0;
483 if (g_stat (file: filename, buf: &statbuf) == 0 &&
484 g_file_get_contents (filename, contents: &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 (string: data, delimiter: "\n", max_tokens: -1);
502 g_free (mem: 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 (s: line, c: ':');
515 if (colon == NULL || line == colon)
516 continue; /* Invalid line, ignore */
517
518 *colon = 0; /* terminate filename */
519 file = g_strdup (str: 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 (hash_func: g_str_hash, key_equal_func: g_str_equal,
527 key_destroy_func: g_free, value_destroy_func: (GDestroyNotify)g_strfreev);
528
529 extension_points = g_strsplit (string: colon, delimiter: ",", max_tokens: -1);
530 g_hash_table_insert (hash_table: cache, key: file, value: extension_points);
531 }
532 g_strfreev (str_array: lines);
533 }
534
535 while ((name = g_dir_read_name (dir)))
536 {
537 if (is_valid_module_name (basename: 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 (first_element: dirname, name, NULL);
546 module = g_io_module_new (filename: path);
547
548 if (cache)
549 extension_points = g_hash_table_lookup (hash_table: cache, key: name);
550
551 if (extension_points != NULL &&
552 g_stat (file: path, buf: &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 (name: extension_points[i]);
560 extension_point->lazy_load_modules =
561 g_list_prepend (list: extension_point->lazy_load_modules,
562 data: 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 (format: "Failed to load module: %s\n", path);
573 g_object_unref (object: module);
574 g_free (mem: path);
575 continue;
576 }
577 }
578
579 g_free (mem: path);
580 }
581 }
582
583 g_dir_close (dir);
584
585 if (cache)
586 g_hash_table_destroy (hash_table: cache);
587
588 g_free (mem: 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 **/
610void
611g_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 **/
637GList *
638g_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 (path: dirname, flags: 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 (basename: name, scope))
656 {
657 GIOModule *module;
658 gchar *path;
659
660 path = g_build_filename (first_element: dirname, name, NULL);
661 module = g_io_module_new (filename: path);
662
663 if (!g_type_module_use (G_TYPE_MODULE (module)))
664 {
665 g_printerr (format: "Failed to load module: %s\n", path);
666 g_object_unref (object: module);
667 g_free (mem: path);
668 continue;
669 }
670
671 g_free (mem: path);
672
673 modules = g_list_prepend (list: modules, data: 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 **/
700GList *
701g_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
706static gpointer
707try_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 (g_class: class);
719 return NULL;
720}
721
722static void
723print_help (const char *envvar,
724 GIOExtensionPoint *ep)
725{
726 g_print (format: "Supported arguments for %s environment variable:\n", envvar);
727
728 if (g_io_extension_point_get_extensions (extension_point: ep) == NULL)
729 g_print (format: " (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 (extension_point: 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 (extension_point: ep); l; l = l->next)
743 {
744 extension = l->data;
745
746 g_print (format: " %*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 */
777GType
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 (rec_mutex: &default_modules_lock);
791 if (default_modules)
792 {
793 gpointer key;
794
795 if (g_hash_table_lookup_extended (hash_table: default_modules, lookup_key: extension_point, orig_key: &key, value: &impl))
796 {
797 g_rec_mutex_unlock (rec_mutex: &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 (hash_func: g_str_hash, key_equal_func: g_str_equal);
804 }
805
806 _g_io_modules_ensure_loaded ();
807 ep = g_io_extension_point_lookup (name: extension_point);
808
809 if (!ep)
810 {
811 g_warn_if_reached ();
812 g_rec_mutex_unlock (rec_mutex: &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 (variable: envvar) : NULL;
820 if (g_strcmp0 (str1: use_this, str2: "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 (extension_point: ep, name: use_this);
829 if (preferred)
830 {
831 impl = try_class (extension: 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 (extension_point: 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 (hash_table: default_modules, key: g_strdup (str: extension_point), value: impl);
856 g_rec_mutex_unlock (rec_mutex: &default_modules_lock);
857
858 return impl ? G_OBJECT_CLASS_TYPE (impl) : G_TYPE_INVALID;
859}
860
861static gpointer
862try_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 (object_type: type, NULL, error: &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 (err: &error);
883 return NULL;
884 }
885 else
886 {
887 impl = g_object_new (object_type: type, NULL);
888 if (!verify_func || verify_func (impl))
889 return impl;
890
891 g_object_unref (object: impl);
892 return NULL;
893 }
894}
895
896static void
897weak_ref_free (GWeakRef *weak_ref)
898{
899 g_weak_ref_clear (weak_ref);
900 g_free (mem: 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 */
932gpointer
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 (rec_mutex: &default_modules_lock);
947 if (default_modules)
948 {
949 if (g_hash_table_lookup_extended (hash_table: default_modules, lookup_key: extension_point,
950 NULL, value: &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 (weak_ref: 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 (rec_mutex: &default_modules_lock);
962 return g_steal_pointer (&impl);
963 }
964 }
965 }
966 else
967 {
968 default_modules = g_hash_table_new_full (hash_func: g_str_hash, key_equal_func: g_str_equal,
969 key_destroy_func: g_free, value_destroy_func: (GDestroyNotify) weak_ref_free);
970 }
971
972 _g_io_modules_ensure_loaded ();
973 ep = g_io_extension_point_lookup (name: 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 (rec_mutex: &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 (variable: envvar) : NULL;
988 if (g_strcmp0 (str1: use_this, str2: "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 (extension_point: ep, name: use_this);
997 if (preferred)
998 {
999 impl = try_implementation (extension_point, extension: 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 (extension_point: 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 (weak_ref: impl_weak_ref, object: impl);
1028 g_hash_table_insert (hash_table: default_modules, key: g_strdup (str: extension_point),
1029 g_steal_pointer (&impl_weak_ref));
1030 }
1031 else
1032 {
1033 g_weak_ref_set (weak_ref: impl_weak_ref, object: impl);
1034 }
1035
1036 g_rec_mutex_unlock (rec_mutex: &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
1052G_LOCK_DEFINE_STATIC (registered_extensions);
1053G_LOCK_DEFINE_STATIC (loaded_dirs);
1054
1055extern GType g_fen_file_monitor_get_type (void);
1056extern GType g_inotify_file_monitor_get_type (void);
1057extern GType g_kqueue_file_monitor_get_type (void);
1058extern GType g_win32_file_monitor_get_type (void);
1059
1060extern GType _g_unix_volume_monitor_get_type (void);
1061extern GType _g_local_vfs_get_type (void);
1062
1063extern GType _g_win32_volume_monitor_get_type (void);
1064extern GType _g_winhttp_vfs_get_type (void);
1065
1066extern GType _g_dummy_proxy_resolver_get_type (void);
1067extern GType _g_dummy_tls_backend_get_type (void);
1068extern GType g_network_monitor_base_get_type (void);
1069#ifdef HAVE_NETLINK
1070extern GType _g_network_monitor_netlink_get_type (void);
1071extern GType _g_network_monitor_nm_get_type (void);
1072#endif
1073
1074extern GType g_memory_monitor_dbus_get_type (void);
1075extern GType g_memory_monitor_portal_get_type (void);
1076
1077#ifdef G_OS_UNIX
1078extern GType g_fdo_notification_backend_get_type (void);
1079extern GType g_gtk_notification_backend_get_type (void);
1080extern GType g_portal_notification_backend_get_type (void);
1081extern GType g_proxy_resolver_portal_get_type (void);
1082extern GType g_network_monitor_portal_get_type (void);
1083#endif
1084
1085#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
1086extern GType g_cocoa_notification_backend_get_type (void);
1087#endif
1088
1089#ifdef G_PLATFORM_WIN32
1090extern GType g_win32_notification_backend_get_type (void);
1091
1092#include <windows.h>
1093extern GType _g_win32_network_monitor_get_type (void);
1094
1095static HMODULE gio_dll = NULL;
1096
1097#ifdef DLL_EXPORT
1098
1099BOOL WINAPI DllMain (HINSTANCE hinstDLL,
1100 DWORD fdwReason,
1101 LPVOID lpvReserved);
1102
1103BOOL WINAPI
1104DllMain (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
1119void *
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
1132void
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 (extension_point: 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 (extension_point: 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 (extension_point: 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 (extension_point: 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 (extension_point: 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 (extension_point: ep, G_TYPE_VFS);
1165
1166 ep = g_io_extension_point_register (name: "gsettings-backend");
1167 g_io_extension_point_set_required_type (extension_point: 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 (extension_point: 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 (extension_point: 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 (extension_point: 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 (extension_point: 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 (extension_point: 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 (extension_point: ep, G_TYPE_MEMORY_MONITOR);
1186 }
1187
1188 G_UNLOCK (registered_extensions);
1189}
1190
1191static gchar *
1192get_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 (str: g_getenv (variable: "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
1223void
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 (flags: 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 (variable: "GIO_EXTRA_MODULES") : NULL;
1244 if (module_path)
1245 {
1246 gchar **paths;
1247 int i;
1248
1249 paths = g_strsplit (string: module_path, G_SEARCHPATH_SEPARATOR_S, max_tokens: 0);
1250
1251 for (i = 0; paths[i] != NULL; i++)
1252 {
1253 g_io_modules_scan_all_in_directory_with_scope (dirname: paths[i], scope);
1254 }
1255
1256 g_strfreev (str_array: 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 (dirname: module_dir, scope);
1263 g_free (mem: module_dir);
1264
1265 g_io_module_scope_free (scope);
1266
1267 /* Initialize types from built-in "modules" */
1268 g_type_ensure (type: g_null_settings_backend_get_type ());
1269 g_type_ensure (type: g_memory_settings_backend_get_type ());
1270 g_type_ensure (type: g_keyfile_settings_backend_get_type ());
1271#if defined(HAVE_INOTIFY_INIT1)
1272 g_type_ensure (type: 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 (type: _g_unix_volume_monitor_get_type ());
1291 g_type_ensure (type: g_fdo_notification_backend_get_type ());
1292 g_type_ensure (type: g_gtk_notification_backend_get_type ());
1293 g_type_ensure (type: g_portal_notification_backend_get_type ());
1294 g_type_ensure (type: g_memory_monitor_dbus_get_type ());
1295 g_type_ensure (type: g_memory_monitor_portal_get_type ());
1296 g_type_ensure (type: g_network_monitor_portal_get_type ());
1297 g_type_ensure (type: 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 (type: _g_local_vfs_get_type ());
1307 g_type_ensure (type: _g_dummy_proxy_resolver_get_type ());
1308 g_type_ensure (type: _g_http_proxy_get_type ());
1309 g_type_ensure (type: _g_https_proxy_get_type ());
1310 g_type_ensure (type: _g_socks4a_proxy_get_type ());
1311 g_type_ensure (type: _g_socks4_proxy_get_type ());
1312 g_type_ensure (type: _g_socks5_proxy_get_type ());
1313 g_type_ensure (type: _g_dummy_tls_backend_get_type ());
1314 g_type_ensure (type: g_network_monitor_base_get_type ());
1315#ifdef HAVE_NETLINK
1316 g_type_ensure (type: _g_network_monitor_netlink_get_type ());
1317 g_type_ensure (type: _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
1327static void
1328g_io_extension_point_free (GIOExtensionPoint *ep)
1329{
1330 g_free (mem: ep->name);
1331 g_free (mem: 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 */
1343GIOExtensionPoint *
1344g_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 (hash_func: g_str_hash,
1351 key_equal_func: g_str_equal,
1352 NULL,
1353 value_destroy_func: (GDestroyNotify)g_io_extension_point_free);
1354
1355 ep = g_hash_table_lookup (hash_table: extension_points, key: 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 (str: name);
1364
1365 g_hash_table_insert (hash_table: extension_points, key: ep->name, value: 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 */
1381GIOExtensionPoint *
1382g_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 (hash_table: extension_points, key: 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 */
1405void
1406g_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 */
1421GType
1422g_io_extension_point_get_required_type (GIOExtensionPoint *extension_point)
1423{
1424 return extension_point->required_type;
1425}
1426
1427static void
1428lazy_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 (format: "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 */
1459GList *
1460g_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 */
1478GIOExtension *
1479g_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 (s1: e->name, s2: name) == 0)
1493 return e;
1494 }
1495
1496 return NULL;
1497}
1498
1499static gint
1500extension_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 */
1529GIOExtension *
1530g_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 (name: 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, 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 (str: extension_name);
1570 extension->priority = priority;
1571
1572 extension_point->extensions = g_list_insert_sorted (list: extension_point->extensions,
1573 data: extension, func: 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 */
1587GTypeClass *
1588g_io_extension_ref_class (GIOExtension *extension)
1589{
1590 return g_type_class_ref (type: 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 */
1601GType
1602g_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 */
1618const char *
1619g_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 */
1632gint
1633g_io_extension_get_priority (GIOExtension *extension)
1634{
1635 return extension->priority;
1636}
1637

source code of gtk/subprojects/glib/gio/giomodule.c