1/* 2 * Copyright (c) 1998-2014 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 416IOReturn IOPartitionScheme::setPriority(IOService * client, 417 IOStorageExtent * extents, 418 UInt32 extentsCount, 419 IOStoragePriority priority) 420{ 421 // 422 // Reprioritize read or write requests at the specified byte offsets. 423 // 424 425 return getProvider( )->setPriority( this, extents, extentsCount, priority ); 426} 427 428#ifdef __LP64__ 429bool IOPartitionScheme::attachMediaObjectToDeviceTree(IOMedia * media) 430#else /* !__LP64__ */ 431bool IOPartitionScheme::attachMediaObjectToDeviceTree(IOMedia * media, 432 IOOptionBits options) 433#endif /* !__LP64__ */ 434{ 435 // 436 // Attach the given media object to the device tree plane. 437 // 438 439 IORegistryEntry * parent = this; 440 441 while ( (parent = parent->getParentEntry(gIOServicePlane)) ) 442 { 443 if ( parent->inPlane(gIODTPlane) ) 444 { 445 char location[ 32 ]; 446 const char * locationOfParent = parent->getLocation(gIODTPlane); 447 const char * nameOfParent = parent->getName(gIODTPlane); 448 449 if ( locationOfParent == 0 ) break; 450 451 if ( OSDynamicCast(IOMedia, parent) == 0 ) break; 452 453 parent = parent->getParentEntry(gIODTPlane); 454 455 if ( parent == 0 ) break; 456 457 if ( media->attachToParent(parent, gIODTPlane) == false ) break; 458 459 strlcpy(location, locationOfParent, sizeof(location)); 460 if ( strchr(location, ':') ) *(strchr(location, ':') + 1) = 0; 461 strlcat(location, media->getLocation(), sizeof(location) - strlen(location)); 462 media->setLocation(location, gIODTPlane); 463 media->setName(nameOfParent, gIODTPlane); 464 465 return true; 466 } 467 } 468 469 return false; 470} 471 472#ifdef __LP64__ 473void IOPartitionScheme::detachMediaObjectFromDeviceTree(IOMedia * media) 474#else /* !__LP64__ */ 475void IOPartitionScheme::detachMediaObjectFromDeviceTree(IOMedia * media, 476 IOOptionBits options) 477#endif /* !__LP64__ */ 478{ 479 // 480 // Detach the given media object from the device tree plane. 481 // 482 483 IORegistryEntry * parent; 484 485 if ( (parent = media->getParentEntry(gIODTPlane)) ) 486 { 487 media->detachFromParent(parent, gIODTPlane); 488 } 489} 490 491OSSet * IOPartitionScheme::juxtaposeMediaObjects(OSSet * partitionsOld, 492 OSSet * partitionsNew) 493{ 494 // 495 // Updates a set of existing partitions, represented by partitionsOld, 496 // with possible updates from a rescan of the disk, represented by 497 // partitionsNew. It returns a new set of partitions with the results, 498 // removing partitions from partitionsOld where applicable, adding 499 // partitions from partitionsNew where applicable, and folding in property 500 // changes to partitions from partitionsNew into partitionsOld where 501 // applicable. 502 // 503 504 OSIterator * iterator = 0; 505 OSIterator * iterator1 = 0; 506 OSIterator * iterator2 = 0; 507 OSSymbol * key; 508 OSSet * keys = 0; 509 IOMedia * partition; 510 IOMedia * partition1; 511 IOMedia * partition2; 512 OSSet * partitions = 0; 513 OSOrderedSet * partitions1 = 0; 514 OSOrderedSet * partitions2 = 0; 515 UInt32 partitionID = 0; 516 OSDictionary * properties; 517 518 // Allocate a set to hold the set of media objects representing partitions. 519 520 partitions = OSSet::withCapacity( partitionsNew->getCapacity( ) ); 521 if ( partitions == 0 ) goto juxtaposeErr; 522 523 // Prepare the reference set of partitions. 524 525 partitions1 = OSOrderedSet::withCapacity( partitionsOld->getCapacity( ), partitionComparison, 0 ); 526 if ( partitions1 == 0 ) goto juxtaposeErr; 527 528 iterator1 = OSCollectionIterator::withCollection( partitionsOld ); 529 if ( iterator1 == 0 ) goto juxtaposeErr; 530 531 while ( ( partition1 = ( IOMedia * ) iterator1->getNextObject( ) ) ) 532 { 533 partitionID = max( partitionID, strtoul( partition1->getLocation( ), NULL, 10 ) ); 534 535 partitions1->setObject( partition1 ); 536 } 537 538 iterator1->release( ); 539 iterator1 = 0; 540 541 // Prepare the comparison set of partitions. 542 543 partitions2 = OSOrderedSet::withCapacity( partitionsNew->getCapacity( ), partitionComparison, 0 ); 544 if ( partitions2 == 0 ) goto juxtaposeErr; 545 546 iterator2 = OSCollectionIterator::withCollection( partitionsNew ); 547 if ( iterator2 == 0 ) goto juxtaposeErr; 548 549 while ( ( partition2 = ( IOMedia * ) iterator2->getNextObject( ) ) ) 550 { 551 partitionID = max( partitionID, strtoul( partition2->getLocation( ), NULL, 10 ) ); 552 553 partitions2->setObject( partition2 ); 554 } 555 556 iterator2->release( ); 557 iterator2 = 0; 558 559 // Juxtapose the partitions. 560 561 iterator1 = OSCollectionIterator::withCollection( partitions1 ); 562 if ( iterator1 == 0 ) goto juxtaposeErr; 563 564 iterator2 = OSCollectionIterator::withCollection( partitions2 ); 565 if ( iterator2 == 0 ) goto juxtaposeErr; 566 567 partition1 = ( IOMedia * ) iterator1->getNextObject( ); 568 partition2 = ( IOMedia * ) iterator2->getNextObject( ); 569 570 while ( partition1 || partition2 ) 571 { 572 UInt64 base1; 573 UInt64 base2; 574 575 base1 = partition1 ? partition1->getBase( ) : UINT64_MAX; 576 base2 = partition2 ? partition2->getBase( ) : UINT64_MAX; 577 578#if TARGET_OS_EMBEDDED 579 if ( partition1 && partition2 ) 580 { 581 OSString * uuid1; 582 OSString * uuid2; 583 584 uuid1 = OSDynamicCast( OSString, partition1->getProperty( kIOMediaUUIDKey ) ); 585 uuid2 = OSDynamicCast( OSString, partition2->getProperty( kIOMediaUUIDKey ) ); 586 587 if ( uuid1 || uuid2 ) 588 { 589 if ( uuid1 == 0 ) 590 { 591 base1 = UINT64_MAX; 592 } 593 else if ( uuid2 == 0 ) 594 { 595 base2 = UINT64_MAX; 596 } 597 else 598 { 599 int compare; 600 601 compare = strcmp( uuid1->getCStringNoCopy( ), uuid2->getCStringNoCopy( ) ); 602 603 if ( compare > 0 ) 604 { 605 base1 = UINT64_MAX; 606 } 607 else if ( compare < 0 ) 608 { 609 base2 = UINT64_MAX; 610 } 611 else 612 { 613 base1 = base2; 614 } 615 } 616 } 617 } 618#endif /* TARGET_OS_EMBEDDED */ 619 620 if ( base1 > base2 ) 621 { 622 // A partition was added. 623 624 partition2->setProperty( kIOMediaLiveKey, true ); 625 626 iterator = OSCollectionIterator::withCollection( partitions1 ); 627 if ( iterator == 0 ) goto juxtaposeErr; 628 629 while ( ( partition = ( IOMedia * ) iterator->getNextObject( ) ) ) 630 { 631 if ( strcmp( partition->getLocation( ), partition2->getLocation( ) ) == 0 ) 632 { 633 // Set a location value for this partition. 634 635 char location[ 12 ]; 636 637 partitionID++; 638 639 snprintf( location, sizeof( location ), "%d", ( int ) partitionID ); 640 641 partition2->setLocation( location ); 642 643 partition2->setProperty( kIOMediaLiveKey, false ); 644 645 break; 646 } 647 } 648 649 iterator->release( ); 650 iterator = 0; 651 652 if ( partition2->attach( this ) ) 653 { 654 attachMediaObjectToDeviceTree( partition2 ); 655 656 partition2->registerService( kIOServiceAsynchronous ); 657 } 658 659 partitions->setObject( partition2 ); 660 661 partition2 = ( IOMedia * ) iterator2->getNextObject( ); 662 } 663 else if ( base1 < base2 ) 664 { 665 // A partition was removed. 666 667 partition1->setProperty( kIOMediaLiveKey, false ); 668 669 if ( handleIsOpen( partition1 ) == false ) 670 { 671 partition1->terminate( kIOServiceSynchronous ); 672 673 detachMediaObjectFromDeviceTree( partition1 ); 674 } 675 else 676 { 677 partition1->removeProperty( kIOMediaPartitionIDKey ); 678 679 partitions->setObject( partition1 ); 680 } 681 682 partition1 = ( IOMedia * ) iterator1->getNextObject( ); 683 } 684 else 685 { 686 // A partition was matched. 687 688 bool edit; 689 bool move; 690 691 edit = false; 692 move = false; 693 694 keys = OSSet::withCapacity( 1 ); 695 if ( keys == 0 ) goto juxtaposeErr; 696 697 properties = partition2->getPropertyTable( ); 698 699 // Determine which properties were updated. 700 701 if ( partition1->getBase( ) != partition2->getBase( ) || 702 partition1->getSize( ) != partition2->getSize( ) || 703 partition1->getPreferredBlockSize( ) != partition2->getPreferredBlockSize( ) || 704 partition1->getAttributes( ) != partition2->getAttributes( ) || 705 partition1->isWhole( ) != partition2->isWhole( ) || 706 partition1->isWritable( ) != partition2->isWritable( ) || 707 strcmp( partition1->getContentHint( ), partition2->getContentHint( ) ) ) 708 { 709 edit = true; 710 } 711 712 if ( strcmp( partition1->getName( ), partition2->getName( ) ) || 713 strcmp( partition1->getLocation( ), partition2->getLocation( ) ) ) 714 { 715 move = true; 716 } 717 718 iterator = OSCollectionIterator::withCollection( properties ); 719 if ( iterator == 0 ) goto juxtaposeErr; 720 721 while ( ( key = ( OSSymbol * ) iterator->getNextObject( ) ) ) 722 { 723 OSObject * value1; 724 OSObject * value2; 725 726 if ( key->isEqualTo( kIOMediaContentHintKey ) || 727 key->isEqualTo( kIOMediaEjectableKey ) || 728 key->isEqualTo( kIOMediaPreferredBlockSizeKey ) || 729 key->isEqualTo( kIOMediaRemovableKey ) || 730 key->isEqualTo( kIOMediaSizeKey ) || 731 key->isEqualTo( kIOMediaWholeKey ) || 732 key->isEqualTo( kIOMediaWritableKey ) ) 733 { 734 continue; 735 } 736 737 if ( key->isEqualTo( kIOMediaContentKey ) || 738 key->isEqualTo( kIOMediaLeafKey ) || 739 key->isEqualTo( kIOMediaLiveKey ) || 740 key->isEqualTo( kIOMediaOpenKey ) ) 741 { 742 continue; 743 } 744 745 value1 = partition1->getProperty( key ); 746 value2 = partition2->getProperty( key ); 747 748 if ( value1 == 0 || value1->isEqualTo( value2 ) == false ) 749 { 750 keys->setObject( key ); 751 } 752 } 753 754 iterator->release( ); 755 iterator = 0; 756 757 // A partition was updated. 758 759 partition1->setProperty( kIOMediaLiveKey, ( move == false ) ); 760 761 if ( edit ) 762 { 763 partition1->init( partition2->getBase( ), 764 partition2->getSize( ), 765 partition2->getPreferredBlockSize( ), 766 partition2->getAttributes( ), 767 partition2->isWhole( ), 768 partition2->isWritable( ), 769 partition2->getContentHint( ) ); 770 } 771 772 if ( keys->getCount( ) ) 773 { 774 iterator = OSCollectionIterator::withCollection( keys ); 775 if ( iterator == 0 ) goto juxtaposeErr; 776 777 while ( ( key = ( OSSymbol * ) iterator->getNextObject( ) ) ) 778 { 779 partition1->setProperty( key, partition2->getProperty( key ) ); 780 } 781 782 iterator->release( ); 783 iterator = 0; 784 } 785 786 if ( edit || keys->getCount( ) ) 787 { 788 partition1->messageClients( kIOMessageServicePropertyChange ); 789 790 partition1->registerService( kIOServiceAsynchronous ); 791 } 792 793 keys->release( ); 794 keys = 0; 795 796 partitions->setObject( partition1 ); 797 798 partition1 = ( IOMedia * ) iterator1->getNextObject( ); 799 partition2 = ( IOMedia * ) iterator2->getNextObject( ); 800 } 801 } 802 803 // Release our resources. 804 805 iterator1->release( ); 806 iterator2->release( ); 807 partitions1->release( ); 808 partitions2->release( ); 809 810 return partitions; 811 812juxtaposeErr: 813 814 // Release our resources. 815 816 if ( iterator ) iterator->release( ); 817 if ( iterator1 ) iterator1->release( ); 818 if ( iterator2 ) iterator2->release( ); 819 if ( keys ) keys->release( ); 820 if ( partitions ) partitions->release( ); 821 if ( partitions1 ) partitions1->release( ); 822 if ( partitions2 ) partitions2->release( ); 823 824 return 0; 825} 826 827#ifdef __LP64__ 828OSMetaClassDefineReservedUnused(IOPartitionScheme, 0); 829OSMetaClassDefineReservedUnused(IOPartitionScheme, 1); 830OSMetaClassDefineReservedUnused(IOPartitionScheme, 2); 831#else /* !__LP64__ */ 832OSMetaClassDefineReservedUsed(IOPartitionScheme, 0); 833OSMetaClassDefineReservedUsed(IOPartitionScheme, 1); 834OSMetaClassDefineReservedUsed(IOPartitionScheme, 2); 835#endif /* !__LP64__ */ 836OSMetaClassDefineReservedUnused(IOPartitionScheme, 3); 837OSMetaClassDefineReservedUnused(IOPartitionScheme, 4); 838OSMetaClassDefineReservedUnused(IOPartitionScheme, 5); 839OSMetaClassDefineReservedUnused(IOPartitionScheme, 6); 840OSMetaClassDefineReservedUnused(IOPartitionScheme, 7); 841OSMetaClassDefineReservedUnused(IOPartitionScheme, 8); 842OSMetaClassDefineReservedUnused(IOPartitionScheme, 9); 843OSMetaClassDefineReservedUnused(IOPartitionScheme, 10); 844OSMetaClassDefineReservedUnused(IOPartitionScheme, 11); 845OSMetaClassDefineReservedUnused(IOPartitionScheme, 12); 846OSMetaClassDefineReservedUnused(IOPartitionScheme, 13); 847OSMetaClassDefineReservedUnused(IOPartitionScheme, 14); 848OSMetaClassDefineReservedUnused(IOPartitionScheme, 15); 849OSMetaClassDefineReservedUnused(IOPartitionScheme, 16); 850OSMetaClassDefineReservedUnused(IOPartitionScheme, 17); 851OSMetaClassDefineReservedUnused(IOPartitionScheme, 18); 852OSMetaClassDefineReservedUnused(IOPartitionScheme, 19); 853OSMetaClassDefineReservedUnused(IOPartitionScheme, 20); 854OSMetaClassDefineReservedUnused(IOPartitionScheme, 21); 855OSMetaClassDefineReservedUnused(IOPartitionScheme, 22); 856OSMetaClassDefineReservedUnused(IOPartitionScheme, 23); 857OSMetaClassDefineReservedUnused(IOPartitionScheme, 24); 858OSMetaClassDefineReservedUnused(IOPartitionScheme, 25); 859OSMetaClassDefineReservedUnused(IOPartitionScheme, 26); 860OSMetaClassDefineReservedUnused(IOPartitionScheme, 27); 861OSMetaClassDefineReservedUnused(IOPartitionScheme, 28); 862OSMetaClassDefineReservedUnused(IOPartitionScheme, 29); 863OSMetaClassDefineReservedUnused(IOPartitionScheme, 30); 864OSMetaClassDefineReservedUnused(IOPartitionScheme, 31); 865 866#ifndef __LP64__ 867extern "C" void _ZN17IOPartitionScheme4readEP9IOServiceyP18IOMemoryDescriptor19IOStorageCompletion( IOPartitionScheme * scheme, IOService * client, UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion ) 868{ 869 scheme->read( client, byteStart, buffer, NULL, &completion ); 870} 871 872extern "C" void _ZN17IOPartitionScheme5writeEP9IOServiceyP18IOMemoryDescriptor19IOStorageCompletion( IOPartitionScheme * scheme, IOService * client, UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion ) 873{ 874 scheme->write( client, byteStart, buffer, NULL, &completion ); 875} 876#endif /* !__LP64__ */ 877