Coverage Report

Created: 2025-07-23 08:13

/src/pango/subprojects/glib/gio/giomodule.c
Line
Count
Source (jump to first uncovered line)
1
/* GIO - GLib Input, Output and Streaming Library
2
 * 
3
 * Copyright (C) 2006-2007 Red Hat, Inc.
4
 *
5
 * SPDX-License-Identifier: LGPL-2.1-or-later
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2.1 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General
18
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19
 *
20
 * Author: Alexander Larsson <alexl@redhat.com>
21
 */
22
23
#include "config.h"
24
25
/* For the #GDesktopAppInfoLookup macros; since macro deprecation is implemented
26
 * in the preprocessor, we need to define this before including glib.h*/
27
#ifndef GLIB_DISABLE_DEPRECATION_WARNINGS
28
#define GLIB_DISABLE_DEPRECATION_WARNINGS
29
#endif
30
31
#include <string.h>
32
33
#include "giomodule.h"
34
#include "giomodule-priv.h"
35
#include "glib-private.h"
36
#include "glocalfilemonitor.h"
37
#include "gnativevolumemonitor.h"
38
#include "gproxyresolver.h"
39
#include "gproxy.h"
40
#include "gsettingsbackendinternal.h"
41
#include "ghttpproxy.h"
42
#include "gsocks4proxy.h"
43
#include "gsocks4aproxy.h"
44
#include "gsocks5proxy.h"
45
#include "gtlsbackend.h"
46
#include "gvfs.h"
47
#include "gnotificationbackend.h"
48
#include "ginitable.h"
49
#include "gnetworkmonitor.h"
50
#include "gdebugcontroller.h"
51
#include "gdebugcontrollerdbus.h"
52
#include "gmemorymonitor.h"
53
#include "gmemorymonitorportal.h"
54
#include "gmemorymonitordbus.h"
55
#ifdef __linux__
56
#include "gmemorymonitorpsi.h"
57
#endif
58
#ifdef HAVE_SYSINFO
59
#include "gmemorymonitorpoll.h"
60
#endif
61
#include "gpowerprofilemonitor.h"
62
#include "gpowerprofilemonitordbus.h"
63
#include "gpowerprofilemonitorportal.h"
64
#ifdef G_OS_WIN32
65
#include "gregistrysettingsbackend.h"
66
#include "giowin32-priv.h"
67
#endif
68
#include <glib/gstdio.h>
69
70
#if defined(G_OS_UNIX) && !defined(__APPLE__)
71
#include "gdesktopappinfo.h"
72
#endif
73
#ifdef HAVE_COCOA
74
#include "gosxappinfo.h"
75
#endif
76
77
#ifdef __APPLE__
78
#include <AvailabilityMacros.h>
79
#endif
80
81
#define __GLIB_H_INSIDE__
82
#include "gconstructor.h"
83
#undef __GLIB_H_INSIDE__
84
85
/**
86
 * GIOModule:
87
 *
88
 * Provides an interface and default functions for loading and unloading 
89
 * modules. This is used internally to make GIO extensible, but can also
90
 * be used by others to implement module loading.
91
 */
92
93
/**
94
 * GIOExtensionPoint:
95
 *
96
 * `GIOExtensionPoint` provides a mechanism for modules to extend the
97
 * functionality of the library or application that loaded it in an 
98
 * organized fashion.
99
 *
100
 * An extension point is identified by a name, and it may optionally
101
 * require that any implementation must be of a certain type (or derived
102
 * thereof). Use [func@Gio.IOExtensionPoint.register] to register an
103
 * extension point, and [method@Gio.IOExtensionPoint.set_required_type] to
104
 * set a required type.
105
 *
106
 * A module can implement an extension point by specifying the
107
 * [type@GObject.Type] that implements the functionality. Additionally, each
108
 * implementation of an extension point has a name, and a priority. Use
109
 * [func@Gio.IOExtensionPoint.implement] to implement an extension point.
110
 * 
111
 * ```c
112
 * GIOExtensionPoint *ep;
113
 *
114
 * // Register an extension point
115
 * ep = g_io_extension_point_register ("my-extension-point");
116
 * g_io_extension_point_set_required_type (ep, MY_TYPE_EXAMPLE);
117
 * ```
118
 *
119
 * ```c
120
 * // Implement an extension point
121
 * G_DEFINE_TYPE (MyExampleImpl, my_example_impl, MY_TYPE_EXAMPLE)
122
 * g_io_extension_point_implement ("my-extension-point",
123
 *                                 my_example_impl_get_type (),
124
 *                                 "my-example",
125
 *                                 10);
126
 * ```
127
 *
128
 *  It is up to the code that registered the extension point how
129
 *  it uses the implementations that have been associated with it.
130
 *  Depending on the use case, it may use all implementations, or
131
 *  only the one with the highest priority, or pick a specific
132
 *  one by name.
133
 *
134
 *  To avoid opening all modules just to find out what extension
135
 *  points they implement, GIO makes use of a caching mechanism,
136
 *  see [gio-querymodules](gio-querymodules.html).
137
 *  You are expected to run this command after installing a
138
 *  GIO module.
139
 *
140
 *  The `GIO_EXTRA_MODULES` environment variable can be used to
141
 *  specify additional directories to automatically load modules
142
 *  from. This environment variable has the same syntax as the
143
 *  `PATH`. If two modules have the same base name in different
144
 *  directories, then the latter one will be ignored. If additional
145
 *  directories are specified GIO will load modules from the built-in
146
 *  directory last.
147
 */
148
149
/**
150
 * GIOModuleScope:
151
 *
152
 * Represents a scope for loading IO modules. A scope can be used for blocking
153
 * duplicate modules, or blocking a module you don't want to load.
154
 *
155
 * The scope can be used with g_io_modules_load_all_in_directory_with_scope()
156
 * or g_io_modules_scan_all_in_directory_with_scope().
157
 *
158
 * Since: 2.30
159
 */
160
struct _GIOModuleScope {
161
  GIOModuleScopeFlags flags;
162
  GHashTable *basenames;
163
};
164
165
/**
166
 * g_io_module_scope_new:
167
 * @flags: flags for the new scope
168
 *
169
 * Create a new scope for loading of IO modules. A scope can be used for
170
 * blocking duplicate modules, or blocking a module you don't want to load.
171
 *
172
 * Specify the %G_IO_MODULE_SCOPE_BLOCK_DUPLICATES flag to block modules
173
 * which have the same base name as a module that has already been seen
174
 * in this scope.
175
 *
176
 * Returns: (transfer full): the new module scope
177
 *
178
 * Since: 2.30
179
 */
180
GIOModuleScope *
181
g_io_module_scope_new (GIOModuleScopeFlags flags)
182
0
{
183
0
  GIOModuleScope *scope = g_new0 (GIOModuleScope, 1);
184
0
  scope->flags = flags;
185
0
  scope->basenames = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
186
0
  return scope;
187
0
}
188
189
/**
190
 * g_io_module_scope_free:
191
 * @scope: a module loading scope
192
 *
193
 * Free a module scope.
194
 *
195
 * Since: 2.30
196
 */
197
void
198
g_io_module_scope_free (GIOModuleScope *scope)
199
0
{
200
0
  if (!scope)
201
0
    return;
202
0
  g_hash_table_destroy (scope->basenames);
203
0
  g_free (scope);
204
0
}
205
206
/**
207
 * g_io_module_scope_block:
208
 * @scope: a module loading scope
209
 * @basename: the basename to block
210
 *
211
 * Block modules with the given @basename from being loaded when
212
 * this scope is used with g_io_modules_scan_all_in_directory_with_scope()
213
 * or g_io_modules_load_all_in_directory_with_scope().
214
 *
215
 * Since: 2.30
216
 */
217
void
218
g_io_module_scope_block (GIOModuleScope *scope,
219
                         const gchar    *basename)
220
0
{
221
0
  gchar *key;
222
223
0
  g_return_if_fail (scope != NULL);
224
0
  g_return_if_fail (basename != NULL);
225
226
0
  key = g_strdup (basename);
227
0
  g_hash_table_add (scope->basenames, key);
228
0
}
229
230
static gboolean
231
_g_io_module_scope_contains (GIOModuleScope *scope,
232
                             const gchar    *basename)
