1/* 2 * Copyright (c) 1998-2013 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include "DARequest.h" 25 26#include "DABase.h" 27#include "DACallback.h" 28#include "DADialog.h" 29#include "DADissenter.h" 30#include "DAFileSystem.h" 31#include "DALog.h" 32#include "DAMain.h" 33#include "DAMount.h" 34#include "DAPrivate.h" 35#include "DAQueue.h" 36#include "DAStage.h" 37#include "DASupport.h" 38#include "DAThread.h" 39 40#include <fcntl.h> 41#include <libproc.h> 42#include <unistd.h> 43#include <sys/disk.h> 44#include <DiskArbitration/DiskArbitration.h> 45 46static void __DARequestClaimCallback( int status, void * context ); 47static void __DARequestClaimReleaseCallback( CFTypeRef response, void * context ); 48static void __DARequestEjectCallback( int status, void * context ); 49static void __DARequestEjectApprovalCallback( CFTypeRef response, void * context ); 50static int __DARequestEjectEject( void * context ); 51static void __DARequestMountCallback( int status, CFURLRef mountpoint, void * context ); 52static void __DARequestMountApprovalCallback( CFTypeRef response, void * context ); 53static void __DARequestProbeCallback( int status, void * context ); 54static void __DARequestRefreshCallback( int status, void * context ); 55static void __DARequestRenameCallback( int status, void * context ); 56static void __DARequestUnmountCallback( int status, void * context ); 57static void __DARequestUnmountApprovalCallback( CFTypeRef response, void * context ); 58static int __DARequestUnmountGetProcessID( void * context ); 59///w:start 60static void __DARequestMountAuthorizationCallback( DAReturn status, void * context ); 61static int __DARequestUnmountTickle( void * context ); 62static void __DARequestUnmountTickleCallback( int status, void * context ); 63 64static void __DARequestAuthorize( DARequestRef request, 65 DAAuthorizeCallback callback, 66 void * callbackContext, 67 const char * right ) 68{ 69 DASessionRef session; 70 CFArrayRef sessionList; 71 CFIndex sessionListCount; 72 CFIndex sessionListIndex; 73 74 sessionList = gDASessionList; 75 sessionListCount = CFArrayGetCount( sessionList ); 76 77 for ( sessionListIndex = 0; sessionListIndex < sessionListCount; sessionListIndex++ ) 78 { 79 session = ( void * ) CFArrayGetValueAtIndex( sessionList, sessionListIndex ); 80 81 if ( strcmp( _DASessionGetName( session ), "SystemUIServer" ) == 0 ) 82 { 83 break; 84 } 85 } 86 87 if ( sessionListIndex < sessionListCount ) 88 { 89 DAAuthorizeWithCallback( session, 90 _kDAAuthorizeOptionAuthenticateAdministrator, 91 DARequestGetDisk( request ), 92 DARequestGetUserUID( request ), 93 DARequestGetUserGID( request ), 94 callback, 95 callbackContext, 96 right ); 97 } 98 else 99 { 100 ( callback )( kDAReturnNotPrivileged, callbackContext ); 101 } 102} 103///w:stop 104static void __DARequestDispatchCallback( DARequestRef request, DADissenterRef dissenter ) 105{ 106 DACallbackRef callback; 107 108 callback = DARequestGetCallback( request ); 109 110 if ( callback ) 111 { 112 CFArrayRef link; 113 114 link = DARequestGetLink( request ); 115 116 if ( link ) 117 { 118 dissenter = DARequestGetDissenter( request ); 119 120 if ( dissenter == NULL ) 121 { 122 CFIndex count; 123 CFIndex index; 124 125 count = CFArrayGetCount( link ); 126 127 for ( index = 0; index < count; index++ ) 128 { 129 DARequestRef subrequest; 130 131 subrequest = ( void * ) CFArrayGetValueAtIndex( link, index ); 132 133 dissenter = DARequestGetDissenter( subrequest ); 134 135 if ( dissenter ) break; 136 } 137 } 138 } 139 140 DAQueueCallback( callback, DARequestGetDisk( request ), dissenter ); 141 } 142} 143 144static Boolean __DARequestClaim( DARequestRef request ) 145{ 146 DADiskRef disk; 147 148 disk = DARequestGetDisk( request ); 149 150 /* 151 * Commence the claim release. 152 */ 153 154 if ( DARequestGetState( request, kDARequestStateStagedApprove ) == FALSE ) 155 { 156 DACallbackRef callback; 157 158 callback = DADiskGetClaim( disk ); 159 160 CFRetain( request ); 161 162 DADiskSetState( disk, kDADiskStateCommandActive, TRUE ); 163 164 DARequestSetState( request, kDARequestStateStagedApprove, TRUE ); 165 166 if ( callback ) 167 { 168 if ( DACallbackGetAddress( callback ) ) 169 { 170 DADiskClaimReleaseCallback( disk, callback, __DARequestClaimReleaseCallback, request ); 171 } 172 else 173 { 174 DADissenterRef dissenter; 175 176 dissenter = DADissenterCreate( kCFAllocatorDefault, kDAReturnNotPermitted ); 177 178 __DARequestClaimReleaseCallback( dissenter, request ); 179 180 CFRelease( dissenter ); 181 } 182 } 183 else 184 { 185 __DARequestClaimReleaseCallback( NULL, request ); 186 } 187 188 return FALSE; 189 } 190 191 if ( DARequestGetDissenter( request ) ) 192 { 193 DADissenterRef dissenter; 194 195 dissenter = DARequestGetDissenter( request ); 196 197 __DARequestDispatchCallback( request, dissenter ); 198 199 DAStageSignal( ); 200 201 return TRUE; 202 } 203 204 /* 205 * Commence the claim. 206 */ 207 208 { 209 DACallbackRef callback; 210 211 CFRetain( request ); 212 213 DADiskSetState( disk, kDADiskStateCommandActive, TRUE ); 214 215 DADiskSetClaim( disk, NULL ); 216 217 callback = DARequestGetCallback( request ); 218 219 if ( callback ) 220 { 221 DASessionRef session; 222 223 session = DACallbackGetSession( callback ); 224 225 if ( session ) 226 { 227 mach_vm_offset_t address; 228 mach_vm_offset_t context; 229 230 address = ___CFNumberGetIntegerValue( DARequestGetArgument2( request ) ); 231 context = ___CFNumberGetIntegerValue( DARequestGetArgument3( request ) ); 232 233 callback = DACallbackCreate( kCFAllocatorDefault, session, address, context, _kDADiskClaimReleaseCallback, 0, NULL, NULL ); 234 235 if ( callback ) 236 { 237 DADiskSetClaim( disk, callback ); 238 239 CFRelease( callback ); 240 } 241 } 242 } 243 244 __DARequestClaimCallback( 0, request ); 245 246 return TRUE; 247 } 248} 249 250static void __DARequestClaimCallback( int status, void * context ) 251{ 252 DADiskRef disk; 253 DARequestRef request = context; 254 255 DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID ); 256 257 disk = DARequestGetDisk( request ); 258 259 DALogDebug( " claimed disk, id = %@, success.", disk ); 260 261 DARequestDispatchCallback( request, status ? unix_err( status ) : status ); 262 263 DADiskSetState( disk, kDADiskStateCommandActive, FALSE ); 264 265 DAStageSignal( ); 266 267 CFRelease( request ); 268} 269 270static void __DARequestClaimReleaseCallback( CFTypeRef response, void * context ) 271{ 272 DARequestRef request = context; 273 274 DARequestSetDissenter( request, response ); 275 276 DADiskSetState( DARequestGetDisk( request ), kDADiskStateCommandActive, FALSE ); 277 278 DAStageSignal( ); 279 280 CFRelease( request ); 281} 282 283static Boolean __DARequestEject( DARequestRef request ) 284{ 285 DADiskRef disk; 286 287 DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID ); 288 289 disk = DARequestGetDisk( request ); 290 291 /* 292 * Commence the eject approval. 293 */ 294 295 if ( DARequestGetState( request, kDARequestStateStagedApprove ) == FALSE ) 296 { 297 DAReturn status; 298 299 status = kDAReturnSuccess; 300 301 /* 302 * Determine whether the disk is ejectable. 303 */ 304 305 if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWholeKey ) == NULL ) 306 { 307 status = kDAReturnUnsupported; 308 } 309 310 if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWholeKey ) == kCFBooleanFalse ) 311 { 312 status = kDAReturnUnsupported; 313 } 314 315 if ( status ) 316 { 317 DARequestDispatchCallback( request, status ); 318 319 DAStageSignal( ); 320 321 return TRUE; 322 } 323 else 324 { 325 CFRetain( request ); 326 327 DADiskSetState( disk, kDADiskStateCommandActive, TRUE ); 328 329 DARequestSetState( request, kDARequestStateStagedApprove, TRUE ); 330 331 DADiskEjectApprovalCallback( disk, __DARequestEjectApprovalCallback, request ); 332 333 return FALSE; 334 } 335 } 336 337 if ( DARequestGetDissenter( request ) ) 338 { 339 DADissenterRef dissenter; 340 341 dissenter = DARequestGetDissenter( request ); 342 343 __DARequestDispatchCallback( request, dissenter ); 344 345 DAStageSignal( ); 346 347 return TRUE; 348 } 349 350 /* 351 * Commence the eject. 352 */ 353 354 if ( DAUnitGetState( disk, kDAUnitStateCommandActive ) == FALSE ) 355 { 356 CFRetain( request ); 357 358 DADiskSetState( disk, kDADiskStateCommandActive, TRUE ); 359 360 DAUnitSetState( disk, kDAUnitStateCommandActive, TRUE ); 361 362 DALogDebug( " ejected disk, id = %@, ongoing.", disk ); 363 364 DAThreadExecute( __DARequestEjectEject, disk, __DARequestEjectCallback, request ); 365 366 return TRUE; 367 } 368 else 369 { 370 return FALSE; 371 } 372} 373 374static void __DARequestEjectCallback( int status, void * context ) 375{ 376 DADiskRef disk; 377 DARequestRef request = context; 378 379 DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID ); 380 381 disk = DARequestGetDisk( request ); 382 383 if ( status ) 384 { 385 /* 386 * We were unable to eject the disk. 387 */ 388 389 DADissenterRef dissenter; 390 391 DALogDebug( " ejected disk, id = %@, failure.", disk ); 392 393 DALogDebug( "unable to eject %@ (status code 0x%08X).", disk, status ); 394 395 dissenter = DADissenterCreate( kCFAllocatorDefault, unix_err( status ) ); 396 397 DARequestSetDissenter( request, dissenter ); 398 399 CFRelease( dissenter ); 400 } 401 else 402 { 403 /* 404 * We were able to eject the disk. 405 */ 406 407 DALogDebug( " ejected disk, id = %@, success.", disk ); 408 } 409 410 DARequestDispatchCallback( request, status ? unix_err( status ) : status ); 411 412 DAUnitSetState( disk, kDAUnitStateCommandActive, FALSE ); 413 414 DADiskSetState( disk, kDADiskStateCommandActive, FALSE ); 415 416 DAStageSignal( ); 417 418 CFRelease( request ); 419} 420 421static void __DARequestEjectApprovalCallback( CFTypeRef response, void * context ) 422{ 423 DARequestRef request = context; 424 425 DARequestSetDissenter( request, response ); 426 427 DADiskSetState( DARequestGetDisk( request ), kDADiskStateCommandActive, FALSE ); 428 429 DAStageSignal( ); 430 431 CFRelease( request ); 432} 433 434static int __DARequestEjectEject( void * context ) 435{ 436 DADiskRef disk = context; 437 int file; 438 int status; 439 440 file = open( DADiskGetBSDPath( disk, TRUE ), O_RDONLY ); 441 442 if ( file == -1 ) 443 { 444 status = errno; 445 } 446 else 447 { 448 status = ioctl( file, DKIOCEJECT, NULL ); 449 450 if ( status == -1 ) 451 { 452 status = ( errno == ENOTTY ) ? 0 : errno; 453 } 454 455 close( file ); 456 } 457 458 return status; 459} 460 461static Boolean __DARequestMount( DARequestRef request ) 462{ 463 DADiskRef disk; 464 465 disk = DARequestGetDisk( request ); 466 467 if ( DARequestGetLink( request ) ) 468 { 469 if ( DAUnitGetState( disk, kDAUnitStateCommandActive ) ) 470 { 471 return FALSE; 472 } 473 } 474 475 /* 476 * Commence the probe. 477 */ 478 479 if ( DARequestGetState( request, kDARequestStateStagedProbe ) == FALSE ) 480 { 481 /* 482 * Determine whether the disk is probeable. 483 */ 484 485 if ( DADiskGetDescription( disk, kDADiskDescriptionMediaPathKey ) == NULL ) 486 { 487 DARequestDispatchCallback( request, kDAReturnUnsupported ); 488 489 DAStageSignal( ); 490 491 return TRUE; 492 } 493 494 /* 495 * Determine whether the disk is mounted. 496 */ 497 498 if ( DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ) == NULL ) 499 { 500 DARequestSetState( request, kDARequestStateStagedProbe, TRUE ); 501 502 DADiskSetState( disk, kDADiskStateStagedProbe, FALSE ); 503 504 DAStageSignal( ); 505 506 return FALSE; 507 } 508 } 509 else 510 { 511 if ( DADiskGetState( disk, kDADiskStateStagedProbe ) == FALSE ) 512 { 513 return FALSE; 514 } 515 } 516 517 /* 518 * Commence the mount approval. 519 */ 520 521 if ( DARequestGetState( request, kDARequestStateStagedApprove ) == FALSE ) 522 { 523 DAReturn status; 524 525 status = kDAReturnSuccess; 526 527 /* 528 * Determine whether the disk is mountable. 529 */ 530 531 if ( DADiskGetDescription( disk, kDADiskDescriptionVolumeMountableKey ) == kCFBooleanFalse ) 532 { 533 status = kDAReturnUnsupported; 534 } 535 536 /* 537 * Determine whether the disk is mounted. 538 */ 539 540 if ( DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ) ) 541 { 542 CFStringRef arguments; 543 544 arguments = DARequestGetArgument3( request ); 545 546 if ( arguments == NULL || DAMountContainsArgument( arguments, kDAFileSystemMountArgumentUpdate ) == FALSE ) 547 { 548 status = kDAReturnBusy; 549 } 550 } 551 552 if ( status ) 553 { 554 DARequestDispatchCallback( request, status ); 555 556 DAStageSignal( ); 557 558 return TRUE; 559 } 560 else 561 { 562 CFRetain( request ); 563 564 DADiskSetState( disk, kDADiskStateCommandActive, TRUE ); 565 566 DARequestSetState( request, kDARequestStateStagedApprove, TRUE ); 567 568 DADiskMountApprovalCallback( disk, __DARequestMountApprovalCallback, request ); 569 570 return FALSE; 571 } 572 } 573///w:start 574 /* 575 * Commence the mount authorization. 576 */ 577 578 if ( DARequestGetState( request, _kDARequestStateStagedAuthorize ) == FALSE ) 579 { 580 DAReturn status; 581 582 status = kDAReturnSuccess; 583 584 if ( DARequestGetDissenter( request ) ) 585 { 586 DADissenterRef dissenter; 587 588 dissenter = DARequestGetDissenter( request ); 589 590 if ( DADissenterGetStatus( dissenter ) == 0xF8DAFF01 ) 591 { 592 DARequestSetDissenter( request, NULL ); 593 594 status = kDAReturnNotPrivileged; 595 } 596 else if ( DADissenterGetStatus( dissenter ) == 0xF8DAFF03 ) 597 { 598 status = kDAReturnNotPrivileged; 599 } 600 } 601 602 if ( status ) 603 { 604 CFRetain( request ); 605 606 DADiskSetState( disk, kDADiskStateCommandActive, TRUE ); 607 608 DARequestSetState( request, _kDARequestStateStagedAuthorize, TRUE ); 609 610 __DARequestAuthorize( request, __DARequestMountAuthorizationCallback, request, _kDAAuthorizeRightMount ); 611 612 return FALSE; 613 } 614 else 615 { 616 DARequestSetState( request, _kDARequestStateStagedAuthorize, TRUE ); 617 } 618 } 619///w:stop 620 621///w:start 622 if ( DARequestGetDissenter( request ) ) 623 { 624 DADissenterRef dissenter; 625 626 dissenter = DARequestGetDissenter( request ); 627 628 if ( DADissenterGetStatus( dissenter ) == 0xF8DAFF02 ) 629 { 630 DADiskSetState( disk, _kDADiskStateMountPreferenceNoWrite, TRUE ); 631 632 DARequestSetDissenter( request, NULL ); 633 } 634 else if ( DADissenterGetStatus( dissenter ) == 0xF8DAFF03 ) 635 { 636 DADiskSetState( disk, _kDADiskStateMountPreferenceNoWrite, TRUE ); 637 638 DARequestSetDissenter( request, NULL ); 639 } 640 } 641///w:stop 642 if ( DARequestGetDissenter( request ) ) 643 { 644 DADissenterRef dissenter; 645 646 dissenter = DARequestGetDissenter( request ); 647 648 __DARequestDispatchCallback( request, dissenter ); 649 650 DAStageSignal( ); 651 652 return TRUE; 653 } 654 655 /* 656 * Commence the mount. 657 */ 658 659 if ( DAUnitGetState( disk, kDAUnitStateCommandActive ) == FALSE ) 660 { 661 CFTypeRef path; 662 663 path = DARequestGetArgument2( request ); 664 665 if ( path ) 666 { 667 path = CFURLCreateWithString( kCFAllocatorDefault, path, NULL ); 668 } 669 670 CFRetain( request ); 671 672 DADiskSetState( disk, kDADiskStateCommandActive, TRUE ); 673 674 DAUnitSetState( disk, kDAUnitStateCommandActive, TRUE ); 675 676 DAMountWithArguments( disk, path, __DARequestMountCallback, request, DARequestGetArgument3( request ), NULL ); 677 678 if ( path ) 679 { 680 CFRelease( path ); 681 } 682 683 return TRUE; 684 } 685 else 686 { 687 return FALSE; 688 } 689} 690 691static void __DARequestMountCallback( int status, CFURLRef mountpoint, void * context ) 692{ 693 DADiskRef disk; 694 DARequestRef request = context; 695 696 disk = DARequestGetDisk( request ); 697 698 if ( status ) 699 { 700 /* 701 * We were unable to mount the volume. 702 */ 703 704 DADissenterRef dissenter; 705 706 dissenter = DADissenterCreate( kCFAllocatorDefault, unix_err( status ) ); 707 708 DARequestSetDissenter( request, dissenter ); 709 710 CFRelease( dissenter ); 711 } 712 else 713 { 714 /* 715 * We were able to mount the volume. 716 */ 717 718 CFStringRef arguments; 719 720 DADiskSetBypath( disk, mountpoint ); 721 722 DADiskSetDescription( disk, kDADiskDescriptionVolumePathKey, mountpoint ); 723 724 arguments = DARequestGetArgument3( request ); 725 726 if ( arguments == NULL || DAMountContainsArgument( arguments, kDAFileSystemMountArgumentUpdate ) == FALSE ) 727 { 728 DADiskDescriptionChangedCallback( disk, kDADiskDescriptionVolumePathKey ); 729 } 730 } 731 732 DARequestDispatchCallback( request, status ? unix_err( status ) : status ); 733 734 DAUnitSetState( disk, kDAUnitStateCommandActive, FALSE ); 735 736 DADiskSetState( disk, kDADiskStateCommandActive, FALSE ); 737 738 DAStageSignal( ); 739 740 CFRelease( request ); 741} 742 743static void __DARequestMountApprovalCallback( CFTypeRef response, void * context ) 744{ 745 DARequestRef request = context; 746 747 DARequestSetDissenter( request, response ); 748 749 DADiskSetState( DARequestGetDisk( request ), kDADiskStateCommandActive, FALSE ); 750 751 DAStageSignal( ); 752 753 CFRelease( request ); 754} 755///w:start 756static void __DARequestMountAuthorizationCallback( DAReturn status, void * context ) 757{ 758 DARequestRef request = context; 759 760 if ( status ) 761 { 762 DADissenterRef dissenter; 763 764 dissenter = DADissenterCreate( kCFAllocatorDefault, status ); 765 766 DARequestSetDissenter( request, dissenter ); 767 768 CFRelease( dissenter ); 769 } 770 771 DADiskSetState( DARequestGetDisk( request ), kDADiskStateCommandActive, FALSE ); 772 773 DAStageSignal( ); 774 775 CFRelease( request ); 776} 777///w:stop 778 779static Boolean __DARequestProbe( DARequestRef request ) 780{ 781 DADiskRef disk; 782 783 disk = DARequestGetDisk( request ); 784 785 /* 786 * Commence the probe. 787 */ 788 789///w:start 790 if ( DARequestGetState( request, kDARequestStateStagedProbe ) == FALSE ) 791 { 792 /* 793 * Determine whether the disk is mounted. 794 */ 795 796 if ( DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ) == NULL ) 797 { 798 DARequestSetState( request, kDARequestStateStagedProbe, TRUE ); 799 800 DADiskSetState( disk, kDADiskStateStagedProbe, FALSE ); 801 802 DAStageSignal( ); 803 804 return FALSE; 805 } 806 } 807 else 808 { 809 if ( DADiskGetState( disk, kDADiskStateStagedProbe ) == FALSE ) 810 { 811 return FALSE; 812 } 813 } 814///w:stop 815 if ( DAUnitGetState( disk, kDAUnitStateCommandActive ) == FALSE ) 816 { 817 DAReturn status; 818 819 status = kDAReturnSuccess; 820 821 /* 822 * Determine whether the disk is mounted. 823 */ 824 825 if ( DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ) ) 826 { 827 status = kDAReturnBusy; 828 } 829 830 if ( status ) 831 { 832 DARequestDispatchCallback( request, status ); 833 834 DAStageSignal( ); 835 836 return TRUE; 837 } 838 else 839 { 840 CFRetain( request ); 841 842 DADiskSetState( disk, kDADiskStateCommandActive, TRUE ); 843 844 DAUnitSetState( disk, kDAUnitStateCommandActive, TRUE ); 845 846///w:start 847// DAProbe( disk, __DARequestProbeCallback, request ); 848 __DARequestProbeCallback( 0, request ); 849///w:stop 850 851 return TRUE; 852 } 853 } 854 else 855 { 856 return FALSE; 857 } 858} 859 860static void __DARequestProbeCallback( int status, void * context ) 861{ 862 DADiskRef disk; 863 DARequestRef request = context; 864 865 disk = DARequestGetDisk( request ); 866 867 DARequestDispatchCallback( request, status ? unix_err( status ) : status ); 868 869 DAUnitSetState( disk, kDAUnitStateCommandActive, FALSE ); 870 871 DADiskSetState( disk, kDADiskStateCommandActive, FALSE ); 872 873 DAStageSignal( ); 874 875 CFRelease( request ); 876} 877 878static Boolean __DARequestRefresh( DARequestRef request ) 879{ 880 DADiskRef disk; 881 882 disk = DARequestGetDisk( request ); 883 884 /* 885 * Commence the refresh. 886 */ 887 888 { 889 DAReturn status; 890 891 status = kDAReturnSuccess; 892 893 /* 894 * Determine whether the disk is mountable. 895 */ 896 897 if ( DADiskGetDescription( disk, kDADiskDescriptionVolumeMountableKey ) == kCFBooleanFalse ) 898 { 899 status = kDAReturnUnsupported; 900 } 901 902 if ( status ) 903 { 904 DARequestDispatchCallback( request, status ); 905 906 DAStageSignal( ); 907 908 return TRUE; 909 } 910 else 911 { 912 CFRetain( request ); 913 914 DADiskSetState( disk, kDADiskStateCommandActive, TRUE ); 915 916 status = _DADiskRefresh( disk ); 917 918 __DARequestRefreshCallback( status ? ENOTSUP : 0, request ); 919 920 return TRUE; 921 } 922 } 923} 924 925static void __DARequestRefreshCallback( int status, void * context ) 926{ 927 DADiskRef disk; 928 DARequestRef request = context; 929 930 disk = DARequestGetDisk( request ); 931 932 DARequestDispatchCallback( request, status ? unix_err( status ) : status ); 933 934 DADiskSetState( disk, kDADiskStateCommandActive, FALSE ); 935 936 DAStageSignal( ); 937 938 CFRelease( request ); 939} 940 941static Boolean __DARequestRename( DARequestRef request ) 942{ 943 DADiskRef disk; 944 945 DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID ); 946 947 disk = DARequestGetDisk( request ); 948 949 /* 950 * Commence the rename. 951 */ 952 953 if ( DAUnitGetState( disk, kDAUnitStateCommandActive ) == FALSE ) 954 { 955 DAReturn status; 956 957 status = kDAReturnSuccess; 958 959 /* 960 * Determine whether the disk is mountable. 961 */ 962 963 if ( DADiskGetDescription( disk, kDADiskDescriptionVolumeMountableKey ) == kCFBooleanFalse ) 964 { 965 status = kDAReturnUnsupported; 966 } 967 968 /* 969 * Determine whether the disk is mounted. 970 */ 971 972 if ( DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ) == NULL ) 973 { 974 status = kDAReturnNotMounted; 975 } 976 977 /* 978 * Determine whether the name is valid. 979 */ 980 981 if ( DARequestGetArgument2( request ) == NULL ) 982 { 983 status = kDAReturnUnsupported; 984 } 985 986 if ( status ) 987 { 988 DARequestDispatchCallback( request, status ); 989 990 DAStageSignal( ); 991 992 return TRUE; 993 } 994 else 995 { 996 CFRetain( request ); 997 998 DADiskSetState( disk, kDADiskStateCommandActive, TRUE ); 999 1000 DAUnitSetState( disk, kDAUnitStateCommandActive, TRUE ); 1001 1002 DALogDebug( " renamed disk, id = %@, ongoing.", disk ); 1003 1004 DAFileSystemRename( DADiskGetFileSystem( disk ), 1005 DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ), 1006 DARequestGetArgument2( request ), 1007 __DARequestRenameCallback, 1008 request ); 1009 1010 return TRUE; 1011 } 1012 } 1013 else 1014 { 1015 return FALSE; 1016 } 1017} 1018 1019static void __DARequestRenameCallback( int status, void * context ) 1020{ 1021 DADiskRef disk; 1022 DARequestRef request = context; 1023 1024 disk = DARequestGetDisk( request ); 1025 1026 if ( status ) 1027 { 1028 /* 1029 * We were unable to rename the disk. 1030 */ 1031 1032 DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID ); 1033 1034 DALogDebug( " renamed disk, id = %@, failure.", disk ); 1035 1036 DALogDebug( "unable to rename %@ (status code 0x%08X).", disk, status ); 1037 } 1038 else 1039 { 1040 /* 1041 * We were able to rename the disk. 1042 */ 1043 1044 CFMutableArrayRef keys; 1045 1046 keys = CFArrayCreateMutable( kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks ); 1047 1048 if ( keys ) 1049 { 1050 CFStringRef name; 1051 1052 name = DARequestGetArgument2( request ); 1053 1054 if ( DADiskCompareDescription( disk, kDADiskDescriptionVolumeNameKey, name ) ) 1055 { 1056 CFURLRef mountpoint; 1057 1058 DADiskSetDescription( disk, kDADiskDescriptionVolumeNameKey, name ); 1059 1060 CFArrayAppendValue( keys, kDADiskDescriptionVolumeNameKey ); 1061 1062 /* 1063 * Rename the mount point. 1064 */ 1065 1066 mountpoint = DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ); 1067 1068 if ( CFEqual( CFURLGetString( mountpoint ), CFSTR( "file:///" ) ) ) 1069 { 1070 mountpoint = DAMountCreateMountPointWithAction( disk, kDAMountPointActionMove ); 1071 1072 if ( mountpoint ) 1073 { 1074 DADiskSetBypath( disk, mountpoint ); 1075 1076 CFRelease( mountpoint ); 1077 } 1078 } 1079 else 1080 { 1081 mountpoint = DAMountCreateMountPointWithAction( disk, kDAMountPointActionMove ); 1082 1083 if ( mountpoint ) 1084 { 1085 DADiskSetBypath( disk, mountpoint ); 1086 1087 DADiskSetDescription( disk, kDADiskDescriptionVolumePathKey, mountpoint ); 1088 1089 CFArrayAppendValue( keys, kDADiskDescriptionVolumePathKey ); 1090 1091 CFRelease( mountpoint ); 1092 } 1093 } 1094 1095 DADiskDescriptionChangedCallback( disk, keys ); 1096 } 1097 1098 CFRelease( keys ); 1099 } 1100 1101 DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID ); 1102 1103 DALogDebug( " renamed disk, id = %@, success.", disk ); 1104 } 1105 1106 DARequestDispatchCallback( request, status ? unix_err( status ) : status ); 1107 1108 DAUnitSetState( disk, kDAUnitStateCommandActive, FALSE ); 1109 1110 DADiskSetState( disk, kDADiskStateCommandActive, FALSE ); 1111 1112 DAStageSignal( ); 1113 1114 CFRelease( request ); 1115} 1116 1117static Boolean __DARequestUnmount( DARequestRef request ) 1118{ 1119 DADiskRef disk; 1120 1121 DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID ); 1122 1123 disk = DARequestGetDisk( request ); 1124 1125 if ( DARequestGetLink( request ) ) 1126 { 1127 if ( DAUnitGetState( disk, kDAUnitStateCommandActive ) ) 1128 { 1129 return FALSE; 1130 } 1131 } 1132 1133 /* 1134 * Commence the unmount approval. 1135 */ 1136 1137 if ( DARequestGetState( request, kDARequestStateStagedApprove ) == FALSE ) 1138 { 1139 DAReturn status; 1140 1141 status = kDAReturnSuccess; 1142 1143 /* 1144 * Determine whether the disk is mountable. 1145 */ 1146 1147 if ( DADiskGetDescription( disk, kDADiskDescriptionVolumeMountableKey ) == kCFBooleanFalse ) 1148 { 1149 status = kDAReturnUnsupported; 1150 } 1151 1152 /* 1153 * Determine whether the disk is mounted. 1154 */ 1155 1156 if ( DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ) == NULL ) 1157 { 1158 status = kDAReturnNotMounted; 1159 } 1160 else 1161 { 1162 CFURLRef mountpoint; 1163 1164 mountpoint = DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ); 1165 1166 if ( CFEqual( CFURLGetString( mountpoint ), CFSTR( "file:///" ) ) ) 1167 { 1168 DADissenterRef dissenter; 1169 1170 status = kDAReturnBusy; 1171 1172 dissenter = DADissenterCreate( kCFAllocatorDefault, status ); 1173 1174 DARequestSetDissenter( request, dissenter ); 1175 1176 CFRelease( dissenter ); 1177 } 1178 } 1179 1180 if ( status ) 1181 { 1182 DARequestDispatchCallback( request, status ); 1183 1184 DAStageSignal( ); 1185 1186 return TRUE; 1187 } 1188 else 1189 { 1190 if ( DADiskGetState( disk, kDADiskStateZombie ) ) 1191 { 1192 DARequestSetState( request, kDARequestStateStagedApprove, TRUE ); 1193 1194 if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanTrue ) 1195 { 1196 DADialogShowDeviceRemoval( disk ); 1197 } 1198 } 1199 else 1200 { 1201 CFRetain( request ); 1202 1203 DADiskSetState( disk, kDADiskStateCommandActive, TRUE ); 1204 1205 DARequestSetState( request, kDARequestStateStagedApprove, TRUE ); 1206///w:start 1207 if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanTrue ) 1208 { 1209 DAThreadExecute( __DARequestUnmountTickle, disk, __DARequestUnmountTickleCallback, request ); 1210 1211 return FALSE; 1212 } 1213///w:stop 1214 1215 DADiskUnmountApprovalCallback( disk, __DARequestUnmountApprovalCallback, request ); 1216 1217 return FALSE; 1218 } 1219 } 1220 } 1221 1222 if ( DARequestGetDissenter( request ) ) 1223 { 1224 DADissenterRef dissenter; 1225 1226 dissenter = DARequestGetDissenter( request ); 1227 1228 __DARequestDispatchCallback( request, dissenter ); 1229 1230 DAStageSignal( ); 1231 1232 return TRUE; 1233 } 1234 1235 /* 1236 * Commence the unmount. 1237 */ 1238 1239 if ( DAUnitGetState( disk, kDAUnitStateCommandActive ) == FALSE ) 1240 { 1241 DADiskUnmountOptions options; 1242 1243 options = DARequestGetArgument1( request ); 1244 1245 CFRetain( request ); 1246 1247 DADiskSetState( disk, kDADiskStateCommandActive, TRUE ); 1248 1249 DAUnitSetState( disk, kDAUnitStateCommandActive, TRUE ); 1250 1251 DALogDebug( " unmounted disk, id = %@, ongoing.", disk ); 1252 1253 DAFileSystemUnmountWithArguments( DADiskGetFileSystem( disk ), 1254 DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ), 1255 __DARequestUnmountCallback, 1256 request, 1257 ( options & kDADiskUnmountOptionForce ) ? kDAFileSystemUnmountArgumentForce : NULL, 1258 NULL ); 1259 1260 return TRUE; 1261 } 1262 else 1263 { 1264 return FALSE; 1265 } 1266} 1267 1268static void __DARequestUnmountCallback( int status, void * context ) 1269{ 1270 DADiskRef disk; 1271 DARequestRef request = context; 1272 1273 DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID ); 1274 1275 disk = DARequestGetDisk( request ); 1276 1277 if ( status ) 1278 { 1279 /* 1280 * We were unable to unmount the volume. 1281 */ 1282 1283 DADissenterRef dissenter; 1284 1285 dissenter = DARequestGetDissenter( request ); 1286 1287 if ( dissenter == NULL ) 1288 { 1289 DALogDebug( " unmounted disk, id = %@, failure.", disk ); 1290 1291 DALogDebug( "unable to unmount %@ (status code 0x%08X).", disk, status ); 1292 1293///w:start 1294 status = EBUSY; 1295///w:stop 1296 dissenter = DADissenterCreate( kCFAllocatorDefault, unix_err( status ) ); 1297 1298 DARequestSetDissenter( request, dissenter ); 1299 1300 DAThreadExecute( __DARequestUnmountGetProcessID, request, __DARequestUnmountCallback, request ); 1301 1302 CFRelease( dissenter ); 1303 1304 return; 1305 } 1306 1307 __DARequestDispatchCallback( request, dissenter ); 1308 } 1309 else 1310 { 1311 /* 1312 * We were able to unmount the volume. 1313 */ 1314 1315 CFURLRef mountpoint; 1316 1317 mountpoint = DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ); 1318 1319 DAMountRemoveMountPoint( mountpoint ); 1320 1321 DADiskSetBypath( disk, NULL ); 1322 1323 DALogDebug( " unmounted disk, id = %@, success.", disk ); 1324 1325 if ( DADiskGetDescription( disk, kDADiskDescriptionMediaPathKey ) ) 1326 { 1327 DADiskSetDescription( disk, kDADiskDescriptionVolumePathKey, NULL ); 1328 1329 DADiskDescriptionChangedCallback( disk, kDADiskDescriptionVolumePathKey ); 1330 } 1331 else 1332 { 1333 DALogDebug( " removed disk, id = %@.", disk ); 1334 1335 DADiskDisappearedCallback( disk ); 1336 1337 DADiskSetDescription( disk, kDADiskDescriptionVolumePathKey, NULL ); 1338 1339 DADiskSetState( disk, kDADiskStateZombie, TRUE ); 1340 1341 ___CFArrayRemoveValue( gDADiskList, disk ); 1342 } 1343 1344 __DARequestDispatchCallback( request, NULL ); 1345 } 1346 1347 DAUnitSetState( disk, kDAUnitStateCommandActive, FALSE ); 1348 1349 DADiskSetState( disk, kDADiskStateCommandActive, FALSE ); 1350 1351 DAStageSignal( ); 1352 1353 CFRelease( request ); 1354} 1355 1356static void __DARequestUnmountApprovalCallback( CFTypeRef response, void * context ) 1357{ 1358 DARequestRef request = context; 1359 1360 if ( response ) 1361 { 1362 DADiskUnmountOptions options; 1363 1364 options = DARequestGetArgument1( request ); 1365 1366 if ( ( options & kDADiskUnmountOptionForce ) == 0 ) 1367 { 1368 DARequestSetDissenter( request, response ); 1369 } 1370///w:start 1371 if ( DADissenterGetStatus( response ) == 0xF8DAFF01 ) 1372 { 1373 DARequestSetDissenter( request, response ); 1374 } 1375///w:stop 1376 } 1377 1378 DADiskSetState( DARequestGetDisk( request ), kDADiskStateCommandActive, FALSE ); 1379 1380 DAStageSignal( ); 1381 1382 CFRelease( request ); 1383} 1384 1385static int __DARequestUnmountGetProcessID( void * context ) 1386{ 1387 DADiskRef disk; 1388 CFURLRef mountpoint; 1389 char * path; 1390 DARequestRef request = context; 1391 1392 disk = DARequestGetDisk( request ); 1393 1394 mountpoint = DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ); 1395 1396 path = ___CFURLCopyFileSystemRepresentation( mountpoint ); 1397 1398 if ( path ) 1399 { 1400 pid_t dissenterPID = 0; 1401 1402 proc_listpidspath( PROC_ALL_PIDS, 0, path, PROC_LISTPIDSPATH_EXCLUDE_EVTONLY | PROC_LISTPIDSPATH_PATH_IS_VOLUME, &dissenterPID, sizeof( dissenterPID ) ); 1403 1404 if ( dissenterPID ) 1405 { 1406 DADissenterRef dissenter; 1407 1408 dissenter = DARequestGetDissenter( request ); 1409 1410 DADissenterSetProcessID( dissenter, dissenterPID ); 1411 } 1412 1413 free( path ); 1414 } 1415 1416 return -1; 1417} 1418///w:start 1419static int __DARequestUnmountTickle( void * context ) 1420{ 1421 DADiskRef disk = context; 1422 size_t size; 1423 1424 size = ___CFNumberGetIntegerValue( DADiskGetDescription( disk, kDADiskDescriptionMediaBlockSizeKey ) ); 1425 1426 if ( size ) 1427 { 1428 char * buffer; 1429 1430 buffer = malloc( size ); 1431 1432 if ( buffer ) 1433 { 1434 int file; 1435 1436 file = open( DADiskGetBSDPath( disk, TRUE ), O_RDONLY ); 1437 1438 if ( file != -1 ) 1439 { 1440 read( file, buffer, size ); 1441 1442 close( file ); 1443 } 1444 1445 free( buffer ); 1446 } 1447 } 1448 1449 return 0; 1450} 1451 1452static void __DARequestUnmountTickleCallback( int status, void * context ) 1453{ 1454 DADiskUnmountApprovalCallback( DARequestGetDisk( context ), __DARequestUnmountApprovalCallback, context ); 1455} 1456///w:stop 1457 1458DARequestRef DARequestCreate( CFAllocatorRef allocator, 1459 _DARequestKind kind, 1460 DADiskRef argument0, 1461 CFIndex argument1, 1462 CFTypeRef argument2, 1463 CFTypeRef argument3, 1464 uid_t userUID, 1465 gid_t userGID, 1466 DACallbackRef callback ) 1467{ 1468 CFMutableDictionaryRef request; 1469 1470 request = CFDictionaryCreateMutable( kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); 1471 1472 if ( request ) 1473 { 1474 ___CFDictionarySetIntegerValue( request, _kDARequestKindKey, kind ); 1475 1476 if ( argument0 ) CFDictionarySetValue( request, _kDARequestDiskKey, argument0 ); 1477 if ( argument1 ) ___CFDictionarySetIntegerValue( request, _kDARequestArgument1Key, argument1 ); 1478 if ( argument2 ) CFDictionarySetValue( request, _kDARequestArgument2Key, argument2 ); 1479 if ( argument3 ) CFDictionarySetValue( request, _kDARequestArgument3Key, argument3 ); 1480 1481 ___CFDictionarySetIntegerValue( request, _kDARequestUserGIDKey, userGID ); 1482 ___CFDictionarySetIntegerValue( request, _kDARequestUserUIDKey, userUID ); 1483 1484 if ( callback ) CFDictionarySetValue( request, _kDARequestCallbackKey, callback ); 1485 } 1486 1487 return ( void * ) request; 1488} 1489 1490Boolean DARequestDispatch( DARequestRef request ) 1491{ 1492 Boolean dispatch; 1493 1494 dispatch = FALSE; 1495 1496 if ( request ) 1497 { 1498 DADiskRef disk; 1499 1500 disk = DARequestGetDisk( request ); 1501 1502 if ( disk ) 1503 { 1504 if ( DADiskGetState( disk, kDADiskStateCommandActive ) == FALSE ) 1505 { 1506 if ( DADiskGetState( disk, kDADiskStateStagedMount ) ) 1507 { 1508 switch ( DARequestGetKind( request ) ) 1509 { 1510 case _kDADiskClaim: 1511 { 1512 dispatch = __DARequestClaim( request ); 1513 1514 break; 1515 } 1516 case _kDADiskEject: 1517 { 1518 dispatch = __DARequestEject( request ); 1519 1520 break; 1521 } 1522 case _kDADiskMount: 1523 { 1524 dispatch = __DARequestMount( request ); 1525 1526 break; 1527 } 1528 case _kDADiskProbe: 1529 { 1530 dispatch = __DARequestProbe( request ); 1531 1532 break; 1533 } 1534 case _kDADiskRefresh: 1535 { 1536 dispatch = __DARequestRefresh( request ); 1537 1538 break; 1539 } 1540 case _kDADiskRename: 1541 { 1542 dispatch = __DARequestRename( request ); 1543 1544 break; 1545 } 1546 case _kDADiskUnmount: 1547 { 1548 dispatch = __DARequestUnmount( request ); 1549 1550 break; 1551 } 1552 } 1553 } 1554 } 1555 } 1556 } 1557 1558 return dispatch; 1559} 1560 1561void DARequestDispatchCallback( DARequestRef request, DAReturn status ) 1562{ 1563 if ( status ) 1564 { 1565 DADissenterRef dissenter; 1566 1567 dissenter = DADissenterCreate( kCFAllocatorDefault, status ); 1568 1569 __DARequestDispatchCallback( request, dissenter ); 1570 1571 CFRelease( dissenter ); 1572 } 1573 else 1574 { 1575 __DARequestDispatchCallback( request, NULL ); 1576 } 1577} 1578 1579CFIndex DARequestGetArgument1( DARequestRef request ) 1580{ 1581 return ___CFDictionaryGetIntegerValue( ( void * ) request, _kDARequestArgument1Key ); 1582} 1583 1584CFTypeRef DARequestGetArgument2( DARequestRef request ) 1585{ 1586 return CFDictionaryGetValue( ( void * ) request, _kDARequestArgument2Key ); 1587} 1588 1589CFTypeRef DARequestGetArgument3( DARequestRef request ) 1590{ 1591 return CFDictionaryGetValue( ( void * ) request, _kDARequestArgument3Key ); 1592} 1593 1594DACallbackRef DARequestGetCallback( DARequestRef request ) 1595{ 1596 return ( void * ) CFDictionaryGetValue( ( void * ) request, _kDARequestCallbackKey ); 1597} 1598 1599DADiskRef DARequestGetDisk( DARequestRef request ) 1600{ 1601 return ( void * ) CFDictionaryGetValue( ( void * ) request, _kDARequestDiskKey ); 1602} 1603 1604DADissenterRef DARequestGetDissenter( DARequestRef request ) 1605{ 1606 return CFDictionaryGetValue( ( void * ) request, _kDARequestDissenterKey ); 1607} 1608 1609_DARequestKind DARequestGetKind( DARequestRef request ) 1610{ 1611 return ___CFDictionaryGetIntegerValue( ( void * ) request, _kDARequestKindKey ); 1612} 1613 1614CFArrayRef DARequestGetLink( DARequestRef request ) 1615{ 1616 return CFDictionaryGetValue( ( void * ) request, _kDARequestLinkKey ); 1617} 1618 1619Boolean DARequestGetState( DARequestRef request, DARequestState state ) 1620{ 1621 return ( ___CFDictionaryGetIntegerValue( ( void * ) request, _kDARequestStateKey ) & state ) ? TRUE : FALSE; 1622} 1623 1624gid_t DARequestGetUserGID( DARequestRef request ) 1625{ 1626 return ___CFDictionaryGetIntegerValue( ( void * ) request, _kDARequestUserGIDKey ); 1627} 1628 1629uid_t DARequestGetUserUID( DARequestRef request ) 1630{ 1631 return ___CFDictionaryGetIntegerValue( ( void * ) request, _kDARequestUserUIDKey ); 1632} 1633 1634void DARequestSetCallback( DARequestRef request, DACallbackRef callback ) 1635{ 1636 if ( callback ) 1637 { 1638 CFDictionarySetValue( ( void * ) request, _kDARequestCallbackKey, callback ); 1639 } 1640 else 1641 { 1642 CFDictionaryRemoveValue( ( void * ) request, _kDARequestCallbackKey ); 1643 } 1644} 1645 1646void DARequestSetDissenter( DARequestRef request, DADissenterRef dissenter ) 1647{ 1648 if ( dissenter ) 1649 { 1650 CFDictionarySetValue( ( void * ) request, _kDARequestDissenterKey, dissenter ); 1651 } 1652 else 1653 { 1654 CFDictionaryRemoveValue( ( void * ) request, _kDARequestDissenterKey ); 1655 } 1656} 1657 1658void DARequestSetLink( DARequestRef request, CFArrayRef link ) 1659{ 1660 if ( link ) 1661 { 1662 CFDictionarySetValue( ( void * ) request, _kDARequestLinkKey, link ); 1663 } 1664 else 1665 { 1666 CFDictionaryRemoveValue( ( void * ) request, _kDARequestLinkKey ); 1667 } 1668} 1669 1670void DARequestSetState( DARequestRef request, DARequestState state, Boolean value ) 1671{ 1672 if ( value ) 1673 { 1674 state = ___CFDictionaryGetIntegerValue( ( void * ) request, _kDARequestStateKey ) | state; 1675 } 1676 else 1677 { 1678 state = ___CFDictionaryGetIntegerValue( ( void * ) request, _kDARequestStateKey ) & ~state; 1679 } 1680 1681 ___CFDictionarySetIntegerValue( ( void * ) request, _kDARequestStateKey, state ); 1682} 1683