Coverage Report

Created: 2025-06-13 06:21

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