233
0
{
234
0
  return g_hash_table_contains (scope->basenames, basename);
235
0
}
236
237
struct _GIOModule {
238
  GTypeModule parent_instance;
239
240
  gchar       *filename;
241
  GModule     *library;
242
  gboolean     initialized; /* The module was loaded at least once */
243
244
  void (* load)   (GIOModule *module);
245
  void (* unload) (GIOModule *module);
246
};
247
248
struct _GIOModuleClass
249
{
250
  GTypeModuleClass parent_class;
251
252
};
253
254
static void      g_io_module_finalize      (GObject      *object);
255
static gboolean  g_io_module_load_module   (GTypeModule  *gmodule);
256
static void      g_io_module_unload_module (GTypeModule  *gmodule);
257
258
/**
259
 * GIOExtension:
260
 *
261
 * #GIOExtension is an opaque data structure and can only be accessed
262
 * using the following functions.
263
 */
264
struct _GIOExtension {
265
  char *name;
266
  GType type;
267
  gint priority;
268
};
269
270
struct _GIOExtensionPoint {
271
  GType required_type;
272
  char *name;
273
  GList *extensions;
274
  GList *lazy_load_modules;
275
};
276
277
static GHashTable *extension_points = NULL;
278
G_LOCK_DEFINE_STATIC(extension_points);
279
280
G_DEFINE_TYPE (GIOModule, g_io_module, G_TYPE_TYPE_MODULE)
281
282
static void
283
g_io_module_class_init (GIOModuleClass *class)
284
0
{
285
0
  GObjectClass     *object_class      = G_OBJECT_CLASS (class);
286
0
  GTypeModuleClass *type_module_class = G_TYPE_MODULE_CLASS (class);
287
288
0
  object_class->finalize     = g_io_module_finalize;
289
290
0
  type_module_class->load    = g_io_module_load_module;
291
0
  type_module_class->unload  = g_io_module_unload_module;
292
0
}
293
294
static void
295
g_io_module_init (GIOModule *module)
296
0
{
297
0
}
298
299
static void
300
g_io_module_finalize (GObject *object)
301
0
{
302
0
  GIOModule *module = G_IO_MODULE (object);
303
304
0
  g_free (module->filename);
305
306
0
  G_OBJECT_CLASS (g_io_module_parent_class)->finalize (object);
307
0
}
308
309
static gboolean
310
load_symbols (GIOModule *module)
311
0
{
312
0
  gchar *name;
313
0
  gchar *load_symname;
314
0
  gchar *unload_symname;
315
0
  gboolean ret;
316
317
0
  name = _g_io_module_extract_name (module->filename);
318
0
  load_symname = g_strconcat ("g_io_", name, "_load", NULL);
319
0
  unload_symname = g_strconcat ("g_io_", name, "_unload", NULL);
320
321
0
  ret = g_module_symbol (module->library,
322
0
                         load_symname,
323
0
                         (gpointer) &module->load) &&
324
0
        g_module_symbol (module->library,
325
0
                         unload_symname,
326
0
                         (gpointer) &module->unload);
327
328
0
  if (!ret)
329
0
    {
330
      /* Fallback to old names */
331
0
      ret = g_module_symbol (module->library,
332
0
                             "g_io_module_load",
333
0
                             (gpointer) &module->load) &&
334
0
            g_module_symbol (module->library,
335
0
                             "g_io_module_unload",
336
0
                             (gpointer) &module->unload);
337
0
    }
338
339
0
  g_free (name);
340
0
  g_free (load_symname);
341
0
  g_free (unload_symname);
342
343
0
  return ret;
344
0
}
345
346
static gboolean
347
g_io_module_load_module (GTypeModule *gmodule)
348
0
{
349
0
  GIOModule *module = G_IO_MODULE (gmodule);
350
0
  GError *error = NULL;
351
352
0
  if (!module->filename)
353
0
    {
354
0
      g_warning ("GIOModule path not set");
355
0
      return FALSE;
356
0
    }
357
358
0
  module->library = g_module_open_full (module->filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL, &error);
359
360
0
  if (!module->library)
361
0
    {
362
0
      g_printerr ("%s\n", error->message);
363
0
      g_clear_error (&error);
364
0
      return FALSE;
365
0
    }
366
367
  /* Make sure that the loaded library contains the required methods */
368
0
  if (!load_symbols (module))
369
0
    {
370
0
      g_printerr ("%s\n", g_module_error ());
371
0
      g_module_close (module->library);
372
373
0
      return FALSE;
374
0
    }
375
376
  /* Initialize the loaded module */
377
0
  module->load (module);
378
0
  module->initialized = TRUE;
379
380
0
  return TRUE;
381
0
}
382
383
static void
384
g_io_module_unload_module (GTypeModule *gmodule)
385
0
{
386
0
  GIOModule *module = G_IO_MODULE (gmodule);
387
388
0
  module->unload (module);
389
390
0
  g_module_close (module->library);
391
0
  module->library = NULL;
392
393
0
  module->load   = NULL;
394
0
  module->unload = NULL;
395
0
}
396
397
/**
398
 * g_io_module_new:
399
 * @filename: (type filename): filename of the shared library module.
400
 * 
401
 * Creates a new GIOModule that will load the specific
402
 * shared library when in use.
403
 * 
404
 * Returns: a #GIOModule from given @filename, 
405
 * or %NULL on error.
406
 **/
407
GIOModule *
408
g_io_module_new (const gchar *filename)
409
0
{
410
0
  GIOModule *module;
411
412
0
  g_return_val_if_fail (filename != NULL, NULL);
413
414
0
  module = g_object_new (G_IO_TYPE_MODULE, NULL);
415
0
  module->filename = g_strdup (filename);
416
417
0
  return module;
418
0
}
419
420
static gboolean
421
is_valid_module_name (const gchar        *basename,
422
                      GIOModuleScope     *scope)
423
0
{
424
0
  gboolean result;
425
426
0
#if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
427
  #if defined(__APPLE__)
428
  if (!g_str_has_prefix (basename, "lib") ||
429
      !(g_str_has_suffix (basename, ".so") ||
430
        g_str_has_suffix (basename, ".dylib")))
431
    return FALSE;
432
  #else
433
0
  if (!g_str_has_prefix (basename, "lib") ||
434
0
      !g_str_has_suffix (basename, ".so"))
435
0
    return FALSE;
436
0
  #endif
437
#else
438
  if (!g_str_has_suffix (basename, ".dll"))
439
    return FALSE;
440
#endif
441
442
0
  result = TRUE;
443
0
  if (scope)
444
0
    {
445
0
      result = _g_io_module_scope_contains (scope, basename) ? FALSE : TRUE;
446
0
      if (result && (scope->flags & G_IO_MODULE_SCOPE_BLOCK_DUPLICATES))
447
0
        g_io_module_scope_block (scope, basename);
448
0
    }
449
450
0
  return result;
451
0
}
452
453
454
/**
455
 * g_io_modules_scan_all_in_directory_with_scope:
456
 * @dirname: (type filename): pathname for a directory containing modules
457
 *     to scan.
458
 * @scope: a scope to use when scanning the modules
459
 *
460
 * Scans all the modules in the specified directory, ensuring that
461
 * any extension point implemented by a module is registered.
462
 *
463
 * This may not actually load and initialize all the types in each
464
 * module, some modules may be lazily loaded and initialized when
465
 * an extension point it implements is used with e.g.
466
 * g_io_extension_point_get_extensions() or
467
 * g_io_extension_point_get_extension_by_name().
468
 *
469
 * If you need to guarantee that all types are loaded in all the modules,
470
 * use g_io_modules_load_all_in_directory().
471
 *
472
 * Since: 2.30
473
 **/
474
void
475
g_io_modules_scan_all_in_directory_with_scope (const char     *dirname,
476
                                               GIOModuleScope *scope)
