Annotation of XNU/iokit/Families/IOStorage/IOMedia.cpp, revision 1.1.1.1

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: #include <machine/limits.h>                  // (ULONG_MAX, ...)
                     24: #include <IOKit/IODeviceTreeSupport.h>       // (gIODTPlane, ...)
                     25: #include <IOKit/storage/IOMedia.h>
                     26: 
                     27: #define super IOStorage
                     28: OSDefineMetaClassAndStructors(IOMedia, IOStorage)
                     29: 
                     30: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                     31: 
                     32: bool IOMedia::init(UInt64         base,
                     33:                    UInt64         size,
                     34:                    UInt64         preferredBlockSize,
                     35:                    bool           isEjectable,
                     36:                    bool           isWhole,
                     37:                    bool           isWritable,
                     38:                    const char *   contentHint = 0,
                     39:                    OSDictionary * properties  = 0)
                     40: {
                     41:     //
                     42:     // Initialize this object's minimal state.
                     43:     //
                     44: 
                     45:     if (super::init(properties) == false)  return false;
                     46: 
                     47:     _mediaBase          = base;
                     48:     _mediaSize          = size;
                     49:     _isEjectable        = isEjectable;
                     50:     _isWhole            = isWhole;
                     51:     _isWritable         = isWritable;
                     52:     _openLevel          = kAccessNone;
                     53:     _openReaders        = OSSet::withCapacity(1);
                     54:     _openReaderWriter   = 0;
                     55:     _preferredBlockSize = preferredBlockSize;
                     56: 
                     57:     if (_openReaders == 0)  return false;
                     58: 
                     59:     //
                     60:     // Create the standard media registry properties.
                     61:     //
                     62: 
                     63:     setProperty(kIOMediaContent,     contentHint ? contentHint : "");
                     64:     setProperty(kIOMediaContentHint, contentHint ? contentHint : "");
                     65:     setProperty(kIOMediaEjectable,   isEjectable);
                     66:     setProperty(kIOMediaLeaf,        true);
                     67:     setProperty(kIOMediaSize,        size, 64);
                     68:     setProperty(kIOMediaWhole,       isWhole);
                     69:     setProperty(kIOMediaWritable,    isWritable);
                     70: 
                     71:     return true;
                     72: }
                     73: 
                     74: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                     75: 
                     76: void IOMedia::free(void)
                     77: {
                     78:     //
                     79:     // Free all of this object's outstanding resources.
                     80:     //
                     81: 
                     82:     if (_openReaders)  _openReaders->release();
                     83: 
                     84:     super::free();
                     85: }
                     86: 
                     87: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                     88: 
                     89: bool IOMedia::attachToChild(IORegistryEntry *       client,
                     90:                             const IORegistryPlane * plane)
                     91: {
                     92:     //
                     93:     // This method is called for each client interested in the services we
                     94:     // provide.  The superclass links us as a parent to this client in the
                     95:     // I/O Kit registry on success.
                     96:     //
                     97: 
                     98:     OSString * s;
                     99: 
                    100:     // Ask our superclass' opinion.
                    101: 
                    102:     if (super::attachToChild(client, plane) == false)  return false;
                    103: 
                    104:     //
                    105:     // Determine whether the client is a storage object, which we consider
                    106:     // to be a consumer of this storage object's content and a producer of
                    107:     // new content. A storage object need not be an IOStorage subclass, so
                    108:     // long as it identifies itself with a match category of "IOStorage".
                    109:     //
                    110:     // If the client is indeed a storage object, we reset the media's Leaf
                    111:     // property to false and replace the media's Content property with the
                    112:     // client's Content Mask property, if any.
                    113:     //
                    114: 
                    115:     s = OSDynamicCast(OSString, client->getProperty(gIOMatchCategoryKey));
                    116:  
                    117:     if (s && !strcmp(s->getCStringNoCopy(), kIOStorageCategory))
                    118:     {
                    119:         setProperty(kIOMediaLeaf, false);
                    120: 
                    121:         s = OSDynamicCast(OSString, client->getProperty(kIOMediaContentMask));
                    122:         if (s)  setProperty(kIOMediaContent, s->getCStringNoCopy());
                    123:     }
                    124: 
                    125:     return true;
                    126: }
                    127: 
                    128: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    129: 
                    130: void IOMedia::detachFromChild(IORegistryEntry *       client,
                    131:                               const IORegistryPlane * plane)
                    132: {
                    133:     //
                    134:     // This method is called for each client that loses interest in the
                    135:     // services we provide.  The superclass unlinks us from this client
                    136:     // in the I/O Kit registry on success.
                    137:     //
                    138:     // Note that this method is called at a nondeterministic time after
                    139:     // our client is terminated, which means another client may already
                    140:     // have arrived and attached in the meantime.  This is not an issue
                    141:     // should the termination be issued synchrnously, however, which we
                    142:     // take advantage of when this media needs to  eliminate one of its
                    143:     // clients.  If the termination was issued on this media or farther
                    144:     // below in the hierarchy, we don't really care that the properties
                    145:     // would not  be consistent since this media object is going to die
                    146:     // anyway.
                    147:     //
                    148: 
                    149:     OSString * s;
                    150: 
                    151:     //
                    152:     // Determine whether the client is a storage object, which we consider
                    153:     // to be a consumer of this storage object's content and a producer of
                    154:     // new content. A storage object need not be an IOStorage subclass, so
                    155:     // long as it identifies itself with a match category of "IOStorage".
                    156:     //
                    157:     // If the client is indeed a storage object, we reset the media's Leaf
                    158:     // property to true and reset the media's Content property to the hint
                    159:     // we obtained when this media was initialized.
                    160:     //
                    161: 
                    162:     s = OSDynamicCast(OSString, client->getProperty(gIOMatchCategoryKey));
                    163:  
                    164:     if (s && !strcmp(s->getCStringNoCopy(), kIOStorageCategory))
                    165:     {
                    166:         setProperty(kIOMediaContent, getContentHint());
                    167:         setProperty(kIOMediaLeaf, true);
                    168:     }
                    169: 
                    170:     // Pass the call onto our superclass.
                    171: 
                    172:     super::detachFromChild(client, plane);
                    173: }
                    174: 
                    175: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    176: 
                    177: bool IOMedia::handleOpen(IOService *  client,
                    178:                          IOOptionBits options,
                    179:                          void *       argument)
                    180: {
                    181:     //
                    182:     // The handleOpen method grants or denies permission to access this object
                    183:     // to an interested client.  The argument is an IOStorageAccess value that
                    184:     // specifies the level of access desired -- reader or reader-writer.
                    185:     //
                    186:     // This method can be invoked to upgrade or downgrade the access level for
                    187:     // an existing client as well.  The previous access level will prevail for
                    188:     // upgrades that fail, of course.   A downgrade should never fail.  If the
                    189:     // new access level should be the same as the old for a given client, this
                    190:     // method will do nothing and return success.  In all cases, one, singular
                    191:     // close-per-client is expected for all opens-per-client received.
                    192:     //
                    193:     // This method will work even when the media is in the terminated state.
                    194:     //
                    195:     // We are guaranteed that no other opens or closes will be processed until
                    196:     // we make our decision, change our state, and return from this method.
                    197:     //
                    198: 
                    199:     IOStorageAccess access = (IOStorageAccess) (int) argument;
                    200:     IOStorageAccess level;
                    201: 
                    202:     assert(client);
                    203: 
                    204:     //
                    205:     // Chart our course of action.
                    206:     //
                    207: 
                    208:     switch (access)
                    209:     {
                    210:         case kAccessReader:
                    211:         {
                    212:             if (_openReaders->containsObject(client))     // (access: no change)
                    213:                 return true;
                    214:             else if (_openReaderWriter == client)         // (access: downgrade)
                    215:                 level = kAccessReader;
                    216:             else                                         // (access: new reader)
                    217:                 level = _openReaderWriter ? kAccessReaderWriter : kAccessReader;
                    218:             break;
                    219:         }
                    220:         case kAccessReaderWriter:
                    221:         {
                    222:             if (_openReaders->containsObject(client))       // (access: upgrade)
                    223:                 level = kAccessReaderWriter; 
                    224:             else if (_openReaderWriter == client)         // (access: no change)
                    225:                 return true;
                    226:             else                                         // (access: new writer)
                    227:                 level = kAccessReaderWriter; 
                    228: 
                    229:             if (_isWritable == false)        // (is this media object writable?)
                    230:                 return false;
                    231: 
                    232:             if (_openReaderWriter)      // (does a reader-writer already exist?)
                    233:                 return false;
                    234: 
                    235:             break;
                    236:         }
                    237:         default:
                    238:         {
                    239:             assert(0);
                    240:             return false;
                    241:         }
                    242:     }
                    243: 
                    244:     //
                    245:     // If we are in the terminated state, we only accept downgrades.
                    246:     //
                    247: 
                    248:     if (isInactive() && _openReaderWriter != client) // (dead? not a downgrade?)
                    249:         return false;
                    250: 
                    251:     //
                    252:     // Determine whether the storage objects above us can be torn down, should
                    253:     // this be a new reader-writer open or an upgrade into a reader-writer (if
                    254:     // the client issuing the open is not a storage object itself, of course).
                    255:     //
                    256: 
                    257:     if (access == kAccessReaderWriter)   // (a new reader-writer or an upgrade?)
                    258:     {
                    259:         const OSSymbol * category = OSSymbol::withCString(kIOStorageCategory);
                    260: 
                    261:         if (category)
                    262:         {
                    263:             IOService * storageObject = getClientWithCategory(category);
                    264:             category->release();
                    265: 
                    266:             if (storageObject && storageObject != client)
                    267:             {
                    268:                 if (storageObject->terminate(kIOServiceSynchronous) == false)
                    269:                     return false;
                    270:             }
                    271:         }
                    272:     }
                    273: 
                    274:     //
                    275:     // Determine whether the storage objects below us accept this open at this
                    276:     // multiplexed level of access -- new opens, upgrades, and downgrades (and
                    277:     // no changes in access) all enter through the same open api.
                    278:     //
                    279: 
                    280:     if (_openLevel != level)                        // (has open level changed?)
                    281:     {
                    282:         IOStorage * provider = OSDynamicCast(IOStorage, getProvider());
                    283: 
                    284:         if (provider && provider->open(this, options, level) == false)
                    285:         {
                    286:             //
                    287:             // We were unable to open the storage objects below us.   We must
                    288:             // recover from the terminate we issued above before bailing out,
                    289:             // if applicable, by re-registering the media object for matching.
                    290:             //
                    291: 
                    292:             if (access == kAccessReaderWriter)
                    293:                 registerService(kIOServiceSynchronous);   // (re-register media)
                    294: 
                    295:             return false;
                    296:         }
                    297:     }
                    298: 
                    299:     //
                    300:     // Process the open.
                    301:     //
                    302:     // We make sure our open state is consistent before calling registerService
                    303:     // (if applicable) since this method can be called again on the same thread
                    304:     // (the lock protecting handleOpen is recursive, so access would be given). 
                    305:     //
                    306: 
                    307:     _openLevel = level;
                    308: 
                    309:     if (access == kAccessReader)
                    310:     {
                    311:         _openReaders->setObject(client);
                    312: 
                    313:         if (_openReaderWriter == client)                    // (for a downgrade)
                    314:         {
                    315:             _openReaderWriter = 0;
                    316:             registerService(kIOServiceSynchronous);       // (re-register media)
                    317:         }
                    318:     }
                    319:     else // (access == kAccessReaderWriter)
                    320:     {
                    321:         _openReaderWriter = client;
                    322: 
                    323:         _openReaders->removeObject(client);                  // (for an upgrade)
                    324:     }
                    325: 
                    326:     return true;
                    327: }
                    328: 
                    329: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    330: 
                    331: bool IOMedia::handleIsOpen(const IOService * client) const
                    332: {
                    333:     //
                    334:     // The handleIsOpen method determines whether the specified client, or any
                    335:     // client if none is specificed, presently has an open on this object.
                    336:     //
                    337:     // This method will work even when the media is in the terminated state.
                    338:     //
                    339:     // We are guaranteed that no other opens or closes will be processed until
                    340:     // we return from this method.
                    341:     //
                    342: 
                    343:     if (client == 0)  return (_openLevel != kAccessNone);
                    344: 
                    345:     return ( _openReaderWriter == client          ||
                    346:              _openReaders->containsObject(client) );
                    347: }
                    348: 
                    349: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    350: 
                    351: void IOMedia::handleClose(IOService * client, IOOptionBits options)
                    352: {
                    353:     //
                    354:     // A client is informing us that it is giving up access to our contents.
                    355:     //
                    356:     // This method will work even when the media is in the terminated state.
                    357:     //
                    358:     // We are guaranteed that no other opens or closes will be processed until
                    359:     // we change our state and return from this method.
                    360:     //
                    361: 
                    362:     assert(client);
                    363: 
                    364:     //
                    365:     // Process the close.
                    366:     //
                    367: 
                    368:     bool reregister = (_openReaderWriter == client) && (isInactive() == false);
                    369: 
                    370:     if (_openReaderWriter == client)         // (is the client a reader-writer?)
                    371:     {
                    372:         _openReaderWriter = 0;
                    373:     }
                    374:     else if (_openReaders->containsObject(client))  // (is the client a reader?)
                    375:     {
                    376:         _openReaders->removeObject(client);
                    377:     }
                    378:     else                                      // (is the client is an imposter?)
                    379:     {
                    380:         assert(0);
                    381:         return;
                    382:     }
                    383: 
                    384:     //
                    385:     // Reevaluate the open we have on the level below us.  If no opens remain,
                    386:     // we close, or if no reader-writer remains, but readers do, we downgrade.
                    387:     //
                    388: 
                    389:     IOStorageAccess level;
                    390: 
                    391:     if      (_openReaderWriter)         level = kAccessReaderWriter;
                    392:     else if (_openReaders->getCount())  level = kAccessReader;
                    393:     else                                level = kAccessNone;
                    394: 
                    395:     if (_openLevel != level)                        // (has open level changed?)
                    396:     {
                    397:         IOStorage * provider = OSDynamicCast(IOStorage, getProvider());
                    398: 
                    399:         assert(level != kAccessReaderWriter);
                    400: 
                    401:         if (provider)
                    402:         {
                    403:             if (level == kAccessNone)                  // (is a close in order?)
                    404:             {
                    405:                 provider->close(this, options);
                    406:             }
                    407:             else                                   // (is a downgrade in order?)
                    408:             {
                    409:                 bool success;
                    410:                 success = provider->open(this, 0, level);
                    411:                 assert(success); // (should never fail, unless avoided deadlock)
                    412:             }
                    413:          }
                    414: 
                    415:          _openLevel = level;                             // (set new open level)
                    416:     }
                    417: 
                    418:     //
                    419:     // If the reader-writer just closeed, re-register the media so that I/O Kit
                    420:     // will attempt to match storage objects that may now be interested in this
                    421:     // media.
                    422:     //
                    423:     // We make sure our open state is consistent before calling registerService
                    424:     // (if applicable) since this method can be called again on the same thread
                    425:     // (the lock protecting handleClose is recursive, so access would be given).
                    426:     //
                    427: 
                    428:     if (reregister)
                    429:         registerService(kIOServiceSynchronous);           // (re-register media)
                    430: }
                    431: 
                    432: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    433: 
                    434: void IOMedia::read(IOService *          /* client */,
                    435:                    UInt64               byteStart,
                    436:                    IOMemoryDescriptor * buffer,
                    437:                    IOStorageCompletion  completion)
                    438: {
                    439:     //
                    440:     // Read data from the storage object at the specified byte offset into the
                    441:     // specified buffer, asynchronously.   When the read completes, the caller
                    442:     // will be notified via the specified completion action.
                    443:     //
                    444:     // The buffer will be retained for the duration of the read.
                    445:     //
                    446:     // This method will work even when the media is in the terminated state.
                    447:     //
                    448: 
                    449:     if (isInactive())
                    450:     {
                    451:         complete(completion, kIOReturnNoMedia);
                    452:         return;
                    453:     }
                    454: 
                    455:     if (_openLevel == kAccessNone)             // (instantaneous value, no lock)
                    456:     {
                    457:         complete(completion, kIOReturnNotOpen);
                    458:         return;
                    459:     }
                    460: 
                    461:     if (_mediaSize == 0 || _preferredBlockSize == 0)
                    462:     {
                    463:         complete(completion, kIOReturnUnformattedMedia);
                    464:         return;
                    465:     }
                    466: 
                    467:     if (_mediaSize < byteStart + buffer->getLength())
                    468:     {
                    469:         complete(completion, kIOReturnBadArgument);
                    470:         return;
                    471:     }
                    472: 
                    473:     byteStart += _mediaBase;
                    474:     getProvider()->read(this, byteStart, buffer, completion);
                    475: }
                    476: 
                    477: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    478: 
                    479: void IOMedia::write(IOService *          client,
                    480:                     UInt64               byteStart,
                    481:                     IOMemoryDescriptor * buffer,
                    482:                     IOStorageCompletion  completion)
                    483: {
                    484:     //
                    485:     // Write data into the storage object at the specified byte offset from the
                    486:     // specified buffer, asynchronously.   When the write completes, the caller
                    487:     // will be notified via the specified completion action.
                    488:     //
                    489:     // The buffer will be retained for the duration of the write.
                    490:     //
                    491:     // This method will work even when the media is in the terminated state.
                    492:     //
                    493: 
                    494:     if (isInactive())
                    495:     {
                    496:         complete(completion, kIOReturnNoMedia);
                    497:         return;
                    498:     }
                    499: 
                    500:     if (_openLevel == kAccessNone)             // (instantaneous value, no lock)
                    501:     {
                    502:         complete(completion, kIOReturnNotOpen);
                    503:         return;
                    504:     }
                    505: 
                    506:     if (_openReaderWriter != client)           // (instantaneous value, no lock)
                    507:     {
                    508: ///m:2425148:workaround:commented:start
                    509: //        complete(completion, kIOReturnNotPrivileged);
                    510: //        return;
                    511: ///m:2425148:workaround:commented:stop
                    512:     }
                    513: 
                    514:     if (_isWritable == 0)
                    515:     {
                    516:         complete(completion, kIOReturnLockedWrite);
                    517:         return;
                    518:     }
                    519: 
                    520:     if (_mediaSize == 0 || _preferredBlockSize == 0)
                    521:     {
                    522:         complete(completion, kIOReturnUnformattedMedia);
                    523:         return;
                    524:     }
                    525: 
                    526:     if (_mediaSize < byteStart + buffer->getLength())
                    527:     {
                    528:         complete(completion, kIOReturnBadArgument);
                    529:         return;
                    530:     }
                    531: 
                    532:     byteStart += _mediaBase;
                    533:     getProvider()->write(this, byteStart, buffer, completion);
                    534: }
                    535: 
                    536: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    537: 
                    538: UInt64 IOMedia::getPreferredBlockSize() const
                    539: {
                    540:     //
                    541:     // Ask the media object for its natural block size.  This information
                    542:     // is useful to clients that want to optimize access to the media.
                    543:     //
                    544: 
                    545:     return _preferredBlockSize;
                    546: }
                    547: 
                    548: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    549: 
                    550: UInt64 IOMedia::getSize() const
                    551: {
                    552:     //
                    553:     // Ask the media object for its total length in bytes.
                    554:     //
                    555: 
                    556:     return _mediaSize;
                    557: }
                    558: 
                    559: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    560: 
                    561: UInt64 IOMedia::getBase() const
                    562: {
                    563:     //
                    564:     // Ask the media object for its byte offset relative to its provider media
                    565:     // object below it in the storage hierarchy.
                    566:     //
                    567: 
                    568:     return _mediaBase;
                    569: }
                    570: 
                    571: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    572: 
                    573: bool IOMedia::isEjectable() const
                    574: {
                    575:     //
                    576:     // Ask the media object whether it is ejectable.
                    577:     //
                    578: 
                    579:     return _isEjectable;
                    580: }
                    581: 
                    582: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    583: 
                    584: bool IOMedia::isFormatted() const
                    585: {
                    586:     //
                    587:     // Ask the media object whether it is formatted.
                    588:     //
                    589: 
                    590:     return (_mediaSize && _preferredBlockSize);
                    591: }
                    592: 
                    593: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    594: 
                    595: bool IOMedia::isWritable() const
                    596: {
                    597:     //
                    598:     // Ask the media object whether it is writable.
                    599:     //
                    600: 
                    601:     return _isWritable;
                    602: }
                    603: 
                    604: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    605: 
                    606: bool IOMedia::isWhole() const
                    607: {
                    608:     //
                    609:     // Ask the media object whether it represents the whole disk.
                    610:     //
                    611: 
                    612:     return _isWhole;
                    613: }
                    614: 
                    615: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    616: 
                    617: const char * IOMedia::getContent() const
                    618: {
                    619:     //
                    620:     // Ask the media object for a description of its contents.  The description
                    621:     // is the same as the hint at the time of the object's creation,  but it is
                    622:     // possible that the description be overrided by a client (which has probed
                    623:     // the media and identified the content correctly) of the media object.  It
                    624:     // is more accurate than the hint for this reason.  The string is formed in
                    625:     // the likeness of Apple's "Apple_HFS" strings.
                    626:     //
                    627:     // The content description can be overrided by any client that matches onto
                    628:     // this media object with a match category of kIOStorageCategory.  The media
                    629:     // object checks for a kIOMediaContentMask property in the client, and if it
                    630:     // finds one, it copies it into kIOMediaContent property.
                    631:     // property with it.
                    632:     //
                    633: 
                    634:     OSString * string;
                    635: 
                    636:     string = OSDynamicCast(OSString, getProperty(kIOMediaContent));
                    637:     if (string == 0)  return "";
                    638:     return string->getCStringNoCopy();
                    639: }
                    640: 
                    641: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    642: 
                    643: const char * IOMedia::getContentHint() const
                    644: {
                    645:     //
                    646:     // Ask the media object for a hint of its contents.  The hint is set at the
                    647:     // time of the object's creation, should the creator have a clue as to what
                    648:     // it may contain.  The hint string does not change for the lifetime of the
                    649:     // object and is also formed in the likeness of Apple's "Apple_HFS" strings.
                    650:     //
                    651: 
                    652:     OSString * string;
                    653: 
                    654:     string = OSDynamicCast(OSString, getProperty(kIOMediaContentHint));
                    655:     if (string == 0)  return "";
                    656:     return string->getCStringNoCopy();
                    657: }
                    658: 
                    659: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    660: 
                    661: IOService * IOMedia::matchLocation(IOService * client)
                    662: {
                    663:     //
                    664:     // I/O Kit is in the process of searching for a candidate object that wishes
                    665:     // to match against an IOLocation={x} dictionary of properties.  This is the
                    666:     // method called to determine whether this object wants to be the candidate.
                    667:     //
                    668:     // The matchLocation method should return "this" if it decides to match with
                    669:     // the IOLocation={x} dictionary, otherwise it should call the superclass to
                    670:     // continue with the search and skip this object as a candidate.
                    671:     //
                    672:     // If this object chooses to match, the dictionary {x} will be passed to the
                    673:     // standard (passive) matching method matchPropertyTable for comparison.
                    674:     //
                    675: 
                    676:     if (isWhole() == false)
                    677:     {
                    678:         // We elect to be the candidate object for the IOLocation={x} dictionary
                    679:         // only if we are a non-whole media; whole medias have no "location" per
                    680:         // se.
                    681:  
                    682:         assert(getLocation() && strcmp(getLocation(), ""));
                    683:         return this;                                    // ("please compare us")
                    684:     }
                    685: 
                    686:     return super::matchLocation(client);              // ("please skip over us")
                    687: }
                    688: 
                    689: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    690: 
                    691: bool IOMedia::matchPropertyTable(OSDictionary * table)
                    692: {
                    693:     //
                    694:     // Compare the properties in the supplied table to this object's properties.
                    695:     //
                    696: 
                    697:     OSString * string;
                    698: 
                    699:     // Ask our superclass' opinion.
                    700: 
                    701:     if (super::matchPropertyTable(table) == false)  return false;
                    702: 
                    703:     // Determine whether the "IOPath Extension" property is in the comparison
                    704:     // dictionary.  If it is, we compare this media's location against it.
                    705: 
                    706:     string = OSDynamicCast(OSString, table->getObject("IOPath Extension"));
                    707: 
                    708:     if (string)                              // (does "IOPath Extension" exist?)
                    709:     {
                    710:         const char * location = getLocation();
                    711: 
                    712:         if (location == 0 && isWhole() == false)  return false;
                    713: 
                    714:         UInt32 value1 = location ? strtoul(location, 0, 10) : 0;
                    715:         UInt32 value2 = strtoul(string->getCStringNoCopy(), 0, 10);
                    716: 
                    717:         if (value1 == ULONG_MAX || value2 == ULONG_MAX)  return false;
                    718:         if (value1 != value2)  return false;
                    719:     }
                    720: 
                    721:     // Ensure the "IOProviderClass" property is present in the comparison
                    722:     // dictionary, and that the given class name belongs to this object's
                    723:     // inheritance chain.
                    724: 
                    725:     string = OSDynamicCast(OSString, table->getObject(gIOProviderClassKey));
                    726: 
                    727:     if (string == 0 || metaCast(string) == 0)  return false;
                    728: 
                    729:     // We return success if the following expression is true -- individual
                    730:     // comparisions evaluate to truth if the named property is not present
                    731:     // in the supplied table.
                    732: 
                    733:     return compareProperty(table, kIOMediaContent)     &&
                    734:            compareProperty(table, kIOMediaContentHint) &&
                    735:            compareProperty(table, kIOMediaEjectable)   &&
                    736:            compareProperty(table, kIOMediaLeaf)        &&
                    737:            compareProperty(table, kIOMediaSize)        &&
                    738:            compareProperty(table, kIOMediaWhole)       &&
                    739:            compareProperty(table, kIOMediaWritable)    ;
                    740: }
                    741: 
                    742: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    743: 
                    744: bool IOMedia::getPath( char *                  path,
                    745:                        int *                   length, 
                    746:                        const IORegistryPlane * plane ) const
                    747: {
                    748:     //
                    749:     // Obtain a path to this service object.
                    750:     //
                    751:     // This method will work even when the media is in the terminated state.
                    752:     //
                    753: 
                    754:     IOMedia *   media;
                    755:     IOService * next;
                    756:     OSNumber *  number;
                    757:     bool        success = false;
                    758:     int         unit = -1, partition = 0;
                    759:     int         len, maxlen;
                    760: 
                    761:     if ( isInactive() )  return false;
                    762: 
                    763:     if ( (plane == gIODTPlane) && length )
                    764:     {
                    765:         maxlen = *length;
                    766: 
                    767:         for (next = (IOService *) this; next; next = next->getProvider())
                    768:         {
                    769:             *length = maxlen;
                    770:             media = OSDynamicCast(IOMedia, next);
                    771: 
                    772:             if ( media && media->isWhole() == false && media->getLocation() )
                    773:                 partition = strtoul(media->getLocation(), 0, 10);
                    774:             else if ( (number = (OSNumber *) next->getProperty("IOUnit")) )
                    775:                 unit = number->unsigned32BitValue();
                    776:             else if( !media && next->getPath( path, length, plane ))
                    777:                 break;
                    778:         }
                    779: 
                    780:         if (next && (unit != -1) && (partition != -1)) {
                    781:             // add the @unit:partition
                    782:             len = *length;
                    783:            maxlen -= len;
                    784:            success = (maxlen > 20);
                    785:            if( success ) {
                    786:                 len += sprintf( path + len, "/@%x:%d", unit, partition );
                    787:                *length = len;
                    788:            }
                    789:         }
                    790: 
                    791:     }
                    792:     else
                    793:     {
                    794:         success = super::getPath(path, length, plane);
                    795:     }
                    796: 
                    797:     return success;
                    798: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.