]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
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. | |
11 | * | |
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 | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | ||
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> | |
28 | ||
29 | #define super IOPartitionScheme | |
30 | OSDefineMetaClassAndStructors(IOFDiskPartitionScheme, IOPartitionScheme); | |
31 | ||
32 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
33 | // Notes | |
34 | // | |
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 | |
46 | // | |
47 | ||
48 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
49 | ||
50 | #define kIOFDiskPartitionSchemeContentTable "Content Table" | |
51 | ||
52 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
53 | ||
54 | bool IOFDiskPartitionScheme::init(OSDictionary * properties = 0) | |
55 | { | |
56 | // | |
57 | // Initialize this object's minimal state. | |
58 | // | |
59 | ||
60 | // State our assumptions. | |
61 | ||
62 | assert(sizeof(fdisk_part) == 16); // (compiler/platform check) | |
63 | assert(sizeof(disk_blk0) == 512); // (compiler/platform check) | |
64 | ||
65 | // Ask our superclass' opinion. | |
66 | ||
67 | if ( super::init(properties) == false ) return false; | |
68 | ||
69 | // Initialize our state. | |
70 | ||
71 | _partitions = 0; | |
72 | ||
73 | return true; | |
74 | } | |
75 | ||
76 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
77 | ||
78 | void IOFDiskPartitionScheme::free() | |
79 | { | |
80 | // | |
81 | // Free all of this object's outstanding resources. | |
82 | // | |
83 | ||
84 | if ( _partitions ) _partitions->release(); | |
85 | ||
86 | super::free(); | |
87 | } | |
88 | ||
89 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
90 | ||
91 | IOService * IOFDiskPartitionScheme::probe(IOService * provider, SInt32 * score) | |
92 | { | |
93 | // | |
94 | // Determine whether the provider media contains an FDisk partition map. | |
95 | // | |
96 | ||
97 | // State our assumptions. | |
98 | ||
99 | assert(OSDynamicCast(IOMedia, provider)); | |
100 | ||
101 | // Ask our superclass' opinion. | |
102 | ||
103 | if ( super::probe(provider, score) == 0 ) return 0; | |
104 | ||
105 | // Scan the provider media for an FDisk partition map. | |
106 | ||
107 | _partitions = scan(score); | |
108 | ||
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 | |
111 | // from probe. | |
112 | ||
113 | if ( _partitions && _partitions->getCount() == 0 ) | |
114 | { | |
115 | _partitions->release(); | |
116 | _partitions = 0; | |
117 | } | |
118 | ||
119 | return ( _partitions ) ? this : 0; | |
120 | } | |
121 | ||
122 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
123 | ||
124 | bool IOFDiskPartitionScheme::start(IOService * provider) | |
125 | { | |
126 | // | |
127 | // Publish the new media objects which represent our partitions. | |
128 | // | |
129 | ||
130 | IOMedia * partition; | |
131 | OSIterator * partitionIterator; | |
132 | ||
133 | // State our assumptions. | |
134 | ||
135 | assert(_partitions); | |
136 | ||
137 | // Ask our superclass' opinion. | |
138 | ||
139 | if ( super::start(provider) == false ) return false; | |
140 | ||
141 | // Attach and register the new media objects representing our partitions. | |
142 | ||
143 | partitionIterator = OSCollectionIterator::withCollection(_partitions); | |
144 | if ( partitionIterator == 0 ) return false; | |
145 | ||
146 | while ( (partition = (IOMedia *) partitionIterator->getNextObject()) ) | |
147 | { | |
148 | if ( partition->attach(this) ) | |
149 | { | |
150 | partition->registerService(); | |
151 | } | |
152 | } | |
153 | ||
154 | partitionIterator->release(); | |
155 | ||
156 | return true; | |
157 | } | |
158 | ||
159 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
160 | ||
161 | OSSet * IOFDiskPartitionScheme::scan(SInt32 * score) | |
162 | { | |
163 | // | |
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. | |
169 | // | |
170 | ||
171 | IOBufferMemoryDescriptor * buffer = 0; | |
172 | UInt32 bufferSize = 0; | |
173 | UInt32 fdiskBlock = 0; | |
174 | UInt32 fdiskBlockExtn = 0; | |
175 | UInt32 fdiskBlockNext = 0; | |
176 | UInt32 fdiskID = 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; | |
183 | ||
184 | // Determine whether this media is formatted. | |
185 | ||
186 | if ( media->isFormatted() == false ) goto scanErr; | |
187 | ||
188 | // Determine whether this media has an appropriate block size. | |
189 | ||
190 | if ( (mediaBlockSize % sizeof(disk_blk0)) ) goto scanErr; | |
191 | ||
192 | // Allocate a buffer large enough to hold one map, rounded to a media block. | |
193 | ||
194 | bufferSize = IORound(sizeof(disk_blk0), mediaBlockSize); | |
195 | buffer = IOBufferMemoryDescriptor::withCapacity( | |
196 | /* capacity */ bufferSize, | |
197 | /* withDirection */ kIODirectionIn ); | |
198 | if ( buffer == 0 ) goto scanErr; | |
199 | ||
200 | // Allocate a set to hold the set of media objects representing partitions. | |
201 | ||
202 | partitions = OSSet::withCapacity(4); | |
203 | if ( partitions == 0 ) goto scanErr; | |
204 | ||
205 | // Open the media with read access. | |
206 | ||
207 | mediaIsOpen = media->open(this, 0, kIOStorageAccessReader); | |
208 | if ( mediaIsOpen == false ) goto scanErr; | |
209 | ||
210 | // Scan the media for FDisk partition map(s). | |
211 | ||
212 | do | |
213 | { | |
214 | // Read the next FDisk map into our buffer. | |
215 | ||
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; | |
223 | ||
224 | fdiskMap = (disk_blk0 *) buffer->getBytesNoCopy(); | |
225 | ||
226 | // Determine whether the partition map signature is present. | |
227 | ||
228 | if ( OSSwapLittleToHostInt16(fdiskMap->signature) != DISK_SIGNATURE ) | |
229 | { | |
230 | goto scanErr; | |
231 | } | |
232 | ||
233 | // Scan for valid partition entries in the partition map. | |
234 | ||
235 | fdiskBlockNext = 0; | |
236 | ||
237 | for ( unsigned index = 0; index < DISK_NPART; index++ ) | |
238 | { | |
239 | // Determine whether this is an extended (vs. data) partition. | |
240 | ||
241 | if ( isPartitionExtended(fdiskMap->parts + index) ) // (extended) | |
242 | { | |
243 | // If peer extended partitions exist, we accept only the first. | |
244 | ||
245 | if ( fdiskBlockNext == 0 ) // (no peer extended partition) | |
246 | { | |
247 | fdiskBlockNext = fdiskBlockExtn + | |
248 | OSSwapLittleToHostInt32( | |
249 | /* data */ fdiskMap->parts[index].relsect ); | |
250 | ||
251 | if ( fdiskBlockNext * mediaBlockSize >= media->getSize() ) | |
252 | { | |
253 | fdiskBlockNext = 0; // (exceeds confines of media) | |
254 | } | |
255 | } | |
256 | } | |
257 | else if ( isPartitionUsed(fdiskMap->parts + index) ) // (data) | |
258 | { | |
259 | // Prepare this partition's ID. | |
260 | ||
261 | fdiskID = ( fdiskBlock == 0 ) ? (index + 1) : (fdiskID + 1); | |
262 | ||
263 | // Determine whether the partition is corrupt (fatal). | |
264 | ||
265 | if ( isPartitionCorrupt( | |
266 | /* partition */ fdiskMap->parts + index, | |
267 | /* partitionID */ fdiskID, | |
268 | /* fdiskBlock */ fdiskBlock ) ) | |
269 | { | |
270 | goto scanErr; | |
271 | } | |
272 | ||
273 | // Determine whether the partition is invalid (skipped). | |
274 | ||
275 | if ( isPartitionInvalid( | |
276 | /* partition */ fdiskMap->parts + index, | |
277 | /* partitionID */ fdiskID, | |
278 | /* fdiskBlock */ fdiskBlock ) ) | |
279 | { | |
280 | continue; | |
281 | } | |
282 | ||
283 | // Create a media object to represent this partition. | |
284 | ||
285 | IOMedia * newMedia = instantiateMediaObject( | |
286 | /* partition */ fdiskMap->parts + index, | |
287 | /* partitionID */ fdiskID, | |
288 | /* fdiskBlock */ fdiskBlock ); | |
289 | ||
290 | if ( newMedia ) | |
291 | { | |
292 | partitions->setObject(newMedia); | |
293 | newMedia->release(); | |
294 | } | |
295 | } | |
296 | } | |
297 | ||
298 | // Prepare for first extended partition, if any. | |
299 | ||
300 | if ( fdiskBlock == 0 ) | |
301 | { | |
302 | fdiskID = DISK_NPART; | |
303 | fdiskBlockExtn = fdiskBlockNext; | |
304 | } | |
305 | ||
306 | } while ( (fdiskBlock = fdiskBlockNext) ); | |
307 | ||
308 | // Release our resources. | |
309 | ||
310 | media->close(this); | |
311 | buffer->release(); | |
312 | ||
313 | return partitions; | |
314 | ||
315 | scanErr: | |
316 | ||
317 | // Release our resources. | |
318 | ||
319 | if ( mediaIsOpen ) media->close(this); | |
320 | if ( partitions ) partitions->release(); | |
321 | if ( buffer ) buffer->release(); | |
322 | ||
323 | return 0; | |
324 | } | |
325 | ||
326 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
327 | ||
328 | bool IOFDiskPartitionScheme::isPartitionExtended(fdisk_part * partition) | |
329 | { | |
330 | // | |
331 | // Ask whether the given partition is extended. | |
332 | // | |
333 | ||
334 | return ( partition->systid == 0x05 || | |
335 | partition->systid == 0x0F || | |
336 | partition->systid == 0x85 ); | |
337 | } | |
338 | ||
339 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
340 | ||
341 | bool IOFDiskPartitionScheme::isPartitionUsed(fdisk_part * partition) | |
342 | { | |
343 | // | |
344 | // Ask whether the given partition is used. | |
345 | // | |
346 | ||
347 | return ( partition->systid != 0 && partition->numsect != 0 ); | |
348 | } | |
349 | ||
350 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
351 | ||
352 | bool IOFDiskPartitionScheme::isPartitionCorrupt( | |
353 | fdisk_part * /* partition */ , | |
354 | UInt32 /* partitionID */ , | |
355 | UInt32 /* fdiskBlock */ ) | |
356 | { | |
357 | // | |
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 | |
360 | // altogether. | |
361 | // | |
362 | ||
363 | return false; | |
364 | } | |
365 | ||
366 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
367 | ||
368 | bool IOFDiskPartitionScheme::isPartitionInvalid( fdisk_part * partition, | |
369 | UInt32 partitionID, | |
370 | UInt32 fdiskBlock ) | |
371 | { | |
372 | // | |
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. | |
376 | // | |
377 | ||
378 | IOMedia * media = getProvider(); | |
379 | UInt64 mediaBlockSize = media->getPreferredBlockSize(); | |
380 | UInt64 partitionBase = 0; | |
381 | UInt64 partitionSize = 0; | |
382 | ||
383 | // Compute the relative byte position and size of the new partition. | |
384 | ||
385 | partitionBase = OSSwapLittleToHostInt32(partition->relsect) + fdiskBlock; | |
386 | partitionSize = OSSwapLittleToHostInt32(partition->numsect); | |
387 | partitionBase *= mediaBlockSize; | |
388 | partitionSize *= mediaBlockSize; | |
389 | ||
390 | // Determine whether the partition starts at (or past) the end-of-media. | |
391 | ||
392 | if ( partitionBase >= media->getSize() ) return true; | |
393 | ||
394 | return false; | |
395 | } | |
396 | ||
397 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
398 | ||
399 | IOMedia * IOFDiskPartitionScheme::instantiateMediaObject( | |
400 | fdisk_part * partition, | |
401 | UInt32 partitionID, | |
402 | UInt32 fdiskBlock ) | |
403 | { | |
404 | // | |
405 | // Instantiate a new media object to represent the given partition. | |
406 | // | |
407 | ||
408 | IOMedia * media = getProvider(); | |
409 | UInt64 mediaBlockSize = media->getPreferredBlockSize(); | |
410 | UInt64 partitionBase = 0; | |
411 | char * partitionHint = 0; | |
412 | UInt64 partitionSize = 0; | |
413 | ||
414 | // Compute the relative byte position and size of the new partition. | |
415 | ||
416 | partitionBase = OSSwapLittleToHostInt32(partition->relsect) + fdiskBlock; | |
417 | partitionSize = OSSwapLittleToHostInt32(partition->numsect); | |
418 | partitionBase *= mediaBlockSize; | |
419 | partitionSize *= mediaBlockSize; | |
420 | ||
421 | // Clip the size of the new partition if it extends past the end-of-media. | |
422 | ||
423 | if ( partitionBase + partitionSize > media->getSize() ) | |
424 | { | |
425 | partitionSize = media->getSize() - partitionBase; | |
426 | } | |
427 | ||
428 | // Look up a type for the new partition. | |
429 | ||
430 | OSDictionary * hintTable = OSDynamicCast( | |
431 | /* type */ OSDictionary, | |
432 | /* instance */ getProperty(kIOFDiskPartitionSchemeContentTable) ); | |
433 | ||
434 | if ( hintTable ) | |
435 | { | |
436 | char hintIndex[5]; | |
437 | OSString * hintValue; | |
438 | ||
439 | sprintf(hintIndex, "0x%02X", partition->systid & 0xFF); | |
440 | ||
441 | hintValue = OSDynamicCast(OSString, hintTable->getObject(hintIndex)); | |
442 | ||
443 | if ( hintValue ) partitionHint = (char *) hintValue->getCStringNoCopy(); | |
444 | } | |
445 | ||
446 | // Create the new media object. | |
447 | ||
448 | IOMedia * newMedia = instantiateDesiredMediaObject( | |
449 | /* partition */ partition, | |
450 | /* partitionID */ partitionID, | |
451 | /* fdiskBlock */ fdiskBlock ); | |
452 | ||
453 | if ( newMedia ) | |
454 | { | |
455 | if ( newMedia->init( | |
456 | /* base */ partitionBase, | |
457 | /* size */ partitionSize, | |
458 | /* preferredBlockSize */ mediaBlockSize, | |
459 | /* isEjectable */ media->isEjectable(), | |
460 | /* isWhole */ false, | |
461 | /* isWritable */ media->isWritable(), | |
462 | /* contentHint */ partitionHint ) ) | |
463 | { | |
464 | // Set a name for this partition. | |
465 | ||
466 | char name[24]; | |
467 | sprintf(name, "Untitled %ld", partitionID); | |
468 | newMedia->setName(name); | |
469 | ||
470 | // Set a location value (the partition number) for this partition. | |
471 | ||
472 | char location[12]; | |
473 | sprintf(location, "%ld", partitionID); | |
474 | newMedia->setLocation(location); | |
475 | ||
476 | // Set the "Partition ID" key for this partition. | |
477 | ||
478 | newMedia->setProperty(kIOMediaPartitionIDKey, partitionID, 32); | |
479 | } | |
480 | else | |
481 | { | |
482 | newMedia->release(); | |
483 | newMedia = 0; | |
484 | } | |
485 | } | |
486 | ||
487 | return newMedia; | |
488 | } | |
489 | ||
490 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
491 | ||
492 | IOMedia * IOFDiskPartitionScheme::instantiateDesiredMediaObject( | |
493 | fdisk_part * partition, | |
494 | UInt32 partitionID, | |
495 | UInt32 fdiskBlock ) | |
496 | { | |
497 | // | |
498 | // Allocate a new media object (called from instantiateMediaObject). | |
499 | // | |
500 | ||
501 | return new IOMedia; | |
502 | } | |
503 | ||
504 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
505 | ||
506 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 0); | |
507 | ||
508 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
509 | ||
510 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 1); | |
511 | ||
512 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
513 | ||
514 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 2); | |
515 | ||
516 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
517 | ||
518 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 3); | |
519 | ||
520 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
521 | ||
522 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 4); | |
523 | ||
524 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
525 | ||
526 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 5); | |
527 | ||
528 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
529 | ||
530 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 6); | |
531 | ||
532 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
533 | ||
534 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 7); | |
535 | ||
536 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
537 | ||
538 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 8); | |
539 | ||
540 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
541 | ||
542 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 9); | |
543 | ||
544 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
545 | ||
546 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 10); | |
547 | ||
548 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
549 | ||
550 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 11); | |
551 | ||
552 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
553 | ||
554 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 12); | |
555 | ||
556 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
557 | ||
558 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 13); | |
559 | ||
560 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
561 | ||
562 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 14); | |
563 | ||
564 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - | |
565 | ||
566 | OSMetaClassDefineReservedUnused(IOFDiskPartitionScheme, 15); |