477
0
{
478
0
  const gchar *name;
479
0
  char *filename;
480
0
  GDir *dir;
481
0
  GStatBuf statbuf;
482
0
  char *data;
483
0
  time_t cache_time;
484
0
  GHashTable *cache;
485
486
0
  if (!g_module_supported ())
487
0
    return;
488
489
0
  dir = g_dir_open (dirname, 0, NULL);
490
0
  if (!dir)
491
0
    return;
492
493
0
  filename = g_build_filename (dirname, "giomodule.cache", NULL);
494
495
0
  cache = NULL;
496
0
  cache_time = 0;
497
0
  if (g_stat (filename, &statbuf) == 0 &&
498
0
      g_file_get_contents (filename, &data, NULL, NULL))
499
0
    {
500
0
      char **lines;
501
0
      int i;
502
503
      /* cache_time is the time the cache file was created; we also take
504
       * into account the change time because in ostree based systems, all
505
       * system file have mtime equal to epoch 0.
506
       *
507
       * Any file that has a ctime before this was created then and not modified
508
       * since then (userspace can't change ctime). Its possible to change the
509
       * ctime forward without changing the file content, by e.g.  chmoding the
510
       * file, but this is uncommon and will only cause us to not use the cache
511
       * so will not cause bugs.
512
       */
513
0
      cache_time = MAX(statbuf.st_mtime, statbuf.st_ctime);
514
515
0
      lines = g_strsplit (data, "\n", -1);
516
0
      g_free (data);
517
518
0
      for (i = 0;  lines[i] != NULL; i++)
519
0
  {
520
0
    char *line = lines[i];
521
0
    char *file;
522
0
    char *colon;
523
0
    char **strv_extension_points;
524
525
0
    if (line[0] == '#')
526
0
      continue;
527
528
0
    colon = strchr (line, ':');
529
0
    if (colon == NULL || line == colon)
530
0
      continue; /* Invalid line, ignore */
531
532
0
    *colon = 0; /* terminate filename */
533
0
    file = g_strdup (line);
534
0
    colon++; /* after colon */
535
536
0
    while (g_ascii_isspace (*colon))
537
0
      colon++;
538
539
0
          if (G_UNLIKELY (!cache))
540
0
            cache = g_hash_table_new_full (g_str_hash, g_str_equal,
541
0
                                           g_free, (GDestroyNotify)g_strfreev);
542
543
0
    strv_extension_points = g_strsplit (colon, ",", -1);
544
0
    g_hash_table_insert (cache, file, strv_extension_points);
545
0
  }
546
0
      g_strfreev (lines);
547
0
    }
548
549
0
  while ((name = g_dir_read_name (dir)))
550
0
    {
551
0
      if (is_valid_module_name (name, scope))
552
0
  {
553
0
    GIOExtensionPoint *extension_point;
554
0
    GIOModule *module;
555
0
    gchar *path;
556
0
    char **strv_extension_points = NULL;
557
0
    int i;
558
559
0
    path = g_build_filename (dirname, name, NULL);
560
0
    module = g_io_module_new (path);
561
562
0
          if (cache)
563
0
            strv_extension_points = g_hash_table_lookup (cache, name);
564
565
0
    if (strv_extension_points != NULL &&
566
0
        g_stat (path, &statbuf) == 0 &&
567
0
        statbuf.st_ctime <= cache_time)
568
0
      {
569
        /* Lazy load/init the library when first required */
570
0
        for (i = 0; strv_extension_points[i] != NULL; i++)
571
0
    {
572
0
      extension_point =
573
0
        g_io_extension_point_register (strv_extension_points[i]);
574
0
      extension_point->lazy_load_modules =
575
0
        g_list_prepend (extension_point->lazy_load_modules,
576
0
            module);
577
0
    }
578
0
      }
579
0
    else
580
0
      {
581
        /* Try to load and init types */
582
0
        if (g_type_module_use (G_TYPE_MODULE (module)))
583
0
    {
584
0
      g_type_module_unuse (G_TYPE_MODULE (module)); /* Unload */
585
      /* module must remain alive, because the type system keeps weak refs */
586
0
      g_ignore_leak (module);
587
0
    }
588
0
        else
589
0
    {
590
0
      g_printerr ("Failed to load module: %s\n", path);
591
0
      g_object_unref (module);
592
0
    }
593
0
      }
594
595
0
    g_free (path);
596
0
  }
597
0
    }
598
599
0
  g_dir_close (dir);
600
601
0
  if (cache)
602
0
    g_hash_table_destroy (cache);
603
604
0
  g_free (filename);
605
0
}
606
607
/**
608
 * g_io_modules_scan_all_in_directory:
609
 * @dirname: (type filename): pathname for a directory containing modules
610
 *     to scan.
611
 *
612
 * Scans all the modules in the specified directory, ensuring that
613
 * any extension point implemented by a module is registered.
614
 *
615
 * This may not actually load and initialize all the types in each
616
 * module, some modules may be lazily loaded and initialized when
617
 * an extension point it implements is used with e.g.
618
 * g_io_extension_point_get_extensions() or
619
 * g_io_extension_point_get_extension_by_name().
620
 *
621
 * If you need to guarantee that all types are loaded in all the modules,
622
 * use g_io_modules_load_all_in_directory().
623
 *
624
 * Since: 2.24
625
 **/
626
void
627
g_io_modules_scan_all_in_directory (const char *dirname)
628
0
{
629
0
  g_io_modules_scan_all_in_directory_with_scope (dirname, NULL);
630
0
}
631
632
/**
633
 * g_io_modules_load_all_in_directory_with_scope:
634
 * @dirname: (type filename): pathname for a directory containing modules
635
 *     to load.
636
 * @scope: a scope to use when scanning the modules.
637
 *
638
 * Loads all the modules in the specified directory.
639
 *
640
 * If don't require all modules to be initialized (and thus registering
641
 * all gtypes) then you can use g_io_modules_scan_all_in_directory()
642
 * which allows delayed/lazy loading of modules.
643
 *
644
 * Returns: (element-type GIOModule) (transfer full): a list of #GIOModules loaded
645
 *      from the directory,
646
 *      All the modules are loaded into memory, if you want to
647
 *      unload them (enabling on-demand loading) you must call
648
 *      g_type_module_unuse() on all the modules. Free the list
649
 *      with g_list_free().
650
 *
651
 * Since: 2.30
652
 **/
653
GList *
654
g_io_modules_load_all_in_directory_with_scope (const char     *dirname,
655
                                               GIOModuleScope *scope)
656
0
{
657
0
  const gchar *name;
658
0
  GDir        *dir;
659
0
  GList *modules;
660
661
0
  if (!g_module_supported ())
662
0
    return NULL;
663
664
0
  dir = g_dir_open (dirname, 0, NULL);
665
0
  if (!dir)
666
0
    return NULL;
667
668
0
  modules = NULL;
669
0
  while ((name = g_dir_read_name (dir)))
670
0
    {
671
0
      if (is_valid_module_name (name, scope))
672
0
        {
673
0
          GIOModule *module;
674
0
          gchar     *path;
675
676
0
          path = g_build_filename (dirname, name, NULL);
677
0
          module = g_io_module_new (path);
678
679
0
          if (!g_type_module_use (G_TYPE_MODULE (module)))
680
0
            {
681
0
              g_printerr ("Failed to load module: %s\n", path);
682
0
              g_object_unref (module);
683
0
              g_free (path);
684
0
              continue;
685
0
            }
686
    
687
0
          g_free (path);
688
689
0
          modules = g_list_prepend (modules, module);
690
0
        }
691
0
    }
692
  
693
0
  g_dir_close (dir);
694
695
0
  return modules;
696
0
}
697
698
/**
699
 * g_io_modules_load_all_in_directory:
700
 * @dirname: (type filename): pathname for a directory containing modules
701
 *     to load.
702
 *
703
 * Loads all the modules in the specified directory.
704
 *
705
 * If don't require all modules to be initialized (and thus registering
706
 * all gtypes) then you can use g_io_modules_scan_all_in_directory()
707
 * which allows delayed/lazy loading of modules.
708
 *
709
 * Returns: (element-type GIOModule) (transfer full): a list of #GIOModules loaded
710
 *      from the directory,
711
 *      All the modules are loaded into memory, if you want to
712
 *      unload them (enabling on-demand loading) you must call
713
 *      g_type_module_unuse() on all the modules. Free the list
714
 *      with g_list_free().
715
 **/
