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