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-2008 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 "gmount.h"
     31 #include "gmountprivate.h"
     32 #include "gasyncresult.h"
     33 #include "gsimpleasyncresult.h"
     34 #include "gioerror.h"
     35 #include "glibintl.h"
     36 
     37 #include "gioalias.h"
     38 
     39 /**
     40  * SECTION:gmount
     41  * @short_description: Mount management
     42  * @include: gio/gio.h
     43  * @see also: GVolume, GUnixMount
     44  *
     45  * The #GMount interface represents user-visible mounts. Note, when
     46  * porting from GnomeVFS, #GMount is the moral equivalent of #GnomeVFSVolume.
     47  *
     48  * #GMount is a "mounted" filesystem that you can access. Mounted is in
     49  * quotes because it's not the same as a unix mount, it might be a gvfs
     50  * mount, but you can still access the files on it if you use GIO. Might or
     51  * might not be related to a volume object.
     52  *
     53  * Unmounting a #GMount instance is an asynchronous operation. For
     54  * more information about asynchronous operations, see #GAsyncReady
     55  * and #GSimpleAsyncReady. To unmount a #GMount instance, first call
     56  * g_mount_unmount() with (at least) the #GMount instance and a
     57  * #GAsyncReadyCallback.  The callback will be fired when the
     58  * operation has resolved (either with success or failure), and a
     59  * #GAsyncReady structure will be passed to the callback.  That
     60  * callback should then call g_mount_unmount_finish() with the #GMount
     61  * and the #GAsyncReady data to see if the operation was completed
     62  * successfully.  If an @error is present when g_mount_unmount_finish()
     63  * is called, then it will be filled with any error information.
     64  **/
     65 
     66 static void g_mount_base_init (gpointer g_class);
     67 static void g_mount_class_init (gpointer g_class,
     68                                 gpointer class_data);
     69 
     70 GType
     71 g_mount_get_type (void)
     72 {
     73   static volatile gsize g_define_type_id__volatile = 0;
     74 
     75   if (g_once_init_enter (&g_define_type_id__volatile))
     76     {
     77       const GTypeInfo mount_info =
     78       {
     79         sizeof (GMountIface), /* class_size */
     80 	g_mount_base_init,   /* base_init */
     81 	NULL,		/* base_finalize */
     82 	g_mount_class_init,
     83 	NULL,		/* class_finalize */
     84 	NULL,		/* class_data */
     85 	0,
     86 	0,              /* n_preallocs */
     87 	NULL
     88       };
     89       GType g_define_type_id =
     90 	g_type_register_static (G_TYPE_INTERFACE, I_("GMount"),
     91 				&mount_info, 0);
     92 
     93       g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_OBJECT);
     94 
     95       g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
     96     }
     97 
     98   return g_define_type_id__volatile;
     99 }
    100 
    101 static void
    102 g_mount_class_init (gpointer g_class,
    103                     gpointer class_data)
    104 {
    105 }
    106 
    107 static void
    108 g_mount_base_init (gpointer g_class)
    109 {
    110   static gboolean initialized = FALSE;
    111 
    112   if (! initialized)
    113     {
    114      /**
    115       * GMount::changed:
    116       * @mount: the object on which the signal is emitted
    117       *
    118       * Emitted when the mount has been changed.
    119       **/
    120       g_signal_new (I_("changed"),
    121                     G_TYPE_MOUNT,
    122                     G_SIGNAL_RUN_LAST,
    123                     G_STRUCT_OFFSET (GMountIface, changed),
    124                     NULL, NULL,
    125                     g_cclosure_marshal_VOID__VOID,
    126                     G_TYPE_NONE, 0);
    127 
    128      /**
    129       * GMount::unmounted:
    130       * @mount: the object on which the signal is emitted
    131       *
    132       * This signal is emitted when the #GMount have been
    133       * unmounted. If the recipient is holding references to the
    134       * object they should release them so the object can be
    135       * finalized.
    136       **/
    137       g_signal_new (I_("unmounted"),
    138                     G_TYPE_MOUNT,
    139                     G_SIGNAL_RUN_LAST,
    140                     G_STRUCT_OFFSET (GMountIface, unmounted),
    141                     NULL, NULL,
    142                     g_cclosure_marshal_VOID__VOID,
    143                     G_TYPE_NONE, 0);
    144 
    145       initialized = TRUE;
    146     }
    147 }
    148 
    149 /**
    150  * g_mount_get_root:
    151  * @mount: a #GMount.
    152  *
    153  * Gets the root directory on @mount.
    154  *
    155  * Returns: a #GFile.
    156  *      The returned object should be unreffed with
    157  *      g_object_unref() when no longer needed.
    158  **/
    159 GFile *
    160 g_mount_get_root (GMount *mount)
    161 {
    162   GMountIface *iface;
    163 
    164   g_return_val_if_fail (G_IS_MOUNT (mount), NULL);
    165 
    166   iface = G_MOUNT_GET_IFACE (mount);
    167 
    168   return (* iface->get_root) (mount);
    169 }
    170 
    171 /**
    172  * g_mount_get_name:
    173  * @mount: a #GMount.
    174  *
    175  * Gets the name of @mount.
    176  *
    177  * Returns: the name for the given @mount.
    178  *     The returned string should be freed with g_free()
    179  *     when no longer needed.
    180  **/
    181 char *
    182 g_mount_get_name (GMount *mount)
    183 {
    184   GMountIface *iface;
    185 
    186   g_return_val_if_fail (G_IS_MOUNT (mount), NULL);
    187 
    188   iface = G_MOUNT_GET_IFACE (mount);
    189 
    190   return (* iface->get_name) (mount);
    191 }
    192 
    193 /**
    194  * g_mount_get_icon:
    195  * @mount: a #GMount.
    196  *
    197  * Gets the icon for @mount.
    198  *
    199  * Returns: a #GIcon.
    200  *      The returned object should be unreffed with
    201  *      g_object_unref() when no longer needed.
    202  **/
    203 GIcon *
    204 g_mount_get_icon (GMount *mount)
    205 {
    206   GMountIface *iface;
    207 
    208   g_return_val_if_fail (G_IS_MOUNT (mount), NULL);
    209 
    210   iface = G_MOUNT_GET_IFACE (mount);
    211 
    212   return (* iface->get_icon) (mount);
    213 }
    214 
    215 /**
    216  * g_mount_get_uuid:
    217  * @mount: a #GMount.
    218  *
    219  * Gets the UUID for the @mount. The reference is typically based on
    220  * the file system UUID for the mount in question and should be
    221  * considered an opaque string. Returns %NULL if there is no UUID
    222  * available.
    223  *
    224  * Returns: the UUID for @mount or %NULL if no UUID can be computed.
    225  *     The returned string should be freed with g_free()
    226  *     when no longer needed.
    227  **/
    228 char *
    229 g_mount_get_uuid (GMount *mount)
    230 {
    231   GMountIface *iface;
    232 
    233   g_return_val_if_fail (G_IS_MOUNT (mount), NULL);
    234 
    235   iface = G_MOUNT_GET_IFACE (mount);
    236 
    237   return (* iface->get_uuid) (mount);
    238 }
    239 
    240 /**
    241  * g_mount_get_volume:
    242  * @mount: a #GMount.
    243  *
    244  * Gets the volume for the @mount.
    245  *
    246  * Returns: a #GVolume or %NULL if @mount is not associated with a volume.
    247  *      The returned object should be unreffed with
    248  *      g_object_unref() when no longer needed.
    249  **/
    250 GVolume *
    251 g_mount_get_volume (GMount *mount)
    252 {
    253   GMountIface *iface;
    254 
    255   g_return_val_if_fail (G_IS_MOUNT (mount), NULL);
    256 
    257   iface = G_MOUNT_GET_IFACE (mount);
    258 
    259   return (* iface->get_volume) (mount);
    260 }
    261 
    262 /**
    263  * g_mount_get_drive:
    264  * @mount: a #GMount.
    265  *
    266  * Gets the drive for the @mount.
    267  *
    268  * This is a convenience method for getting the #GVolume and then
    269  * using that object to get the #GDrive.
    270  *
    271  * Returns: a #GDrive or %NULL if @mount is not associated with a volume or a drive.
    272  *      The returned object should be unreffed with
    273  *      g_object_unref() when no longer needed.
    274  **/
    275 GDrive *
    276 g_mount_get_drive (GMount *mount)
    277 {
    278   GMountIface *iface;
    279 
    280   g_return_val_if_fail (G_IS_MOUNT (mount), NULL);
    281 
    282   iface = G_MOUNT_GET_IFACE (mount);
    283 
    284   return (* iface->get_drive) (mount);
    285 }
    286 
    287 /**
    288  * g_mount_can_unmount:
    289  * @mount: a #GMount.
    290  *
    291  * Checks if @mount can be mounted.
    292  *
    293  * Returns: %TRUE if the @mount can be unmounted.
    294  **/
    295 gboolean
    296 g_mount_can_unmount (GMount *mount)
    297 {
    298   GMountIface *iface;
    299 
    300   g_return_val_if_fail (G_IS_MOUNT (mount), FALSE);
    301 
    302   iface = G_MOUNT_GET_IFACE (mount);
    303 
    304   return (* iface->can_unmount) (mount);
    305 }
    306 
    307 /**
    308  * g_mount_can_eject:
    309  * @mount: a #GMount.
    310  *
    311  * Checks if @mount can be eject.
    312  *
    313  * Returns: %TRUE if the @mount can be ejected.
    314  **/
    315 gboolean
    316 g_mount_can_eject (GMount *mount)
    317 {
    318   GMountIface *iface;
    319 
    320   g_return_val_if_fail (G_IS_MOUNT (mount), FALSE);
    321 
    322   iface = G_MOUNT_GET_IFACE (mount);
    323 
    324   return (* iface->can_eject) (mount);
    325 }
    326 
    327 /**
    328  * g_mount_unmount:
    329  * @mount: a #GMount.
    330  * @flags: flags affecting the operation
    331  * @cancellable: optional #GCancellable object, %NULL to ignore.
    332  * @callback: a #GAsyncReadyCallback, or %NULL.
    333  * @user_data: user data passed to @callback.
    334  *
    335  * Unmounts a mount. This is an asynchronous operation, and is
    336  * finished by calling g_mount_unmount_finish() with the @mount
    337  * and #GAsyncResult data returned in the @callback.
    338  **/
    339 void
    340 g_mount_unmount (GMount              *mount,
    341                  GMountUnmountFlags   flags,
    342                  GCancellable        *cancellable,
    343                  GAsyncReadyCallback  callback,
    344                  gpointer             user_data)
    345 {
    346   GMountIface *iface;
    347 
    348   g_return_if_fail (G_IS_MOUNT (mount));
    349 
    350   iface = G_MOUNT_GET_IFACE (mount);
    351 
    352   if (iface->unmount == NULL)
    353     {
    354       g_simple_async_report_error_in_idle (G_OBJECT (mount),
    355 					   callback, user_data,
    356 					   G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
    357 					   /* Translators: This is an error
    358 					    * message for mount objects that
    359 					    * don't implement unmount. */
    360 					   _("mount doesn't implement unmount"));
    361 
    362       return;
    363     }
    364 
    365   (* iface->unmount) (mount, flags, cancellable, callback, user_data);
    366 }
    367 
    368 /**
    369  * g_mount_unmount_finish:
    370  * @mount: a #GMount.
    371  * @result: a #GAsyncResult.
    372  * @error: a #GError location to store the error occuring, or %NULL to
    373  *     ignore.
    374  *
    375  * Finishes unmounting a mount. If any errors occurred during the operation,
    376  * @error will be set to contain the errors and %FALSE will be returned.
    377  *
    378  * Returns: %TRUE if the mount was successfully unmounted. %FALSE otherwise.
    379  **/
    380 gboolean
    381 g_mount_unmount_finish (GMount        *mount,
    382                         GAsyncResult  *result,
    383                         GError       **error)
    384 {
    385   GMountIface *iface;
    386 
    387   g_return_val_if_fail (G_IS_MOUNT (mount), FALSE);
    388   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
    389 
    390   if (G_IS_SIMPLE_ASYNC_RESULT (result))
    391     {
    392       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
    393       if (g_simple_async_result_propagate_error (simple, error))
    394         return FALSE;
    395     }
    396 
    397   iface = G_MOUNT_GET_IFACE (mount);
    398   return (* iface->unmount_finish) (mount, result, error);
    399 }
    400 
    401 
    402 /**
    403  * g_mount_eject:
    404  * @mount: a #GMount.
    405  * @flags: flags affecting the unmount if required for eject
    406  * @cancellable: optional #GCancellable object, %NULL to ignore.
    407  * @callback: a #GAsyncReadyCallback, or %NULL.
    408  * @user_data: user data passed to @callback.
    409  *
    410  * Ejects a mount. This is an asynchronous operation, and is
    411  * finished by calling g_mount_eject_finish() with the @mount
    412  * and #GAsyncResult data returned in the @callback.
    413  **/
    414 void
    415 g_mount_eject (GMount              *mount,
    416                GMountUnmountFlags   flags,
    417                GCancellable        *cancellable,
    418                GAsyncReadyCallback  callback,
    419                gpointer             user_data)
    420 {
    421   GMountIface *iface;
    422 
    423   g_return_if_fail (G_IS_MOUNT (mount));
    424 
    425   iface = G_MOUNT_GET_IFACE (mount);
    426 
    427   if (iface->eject == NULL)
    428     {
    429       g_simple_async_report_error_in_idle (G_OBJECT (mount),
    430 					   callback, user_data,
    431 					   G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
    432 					   /* Translators: This is an error
    433 					    * message for mount objects that
    434 					    * don't implement eject. */
    435 					   _("mount doesn't implement eject"));
    436 
    437       return;
    438     }
    439 
    440   (* iface->eject) (mount, flags, cancellable, callback, user_data);
    441 }
    442 
    443 /**
    444  * g_mount_eject_finish:
    445  * @mount: a #GMount.
    446  * @result: a #GAsyncResult.
    447  * @error: a #GError location to store the error occuring, or %NULL to
    448  *     ignore.
    449  *
    450  * Finishes ejecting a mount. If any errors occurred during the operation,
    451  * @error will be set to contain the errors and %FALSE will be returned.
    452  *
    453  * Returns: %TRUE if the mount was successfully ejected. %FALSE otherwise.
    454  **/
    455 gboolean
    456 g_mount_eject_finish (GMount        *mount,
    457                       GAsyncResult  *result,
    458                       GError       **error)
    459 {
    460   GMountIface *iface;
    461 
    462   g_return_val_if_fail (G_IS_MOUNT (mount), FALSE);
    463   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
    464 
    465   if (G_IS_SIMPLE_ASYNC_RESULT (result))
    466     {
    467       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
    468       if (g_simple_async_result_propagate_error (simple, error))
    469         return FALSE;
    470     }
    471 
    472   iface = G_MOUNT_GET_IFACE (mount);
    473   return (* iface->eject_finish) (mount, result, error);
    474 }
    475 
    476 /**
    477  * g_mount_remount:
    478  * @mount: a #GMount.
    479  * @flags: flags affecting the operation
    480  * @mount_operation: a #GMountOperation or %NULL to avoid user interaction.
    481  * @cancellable: optional #GCancellable object, %NULL to ignore.
    482  * @callback: a #GAsyncReadyCallback, or %NULL.
    483  * @user_data: user data passed to @callback.
    484  *
    485  * Remounts a mount. This is an asynchronous operation, and is
    486  * finished by calling g_mount_remount_finish() with the @mount
    487  * and #GAsyncResults data returned in the @callback.
    488  *
    489  * Remounting is useful when some setting affecting the operation
    490  * of the volume has been changed, as these may need a remount to
    491  * take affect. While this is semantically equivalent with unmounting
    492  * and then remounting not all backends might need to actually be
    493  * unmounted.
    494  **/
    495 void
    496 g_mount_remount (GMount              *mount,
    497                  GMountMountFlags     flags,
    498                  GMountOperation     *mount_operation,
    499                  GCancellable        *cancellable,
    500                  GAsyncReadyCallback  callback,
    501                  gpointer             user_data)
    502 {
    503   GMountIface *iface;
    504 
    505   g_return_if_fail (G_IS_MOUNT (mount));
    506 
    507   iface = G_MOUNT_GET_IFACE (mount);
    508 
    509   if (iface->remount == NULL)
    510     {
    511       g_simple_async_report_error_in_idle (G_OBJECT (mount),
    512 					   callback, user_data,
    513 					   G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
    514 					   /* Translators: This is an error
    515 					    * message for mount objects that
    516 					    * don't implement remount. */
    517 					   _("mount doesn't implement remount"));
    518 
    519       return;
    520     }
    521 
    522   (* iface->remount) (mount, flags, mount_operation, cancellable, callback, user_data);
    523 }
    524 
    525 /**
    526  * g_mount_remount_finish:
    527  * @mount: a #GMount.
    528  * @result: a #GAsyncResult.
    529  * @error: a #GError location to store the error occuring, or %NULL to
    530  *     ignore.
    531  *
    532  * Finishes remounting a mount. If any errors occurred during the operation,
    533  * @error will be set to contain the errors and %FALSE will be returned.
    534  *
    535  * Returns: %TRUE if the mount was successfully remounted. %FALSE otherwise.
    536  **/
    537 gboolean
    538 g_mount_remount_finish (GMount        *mount,
    539                         GAsyncResult  *result,
    540                         GError       **error)
    541 {
    542   GMountIface *iface;
    543 
    544   g_return_val_if_fail (G_IS_MOUNT (mount), FALSE);
    545   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
    546 
    547   if (G_IS_SIMPLE_ASYNC_RESULT (result))
    548     {
    549       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
    550       if (g_simple_async_result_propagate_error (simple, error))
    551         return FALSE;
    552     }
    553 
    554   iface = G_MOUNT_GET_IFACE (mount);
    555   return (* iface->remount_finish) (mount, result, error);
    556 }
    557 
    558 /**
    559  * g_mount_guess_content_type:
    560  * @mount: a #GMount
    561  * @force_rescan: Whether to force a rescan of the content.
    562  *     Otherwise a cached result will be used if available
    563  * @cancellable: optional #GCancellable object, %NULL to ignore
    564  * @callback: a #GAsyncReadyCallback
    565  * @user_data: user data passed to @callback
    566  *
    567  * Tries to guess the type of content stored on @mount. Returns one or
    568  * more textual identifiers of well-known content types (typically
    569  * prefixed with "x-content/"), e.g. x-content/image-dcf for camera
    570  * memory cards. See the <ulink url="http://www.freedesktop.org/wiki/Specifications/shared-mime-info-spec">shared-mime-info</ulink>
    571  * specification for more on x-content types.
    572  *
    573  * This is an asynchronous operation (see
    574  * g_mount_guess_content_type_sync() for the synchronous version), and
    575  * is finished by calling g_mount_guess_content_type_finish() with the
    576  * @mount and #GAsyncResult data returned in the @callback.
    577  *
    578  * Since: 2.18
    579  */
    580 void
    581 g_mount_guess_content_type (GMount              *mount,
    582                             gboolean             force_rescan,
    583                             GCancellable        *cancellable,
    584                             GAsyncReadyCallback  callback,
    585                             gpointer             user_data)
    586 {
    587   GMountIface *iface;
    588 
    589   g_return_if_fail (G_IS_MOUNT (mount));
    590 
    591   iface = G_MOUNT_GET_IFACE (mount);
    592 
    593   if (iface->guess_content_type == NULL)
    594     {
    595       g_simple_async_report_error_in_idle (G_OBJECT (mount),
    596                                            callback, user_data,
    597                                            G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
    598                                            /* Translators: This is an error
    599                                             * message for mount objects that
    600                                             * don't implement content type guessing. */
    601                                            _("mount doesn't implement content type guessing"));
    602 
    603       return;
    604     }
    605 
    606   (* iface->guess_content_type) (mount, force_rescan, cancellable, callback, user_data);
    607 }
    608 
    609 /**
    610  * g_mount_guess_content_type_finish:
    611  * @mount: a #GMount
    612  * @result: a #GAsyncResult
    613  * @error: a #GError location to store the error occuring, or %NULL to
    614  *     ignore
    615  *
    616  * Finishes guessing content types of @mount. If any errors occured
    617  * during the operation, @error will be set to contain the errors and
    618  * %FALSE will be returned. In particular, you may get an
    619  * %G_IO_ERROR_NOT_SUPPORTED if the mount does not support content
    620  * guessing.
    621  *
    622  * Returns: a %NULL-terminated array of content types or %NULL on error.
    623  *     Caller should free this array with g_strfreev() when done with it.
    624  *
    625  * Since: 2.18
    626  **/
    627 gchar **
    628 g_mount_guess_content_type_finish (GMount        *mount,
    629                                    GAsyncResult  *result,
    630                                    GError       **error)
    631 {
    632   GMountIface *iface;
    633 
    634   g_return_val_if_fail (G_IS_MOUNT (mount), FALSE);
    635   g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
    636 
    637   if (G_IS_SIMPLE_ASYNC_RESULT (result))
    638     {
    639       GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
    640       if (g_simple_async_result_propagate_error (simple, error))
    641         return FALSE;
    642     }
    643 
    644   iface = G_MOUNT_GET_IFACE (mount);
    645   return (* iface->guess_content_type_finish) (mount, result, error);
    646 }
    647 
    648 /**
    649  * g_mount_guess_content_type_sync:
    650  * @mount: a #GMount
    651  * @force_rescan: Whether to force a rescan of the content.
    652  *     Otherwise a cached result will be used if available
    653  * @cancellable: optional #GCancellable object, %NULL to ignore
    654  * @error: a #GError location to store the error occuring, or %NULL to
    655  *     ignore
    656  *
    657  * Tries to guess the type of content stored on @mount. Returns one or
    658  * more textual identifiers of well-known content types (typically
    659  * prefixed with "x-content/"), e.g. x-content/image-dcf for camera
    660  * memory cards. See the <ulink url="http://www.freedesktop.org/wiki/Specifications/shared-mime-info-spec">shared-mime-info</ulink>
    661  * specification for more on x-content types.
    662  *
    663  * This is an synchronous operation and as such may block doing IO;
    664  * see g_mount_guess_content_type() for the asynchronous version.
    665  *
    666  * Returns: a %NULL-terminated array of content types or %NULL on error.
    667  *     Caller should free this array with g_strfreev() when done with it.
    668  *
    669  * Since: 2.18
    670  */
    671 char **
    672 g_mount_guess_content_type_sync (GMount              *mount,
    673                                  gboolean             force_rescan,
    674                                  GCancellable        *cancellable,
    675                                  GError             **error)
    676 {
    677   GMountIface *iface;
    678 
    679   g_return_val_if_fail (G_IS_MOUNT (mount), NULL);
    680 
    681   iface = G_MOUNT_GET_IFACE (mount);
    682 
    683   if (iface->guess_content_type_sync == NULL)
    684     {
    685       g_set_error_literal (error,
    686                            G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
    687                            /* Translators: This is an error
    688                             * message for mount objects that
    689                             * don't implement content type guessing. */
    690                            _("mount doesn't implement synchronous content type guessing"));
    691 
    692       return NULL;
    693     }
    694 
    695   return (* iface->guess_content_type_sync) (mount, force_rescan, cancellable, error);
    696 }
    697 
    698 G_LOCK_DEFINE_STATIC (priv_lock);
    699 
    700 /* only access this structure when holding priv_lock */
    701 typedef struct
    702 {
    703   gint shadow_ref_count;
    704 } GMountPrivate;
    705 
    706 static void
    707 free_private (GMountPrivate *private)
    708 {
    709   G_LOCK (priv_lock);
    710   g_free (private);
    711   G_UNLOCK (priv_lock);
    712 }
    713 
    714 /* may only be called when holding priv_lock */
    715 static GMountPrivate *
    716 get_private (GMount *mount)
    717 {
    718   GMountPrivate *private;
    719 
    720   private = g_object_get_data (G_OBJECT (mount), "g-mount-private");
    721   if (G_LIKELY (private != NULL))
    722     goto out;
    723 
    724   private = g_new0 (GMountPrivate, 1);
    725   g_object_set_data_full (G_OBJECT (mount),
    726                           "g-mount-private",
    727                           private,
    728                           (GDestroyNotify) free_private);
    729 
    730  out:
    731   return private;
    732 }
    733 
    734 /**
    735  * g_mount_is_shadowed:
    736  * @mount: A #GMount.
    737  *
    738  * Determines if @mount is shadowed. Applications or libraries should
    739  * avoid displaying @mount in the user interface if it is shadowed.
    740  *
    741  * A mount is said to be shadowed if there exists one or more user
    742  * visible objects (currently #GMount objects) with a root that is
    743  * inside the root of @mount.
    744  *
    745  * One application of shadow mounts is when exposing a single file
    746  * system that is used to address several logical volumes. In this
    747  * situation, a #GVolumeMonitor implementation would create two
    748  * #GVolume objects (for example, one for the camera functionality of
    749  * the device and one for a SD card reader on the device) with
    750  * activation URIs <literal>gphoto2://[usb:001,002]/store1/</literal>
    751  * and <literal>gphoto2://[usb:001,002]/store2/</literal>. When the
    752  * underlying mount (with root
    753  * <literal>gphoto2://[usb:001,002]/</literal>) is mounted, said
    754  * #GVolumeMonitor implementation would create two #GMount objects
    755  * (each with their root matching the corresponding volume activation
    756  * root) that would shadow the original mount.
    757  *
    758  * The proxy monitor in GVfs 2.26 and later, automatically creates and
    759  * manage shadow mounts (and shadows the underlying mount) if the
    760  * activation root on a #GVolume is set.
    761  *
    762  * Returns: %TRUE if @mount is shadowed.
    763  *
    764  * Since: 2.20
    765  **/
    766 gboolean
    767 g_mount_is_shadowed (GMount *mount)
    768 {
    769   GMountPrivate *priv;
    770   gboolean ret;
    771 
    772   g_return_val_if_fail (G_IS_MOUNT (mount), FALSE);
    773 
    774   G_LOCK (priv_lock);
    775   priv = get_private (mount);
    776   ret = (priv->shadow_ref_count > 0);
    777   G_UNLOCK (priv_lock);
    778 
    779   return ret;
    780 }
    781 
    782 /**
    783  * g_mount_shadow:
    784  * @mount: A #GMount.
    785  *
    786  * Increments the shadow count on @mount. Usually used by
    787  * #GVolumeMonitor implementations when creating a shadow mount for
    788  * @mount, see g_mount_is_shadowed() for more information. The caller
    789  * will need to emit the #GMount::changed signal on @mount manually.
    790  *
    791  * Since: 2.20
    792  **/
    793 void
    794 g_mount_shadow (GMount *mount)
    795 {
    796   GMountPrivate *priv;
    797 
    798   g_return_if_fail (G_IS_MOUNT (mount));
    799 
    800   G_LOCK (priv_lock);
    801   priv = get_private (mount);
    802   priv->shadow_ref_count += 1;
    803   G_UNLOCK (priv_lock);
    804 }
    805 
    806 /**
    807  * g_mount_unshadow:
    808  * @mount: A #GMount.
    809  *
    810  * Decrements the shadow count on @mount. Usually used by
    811  * #GVolumeMonitor implementations when destroying a shadow mount for
    812  * @mount, see g_mount_is_shadowed() for more information. The caller
    813  * will need to emit the #GMount::changed signal on @mount manually.
    814  *
    815  * Since: 2.20
    816  **/
    817 void
    818 g_mount_unshadow (GMount *mount)
    819 {
    820   GMountPrivate *priv;
    821 
    822   g_return_if_fail (G_IS_MOUNT (mount));
    823 
    824   G_LOCK (priv_lock);
    825   priv = get_private (mount);
    826   priv->shadow_ref_count -= 1;
    827   if (priv->shadow_ref_count < 0)
    828     g_warning ("Shadow ref count on GMount is negative");
    829   G_UNLOCK (priv_lock);
    830 }
    831 
    832 #define __G_MOUNT_C__
    833 #include "gioaliasdef.c"
    834