716
GList *
717
g_io_modules_load_all_in_directory (const char *dirname)
718
0
{
719
0
  return g_io_modules_load_all_in_directory_with_scope (dirname, NULL);
720
0
}
721
722
static gpointer
723
try_class (GIOExtension *extension,
724
           guint         is_supported_offset)
725
0
{
726
0
  GType type = g_io_extension_get_type (extension);
727
0
  typedef gboolean (*verify_func) (void);
728
0
  gpointer class;
729
730
0
  class = g_type_class_ref (type);
731
0
  if (!is_supported_offset || (* G_STRUCT_MEMBER(verify_func, class, is_supported_offset)) ())
732
0
    return class;
733
734
0
  g_type_class_unref (class);
735
0
  return NULL;
736
0
}
737
738
static void
739
print_help (const char        *envvar,
740
            GIOExtensionPoint *ep)
741
0
{
742
0
  g_print ("Supported arguments for %s environment variable:\n", envvar);
743
744
0
  if (g_io_extension_point_get_extensions (ep) == NULL)
745
0
    g_print (" (none)\n");
746
0
  else
747
0
    {
748
0
      GList *l;
749
0
      GIOExtension *extension;
750
0
      gsize width = 0;
751
752
0
      for (l = g_io_extension_point_get_extensions (ep); l; l = l->next)
753
0
        {
754
0
          extension = l->data;
755
0
          width = MAX (width, strlen (g_io_extension_get_name (extension)));
756
0
        }
757
758
0
      for (l = g_io_extension_point_get_extensions (ep); l; l = l->next)
759
0
        {
760
0
          extension = l->data;
761
762
0
          g_print (" %*s - %d\n", (int) MIN (width, G_MAXINT),
763
0
                   g_io_extension_get_name (extension),
764
0
                   g_io_extension_get_priority (extension));
765
0
        }
766
0
    }
767
0
}
768
769
/**
770
 * _g_io_module_get_default_type:
771
 * @extension_point: the name of an extension point
772
 * @envvar: (nullable): the name of an environment variable to
773
 *     override the default implementation.
774
 * @is_supported_offset: a vtable offset, or zero
775
 *
776
 * Retrieves the default class implementing @extension_point.
777
 *
778
 * If @envvar is not %NULL, and the environment variable with that
779
 * name is set, then the implementation it specifies will be tried
780
 * first. After that, or if @envvar is not set, all other
781
 * implementations will be tried in order of decreasing priority.
782
 *
783
 * If @is_supported_offset is non-zero, then it is the offset into the
784
 * class vtable at which there is a function that takes no arguments and
785
 * returns a boolean.  This function will be called on each candidate
786
 * implementation to check if it is actually usable or not.
787
 *
788
 * The result is cached after it is generated the first time, and
789
 * the function is thread-safe.
790
 *
791
 * Returns: (transfer none): the type to instantiate to implement
792
 *     @extension_point, or %G_TYPE_INVALID if there are no usable
793
 *     implementations.
794
 */
795
GType
796
_g_io_module_get_default_type (const gchar *extension_point,
797
                               const gchar *envvar,
798
                               guint        is_supported_offset)
799
0
{
800
0
  static GRecMutex default_modules_lock;
801
0
  static GHashTable *default_modules;
802
0
  const char *use_this;
803
0
  GList *l;
804
0
  GIOExtensionPoint *ep;
805
0
  GIOExtension *extension, *preferred;
806
0
  gpointer impl;
807
808
0
  g_rec_mutex_lock (&default_modules_lock);
809
0
  if (default_modules)
810
0
    {
811
0
      gpointer key;
812
813
0
      if (g_hash_table_lookup_extended (default_modules, extension_point, &key, &impl))
814
0
        {
815
0
          g_rec_mutex_unlock (&default_modules_lock);
816
0
          return impl ? G_OBJECT_CLASS_TYPE (impl) : G_TYPE_INVALID;
817
0
        }
818
0
    }
819
0
  else
820
0
    {
821
0
      default_modules = g_hash_table_new (g_str_hash, g_str_equal);
822
0
    }
823
824
0
  _g_io_modules_ensure_loaded ();
825
0
  ep = g_io_extension_point_lookup (extension_point);
826
827
0
  if (!ep)
828
0
    {
829
0
      g_warn_if_reached ();
830
0
      g_rec_mutex_unlock (&default_modules_lock);
831
0
      return G_TYPE_INVALID;
832
0
    }
833
834
  /* It’s OK to query the environment here, even when running as setuid, because
835
   * it only allows a choice between existing already-loaded modules. No new
836
   * code is loaded based on the environment variable value. */
837
0
  use_this = envvar ? g_getenv (envvar) : NULL;
838
0
  if (g_strcmp0 (use_this, "help") == 0)
839
0
    {
840
0
      print_help (envvar, ep);
841
0
      use_this = NULL;
842
0
    }
843
844
0
  if (use_this)
845
0
    {
846
0
      preferred = g_io_extension_point_get_extension_by_name (ep, use_this);
847
0
      if (preferred)
848
0
        {
849
0
          impl = try_class (preferred, is_supported_offset);
850
0
          if (impl)
851
0
            goto done;
852
0
        }
853
0
      else
854
0
        g_warning ("Can't find module '%s' specified in %s", use_this, envvar);
855
0
    }
856
0
  else
857
0
    preferred = NULL;
858
859
0
  for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
860
0
    {
861
0
      extension = l->data;
862
0
      if (extension == preferred)
863
0
        continue;
864
865
0
      impl = try_class (extension, is_supported_offset);
866
0
      if (impl)
867
0
        goto done;
868
0
    }
869
870
0
  impl = NULL;
871
872
0
 done:
873
0
  g_hash_table_insert (default_modules, g_strdup (extension_point), impl);
874
0
  g_rec_mutex_unlock (&default_modules_lock);
875
876
0
  return impl ? G_OBJECT_CLASS_TYPE (impl) : G_TYPE_INVALID;
877
0
}
878
879
static gpointer
880
try_implementation (const char           *extension_point,
881
                    GIOExtension         *extension,
882
        GIOModuleVerifyFunc   verify_func)
883
0
{
884
0
  GType type = g_io_extension_get_type (extension);
885
0
  gpointer impl;
886
887
0
  if (g_type_is_a (type, G_TYPE_INITABLE))
888
0
    {
889
0
      GError *error = NULL;
890
891
0
      impl = g_initable_new (type, NULL, &error, NULL);
892
0
      if (impl)
893
0
        return impl;
894
895
0
      g_debug ("Failed to initialize %s (%s) for %s: %s",
896
0
               g_io_extension_get_name (extension),
897
0
               g_type_name (type),
898
0
               extension_point,
899
0
               error ? error->message : "");
900
0
      g_clear_error (&error);
901
0
      return NULL;
902
0
    }
903
0
  else
904
0
    {
905
0
      impl = g_object_new (type, NULL);
906
0
      if (!verify_func || verify_func (impl))
907
0
  return impl;
908
909
0
      g_object_unref (impl);
910
0
      return NULL;
911
0
    }
912
0
}
913
914
static void
915
weak_ref_free (GWeakRef *weak_ref)
916
0
{
917
0
  g_weak_ref_clear (weak_ref);
918
0
  g_free (weak_ref);
919
0
}
920
921
/**
922
 * _g_io_module_get_default:
923
 * @extension_point: the name of an extension point
924
 * @envvar: (nullable): the name of an environment variable to
925
 *     override the default implementation.
926
 * @verify_func: (nullable): a function to call to verify that
927
 *     a given implementation is usable in the current environment.
928
 *
929
 * Retrieves the default object implementing @extension_point.
930
 *
931
 * If @envvar is not %NULL, and the environment variable with that
932
 * name is set, then the implementation it specifies will be tried
933
 * first. After that, or if @envvar is not set, all other
934
 * implementations will be tried in order of decreasing priority.
935
 *
936
 * If an extension point implementation implements #GInitable, then
937
 * that implementation will only be used if it initializes
938
 * successfully. Otherwise, if @verify_func is not %NULL, then it will
939
 * be called on each candidate implementation after construction, to
940
 * check if it is actually usable or not.
941
 *
942
 * The result is cached after it is generated the first time (but the cache does
943
 * not keep a strong reference to the object), and
944
 * the function is thread-safe.
945
 *
946
 * Returns: (transfer full) (nullable): an object implementing
947
 *     @extension_point, or %NULL if there are no usable
948
 *     implementations.
949
 */
