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@redhat.com>
23 *         David Zeuthen <davidz@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
66static void g_mount_base_init (gpointer g_class);
67static void g_mount_class_init (gpointer g_class,
68                                gpointer class_data);
69
70GType
71g_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
101static void
102g_mount_class_init (gpointer g_class,
103                    gpointer class_data)
104{
105}
106
107static void
108g_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 **/
159GFile *
160g_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 **/
181char *
182g_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 **/
203GIcon *
204g_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 **/
228char *
229g_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 **/
250GVolume *
251g_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 **/
275GDrive *
276g_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 **/
295gboolean
296g_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 **/
315gboolean
316g_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 **/
339void
340g_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 **/
380gboolean
381g_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 **/
414void
415g_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 **/
455gboolean
456g_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 **/
495void
496g_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 **/
537gboolean
538g_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 */
580void
581g_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 **/
627gchar **
628g_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 */
671char **
672g_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
698G_LOCK_DEFINE_STATIC (priv_lock);
699
700/* only access this structure when holding priv_lock */
701typedef struct
702{
703  gint shadow_ref_count;
704} GMountPrivate;
705
706static void
707free_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 */
715static GMountPrivate *
716get_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 **/
766gboolean
767g_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 **/
793void
794g_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 **/
817void
818g_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