00e8c487bbceec4be0331014c60acc2c297e8f7f
[platform/upstream/glib.git] / gio / giomodule.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 Red Hat, Inc.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 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, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include "config.h"
24
25 #include <string.h>
26
27 #include "giomodule.h"
28 #include "giomodule-priv.h"
29 #include "glocalfilemonitor.h"
30 #include "glocaldirectorymonitor.h"
31 #include "gnativevolumemonitor.h"
32 #include "gproxyresolver.h"
33 #include "gproxy.h"
34 #include "gsettingsbackendinternal.h"
35 #include "gsocks4proxy.h"
36 #include "gsocks4aproxy.h"
37 #include "gsocks5proxy.h"
38 #include "gtlsbackend.h"
39 #include "gvfs.h"
40 #ifdef G_OS_WIN32
41 #include "gregistrysettingsbackend.h"
42 #endif
43 #include <glib/gstdio.h>
44
45 #undef G_DISABLE_DEPRECATED
46
47 #ifdef G_OS_UNIX
48 #include "gdesktopappinfo.h"
49 #endif
50
51 /**
52  * SECTION:giomodule
53  * @short_description: Loadable GIO Modules
54  * @include: gio/gio.h
55  *
56  * Provides an interface and default functions for loading and unloading 
57  * modules. This is used internally to make GIO extensible, but can also
58  * be used by others to implement module loading.
59  * 
60  **/
61
62 /**
63  * SECTION:extensionpoints
64  * @short_description: Extension Points
65  * @include: gio.h
66  * @see_also: <link linkend="extending-gio">Extending GIO</link>
67  *
68  * #GIOExtensionPoint provides a mechanism for modules to extend the
69  * functionality of the library or application that loaded it in an 
70  * organized fashion.  
71  *
72  * An extension point is identified by a name, and it may optionally
73  * require that any implementation must by of a certain type (or derived
74  * thereof). Use g_io_extension_point_register() to register an
75  * extension point, and g_io_extension_point_set_required_type() to
76  * set a required type.
77  *
78  * A module can implement an extension point by specifying the #GType 
79  * that implements the functionality. Additionally, each implementation
80  * of an extension point has a name, and a priority. Use
81  * g_io_extension_point_implement() to implement an extension point.
82  * 
83  *  |[
84  *  GIOExtensionPoint *ep;
85  *
86  *  /&ast; Register an extension point &ast;/
87  *  ep = g_io_extension_point_register ("my-extension-point");
88  *  g_io_extension_point_set_required_type (ep, MY_TYPE_EXAMPLE);
89  *  ]|
90  *
91  *  |[
92  *  /&ast; Implement an extension point &ast;/
93  *  G_DEFINE_TYPE (MyExampleImpl, my_example_impl, MY_TYPE_EXAMPLE);
94  *  g_io_extension_point_implement ("my-extension-point",
95  *                                  my_example_impl_get_type (),
96  *                                  "my-example",
97  *                                  10);
98  *  ]|
99  *
100  *  It is up to the code that registered the extension point how
101  *  it uses the implementations that have been associated with it.
102  *  Depending on the use case, it may use all implementations, or
103  *  only the one with the highest priority, or pick a specific
104  *  one by name.
105  *
106  *  To avoid opening all modules just to find out what extension
107  *  points they implement, GIO makes use of a caching mechanism,
108  *  see <link linkend="gio-querymodules">gio-querymodules</link>.
109  *  You are expected to run this command after installing a
110  *  GIO module.
111  */
112 struct _GIOModule {
113   GTypeModule parent_instance;
114
115   gchar       *filename;
116   GModule     *library;
117   gboolean     initialized; /* The module was loaded at least once */
118
119   void (* load)   (GIOModule *module);
120   void (* unload) (GIOModule *module);
121 };
122
123 struct _GIOModuleClass
124 {
125   GTypeModuleClass parent_class;
126
127 };
128
129 static void      g_io_module_finalize      (GObject      *object);
130 static gboolean  g_io_module_load_module   (GTypeModule  *gmodule);
131 static void      g_io_module_unload_module (GTypeModule  *gmodule);
132
133 struct _GIOExtension {
134   char *name;
135   GType type;
136   gint priority;
137 };
138
139 struct _GIOExtensionPoint {
140   GType required_type;
141   char *name;
142   GList *extensions;
143   GList *lazy_load_modules;
144 };
145
146 static GHashTable *extension_points = NULL;
147 G_LOCK_DEFINE_STATIC(extension_points);
148
149 G_DEFINE_TYPE (GIOModule, g_io_module, G_TYPE_TYPE_MODULE);
150
151 static void
152 g_io_module_class_init (GIOModuleClass *class)
153 {
154   GObjectClass     *object_class      = G_OBJECT_CLASS (class);
155   GTypeModuleClass *type_module_class = G_TYPE_MODULE_CLASS (class);
156
157   object_class->finalize     = g_io_module_finalize;
158
159   type_module_class->load    = g_io_module_load_module;
160   type_module_class->unload  = g_io_module_unload_module;
161 }
162
163 static void
164 g_io_module_init (GIOModule *module)
165 {
166 }
167
168 static void
169 g_io_module_finalize (GObject *object)
170 {
171   GIOModule *module = G_IO_MODULE (object);
172
173   g_free (module->filename);
174
175   G_OBJECT_CLASS (g_io_module_parent_class)->finalize (object);
176 }
177
178 static gboolean
179 g_io_module_load_module (GTypeModule *gmodule)
180 {
181   GIOModule *module = G_IO_MODULE (gmodule);
182
183   if (!module->filename)
184     {
185       g_warning ("GIOModule path not set");
186       return FALSE;
187     }
188
189   module->library = g_module_open (module->filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
190
191   if (!module->library)
192     {
193       g_printerr ("%s\n", g_module_error ());
194       return FALSE;
195     }
196
197   /* Make sure that the loaded library contains the required methods */
198   if (! g_module_symbol (module->library,
199                          "g_io_module_load",
200                          (gpointer) &module->load) ||
201       ! g_module_symbol (module->library,
202                          "g_io_module_unload",
203                          (gpointer) &module->unload))
204     {
205       g_printerr ("%s\n", g_module_error ());
206       g_module_close (module->library);
207
208       return FALSE;
209     }
210
211   /* Initialize the loaded module */
212   module->load (module);
213   module->initialized = TRUE;
214
215   return TRUE;
216 }
217
218 static void
219 g_io_module_unload_module (GTypeModule *gmodule)
220 {
221   GIOModule *module = G_IO_MODULE (gmodule);
222
223   module->unload (module);
224
225   g_module_close (module->library);
226   module->library = NULL;
227
228   module->load   = NULL;
229   module->unload = NULL;
230 }
231
232 /**
233  * g_io_module_new:
234  * @filename: filename of the shared library module.
235  * 
236  * Creates a new GIOModule that will load the specific
237  * shared library when in use.
238  * 
239  * Returns: a #GIOModule from given @filename, 
240  * or %NULL on error.
241  **/
242 GIOModule *
243 g_io_module_new (const gchar *filename)
244 {
245   GIOModule *module;
246
247   g_return_val_if_fail (filename != NULL, NULL);
248
249   module = g_object_new (G_IO_TYPE_MODULE, NULL);
250   module->filename = g_strdup (filename);
251
252   return module;
253 }
254
255 static gboolean
256 is_valid_module_name (const gchar *basename)
257 {
258 #if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
259   return
260     g_str_has_prefix (basename, "lib") &&
261     g_str_has_suffix (basename, ".so");
262 #else
263   return g_str_has_suffix (basename, ".dll");
264 #endif
265 }
266
267 /**
268  * g_io_modules_scan_all_in_directory:
269  * @dirname: pathname for a directory containing modules to scan.
270  *
271  * Scans all the modules in the specified directory, ensuring that
272  * any extension point implemented by a module is registered.
273  *
274  * This may not actually load and initialize all the types in each
275  * module, some modules may be lazily loaded and initialized when
276  * an extension point it implementes is used with e.g.
277  * g_io_extension_point_get_extensions() or
278  * g_io_extension_point_get_extension_by_name().
279  *
280  * If you need to guarantee that all types are loaded in all the modules,
281  * use g_io_modules_load_all_in_directory().
282  *
283  * Since: 2.24
284  **/
285 void
286 g_io_modules_scan_all_in_directory (const char *dirname)
287 {
288   const gchar *name;
289   char *filename;
290   GDir *dir;
291   GStatBuf statbuf;
292   char *data;
293   time_t cache_mtime;
294   GHashTable *cache;
295
296   if (!g_module_supported ())
297     return;
298
299   dir = g_dir_open (dirname, 0, NULL);
300   if (!dir)
301     return;
302
303   filename = g_build_filename (dirname, "giomodule.cache", NULL);
304
305   cache = g_hash_table_new_full (g_str_hash, g_str_equal,
306                                  g_free, (GDestroyNotify)g_strfreev);
307
308   cache_mtime = 0;
309   if (g_stat (filename, &statbuf) == 0 &&
310       g_file_get_contents (filename, &data, NULL, NULL))
311     {
312       char **lines;
313       int i;
314
315       /* Cache mtime is the time the cache file was created, any file
316        * that has a ctime before this was created then and not modified
317        * since then (userspace can't change ctime). Its possible to change
318        * the ctime forward without changing the file content, by e.g.
319        * chmoding the file, but this is uncommon and will only cause us
320        * to not use the cache so will not cause bugs.
321        */
322       cache_mtime = statbuf.st_mtime;
323
324       lines = g_strsplit (data, "\n", -1);
325       g_free (data);
326
327       for (i = 0;  lines[i] != NULL; i++)
328         {
329           char *line = lines[i];
330           char *file;
331           char *colon;
332           char **extension_points;
333
334           if (line[0] == '#')
335             continue;
336
337           colon = strchr (line, ':');
338           if (colon == NULL || line == colon)
339             continue; /* Invalid line, ignore */
340
341           *colon = 0; /* terminate filename */
342           file = g_strdup (line);
343           colon++; /* after colon */
344
345           while (g_ascii_isspace (*colon))
346             colon++;
347
348           extension_points = g_strsplit (colon, ",", -1);
349           g_hash_table_insert (cache, file, extension_points);
350         }
351       g_strfreev (lines);
352     }
353
354   while ((name = g_dir_read_name (dir)))
355     {
356       if (is_valid_module_name (name))
357         {
358           GIOExtensionPoint *extension_point;
359           GIOModule *module;
360           gchar *path;
361           char **extension_points;
362           int i;
363
364           path = g_build_filename (dirname, name, NULL);
365           module = g_io_module_new (path);
366
367           extension_points = g_hash_table_lookup (cache, name);
368           if (extension_points != NULL &&
369               g_stat (path, &statbuf) == 0 &&
370               statbuf.st_ctime <= cache_mtime)
371             {
372               /* Lazy load/init the library when first required */
373               for (i = 0; extension_points[i] != NULL; i++)
374                 {
375                   extension_point =
376                     g_io_extension_point_register (extension_points[i]);
377                   extension_point->lazy_load_modules =
378                     g_list_prepend (extension_point->lazy_load_modules,
379                                     module);
380                 }
381             }
382           else
383             {
384               /* Try to load and init types */
385               if (g_type_module_use (G_TYPE_MODULE (module)))
386                 g_type_module_unuse (G_TYPE_MODULE (module)); /* Unload */
387               else
388                 { /* Failure to load */
389                   g_printerr ("Failed to load module: %s\n", path);
390                   g_object_unref (module);
391                   g_free (path);
392                   continue;
393                 }
394             }
395
396           g_free (path);
397         }
398     }
399
400   g_dir_close (dir);
401
402   g_hash_table_destroy (cache);
403
404   g_free (filename);
405 }
406
407
408 /**
409  * g_io_modules_load_all_in_directory:
410  * @dirname: pathname for a directory containing modules to load.
411  *
412  * Loads all the modules in the specified directory.
413  *
414  * If don't require all modules to be initialized (and thus registering
415  * all gtypes) then you can use g_io_modules_scan_all_in_directory()
416  * which allows delayed/lazy loading of modules.
417  *
418  * Returns: (element-type GIOModule) (transfer full): a list of #GIOModules loaded
419  *      from the directory,
420  *      All the modules are loaded into memory, if you want to
421  *      unload them (enabling on-demand loading) you must call
422  *      g_type_module_unuse() on all the modules. Free the list
423  *      with g_list_free().
424  **/
425 GList *
426 g_io_modules_load_all_in_directory (const char *dirname)
427 {
428   const gchar *name;
429   GDir        *dir;
430   GList *modules;
431
432   if (!g_module_supported ())
433     return NULL;
434
435   dir = g_dir_open (dirname, 0, NULL);
436   if (!dir)
437     return NULL;
438
439   modules = NULL;
440   while ((name = g_dir_read_name (dir)))
441     {
442       if (is_valid_module_name (name))
443         {
444           GIOModule *module;
445           gchar     *path;
446
447           path = g_build_filename (dirname, name, NULL);
448           module = g_io_module_new (path);
449
450           if (!g_type_module_use (G_TYPE_MODULE (module)))
451             {
452               g_printerr ("Failed to load module: %s\n", path);
453               g_object_unref (module);
454               g_free (path);
455               continue;
456             }
457           
458           g_free (path);
459
460           modules = g_list_prepend (modules, module);
461         }
462     }
463   
464   g_dir_close (dir);
465
466   return modules;
467 }
468
469 G_LOCK_DEFINE_STATIC (registered_extensions);
470 G_LOCK_DEFINE_STATIC (loaded_dirs);
471
472 extern GType _g_fen_directory_monitor_get_type (void);
473 extern GType _g_fen_file_monitor_get_type (void);
474 extern GType _g_inotify_directory_monitor_get_type (void);
475 extern GType _g_inotify_file_monitor_get_type (void);
476 extern GType _g_unix_volume_monitor_get_type (void);
477 extern GType _g_local_vfs_get_type (void);
478
479 extern GType _g_win32_volume_monitor_get_type (void);
480 extern GType g_win32_directory_monitor_get_type (void);
481 extern GType _g_winhttp_vfs_get_type (void);
482
483 extern GType _g_dummy_proxy_resolver_get_type (void);
484 extern GType _g_dummy_tls_backend_get_type (void);
485
486 #ifdef G_PLATFORM_WIN32
487
488 #include <windows.h>
489
490 static HMODULE gio_dll = NULL;
491
492 #ifdef DLL_EXPORT
493
494 BOOL WINAPI
495 DllMain (HINSTANCE hinstDLL,
496          DWORD     fdwReason,
497          LPVOID    lpvReserved)
498 {
499   if (fdwReason == DLL_PROCESS_ATTACH)
500       gio_dll = hinstDLL;
501
502   return TRUE;
503 }
504
505 #endif
506
507 #undef GIO_MODULE_DIR
508
509 /* GIO_MODULE_DIR is used only in code called just once,
510  * so no problem leaking this
511  */
512 #define GIO_MODULE_DIR \
513   g_build_filename (g_win32_get_package_installation_directory_of_module (gio_dll), \
514                     "lib/gio/modules", \
515                     NULL)
516
517 #endif
518
519 void
520 _g_io_modules_ensure_extension_points_registered (void)
521 {
522   static gboolean registered_extensions = FALSE;
523   GIOExtensionPoint *ep;
524
525   G_LOCK (registered_extensions);
526   
527   if (!registered_extensions)
528     {
529       registered_extensions = TRUE;
530       
531 #ifdef G_OS_UNIX
532 #if !GLIB_CHECK_VERSION (3, 0, 0)
533       ep = g_io_extension_point_register (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
534       g_io_extension_point_set_required_type (ep, G_TYPE_DESKTOP_APP_INFO_LOOKUP);
535 #endif
536 #endif
537       
538       ep = g_io_extension_point_register (G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME);
539       g_io_extension_point_set_required_type (ep, G_TYPE_LOCAL_DIRECTORY_MONITOR);
540       
541       ep = g_io_extension_point_register (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME);
542       g_io_extension_point_set_required_type (ep, G_TYPE_LOCAL_FILE_MONITOR);
543       
544       ep = g_io_extension_point_register (G_VOLUME_MONITOR_EXTENSION_POINT_NAME);
545       g_io_extension_point_set_required_type (ep, G_TYPE_VOLUME_MONITOR);
546       
547       ep = g_io_extension_point_register (G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME);
548       g_io_extension_point_set_required_type (ep, G_TYPE_NATIVE_VOLUME_MONITOR);
549       
550       ep = g_io_extension_point_register (G_VFS_EXTENSION_POINT_NAME);
551       g_io_extension_point_set_required_type (ep, G_TYPE_VFS);
552
553       ep = g_io_extension_point_register ("gsettings-backend");
554       g_io_extension_point_set_required_type (ep, G_TYPE_OBJECT);
555
556       ep = g_io_extension_point_register (G_PROXY_RESOLVER_EXTENSION_POINT_NAME);
557       g_io_extension_point_set_required_type (ep, G_TYPE_PROXY_RESOLVER);
558
559       ep = g_io_extension_point_register (G_PROXY_EXTENSION_POINT_NAME);
560       g_io_extension_point_set_required_type (ep, G_TYPE_PROXY);
561
562       ep = g_io_extension_point_register (G_TLS_BACKEND_EXTENSION_POINT_NAME);
563       g_io_extension_point_set_required_type (ep, G_TYPE_TLS_BACKEND);
564     }
565   
566   G_UNLOCK (registered_extensions);
567  }
568
569 void
570 _g_io_modules_ensure_loaded (void)
571 {
572   static gboolean loaded_dirs = FALSE;
573   const char *module_path;
574
575   _g_io_modules_ensure_extension_points_registered ();
576   
577   G_LOCK (loaded_dirs);
578
579   if (!loaded_dirs)
580     {
581       loaded_dirs = TRUE;
582
583       g_io_modules_scan_all_in_directory (GIO_MODULE_DIR);
584
585       module_path = g_getenv ("GIO_EXTRA_MODULES");
586
587       if (module_path)
588         {
589           gchar **paths;
590           int i;
591
592           paths = g_strsplit (module_path, ":", 0);
593
594           for (i = 0; paths[i] != NULL; i++)
595             g_io_modules_scan_all_in_directory (paths[i]);
596
597           g_strfreev (paths);
598         }
599
600       /* Initialize types from built-in "modules" */
601       g_null_settings_backend_get_type ();
602       g_memory_settings_backend_get_type ();
603 #if defined(HAVE_SYS_INOTIFY_H) || defined(HAVE_LINUX_INOTIFY_H)
604       _g_inotify_directory_monitor_get_type ();
605       _g_inotify_file_monitor_get_type ();
606 #endif
607 #if defined(HAVE_FEN)
608       _g_fen_directory_monitor_get_type ();
609       _g_fen_file_monitor_get_type ();
610 #endif
611 #ifdef G_OS_WIN32
612       _g_win32_volume_monitor_get_type ();
613       g_win32_directory_monitor_get_type ();
614       g_registry_backend_get_type ();
615 #endif
616 #ifdef G_OS_UNIX
617       _g_unix_volume_monitor_get_type ();
618 #endif
619 #ifdef G_OS_WIN32
620       _g_winhttp_vfs_get_type ();
621 #endif
622       _g_local_vfs_get_type ();
623       _g_dummy_proxy_resolver_get_type ();
624       _g_socks4a_proxy_get_type ();
625       _g_socks4_proxy_get_type ();
626       _g_socks5_proxy_get_type ();
627       _g_dummy_tls_backend_get_type ();
628     }
629
630   G_UNLOCK (loaded_dirs);
631 }
632
633 static void
634 g_io_extension_point_free (GIOExtensionPoint *ep)
635 {
636   g_free (ep->name);
637   g_free (ep);
638 }
639
640 /**
641  * g_io_extension_point_register:
642  * @name: The name of the extension point
643  *
644  * Registers an extension point.
645  *
646  * Returns: the new #GIOExtensionPoint. This object is owned by GIO
647  *    and should not be freed
648  */
649 GIOExtensionPoint *
650 g_io_extension_point_register (const char *name)
651 {
652   GIOExtensionPoint *ep;
653   
654   G_LOCK (extension_points);
655   if (extension_points == NULL)
656     extension_points = g_hash_table_new_full (g_str_hash,
657                                               g_str_equal,
658                                               NULL,
659                                               (GDestroyNotify)g_io_extension_point_free);
660
661   ep = g_hash_table_lookup (extension_points, name);
662   if (ep != NULL)
663     {
664       G_UNLOCK (extension_points);
665       return ep;
666     }
667
668   ep = g_new0 (GIOExtensionPoint, 1);
669   ep->name = g_strdup (name);
670   
671   g_hash_table_insert (extension_points, ep->name, ep);
672   
673   G_UNLOCK (extension_points);
674
675   return ep;
676 }
677
678 /**
679  * g_io_extension_point_lookup:
680  * @name: the name of the extension point
681  *
682  * Looks up an existing extension point.
683  *
684  * Returns: the #GIOExtensionPoint, or %NULL if there is no
685  *    registered extension point with the given name
686  */
687 GIOExtensionPoint *
688 g_io_extension_point_lookup (const char *name)
689 {
690   GIOExtensionPoint *ep;
691
692   G_LOCK (extension_points);
693   ep = NULL;
694   if (extension_points != NULL)
695     ep = g_hash_table_lookup (extension_points, name);
696   
697   G_UNLOCK (extension_points);
698
699   return ep;
700   
701 }
702
703 /**
704  * g_io_extension_point_set_required_type:
705  * @extension_point: a #GIOExtensionPoint
706  * @type: the #GType to require
707  *
708  * Sets the required type for @extension_point to @type. 
709  * All implementations must henceforth have this type.
710  */
711 void
712 g_io_extension_point_set_required_type (GIOExtensionPoint *extension_point,
713                                         GType              type)
714 {
715   extension_point->required_type = type;
716 }
717
718 /**
719  * g_io_extension_point_get_required_type:
720  * @extension_point: a #GIOExtensionPoint
721  *
722  * Gets the required type for @extension_point.
723  *
724  * Returns: the #GType that all implementations must have, 
725  *     or #G_TYPE_INVALID if the extension point has no required type
726  */
727 GType
728 g_io_extension_point_get_required_type (GIOExtensionPoint *extension_point)
729 {
730   return extension_point->required_type;
731 }
732
733 void
734 lazy_load_modules (GIOExtensionPoint *extension_point)
735 {
736   GIOModule *module;
737   GList *l;
738
739   for (l = extension_point->lazy_load_modules; l != NULL; l = l->next)
740     {
741       module = l->data;
742
743       if (!module->initialized)
744         {
745           if (g_type_module_use (G_TYPE_MODULE (module)))
746             g_type_module_unuse (G_TYPE_MODULE (module)); /* Unload */
747           else
748             g_printerr ("Failed to load module: %s\n",
749                         module->filename);
750         }
751     }
752 }
753
754 /**
755  * g_io_extension_point_get_extensions:
756  * @extension_point: a #GIOExtensionPoint
757  *
758  * Gets a list of all extensions that implement this extension point.
759  * The list is sorted by priority, beginning with the highest priority.
760  *
761  * Returns: (element-type GIOExtension) (transfer none): a #GList of
762  * #GIOExtension<!-- -->s. The list is owned by GIO and should not be
763  * modified.
764  */
765 GList *
766 g_io_extension_point_get_extensions (GIOExtensionPoint *extension_point)
767 {
768   lazy_load_modules (extension_point);
769   return extension_point->extensions;
770 }
771
772 /**
773  * g_io_extension_point_get_extension_by_name:
774  * @extension_point: a #GIOExtensionPoint
775  * @name: the name of the extension to get
776  *
777  * Finds a #GIOExtension for an extension point by name.
778  *
779  * Returns: (transfer none): the #GIOExtension for @extension_point that has the
780  *    given name, or %NULL if there is no extension with that name
781  */
782 GIOExtension *
783 g_io_extension_point_get_extension_by_name (GIOExtensionPoint *extension_point,
784                                             const char        *name)
785 {
786   GList *l;
787
788   lazy_load_modules (extension_point);
789   for (l = extension_point->extensions; l != NULL; l = l->next)
790     {
791       GIOExtension *e = l->data;
792
793       if (e->name != NULL &&
794           strcmp (e->name, name) == 0)
795         return e;
796     }
797   
798   return NULL;
799 }
800
801 static gint
802 extension_prio_compare (gconstpointer  a,
803                         gconstpointer  b)
804 {
805   const GIOExtension *extension_a = a, *extension_b = b;
806
807   if (extension_a->priority > extension_b->priority)
808     return -1;
809
810   if (extension_b->priority > extension_a->priority)
811     return 1;
812
813   return 0;
814 }
815
816 /**
817  * g_io_extension_point_implement:
818  * @extension_point_name: the name of the extension point
819  * @type: the #GType to register as extension 
820  * @extension_name: the name for the extension
821  * @priority: the priority for the extension
822  *
823  * Registers @type as extension for the extension point with name
824  * @extension_point_name. 
825  *
826  * If @type has already been registered as an extension for this 
827  * extension point, the existing #GIOExtension object is returned.
828  *
829  * Returns: a #GIOExtension object for #GType
830  */
831 GIOExtension *
832 g_io_extension_point_implement (const char *extension_point_name,
833                                 GType       type,
834                                 const char *extension_name,
835                                 gint        priority)
836 {
837   GIOExtensionPoint *extension_point;
838   GIOExtension *extension;
839   GList *l;
840
841   g_return_val_if_fail (extension_point_name != NULL, NULL);
842
843   extension_point = g_io_extension_point_lookup (extension_point_name);
844   if (extension_point == NULL)
845     {
846       g_warning ("Tried to implement non-registered extension point %s", extension_point_name);
847       return NULL;
848     }
849   
850   if (extension_point->required_type != 0 &&
851       !g_type_is_a (type, extension_point->required_type))
852     {
853       g_warning ("Tried to register an extension of the type %s to extension point %s. "
854                  "Expected type is %s.",
855                  g_type_name (type),
856                  extension_point_name, 
857                  g_type_name (extension_point->required_type));
858       return NULL;
859     }      
860
861   /* It's safe to register the same type multiple times */
862   for (l = extension_point->extensions; l != NULL; l = l->next)
863     {
864       extension = l->data;
865       if (extension->type == type)
866         return extension;
867     }
868   
869   extension = g_slice_new0 (GIOExtension);
870   extension->type = type;
871   extension->name = g_strdup (extension_name);
872   extension->priority = priority;
873   
874   extension_point->extensions = g_list_insert_sorted (extension_point->extensions,
875                                                       extension, extension_prio_compare);
876   
877   return extension;
878 }
879
880 /**
881  * g_io_extension_ref_class:
882  * @extension: a #GIOExtension
883  *
884  * Gets a reference to the class for the type that is 
885  * associated with @extension.
886  *
887  * Returns: (transfer full): the #GTypeClass for the type of @extension
888  */
889 GTypeClass *
890 g_io_extension_ref_class (GIOExtension *extension)
891 {
892   return g_type_class_ref (extension->type);
893 }
894
895 /**
896  * g_io_extension_get_type:
897  * @extension: a #GIOExtension
898  *
899  * Gets the type associated with @extension.
900  *
901  * Returns: the type of @extension
902  */
903 GType
904 g_io_extension_get_type (GIOExtension *extension)
905 {
906   return extension->type;
907 }
908
909 /**
910  * g_io_extension_get_name:
911  * @extension: a #GIOExtension
912  *
913  * Gets the name under which @extension was registered.
914  *
915  * Note that the same type may be registered as extension
916  * for multiple extension points, under different names.
917  *
918  * Returns: the name of @extension.
919  */
920 const char *
921 g_io_extension_get_name (GIOExtension *extension)
922 {
923   return extension->name;
924 }
925
926 /**
927  * g_io_extension_get_priority:
928  * @extension: a #GIOExtension
929  *
930  * Gets the priority with which @extension was registered.
931  *
932  * Returns: the priority of @extension
933  */
934 gint
935 g_io_extension_get_priority (GIOExtension *extension)
936 {
937   return extension->priority;
938 }