|
|
1.1 root 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: //
24: // Notes:
25: // -----
26: // o the on-disk dpme structure is packed for PowerPC and has big endian fields
27: //
28: // o the dpme_pblock_start block value is relative to the containing media's
29: // boundary, and the implicit block size is hardcoded to 512 bytes
30: //
31: // o the dpme_pblocks block value's implicit block size is 512 bytes
32: //
33: // Policies:
34: // --------
35: // o the apple partition scheme accepts probes only on "whole" media objects --
36: // this is done in the spirit of minimizing reads, since in general practice,
37: // subpartitions of the apple type do not exist
38: //
39: // o the default probe score of the apple partition scheme is 1200
40: //
41: // o the "Apple_partition_map" partition is always published as a non-writable
42: // media -- this is because its contents are nobody's business but ours
43: //
44: // o the "Apple_Free" partition is always skipped -- this is because it would
45: // never be used by a serious user application, and it cries out to harbour
46: // viruses; the partition also often exceeds the confines of the media for
47: // CDs, which would arguably require ugly truncation logic to be consistent
48: //
49: // o the checksum for each partition entry is not validated -- this is done in
50: // the spirit of non-necessity and perhaps a bit of laziness
51: //
52:
53: #include <IOKit/assert.h>
54: #include <IOKit/IOLib.h>
55: #include <IOKit/storage/IOApplePartitionScheme.h>
56: #include <libkern/OSByteOrder.h>
57:
58: #define super IOPartitionScheme
59: OSDefineMetaClassAndStructors(IOApplePartitionScheme, IOPartitionScheme);
60:
61: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
62:
63: bool IOApplePartitionScheme::init(OSDictionary * properties = 0)
64: {
65: //
66: // Initialize this object's minimal state.
67: //
68:
69: if (super::init(properties) == false) return false;
70:
71: _buffer = 0;
72: _bufferSize = 0;
73: _masteredAt512 = false;
74:
75: // Validate the compiled size of our important fixed-size structures.
76:
77: assert(sizeof(dpme) == 512);
78: assert(sizeof(DDMap) == 8);
79: assert(sizeof(Block0) == 512);
80:
81: return true;
82: }
83:
84: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
85:
86: void IOApplePartitionScheme::free()
87: {
88: //
89: // Free all of this object's outstanding resources.
90: //
91:
92: if (_buffer) _buffer->release();
93:
94: super::free();
95: }
96:
97: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
98:
99: IOService * IOApplePartitionScheme::probe(IOService * provider, SInt32 * score)
100: {
101: //
102: // Determine whether the provider media contains an apple partition map. If
103: // it does, we return "this" to indicate success, otherwise we return zero.
104: //
105:
106: IOMedia * media = (IOMedia *) provider;
107:
108: // State our assumptions.
109:
110: assert(OSDynamicCast(IOMedia, provider));
111:
112: // Ask superclass' opinion about this probe.
113:
114: if (super::probe(provider, score) == 0) return 0;
115:
116: // Determine whether this media object is unformatted.
117:
118: if (media->isFormatted() == false) return 0;
119:
120: // Determine whether this media's block size is below our assumed minimum.
121:
122: if (media->getPreferredBlockSize() < sizeof(dpme)) return 0;
123:
124: // Determine whether we can rule out the media object as an apple partition
125: // map container without reading actual data from the media. We rule out
126: // all non-whole media objects.
127:
128: if (media->isWhole() == false) return 0;
129:
130: // Allocate a buffer large enough to hold one media block.
131:
132: _bufferSize = media->getPreferredBlockSize();
133: _buffer = IOBufferMemoryDescriptor::withCapacity(_bufferSize,
134: kIODirectionIn);
135:
136: if (_buffer == 0) return 0;
137:
138: // Search for a valid apple partition on the provider media.
139:
140: return identify(media) ? this : 0;
141: }
142:
143: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
144:
145: bool IOApplePartitionScheme::start(IOService * provider)
146: {
147: //
148: // This method is called once we have been attached to the media object. We
149: // generate the new media objects that will represent our partitions here.
150: //
151:
152: UInt64 block;
153: UInt32 entriesCount;
154: IOMedia * media = (IOMedia *) provider;
155: dpme * partition;
156: UInt32 partitionsPerBlock;
157: UInt32 partitionsLeftOnThisBlock;
158: bool success = false;
159:
160: // State our assumptions.
161:
162: assert(_buffer);
163:
164: // Ask our superclass' opinion.
165:
166: if ( !super::start(provider) ) return false;
167:
168: // Open the media object for access.
169:
170: if ( media->open(this, 0, kAccessReader) == false ) return false;
171:
172: // Set up our iteration variables, based on whether the media was mastered
173: // on a 512-byte-block medium or at the media's preferred block size.
174:
175: if ( _masteredAt512 )
176: {
177: block = 0;
178: partition = (dpme*)((UInt8*)_buffer->getBytesNoCopy() + sizeof(Block0));
179: partitionsPerBlock = _bufferSize / sizeof(dpme);
180: partitionsLeftOnThisBlock = partitionsPerBlock - 1;
181: }
182: else
183: {
184: block = 1;
185: partition = (dpme *) _buffer->getBytesNoCopy();
186: partitionsPerBlock = 1;
187: partitionsLeftOnThisBlock = 1;
188: }
189:
190: // Scan through all the partition entries.
191:
192: entriesCount = OSSwapBigToHostInt32(partition->dpme_map_entries);
193:
194: for ( unsigned index = 0; index < entriesCount; index++, partition += 1 )
195: {
196: // Determine whether we've exhausted the current buffer of partitions.
197:
198: if ( partitionsLeftOnThisBlock == 0 )
199: {
200: // Read the next block into our buffer.
201:
202: block++;
203: _buffer->setDirection(kIODirectionIn); // (a read)
204: _buffer->setLength(_bufferSize); // (transfer one full block)
205:
206: if ( media->read( /* client */ this,
207: /* byteStart */ block * _bufferSize,
208: /* buffer */ _buffer ) != kIOReturnSuccess )
209: {
210: IOLog("%s: %s: Unable to read block %d.\n",
211: getName(), media->getName(), (int) block);
212: break; // (failure)
213: }
214:
215: partition = (dpme *) _buffer->getBytesNoCopy();
216: partitionsLeftOnThisBlock = partitionsPerBlock;
217: }
218:
219: partitionsLeftOnThisBlock--;
220:
221: // Determine whether this partition has a valid 'PM' signature.
222:
223: if ( OSSwapBigToHostInt16(partition->dpme_signature) != DPME_SIGNATURE )
224: {
225: IOLog("%s on %s: Partition %d has an invalid signature.\n",
226: getName(), media->getName(), index + 1);
227: continue; // (skip)
228: }
229:
230: // Determine whether this partition's type is 'Apple_Free'.
231:
232: if ( !strcmp(partition->dpme_type, "Apple_Free") )
233: continue; // (skip)
234:
235: // Determine whether this partition's type is 'Apple_partition_map'.
236:
237: bool isWritable = media->isWritable();
238:
239: if ( !strcmp(partition->dpme_type, "Apple_partition_map") )
240: isWritable = false;
241:
242: // Compute the relative position and size of the new partition. The
243: // block values are always in terms of 512-byte blocks.
244:
245: UInt64 base = OSSwapBigToHostInt32(partition->dpme_pblock_start)*512ULL;
246: UInt64 size = OSSwapBigToHostInt32(partition->dpme_pblocks) * 512ULL;
247:
248: if ( base == 0 || size == 0 )
249: continue; // (skip)
250:
251: // Look up a name and a type for this partition.
252:
253: const char * aName = partition->dpme_name;
254: const char * aHint = partition->dpme_type;
255:
256: // Ensure the partition definition does not leave the confines of the
257: // containing media. Note the "Apple_Free" partition often leaves its
258: // confines on CD media, however it is our policy to ignore Apple_Free
259: // partitions anyway.
260:
261: if ( base + size > media->getSize() )
262: {
263: IOLog("%s on %s: \"%s\" (partition %d) exceeds confines of "
264: "containing media.\n",
265: getName(), media->getName(), aName, index+1);
266: continue; // (skip)
267: }
268:
269: // The partition base may be unaligned with respect the parent media's
270: // block boundaries. We warn the user in this event since every read
271: // or write is going to cause deblocking. We presume, of course, that
272: // the parent media's base is aligned in making this determination.
273:
274: if ( base % media->getPreferredBlockSize() )
275: {
276: IOLog("%s on %s: Access to \"%s\" (partition %d) may be slow due "
277: "to a misaligned block boundary.\n",
278: getName(), media->getName(), aName, index + 1);
279: }
280:
281: // Create the new media object.
282:
283: IOMedia * newMedia = new IOMedia;
284:
285: if ( !newMedia ||
286: !newMedia->init( // base (bytes; relative to provider media)
287: base,
288: // size (bytes)
289: size,
290: // natural block size (bytes)
291: ///m:2361246:workaround:added:start
292: (!strcmp(aHint, "Apple_HFS")) ? (512) :
293: ///m:2361246:workaround:added:stop
294: media->getPreferredBlockSize(),
295: // is ejectable
296: media->isEjectable(),
297: // is whole
298: false,
299: // is writable
300: isWritable,
301: // content hint
302: aHint ) ||
303: !newMedia->attach(this) )
304: {
305: IOLog("%s on %s: Unable to create media object for \"%s\" "
306: "(partition %d).\n",
307: getName(), media->getName(), aName, index + 1);
308:
309: if ( newMedia ) newMedia->release();
310: continue; // (skip)
311: }
312:
313: newMedia->setName(aName);
314:
315: // Set a location value (the partition number) for this partition.
316:
317: char location[12];
318: sprintf(location, "%d", index + 1);
319: newMedia->setLocation(location);
320:
321: // Create the "Partition ID" key.
322:
323: newMedia->setProperty(kIOMediaPartitionID, index + 1, 32);
324:
325: // Release our retain on the new media object (in registry).
326:
327: newMedia->release();
328:
329: // We don't register the new media object with the matching system
330: // until we've closed our open on the media object below us.
331:
332: success = true;
333: } // (for all partition entries)
334:
335: // Release our buffer now that we no longer need it.
336:
337: _buffer->release();
338:
339: _buffer = 0;
340: _bufferSize = 0;
341:
342: // Close the media object we opened earlier.
343:
344: media->close(this);
345:
346: // We now register the new media objects with the matching system, now
347: // that we've closed our open on the media object below us.
348:
349: if ( success )
350: {
351: OSIterator * clients = getClientIterator();
352:
353: if (clients)
354: {
355: IOService * client;
356: while ( (client = (IOService *) clients->getNextObject()) )
357: client->registerService();
358: clients->release();
359: }
360: }
361:
362: // Return success if we found at least one partition.
363:
364: return success;
365: }
366:
367: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
368:
369: bool IOApplePartitionScheme::identify(IOMedia * media)
370: {
371: //
372: // Searches for the existence of an apple partition map on the given media.
373: //
374:
375: bool success = false;
376:
377: // State our assumptions.
378:
379: assert(_buffer);
380:
381: // Open the media object for access.
382:
383: if ( media->open(this, 0, kAccessReader) == false ) return false;
384:
385: // Determine whether this is a larger-than-512-byte-block media that was
386: // mastered from a 512-byte-block media -- the mastering of 2048-byte-
387: // block CDs is the prime example, from a 512-byte-block hard drive.
388:
389: if ( _bufferSize > sizeof(Block0) )
390: {
391: // State our assumptions.
392:
393: assert(_bufferSize >= sizeof(Block0) + sizeof(dpme));
394:
395: // Read the first block into our buffer.
396:
397: _buffer->setDirection(kIODirectionIn); // (a read)
398: _buffer->setLength(_bufferSize); // (transfer one full block)
399:
400: if ( media->read(this, 0, _buffer) != kIOReturnSuccess )
401: {
402: media->close(this);
403: return false; // (failure)
404: }
405:
406: // Determine whether the partition signature 'PM' is present at a 512
407: // byte offset into the block.
408:
409: dpme * partition;
410: partition = (dpme*)((UInt8*)_buffer->getBytesNoCopy() + sizeof(Block0));
411:
412: if ( OSSwapBigToHostInt16(partition->dpme_signature) == DPME_SIGNATURE )
413: {
414: _masteredAt512 = true;
415: success = true;
416: }
417: }
418:
419: // Determine whether there is a valid apple partition map on the media;
420: // note if the masteredAt512 flag is set, we already confirmed it does.
421:
422: if ( _masteredAt512 == false )
423: {
424: // Read the second block into our buffer.
425:
426: _buffer->setDirection(kIODirectionIn); // (a read)
427: _buffer->setLength(_bufferSize); // (transfer one full block)
428:
429: if ( media->read(this, _bufferSize, _buffer) == kIOReturnSuccess )
430: {
431: // Determine whether the partition map signature 'PM' is present.
432:
433: dpme * partition = (dpme *) _buffer->getBytesNoCopy();
434:
435: if (OSSwapBigToHostInt16(partition->dpme_signature)==DPME_SIGNATURE)
436: success = true;
437: }
438: }
439:
440: // Close the media object we opened earlier.
441:
442: media->close(this);
443:
444: return success;
445: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.