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