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