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 <IOKit/IODeviceTreeSupport.h> 25#include <IOKit/IOMessage.h> 26#include <IOKit/storage/IOPartitionScheme.h> 27 28#define super IOStorage 29OSDefineMetaClassAndStructors(IOPartitionScheme, IOStorage) 30 31#ifndef __LP64__ 32extern IOStorageAttributes gIOStorageAttributesUnsupported; 33#endif /* !__LP64__ */ 34 35static SInt32 partitionComparison( const OSMetaClassBase * object1, 36 const OSMetaClassBase * object2, 37 void * context ) 38{ 39 // 40 // Internal comparison routine for sorting partitions in an ordered set. 41 // 42 43 UInt64 base1 = ( ( IOMedia * ) object1 )->getBase( ); 44 UInt64 base2 = ( ( IOMedia * ) object2 )->getBase( ); 45 46#if TARGET_OS_EMBEDDED 47 OSString * uuid1 = OSDynamicCast( OSString, ( ( IOMedia * ) object1 )->getProperty( kIOMediaUUIDKey ) ); 48 OSString * uuid2 = OSDynamicCast( OSString, ( ( IOMedia * ) object2 )->getProperty( kIOMediaUUIDKey ) ); 49 50 if ( uuid1 || uuid2 ) 51 { 52 if ( uuid1 == 0 ) return -1; 53 if ( uuid2 == 0 ) return 1; 54 55 return strcmp( uuid2->getCStringNoCopy( ), uuid1->getCStringNoCopy( ) ); 56 } 57#endif /* TARGET_OS_EMBEDDED */ 58 59 if ( base1 < base2 ) return 1; 60 if ( base1 > base2 ) return -1; 61 62 return 0; 63} 64 65IOMedia * IOPartitionScheme::getProvider() const 66{ 67 // 68 // Obtain this object's provider. We override the superclass's method 69 // to return a more specific subclass of OSObject -- an IOMedia. This 70 // method serves simply as a convenience to subclass developers. 71 // 72 73 return (IOMedia *) IOService::getProvider(); 74} 75 76bool IOPartitionScheme::init(OSDictionary * properties) 77{ 78 // 79 // Initialize this object's minimal state. 80 // 81 82 if (super::init(properties) == false) return false; 83 84 _openLevel = kIOStorageAccessNone; 85 _openReaders = OSSet::withCapacity(16); 86 _openReaderWriters = OSSet::withCapacity(16); 87 88 if (_openReaders == 0 || _openReaderWriters == 0) return false; 89 90 return true; 91} 92 93void IOPartitionScheme::free() 94{ 95 // 96 // Free all of this object's outstanding resources. 97 // 98 99 if (_openReaders) _openReaders->release(); 100 if (_openReaderWriters) _openReaderWriters->release(); 101 102 super::free(); 103} 104 105bool IOPartitionScheme::handleOpen(IOService * client, 106 IOOptionBits options, 107 void * argument) 108{ 109 // 110 // The handleOpen method grants or denies permission to access this object 111 // to an interested client. The argument is an IOStorageAccess value that 112 // specifies the level of access desired -- reader or reader-writer. 113 // 114 // This method can be invoked to upgrade or downgrade the access level for 115 // an existing client as well. The previous access level will prevail for 116 // upgrades that fail, of course. A downgrade should never fail. If the 117 // new access level should be the same as the old for a given client, this 118 // method will do nothing and return success. In all cases, one, singular 119 // close-per-client is expected for all opens-per-client received. 120 // 121 // This implementation replaces the IOService definition of handleOpen(). 122 // 123 // We are guaranteed that no other opens or closes will be processed until 124 // we make our decision, change our state, and return from this method. 125 // 126 127 IOStorageAccess access = (uintptr_t) argument; 128 IOStorageAccess level; 129 130 assert(client); 131 assert( access == kIOStorageAccessReader || 132 access == kIOStorageAccessReaderWriter ); 133 134 // 135 // A partition scheme multiplexes the opens it receives from several clients 136 // and sends one open to the level below that satisfies the highest level of 137 // access. 138 // 139 140 unsigned writers = _openReaderWriters->getCount(); 141 142 if (_openReaderWriters->containsObject(client)) writers--; 143 if (access == kIOStorageAccessReaderWriter) writers++; 144 145 level = (writers) ? kIOStorageAccessReaderWriter : kIOStorageAccessReader; 146 147 // 148 // Determine whether the levels below us accept this open or not (we avoid 149 // the open if the required access is the access we already hold). 150 // 151 152 if ( _openLevel != level ) 153 { 154 IOStorage * provider; 155 156 provider = OSDynamicCast( IOStorage, getProvider( ) ); 157 158 if ( provider ) 159 { 160 bool success; 161 162 level = ( level | kIOStorageAccessSharedLock ); 163 164 success = provider->open( this, options, level ); 165 166 level = ( level & kIOStorageAccessReaderWriter ); 167 168 if ( success == false ) 169 { 170 return false; 171 } 172 } 173 } 174 175 // 176 // Process the open. 177 // 178 179 if (access == kIOStorageAccessReader) 180 { 181 _openReaders->setObject(client); 182 183 _openReaderWriters->removeObject(client); // (for a downgrade) 184 } 185 else // (access == kIOStorageAccessReaderWriter) 186 { 187 _openReaderWriters->setObject(client); 188 189 _openReaders->removeObject(client); // (for an upgrade) 190 } 191 192 _openLevel = level; 193 194 return true; 195} 196 197bool IOPartitionScheme::handleIsOpen(const IOService * client) const 198{ 199 // 200 // The handleIsOpen method determines whether the specified client, or any 201 // client if none is specificed, presently has an open on this object. 202 // 203 // This implementation replaces the IOService definition of handleIsOpen(). 204 // 205 // We are guaranteed that no other opens or closes will be processed until 206 // we return from this method. 207 // 208 209 if (client == 0) return (_openLevel != kIOStorageAccessNone); 210 211 return ( _openReaderWriters->containsObject(client) || 212 _openReaders->containsObject(client) ); 213} 214 215void IOPartitionScheme::handleClose(IOService * client, IOOptionBits options) 216{ 217 // 218 // The handleClose method closes the client's access to this object. 219 // 220 // This implementation replaces the IOService definition of handleClose(). 221 // 222 // We are guaranteed that no other opens or closes will be processed until 223 // we change our state and return from this method. 224 // 225 226 assert(client); 227 228 // 229 // Process the close. 230 // 231 232 if (_openReaderWriters->containsObject(client)) // (is it a reader-writer?) 233 { 234 _openReaderWriters->removeObject(client); 235 } 236 else if (_openReaders->containsObject(client)) // (is the client a reader?) 237 { 238 _openReaders->removeObject(client); 239 } 240 else // (is the client is an imposter?) 241 { 242 assert(0); 243 return; 244 } 245 246 // 247 // Reevaluate the open we have on the level below us. If no opens remain, 248 // we close, or if no reader-writer remains, but readers do, we downgrade. 249 // 250 251 IOStorageAccess level; 252 253 if (_openReaderWriters->getCount()) level = kIOStorageAccessReaderWriter; 254 else if (_openReaders->getCount()) level = kIOStorageAccessReader; 255 else level = kIOStorageAccessNone; 256 257 if ( _openLevel != level ) 258 { 259 IOStorage * provider; 260 261 provider = OSDynamicCast( IOStorage, getProvider( ) ); 262 263 if ( provider ) 264 { 265 if ( level == kIOStorageAccessNone ) 266 { 267 provider->close( this, options ); 268 } 269 else 270 { 271 bool success; 272 273 level = ( level | kIOStorageAccessSharedLock ); 274 275 success = provider->open( this, 0, level ); 276 277 level = ( level & kIOStorageAccessReaderWriter ); 278 279 assert( success ); 280 } 281 } 282 283 _openLevel = level; 284 } 285} 286 287void IOPartitionScheme::read(IOService * client, 288 UInt64 byteStart, 289 IOMemoryDescriptor * buffer, 290 IOStorageAttributes * attributes, 291 IOStorageCompletion * completion) 292{ 293 // 294 // Read data from the storage object at the specified byte offset into the 295 // specified buffer, asynchronously. When the read completes, the caller 296 // will be notified via the specified completion action. 297 // 298 // The buffer will be retained for the duration of the read. 299 // 300 // For simple partition schemes, the default behavior is to simply pass the 301 // read through to the provider media. More complex partition schemes such 302 // as RAID will need to do extra processing here. 303 // 304 305#ifndef __LP64__ 306 if ( IOStorage::_expansionData ) 307 { 308 if ( attributes == &gIOStorageAttributesUnsupported ) 309 { 310 attributes = NULL; 311 } 312 else 313 { 314 IOStorage::read( client, byteStart, buffer, attributes, completion ); 315 316 return; 317 } 318 } 319#endif /* !__LP64__ */ 320 321 getProvider( )->read( this, byteStart, buffer, attributes, completion ); 322} 323 324void IOPartitionScheme::write(IOService * client, 325 UInt64 byteStart, 326 IOMemoryDescriptor * buffer, 327 IOStorageAttributes * attributes, 328 IOStorageCompletion * completion) 329{ 330 // 331 // Write data into the storage object at the specified byte offset from the 332 // specified buffer, asynchronously. When the write completes, the caller 333 // will be notified via the specified completion action. 334 // 335 // The buffer will be retained for the duration of the write. 336 // 337 // For simple partition schemes, the default behavior is to simply pass the 338 // write through to the provider media. More complex partition schemes such 339 // as RAID will need to do extra processing here. 340 // 341 342#ifndef __LP64__ 343 if ( IOStorage::_expansionData ) 344 { 345 if ( attributes == &gIOStorageAttributesUnsupported ) 346 { 347 attributes = NULL; 348 } 349 else 350 { 351 IOStorage::write( client, byteStart, buffer, attributes, completion ); 352 353 return; 354 } 355 } 356#endif /* !__LP64__ */ 357 358 getProvider( )->write( this, byteStart, buffer, attributes, completion ); 359} 360 361IOReturn IOPartitionScheme::synchronizeCache(IOService * client) 362{ 363 // 364 // Flush the cached data in the storage object, if any, synchronously. 365 // 366 367 return getProvider()->synchronizeCache(this); 368} 369 370IOReturn IOPartitionScheme::unmap(IOService * client, 371 IOStorageExtent * extents, 372 UInt32 extentsCount, 373 UInt32 options) 374{ 375 // 376 // Delete unused data from the storage object at the specified byte offsets, 377 // synchronously. 378 // 379 380 return getProvider( )->unmap( this, extents, extentsCount, options ); 381} 382 383bool IOPartitionScheme::lockPhysicalExtents(IOService * client) 384{ 385 // 386 // Lock the contents of the storage object against relocation temporarily, 387 // for the purpose of getting physical extents. 388 // 389 390 return getProvider( )->lockPhysicalExtents( this ); 391} 392 393IOStorage * IOPartitionScheme::copyPhysicalExtent(IOService * client, 394 UInt64 * byteStart, 395 UInt64 * byteCount) 396{ 397 // 398 // Convert the specified byte offset into a physical byte offset, relative 399 // to a physical storage object. This call should only be made within the 400 // context of lockPhysicalExtents(). 401 // 402 403 return getProvider( )->copyPhysicalExtent( this, byteStart, byteCount ); 404} 405 406void IOPartitionScheme::unlockPhysicalExtents(IOService * client) 407{ 408 // 409 // Unlock the contents of the storage object for relocation again. This 410 // call must balance a successful call to lockPhysicalExtents(). 411 // 412 413 getProvider( )->unlockPhysicalExtents( this ); 414} 415 416#ifdef __LP64__ 417bool IOPartitionScheme::attachMediaObjectToDeviceTree(IOMedia * media) 418#else /* !__LP64__ */ 419bool IOPartitionScheme::attachMediaObjectToDeviceTree(IOMedia * media, 420 IOOptionBits options) 421#endif /* !__LP64__ */ 422{ 423 // 424 // Attach the given media object to the device tree plane. 425 // 426 427 IORegistryEntry * parent = this; 428 429 while ( (parent = parent->getParentEntry(gIOServicePlane)) ) 430 { 431 if ( parent->inPlane(gIODTPlane) ) 432 { 433 char location[ 32 ]; 434 const char * locationOfParent = parent->getLocation(gIODTPlane); 435 const char * nameOfParent = parent->getName(gIODTPlane); 436 437 if ( locationOfParent == 0 ) break; 438 439 if ( OSDynamicCast(IOMedia, parent) == 0 ) break; 440 441 parent = parent->getParentEntry(gIODTPlane); 442 443 if ( parent == 0 ) break; 444 445 if ( media->attachToParent(parent, gIODTPlane) == false ) break; 446 447 strlcpy(location, locationOfParent, sizeof(location)); 448 if ( strchr(location, ':') ) *(strchr(location, ':') + 1) = 0; 449 strlcat(location, media->getLocation(), sizeof(location) - strlen(location)); 450 media->setLocation(location, gIODTPlane); 451 media->setName(nameOfParent, gIODTPlane); 452 453 return true; 454 } 455 } 456 457 return false; 458} 459 460#ifdef __LP64__ 461void IOPartitionScheme::detachMediaObjectFromDeviceTree(IOMedia * media) 462#else /* !__LP64__ */ 463void IOPartitionScheme::detachMediaObjectFromDeviceTree(IOMedia * media, 464 IOOptionBits options) 465#endif /* !__LP64__ */ 466{ 467 // 468 // Detach the given media object from the device tree plane. 469 // 470 471 IORegistryEntry * parent; 472 473 if ( (parent = media->getParentEntry(gIODTPlane)) ) 474 { 475 media->detachFromParent(parent, gIODTPlane); 476 } 477} 478 479OSSet * IOPartitionScheme::juxtaposeMediaObjects(OSSet * partitionsOld, 480 OSSet * partitionsNew) 481{ 482 // 483 // Updates a set of existing partitions, represented by partitionsOld, 484 // with possible updates from a rescan of the disk, represented by 485 // partitionsNew. It returns a new set of partitions with the results, 486 // removing partitions from partitionsOld where applicable, adding 487 // partitions from partitionsNew where applicable, and folding in property 488 // changes to partitions from partitionsNew into partitionsOld where 489 // applicable. 490 // 491 492 OSIterator * iterator = 0; 493 OSIterator * iterator1 = 0; 494 OSIterator * iterator2 = 0; 495 OSSymbol * key; 496 OSSet * keys = 0; 497 IOMedia * partition; 498 IOMedia * partition1; 499 IOMedia * partition2; 500 OSSet * partitions = 0; 501 OSOrderedSet * partitions1 = 0; 502 OSOrderedSet * partitions2 = 0; 503 UInt32 partitionID = 0; 504 OSDictionary * properties; 505 506 // Allocate a set to hold the set of media objects representing partitions. 507 508 partitions = OSSet::withCapacity( partitionsNew->getCapacity( ) ); 509 if ( partitions == 0 ) goto juxtaposeErr; 510 511 // Prepare the reference set of partitions. 512 513 partitions1 = OSOrderedSet::withCapacity( partitionsOld->getCapacity( ), partitionComparison, 0 ); 514 if ( partitions1 == 0 ) goto juxtaposeErr; 515 516 iterator1 = OSCollectionIterator::withCollection( partitionsOld ); 517 if ( iterator1 == 0 ) goto juxtaposeErr; 518 519 while ( ( partition1 = ( IOMedia * ) iterator1->getNextObject( ) ) ) 520 { 521 partitionID = max( partitionID, strtoul( partition1->getLocation( ), NULL, 10 ) ); 522 523 partitions1->setObject( partition1 ); 524 } 525 526 iterator1->release( ); 527 iterator1 = 0; 528 529 // Prepare the comparison set of partitions. 530 531 partitions2 = OSOrderedSet::withCapacity( partitionsNew->getCapacity( ), partitionComparison, 0 ); 532 if ( partitions2 == 0 ) goto juxtaposeErr; 533 534 iterator2 = OSCollectionIterator::withCollection( partitionsNew ); 535 if ( iterator2 == 0 ) goto juxtaposeErr; 536 537 while ( ( partition2 = ( IOMedia * ) iterator2->getNextObject( ) ) ) 538 { 539 partitionID = max( partitionID, strtoul( partition2->getLocation( ), NULL, 10 ) ); 540 541 partitions2->setObject( partition2 ); 542 } 543 544 iterator2->release( ); 545 iterator2 = 0; 546 547 // Juxtapose the partitions. 548 549 iterator1 = OSCollectionIterator::withCollection( partitions1 ); 550 if ( iterator1 == 0 ) goto juxtaposeErr; 551 552 iterator2 = OSCollectionIterator::withCollection( partitions2 ); 553 if ( iterator2 == 0 ) goto juxtaposeErr; 554 555 partition1 = ( IOMedia * ) iterator1->getNextObject( ); 556 partition2 = ( IOMedia * ) iterator2->getNextObject( ); 557 558 while ( partition1 || partition2 ) 559 { 560 UInt64 base1; 561 UInt64 base2; 562 563 base1 = partition1 ? partition1->getBase( ) : UINT64_MAX; 564 base2 = partition2 ? partition2->getBase( ) : UINT64_MAX; 565 566#if TARGET_OS_EMBEDDED 567 if ( partition1 && partition2 ) 568 { 569 OSString * uuid1; 570 OSString * uuid2; 571 572 uuid1 = OSDynamicCast( OSString, partition1->getProperty( kIOMediaUUIDKey ) ); 573 uuid2 = OSDynamicCast( OSString, partition2->getProperty( kIOMediaUUIDKey ) ); 574 575 if ( uuid1 || uuid2 ) 576 { 577 if ( uuid1 == 0 ) 578 { 579 base1 = UINT64_MAX; 580 } 581 else if ( uuid2 == 0 ) 582 { 583 base2 = UINT64_MAX; 584 } 585 else 586 { 587 int compare; 588 589 compare = strcmp( uuid1->getCStringNoCopy( ), uuid2->getCStringNoCopy( ) ); 590 591 if ( compare > 0 ) 592 { 593 base1 = UINT64_MAX; 594 } 595 else if ( compare < 0 ) 596 { 597 base2 = UINT64_MAX; 598 } 599 else 600 { 601 base1 = base2; 602 } 603 } 604 } 605 } 606#endif /* TARGET_OS_EMBEDDED */ 607 608 if ( base1 > base2 ) 609 { 610 // A partition was added. 611 612 partition2->setProperty( kIOMediaLiveKey, true ); 613 614 iterator = OSCollectionIterator::withCollection( partitions1 ); 615 if ( iterator == 0 ) goto juxtaposeErr; 616 617 while ( ( partition = ( IOMedia * ) iterator->getNextObject( ) ) ) 618 { 619 if ( strcmp( partition->getLocation( ), partition2->getLocation( ) ) == 0 ) 620 { 621 // Set a location value for this partition. 622 623 char location[ 12 ]; 624 625 partitionID++; 626 627 snprintf( location, sizeof( location ), "%d", ( int ) partitionID ); 628 629 partition2->setLocation( location ); 630 631 partition2->setProperty( kIOMediaLiveKey, false ); 632 633 break; 634 } 635 } 636 637 iterator->release( ); 638 iterator = 0; 639 640 if ( partition2->attach( this ) ) 641 { 642 attachMediaObjectToDeviceTree( partition2 ); 643 644 partition2->registerService( kIOServiceAsynchronous ); 645 } 646 647 partitions->setObject( partition2 ); 648 649 partition2 = ( IOMedia * ) iterator2->getNextObject( ); 650 } 651 else if ( base1 < base2 ) 652 { 653 // A partition was removed. 654 655 partition1->setProperty( kIOMediaLiveKey, false ); 656 657 if ( handleIsOpen( partition1 ) == false ) 658 { 659 partition1->terminate( kIOServiceSynchronous ); 660 661 detachMediaObjectFromDeviceTree( partition1 ); 662 } 663 else 664 { 665 partition1->removeProperty( kIOMediaPartitionIDKey ); 666 667 partitions->setObject( partition1 ); 668 } 669 670 partition1 = ( IOMedia * ) iterator1->getNextObject( ); 671 } 672 else 673 { 674 // A partition was matched. 675 676 bool edit; 677 bool move; 678 679 edit = false; 680 move = false; 681 682 keys = OSSet::withCapacity( 1 ); 683 if ( keys == 0 ) goto juxtaposeErr; 684 685 properties = partition2->getPropertyTable( ); 686 687 // Determine which properties were updated. 688 689 if ( partition1->getBase( ) != partition2->getBase( ) || 690 partition1->getSize( ) != partition2->getSize( ) || 691 partition1->getPreferredBlockSize( ) != partition2->getPreferredBlockSize( ) || 692 partition1->getAttributes( ) != partition2->getAttributes( ) || 693 partition1->isWhole( ) != partition2->isWhole( ) || 694 partition1->isWritable( ) != partition2->isWritable( ) || 695 strcmp( partition1->getContentHint( ), partition2->getContentHint( ) ) ) 696 { 697 edit = true; 698 } 699 700 if ( strcmp( partition1->getName( ), partition2->getName( ) ) || 701 strcmp( partition1->getLocation( ), partition2->getLocation( ) ) ) 702 { 703 move = true; 704 } 705 706 iterator = OSCollectionIterator::withCollection( properties ); 707 if ( iterator == 0 ) goto juxtaposeErr; 708 709 while ( ( key = ( OSSymbol * ) iterator->getNextObject( ) ) ) 710 { 711 OSObject * value1; 712 OSObject * value2; 713 714 if ( key->isEqualTo( kIOMediaContentHintKey ) || 715 key->isEqualTo( kIOMediaEjectableKey ) || 716 key->isEqualTo( kIOMediaPreferredBlockSizeKey ) || 717 key->isEqualTo( kIOMediaRemovableKey ) || 718 key->isEqualTo( kIOMediaSizeKey ) || 719 key->isEqualTo( kIOMediaWholeKey ) || 720 key->isEqualTo( kIOMediaWritableKey ) ) 721 { 722 continue; 723 } 724 725 if ( key->isEqualTo( kIOMediaContentKey ) || 726 key->isEqualTo( kIOMediaLeafKey ) || 727 key->isEqualTo( kIOMediaLiveKey ) || 728 key->isEqualTo( kIOMediaOpenKey ) ) 729 { 730 continue; 731 } 732 733 value1 = partition1->getProperty( key ); 734 value2 = partition2->getProperty( key ); 735 736 if ( value1 == 0 || value1->isEqualTo( value2 ) == false ) 737 { 738 keys->setObject( key ); 739 } 740 } 741 742 iterator->release( ); 743 iterator = 0; 744 745 // A partition was updated. 746 747 partition1->setProperty( kIOMediaLiveKey, ( move == false ) ); 748 749 if ( edit ) 750 { 751 partition1->init( partition2->getBase( ), 752 partition2->getSize( ), 753 partition2->getPreferredBlockSize( ), 754 partition2->getAttributes( ), 755 partition2->isWhole( ), 756 partition2->isWritable( ), 757 partition2->getContentHint( ) ); 758 } 759 760 if ( keys->getCount( ) ) 761 { 762 iterator = OSCollectionIterator::withCollection( keys ); 763 if ( iterator == 0 ) goto juxtaposeErr; 764 765 while ( ( key = ( OSSymbol * ) iterator->getNextObject( ) ) ) 766 { 767 partition1->setProperty( key, partition2->getProperty( key ) ); 768 } 769 770 iterator->release( ); 771 iterator = 0; 772 } 773 774 if ( edit || keys->getCount( ) ) 775 { 776 partition1->messageClients( kIOMessageServicePropertyChange ); 777 778 partition1->registerService( kIOServiceAsynchronous ); 779 } 780 781 keys->release( ); 782 keys = 0; 783 784 partitions->setObject( partition1 ); 785 786 partition1 = ( IOMedia * ) iterator1->getNextObject( ); 787 partition2 = ( IOMedia * ) iterator2->getNextObject( ); 788 } 789 } 790 791 // Release our resources. 792 793 iterator1->release( ); 794 iterator2->release( ); 795 partitions1->release( ); 796 partitions2->release( ); 797 798 return partitions; 799 800juxtaposeErr: 801 802 // Release our resources. 803 804 if ( iterator ) iterator->release( ); 805 if ( iterator1 ) iterator1->release( ); 806 if ( iterator2 ) iterator2->release( ); 807 if ( keys ) keys->release( ); 808 if ( partitions ) partitions->release( ); 809 if ( partitions1 ) partitions1->release( ); 810 if ( partitions2 ) partitions2->release( ); 811 812 return 0; 813} 814 815#ifdef __LP64__ 816OSMetaClassDefineReservedUnused(IOPartitionScheme, 0); 817OSMetaClassDefineReservedUnused(IOPartitionScheme, 1); 818OSMetaClassDefineReservedUnused(IOPartitionScheme, 2); 819#else /* !__LP64__ */ 820OSMetaClassDefineReservedUsed(IOPartitionScheme, 0); 821OSMetaClassDefineReservedUsed(IOPartitionScheme, 1); 822OSMetaClassDefineReservedUsed(IOPartitionScheme, 2); 823#endif /* !__LP64__ */ 824OSMetaClassDefineReservedUnused(IOPartitionScheme, 3); 825OSMetaClassDefineReservedUnused(IOPartitionScheme, 4); 826OSMetaClassDefineReservedUnused(IOPartitionScheme, 5); 827OSMetaClassDefineReservedUnused(IOPartitionScheme, 6); 828OSMetaClassDefineReservedUnused(IOPartitionScheme, 7); 829OSMetaClassDefineReservedUnused(IOPartitionScheme, 8); 830OSMetaClassDefineReservedUnused(IOPartitionScheme, 9); 831OSMetaClassDefineReservedUnused(IOPartitionScheme, 10); 832OSMetaClassDefineReservedUnused(IOPartitionScheme, 11); 833OSMetaClassDefineReservedUnused(IOPartitionScheme, 12); 834OSMetaClassDefineReservedUnused(IOPartitionScheme, 13); 835OSMetaClassDefineReservedUnused(IOPartitionScheme, 14); 836OSMetaClassDefineReservedUnused(IOPartitionScheme, 15); 837OSMetaClassDefineReservedUnused(IOPartitionScheme, 16); 838OSMetaClassDefineReservedUnused(IOPartitionScheme, 17); 839OSMetaClassDefineReservedUnused(IOPartitionScheme, 18); 840OSMetaClassDefineReservedUnused(IOPartitionScheme, 19); 841OSMetaClassDefineReservedUnused(IOPartitionScheme, 20); 842OSMetaClassDefineReservedUnused(IOPartitionScheme, 21); 843OSMetaClassDefineReservedUnused(IOPartitionScheme, 22); 844OSMetaClassDefineReservedUnused(IOPartitionScheme, 23); 845OSMetaClassDefineReservedUnused(IOPartitionScheme, 24); 846OSMetaClassDefineReservedUnused(IOPartitionScheme, 25); 847OSMetaClassDefineReservedUnused(IOPartitionScheme, 26); 848OSMetaClassDefineReservedUnused(IOPartitionScheme, 27); 849OSMetaClassDefineReservedUnused(IOPartitionScheme, 28); 850OSMetaClassDefineReservedUnused(IOPartitionScheme, 29); 851OSMetaClassDefineReservedUnused(IOPartitionScheme, 30); 852OSMetaClassDefineReservedUnused(IOPartitionScheme, 31); 853 854#ifndef __LP64__ 855extern "C" void _ZN17IOPartitionScheme4readEP9IOServiceyP18IOMemoryDescriptor19IOStorageCompletion( IOPartitionScheme * scheme, IOService * client, UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion ) 856{ 857 scheme->read( client, byteStart, buffer, NULL, &completion ); 858} 859 860extern "C" void _ZN17IOPartitionScheme5writeEP9IOServiceyP18IOMemoryDescriptor19IOStorageCompletion( IOPartitionScheme * scheme, IOService * client, UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion ) 861{ 862 scheme->write( client, byteStart, buffer, NULL, &completion ); 863} 864#endif /* !__LP64__ */ 865