Home | History | Annotate | Download | only in gio
      1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
      2 
      3 /* GIO - GLib Input, Output and Streaming Library
      4  *
      5  * Copyright (C) 2006-2007 Red Hat, Inc.
      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 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, write to the
     19  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
     20  * Boston, MA 02111-1307, USA.
     21  *
     22  * Author: Alexander Larsson <alexl (at) redhat.com>
     23  *         David Zeuthen <davidz (at) redhat.com>
     24  */
     25 
     26 #include "config.h"
     27 
     28 #include <string.h>
     29 
     30 #include <glib.h>
     31 #include "gunionvolumemonitor.h"
     32 #include "gmountprivate.h"
     33 #include "giomodule-priv.h"
     34 #ifdef G_OS_UNIX
     35 #include "gunixvolumemonitor.h"
     36 #endif
     37 #include "gnativevolumemonitor.h"
     38 
     39 #include "glibintl.h"
     40 
     41 #include "gioalias.h"
     42 
     43 struct _GUnionVolumeMonitor {
     44   GVolumeMonitor parent;
     45 
     46   GList *monitors;
     47 };
     48 
     49 static void g_union_volume_monitor_remove_monitor (GUnionVolumeMonitor *union_monitor,
     50 						   GVolumeMonitor *child_monitor);
     51 
     52 
     53 #define g_union_volume_monitor_get_type _g_union_volume_monitor_get_type
     54 G_DEFINE_TYPE (GUnionVolumeMonitor, g_union_volume_monitor, G_TYPE_VOLUME_MONITOR);
     55 
     56 static GStaticRecMutex the_volume_monitor_mutex = G_STATIC_REC_MUTEX_INIT;
     57 
     58 static GUnionVolumeMonitor *the_volume_monitor = NULL;
     59 
     60 static void
     61 g_union_volume_monitor_finalize (GObject *object)
     62 {
     63   GUnionVolumeMonitor *monitor;
     64   GVolumeMonitor *child_monitor;
     65 
     66   monitor = G_UNION_VOLUME_MONITOR (object);
     67 
     68   while (monitor->monitors != NULL)
     69     {
     70       child_monitor = monitor->monitors->data;
     71       g_union_volume_monitor_remove_monitor (monitor,
     72                                              child_monitor);
     73       g_object_unref (child_monitor);
     74     }
     75 
     76   G_OBJECT_CLASS (g_union_volume_monitor_parent_class)->finalize (object);
     77 }
     78 
     79 static void
     80 g_union_volume_monitor_dispose (GObject *object)
     81 {
     82   GUnionVolumeMonitor *monitor;
     83   GVolumeMonitor *child_monitor;
     84   GList *l;
     85 
     86   monitor = G_UNION_VOLUME_MONITOR (object);
     87 
     88   g_static_rec_mutex_lock (&the_volume_monitor_mutex);
     89   the_volume_monitor = NULL;
     90 
     91   for (l = monitor->monitors; l != NULL; l = l->next)
     92     {
     93       child_monitor = l->data;
     94       g_object_run_dispose (G_OBJECT (child_monitor));
     95     }
     96 
     97   g_static_rec_mutex_unlock (&the_volume_monitor_mutex);
     98 
     99   G_OBJECT_CLASS (g_union_volume_monitor_parent_class)->dispose (object);
    100 }
    101 
    102 static GList *
    103 get_mounts (GVolumeMonitor *volume_monitor)
    104 {
    105   GUnionVolumeMonitor *monitor;
    106   GVolumeMonitor *child_monitor;
    107   GList *res;
    108   GList *l;
    109 
    110   monitor = G_UNION_VOLUME_MONITOR (volume_monitor);
    111 
    112   res = NULL;
    113 
    114   g_static_rec_mutex_lock (&the_volume_monitor_mutex);
    115 
    116   for (l = monitor->monitors; l != NULL; l = l->next)
    117     {
    118       child_monitor = l->data;
    119 
    120       res = g_list_concat (res, g_volume_monitor_get_mounts (child_monitor));
    121     }
    122 
    123   g_static_rec_mutex_unlock (&the_volume_monitor_mutex);
    124 
    125   return res;
    126 }
    127 
    128 static GList *
    129 get_volumes (GVolumeMonitor *volume_monitor)
    130 {
    131   GUnionVolumeMonitor *monitor;
    132   GVolumeMonitor *child_monitor;
    133   GList *res;
    134   GList *l;
    135 
    136   monitor = G_UNION_VOLUME_MONITOR (volume_monitor);
    137 
    138   res = NULL;
    139 
    140   g_static_rec_mutex_lock (&the_volume_monitor_mutex);
    141 
    142   for (l = monitor->monitors; l != NULL; l = l->next)
    143     {
    144       child_monitor = l->data;
    145 
    146       res = g_list_concat (res, g_volume_monitor_get_volumes (child_monitor));
    147     }
    148 
    149   g_static_rec_mutex_unlock (&the_volume_monitor_mutex);
    150 
    151   return res;
    152 }
    153 
    154 static GList *
    155 get_connected_drives (GVolumeMonitor *volume_monitor)
    156 {
    157   GUnionVolumeMonitor *monitor;
    158   GVolumeMonitor *child_monitor;
    159   GList *res;
    160   GList *l;
    161 
    162   monitor = G_UNION_VOLUME_MONITOR (volume_monitor);
    163 
    164   res = NULL;
    165 
    166   g_static_rec_mutex_lock (&the_volume_monitor_mutex);
    167 
    168   for (l = monitor->monitors; l != NULL; l = l->next)
    169     {
    170       child_monitor = l->data;
    171 
    172       res = g_list_concat (res, g_volume_monitor_get_connected_drives (child_monitor));
    173     }
    174 
    175   g_static_rec_mutex_unlock (&the_volume_monitor_mutex);
    176 
    177   return res;
    178 }
    179 
    180 static GVolume *
    181 get_volume_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
    182 {
    183   GUnionVolumeMonitor *monitor;
    184   GVolumeMonitor *child_monitor;
    185   GVolume *volume;
    186   GList *l;
    187 
    188   monitor = G_UNION_VOLUME_MONITOR (volume_monitor);
    189 
    190   volume = NULL;
    191 
    192   g_static_rec_mutex_lock (&the_volume_monitor_mutex);
    193 
    194   for (l = monitor->monitors; l != NULL; l = l->next)
    195     {
    196       child_monitor = l->data;
    197 
    198       volume = g_volume_monitor_get_volume_for_uuid (child_monitor, uuid);
    199       if (volume != NULL)
    200         break;
    201 
    202     }
    203 
    204   g_static_rec_mutex_unlock (&the_volume_monitor_mutex);
    205 
    206   return volume;
    207 }
    208 
    209 static GMount *
    210 get_mount_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
    211 {
    212   GUnionVolumeMonitor *monitor;
    213   GVolumeMonitor *child_monitor;
    214   GMount *mount;
    215   GList *l;
    216 
    217   monitor = G_UNION_VOLUME_MONITOR (volume_monitor);
    218 
    219   mount = NULL;
    220 
    221   g_static_rec_mutex_lock (&the_volume_monitor_mutex);
    222 
    223   for (l = monitor->monitors; l != NULL; l = l->next)
    224     {
    225       child_monitor = l->data;
    226 
    227       mount = g_volume_monitor_get_mount_for_uuid (child_monitor, uuid);
    228       if (mount != NULL)
    229         break;
    230 
    231     }
    232 
    233   g_static_rec_mutex_unlock (&the_volume_monitor_mutex);
    234 
    235   return mount;
    236 }
    237 
    238 static void
    239 g_union_volume_monitor_class_init (GUnionVolumeMonitorClass *klass)
    240 {
    241   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
    242   GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass);
    243 
    244   gobject_class->finalize = g_union_volume_monitor_finalize;
    245   gobject_class->dispose = g_union_volume_monitor_dispose;
    246 
    247   monitor_class->get_connected_drives = get_connected_drives;
    248   monitor_class->get_volumes = get_volumes;
    249   monitor_class->get_mounts = get_mounts;
    250   monitor_class->get_volume_for_uuid = get_volume_for_uuid;
    251   monitor_class->get_mount_for_uuid = get_mount_for_uuid;
    252 }
    253 
    254 static void
    255 child_volume_added (GVolumeMonitor      *child_monitor,
    256                     GVolume    *child_volume,
    257                     GUnionVolumeMonitor *union_monitor)
    258 {
    259   g_signal_emit_by_name (union_monitor,
    260 			 "volume-added",
    261 			 child_volume);
    262 }
    263 
    264 static void
    265 child_volume_removed (GVolumeMonitor      *child_monitor,
    266                       GVolume    *child_volume,
    267                       GUnionVolumeMonitor *union_monitor)
    268 {
    269   g_signal_emit_by_name (union_monitor,
    270 			 "volume-removed",
    271 			 child_volume);
    272 }
    273 
    274 static void
    275 child_volume_changed (GVolumeMonitor      *child_monitor,
    276                       GVolume    *child_volume,
    277                       GUnionVolumeMonitor *union_monitor)
    278 {
    279   g_signal_emit_by_name (union_monitor,
    280 			 "volume-changed",
    281 			 child_volume);
    282 }
    283 
    284 static void
    285 child_mount_added (GVolumeMonitor      *child_monitor,
    286                    GMount              *child_mount,
    287                    GUnionVolumeMonitor *union_monitor)
    288 {
    289   g_signal_emit_by_name (union_monitor,
    290                          "mount-added",
    291                          child_mount);
    292 }
    293 
    294 static void
    295 child_mount_removed (GVolumeMonitor      *child_monitor,
    296                      GMount              *child_mount,
    297                      GUnionVolumeMonitor *union_monitor)
    298 {
    299   g_signal_emit_by_name (union_monitor,
    300 			 "mount-removed",
    301 			 child_mount);
    302 }
    303 
    304 static void
    305 child_mount_pre_unmount (GVolumeMonitor       *child_monitor,
    306                           GMount              *child_mount,
    307                           GUnionVolumeMonitor *union_monitor)
    308 {
    309   g_signal_emit_by_name (union_monitor,
    310 			 "mount-pre-unmount",
    311 			 child_mount);
    312 }
    313 
    314 
    315 static void
    316 child_mount_changed (GVolumeMonitor       *child_monitor,
    317                       GMount              *child_mount,
    318                       GUnionVolumeMonitor *union_monitor)
    319 {
    320   g_signal_emit_by_name (union_monitor,
    321 			 "mount-changed",
    322 			 child_mount);
    323 }
    324 
    325 static void
    326 child_drive_connected (GVolumeMonitor      *child_monitor,
    327                        GDrive              *child_drive,
    328                        GUnionVolumeMonitor *union_monitor)
    329 {
    330   g_signal_emit_by_name (union_monitor,
    331 			 "drive-connected",
    332 			 child_drive);
    333 }
    334 
    335 static void
    336 child_drive_disconnected (GVolumeMonitor      *child_monitor,
    337                           GDrive              *child_drive,
    338                           GUnionVolumeMonitor *union_monitor)
    339 {
    340   g_signal_emit_by_name (union_monitor,
    341 			 "drive-disconnected",
    342 			 child_drive);
    343 }
    344 
    345 static void
    346 child_drive_changed (GVolumeMonitor      *child_monitor,
    347                      GDrive             *child_drive,
    348                      GUnionVolumeMonitor *union_monitor)
    349 {
    350   g_signal_emit_by_name (union_monitor,
    351                          "drive-changed",
    352                          child_drive);
    353 }
    354 
    355 static void
    356 child_drive_eject_button (GVolumeMonitor      *child_monitor,
    357                           GDrive             *child_drive,
    358                           GUnionVolumeMonitor *union_monitor)
    359 {
    360   g_signal_emit_by_name (union_monitor,
    361                          "drive-eject-button",
    362                          child_drive);
    363 }
    364 
    365 static void
    366 g_union_volume_monitor_add_monitor (GUnionVolumeMonitor *union_monitor,
    367                                     GVolumeMonitor      *volume_monitor)
    368 {
    369   if (g_list_find (union_monitor->monitors, volume_monitor))
    370     return;
    371 
    372   union_monitor->monitors =
    373     g_list_prepend (union_monitor->monitors,
    374 		    g_object_ref (volume_monitor));
    375 
    376   g_signal_connect (volume_monitor, "volume-added", (GCallback)child_volume_added, union_monitor);
    377   g_signal_connect (volume_monitor, "volume-removed", (GCallback)child_volume_removed, union_monitor);
    378   g_signal_connect (volume_monitor, "volume-changed", (GCallback)child_volume_changed, union_monitor);
    379   g_signal_connect (volume_monitor, "mount-added", (GCallback)child_mount_added, union_monitor);
    380   g_signal_connect (volume_monitor, "mount-removed", (GCallback)child_mount_removed, union_monitor);
    381   g_signal_connect (volume_monitor, "mount-pre-unmount", (GCallback)child_mount_pre_unmount, union_monitor);
    382   g_signal_connect (volume_monitor, "mount-changed", (GCallback)child_mount_changed, union_monitor);
    383   g_signal_connect (volume_monitor, "drive-connected", (GCallback)child_drive_connected, union_monitor);
    384   g_signal_connect (volume_monitor, "drive-disconnected", (GCallback)child_drive_disconnected, union_monitor);
    385   g_signal_connect (volume_monitor, "drive-changed", (GCallback)child_drive_changed, union_monitor);
    386   g_signal_connect (volume_monitor, "drive-eject-button", (GCallback)child_drive_eject_button, union_monitor);
    387 }
    388 
    389 static void
    390 g_union_volume_monitor_remove_monitor (GUnionVolumeMonitor *union_monitor,
    391                                        GVolumeMonitor      *child_monitor)
    392 {
    393   GList *l;
    394 
    395   l = g_list_find (union_monitor->monitors, child_monitor);
    396   if (l == NULL)
    397     return;
    398 
    399   union_monitor->monitors = g_list_delete_link (union_monitor->monitors, l);
    400 
    401   g_signal_handlers_disconnect_by_func (child_monitor, child_volume_added, union_monitor);
    402   g_signal_handlers_disconnect_by_func (child_monitor, child_volume_removed, union_monitor);
    403   g_signal_handlers_disconnect_by_func (child_monitor, child_volume_changed, union_monitor);
    404   g_signal_handlers_disconnect_by_func (child_monitor, child_mount_added, union_monitor);
    405   g_signal_handlers_disconnect_by_func (child_monitor, child_mount_removed, union_monitor);
    406   g_signal_handlers_disconnect_by_func (child_monitor, child_mount_pre_unmount, union_monitor);
    407   g_signal_handlers_disconnect_by_func (child_monitor, child_mount_changed, union_monitor);
    408   g_signal_handlers_disconnect_by_func (child_monitor, child_drive_connected, union_monitor);
    409   g_signal_handlers_disconnect_by_func (child_monitor, child_drive_disconnected, union_monitor);
    410   g_signal_handlers_disconnect_by_func (child_monitor, child_drive_changed, union_monitor);
    411   g_signal_handlers_disconnect_by_func (child_monitor, child_drive_eject_button, union_monitor);
    412 }
    413 
    414 static GType
    415 get_default_native_class (gpointer data)
    416 {
    417   GNativeVolumeMonitorClass *klass, *native_class, **native_class_out;
    418   const char *use_this;
    419   GIOExtensionPoint *ep;
    420   GIOExtension *extension;
    421   GList *l;
    422 
    423   native_class_out = data;
    424 
    425   use_this = g_getenv ("GIO_USE_VOLUME_MONITOR");
    426 
    427   /* Ensure vfs in modules loaded */
    428   _g_io_modules_ensure_loaded ();
    429 
    430   ep = g_io_extension_point_lookup (G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME);
    431 
    432   native_class = NULL;
    433   if (use_this)
    434     {
    435       extension = g_io_extension_point_get_extension_by_name (ep, use_this);
    436       if (extension)
    437 	{
    438 	  klass = G_NATIVE_VOLUME_MONITOR_CLASS (g_io_extension_ref_class (extension));
    439 	  if (G_VOLUME_MONITOR_CLASS (klass)->is_supported())
    440 	    native_class = klass;
    441 	  else
    442 	    g_type_class_unref (klass);
    443 	}
    444     }
    445 
    446   if (native_class == NULL)
    447     {
    448       for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
    449 	{
    450 	  extension = l->data;
    451 	  klass = G_NATIVE_VOLUME_MONITOR_CLASS (g_io_extension_ref_class (extension));
    452 	  if (G_VOLUME_MONITOR_CLASS (klass)->is_supported())
    453 	    {
    454 	      native_class = klass;
    455 	      break;
    456 	    }
    457 	  else
    458 	    g_type_class_unref (klass);
    459 	}
    460     }
    461 
    462   if (native_class)
    463     {
    464       *native_class_out = native_class;
    465       return G_TYPE_FROM_CLASS (native_class);
    466     }
    467   else
    468     return G_TYPE_INVALID;
    469 }
    470 
    471 /* We return the class, with a ref taken.
    472  * This way we avoid unloading the class/module
    473  * between selecting the type and creating the
    474  * instance on the first call.
    475  */
    476 static GNativeVolumeMonitorClass *
    477 get_native_class (void)
    478 {
    479   static GOnce once_init = G_ONCE_INIT;
    480   GTypeClass *type_class;
    481 
    482   type_class = NULL;
    483   g_once (&once_init, (GThreadFunc)get_default_native_class, &type_class);
    484 
    485   if (type_class == NULL && once_init.retval != GUINT_TO_POINTER(G_TYPE_INVALID))
    486     type_class = g_type_class_ref ((GType)once_init.retval);
    487 
    488   return (GNativeVolumeMonitorClass *)type_class;
    489 }
    490 
    491 static void
    492 g_union_volume_monitor_init (GUnionVolumeMonitor *union_monitor)
    493 {
    494 }
    495 
    496 static void
    497 populate_union_monitor (GUnionVolumeMonitor *union_monitor)
    498 {
    499   GVolumeMonitor *monitor;
    500   GNativeVolumeMonitorClass *native_class;
    501   GVolumeMonitorClass *klass;
    502   GIOExtensionPoint *ep;
    503   GIOExtension *extension;
    504   GList *l;
    505 
    506   native_class = get_native_class ();
    507 
    508   if (native_class != NULL)
    509     {
    510       monitor = g_object_new (G_TYPE_FROM_CLASS (native_class), NULL);
    511       g_union_volume_monitor_add_monitor (union_monitor, monitor);
    512       g_object_unref (monitor);
    513       g_type_class_unref (native_class);
    514     }
    515 
    516   ep = g_io_extension_point_lookup (G_VOLUME_MONITOR_EXTENSION_POINT_NAME);
    517   for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next)
    518     {
    519       extension = l->data;
    520 
    521       klass = G_VOLUME_MONITOR_CLASS (g_io_extension_ref_class (extension));
    522       if (klass->is_supported == NULL || klass->is_supported())
    523 	{
    524 	  monitor = g_object_new (g_io_extension_get_type (extension), NULL);
    525 	  g_union_volume_monitor_add_monitor (union_monitor, monitor);
    526 	  g_object_unref (monitor);
    527 	}
    528       g_type_class_unref (klass);
    529     }
    530 }
    531 
    532 static GUnionVolumeMonitor *
    533 g_union_volume_monitor_new (void)
    534 {
    535   GUnionVolumeMonitor *monitor;
    536 
    537   monitor = g_object_new (G_TYPE_UNION_VOLUME_MONITOR, NULL);
    538 
    539   return monitor;
    540 }
    541 
    542 /**
    543  * g_volume_monitor_get:
    544  *
    545  * Gets the volume monitor used by gio.
    546  *
    547  * Returns: a reference to the #GVolumeMonitor used by gio. Call
    548  *    g_object_unref() when done with it.
    549  **/
    550 GVolumeMonitor *
    551 g_volume_monitor_get (void)
    552 {
    553   GVolumeMonitor *vm;
    554 
    555   g_static_rec_mutex_lock (&the_volume_monitor_mutex);
    556 
    557   if (the_volume_monitor)
    558     vm = G_VOLUME_MONITOR (g_object_ref (the_volume_monitor));
    559   else
    560     {
    561       the_volume_monitor = g_union_volume_monitor_new ();
    562       populate_union_monitor (the_volume_monitor);
    563       vm = G_VOLUME_MONITOR (the_volume_monitor);
    564     }
    565 
    566   g_static_rec_mutex_unlock (&the_volume_monitor_mutex);
    567 
    568   return vm;
    569 }
    570 
    571 /**
    572  * _g_mount_get_for_mount_path:
    573  * @mountpoint: a string.
    574  * @cancellable: a #GCancellable, or %NULL
    575  *
    576  * Returns: a #GMount for given @mount_path or %NULL.
    577  **/
    578 GMount *
    579 _g_mount_get_for_mount_path (const char *mount_path,
    580 			     GCancellable *cancellable)
    581 {
    582   GNativeVolumeMonitorClass *klass;
    583   GMount *mount;
    584 
    585   klass = get_native_class ();
    586   if (klass == NULL)
    587     return NULL;
    588 
    589   mount = NULL;
    590 
    591   if (klass->get_mount_for_mount_path)
    592     {
    593       g_static_rec_mutex_lock (&the_volume_monitor_mutex);
    594       mount = klass->get_mount_for_mount_path (mount_path, cancellable);
    595       g_static_rec_mutex_unlock (&the_volume_monitor_mutex);
    596     }
    597 
    598   /* TODO: How do we know this succeeded? Keep in mind that the native
    599    *       volume monitor may fail (e.g. not being able to connect to
    600    *       hald). Is the get_mount_for_mount_path() method allowed to
    601    *       return NULL? Seems like it is ... probably the method needs
    602    *       to take a boolean and write if it succeeds or not.. Messy.
    603    *       Very messy.
    604    */
    605 
    606   g_type_class_unref (klass);
    607 
    608   return mount;
    609 }
    610 
    611 /**
    612  * g_volume_monitor_adopt_orphan_mount:
    613  * @mount: a #GMount object to find a parent for
    614  *
    615  * This function should be called by any #GVolumeMonitor
    616  * implementation when a new #GMount object is created that is not
    617  * associated with a #GVolume object. It must be called just before
    618  * emitting the @mount_added signal.
    619  *
    620  * If the return value is not %NULL, the caller must associate the
    621  * returned #GVolume object with the #GMount. This involves returning
    622  * it in its g_mount_get_volume() implementation. The caller must
    623  * also listen for the "removed" signal on the returned object
    624  * and give up its reference when handling that signal
    625  *
    626  * Similary, if implementing g_volume_monitor_adopt_orphan_mount(),
    627  * the implementor must take a reference to @mount and return it in
    628  * its g_volume_get_mount() implemented. Also, the implementor must
    629  * listen for the "unmounted" signal on @mount and give up its
    630  * reference upon handling that signal.
    631  *
    632  * There are two main use cases for this function.
    633  *
    634  * One is when implementing a user space file system driver that reads
    635  * blocks of a block device that is already represented by the native
    636  * volume monitor (for example a CD Audio file system driver). Such
    637  * a driver will generate its own #GMount object that needs to be
    638  * assoicated with the #GVolume object that represents the volume.
    639  *
    640  * The other is for implementing a #GVolumeMonitor whose sole purpose
    641  * is to return #GVolume objects representing entries in the users
    642  * "favorite servers" list or similar.
    643  *
    644  * Returns: the #GVolume object that is the parent for @mount or %NULL
    645  * if no wants to adopt the #GMount.
    646  *
    647  * Deprecated: 2.20: Instead of using this function, #GVolumeMonitor
    648  * implementations should instead create shadow mounts with the URI of
    649  * the mount they intend to adopt. See the proxy volume monitor in
    650  * gvfs for an example of this. Also see g_mount_is_shadowed(),
    651  * g_mount_shadow() and g_mount_unshadow() functions.
    652  */
    653 GVolume *
    654 g_volume_monitor_adopt_orphan_mount (GMount *mount)
    655 {
    656   GVolumeMonitor *child_monitor;
    657   GVolumeMonitorClass *child_monitor_class;
    658   GVolume *volume;
    659   GList *l;
    660 
    661   g_return_val_if_fail (mount != NULL, NULL);
    662 
    663   if (the_volume_monitor == NULL)
    664     return NULL;
    665 
    666   volume = NULL;
    667 
    668   g_static_rec_mutex_lock (&the_volume_monitor_mutex);
    669 
    670   for (l = the_volume_monitor->monitors; l != NULL; l = l->next)
    671     {
    672       child_monitor = l->data;
    673       child_monitor_class = G_VOLUME_MONITOR_GET_CLASS (child_monitor);
    674 
    675       if (child_monitor_class->adopt_orphan_mount != NULL)
    676         {
    677           volume = child_monitor_class->adopt_orphan_mount (mount, child_monitor);
    678           if (volume != NULL)
    679             break;
    680         }
    681     }
    682 
    683   g_static_rec_mutex_unlock (&the_volume_monitor_mutex);
    684 
    685   return volume;
    686 }
    687 
    688 
    689 #define __G_UNION_VOLUME_MONITOR_C__
    690 #include "gioaliasdef.c"
    691