Coverage Report

Created: 2026-10-14 08:19

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