2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include <IOKit/assert.h>
24 #include <IOKit/IOBufferMemoryDescriptor.h>
25 #include <IOKit/IOLib.h>
26 #include <IOKit/storage/IOFDiskPartitionScheme.h>
27 #include <libkern/OSByteOrder.h>
29 #define super IOPartitionScheme
30 OSDefineMetaClassAndStructors(IOFDiskPartitionScheme
, IOPartitionScheme
);
32 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
35 // o the on-disk structure's fields are: 16-bit packed, little-endian formatted
36 // o the relsect and numsect block values assume the drive's natural block size
37 // o the relsect block value is:
38 // o for data partitions:
39 // o relative to the FDisk map that defines the partition
40 // o for extended partitions defined in the root-level FDisk map:
41 // o relative to the FDisk map that defines the partition (start of disk)
42 // o for extended partitions defined in a second-level or deeper FDisk map:
43 // o relative to the second-level FDisk map, regardless of depth
44 // o the valid extended partition types are: 0x05, 0x0F, 0x85
45 // o there should be no more than one extended partition defined per FDisk map
48 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
50 #define kIOFDiskPartitionSchemeContentTable "Content Table"
52 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
54 bool IOFDiskPartitionScheme::init(OSDictionary
* properties
= 0)
57 // Initialize this object's minimal state.
60 // State our assumptions.
62 assert(sizeof(fdisk_part
) == 16); // (compiler/platform check)
63 assert(sizeof(disk_blk0
) == 512); // (compiler/platform check)
65 // Ask our superclass' opinion.
67 if ( super::init(properties
) == false ) return false;
69 // Initialize our state.
76 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
78 void IOFDiskPartitionScheme::free()
81 // Free all of this object's outstanding resources.
84 if ( _partitions
) _partitions
->release();
89 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
91 IOService
* IOFDiskPartitionScheme::probe(IOService
* provider
, SInt32
* score
)
94 // Determine whether the provider media contains an FDisk partition map.
97 // State our assumptions.
99 assert(OSDynamicCast(IOMedia
, provider
));
101 // Ask our superclass' opinion.
103 if ( super::probe(provider
, score
) == 0 ) return 0;
105 // Scan the provider media for an FDisk partition map.
107 _partitions
= scan(score
);
109 // There might be an FDisk partition scheme on disk with boot code, but with
110 // no partitions defined. We don't consider this a match and return failure
113 if ( _partitions
&& _partitions
->getCount() == 0 )
115 _partitions
->release();
119 return ( _partitions
) ? this : 0;
122 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
124 bool IOFDiskPartitionScheme::start(IOService
* provider
)
127 // Publish the new media objects which represent our partitions.
131 OSIterator
* partitionIterator
;
133 // State our assumptions.
137 // Ask our superclass' opinion.
139 if ( super::start(provider
) == false ) return false;
141 // Attach and register the new media objects representing our partitions.
143 partitionIterator
= OSCollectionIterator::withCollection(_partitions
);
144 if ( partitionIterator
== 0 ) return false;
146 while ( (partition
= (IOMedia
*) partitionIterator
->getNextObject()) )
148 if ( partition
->attach(this) )
150 partition
->registerService();
154 partitionIterator
->release();
159 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
161 OSSet
* IOFDiskPartitionScheme::scan(SInt32
* score
)
164 // Scan the provider media for an FDisk partition map. Returns the set
165 // of media objects representing each of the partitions (the retain for
166 // the set is passed to the caller), or null should no partition map be
167 // found. The default probe score can be adjusted up or down, based on
168 // the confidence of the scan.
171 IOBufferMemoryDescriptor
* buffer
= 0;
172 UInt32 bufferSize
= 0;
173 UInt32 fdiskBlock
= 0;
174 UInt32 fdiskBlockExtn
= 0;
175 UInt32 fdiskBlockNext
= 0;
177 disk_blk0
* fdiskMap
= 0;
178 IOMedia
* media
= getProvider();
179 UInt64 mediaBlockSize
= media
->getPreferredBlockSize();
180 bool mediaIsOpen
= false;
181 OSSet
* partitions
= 0;
182 IOReturn status
= kIOReturnError
;
184 // Determine whether this media is formatted.
186 if ( media
->isFormatted() == false ) goto scanErr
;
188 // Determine whether this media has an appropriate block size.
190 if ( (mediaBlockSize
% sizeof(disk_blk0
)) ) goto scanErr
;
192 // Allocate a buffer large enough to hold one map, rounded to a media block.
194 bufferSize
= IORound(sizeof(disk_blk0
), mediaBlockSize
);
195 buffer
= IOBufferMemoryDescriptor::withCapacity(
196 /* capacity */ bufferSize
,
197 /* withDirection */ kIODirectionIn
);
198 if ( buffer
== 0 ) goto scanErr
;
200 // Allocate a set to hold the set of media objects representing partitions.
202 partitions
= OSSet::withCapacity(4);
203 if ( partitions
== 0 ) goto scanErr
;
205 // Open the media with read access.
207 mediaIsOpen
= media
->open(this, 0, kIOStorageAccessReader
);
208 if ( mediaIsOpen
== false ) goto scanErr
;
210 // Scan the media for FDisk partition map(s).
214 // Read the next FDisk map into our buffer.
216 ///m:2333367:workaround:commented:start
217 // status = media->read(this, fdiskBlock * mediaBlockSize, buffer);
218 ///m:2333367:workaround:commented:stop
219 ///m:2333367:workaround:added:start
220 status
= media
->IOStorage::read(this, fdiskBlock
* mediaBlockSize
, buffer
);
221 ///m:2333367:workaround:added:stop
222 if ( status
!= kIOReturnSuccess
) goto scanErr
;
224 fdiskMap
= (disk_blk0
*) buffer
->getBytesNoCopy();
226 // Determine whether the partition map signature is present.
228 if ( OSSwapLittleToHostInt16(fdiskMap
->signature
) != DISK_SIGNATURE
)
233 // Scan for valid partition entries in the partition map.
237 for ( unsigned index
= 0; index
< DISK_NPART
; index
++ )
239 // Determine whether this is an extended (vs. data) partition.
241 if ( isPartitionExtended(fdiskMap
->parts
+ index
) ) // (extended)
243 // If peer extended partitions exist, we accept only the first.
245 if ( fdiskBlockNext
== 0 ) // (no peer extended partition)
247 fdiskBlockNext
= fdiskBlockExtn
+
248 OSSwapLittleToHostInt32(
249 /* data */ fdiskMap
->parts
[index
].relsect
);
251 if ( fdiskBlockNext
* mediaBlockSize
>= media
->getSize() )
253 fdiskBlockNext
= 0; // (exceeds confines of media)
257 else if ( isPartitionUsed(fdiskMap
->parts
+ index
) ) // (data)
259 // Prepare this partition's ID.
261 fdiskID
= ( fdiskBlock
== 0 ) ? (index
+ 1) : (fdiskID
+ 1);
263 // Determine whether the partition is corrupt (fatal).
265 if ( isPartitionCorrupt(
266 /* partition */ fdiskMap
->parts
+ index
,
267 /* partitionID */ fdiskID
,
268 /* fdiskBlock */ fdiskBlock
) )
273 // Determine whether the partition is invalid (skipped).
275 if ( isPartitionInvalid(
276 /* partition */ fdiskMap
->parts
+ index
,
277 /* partitionID */ fdiskID
,
278 /* fdiskBlock */ fdiskBlock
) )
283 // Create a media object to represent this partition.
285 IOMedia
* newMedia
= instantiateMediaObject(
286 /* partition */ fdiskMap
->parts
+ index
,
287 /* partitionID */ fdiskID
,
288 /* fdiskBlock */ fdiskBlock
);
292 partitions
->setObject(newMedia
);
298 // Prepare for first extended partition, if any.
300 if ( fdiskBlock
== 0 )
302 fdiskID
= DISK_NPART
;
303 fdiskBlockExtn
= fdiskBlockNext
;
306 } while ( (fdiskBlock
= fdiskBlockNext
) );
308 // Release our resources.
317 // Release our resources.
319 if ( mediaIsOpen
) media
->close(this);
320 if ( partitions
) partitions
->release();
321 if ( buffer
) buffer
->release();
326 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
328 bool IOFDiskPartitionScheme::isPartitionExtended(fdisk_part
* partition
)
331 // Ask whether the given partition is extended.
334 return ( partition
->systid
== 0x05 ||
335 partition
->systid
== 0x0F ||
336 partition
->systid
== 0x85 );
339 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
341 bool IOFDiskPartitionScheme::isPartitionUsed(fdisk_part
* partition
)
344 // Ask whether the given partition is used.
347 return ( partition
->systid
!= 0 && partition
->numsect
!= 0 );
350 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
352 bool IOFDiskPartitionScheme::isPartitionCorrupt(
353 fdisk_part
* /* partition */ ,
354 UInt32
/* partitionID */ ,
355 UInt32
/* fdiskBlock */ )
358 // Ask whether the given partition appears to be corrupt. A partition that
359 // is corrupt will cause the failure of the FDisk partition map recognition
366 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
368 bool IOFDiskPartitionScheme::isPartitionInvalid( fdisk_part
* partition
,
373 // Ask whether the given partition appears to be invalid. A partition that
374 // is invalid will cause it to be skipped in the scan, but will not cause a
375 // failure of the FDisk partition map recognition.
378 IOMedia
* media
= getProvider();
379 UInt64 mediaBlockSize
= media
->getPreferredBlockSize();
380 UInt64 partitionBase
= 0;
381 UInt64 partitionSize
= 0;
383 // Compute the relative byte position and size of the new partition.
385 partitionBase
= OSSwapLittleToHostInt32(partition
->relsect
) + fdiskBlock
;
386 partitionSize
= OSSwapLittleToHostInt32(partition
->numsect
);
387 partitionBase
*= mediaBlockSize
;
388 partitionSize
*= mediaBlockSize
;
390 // Determine whether the partition starts at (or past) the end-of-media.
392 if ( partitionBase
>= media
->getSize() ) return true;
397 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
399 IOMedia
* IOFDiskPartitionScheme::instantiateMediaObject(
400 fdisk_part
* partition
,
405 // Instantiate a new media object to represent the given partition.
408 IOMedia
* media
= getProvider();
409 UInt64 mediaBlockSize
= media
->getPreferredBlockSize();
410 UInt64 partitionBase
= 0;
411 char * partitionHint
= 0;
412 UInt64 partitionSize
= 0;
414 // Compute the relative byte position and size of the new partition.
416 partitionBase
= OSSwapLittleToHostInt32(partition
->relsect
) + fdiskBlock
;
417 partitionSize
= OSSwapLittleToHostInt32(partition
->numsect
);
418 partitionBase
*= mediaBlockSize
;
419 partitionSize
*= mediaBlockSize
;
421 // Clip the size of the new partition if it extends past the end-of-media.
423 if ( partitionBase
+ partitionSize
> media
->getSize() )
425 partitionSize
= media
->getSize() - partitionBase
;
428 // Look up a type for the new partition.
430 OSDictionary
* hintTable
= OSDynamicCast(
431 /* type */ OSDictionary
,
432 /* instance */ getProperty(kIOFDiskPartitionSchemeContentTable
) );
437 OSString
* hintValue
;
439 sprintf(hintIndex
, "0x%02X", partition
->systid
& 0xFF);
441 hintValue
= OSDynamicCast(OSString
, hintTable
->getObject(hintIndex
));
443 if ( hintValue
) partitionHint
= (char *) hintValue
->getCStringNoCopy();
446 // Create the new media object.
448 IOMedia
* newMedia
= instantiateDesiredMediaObject(
449 /* partition */ partition
,
450 /* partitionID */ partitionID
,
451 /* fdiskBlock */ fdiskBlock
);
456 /* base */ partitionBase
,
457 /* size */ partitionSize
,
458 /* preferredBlockSize */ mediaBlockSize
,
459 /* isEjectable */ media
->isEjectable(),
461 /* isWritable */ media
->isWritable(),
462 /* contentHint */ partitionHint
) )
464 // Set a name for this partition.
467 sprintf(name
, "Untitled %ld", partitionID
);
468 newMedia
->setName(name
);
470 // Set a location value (the partition number) for this partition.
473 sprintf(location
, "%ld", partitionID
);
474 newMedia
->setLocation(location
);
476 // Set the "Partition ID" key for this partition.
478 newMedia
->setProperty(kIOMediaPartitionIDKey
, partitionID
, 32);
490 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
492 IOMedia
* IOFDiskPartitionScheme::instantiateDesiredMediaObject(
493 fdisk_part
* partition
,
498 // Allocate a new media object (called from instantiateMediaObject).
504 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
506 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 0);
508 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
510 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 1);
512 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
514 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 2);
516 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
518 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 3);
520 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
522 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 4);
524 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
526 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 5);
528 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
530 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 6);
532 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
534 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 7);
536 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
538 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 8);
540 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
542 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 9);
544 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
546 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 10);
548 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
550 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 11);
552 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
554 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 12);
556 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
558 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 13);
560 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
562 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 14);
564 // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
566 OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme
, 15);