950
gpointer
951
_g_io_module_get_default (const gchar         *extension_point,
952
        const gchar         *envvar,
953
        GIOModuleVerifyFunc  verify_func)
954
0
{
955
0
  static GRecMutex default_modules_lock;
956
0
  static GHashTable *default_modules;
957
0
  const char *use_this;
958
0
  GList *l;
959
0
  GIOExtensionPoint *ep;
960
0
  GIOExtension *extension = NULL, *preferred;
961
0
  gpointer impl, value;
962
0
  GWeakRef *impl_weak_ref = NULL;
963
964
0
  g_rec_mutex_lock (&default_modules_lock);
965
0
  if (default_modules)
966
0
    {
967
0
      if (g_hash_table_lookup_extended (default_modules, extension_point,
968
0
                                        NULL, &value))
969
0
        {
970
          /* Don’t debug here, since we’re returning a cached object which was
971
           * already printed earlier. */
972
0
          impl_weak_ref = value;
973
0
          impl = g_weak_ref_get (impl_weak_ref);
974
975
          /* If the object has been finalised (impl == NULL), fall through and
976
           * instantiate a new one. */
977
0
          if (impl != NULL)
978
0
            {
979
0
              g_rec_mutex_unlock (&default_modules_lock);
980
0
              return g_steal_pointer (&impl);
981
0
            }
982
0
        }
983
0
    }
984
0
  else
985
0
    {
986
0
      default_modules = g_hash_table_new_full (g_str_hash, g_str_equal,
987
0
                                               g_free, (GDestroyNotify) weak_ref_free);
988
0
    }
989
990
0
  _g_io_modules_ensure_loaded ();
991
0
  ep = g_io_extension_point_lookup (extension_point);
992
993
0
  if (!ep)
994
0
    {
995
0
      g_debug ("%s: Failed to find extension point ‘%s’",
996
0
               G_STRFUNC, extension_point);
997
0
      g_warn_if_reached ();
998
0
      g_rec_mutex_unlock (&default_modules_lock);
999
0
      return NULL;
1000
0
    }
1001
1002
  /* It’s OK to query the environment here, even when running as setuid, because
1003
   * it only allows a choice between existing already-loaded modules. No new
1004
   * code is loaded based on the environment variable value. */
1005
0
  use_this = envvar ? g_getenv (envvar) : NULL;
1006
0
  if (g_strcmp0 (use_this, "help") == 0)
1007
0
    {
1008
0
      print_help (envvar, ep);
1009
0
      use_this = NULL;
1010
0
    }
1011
1012
0
  if (use_this)
1013
0
    {
1014
0
      preferred = g_io_extension_point_get_extension_by_name (ep, use_this);
1015
0
      if (preferred)
1016
0
  {
1017
0
    impl = try_implementation (extension_point, preferred, verify_func);
1018
0
    extension = preferred;
1019
0
    if (impl)
1020
0
      goto done;
1021
0
  }
1022
0
      else
1023
0
        g_warning ("Can't find module '%s' specified in %s", use_this, envvar);
1024
0
    }
1025
0
  else
1026
0
    preferred = NULL;
1027
1028
0
  for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
1029
0
    {
1030
0
      extension = l->data;
1031
0
      if (extension == preferred)
1032
0
  continue;
1033
1034
0
      impl = try_implementation (extension_point, extension, verify_func);
1035
0
      if (impl)
1036
0
  goto done;
1037
0
    }
1038
1039
0
  impl = NULL;
1040
1041
0
 done:
1042
0
  if (impl_weak_ref == NULL)
1043
0
    {
1044
0
      impl_weak_ref = g_new0 (GWeakRef, 1);
1045
0
      g_weak_ref_init (impl_weak_ref, impl);
1046
0
      g_hash_table_insert (default_modules, g_strdup (extension_point),
1047
0
                           g_steal_pointer (&impl_weak_ref));
1048
0
    }
1049
0
  else
1050
0
    {
1051
0
      g_weak_ref_set (impl_weak_ref, impl);
1052
0
    }
1053
1054
0
  g_rec_mutex_unlock (&default_modules_lock);
1055
1056
0
  if (impl != NULL)
1057
0
    {
1058
0
      g_assert (extension != NULL);
1059
0
      g_debug ("%s: Found default implementation %s (%s) for ‘%s’",
1060
0
               G_STRFUNC, g_io_extension_get_name (extension),
1061
0
               G_OBJECT_TYPE_NAME (impl), extension_point);
1062
0
    }
1063
0
  else
1064
0
    g_debug ("%s: Failed to find default implementation for ‘%s’",
1065
0
             G_STRFUNC, extension_point);
1066
1067
0
  return g_steal_pointer (&impl);
1068
0
}
1069
1070
extern GType g_inotify_file_monitor_get_type (void);
1071
extern GType g_kqueue_file_monitor_get_type (void);
1072
extern GType g_win32_file_monitor_get_type (void);
1073
1074
extern GType _g_unix_volume_monitor_get_type (void);
1075
extern GType _g_local_vfs_get_type (void);
1076
1077
extern GType _g_win32_volume_monitor_get_type (void);
1078
extern GType _g_winhttp_vfs_get_type (void);
1079
1080
extern GType _g_dummy_proxy_resolver_get_type (void);
1081
extern GType _g_dummy_tls_backend_get_type (void);
1082
extern GType g_network_monitor_base_get_type (void);
1083
#ifdef HAVE_NETLINK
1084
extern GType _g_network_monitor_netlink_get_type (void);
1085
extern GType _g_network_monitor_nm_get_type (void);
1086
#endif
1087
1088
extern GType g_debug_controller_dbus_get_type (void);
1089
extern GType g_memory_monitor_dbus_get_type (void);
1090
#ifdef __linux__
1091
extern GType g_memory_monitor_psi_get_type (void);
1092
#endif
1093
#ifdef HAVE_SYSINFO
1094
extern GType g_memory_monitor_poll_get_type (void);
1095
#endif
1096
extern GType g_memory_monitor_portal_get_type (void);
1097
extern GType g_memory_monitor_win32_get_type (void);
1098
extern GType g_power_profile_monitor_dbus_get_type (void);
1099
1100
#ifdef G_OS_UNIX
1101
extern GType g_fdo_notification_backend_get_type (void);
1102
extern GType g_gtk_notification_backend_get_type (void);
1103
extern GType g_portal_notification_backend_get_type (void);
1104
extern GType g_proxy_resolver_portal_get_type (void);
1105
extern GType g_network_monitor_portal_get_type (void);
1106
#endif
1107
1108
#ifdef HAVE_COCOA
1109
extern GType g_cocoa_notification_backend_get_type (void);
1110
extern GType g_osx_network_monitor_get_type (void);
1111
#endif
1112
1113
#ifdef G_PLATFORM_WIN32
1114
extern GType g_win32_notification_backend_get_type (void);
1115
1116
#include <windows.h>
1117
extern GType _g_win32_network_monitor_get_type (void);
1118
1119
static HMODULE gio_dll = NULL;
1120
1121
#ifndef GLIB_STATIC_COMPILATION
1122
1123
BOOL WINAPI DllMain (HINSTANCE hinstDLL,
1124
                     DWORD     fdwReason,
1125
                     LPVOID    lpvReserved);
1126
1127
BOOL WINAPI
1128
DllMain (HINSTANCE hinstDLL,
1129
   DWORD     fdwReason,
1130
   LPVOID    lpvReserved)
