Home | History | Annotate | Download | only in gio
      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 (at) 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 "gvfs.h"
     33 #ifdef G_OS_UNIX
     34 #include "gdesktopappinfo.h"
     35 #endif
     36 #include "gioalias.h"
     37 
     38 /**
     39  * SECTION:giomodule
     40  * @short_description: Loadable GIO Modules
     41  * @include: gio/gio.h
     42  *
     43  * Provides an interface and default functions for loading and unloading
     44  * modules. This is used internally to make GIO extensible, but can also
     45  * be used by others to implement module loading.
     46  *
     47  **/
     48 
     49 /**
     50  * SECTION:extensionpoints
     51  * @short_description: Extension Points
     52  * @include: gio.h
     53  * @see_also: <link linkend="extending-gio">Extending GIO</link>
     54  *
     55  * #GIOExtensionPoint provides a mechanism for modules to extend the
     56  * functionality of the library or application that loaded it in an
     57  * organized fashion.
     58  *
     59  * An extension point is identified by a name, and it may optionally
     60  * require that any implementation must by of a certain type (or derived
     61  * thereof). Use g_io_extension_point_register() to register an
     62  * extension point, and g_io_extension_point_set_required_type() to
     63  * set a required type.
     64  *
     65  * A module can implement an extension point by specifying the #GType
     66  * that implements the functionality. Additionally, each implementation
     67  * of an extension point has a name, and a priority. Use
     68  * g_io_extension_point_implement() to implement an extension point.
     69  *
     70  *  |[
     71  *  GIOExtensionPoint *ep;
     72  *
     73  *  /&ast; Register an extension point &ast;/
     74  *  ep = g_io_extension_point_register ("my-extension-point");
     75  *  g_io_extension_point_set_required_type (ep, MY_TYPE_EXAMPLE);
     76  *  ]|
     77  *
     78  *  |[
     79  *  /&ast; Implement an extension point &ast;/
     80  *  G_DEFINE_TYPE (MyExampleImpl, my_example_impl, MY_TYPE_EXAMPLE);
     81  *  g_io_extension_point_implement ("my-extension-point",
     82  *                                  my_example_impl_get_type (),
     83  *                                  "my-example",
     84  *                                  10);
     85  *  ]|
     86  *
     87  *  It is up to the code that registered the extension point how
     88  *  it uses the implementations that have been associated with it.
     89  *  Depending on the use case, it may use all implementations, or
     90  *  only the one with the highest priority, or pick a specific
     91  *  one by name.
     92  */
     93 struct _GIOModule {
     94   GTypeModule parent_instance;
     95 
     96   gchar       *filename;
     97   GModule     *library;
     98 
     99   void (* load)   (GIOModule *module);
    100   void (* unload) (GIOModule *module);
    101 };
    102 
    103 struct _GIOModuleClass
    104 {
    105   GTypeModuleClass parent_class;
    106 
    107 };
    108 
    109 static void      g_io_module_finalize      (GObject      *object);
    110 static gboolean  g_io_module_load_module   (GTypeModule  *gmodule);
    111 static void      g_io_module_unload_module (GTypeModule  *gmodule);
    112 
    113 G_DEFINE_TYPE (GIOModule, g_io_module, G_TYPE_TYPE_MODULE);
    114 
    115 static void
    116 g_io_module_class_init (GIOModuleClass *class)
    117 {
    118   GObjectClass     *object_class      = G_OBJECT_CLASS (class);
    119   GTypeModuleClass *type_module_class = G_TYPE_MODULE_CLASS (class);
    120 
    121   object_class->finalize     = g_io_module_finalize;
    122 
    123   type_module_class->load    = g_io_module_load_module;
    124   type_module_class->unload  = g_io_module_unload_module;
    125 }
    126 
    127 static void
    128 g_io_module_init (GIOModule *module)
    129 {
    130 }
    131 
    132 static void
    133 g_io_module_finalize (GObject *object)
    134 {
    135   GIOModule *module = G_IO_MODULE (object);
    136 
    137   g_free (module->filename);
    138 
    139   G_OBJECT_CLASS (g_io_module_parent_class)->finalize (object);
    140 }
    141 
    142 static gboolean
    143 g_io_module_load_module (GTypeModule *gmodule)
    144 {
    145   GIOModule *module = G_IO_MODULE (gmodule);
    146 
    147   if (!module->filename)
    148     {
    149       g_warning ("GIOModule path not set");
    150       return FALSE;
    151     }
    152 
    153   module->library = g_module_open (module->filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
    154 
    155   if (!module->library)
    156     {
    157       g_printerr ("%s\n", g_module_error ());
    158       return FALSE;
    159     }
    160 
    161   /* Make sure that the loaded library contains the required methods */
    162   if (! g_module_symbol (module->library,
    163                          "g_io_module_load",
    164                          (gpointer) &module->load) ||
    165       ! g_module_symbol (module->library,
    166                          "g_io_module_unload",
    167                          (gpointer) &module->unload))
    168     {
    169       g_printerr ("%s\n", g_module_error ());
    170       g_module_close (module->library);
    171 
    172       return FALSE;
    173     }
    174 
    175   /* Initialize the loaded module */
    176   module->load (module);
    177 
    178   return TRUE;
    179 }
    180 
    181 static void
    182 g_io_module_unload_module (GTypeModule *gmodule)
    183 {
    184   GIOModule *module = G_IO_MODULE (gmodule);
    185 
    186   module->unload (module);
    187 
    188   g_module_close (module->library);
    189   module->library = NULL;
    190 
    191   module->load   = NULL;
    192   module->unload = NULL;
    193 }
    194 
    195 /**
    196  * g_io_module_new:
    197  * @filename: filename of the shared library module.
    198  *
    199  * Creates a new GIOModule that will load the specific
    200  * shared library when in use.
    201  *
    202  * Returns: a #GIOModule from given @filename,
    203  * or %NULL on error.
    204  **/
    205 GIOModule *
    206 g_io_module_new (const gchar *filename)
    207 {
    208   GIOModule *module;
    209 
    210   g_return_val_if_fail (filename != NULL, NULL);
    211 
    212   module = g_object_new (G_IO_TYPE_MODULE, NULL);
    213   module->filename = g_strdup (filename);
    214 
    215   return module;
    216 }
    217 
    218 static gboolean
    219 is_valid_module_name (const gchar *basename)
    220 {
    221 #if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
    222   return
    223     g_str_has_prefix (basename, "lib") &&
    224     g_str_has_suffix (basename, ".so");
    225 #else
    226   return g_str_has_suffix (basename, ".dll");
    227 #endif
    228 }
    229 
    230 /**
    231  * g_io_modules_load_all_in_directory:
    232  * @dirname: pathname for a directory containing modules to load.
    233  *
    234  * Loads all the modules in the specified directory.
    235  *
    236  * Returns: a list of #GIOModules loaded from the directory,
    237  *      All the modules are loaded into memory, if you want to
    238  *      unload them (enabling on-demand loading) you must call
    239  *      g_type_module_unuse() on all the modules. Free the list
    240  *      with g_list_free().
    241  **/
    242 GList *
    243 g_io_modules_load_all_in_directory (const char *dirname)
    244 {
    245   const gchar *name;
    246   GDir        *dir;
    247   GList *modules;
    248 
    249   if (!g_module_supported ())
    250     return NULL;
    251 
    252   dir = g_dir_open (dirname, 0, NULL);
    253   if (!dir)
    254     return NULL;
    255 
    256   modules = NULL;
    257   while ((name = g_dir_read_name (dir)))
    258     {
    259       if (is_valid_module_name (name))
    260         {
    261           GIOModule *module;
    262           gchar     *path;
    263 
    264           path = g_build_filename (dirname, name, NULL);
    265           module = g_io_module_new (path);
    266 
    267           if (!g_type_module_use (G_TYPE_MODULE (module)))
    268             {
    269               g_printerr ("Failed to load module: %s\n", path);
    270               g_object_unref (module);
    271               g_free (path);
    272               continue;
    273             }
    274 
    275           g_free (path);
    276 
    277           modules = g_list_prepend (modules, module);
    278         }
    279     }
    280 
    281   g_dir_close (dir);
    282 
    283   return modules;
    284 }
    285 
    286 G_LOCK_DEFINE_STATIC (registered_extensions);
    287 G_LOCK_DEFINE_STATIC (loaded_dirs);
    288 
    289 extern GType _g_fen_directory_monitor_get_type (void);
    290 extern GType _g_fen_file_monitor_get_type (void);
    291 extern GType _g_inotify_directory_monitor_get_type (void);
    292 extern GType _g_inotify_file_monitor_get_type (void);
    293 extern GType _g_unix_volume_monitor_get_type (void);
    294 extern GType _g_local_vfs_get_type (void);
    295 
    296 extern GType _g_win32_volume_monitor_get_type (void);
    297 extern GType g_win32_directory_monitor_get_type (void);
    298 extern GType _g_winhttp_vfs_get_type (void);
    299 
    300 void
    301 _g_io_modules_ensure_extension_points_registered (void)
    302 {
    303   static gboolean registered_extensions = FALSE;
    304   GIOExtensionPoint *ep;
    305 
    306   G_LOCK (registered_extensions);
    307 
    308   if (!registered_extensions)
    309     {
    310       registered_extensions = TRUE;
    311 
    312 #ifdef G_OS_UNIX
    313       ep = g_io_extension_point_register (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
    314       g_io_extension_point_set_required_type (ep, G_TYPE_DESKTOP_APP_INFO_LOOKUP);
    315 #endif
    316 
    317       ep = g_io_extension_point_register (G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME);
    318       g_io_extension_point_set_required_type (ep, G_TYPE_LOCAL_DIRECTORY_MONITOR);
    319 
    320       ep = g_io_extension_point_register (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME);
    321       g_io_extension_point_set_required_type (ep, G_TYPE_LOCAL_FILE_MONITOR);
    322 
    323       ep = g_io_extension_point_register (G_VOLUME_MONITOR_EXTENSION_POINT_NAME);
    324       g_io_extension_point_set_required_type (ep, G_TYPE_VOLUME_MONITOR);
    325 
    326       ep = g_io_extension_point_register (G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME);
    327       g_io_extension_point_set_required_type (ep, G_TYPE_NATIVE_VOLUME_MONITOR);
    328 
    329       ep = g_io_extension_point_register (G_VFS_EXTENSION_POINT_NAME);
    330       g_io_extension_point_set_required_type (ep, G_TYPE_VFS);
    331     }
    332 
    333   G_UNLOCK (registered_extensions);
    334  }
    335 
    336 void
    337 _g_io_modules_ensure_loaded (void)
    338 {
    339   GList *modules, *l;
    340   static gboolean loaded_dirs = FALSE;
    341   const char *module_path;
    342 
    343   _g_io_modules_ensure_extension_points_registered ();
    344 
    345   G_LOCK (loaded_dirs);
    346 
    347   if (!loaded_dirs)
    348     {
    349       loaded_dirs = TRUE;
    350 
    351       modules = g_io_modules_load_all_in_directory (GIO_MODULE_DIR);
    352 
    353       module_path = g_getenv ("GIO_EXTRA_MODULES");
    354 
    355       if (module_path)
    356         {
    357           int i = 0;
    358           gchar **paths;
    359           paths = g_strsplit (module_path, ":", 0);
    360 
    361           while (paths[i] != NULL)
    362             {
    363               modules = g_list_concat (modules, g_io_modules_load_all_in_directory (paths[i]));
    364               i++;
    365             }
    366 
    367           g_strfreev (paths);
    368         }
    369 
    370       /* Initialize types from built-in "modules" */
    371 #if defined(HAVE_SYS_INOTIFY_H) || defined(HAVE_LINUX_INOTIFY_H)
    372       _g_inotify_directory_monitor_get_type ();
    373       _g_inotify_file_monitor_get_type ();
    374 #endif
    375 #if defined(HAVE_FEN)
    376       _g_fen_directory_monitor_get_type ();
    377       _g_fen_file_monitor_get_type ();
    378 #endif
    379 #ifdef G_OS_WIN32
    380       _g_win32_volume_monitor_get_type ();
    381       g_win32_directory_monitor_get_type ();
    382 #endif
    383 #ifdef G_OS_UNIX
    384       _g_unix_volume_monitor_get_type ();
    385 #endif
    386 #ifdef G_OS_WIN32
    387       _g_winhttp_vfs_get_type ();
    388 #endif
    389       _g_local_vfs_get_type ();
    390 
    391       for (l = modules; l != NULL; l = l->next)
    392 	g_type_module_unuse (G_TYPE_MODULE (l->data));
    393 
    394       g_list_free (modules);
    395     }
    396 
    397   G_UNLOCK (loaded_dirs);
    398 }
    399 
    400 struct _GIOExtension {
    401   char *name;
    402   GType type;
    403   gint priority;
    404 };
    405 
    406 struct _GIOExtensionPoint {
    407   GType required_type;
    408   char *name;
    409   GList *extensions;
    410 };
    411 
    412 static GHashTable *extension_points = NULL;
    413 G_LOCK_DEFINE_STATIC(extension_points);
    414 
    415 
    416 static void
    417 g_io_extension_point_free (GIOExtensionPoint *ep)
    418 {
    419   g_free (ep->name);
    420   g_free (ep);
    421 }
    422 
    423 /**
    424  * g_io_extension_point_register:
    425  * @name: The name of the extension point
    426  *
    427  * Registers an extension point.
    428  *
    429  * Returns: the new #GIOExtensionPoint. This object is owned by GIO
    430  *    and should not be freed
    431  */
    432 GIOExtensionPoint *
    433 g_io_extension_point_register (const char *name)
    434 {
    435   GIOExtensionPoint *ep;
    436 
    437   G_LOCK (extension_points);
    438   if (extension_points == NULL)
    439     extension_points = g_hash_table_new_full (g_str_hash,
    440 					      g_str_equal,
    441 					      NULL,
    442 					      (GDestroyNotify)g_io_extension_point_free);
    443 
    444   if (g_hash_table_lookup (extension_points, name) != NULL)
    445     {
    446       g_warning ("Extension point %s registered multiple times", name);
    447       G_UNLOCK (extension_points);
    448       return NULL;
    449     }
    450 
    451   ep = g_new0 (GIOExtensionPoint, 1);
    452   ep->name = g_strdup (name);
    453 
    454   g_hash_table_insert (extension_points, ep->name, ep);
    455 
    456   G_UNLOCK (extension_points);
    457 
    458   return ep;
    459 }
    460 
    461 /**
    462  * g_io_extension_point_lookup:
    463  * @name: the name of the extension point
    464  *
    465  * Looks up an existing extension point.
    466  *
    467  * Returns: the #GIOExtensionPoint, or %NULL if there is no
    468  *    registered extension point with the given name
    469  */
    470 GIOExtensionPoint *
    471 g_io_extension_point_lookup (const char *name)
    472 {
    473   GIOExtensionPoint *ep;
    474 
    475   G_LOCK (extension_points);
    476   ep = NULL;
    477   if (extension_points != NULL)
    478     ep = g_hash_table_lookup (extension_points, name);
    479 
    480   G_UNLOCK (extension_points);
    481 
    482   return ep;
    483 
    484 }
    485 
    486 /**
    487  * g_io_extension_point_set_required_type:
    488  * @extension_point: a #GIOExtensionPoint
    489  * @type: the #GType to require
    490  *
    491  * Sets the required type for @extension_point to @type.
    492  * All implementations must henceforth have this type.
    493  */
    494 void
    495 g_io_extension_point_set_required_type (GIOExtensionPoint *extension_point,
    496 					GType              type)
    497 {
    498   extension_point->required_type = type;
    499 }
    500 
    501 /**
    502  * g_io_extension_point_get_required_type:
    503  * @extension_point: a #GIOExtensionPoint
    504  *
    505  * Gets the required type for @extension_point.
    506  *
    507  * Returns: the #GType that all implementations must have,
    508  *     or #G_TYPE_INVALID if the extension point has no required type
    509  */
    510 GType
    511 g_io_extension_point_get_required_type (GIOExtensionPoint *extension_point)
    512 {
    513   return extension_point->required_type;
    514 }
    515 
    516 /**
    517  * g_io_extension_point_get_extensions:
    518  * @extension_point: a #GIOExtensionPoint
    519  *
    520  * Gets a list of all extensions that implement this extension point.
    521  * The list is sorted by priority, beginning with the highest priority.
    522  *
    523  * Returns: a #GList of #GIOExtension<!-- -->s. The list is owned by
    524  *   GIO and should not be modified
    525  */
    526 GList *
    527 g_io_extension_point_get_extensions (GIOExtensionPoint *extension_point)
    528 {
    529   return extension_point->extensions;
    530 }
    531 
    532 /**
    533  * g_io_extension_point_get_extension_by_name:
    534  * @extension_point: a #GIOExtensionPoint
    535  * @name: the name of the extension to get
    536  *
    537  * Finds a #GIOExtension for an extension point by name.
    538  *
    539  * Returns: the #GIOExtension for @extension_point that has the
    540  *    given name, or %NULL if there is no extension with that name
    541  */
    542 GIOExtension *
    543 g_io_extension_point_get_extension_by_name (GIOExtensionPoint *extension_point,
    544 					    const char        *name)
    545 {
    546   GList *l;
    547 
    548   for (l = extension_point->extensions; l != NULL; l = l->next)
    549     {
    550       GIOExtension *e = l->data;
    551 
    552       if (e->name != NULL &&
    553 	  strcmp (e->name, name) == 0)
    554 	return e;
    555     }
    556 
    557   return NULL;
    558 }
    559 
    560 static gint
    561 extension_prio_compare (gconstpointer  a,
    562 			gconstpointer  b)
    563 {
    564   const GIOExtension *extension_a = a, *extension_b = b;
    565 
    566   return extension_b->priority - extension_a->priority;
    567 }
    568 
    569 /**
    570  * g_io_extension_point_implement:
    571  * @extension_point_name: the name of the extension point
    572  * @type: the #GType to register as extension
    573  * @extension_name: the name for the extension
    574  * @priority: the priority for the extension
    575  *
    576  * Registers @type as extension for the extension point with name
    577  * @extension_point_name.
    578  *
    579  * If @type has already been registered as an extension for this
    580  * extension point, the existing #GIOExtension object is returned.
    581  *
    582  * Returns: a #GIOExtension object for #GType
    583  */
    584 GIOExtension *
    585 g_io_extension_point_implement (const char *extension_point_name,
    586 				GType       type,
    587 				const char *extension_name,
    588 				gint        priority)
    589 {
    590   GIOExtensionPoint *extension_point;
    591   GIOExtension *extension;
    592   GList *l;
    593 
    594   g_return_val_if_fail (extension_point_name != NULL, NULL);
    595 
    596   extension_point = g_io_extension_point_lookup (extension_point_name);
    597   if (extension_point == NULL)
    598     {
    599       g_warning ("Tried to implement non-registered extension point %s", extension_point_name);
    600       return NULL;
    601     }
    602 
    603   if (extension_point->required_type != 0 &&
    604       !g_type_is_a (type, extension_point->required_type))
    605     {
    606       g_warning ("Tried to register an extension of the type %s to extension point %s. "
    607 		 "Expected type is %s.",
    608 		 g_type_name (type),
    609 		 extension_point_name,
    610 		 g_type_name (extension_point->required_type));
    611       return NULL;
    612     }
    613 
    614   /* It's safe to register the same type multiple times */
    615   for (l = extension_point->extensions; l != NULL; l = l->next)
    616     {
    617       extension = l->data;
    618       if (extension->type == type)
    619 	return extension;
    620     }
    621 
    622   extension = g_slice_new0 (GIOExtension);
    623   extension->type = type;
    624   extension->name = g_strdup (extension_name);
    625   extension->priority = priority;
    626 
    627   extension_point->extensions = g_list_insert_sorted (extension_point->extensions,
    628 						      extension, extension_prio_compare);
    629 
    630   return extension;
    631 }
    632 
    633 /**
    634  * g_io_extension_ref_class:
    635  * @extension: a #GIOExtension
    636  *
    637  * Gets a reference to the class for the type that is
    638  * associated with @extension.
    639  *
    640  * Returns: the #GTypeClass for the type of @extension
    641  */
    642 GTypeClass *
    643 g_io_extension_ref_class (GIOExtension *extension)
    644 {
    645   return g_type_class_ref (extension->type);
    646 }
    647 
    648 /**
    649  * g_io_extension_get_type:
    650  * @extension: a #GIOExtension
    651  *
    652  * Gets the type associated with @extension.
    653  *
    654  * Returns: the type of @extension
    655  */
    656 GType
    657 g_io_extension_get_type (GIOExtension *extension)
    658 {
    659   return extension->type;
    660 }
    661 
    662 /**
    663  * g_io_extension_get_name:
    664  * @extension: a #GIOExtension
    665  *
    666  * Gets the name under which @extension was registered.
    667  *
    668  * Note that the same type may be registered as extension
    669  * for multiple extension points, under different names.
    670  *
    671  * Returns: the name of @extension.
    672  */
    673 const char *
    674 g_io_extension_get_name (GIOExtension *extension)
    675 {
    676   return extension->name;
    677 }
    678 
    679 /**
    680  * g_io_extension_get_priority:
    681  * @extension: a #GIOExtension
    682  *
    683  * Gets the priority with which @extension was registered.
    684  *
    685  * Returns: the priority of @extension
    686  */
    687 gint
    688 g_io_extension_get_priority (GIOExtension *extension)
    689 {
    690   return extension->priority;
    691 }
    692 
    693 #define __G_IO_MODULE_C__
    694 #include "gioaliasdef.c"
    695