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 "DADisk.h" 25 26#include "DABase.h" 27#include "DAInternal.h" 28#include "DALog.h" 29 30#include <grp.h> 31#include <paths.h> 32#include <pwd.h> 33#include <CoreFoundation/CFRuntime.h> 34#include <DiskArbitration/DiskArbitrationPrivate.h> 35#include <IOKit/IOBSD.h> 36#include <IOKit/storage/IOBlockStorageDevice.h> 37#include <IOKit/storage/IOMedia.h> 38#include <IOKit/storage/IOBDMedia.h> 39#include <IOKit/storage/IOCDMedia.h> 40#include <IOKit/storage/IODVDMedia.h> 41#include <IOKit/storage/IOStorageDeviceCharacteristics.h> 42 43struct __DADisk 44{ 45 CFRuntimeBase _base; 46 CFAbsoluteTime _busy; 47 io_object_t _busyNotification; 48 CFURLRef _bypath; 49 DACallbackRef _claim; 50 CFTypeRef _context; 51 CFTypeRef _contextRe; 52 CFMutableDictionaryRef _description; 53 CFURLRef _device; 54 char * _deviceLink[2]; 55 dev_t _deviceNode; 56 char * _devicePath[2]; 57 SInt32 _deviceUnit; 58 DAFileSystemRef _filesystem; 59 char * _id; 60 io_service_t _media; 61 mode_t _mode; 62 DADiskOptions _options; 63 io_object_t _propertyNotification; 64 CFDataRef _serialization; 65 DADiskState _state; 66 gid_t _userGID; 67 uid_t _userUID; 68}; 69 70typedef struct __DADisk __DADisk; 71 72static CFStringRef __DADiskCopyDescription( CFTypeRef object ); 73static CFStringRef __DADiskCopyFormattingDescription( CFTypeRef object, CFDictionaryRef options ); 74static void __DADiskDeallocate( CFTypeRef object ); 75static Boolean __DADiskEqual( CFTypeRef object1, CFTypeRef object2 ); 76static CFHashCode __DADiskHash( CFTypeRef object ); 77 78static const CFRuntimeClass __DADiskClass = 79{ 80 0, 81 "DADisk", 82 NULL, 83 NULL, 84 __DADiskDeallocate, 85 __DADiskEqual, 86 __DADiskHash, 87 __DADiskCopyFormattingDescription, 88 __DADiskCopyDescription 89}; 90 91static CFTypeID __kDADiskTypeID = _kCFRuntimeNotATypeID; 92 93extern CFHashCode CFHashBytes( UInt8 * bytes, CFIndex length ); 94 95static CFStringRef __DADiskCopyDescription( CFTypeRef object ) 96{ 97 DADiskRef disk = ( DADiskRef ) object; 98 99 return CFStringCreateWithFormat( CFGetAllocator( object ), NULL, CFSTR( "<DADisk %p [%p]>{id = %s}" ), object, CFGetAllocator( object ), disk->_id ); 100} 101 102static CFStringRef __DADiskCopyFormattingDescription( CFTypeRef object, CFDictionaryRef options ) 103{ 104 DADiskRef disk = ( DADiskRef ) object; 105 106 return CFStringCreateWithFormat( CFGetAllocator( object ), NULL, CFSTR( "%s" ), disk->_id ); 107} 108 109static DADiskRef __DADiskCreate( CFAllocatorRef allocator, const char * id ) 110{ 111 __DADisk * disk; 112 113 disk = ( void * ) _CFRuntimeCreateInstance( allocator, __kDADiskTypeID, sizeof( __DADisk ) - sizeof( CFRuntimeBase ), NULL ); 114 115 if ( disk ) 116 { 117 CFDataRef data; 118 119 disk->_busy = 0; 120 disk->_busyNotification = IO_OBJECT_NULL; 121 disk->_bypath = NULL; 122 disk->_claim = NULL; 123 disk->_context = NULL; 124 disk->_contextRe = NULL; 125 disk->_description = CFDictionaryCreateMutable( allocator, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks ); 126 disk->_device = NULL; 127 disk->_deviceLink[0] = NULL; 128 disk->_deviceLink[1] = NULL; 129 disk->_deviceNode = 0; 130 disk->_devicePath[0] = NULL; 131 disk->_devicePath[1] = NULL; 132 disk->_deviceUnit = -1; 133 disk->_filesystem = NULL; 134 disk->_id = strdup( id ); 135 disk->_media = IO_OBJECT_NULL; 136 disk->_mode = 0750; 137 disk->_options = 0; 138 disk->_propertyNotification = IO_OBJECT_NULL; 139 disk->_serialization = NULL; 140 disk->_state = 0; 141 disk->_userGID = ___GID_WHEEL; 142 disk->_userUID = ___UID_ROOT; 143 144 assert( disk->_description ); 145 assert( disk->_id ); 146 147 data = CFDataCreate( allocator, ( void * ) id, strlen( id ) + 1 ); 148 149 if ( data ) 150 { 151 CFDictionarySetValue( disk->_description, _kDADiskIDKey, data ); 152 153 CFRelease( data ); 154 } 155 } 156 157 return disk; 158} 159 160static void __DADiskDeallocate( CFTypeRef object ) 161{ 162 DADiskRef disk = ( DADiskRef ) object; 163 164 if ( disk->_busyNotification ) IOObjectRelease( disk->_busyNotification ); 165 if ( disk->_bypath ) CFRelease( disk->_bypath ); 166 if ( disk->_claim ) CFRelease( disk->_claim ); 167 if ( disk->_context ) CFRelease( disk->_context ); 168 if ( disk->_contextRe ) CFRelease( disk->_contextRe ); 169 if ( disk->_description ) CFRelease( disk->_description ); 170 if ( disk->_device ) CFRelease( disk->_device ); 171 if ( disk->_deviceLink[0] ) free( disk->_deviceLink[0] ); 172 if ( disk->_deviceLink[1] ) free( disk->_deviceLink[1] ); 173 if ( disk->_devicePath[0] ) free( disk->_devicePath[0] ); 174 if ( disk->_devicePath[1] ) free( disk->_devicePath[1] ); 175 if ( disk->_filesystem ) CFRelease( disk->_filesystem ); 176 if ( disk->_id ) free( disk->_id ); 177 if ( disk->_media ) IOObjectRelease( disk->_media ); 178 if ( disk->_propertyNotification ) IOObjectRelease( disk->_propertyNotification ); 179 if ( disk->_serialization ) CFRelease( disk->_serialization ); 180} 181 182static Boolean __DADiskEqual( CFTypeRef object1, CFTypeRef object2 ) 183{ 184 DADiskRef disk1 = ( DADiskRef ) object1; 185 DADiskRef disk2 = ( DADiskRef ) object2; 186 187 return ( strcmp( disk1->_id, disk2->_id ) == 0 ); 188} 189 190static CFHashCode __DADiskHash( CFTypeRef object ) 191{ 192 DADiskRef disk = ( DADiskRef ) object; 193 194 return CFHashBytes( ( void * ) disk->_id, MIN( strlen( disk->_id ), 16 ) ); 195} 196 197static void __DADiskMatch( const void * key, const void * value, void * context ) 198{ 199 DADiskRef disk = *( ( void * * ) context ); 200 201 if ( disk ) 202 { 203 if ( CFEqual( key, kDADiskDescriptionMediaMatchKey ) ) 204 { 205 boolean_t match = FALSE; 206 207 IOServiceMatchPropertyTable( disk->_media, value, &match ); 208 209 if ( match == FALSE ) 210 { 211 *( ( void * * ) context ) = NULL; 212 } 213 } 214 else 215 { 216 CFTypeRef compare; 217 218 compare = CFDictionaryGetValue( disk->_description, key ); 219 220 if ( compare == NULL || CFEqual( value, compare ) == FALSE ) 221 { 222 *( ( void * * ) context ) = NULL; 223 } 224 } 225 } 226} 227 228CFComparisonResult DADiskCompareDescription( DADiskRef disk, CFStringRef description, CFTypeRef value ) 229{ 230 CFTypeRef object1 = CFDictionaryGetValue( disk->_description, description ); 231 CFTypeRef object2 = value; 232 233 if ( object1 == object2 ) return kCFCompareEqualTo; 234 if ( object1 == NULL ) return kCFCompareLessThan; 235 if ( object2 == NULL ) return kCFCompareGreaterThan; 236 237 return CFEqual( object1, object2 ) ? kCFCompareEqualTo : kCFCompareLessThan; 238} 239 240DADiskRef DADiskCreateFromIOMedia( CFAllocatorRef allocator, io_service_t media ) 241{ 242 io_service_t bus = IO_OBJECT_NULL; 243 uint32_t busy; 244 io_service_t device = IO_OBJECT_NULL; 245 DADiskRef disk = NULL; 246 UInt32 major; 247 UInt32 minor; 248 io_name_t name; 249 CFMutableDictionaryRef properties = NULL; 250 CFTypeRef object; 251 ___io_path_t path; 252 io_iterator_t services; 253 kern_return_t status; 254 CFDictionaryRef sub; 255 double time; 256 257 /* 258 * Obtain the media properties. 259 */ 260 261 status = IORegistryEntryCreateCFProperties( media, &properties, allocator, 0 ); 262 if ( status != KERN_SUCCESS ) goto DADiskCreateFromIOMediaErr; 263 264 /* 265 * Create the disk object. 266 */ 267 268 object = CFDictionaryGetValue( properties, CFSTR( kIOBSDNameKey ) ); 269 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 270 271 status = CFStringGetCString( object, name, sizeof( name ), kCFStringEncodingUTF8 ); 272 if ( status == FALSE ) goto DADiskCreateFromIOMediaErr; 273 274 strlcpy( path, _PATH_DEV, sizeof( path ) ); 275 strlcat( path, name, sizeof( path ) ); 276 277 disk = __DADiskCreate( allocator, path ); 278 if ( disk == NULL ) goto DADiskCreateFromIOMediaErr; 279 280 disk->_device = CFURLCreateFromFileSystemRepresentation( allocator, ( void * ) path, strlen( path ), FALSE ); 281 if ( disk->_device == NULL ) goto DADiskCreateFromIOMediaErr; 282 283 disk->_devicePath[0] = strdup( path ); 284 285 strlcpy( path, _PATH_DEV, sizeof( path ) ); 286 strlcat( path, "r", sizeof( path ) ); 287 strlcat( path, name, sizeof( path ) ); 288 289 disk->_devicePath[1] = strdup( path ); 290 291 IOObjectRetain( media ); 292 293 disk->_media = media; 294 295 CFDictionarySetValue( disk->_description, kDADiskDescriptionVolumeNetworkKey, kCFBooleanFalse ); 296 297 /* 298 * Create the disk description -- media block size. 299 */ 300 301 object = CFDictionaryGetValue( properties, CFSTR( kIOMediaPreferredBlockSizeKey ) ); 302 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 303 304 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaBlockSizeKey, object ); 305 306 /* 307 * Create the disk description -- media BSD name. 308 */ 309 310 object = CFDictionaryGetValue( properties, CFSTR( kIOBSDNameKey ) ); 311 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 312 313 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaBSDNameKey, object ); 314 315 /* 316 * Create the disk description -- media BSD node. 317 */ 318 319 object = CFDictionaryGetValue( properties, CFSTR( kIOBSDMajorKey ) ); 320 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 321 322 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaBSDMajorKey, object ); 323 324 CFNumberGetValue( object, kCFNumberSInt32Type, &major ); 325 326 object = CFDictionaryGetValue( properties, CFSTR( kIOBSDMinorKey ) ); 327 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 328 329 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaBSDMinorKey, object ); 330 331 CFNumberGetValue( object, kCFNumberSInt32Type, &minor ); 332 333 disk->_deviceNode = makedev( major, minor ); 334 335 /* 336 * Create the disk description -- media BSD unit. 337 */ 338 339 object = CFDictionaryGetValue( properties, CFSTR( kIOBSDUnitKey ) ); 340 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 341 342 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaBSDUnitKey, object ); 343 344 CFNumberGetValue( object, kCFNumberSInt32Type, &disk->_deviceUnit ); 345 346 /* 347 * Create the disk description -- media content. 348 */ 349 350 object = CFDictionaryGetValue( properties, CFSTR( kIOMediaContentKey ) ); 351 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 352 353 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaContentKey, object ); 354 355 /* 356 * Create the disk description -- media ejectable? 357 */ 358 359 object = CFDictionaryGetValue( properties, CFSTR( kIOMediaEjectableKey ) ); 360 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 361 362 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaEjectableKey, object ); 363 364 /* 365 * Create the disk description -- media icon. 366 */ 367 368 object = IORegistryEntrySearchCFProperty( media, 369 kIOServicePlane, 370 CFSTR( kIOMediaIconKey ), 371 allocator, 372 kIORegistryIterateParents | kIORegistryIterateRecursively ); 373 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 374 375 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaIconKey, object ); 376 CFRelease( object ); 377 378 /* 379 * Create the disk description -- media kind. 380 */ 381 382 if ( IOObjectConformsTo( media, kIOBDMediaClass ) ) 383 { 384 object = CFSTR( kIOBDMediaClass ); 385 386 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaKindKey, object ); 387 388 /* 389 * Create the disk description -- media type. 390 */ 391 392 object = CFDictionaryGetValue( properties, CFSTR( kIOBDMediaTypeKey ) ); 393 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 394 395 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaTypeKey, object ); 396 } 397 else if ( IOObjectConformsTo( media, kIODVDMediaClass ) ) 398 { 399 object = CFSTR( kIODVDMediaClass ); 400 401 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaKindKey, object ); 402 403 /* 404 * Create the disk description -- media type. 405 */ 406 407 object = CFDictionaryGetValue( properties, CFSTR( kIODVDMediaTypeKey ) ); 408 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 409 410 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaTypeKey, object ); 411 } 412 else if ( IOObjectConformsTo( media, kIOCDMediaClass ) ) 413 { 414 object = CFSTR( kIOCDMediaClass ); 415 416 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaKindKey, object ); 417 418 /* 419 * Create the disk description -- media type. 420 */ 421 422 object = CFDictionaryGetValue( properties, CFSTR( kIOCDMediaTypeKey ) ); 423 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 424 425 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaTypeKey, object ); 426 } 427 else 428 { 429 object = CFSTR( kIOMediaClass ); 430 431 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaKindKey, object ); 432 } 433 434 /* 435 * Create the disk description -- media leaf? 436 */ 437 438 object = CFDictionaryGetValue( properties, CFSTR( kIOMediaLeafKey ) ); 439 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 440 441 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaLeafKey, object ); 442 443 /* 444 * Create the disk description -- media name. 445 */ 446 447 status = IORegistryEntryGetName( media, name ); 448 if ( status != KERN_SUCCESS ) goto DADiskCreateFromIOMediaErr; 449 450 object = CFStringCreateWithCString( allocator, name, kCFStringEncodingUTF8 ); 451 if ( object == NULL ) object = CFStringCreateWithCString( allocator, name, kCFStringEncodingMacRoman ); 452 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 453 454 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaNameKey, object ); 455 CFRelease( object ); 456 457 /* 458 * Create the disk description -- media path. 459 */ 460 461 status = ___IORegistryEntryGetPath( media, kIODeviceTreePlane, path ); 462 if ( status != KERN_SUCCESS ) status = ___IORegistryEntryGetPath( media, kIOServicePlane, path ); 463 if ( status != KERN_SUCCESS ) goto DADiskCreateFromIOMediaErr; 464 465 object = CFStringCreateWithCString( allocator, path, kCFStringEncodingUTF8 ); 466 if ( object == NULL ) object = CFStringCreateWithCString( allocator, path, kCFStringEncodingMacRoman ); 467 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 468 469 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaPathKey, object ); 470 CFRelease( object ); 471 472 /* 473 * Create the disk description -- media removable? 474 */ 475 476 object = CFDictionaryGetValue( properties, CFSTR( kIOMediaRemovableKey ) ); 477 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 478 479 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaRemovableKey, object ); 480 481 /* 482 * Create the disk description -- media size. 483 */ 484 485 object = CFDictionaryGetValue( properties, CFSTR( kIOMediaSizeKey ) ); 486 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 487 488 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaSizeKey, object ); 489 490 /* 491 * Create the disk description -- media UUID. 492 */ 493 494 object = CFDictionaryGetValue( properties, CFSTR( kIOMediaUUIDKey ) ); 495 496 if ( object ) 497 { 498 object = ___CFUUIDCreateFromString( allocator, object ); 499 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 500 501 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaUUIDKey, object ); 502 CFRelease( object ); 503 } 504 505 /* 506 * Create the disk description -- media whole? 507 */ 508 509 object = CFDictionaryGetValue( properties, CFSTR( kIOMediaWholeKey ) ); 510 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 511 512 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaWholeKey, object ); 513 514 /* 515 * Create the disk description -- media writable? 516 */ 517 518 object = CFDictionaryGetValue( properties, CFSTR( kIOMediaWritableKey ) ); 519 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 520 521 CFDictionarySetValue( disk->_description, kDADiskDescriptionMediaWritableKey, object ); 522 523 CFRelease( properties ); 524 properties = NULL; 525 526 /* 527 * Obtain the device object. 528 */ 529 530 status = IORegistryEntryCreateIterator( media, 531 kIOServicePlane, 532 kIORegistryIterateParents | kIORegistryIterateRecursively, 533 &services ); 534 535 while ( ( device = IOIteratorNext( services ) ) ) 536 { 537 if ( IOObjectConformsTo( device, kIOBlockStorageDeviceClass ) ) break; 538 539 IOObjectRelease( device ); 540 } 541 542 IOObjectRelease( services ); 543 544 if ( device == IO_OBJECT_NULL ) goto DADiskCreateFromIOMediaErr; 545 546 /* 547 * Obtain the device properties. 548 */ 549 550 status = IORegistryEntryCreateCFProperties( device, &properties, allocator, 0 ); 551 if ( status != KERN_SUCCESS ) goto DADiskCreateFromIOMediaErr; 552 553 /* 554 * Obtain the device protocol subproperties. 555 */ 556 557 sub = CFDictionaryGetValue( properties, CFSTR( kIOPropertyProtocolCharacteristicsKey ) ); 558 559 if ( sub ) 560 { 561 /* 562 * Create the disk description -- device internal? 563 */ 564 565 object = CFDictionaryGetValue( sub, CFSTR( kIOPropertyPhysicalInterconnectLocationKey ) ); 566 567 if ( object ) 568 { 569 if ( CFStringCompare( object, CFSTR( kIOPropertyInternalKey ), 0 ) == 0 ) 570 { 571 object = kCFBooleanTrue; 572 573 CFDictionarySetValue( disk->_description, kDADiskDescriptionDeviceInternalKey, object ); 574 } 575 else if ( CFStringCompare( object, CFSTR( kIOPropertyExternalKey ), 0 ) == 0 ) 576 { 577 object = kCFBooleanFalse; 578 579 CFDictionarySetValue( disk->_description, kDADiskDescriptionDeviceInternalKey, object ); 580 } 581 } 582 583 /* 584 * Create the disk description -- device protocol. 585 */ 586 587 object = CFDictionaryGetValue( sub, CFSTR( kIOPropertyPhysicalInterconnectTypeKey ) ); 588 589 if ( object ) 590 { 591 CFDictionarySetValue( disk->_description, kDADiskDescriptionDeviceProtocolKey, object ); 592 } 593 } 594 595 /* 596 * Obtain the device model subproperties. 597 */ 598 599 sub = CFDictionaryGetValue( properties, CFSTR( kIOPropertyDeviceCharacteristicsKey ) ); 600 601 if ( sub ) 602 { 603 /* 604 * Create the disk description -- device model. 605 */ 606 607 object = CFDictionaryGetValue( sub, CFSTR( kIOPropertyProductNameKey ) ); 608 609 if ( object ) 610 { 611 CFDictionarySetValue( disk->_description, kDADiskDescriptionDeviceModelKey, object ); 612 } 613 614 /* 615 * Create the disk description -- device revision. 616 */ 617 618 object = CFDictionaryGetValue( sub, CFSTR( kIOPropertyProductRevisionLevelKey ) ); 619 620 if ( object ) 621 { 622 CFDictionarySetValue( disk->_description, kDADiskDescriptionDeviceRevisionKey, object ); 623 } 624 625 /* 626 * Create the disk description -- device vendor. 627 */ 628 629 object = CFDictionaryGetValue( sub, CFSTR( kIOPropertyVendorNameKey ) ); 630 631 if ( object ) 632 { 633 CFDictionarySetValue( disk->_description, kDADiskDescriptionDeviceVendorKey, object ); 634 } 635 } 636 637 /* 638 * Create the disk description -- device path. 639 */ 640 641 status = ___IORegistryEntryGetPath( device, kIOServicePlane, path ); 642 if ( status != KERN_SUCCESS ) goto DADiskCreateFromIOMediaErr; 643 644 object = CFStringCreateWithCString( allocator, path, kCFStringEncodingUTF8 ); 645 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 646 647 CFDictionarySetValue( disk->_description, kDADiskDescriptionDevicePathKey, object ); 648 CFRelease( object ); 649 650 /* 651 * Create the disk description -- device unit. 652 */ 653 654 object = IORegistryEntrySearchCFProperty( device, 655 kIOServicePlane, 656 CFSTR( "IOUnit" ), 657 allocator, 658 kIORegistryIterateParents | kIORegistryIterateRecursively ); 659 660 if ( object ) 661 { 662 CFDictionarySetValue( disk->_description, kDADiskDescriptionDeviceUnitKey, object ); 663 CFRelease( object ); 664 } 665 666 /* 667 * Create the disk description -- device GUID (IEEE EUI-64). 668 */ 669 670 object = IORegistryEntrySearchCFProperty( device, 671 kIOServicePlane, 672 CFSTR( "GUID" ), 673 allocator, 674 kIORegistryIterateParents | kIORegistryIterateRecursively ); 675 676 if ( object ) 677 { 678 UInt64 value; 679 680 CFNumberGetValue( object, kCFNumberSInt64Type, &value ); 681 CFRelease( object ); 682 683 value = OSSwapHostToBigInt64( value ); 684 685 object = CFDataCreate( allocator, ( void * ) &value, sizeof( value ) ); 686 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 687 688 CFDictionarySetValue( disk->_description, kDADiskDescriptionDeviceGUIDKey, object ); 689 CFRelease( object ); 690 } 691 692 CFRelease( properties ); 693 properties = NULL; 694 695 /* 696 * Obtain the bus object. 697 */ 698 699 status = IORegistryEntryCreateIterator( device, 700 kIOServicePlane, 701 kIORegistryIterateParents | kIORegistryIterateRecursively, 702 &services ); 703 704 while ( ( bus = IOIteratorNext( services ) ) ) 705 { 706 if ( IORegistryEntryInPlane( bus, kIODeviceTreePlane ) ) break; 707 708 IOObjectRelease( bus ); 709 } 710 711 IOObjectRelease( services ); 712 713 if ( bus ) 714 { 715 /* 716 * Create the disk description -- bus name. 717 */ 718 719 status = IORegistryEntryGetNameInPlane( bus, kIODeviceTreePlane, name ); 720 if ( status != KERN_SUCCESS ) goto DADiskCreateFromIOMediaErr; 721 722 object = CFStringCreateWithCString( allocator, name, kCFStringEncodingUTF8 ); 723 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 724 725 CFDictionarySetValue( disk->_description, kDADiskDescriptionBusNameKey, object ); 726 CFRelease( object ); 727 728 /* 729 * Create the disk description -- bus path. 730 */ 731 732 status = ___IORegistryEntryGetPath( bus, kIODeviceTreePlane, path ); 733 if ( status != KERN_SUCCESS ) goto DADiskCreateFromIOMediaErr; 734 735 object = CFStringCreateWithCString( allocator, path, kCFStringEncodingUTF8 ); 736 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 737 738 CFDictionarySetValue( disk->_description, kDADiskDescriptionBusPathKey, object ); 739 CFRelease( object ); 740 741 IOObjectRelease( bus ); 742 bus = IO_OBJECT_NULL; 743 } 744 745 /* 746 * Create the disk description -- appearance time. 747 */ 748 749 time = CFAbsoluteTimeGetCurrent( ); 750 751 object = CFNumberCreate( allocator, kCFNumberDoubleType, &time ); 752 if ( object == NULL ) goto DADiskCreateFromIOMediaErr; 753 754 CFDictionarySetValue( disk->_description, kDADiskDescriptionAppearanceTimeKey, object ); 755 CFRelease( object ); 756 757 /* 758 * Create the disk state -- busy? 759 */ 760 761 busy = 0; 762 763 IOServiceGetBusyState( media, &busy ); 764 765 if ( busy ) 766 { 767 disk->_busy = CFAbsoluteTimeGetCurrent( ); 768 } 769 770 /* 771 * Create the disk state -- mount automatic? 772 */ 773 774 object = IORegistryEntrySearchCFProperty( media, 775 kIOServicePlane, 776 CFSTR( "autodiskmount" ), 777 allocator, 778 kIORegistryIterateParents | kIORegistryIterateRecursively ); 779 780 if ( object == NULL ) 781 { 782 disk->_options |= kDADiskOptionMountAutomatic; 783 } 784 else if ( object == kCFBooleanTrue ) 785 { 786 disk->_options |= kDADiskOptionMountAutomatic | kDADiskOptionMountAutomaticNoDefer; 787 } 788 789 if ( object ) CFRelease( object ); 790 791 /* 792 * Create the disk state -- eject upon logout? 793 */ 794 795 object = IORegistryEntrySearchCFProperty( device, 796 kIOServicePlane, 797 CFSTR( "eject-upon-logout" ), 798 allocator, 799 kIORegistryIterateParents | kIORegistryIterateRecursively ); 800 801 if ( object == kCFBooleanTrue ) 802 { 803 disk->_options |= kDADiskOptionEjectUponLogout; 804 } 805 806 if ( object ) CFRelease( object ); 807 808 /* 809 * Create the disk state -- owner. 810 */ 811 812 object = IORegistryEntrySearchCFProperty( media, 813 kIOServicePlane, 814 CFSTR( "owner-uid" ), 815 allocator, 816 kIORegistryIterateParents | kIORegistryIterateRecursively ); 817 818 if ( object ) 819 { 820 if ( CFGetTypeID( object ) == CFNumberGetTypeID( ) ) 821 { 822 struct passwd * user; 823 int value; 824 825 CFNumberGetValue( object, kCFNumberIntType, &value ); 826 827 disk->_userUID = value; 828 829 user = getpwuid( value ); 830 831 if ( user ) 832 { 833 disk->_userGID = user->pw_gid; 834 } 835 } 836 837 CFRelease( object ); 838 } 839 840 object = IORegistryEntrySearchCFProperty( media, 841 kIOServicePlane, 842 CFSTR( "owner-gid" ), 843 allocator, 844 kIORegistryIterateParents | kIORegistryIterateRecursively ); 845 846 if ( object ) 847 { 848 if ( CFGetTypeID( object ) == CFNumberGetTypeID( ) ) 849 { 850 int value; 851 852 CFNumberGetValue( object, kCFNumberIntType, &value ); 853 854 disk->_userGID = value; 855 } 856 857 CFRelease( object ); 858 } 859 860 object = IORegistryEntrySearchCFProperty( media, 861 kIOServicePlane, 862 CFSTR( "owner-mode" ), 863 allocator, 864 kIORegistryIterateParents | kIORegistryIterateRecursively ); 865 866 if ( object ) 867 { 868 if ( CFGetTypeID( object ) == CFNumberGetTypeID( ) ) 869 { 870 int value; 871 872 CFNumberGetValue( object, kCFNumberIntType, &value ); 873 874 disk->_mode = value; 875 } 876 877 CFRelease( object ); 878 } 879 880 /* 881 * Create the disk state -- media BSD link. 882 */ 883 884 object = IORegistryEntrySearchCFProperty( media, 885 kIOServicePlane, 886 CFSTR( "dev-name" ), 887 allocator, 888 0 ); 889 890 if ( object ) 891 { 892 if ( CFGetTypeID( object ) == CFStringGetTypeID( ) ) 893 { 894 if ( CFStringGetCString( object, name, sizeof( name ), kCFStringEncodingUTF8 ) ) 895 { 896 strlcpy( path, _PATH_DEV, sizeof( path ) ); 897 strlcat( path, name, sizeof( path ) ); 898 899 disk->_deviceLink[0] = strdup( path ); 900 901 strlcpy( path, _PATH_DEV, sizeof( path ) ); 902 strlcat( path, "r", sizeof( path ) ); 903 strlcat( path, name, sizeof( path ) ); 904 905 disk->_deviceLink[1] = strdup( path ); 906 } 907 } 908 909 CFRelease( object ); 910 } 911 912 IOObjectRelease( device ); 913 914 return disk; 915 916DADiskCreateFromIOMediaErr: 917 918 if ( ___IORegistryEntryGetPath( media, kIOServicePlane, path ) == KERN_SUCCESS ) 919 { 920 DALogError( "unable to create disk, id = %s.", disk ? DADiskGetID( disk ) : NULL ); 921 } 922 923 if ( bus ) IOObjectRelease( bus ); 924 if ( device ) IOObjectRelease( device ); 925 if ( disk ) CFRelease( disk ); 926 if ( properties ) CFRelease( properties ); 927 928 return NULL; 929} 930 931DADiskRef DADiskCreateFromVolumePath( CFAllocatorRef allocator, const struct statfs * fs ) 932{ 933 DADiskRef disk; 934 935 disk = NULL; 936 937 if ( fs ) 938 { 939 CFURLRef path; 940 941 path = CFURLCreateFromFileSystemRepresentation( kCFAllocatorDefault, ( void * ) fs->f_mntonname, strlen( fs->f_mntonname ), TRUE ); 942 943 if ( path ) 944 { 945 CFStringRef kind; 946 947 kind = CFStringCreateWithCString( kCFAllocatorDefault, fs->f_fstypename, kCFStringEncodingUTF8 ); 948 949 if ( kind ) 950 { 951 char * id; 952 953 id = _DAVolumeCopyID( fs ); 954 955 if ( id ) 956 { 957 CFTypeRef object; 958 959 disk = __DADiskCreate( allocator, id ); 960 961 if ( disk ) 962 { 963 struct passwd * user; 964 965 disk->_bypath = CFRetain( path ); 966 967 CFDictionarySetValue( disk->_description, kDADiskDescriptionVolumePathKey, path ); 968 969 CFDictionarySetValue( disk->_description, kDADiskDescriptionVolumeMountableKey, kCFBooleanTrue ); 970 971 CFDictionarySetValue( disk->_description, kDADiskDescriptionVolumeKindKey, kind ); 972 973 object = _DAFileSystemCopyName( NULL, path ); 974 975 if ( object ) 976 { 977 CFDictionarySetValue( disk->_description, kDADiskDescriptionVolumeNameKey, object ); 978 979 CFRelease( object ); 980 } 981 982 if ( ( fs->f_flags & MNT_LOCAL ) ) 983 { 984 CFDictionarySetValue( disk->_description, kDADiskDescriptionVolumeNetworkKey, kCFBooleanFalse ); 985 } 986 else 987 { 988 CFDictionarySetValue( disk->_description, kDADiskDescriptionVolumeNetworkKey, kCFBooleanTrue ); 989 } 990 991 disk->_options |= kDADiskOptionMountAutomatic; 992 disk->_options |= kDADiskOptionMountAutomaticNoDefer; 993 994 disk->_state |= kDADiskStateStagedProbe; 995 disk->_state |= kDADiskStateStagedPeek; 996 disk->_state |= kDADiskStateStagedApprove; 997 disk->_state |= kDADiskStateStagedAuthorize; 998 disk->_state |= kDADiskStateStagedMount; 999 1000 disk->_userUID = fs->f_owner; 1001 1002 user = getpwuid( fs->f_owner ); 1003 1004 if ( user ) 1005 { 1006 disk->_userGID = user->pw_gid; 1007 } 1008 } 1009 1010 free( id ); 1011 } 1012 1013 CFRelease( kind ); 1014 } 1015 1016 CFRelease( path ); 1017 } 1018 } 1019 1020 return disk; 1021} 1022 1023CFAbsoluteTime DADiskGetBusy( DADiskRef disk ) 1024{ 1025 return disk->_busy; 1026} 1027 1028io_object_t DADiskGetBusyNotification( DADiskRef disk ) 1029{ 1030 return disk->_busyNotification; 1031} 1032 1033CFURLRef DADiskGetBypath( DADiskRef disk ) 1034{ 1035 return disk->_bypath; 1036} 1037 1038const char * DADiskGetBSDLink( DADiskRef disk, Boolean raw ) 1039{ 1040 return disk->_deviceLink[ raw ? 1 : 0 ]; 1041} 1042 1043dev_t DADiskGetBSDNode( DADiskRef disk ) 1044{ 1045 return disk->_deviceNode; 1046} 1047 1048const char * DADiskGetBSDPath( DADiskRef disk, Boolean raw ) 1049{ 1050 return disk->_devicePath[ raw ? 1 : 0 ]; 1051} 1052 1053UInt32 DADiskGetBSDUnit( DADiskRef disk ) 1054{ 1055 return disk->_deviceUnit; 1056} 1057 1058DACallbackRef DADiskGetClaim( DADiskRef disk ) 1059{ 1060 return disk->_claim; 1061} 1062 1063CFTypeRef DADiskGetContext( DADiskRef disk ) 1064{ 1065 return disk->_context; 1066} 1067 1068CFTypeRef DADiskGetContextRe( DADiskRef disk ) 1069{ 1070 return disk->_contextRe; 1071} 1072 1073CFTypeRef DADiskGetDescription( DADiskRef disk, CFStringRef description ) 1074{ 1075 return CFDictionaryGetValue( disk->_description, description ); 1076} 1077 1078CFURLRef DADiskGetDevice( DADiskRef disk ) 1079{ 1080 return disk->_device; 1081} 1082 1083DAFileSystemRef DADiskGetFileSystem( DADiskRef disk ) 1084{ 1085 return disk->_filesystem; 1086} 1087 1088const char * DADiskGetID( DADiskRef disk ) 1089{ 1090 return disk->_id; 1091} 1092 1093io_service_t DADiskGetIOMedia( DADiskRef disk ) 1094{ 1095 return disk->_media; 1096} 1097 1098mode_t DADiskGetMode( DADiskRef disk ) 1099{ 1100 mode_t mode; 1101 1102 mode = disk->_mode; 1103 1104 if ( DADiskGetDescription( disk, kDADiskDescriptionMediaWritableKey ) == kCFBooleanFalse ) 1105 { 1106 mode &= 0555; 1107 } 1108 1109 return mode; 1110} 1111 1112Boolean DADiskGetOption( DADiskRef disk, DADiskOption option ) 1113{ 1114 return ( disk->_options & option ) ? TRUE : FALSE; 1115} 1116 1117DADiskOptions DADiskGetOptions( DADiskRef disk ) 1118{ 1119 return disk->_options; 1120} 1121 1122io_object_t DADiskGetPropertyNotification( DADiskRef disk ) 1123{ 1124 return disk->_propertyNotification; 1125} 1126 1127CFDataRef DADiskGetSerialization( DADiskRef disk ) 1128{ 1129 if ( disk->_serialization == NULL ) 1130 { 1131 disk->_serialization = _DASerializeDiskDescription( CFGetAllocator( disk ), disk->_description ); 1132 } 1133 1134 return disk->_serialization; 1135} 1136 1137Boolean DADiskGetState( DADiskRef disk, DADiskState state ) 1138{ 1139 return ( disk->_state & state ) ? TRUE : FALSE; 1140} 1141 1142CFTypeID DADiskGetTypeID( void ) 1143{ 1144 return __kDADiskTypeID; 1145} 1146 1147gid_t DADiskGetUserGID( DADiskRef disk ) 1148{ 1149 return disk->_userGID; 1150} 1151 1152uid_t DADiskGetUserUID( DADiskRef disk ) 1153{ 1154 return disk->_userUID; 1155} 1156 1157void DADiskInitialize( void ) 1158{ 1159 __kDADiskTypeID = _CFRuntimeRegisterClass( &__DADiskClass ); 1160} 1161 1162Boolean DADiskMatch( DADiskRef disk, CFDictionaryRef match ) 1163{ 1164 CFDictionaryApplyFunction( match, __DADiskMatch, &disk ); 1165 1166 return disk ? TRUE : FALSE; 1167} 1168 1169void DADiskSetBusy( DADiskRef disk, CFAbsoluteTime busy ) 1170{ 1171 disk->_busy = busy; 1172} 1173 1174void DADiskSetBusyNotification( DADiskRef disk, io_object_t notification ) 1175{ 1176 if ( disk->_busyNotification ) 1177 { 1178 IOObjectRelease( disk->_busyNotification ); 1179 1180 disk->_busyNotification = IO_OBJECT_NULL; 1181 } 1182 1183 if ( notification ) 1184 { 1185 IOObjectRetain( notification ); 1186 1187 disk->_busyNotification = notification; 1188 } 1189} 1190 1191void DADiskSetBypath( DADiskRef disk, CFURLRef bypath ) 1192{ 1193 if ( disk->_bypath ) 1194 { 1195 CFRelease( disk->_bypath ); 1196 1197 disk->_bypath = NULL; 1198 } 1199 1200 if ( bypath ) 1201 { 1202 CFRetain( bypath ); 1203 1204 disk->_bypath = bypath; 1205 } 1206} 1207 1208void DADiskSetBSDLink( DADiskRef disk, Boolean raw, const char * link ) 1209{ 1210 if ( disk->_deviceLink[ raw ? 1 : 0 ] ) 1211 { 1212 free( disk->_deviceLink[ raw ? 1 : 0 ] ); 1213 1214 disk->_deviceLink[ raw ? 1 : 0 ] = NULL; 1215 } 1216 1217 if ( link ) 1218 { 1219 disk->_deviceLink[ raw ? 1 : 0 ] = strdup( link ); 1220 } 1221} 1222 1223void DADiskSetClaim( DADiskRef disk, DACallbackRef claim ) 1224{ 1225 if ( disk->_claim ) 1226 { 1227 CFRelease( disk->_claim ); 1228 1229 disk->_claim = NULL; 1230 } 1231 1232 if ( claim ) 1233 { 1234 CFRetain( claim ); 1235 1236 disk->_claim = claim; 1237 } 1238} 1239 1240void DADiskSetContext( DADiskRef disk, CFTypeRef context ) 1241{ 1242 if ( disk->_context ) 1243 { 1244 CFRelease( disk->_context ); 1245 1246 disk->_context = NULL; 1247 } 1248 1249 if ( context ) 1250 { 1251 CFRetain( context ); 1252 1253 disk->_context = context; 1254 } 1255} 1256 1257void DADiskSetContextRe( DADiskRef disk, CFTypeRef context ) 1258{ 1259 if ( disk->_contextRe ) 1260 { 1261 CFRelease( disk->_contextRe ); 1262 1263 disk->_contextRe = NULL; 1264 } 1265 1266 if ( context ) 1267 { 1268 CFRetain( context ); 1269 1270 disk->_contextRe = context; 1271 } 1272} 1273 1274void DADiskSetDescription( DADiskRef disk, CFStringRef description, CFTypeRef value ) 1275{ 1276 if ( value ) 1277 { 1278 CFDictionarySetValue( disk->_description, description, value ); 1279 } 1280 else 1281 { 1282 CFDictionaryRemoveValue( disk->_description, description ); 1283 } 1284 1285 if ( disk->_serialization ) 1286 { 1287 CFRelease( disk->_serialization ); 1288 1289 disk->_serialization = NULL; 1290 } 1291} 1292 1293void DADiskSetFileSystem( DADiskRef disk, DAFileSystemRef filesystem ) 1294{ 1295 if ( disk->_filesystem ) 1296 { 1297 CFRelease( disk->_filesystem ); 1298 1299 disk->_filesystem = NULL; 1300 } 1301 1302 if ( filesystem ) 1303 { 1304 CFRetain( filesystem ); 1305 1306 disk->_filesystem = filesystem; 1307 } 1308} 1309 1310void DADiskSetOption( DADiskRef disk, DADiskOption option, Boolean value ) 1311{ 1312 DADiskSetOptions( disk, option, value ); 1313} 1314 1315void DADiskSetOptions( DADiskRef disk, DADiskOptions options, Boolean value ) 1316{ 1317 disk->_options &= ~options; 1318 disk->_options |= value ? options : 0; 1319} 1320 1321void DADiskSetPropertyNotification( DADiskRef disk, io_object_t notification ) 1322{ 1323 if ( disk->_propertyNotification ) 1324 { 1325 IOObjectRelease( disk->_propertyNotification ); 1326 1327 disk->_propertyNotification = IO_OBJECT_NULL; 1328 } 1329 1330 if ( notification ) 1331 { 1332 IOObjectRetain( notification ); 1333 1334 disk->_propertyNotification = notification; 1335 } 1336} 1337 1338void DADiskSetState( DADiskRef disk, DADiskState state, Boolean value ) 1339{ 1340 disk->_state &= ~state; 1341 disk->_state |= value ? state : 0; 1342} 1343