1131
{
1132
  if (fdwReason == DLL_PROCESS_ATTACH)
1133
    {
1134
      gio_dll = hinstDLL;
1135
      gio_win32_appinfo_init (FALSE);
1136
    }
1137
1138
  return TRUE;
1139
}
1140
1141
#elif defined(G_HAS_CONSTRUCTORS) /* && G_PLATFORM_WIN32 && GLIB_STATIC_COMPILATION */
1142
extern void glib_win32_init (void);
1143
extern void gobject_win32_init (void);
1144
1145
#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA
1146
#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(giomodule_init_ctor)
1147
#endif
1148
1149
G_DEFINE_CONSTRUCTOR (giomodule_init_ctor)
1150
1151
static void
1152
giomodule_init_ctor (void)
1153
{
1154
  /* When built dynamically, module initialization is done through DllMain
1155
   * function which is called when the dynamic library is loaded by the glib
1156
   * module AFTER loading gobject. So, in dynamic configuration glib and
1157
   * gobject are always initialized BEFORE gio.
1158
   *
1159
   * When built statically, initialization mechanism relies on hooking
1160
   * functions to the CRT section directly at compilation time. As we don't
1161
   * control how each compilation unit will be built and in which order, we
1162
   * obtain the same kind of issue as the "static initialization order fiasco".
1163
   * In this case, we must ensure explicitly that glib and gobject are always
1164
   * well initialized BEFORE gio.
1165
   */
1166
  glib_win32_init ();
1167
  gobject_win32_init ();
1168
  gio_win32_appinfo_init (FALSE);
1169
}
1170
1171
#else /* G_PLATFORM_WIN32 && GLIB_STATIC_COMPILATION && !G_HAS_CONSTRUCTORS */
1172
#error Your platform/compiler is missing constructor support
1173
#endif /* GLIB_STATIC_COMPILATION */
1174
1175
void *
1176
_g_io_win32_get_module (void)
1177
{
1178
  if (!gio_dll)
1179
    GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
1180
                       GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
1181
                       (LPCWSTR) _g_io_win32_get_module,
1182
                       &gio_dll);
1183
  return gio_dll;
1184
}
1185
1186
#endif /* G_PLATFORM_WIN32 */
1187
1188
void
1189
_g_io_modules_ensure_extension_points_registered (void)
1190
0
{
1191
0
  static gsize registered_extensions = FALSE;
1192
0
  GIOExtensionPoint *ep;
1193
1194
0
  if (g_once_init_enter (&registered_extensions))
1195
0
    {
1196
0
#if defined(G_OS_UNIX) && !defined(__APPLE__)
1197
0
#if !GLIB_CHECK_VERSION (3, 0, 0)
1198
0
      ep = g_io_extension_point_register (G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME);
1199
0
      g_io_extension_point_set_required_type (ep, G_TYPE_DESKTOP_APP_INFO_LOOKUP);
1200
0
#endif
1201
0
#endif
1202
1203
0
      ep = g_io_extension_point_register (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME);
1204
0
      g_io_extension_point_set_required_type (ep, G_TYPE_LOCAL_FILE_MONITOR);
1205
1206
0
      ep = g_io_extension_point_register (G_NFS_FILE_MONITOR_EXTENSION_POINT_NAME);
1207
0
      g_io_extension_point_set_required_type (ep, G_TYPE_LOCAL_FILE_MONITOR);
1208
1209
0
      ep = g_io_extension_point_register (G_VOLUME_MONITOR_EXTENSION_POINT_NAME);
1210
0
      g_io_extension_point_set_required_type (ep, G_TYPE_VOLUME_MONITOR);
1211
      
1212
0
      ep = g_io_extension_point_register (G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME);
1213
0
      g_io_extension_point_set_required_type (ep, G_TYPE_NATIVE_VOLUME_MONITOR);
1214
      
1215
0
      ep = g_io_extension_point_register (G_VFS_EXTENSION_POINT_NAME);
1216
0
      g_io_extension_point_set_required_type (ep, G_TYPE_VFS);
1217
1218
0
      ep = g_io_extension_point_register ("gsettings-backend");
1219
0
      g_io_extension_point_set_required_type (ep, G_TYPE_OBJECT);
1220
1221
0
      ep = g_io_extension_point_register (G_PROXY_RESOLVER_EXTENSION_POINT_NAME);
1222
0
      g_io_extension_point_set_required_type (ep, G_TYPE_PROXY_RESOLVER);
1223
1224
0
      ep = g_io_extension_point_register (G_PROXY_EXTENSION_POINT_NAME);
1225
0
      g_io_extension_point_set_required_type (ep, G_TYPE_PROXY);
1226
1227
0
      ep = g_io_extension_point_register (G_TLS_BACKEND_EXTENSION_POINT_NAME);
1228
0
      g_io_extension_point_set_required_type (ep, G_TYPE_TLS_BACKEND);
1229
1230
0
      ep = g_io_extension_point_register (G_NETWORK_MONITOR_EXTENSION_POINT_NAME);
1231
0
      g_io_extension_point_set_required_type (ep, G_TYPE_NETWORK_MONITOR);
1232
1233
0
      ep = g_io_extension_point_register (G_NOTIFICATION_BACKEND_EXTENSION_POINT_NAME);
1234
0
      g_io_extension_point_set_required_type (ep, G_TYPE_NOTIFICATION_BACKEND);
1235
1236
0
      ep = g_io_extension_point_register (G_DEBUG_CONTROLLER_EXTENSION_POINT_NAME);
1237
0
      g_io_extension_point_set_required_type (ep, G_TYPE_DEBUG_CONTROLLER);
1238
1239
0
      ep = g_io_extension_point_register (G_MEMORY_MONITOR_EXTENSION_POINT_NAME);
1240
0
      g_io_extension_point_set_required_type (ep, G_TYPE_MEMORY_MONITOR);
1241
1242
0
      ep = g_io_extension_point_register (G_POWER_PROFILE_MONITOR_EXTENSION_POINT_NAME);
1243
0
      g_io_extension_point_set_required_type (ep, G_TYPE_POWER_PROFILE_MONITOR);
1244
1245
0
      g_once_init_leave (&registered_extensions, TRUE);
1246
0
    }
1247
0
}
1248
1249
static gchar *
1250
get_gio_module_dir (void)
1251
0
{
1252
0
  gchar *module_dir;
1253
0
  gboolean is_setuid = GLIB_PRIVATE_CALL (g_check_setuid) ();
1254
1255
  /* If running as setuid, loading modules from an arbitrary directory
1256
   * controlled by the unprivileged user who is running the program could allow
1257
   * for execution of arbitrary code (in constructors in modules).
1258
   * Don’t allow it.
1259
   *
1260
   * If a setuid program somehow needs to load additional GIO modules, it should
1261
   * explicitly call g_io_modules_scan_all_in_directory(). */
1262
0
  module_dir = !is_setuid ? g_strdup (g_getenv ("GIO_MODULE_DIR")) : NULL;
1263
0
  if (module_dir == NULL)
1264
0
    {
1265
#ifdef G_OS_WIN32
1266
      gchar *install_dir;
1267
1268
      install_dir = g_win32_get_package_installation_directory_of_module (gio_dll);
1269
      module_dir = g_build_filename (install_dir,
1270
                                     "lib", "gio", "modules",
1271
                                     NULL);
1272
      g_free (install_dir);
1273
#else
1274
0
      module_dir = g_strdup (GIO_MODULE_DIR);
1275
#ifdef __APPLE__
1276
#include "TargetConditionals.h"
1277
/* Only auto-relocate on macOS, not watchOS etc; older macOS SDKs only define TARGET_OS_MAC */
1278
#if (defined (TARGET_OS_OSX) && TARGET_OS_OSX) || \
1279
     (!defined (TARGET_OS_OSX) && defined (TARGET_OS_MAC) && TARGET_OS_MAC)
1280
#include <dlfcn.h>
1281
      {
1282
        g_autofree gchar *path = NULL;
1283
        g_autofree gchar *possible_dir = NULL;
1284
        Dl_info info;
1285
1286
        if (dladdr (get_gio_module_dir, &info))
1287
          {
1288
            /* Gets path to the PREFIX/lib directory */
1289
            path = g_path_get_dirname (info.dli_fname);
1290
            possible_dir = g_build_filename (path, "gio", "modules", NULL);
1291
            if (g_file_test (possible_dir, G_FILE_TEST_IS_DIR))
1292
              {
1293
                g_free (module_dir);
1294
                module_dir = g_steal_pointer (&possible_dir);
1295
              }
1296
          }
1297
      }
1298
#endif
1299
#endif
1300
0
#endif
1301
0
    }
1302
1303
0
  return module_dir;
1304
0
}
1305
1306
void
1307
_g_io_modules_ensure_loaded (void)
1308
0
{
1309
0
  static gsize loaded_dirs = FALSE;
1310
0
  const char *module_path;
1311
0
  GIOModuleScope *scope;
1312
1313
0
  _g_io_modules_ensure_extension_points_registered ();
1314
1315
0
  if (g_once_init_enter (&loaded_dirs))
1316
0
    {
1317
0
      gboolean is_setuid = GLIB_PRIVATE_CALL (g_check_setuid) ();
1318
0
      gchar *module_dir;
1319
1320
0
      scope = g_io_module_scope_new (G_IO_MODULE_SCOPE_BLOCK_DUPLICATES);
1321
1322
      /* First load any overrides, extras (but not if running as setuid!) */
1323
0
      module_path = !is_setuid ? g_getenv ("GIO_EXTRA_MODULES") : NULL;
1324
0
      if (module_path)
1325
0
  {
1326
0
    gchar **paths;
1327
0
    int i;
1328
1329
0
    paths = g_strsplit (module_path, G_SEARCHPATH_SEPARATOR_S, 0);
1330
1331
0
    for (i = 0; paths[i] != NULL; i++)
1332
0
      {
1333
0
        g_io_modules_scan_all_in_directory_with_scope (paths[i], scope);
1334
0
      }
1335
1336
0
    g_strfreev (paths);
1337
0
  }
1338
1339
      /* Then load the compiled in path */
1340
0
      module_dir = get_gio_module_dir ();
1341
1342
0
      g_io_modules_scan_all_in_directory_with_scope (module_dir, scope);
1343
0
      g_free (module_dir);
1344
1345
0
      g_io_module_scope_free (scope);
1346
1347
      /* Initialize types from built-in "modules" */
1348
0
      g_type_ensure (g_null_settings_backend_get_type ());
1349
0
      g_type_ensure (g_memory_settings_backend_get_type ());
1350
0
      g_type_ensure (g_keyfile_settings_backend_get_type ());
1351
0
      g_type_ensure (g_power_profile_monitor_dbus_get_type ());
1352
0
#if defined(FILE_MONITOR_BACKEND_INOTIFY) || defined(FILE_MONITOR_BACKEND_LIBINOTIFY_KQUEUE)
1353
0
      g_type_ensure (g_inotify_file_monitor_get_type ());
1354
0
#endif
1355
#if defined(FILE_MONITOR_BACKEND_KQUEUE)
1356
      g_type_ensure (g_kqueue_file_monitor_get_type ());
1357
#endif
1358
#ifdef G_OS_WIN32
1359
      g_type_ensure (_g_win32_volume_monitor_get_type ());
1360
      g_type_ensure (g_win32_file_monitor_get_type ());
1361
      g_type_ensure (g_registry_settings_backend_get_type ());
1362
#endif
1363
#ifdef HAVE_COCOA
1364
      g_type_ensure (g_cocoa_notification_backend_get_type ());
1365
      g_type_ensure (g_nextstep_settings_backend_get_type ());
1366
      g_type_ensure (g_osx_app_info_get_type ());
1367
      g_type_ensure (g_osx_network_monitor_get_type ());
1368
#endif
1369
0
#ifdef G_OS_UNIX
1370
0
      g_type_ensure (_g_unix_volume_monitor_get_type ());
1371
0
      g_type_ensure (g_debug_controller_dbus_get_type ());
1372
0
      g_type_ensure (g_fdo_notification_backend_get_type ());
1373
0
      g_type_ensure (g_gtk_notification_backend_get_type ());
1374
0
      g_type_ensure (g_portal_notification_backend_get_type ());
1375
0
      g_type_ensure (g_memory_monitor_dbus_get_type ());
1376
0
#ifdef __linux__
1377
0
      g_type_ensure (g_memory_monitor_psi_get_type ());
1378
0
#endif
1379
0
#ifdef HAVE_SYSINFO
1380
0
      g_type_ensure (g_memory_monitor_poll_get_type ());
1381
0
#endif
1382
0
      g_type_ensure (g_memory_monitor_portal_get_type ());
1383
0
      g_type_ensure (g_network_monitor_portal_get_type ());
1384
0
      g_type_ensure (g_power_profile_monitor_portal_get_type ());
1385
0
      g_type_ensure (g_proxy_resolver_portal_get_type ());
1386
0
#endif
1387
#ifdef G_OS_WIN32
1388
      g_type_ensure (g_win32_notification_backend_get_type ());
1389
      g_type_ensure (_g_winhttp_vfs_get_type ());
1390
      g_type_ensure (g_memory_monitor_win32_get_type ());
1391
#endif
1392
0
      g_type_ensure (_g_local_vfs_get_type ());
1393
0
      g_type_ensure (_g_dummy_proxy_resolver_get_type ());
1394
0
      g_type_ensure (_g_http_proxy_get_type ());
1395
0
      g_type_ensure (_g_https_proxy_get_type ());
1396
0
      g_type_ensure (_g_socks4a_proxy_get_type ());
1397
0
      g_type_ensure (_g_socks4_proxy_get_type ());
1398
0
      g_type_ensure (_g_socks5_proxy_get_type ());
1399
0
      g_type_ensure (_g_dummy_tls_backend_get_type ());
1400
0
      g_type_ensure (g_network_monitor_base_get_type ());
1401
0
#ifdef HAVE_NETLINK
1402
0
      g_type_ensure (_g_network_monitor_netlink_get_type ());
1403
0
      g_type_ensure (_g_network_monitor_nm_get_type ());
1404
0
#endif
1405
#ifdef G_OS_WIN32
1406
      g_type_ensure (_g_win32_network_monitor_get_type ());
1407
#endif
1408
1409
0
      g_once_init_leave (&loaded_dirs, TRUE);
1410
0
    }
1411
0
}
1412
1413
static void
1414
g_io_extension_point_free (GIOExtensionPoint *ep)
1415
0
{
1416
0
  g_free (ep->name);
1417
0
  g_free (ep);
1418
0
}
1419
1420
/**
1421
 * g_io_extension_point_register:
1422
 * @name: The name of the extension point
1423
 *
1424
 * Registers an extension point.
1425
 *
1426
 * Returns: (transfer none): the new #GIOExtensionPoint. This object is
1427
 *    owned by GIO and should not be freed.
1428
 */
