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/assert.h> 25#include <IOKit/IOBufferMemoryDescriptor.h> 26#include <IOKit/IODeviceTreeSupport.h> 27#include <IOKit/IOLib.h> 28#include <IOKit/storage/IOAppleLabelScheme.h> 29#include <libkern/OSByteOrder.h> 30 31#define super IOFilterScheme 32OSDefineMetaClassAndStructors(IOAppleLabelScheme, IOFilterScheme); 33 34// 35// Notes 36// 37// o the on-disk structure's fields are big-endian formatted 38// o the al_offset value is relative to the media container 39// 40 41#define kIOMediaBaseKey "Base" 42 43bool IOAppleLabelScheme::init(OSDictionary * properties) 44{ 45 // 46 // Initialize this object's minimal state. 47 // 48 49 // State our assumptions. 50 51 assert(sizeof(applelabel) == 512); // (compiler/platform check) 52 53 // Ask our superclass' opinion. 54 55 if (super::init(properties) == false) return false; 56 57 // Initialize our state. 58 59 _content = 0; 60 61 return true; 62} 63 64void IOAppleLabelScheme::free() 65{ 66 // 67 // Free all of this object's outstanding resources. 68 // 69 70 if ( _content ) _content->release(); 71 72 super::free(); 73} 74 75IOService * IOAppleLabelScheme::probe(IOService * provider, SInt32 * score) 76{ 77 // 78 // Determine whether the provider media contains an Apple label scheme. 79 // 80 81 // State our assumptions. 82 83 assert(OSDynamicCast(IOMedia, provider)); 84 85 // Ask superclass' opinion. 86 87 if (super::probe(provider, score) == 0) return 0; 88 89 // Scan the provider media for an Apple label scheme. 90 91 _content = scan(score); 92 93 return ( _content ) ? this : 0; 94} 95 96bool IOAppleLabelScheme::start(IOService * provider) 97{ 98 // 99 // Publish the new media object which represents our content. 100 // 101 102 // State our assumptions. 103 104 assert(_content); 105 106 // Ask our superclass' opinion. 107 108 if ( super::start(provider) == false ) return false; 109 110 // Attach and register the new media object representing our content. 111 112 _content->attach(this); 113 114 attachMediaObjectToDeviceTree(_content); 115 116 _content->registerService(); 117 118 return true; 119} 120 121void IOAppleLabelScheme::stop(IOService * provider) 122{ 123 // 124 // Clean up after the media object we published before terminating. 125 // 126 127 // State our assumptions. 128 129 assert(_content); 130 131 // Detach the media objects we previously attached to the device tree. 132 133 detachMediaObjectFromDeviceTree(_content); 134 135 super::stop(provider); 136} 137 138IOMedia * IOAppleLabelScheme::scan(SInt32 * score) 139{ 140 // 141 // Scan the provider media for an Apple label scheme. 142 // 143 144 IOBufferMemoryDescriptor * buffer = 0; 145 UInt64 bufferBase = 0; 146 UInt32 bufferSize = 0; 147 applelabel * headerMap = 0; 148 UInt64 labelBase = 0; 149 UInt32 labelCheck = 0; 150 char * labelMap = 0; 151 UInt32 labelSize = 0; 152 IOMedia * media = getProvider(); 153 UInt64 mediaBlockSize = media->getPreferredBlockSize(); 154 bool mediaIsOpen = false; 155 IOMedia * newMedia = 0; 156 OSDictionary * properties = 0; 157 IOReturn status = kIOReturnError; 158 159 // Determine whether this media is formatted. 160 161 if ( media->isFormatted() == false ) goto scanErr; 162 163 // Determine whether this media has an appropriate block size. 164 165 if ( (mediaBlockSize % sizeof(applelabel)) ) goto scanErr; 166 167 // Allocate a buffer large enough to hold one map, rounded to a media block. 168 169 bufferSize = IORound(sizeof(applelabel), mediaBlockSize); 170 buffer = IOBufferMemoryDescriptor::withCapacity( 171 /* capacity */ bufferSize, 172 /* withDirection */ kIODirectionIn ); 173 if ( buffer == 0 ) goto scanErr; 174 175 // Open the media with read access. 176 177 mediaIsOpen = media->open(this, 0, kIOStorageAccessReader); 178 if ( mediaIsOpen == false ) goto scanErr; 179 180 // Read the label header into our buffer. 181 182 status = media->read(this, 0, buffer); 183 if ( status != kIOReturnSuccess ) goto scanErr; 184 185 headerMap = (applelabel *) buffer->getBytesNoCopy(); 186 187 // Determine whether the label header signature is present. 188 189 if ( OSSwapBigToHostInt16(headerMap->al_magic) != AL_MAGIC ) 190 { 191 goto scanErr; 192 } 193 194 // Determine whether the label header version is valid. 195 196 if ( OSSwapBigToHostInt16(headerMap->al_type) != AL_TYPE_DEFAULT ) 197 { 198 goto scanErr; 199 } 200 201 // Compute the relative byte position and size of the label. 202 203 labelBase = OSSwapBigToHostInt64(headerMap->al_offset); 204 labelCheck = OSSwapBigToHostInt32(headerMap->al_checksum); 205 labelSize = OSSwapBigToHostInt32(headerMap->al_size); 206 207 if ( labelSize > 131072 ) 208 { 209 goto scanErr; 210 } 211 212 // Allocate a buffer large enough to hold one map, rounded to a media block. 213 214 buffer->release(); 215 216 bufferBase = IOTrunc(labelBase, mediaBlockSize); 217 bufferSize = IORound(labelBase + labelSize, mediaBlockSize) - bufferBase; 218 buffer = IOBufferMemoryDescriptor::withCapacity( 219 /* capacity */ bufferSize, 220 /* withDirection */ kIODirectionIn ); 221 if ( buffer == 0 ) goto scanErr; 222 223 // Determine whether the label leaves the confines of the container. 224 225 if ( bufferBase + bufferSize > media->getSize() ) goto scanErr; 226 227 // Read the label into our buffer. 228 229 status = media->read(this, bufferBase, buffer); 230 if ( status != kIOReturnSuccess ) goto scanErr; 231 232 labelMap = (char *) buffer->getBytesNoCopy() + (labelBase % mediaBlockSize); 233 234 // Determine whether the label checksum is valid. 235 236 if ( crc32(0, labelMap, labelSize) != labelCheck ) 237 { 238 goto scanErr; 239 } 240 241 // Obtain the properties. 242 243 properties = (OSDictionary *) OSUnserializeXML(labelMap, labelSize); 244 245 if ( OSDynamicCast(OSDictionary, properties) == 0 ) 246 { 247 goto scanErr; 248 } 249 250 // Determine whether the content is corrupt. 251 252 if ( isContentCorrupt(properties) ) 253 { 254 goto scanErr; 255 } 256 257 // Determine whether the content is corrupt. 258 259 if ( isContentInvalid(properties) ) 260 { 261 goto scanErr; 262 } 263 264 // Create a media object to represent the content. 265 266 newMedia = instantiateMediaObject(properties); 267 268 if ( newMedia == 0 ) 269 { 270 goto scanErr; 271 } 272 273 // Release our resources. 274 275 media->close(this); 276 buffer->release(); 277 properties->release(); 278 279 return newMedia; 280 281scanErr: 282 283 // Release our resources. 284 285 if ( mediaIsOpen ) media->close(this); 286 if ( buffer ) buffer->release(); 287 if ( properties ) properties->release(); 288 289 return 0; 290} 291 292bool IOAppleLabelScheme::isContentCorrupt(OSDictionary * properties) 293{ 294 // 295 // Ask whether the given content appears to be corrupt. 296 // 297 298 return false; 299} 300 301bool IOAppleLabelScheme::isContentInvalid(OSDictionary * properties) 302{ 303 // 304 // Ask whether the given content appears to be invalid. 305 // 306 307 UInt64 contentBase = 0; 308 UInt64 contentSize = 0; 309 IOMedia * media = getProvider(); 310 OSObject * object = 0; 311 312 // Compute the relative byte position and size of the new content. 313 314 object = properties->getObject(kIOMediaBaseKey); 315 316 if ( OSDynamicCast(OSNumber, object) ) 317 { 318 contentBase = ((OSNumber *) object)->unsigned64BitValue(); 319 } 320 321 object = properties->getObject(kIOMediaSizeKey); 322 323 if ( OSDynamicCast(OSNumber, object) ) 324 { 325 contentSize = ((OSNumber *) object)->unsigned64BitValue(); 326 } 327 328 // Determine whether the content is a placeholder. 329 330 if ( contentSize == 0 ) return true; 331 332 // Determine whether the new content leaves the confines of the container. 333 334 if ( contentBase + contentSize > media->getSize() ) return true; 335 336 return false; 337} 338 339IOMedia * IOAppleLabelScheme::instantiateMediaObject(OSDictionary * properties) 340{ 341 // 342 // Instantiate a new media object to represent the given content. 343 // 344 345 IOMediaAttributeMask contentAttributes = 0; 346 UInt64 contentBase = 0; 347 UInt64 contentBlockSize = 0; 348 const char * contentHint = 0; 349 bool contentIsWhole = false; 350 bool contentIsWritable = false; 351 UInt64 contentSize = 0; 352 IOMedia * media = getProvider(); 353 IOMedia * newMedia = 0; 354 OSObject * object = 0; 355 356 contentAttributes = media->getAttributes(); 357 contentBlockSize = media->getPreferredBlockSize(); 358 contentIsWhole = media->isWhole(); 359 contentIsWritable = media->isWritable(); 360 contentSize = media->getSize(); 361 362 properties = OSDictionary::withDictionary(properties); 363 if ( properties == 0 ) return 0; 364 365 // Obtain the initialization properties. 366 367 object = properties->getObject(kIOMediaBaseKey); 368 369 if ( OSDynamicCast(OSNumber, object) ) 370 { 371 contentBase = ((OSNumber *) object)->unsigned64BitValue(); 372 } 373 374 properties->removeObject(kIOMediaBaseKey); 375 376 object = properties->getObject(kIOMediaContentKey); 377 378 if ( OSDynamicCast(OSString, object) ) 379 { 380 contentHint = ((OSString *) object)->getCStringNoCopy(); 381 } 382 383 properties->removeObject(kIOMediaContentKey); 384 385 object = properties->getObject(kIOMediaContentHintKey); 386 387 if ( OSDynamicCast(OSString, object) ) 388 { 389 contentHint = ((OSString *) object)->getCStringNoCopy(); 390 } 391 392 properties->removeObject(kIOMediaContentHintKey); 393 394 object = properties->getObject(kIOMediaEjectableKey); 395 396 if ( OSDynamicCast(OSBoolean, object) ) 397 { 398 if ( ((OSBoolean *) object)->getValue() ) 399 { 400 contentAttributes |= kIOMediaAttributeEjectableMask; 401 } 402 else 403 { 404 contentAttributes &= ~kIOMediaAttributeEjectableMask; 405 } 406 } 407 408 properties->removeObject(kIOMediaEjectableKey); 409 410 object = properties->getObject(kIOMediaPreferredBlockSizeKey); 411 412 if ( OSDynamicCast(OSNumber, object) ) 413 { 414 contentBlockSize = ((OSNumber *) object)->unsigned64BitValue(); 415 } 416 417 properties->removeObject(kIOMediaPreferredBlockSizeKey); 418 419 object = properties->getObject(kIOMediaRemovableKey); 420 421 if ( OSDynamicCast(OSBoolean, object) ) 422 { 423 if ( ((OSBoolean *) object)->getValue() ) 424 { 425 contentAttributes |= kIOMediaAttributeRemovableMask; 426 } 427 else 428 { 429 contentAttributes &= ~kIOMediaAttributeRemovableMask; 430 } 431 } 432 433 properties->removeObject(kIOMediaRemovableKey); 434 435 object = properties->getObject(kIOMediaWholeKey); 436 437 if ( OSDynamicCast(OSBoolean, object) ) 438 { 439 contentIsWhole = ((OSBoolean *) object)->getValue(); 440 } 441 442 properties->removeObject(kIOMediaWholeKey); 443 444 object = properties->getObject(kIOMediaSizeKey); 445 446 if ( OSDynamicCast(OSNumber, object) ) 447 { 448 contentSize = ((OSNumber *) object)->unsigned64BitValue(); 449 } 450 451 properties->removeObject(kIOMediaSizeKey); 452 453 object = properties->getObject(kIOMediaWritableKey); 454 455 if ( OSDynamicCast(OSBoolean, object) ) 456 { 457 contentIsWritable = ((OSBoolean *) object)->getValue(); 458 } 459 460 properties->removeObject(kIOMediaWritableKey); 461 462 // Create the new media object. 463 464 newMedia = instantiateDesiredMediaObject(properties); 465 466 if ( newMedia ) 467 { 468 if ( newMedia->init( 469 /* base */ contentBase, 470 /* size */ contentSize, 471 /* preferredBlockSize */ contentBlockSize, 472 /* attributes */ contentAttributes, 473 /* isWhole */ contentIsWhole, 474 /* isWritable */ contentIsWritable, 475 /* contentHint */ contentHint ) ) 476 { 477 // Set a location. 478 479 newMedia->setLocation("1"); 480 481 // Set the properties. 482 483 newMedia->getPropertyTable()->merge(properties); 484 } 485 else 486 { 487 newMedia->release(); 488 newMedia = 0; 489 } 490 } 491 492 properties->release(); 493 494 return newMedia; 495} 496 497IOMedia * IOAppleLabelScheme::instantiateDesiredMediaObject( 498 OSDictionary * properties ) 499{ 500 // 501 // Allocate a new media object (called from instantiateMediaObject). 502 // 503 504 return new IOMedia; 505} 506 507bool IOAppleLabelScheme::attachMediaObjectToDeviceTree( IOMedia * media ) 508{ 509 // 510 // Attach the given media object to the device tree plane. 511 // 512 513 IORegistryEntry * child; 514 515 if ( (child = getParentEntry(gIOServicePlane)) ) 516 { 517 IORegistryEntry * parent; 518 519 if ( (parent = child->getParentEntry(gIODTPlane)) ) 520 { 521 const char * location = child->getLocation(gIODTPlane); 522 const char * name = child->getName(gIODTPlane); 523 524 if ( media->attachToParent(parent, gIODTPlane) ) 525 { 526 media->setLocation(location, gIODTPlane); 527 media->setName(name, gIODTPlane); 528 529 child->detachFromParent(parent, gIODTPlane); 530 531 return true; 532 } 533 } 534 } 535 536 return false; 537} 538 539void IOAppleLabelScheme::detachMediaObjectFromDeviceTree( IOMedia * media ) 540{ 541 // 542 // Detach the given media object from the device tree plane. 543 // 544 545 IORegistryEntry * child; 546 547 if ( (child = getParentEntry(gIOServicePlane)) ) 548 { 549 IORegistryEntry * parent; 550 551 if ( (parent = media->getParentEntry(gIODTPlane)) ) 552 { 553 const char * location = media->getLocation(gIODTPlane); 554 const char * name = media->getName(gIODTPlane); 555 556 if ( child->attachToParent(parent, gIODTPlane) ) 557 { 558 child->setLocation(location, gIODTPlane); 559 child->setName(name, gIODTPlane); 560 } 561 562 media->detachFromParent(parent, gIODTPlane); 563 } 564 } 565} 566 567OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 0); 568OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 1); 569OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 2); 570OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 3); 571OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 4); 572OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 5); 573OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 6); 574OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 7); 575OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 8); 576OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 9); 577OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 10); 578OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 11); 579OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 12); 580OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 13); 581OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 14); 582OSMetaClassDefineReservedUnused(IOAppleLabelScheme, 15); 583