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 "DAMount.h" 25 26#include "DABase.h" 27#include "DAInternal.h" 28#include "DALog.h" 29#include "DAMain.h" 30#include "DASupport.h" 31 32#include <fstab.h> 33#include <libgen.h> 34#include <unistd.h> 35#include <sys/param.h> 36#include <sys/stat.h> 37 38struct __DAMountCallbackContext 39{ 40///w:start 41 Boolean automatic; 42///w:stop 43 DAMountCallback callback; 44 void * callbackContext; 45 DADiskRef disk; 46 Boolean force; 47 CFURLRef mountpoint; 48 CFStringRef options; 49}; 50 51typedef struct __DAMountCallbackContext __DAMountCallbackContext; 52 53static void __DAMountWithArgumentsCallbackStage1( int status, void * context ); 54static void __DAMountWithArgumentsCallbackStage2( int status, void * context ); 55static void __DAMountWithArgumentsCallbackStage3( int status, void * context ); 56 57static void __DAMountWithArgumentsCallback( int status, void * parameter ) 58{ 59 /* 60 * Process the mount request completion. 61 */ 62 63 __DAMountCallbackContext * context = parameter; 64 65///w:start 66 if ( context->automatic ) 67 { 68 if ( status == ___EDIRTY ) 69 { 70 DAMountWithArguments( context->disk, NULL, context->callback, context->callbackContext, kDAFileSystemMountArgumentForce, kDAFileSystemMountArgumentNoWrite, NULL ); 71 72 context->callback = NULL; 73 } 74 } 75///w:stop 76 if ( context->callback ) 77 { 78 ( context->callback )( status, context->mountpoint, context->callbackContext ); 79 } 80 81 CFRelease( context->disk ); 82 CFRelease( context->options ); 83 84 if ( context->mountpoint ) CFRelease( context->mountpoint ); 85 86 free( context ); 87} 88 89static void __DAMountWithArgumentsCallbackStage1( int status, void * parameter ) 90{ 91 /* 92 * Process the repair command's completion. 93 */ 94 95 __DAMountCallbackContext * context = parameter; 96 97 DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID ); 98 99 if ( status ) 100 { 101 /* 102 * We were unable to repair the volume. 103 */ 104 105 if ( status == ECANCELED ) 106 { 107 status = 0; 108 } 109 else 110 { 111 DALogDebug( " repaired disk, id = %@, failure.", context->disk ); 112 113 DALogError( "unable to repair %@ (status code 0x%08X).", context->disk, status ); 114 115 if ( context->force ) 116 { 117 status = 0; 118 } 119 else 120 { 121 __DAMountWithArgumentsCallback( ___EDIRTY, context ); 122 } 123 } 124 } 125 else 126 { 127 /* 128 * We were able to repair the volume. 129 */ 130 131 DADiskSetState( context->disk, kDADiskStateRequireRepair, FALSE ); 132 133 DALogDebug( " repaired disk, id = %@, success.", context->disk ); 134 } 135 136 /* 137 * Mount the volume. 138 */ 139 140 if ( status == 0 ) 141 { 142 /* 143 * Create the mount point, in case one needs to be created. 144 */ 145 146 if ( context->mountpoint == NULL ) 147 { 148 context->mountpoint = DAMountCreateMountPointWithAction( context->disk, kDAMountPointActionMake ); 149 } 150 151 /* 152 * Execute the mount command. 153 */ 154 155 if ( context->mountpoint ) 156 { 157 DALogDebug( " mounted disk, id = %@, ongoing.", context->disk ); 158 159 DAFileSystemMountWithArguments( DADiskGetFileSystem( context->disk ), 160 DADiskGetDevice( context->disk ), 161 context->mountpoint, 162 DADiskGetUserUID( context->disk ), 163 DADiskGetUserGID( context->disk ), 164 __DAMountWithArgumentsCallbackStage2, 165 context, 166 context->options, 167 NULL ); 168 } 169 else 170 { 171 __DAMountWithArgumentsCallback( ENOSPC, context ); 172 } 173 } 174} 175 176static void __DAMountWithArgumentsCallbackStage2( int status, void * parameter ) 177{ 178 /* 179 * Process the mount command's completion. 180 */ 181 182 __DAMountCallbackContext * context = parameter; 183 184 DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID ); 185 186 if ( status ) 187 { 188 /* 189 * We were unable to mount the volume. 190 */ 191 192 DALogDebug( " mounted disk, id = %@, failure.", context->disk ); 193 194 DALogError( "unable to mount %@ (status code 0x%08X).", context->disk, status ); 195 196 DAMountRemoveMountPoint( context->mountpoint ); 197 198 __DAMountWithArgumentsCallback( status, context ); 199 } 200 else 201 { 202 /* 203 * We were able to mount the volume. 204 */ 205 206 DALogDebug( " mounted disk, id = %@, success.", context->disk ); 207 208 _DAMountCreateTrashFolder( context->disk, context->mountpoint ); 209 210 /* 211 * Execute the "repair quotas" command. 212 */ 213 214 if ( DADiskGetState( context->disk, kDADiskStateRequireRepairQuotas ) ) 215 { 216 DAFileSystemRepairQuotas( DADiskGetFileSystem( context->disk ), 217 context->mountpoint, 218 __DAMountWithArgumentsCallbackStage3, 219 context ); 220 } 221 else 222 { 223 __DAMountWithArgumentsCallbackStage3( 0, context ); 224 } 225 } 226} 227 228static void __DAMountWithArgumentsCallbackStage3( int status, void * parameter ) 229{ 230 /* 231 * Process the "repair quotas" command's completion. 232 */ 233 234 __DAMountCallbackContext * context = parameter; 235 236 if ( status ) 237 { 238 DALogError( "unable to repair quotas on disk %@ (status code 0x%08X).", context->disk, status ); 239 } 240 else 241 { 242 DADiskSetState( context->disk, kDADiskStateRequireRepairQuotas, FALSE ); 243 } 244 245 __DAMountWithArgumentsCallback( 0, context ); 246} 247 248void _DAMountCreateTrashFolder( DADiskRef disk, CFURLRef mountpoint ) 249{ 250 /* 251 * Create the trash folder in which the user trashes will be stored. 252 */ 253 254 /* 255 * Determine whether the disk is writable. 256 */ 257 258 if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanTrue ) 259 { 260 char path[MAXPATHLEN]; 261 262 /* 263 * Obtain the mount point path. 264 */ 265 266 if ( CFURLGetFileSystemRepresentation( mountpoint, TRUE, ( void * ) path, sizeof( path ) ) ) 267 { 268 struct stat status; 269 270 /* 271 * Determine whether the trash folder exists. 272 */ 273 274 strlcat( path, "/.Trashes", sizeof( path ) ); 275 276 if ( stat( path, &status ) ) 277 { 278 /* 279 * Create the trash folder. 280 */ 281 282 if ( ___mkdir( path, 01333 ) == 0 ) 283 { 284 /* 285 * Correct the trash folder's attributes. 286 */ 287 288 ___chattr( path, ___ATTR_INVISIBLE, 0 ); 289 } 290 } 291 } 292 } 293} 294 295void DAMount( DADiskRef disk, CFURLRef mountpoint, DAMountCallback callback, void * callbackContext ) 296{ 297 /* 298 * Mount the specified volume. A status of 0 indicates success. 299 */ 300 301 return DAMountWithArguments( disk, mountpoint, callback, callbackContext, NULL ); 302 303} 304 305Boolean DAMountContainsArgument( CFStringRef arguments, CFStringRef argument ) 306{ 307 CFBooleanRef argumentValue; 308 CFBooleanRef argumentsValue; 309 310 argumentsValue = NULL; 311 312 if ( CFStringHasPrefix( argument, CFSTR( "no" ) ) ) 313 { 314 argument = CFStringCreateWithSubstring( kCFAllocatorDefault, argument, CFRangeMake( 2, CFStringGetLength( argument ) - 2 ) ); 315 argumentValue = kCFBooleanFalse; 316 } 317 else 318 { 319 argument = CFRetain( argument ); 320 argumentValue = kCFBooleanTrue; 321 } 322 323 if ( argument ) 324 { 325 CFArrayRef argumentList; 326 CFIndex argumentListCount; 327 CFIndex argumentListIndex; 328 329 argumentList = CFStringCreateArrayBySeparatingStrings( kCFAllocatorDefault, arguments, CFSTR( "," ) ); 330 331 if ( argumentList ) 332 { 333 argumentListCount = CFArrayGetCount( argumentList ); 334 335 for ( argumentListIndex = 0; argumentListIndex < argumentListCount; argumentListIndex++ ) 336 { 337 CFStringRef compare; 338 339 compare = CFArrayGetValueAtIndex( argumentList, argumentListIndex ); 340 341 if ( compare ) 342 { 343 CFBooleanRef compareValue; 344 345 if ( CFStringHasPrefix( compare, CFSTR( "no" ) ) ) 346 { 347 compare = CFStringCreateWithSubstring( kCFAllocatorDefault, compare, CFRangeMake( 2, CFStringGetLength( compare ) - 2 ) ); 348 compareValue = kCFBooleanFalse; 349 } 350 else 351 { 352 compare = CFRetain( compare ); 353 compareValue = kCFBooleanTrue; 354 } 355 356 if ( compare ) 357 { 358 if ( CFEqual( compare, CFSTR( FSTAB_RO ) ) ) 359 { 360 CFRelease( compare ); 361 362 compare = CFRetain( kDAFileSystemMountArgumentNoWrite ); 363 compareValue = compareValue; 364 } 365 366 if ( CFEqual( compare, CFSTR( FSTAB_RW ) ) ) 367 { 368 CFRelease( compare ); 369 370 compare = CFRetain( kDAFileSystemMountArgumentNoWrite ); 371 compareValue = ( compareValue == kCFBooleanTrue ) ? kCFBooleanFalse : kCFBooleanTrue; 372 } 373 } 374 375 if ( compare ) 376 { 377 if ( CFEqual( argument, compare ) ) 378 { 379 argumentsValue = compareValue; 380 } 381 382 CFRelease( compare ); 383 } 384 } 385 } 386 387 CFRelease( argumentList ); 388 } 389 390 CFRelease( argument ); 391 } 392 393 return ( argumentValue == argumentsValue ) ? TRUE : FALSE; 394} 395 396CFURLRef DAMountCreateMountPoint( DADiskRef disk ) 397{ 398 return DAMountCreateMountPointWithAction( disk, kDAMountPointActionMake ); 399} 400 401CFURLRef DAMountCreateMountPointWithAction( DADiskRef disk, DAMountPointAction action ) 402{ 403 FILE * file; 404 CFIndex index; 405 CFURLRef mountpoint; 406 char name[MAXPATHLEN]; 407 char path[MAXPATHLEN]; 408 CFStringRef string; 409 410 mountpoint = NULL; 411 412 /* 413 * Obtain the volume name. 414 */ 415 416 string = DADiskGetDescription( disk, kDADiskDescriptionVolumeNameKey ); 417 418 if ( string ) 419 { 420 if ( CFStringGetLength( string ) ) 421 { 422 CFRetain( string ); 423 } 424 else 425 { 426 string = NULL; 427 } 428 } 429 430 if ( string == NULL ) 431 { 432 string = ___CFBundleCopyLocalizedStringInDirectory( gDABundlePath, CFSTR( "Untitled" ), CFSTR( "Untitled" ), NULL ); 433 } 434 435 if ( ___CFStringGetCString( string, name, MNAMELEN - 20 ) ) 436 { 437 /* 438 * Adjust the volume name. 439 */ 440 441 while ( strchr( name, '/' ) ) 442 { 443 *strchr( name, '/' ) = ':'; 444 } 445 446 /* 447 * Create the mount point path. 448 */ 449 450 for ( index = 0; index < 100; index++ ) 451 { 452 if ( index == 0 ) 453 { 454 snprintf( path, sizeof( path ), "%s/%s", kDAMainMountPointFolder, name ); 455 } 456 else 457 { 458 snprintf( path, sizeof( path ), "%s/%s %lu", kDAMainMountPointFolder, name, index ); 459 } 460 461 switch ( action ) 462 { 463 case kDAMountPointActionLink: 464 { 465 /* 466 * Link the mount point. 467 */ 468 469 CFURLRef url; 470 471 url = DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ); 472 473 if ( url ) 474 { 475 char source[MAXPATHLEN]; 476 477 if ( CFURLGetFileSystemRepresentation( url, TRUE, ( void * ) source, sizeof( source ) ) ) 478 { 479 if ( symlink( source, path ) == 0 ) 480 { 481 mountpoint = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, ( void * ) path, strlen( path ), TRUE ); 482 } 483 } 484 } 485 486 break; 487 } 488 case kDAMountPointActionMake: 489 { 490 /* 491 * Create the mount point. 492 */ 493 494 if ( mkdir( path, 0111 ) == 0 ) 495 { 496 if ( DADiskGetUserUID( disk ) ) 497 { 498 chown( path, DADiskGetUserUID( disk ), -1 ); 499 } 500 501 mountpoint = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, ( void * ) path, strlen( path ), TRUE ); 502 503 /* 504 * Create the mount point cookie file. 505 */ 506 507 strlcat( path, "/", sizeof( path ) ); 508 strlcat( path, kDAMainMountPointFolderCookieFile, sizeof( path ) ); 509 510 file = fopen( path, "w" ); 511 512 if ( file ) 513 { 514 fclose( file ); 515 } 516 } 517 518 break; 519 } 520 case kDAMountPointActionMove: 521 { 522 /* 523 * Move the mount point. 524 */ 525 526 CFURLRef url; 527 528 url = DADiskGetBypath( disk ); 529 530 if ( url ) 531 { 532 char source[MAXPATHLEN]; 533 534 if ( CFURLGetFileSystemRepresentation( url, TRUE, ( void * ) source, sizeof( source ) ) ) 535 { 536 if ( rename( source, path ) == 0 ) 537 { 538 mountpoint = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, ( void * ) path, strlen( path ), TRUE ); 539 } 540 } 541 } 542 543 break; 544 } 545 case kDAMountPointActionNone: 546 { 547 mountpoint = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, ( void * ) path, strlen( path ), TRUE ); 548 549 break; 550 } 551 } 552 553 if ( mountpoint ) 554 { 555 break; 556 } 557 } 558 } 559 560 CFRelease( string ); 561 562 return mountpoint; 563} 564 565Boolean DAMountGetPreference( DADiskRef disk, DAMountPreference preference ) 566{ 567 CFBooleanRef value; 568 569 switch ( preference ) 570 { 571 case kDAMountPreferenceDefer: 572 { 573 /* 574 * Determine whether the media is removable. 575 */ 576 577 if ( DADiskGetDescription( disk, kDADiskDescriptionMediaRemovableKey ) == kCFBooleanTrue ) 578 { 579 value = CFDictionaryGetValue( gDAPreferenceList, kDAPreferenceMountDeferRemovableKey ); 580 581 value = value ? value : kCFBooleanTrue; 582 } 583 else 584 { 585 /* 586 * Determine whether the device is internal. 587 */ 588 589 if ( DADiskGetDescription( disk, kDADiskDescriptionDeviceInternalKey ) == kCFBooleanTrue ) 590 { 591 value = CFDictionaryGetValue( gDAPreferenceList, kDAPreferenceMountDeferInternalKey ); 592 593 value = value ? value : kCFBooleanFalse; 594 } 595 else 596 { 597 value = CFDictionaryGetValue( gDAPreferenceList, kDAPreferenceMountDeferExternalKey ); 598 599 value = value ? value : kCFBooleanTrue; 600 } 601 } 602 603 break; 604 } 605 case kDAMountPreferenceTrust: 606 { 607 /* 608 * Determine whether the media is removable. 609 */ 610 611 if ( DADiskGetDescription( disk, kDADiskDescriptionMediaRemovableKey ) == kCFBooleanTrue ) 612 { 613 value = CFDictionaryGetValue( gDAPreferenceList, kDAPreferenceMountTrustRemovableKey ); 614 615 value = value ? value : kCFBooleanFalse; 616 } 617 else 618 { 619 /* 620 * Determine whether the device is internal. 621 */ 622 623 if ( DADiskGetDescription( disk, kDADiskDescriptionDeviceInternalKey ) == kCFBooleanTrue ) 624 { 625 value = CFDictionaryGetValue( gDAPreferenceList, kDAPreferenceMountTrustInternalKey ); 626 627 value = value ? value : kCFBooleanTrue; 628 } 629 else 630 { 631 value = CFDictionaryGetValue( gDAPreferenceList, kDAPreferenceMountTrustExternalKey ); 632 633 value = value ? value : kCFBooleanFalse; 634 } 635 } 636 637 break; 638 } 639 case kDAMountPreferenceWrite: 640 { 641 value = kCFBooleanTrue; 642///w:start 643 if ( DADiskGetState( disk, _kDADiskStateMountPreferenceNoWrite ) ) 644 { 645 DADiskSetState( disk, _kDADiskStateMountPreferenceNoWrite, FALSE ); 646 647 value = kCFBooleanFalse; 648 } 649///w:stop 650 651 break; 652 } 653 default: 654 { 655 value = kCFBooleanFalse; 656 657 break; 658 } 659 } 660 661 assert( value ); 662 663 return CFBooleanGetValue( value ); 664} 665 666void DAMountRemoveMountPoint( CFURLRef mountpoint ) 667{ 668 char path[MAXPATHLEN]; 669 670 /* 671 * Obtain the mount point path. 672 */ 673 674 if ( CFURLGetFileSystemRepresentation( mountpoint, TRUE, ( void * ) path, sizeof( path ) ) ) 675 { 676 if ( ___isautofs( path ) == 0 ) 677 { 678 Boolean remove; 679 680 remove = FALSE; 681 682 if ( strncmp( path, kDAMainMountPointFolder, strlen( kDAMainMountPointFolder ) ) == 0 ) 683 { 684 if ( strrchr( path + strlen( kDAMainMountPointFolder ), '/' ) == path + strlen( kDAMainMountPointFolder ) ) 685 { 686 remove = TRUE; 687 } 688 } 689 690///w:start 691// if ( remove == FALSE ) 692///w:stop 693 { 694 char file[MAXPATHLEN]; 695 696 strlcpy( file, path, sizeof( file ) ); 697 strlcat( file, "/", sizeof( file ) ); 698 strlcat( file, kDAMainMountPointFolderCookieFile, sizeof( file ) ); 699 700 /* 701 * Remove the mount point cookie file. 702 */ 703 704 if ( unlink( file ) == 0 ) 705 { 706 remove = TRUE; 707 } 708 } 709 710 if ( remove ) 711 { 712 /* 713 * Remove the mount point. 714 */ 715 716 rmdir( path ); 717 } 718 } 719 } 720} 721 722void DAMountWithArguments( DADiskRef disk, CFURLRef mountpoint, DAMountCallback callback, void * callbackContext, ... ) 723{ 724 /* 725 * Mount the specified volume. A status of 0 indicates success. All arguments in 726 * the argument list shall be of type CFStringRef. The argument list must be NULL 727 * terminated. 728 */ 729 730 CFStringRef argument = NULL; 731 va_list arguments; 732 CFBooleanRef automatic = kCFBooleanTrue; 733 CFBooleanRef check = NULL; 734 __DAMountCallbackContext * context = NULL; 735 CFIndex count = 0; 736 DAFileSystemRef filesystem = DADiskGetFileSystem( disk ); 737 Boolean force = FALSE; 738 CFIndex index = 0; 739 CFDictionaryRef map = NULL; 740 CFMutableStringRef options = NULL; 741 int status = 0; 742 743 DALogDebugHeader( "%s -> %s", gDAProcessNameID, gDAProcessNameID ); 744 745 /* 746 * Initialize our minimal state. 747 */ 748 749 if ( mountpoint ) 750 { 751 CFRetain( mountpoint ); 752 } 753 754 /* 755 * Prepare the mount context. 756 */ 757 758 context = malloc( sizeof( __DAMountCallbackContext ) ); 759 760 if ( context == NULL ) 761 { 762 status = ENOMEM; 763 764 goto DAMountWithArgumentsErr; 765 } 766 767 /* 768 * Prepare the mount options. 769 */ 770 771 options = CFStringCreateMutable( kCFAllocatorDefault, 0 ); 772 773 if ( options == NULL ) 774 { 775 status = ENOMEM; 776 777 goto DAMountWithArgumentsErr; 778 } 779 780 va_start( arguments, callbackContext ); 781 782 while ( ( argument = va_arg( arguments, CFStringRef ) ) ) 783 { 784 if ( CFEqual( argument, kDAFileSystemMountArgumentForce ) ) 785 { 786 force = TRUE; 787 } 788 else 789 { 790 CFStringAppend( options, argument ); 791 CFStringAppend( options, CFSTR( "," ) ); 792 } 793 } 794 795 va_end( arguments ); 796 797 CFStringTrim( options, CFSTR( "," ) ); 798 799 if ( CFEqual( options, CFSTR( "automatic" ) ) ) 800 { 801 automatic = NULL; 802 803 check = kCFBooleanTrue; 804 805 CFStringReplaceAll( options, CFSTR( "" ) ); 806 } 807///w:start 808 context->automatic = ( automatic == NULL ) ? TRUE : FALSE; 809///w:stop 810 811 /* 812 * Determine whether the volume is to be updated. 813 */ 814 815 if ( DAMountContainsArgument( options, kDAFileSystemMountArgumentUpdate ) ) 816 { 817 if ( mountpoint ) 818 { 819 status = EINVAL; 820 821 goto DAMountWithArgumentsErr; 822 } 823 824 mountpoint = DADiskGetDescription( disk, kDADiskDescriptionVolumePathKey ); 825 826 if ( mountpoint == NULL ) 827 { 828 status = EINVAL; 829 830 goto DAMountWithArgumentsErr; 831 } 832 833 CFRetain( mountpoint ); 834 } 835 836 /* 837 * Scan the mount map list. 838 */ 839 840 count = CFArrayGetCount( gDAMountMapList1 ); 841 842 for ( index = 0; index < count; index++ ) 843 { 844 map = CFArrayGetValueAtIndex( gDAMountMapList1, index ); 845 846 if ( map ) 847 { 848 CFTypeRef id; 849 CFStringRef kind; 850 851 id = CFDictionaryGetValue( map, kDAMountMapProbeIDKey ); 852 kind = CFDictionaryGetValue( map, kDAMountMapProbeKindKey ); 853 854 if ( kind ) 855 { 856 /* 857 * Determine whether the volume kind matches. 858 */ 859 860 if ( CFEqual( kind, DAFileSystemGetKind( filesystem ) ) == FALSE ) 861 { 862 continue; 863 } 864 } 865 866 if ( CFGetTypeID( id ) == CFUUIDGetTypeID( ) ) 867 { 868 /* 869 * Determine whether the volume UUID matches. 870 */ 871 872 if ( DADiskCompareDescription( disk, kDADiskDescriptionVolumeUUIDKey, id ) == kCFCompareEqualTo ) 873 { 874 break; 875 } 876 } 877 else if ( CFGetTypeID( id ) == CFStringGetTypeID( ) ) 878 { 879 /* 880 * Determine whether the volume name matches. 881 */ 882 883 if ( DADiskCompareDescription( disk, kDADiskDescriptionVolumeNameKey, id ) == kCFCompareEqualTo ) 884 { 885 break; 886 } 887 } 888 else if ( CFGetTypeID( id ) == CFDictionaryGetTypeID( ) ) 889 { 890 boolean_t match = FALSE; 891 892 /* 893 * Determine whether the device description matches. 894 */ 895 896 IOServiceMatchPropertyTable( DADiskGetIOMedia( disk ), id, &match ); 897 898 if ( match ) 899 { 900 break; 901 } 902 } 903 } 904 } 905 906 /* 907 * Process the map. 908 */ 909 910 if ( index < count ) 911 { 912 CFStringRef string; 913 914 /* 915 * Determine whether the volume is to be mounted. 916 */ 917 918 if ( automatic == NULL ) 919 { 920 automatic = CFDictionaryGetValue( map, kDAMountMapMountAutomaticKey ); 921 922 if ( automatic == kCFBooleanTrue ) 923 { 924 DADiskSetOption( disk, kDADiskOptionMountAutomatic, TRUE ); 925 DADiskSetOption( disk, kDADiskOptionMountAutomaticNoDefer, TRUE ); 926 } 927 } 928 929 /* 930 * Prepare the mount options. 931 */ 932 933 string = CFDictionaryGetValue( map, kDAMountMapMountOptionsKey ); 934 935 if ( string ) 936 { 937 CFStringInsert( options, 0, CFSTR( "," ) ); 938 CFStringInsert( options, 0, string ); 939 } 940 941 /* 942 * Prepare the mount point. 943 */ 944 945 if ( mountpoint == NULL ) 946 { 947 mountpoint = CFDictionaryGetValue( map, kDAMountMapMountPathKey ); 948 949 if ( mountpoint ) 950 { 951 CFRetain( mountpoint ); 952 } 953 } 954 } 955 956 /* 957 * Scan the mount map list. 958 */ 959 960 count = CFArrayGetCount( gDAMountMapList2 ); 961 962 for ( index = 0; index < count; index++ ) 963 { 964 map = CFArrayGetValueAtIndex( gDAMountMapList2, index ); 965 966 if ( map ) 967 { 968 CFTypeRef id; 969 970 id = CFDictionaryGetValue( map, kDAMountMapProbeIDKey ); 971 972 /* 973 * Determine whether the volume UUID matches. 974 */ 975 976 if ( DADiskCompareDescription( disk, kDADiskDescriptionVolumeUUIDKey, id ) == kCFCompareEqualTo ) 977 { 978 break; 979 } 980 } 981 } 982 983 /* 984 * Process the map. 985 */ 986 987 if ( index < count ) 988 { 989 CFStringRef string; 990 991 /* 992 * Prepare the mount options. 993 */ 994 995 string = CFDictionaryGetValue( map, kDAMountMapMountOptionsKey ); 996 997 if ( string ) 998 { 999 CFStringInsert( options, 0, CFSTR( "," ) ); 1000 CFStringInsert( options, 0, string ); 1001 } 1002 } 1003 1004 /* 1005 * Determine whether the volume is to be mounted. 1006 */ 1007 1008 if ( automatic == NULL ) 1009 { 1010 if ( DADiskGetOption( disk, kDADiskOptionMountAutomatic ) ) 1011 { 1012 if ( DADiskGetOption( disk, kDADiskOptionMountAutomaticNoDefer ) ) 1013 { 1014 automatic = kCFBooleanTrue; 1015 } 1016 } 1017 else 1018 { 1019 automatic = kCFBooleanFalse; 1020 } 1021 1022 if ( automatic == NULL ) 1023 { 1024 if ( gDAConsoleUserList == NULL ) 1025 { 1026 if ( DAMountGetPreference( disk, kDAMountPreferenceDefer ) ) 1027 { 1028 automatic = kCFBooleanFalse; 1029 } 1030 } 1031 } 1032 } 1033 1034 if ( automatic == kCFBooleanFalse ) 1035 { 1036 status = ECANCELED; 1037 1038 goto DAMountWithArgumentsErr; 1039 } 1040 1041 /* 1042 * Prepare the mount options. 1043 */ 1044 1045 if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanFalse ) 1046 { 1047 CFStringInsert( options, 0, CFSTR( "," ) ); 1048 CFStringInsert( options, 0, kDAFileSystemMountArgumentNoWrite ); 1049 } 1050 1051 if ( DAMountGetPreference( disk, kDAMountPreferenceWrite ) == FALSE ) 1052 { 1053 CFStringInsert( options, 0, CFSTR( "," ) ); 1054 CFStringInsert( options, 0, kDAFileSystemMountArgumentNoWrite ); 1055 } 1056 1057 if ( DAMountGetPreference( disk, kDAMountPreferenceTrust ) == FALSE ) 1058 { 1059 CFStringInsert( options, 0, CFSTR( "," ) ); 1060 CFStringInsert( options, 0, kDAFileSystemMountArgumentNoSetUserID ); 1061 1062 CFStringInsert( options, 0, CFSTR( "," ) ); 1063 CFStringInsert( options, 0, kDAFileSystemMountArgumentNoOwnership ); 1064 1065 CFStringInsert( options, 0, CFSTR( "," ) ); 1066 CFStringInsert( options, 0, kDAFileSystemMountArgumentNoDevice ); 1067 } 1068///w:start 1069 if ( CFEqual( DAFileSystemGetKind( filesystem ), CFSTR( "hfs" ) ) ) 1070 { 1071 ___CFStringInsertFormat( options, 0, CFSTR( "-m=%o," ), 0755 ); 1072 1073 if ( DADiskGetUserGID( disk ) ) 1074 { 1075 ___CFStringInsertFormat( options, 0, CFSTR( "-g=%d," ), DADiskGetUserGID( disk ) ); 1076 } 1077 else 1078 { 1079 ___CFStringInsertFormat( options, 0, CFSTR( "-g=%d," ), ___GID_UNKNOWN ); 1080 } 1081 1082 if ( DADiskGetUserUID( disk ) ) 1083 { 1084 ___CFStringInsertFormat( options, 0, CFSTR( "-u=%d," ), DADiskGetUserUID( disk ) ); 1085 } 1086 else 1087 { 1088 ___CFStringInsertFormat( options, 0, CFSTR( "-u=%d," ), ___UID_UNKNOWN ); 1089 } 1090 } 1091///w:stop 1092 1093 CFStringTrim( options, CFSTR( "," ) ); 1094 1095 /* 1096 * Determine whether the volume is to be repaired. 1097 */ 1098 1099 if ( check == NULL ) 1100 { 1101 if ( DAMountContainsArgument( options, kDAFileSystemMountArgumentNoWrite ) ) 1102 { 1103 check = kCFBooleanFalse; 1104 } 1105 else 1106 { 1107 check = kCFBooleanTrue; 1108 } 1109 } 1110 1111 if ( check == kCFBooleanFalse ) 1112 { 1113 if ( DADiskGetState( disk, kDADiskStateRequireRepair ) ) 1114 { 1115 if ( force == FALSE ) 1116 { 1117 status = ___EDIRTY; 1118 1119 goto DAMountWithArgumentsErr; 1120 } 1121 } 1122 } 1123 1124 if ( check == kCFBooleanTrue ) 1125 { 1126 if ( DADiskGetState( disk, kDADiskStateRequireRepair ) == FALSE ) 1127 { 1128 check = kCFBooleanFalse; 1129 } 1130 } 1131 1132 /* 1133 * Repair the volume. 1134 */ 1135 1136 CFRetain( disk ); 1137 1138 context->callback = callback; 1139 context->callbackContext = callbackContext; 1140 context->disk = disk; 1141 context->force = force; 1142 context->mountpoint = mountpoint; 1143 context->options = options; 1144 1145 if ( check == kCFBooleanTrue ) 1146 { 1147 DALogDebug( " repaired disk, id = %@, ongoing.", disk ); 1148 1149 DAFileSystemRepair( DADiskGetFileSystem( disk ), 1150 DADiskGetDevice( disk ), 1151 __DAMountWithArgumentsCallbackStage1, 1152 context ); 1153 } 1154 else 1155 { 1156 __DAMountWithArgumentsCallbackStage1( ECANCELED, context ); 1157 } 1158 1159DAMountWithArgumentsErr: 1160 1161 if ( status ) 1162 { 1163 if ( context ) 1164 { 1165 free( context ); 1166 } 1167 1168 if ( mountpoint ) 1169 { 1170 CFRelease( mountpoint ); 1171 } 1172 1173 if ( options ) 1174 { 1175 CFRelease( options ); 1176 } 1177 1178 if ( callback ) 1179 { 1180 ( callback )( status, NULL, callbackContext ); 1181 } 1182 } 1183} 1184