1429
GIOExtensionPoint *
1430
g_io_extension_point_register (const char *name)
1431
0
{
1432
0
  GIOExtensionPoint *ep;
1433
  
1434
0
  G_LOCK (extension_points);
1435
0
  if (extension_points == NULL)
1436
0
    extension_points = g_hash_table_new_full (g_str_hash,
1437
0
                g_str_equal,
1438
0
                NULL,
1439
0
                (GDestroyNotify)g_io_extension_point_free);
1440
1441
0
  ep = g_hash_table_lookup (extension_points, name);
1442
0
  if (ep != NULL)
1443
0
    {
1444
0
      G_UNLOCK (extension_points);
1445
0
      return ep;
1446
0
    }
1447
1448
0
  ep = g_new0 (GIOExtensionPoint, 1);
1449
0
  ep->name = g_strdup (name);
1450
  
1451
0
  g_hash_table_insert (extension_points, ep->name, ep);
1452
  
1453
0
  G_UNLOCK (extension_points);
1454
1455
0
  return ep;
1456
0
}
1457
1458
/**
1459
 * g_io_extension_point_lookup:
1460
 * @name: the name of the extension point
1461
 *
1462
 * Looks up an existing extension point.
1463
 *
1464
 * Returns: (transfer none): the #GIOExtensionPoint, or %NULL if there
1465
 *    is no registered extension point with the given name.
1466
 */
1467
GIOExtensionPoint *
1468
g_io_extension_point_lookup (const char *name)
1469
0
{
1470
0
  GIOExtensionPoint *ep;
1471
1472
0
  G_LOCK (extension_points);
1473
0
  ep = NULL;
1474
0
  if (extension_points != NULL)
1475
0
    ep = g_hash_table_lookup (extension_points, name);
1476
  
1477
0
  G_UNLOCK (extension_points);
1478
1479
0
  return ep;
1480
  
1481
0
}
1482
1483
/**
1484
 * g_io_extension_point_set_required_type:
1485
 * @extension_point: a #GIOExtensionPoint
1486
 * @type: the #GType to require
1487
 *
1488
 * Sets the required type for @extension_point to @type. 
1489
 * All implementations must henceforth have this type.
1490
 */
