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