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 * /* Register an extension point */ 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 * /* Implement an extension point */ 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