1491
void
1492
g_io_extension_point_set_required_type (GIOExtensionPoint *extension_point,
1493
          GType              type)
1494
0
{
1495
0
  extension_point->required_type = type;
1496
0
}
1497
1498
/**
1499
 * g_io_extension_point_get_required_type:
1500
 * @extension_point: a #GIOExtensionPoint
1501
 *
1502
 * Gets the required type for @extension_point.
1503
 *
1504
 * Returns: the #GType that all implementations must have, 
1505
 *   or %G_TYPE_INVALID if the extension point has no required type
1506
 */
1507
GType
1508
g_io_extension_point_get_required_type (GIOExtensionPoint *extension_point)
1509
0
{
1510
0
  return extension_point->required_type;
1511
0
}
1512
1513
static void
1514
lazy_load_modules (GIOExtensionPoint *extension_point)
1515
0
{
1516
0
  GIOModule *module;
1517
0
  GList *l;
1518
1519
0
  for (l = extension_point->lazy_load_modules; l != NULL; l = l->next)
1520
0
    {
1521
0
      module = l->data;
1522
1523
0
      if (!module->initialized)
1524
0
  {
1525
0
    if (g_type_module_use (G_TYPE_MODULE (module)))
1526
0
      g_type_module_unuse (G_TYPE_MODULE (module)); /* Unload */
1527
0
    else
1528
0
      g_printerr ("Failed to load module: %s\n",
1529
0
      module->filename);
1530
0
  }
1531
0
    }
1532
0
}
1533
1534
/**
1535
 * g_io_extension_point_get_extensions:
1536
 * @extension_point: a #GIOExtensionPoint
1537
 *
1538
 * Gets a list of all extensions that implement this extension point.
1539
 * The list is sorted by priority, beginning with the highest priority.
1540
 *
1541
 * Returns: (element-type GIOExtension) (transfer none): a #GList of
1542
 *     #GIOExtensions. The list is owned by GIO and should not be
1543
 *     modified.
1544
 */
1545
GList *
1546
g_io_extension_point_get_extensions (GIOExtensionPoint *extension_point)
1547
0
{
1548
0
  g_return_val_if_fail (extension_point != NULL, NULL);
1549
1550
0
  lazy_load_modules (extension_point);
1551
0
  return extension_point->extensions;
1552
0
}
1553
1554
/**
1555
 * g_io_extension_point_get_extension_by_name:
1556
 * @extension_point: a #GIOExtensionPoint
1557
 * @name: the name of the extension to get
1558
 *
1559
 * Finds a #GIOExtension for an extension point by name.
1560
 *
1561
 * Returns: (transfer none): the #GIOExtension for @extension_point that has the
1562
 *    given name, or %NULL if there is no extension with that name
1563
 */
1564
GIOExtension *
1565
g_io_extension_point_get_extension_by_name (GIOExtensionPoint *extension_point,
1566
              const char        *name)
1567
0
{
1568
0
  GList *l;
1569
1570
0
  g_return_val_if_fail (name != NULL, NULL);
1571
1572
0
  lazy_load_modules (extension_point);
1573
0
  for (l = extension_point->extensions; l != NULL; l = l->next)
1574
0
    {
1575
0
      GIOExtension *e = l->data;
1576
1577
0
      if (e->name != NULL &&
1578
0
    strcmp (e->name, name) == 0)
1579
0
  return e;
1580
0
    }
1581
  
1582
0
  return NULL;
1583
0
}
1584
1585
static gint
1586
extension_prio_compare (gconstpointer  a,
1587
      gconstpointer  b)
1588
0
{
1589
0
  const GIOExtension *extension_a = a, *extension_b = b;
1590
1591
0
  if (extension_a->priority > extension_b->priority)
1592
0
    return -1;
1593
1594
0
  if (extension_b->priority > extension_a->priority)
1595
0
    return 1;
1596
1597
0
  return 0;
1598
0
}
1599
1600
/**
1601
 * g_io_extension_point_implement:
1602
 * @extension_point_name: the name of the extension point
1603
 * @type: the #GType to register as extension 
1604
 * @extension_name: the name for the extension
1605
 * @priority: the priority for the extension
1606
 *
1607
 * Registers @type as extension for the extension point with name
1608
 * @extension_point_name. 
1609
 *
1610
 * If @type has already been registered as an extension for this 
1611
 * extension point, the existing #GIOExtension object is returned.
1612
 *
1613
 * Returns: (transfer none): a #GIOExtension object for #GType
1614
 */
1615
GIOExtension *
1616
g_io_extension_point_implement (const char *extension_point_name,
1617
        GType       type,
1618
        const char *extension_name,
1619
        gint        priority)
1620
0
{
1621
0
  GIOExtensionPoint *extension_point;
1622
0
  GIOExtension *extension;
1623
0
  GList *l;
1624
1625
0
  g_return_val_if_fail (extension_point_name != NULL, NULL);
1626
1627
0
  extension_point = g_io_extension_point_lookup (extension_point_name);
1628
0
  if (extension_point == NULL)
1629
0
    {
1630
0
      g_warning ("Tried to implement non-registered extension point %s", extension_point_name);
1631
0
      return NULL;
1632
0
    }
1633
  
1634
0
  if (extension_point->required_type != 0 &&
1635
0
      !g_type_is_a (type, extension_point->required_type))
1636
0
    {
1637
0
      g_warning ("Tried to register an extension of the type %s to extension point %s. "
1638
0
     "Expected type is %s.",
1639
0
     g_type_name (type),
1640
0
     extension_point_name, 
1641
0
     g_type_name (extension_point->required_type));
1642
0
      return NULL;
1643
0
    }      
1644
1645
  /* It's safe to register the same type multiple times */
1646
0
  for (l = extension_point->extensions; l != NULL; l = l->next)
1647
0
    {
1648
0
      extension = l->data;
1649
0
      if (extension->type == type)
1650
0
  return extension;
1651
0
    }
1652
  
1653
0
  extension = g_slice_new0 (GIOExtension);
1654
0
  extension->type = type;
1655
0
  extension->name = g_strdup (extension_name);
1656
0
  extension->priority = priority;
1657
  
1658
0
  extension_point->extensions = g_list_insert_sorted (extension_point->extensions,
1659
0
                  extension, extension_prio_compare);
1660
  
1661
0
  return extension;
1662
0
}
1663
1664
/**
1665
 * g_io_extension_ref_class:
1666
 * @extension: a #GIOExtension
1667
 *
1668
 * Gets a reference to the class for the type that is 
1669
 * associated with @extension.
1670
 *
1671
 * Returns: (transfer full): the #GTypeClass for the type of @extension
1672
 */
1673
GTypeClass *
1674
g_io_extension_ref_class (GIOExtension *extension)
1675
0
{
1676
0
  return g_type_class_ref (extension->type);
1677
0
}
1678
1679
/**
1680
 * g_io_extension_get_type:
1681
 * @extension: a #GIOExtension
1682
 *
1683
 * Gets the type associated with @extension.
1684
 *
1685
 * Returns: the type of @extension
1686
 */
1687
GType
1688
g_io_extension_get_type (GIOExtension *extension)
1689
0
{
1690
0
  return extension->type;
1691
0
}
1692
1693
/**
1694
 * g_io_extension_get_name:
1695
 * @extension: a #GIOExtension
1696
 *
1697
 * Gets the name under which @extension was registered.
1698
 *
1699
 * Note that the same type may be registered as extension
1700
 * for multiple extension points, under different names.
1701
 *
1702
 * Returns: the name of @extension.
1703
 */
1704
const char *
1705
g_io_extension_get_name (GIOExtension *extension)
1706
0
{
1707
0
  return extension->name;
1708
0
}
1709
1710
/**
1711
 * g_io_extension_get_priority:
1712
 * @extension: a #GIOExtension
1713
 *
1714
 * Gets the priority with which @extension was registered.
1715
 *
1716
 * Returns: the priority of @extension
1717
 */
1718
gint
1719
g_io_extension_get_priority (GIOExtension *extension)
1720
0
{
1721
0
  return extension->priority;
1722
0
}