Annotation of XNU/bsd/hfs/hfscommon/Catalog/CatalogUtilities.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 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:        File:           CatalogUtilities.c
                     24: 
                     25:        Contains:       Private Catalog Manager support routines.
                     26: 
                     27:        Version:        HFS Plus 1.0
                     28: 
                     29:        Copyright:      � 1997-2000 by Apple Computer, Inc., all rights reserved.
                     30: 
                     31:        File Ownership:
                     32: 
                     33:                DRI:                            Don Brady
                     34: 
                     35:                Other Contact:          Mark Day
                     36: 
                     37:                Technology:                     xxx put technology here xxx
                     38: 
                     39:        Writers:
                     40: 
                     41:                (DSH)   Deric Horn
                     42:                (msd)   Mark Day
                     43:                (djb)   Don Brady
                     44: 
                     45:        Change History (most recent first):
                     46:          <MacOSX>        1/8/99        djb             Fixing LocateCatalogNodeByMangledName...
                     47:          <MacOSX>        1/7/99        djb             In BuildCatalogKeyUTF8 check name length against NAME_MAX.
                     48:          <MacOSX>       12/7/98        djb             Add ExtractTextEncoding routine to get text encodings.
                     49:          <MacOSX>      11/20/98        djb             Add support for UTF-8 names.
                     50:          <MacOSX>       8/31/98        djb             GetTimeLocal now takes an input.
                     51:          <MacOSX>       4/17/98        djb             Add VCB locking.
                     52:          <MacOSX>        4/3/98        djb             Removed last name conversion cache from LocateCatalogNodeWithRetry.
                     53:          <MacOSX>        4/2/98        djb             InvalidateCatalogNodeCache and TrashCatalogNodeCache are not used in MacOS X.
                     54:          <MacOSX>      03/31/98        djb             Sync up with final HFSVolumes.h header file.
                     55: 
                     56:          <CS24>         1/29/98        DSH             Add TrashCatalogNodeCache for TrashAllFSCaches API support.
                     57:          <CS23>        12/15/97        djb             Radar #2202860, In LocateCatalogNodeByMangledName remap
                     58:                                                                        cmParentNotFound error code to cmNotFound.
                     59:          <CS22>        12/10/97        DSH             2201501, Pin the leof and peof to multiple of allocation blocks
                     60:                                                                        under 2 Gig.
                     61:          <CS21>         12/9/97        DSH             2201501, Pin returned leof values to 2^31-1 (SInt32), instead of
                     62:                                                                        2^32-1
                     63:          <CS20>        11/26/97        djb             Radar #2005688, 2005461 - need to handle kTextMalformedInputErr.
                     64:          <CS19>        11/25/97        djb             Radar #2002357 (again) fix new bug introduced in <CS18>.
                     65:          <CS18>        11/17/97        djb             PrepareInputName routine now returns an error.
                     66:          <CS17>        10/19/97        msd             Bug 1684586. GetCatInfo and SetCatInfo use only contentModDate.
                     67:          <CS16>        10/17/97        djb             Add ConvertInputNameToUnicode for Catalog Create/Rename.
                     68:          <CS15>        10/14/97        djb             Fix LocateCatalogNode's MakeFSSpec optimization (radar #1683166)
                     69:          <CS14>        10/13/97        djb             Copy text encoding in CopyCatalogNodeData. Fix cut/paste error
                     70:                                                                        in VolumeHasEncodings macro. When accessing encoding bitmap use
                     71:                                                                        the MapEncodingToIndex and MapIndexToEncoding macros.
                     72:          <CS13>         10/1/97        djb             Remove old Catalog Iterator code...
                     73:          <CS12>          9/8/97        msd             Make sure a folder's modifyDate is set whenever its
                     74:                                                                        contentModDate is set.
                     75:          <CS11>          9/4/97        djb             Add MakeFSSpec optimization.
                     76:          <CS10>          9/4/97        msd             In CatalogNodeData, change attributeModDate to modifyDate.
                     77:           <CS9>         8/26/97        djb             Back out <CS4> (UpdateFolderCount must maintain vcbNmFls for HFS
                     78:                                                                        Plus volumes too).
                     79:           <CS8>         8/14/97        djb             Remove hard link support.
                     80:           <CS7>         7/18/97        msd             Include LowMemPriv.h.
                     81:           <CS6>         7/16/97        DSH             FilesInternal.i renamed FileMgrInternal.i to avoid name
                     82:                                                                        collision
                     83:           <CS5>          7/8/97        DSH             Loading PrecompiledHeaders from define passed in on C line
                     84:           <CS4>         6/27/97        msd             UpdateFolderCount should update number of root files/folders for
                     85:                                                                        HFS volumes, not HFS Plus.
                     86:           <CS3>         6/24/97        djb             LocateCatalogNodeWithRetry did not always set result code.
                     87:           <CS2>         6/24/97        djb             Add LocateCatalogNodeByMangledName routine
                     88:           <CS1>         6/24/97        djb             first checked in
                     89: */
                     90: 
                     91: #include       "../headers/FileMgrInternal.h"
                     92: #include       "../headers/BTreesInternal.h"
                     93: #include       "../headers/CatalogPrivate.h"
                     94: #include       "../headers/HFSUnicodeWrappers.h"
                     95: #include       <string.h>
                     96: 
                     97: static void ExtractTextEncoding (ItemCount length, ConstUniCharArrayPtr string, UInt32 * textEncoding);
                     98: 
                     99: //*******************************************************************************
                    100: //     Routine:        LocateCatalogNode
                    101: //
                    102: // Function:   Locates the catalog record for an existing folder or file
                    103: //                             CNode and returns pointers to the key and data records.
                    104: //
                    105: //*******************************************************************************
                    106: 
                    107: OSErr
                    108: LocateCatalogNode(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name,
                    109:                                        UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *newHint)
                    110: {
                    111:        OSErr                           result;
                    112:        CatalogName             *nodeName = NULL;       /* To ward off uninitialized use warnings from compiler */
                    113:        HFSCatalogNodeID        threadParentID;
                    114: 
                    115: 
                    116:        result = LocateCatalogRecord(volume, folderID, name, hint, keyPtr, dataPtr, newHint);
                    117:        ReturnIfError(result);
                    118:        
                    119:        // if we got a thread record, then go look up real record
                    120:        switch ( dataPtr->recordType )
                    121:        {
                    122:                case kHFSFileThreadRecord:
                    123:                case kHFSFolderThreadRecord:
                    124:                        threadParentID = dataPtr->hfsThread.parentID;
                    125:                        nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName;
                    126:                        break;
                    127: 
                    128:                case kHFSPlusFileThreadRecord:
                    129:                case kHFSPlusFolderThreadRecord:
                    130:                        threadParentID = dataPtr->hfsPlusThread.parentID;
                    131:                        nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName;    
                    132:                        break;
                    133: 
                    134:                default:
                    135:                        threadParentID = 0;
                    136:                        break;
                    137:        }
                    138:        
                    139:        if ( threadParentID )           // found a thread
                    140:                result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
                    141:        
                    142:        return result;
                    143: }
                    144: 
                    145: //
                    146: //     Routine:        LocateCatalogNodeByKey
                    147: //
                    148: // Function:   Locates the catalog record for an existing folder or file
                    149: //                             CNode and returns the key and data records.
                    150: //
                    151: 
                    152: OSErr
                    153: LocateCatalogNodeByKey(const ExtendedVCB *volume, UInt32 hint, CatalogKey *keyPtr,
                    154:                                                CatalogRecord *dataPtr, UInt32 *newHint)
                    155: {
                    156:        OSErr                           result;
                    157:        CatalogName             *nodeName = NULL;       /* To ward off uninitialized use warnings from compiler */
                    158:        HFSCatalogNodeID        threadParentID;
                    159:        UInt16 tempSize;
                    160: 
                    161: 
                    162:        result = SearchBTreeRecord(volume->catalogRefNum, keyPtr, hint, keyPtr,
                    163:                                                                dataPtr, &tempSize, newHint);
                    164:        if (result == btNotFound)
                    165:                result = cmNotFound;    
                    166:        ReturnIfError(result);
                    167:        
                    168:        // if we got a thread record, then go look up real record
                    169:        switch ( dataPtr->recordType )
                    170:        {
                    171:                case kHFSFileThreadRecord:
                    172:                case kHFSFolderThreadRecord:
                    173:                        threadParentID = dataPtr->hfsThread.parentID;
                    174:                        nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName;
                    175:                        break;
                    176: 
                    177:                case kHFSPlusFileThreadRecord:
                    178:                case kHFSPlusFolderThreadRecord:
                    179:                        threadParentID = dataPtr->hfsPlusThread.parentID;
                    180:                        nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName;    
                    181:                        break;
                    182: 
                    183:                default:
                    184:                        threadParentID = 0;
                    185:                        break;
                    186:        }
                    187:        
                    188:        if ( threadParentID )           // found a thread
                    189:                result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint);
                    190:        
                    191:        return result;
                    192: }
                    193: 
                    194: 
                    195: #if 0
                    196: //*******************************************************************************
                    197: //     Routine:        LocateCatalogNodeWithRetry
                    198: //
                    199: // Function:   Locates the catalog record for an existing folder or file node.
                    200: //                             For HFS Plus volumes a retry is performed when a catalog node is
                    201: //                             not found and the volume contains more than one text encoding.
                    202: //
                    203: //�������������������������������������������������������������������������������
                    204: 
                    205: #define VolumeHasEncodings(v) \
                    206:        ( ((v)->encodingsBitmap != 0 )
                    207: 
                    208: #define        EncodingInstalled(i) \
                    209:        ( (fsVars)->gConversionContext[(i)].toUnicode != 0 )
                    210: 
                    211: #define        EncodingUsedByVolume(v,i) \
                    212:        ( ((v)->encodingsBitmap & (1 << (i))) )
                    213: 
                    214: 
                    215: OSErr
                    216: LocateCatalogNodeWithRetry (const ExtendedVCB *volume, HFSCatalogNodeID folderID, ConstStr31Param pascalName, CatalogName *unicodeName,
                    217:                                                        UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *newHint)
                    218: {
                    219:        TextEncoding            defaultEncoding;
                    220:        TextEncoding            encoding;
                    221:        ItemCount                       encodingsToTry;
                    222:        FSVarsRec                       *fsVars;
                    223:        OSErr                           result = cmNotFound;
                    224: 
                    225:        fsVars = (FSVarsRec*) LMGetFSMVars();   // used by macros
                    226: 
                    227:        defaultEncoding = GetDefaultTextEncoding();
                    228:        encodingsToTry = CountInstalledEncodings();
                    229: 
                    230:        // 1. Try finding file using default encoding (typical case)
                    231: 
                    232:        {
                    233:                --encodingsToTry;
                    234:                result = PrepareInputName(pascalName, true, defaultEncoding, unicodeName);
                    235:                if (result == noErr)
                    236:                        result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint);
                    237:                else
                    238:                        result = cmNotFound;
                    239: 
                    240:                if ( result != cmNotFound || encodingsToTry == 0)
                    241:                        return result;
                    242:        }
                    243: 
                    244:        //
                    245:        // XXX if the pascal string contains all 7-bit ascii then we don't need to do anymore retries
                    246:        //
                    247: 
                    248:        // 2. Try finding file using Mac Roman (if not already tried above)
                    249: 
                    250:        if ( defaultEncoding != kTextEncodingMacRoman )
                    251:        {
                    252:                --encodingsToTry;
                    253:                result = PrepareInputName(pascalName, true, kTextEncodingMacRoman, unicodeName);
                    254:                if (result == noErr)
                    255:                        result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint);
                    256:                else
                    257:                        result = cmNotFound;
                    258: 
                    259:                if ( result != cmNotFound || encodingsToTry == 0 )
                    260:                        return result;
                    261:        }
                    262: 
                    263:        // 3. Try with encodings from disk (if any)
                    264: 
                    265:        if ( VolumeHasEncodings(volume) )       // any left to try?
                    266:        {
                    267:                UInt32  index;
                    268: 
                    269:                index = 0;      // since we pre increment this will skip MacRoman (which was already tried above)
                    270: 
                    271:                while ( index < kMacBaseEncodingCount )
                    272:                {
                    273:                        ++index;
                    274:                        
                    275:                        encoding = MapIndexToEncoding(index);
                    276: 
                    277:                        if ( encoding == defaultEncoding )
                    278:                                continue;               // we did this one already
                    279: 
                    280:                        if ( EncodingInstalled(index) && EncodingUsedByVolume(volume, index) )
                    281:                        {
                    282:                                --encodingsToTry;
                    283:                                result = PrepareInputName(pascalName, true, encoding, unicodeName);
                    284:                                if (result == noErr)
                    285:                                        result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint);
                    286:                                else
                    287:                                        result = cmNotFound;
                    288: 
                    289:                                if ( result != cmNotFound || encodingsToTry == 0 )
                    290:                                        return result;
                    291:                        }
                    292:                }
                    293:        }
                    294: 
                    295:        // 4. Try any remaining encodings (if any)
                    296: 
                    297:        {
                    298:                UInt32  index;
                    299: 
                    300:                index = 0;      // since we pre increment this will skip MacRoman (which was already tried above)
                    301:        
                    302:                while ( (encodingsToTry > 0) && (index < kMacBaseEncodingCount) )
                    303:                {
                    304:                        ++index;
                    305:        
                    306:                        encoding = MapIndexToEncoding(index);
                    307:        
                    308:                        if ( encoding == defaultEncoding )
                    309:                                continue;               // we did this one already
                    310:        
                    311:                        if ( EncodingInstalled(index) && EncodingUsedByVolume(volume, index) == false )
                    312:                        {
                    313:                                --encodingsToTry;
                    314:                                result = PrepareInputName(pascalName, true, encoding, unicodeName);
                    315:                                if (result == noErr)
                    316:                                        result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint);
                    317:                                else
                    318:                                        result = cmNotFound;
                    319: 
                    320:                                if ( result != cmNotFound || encodingsToTry == 0 )
                    321:                                        return result;
                    322:                        }
                    323:                }
                    324:        }
                    325: 
                    326:        return cmNotFound;
                    327: }
                    328: #endif
                    329: 
                    330: //*******************************************************************************
                    331: //     Routine:        LocateCatalogNodeByMangledName
                    332: //
                    333: // Function:   Locates the catalog record associated with a mangled name (if any)
                    334: //
                    335: //*******************************************************************************
                    336: 
                    337: OSErr
                    338: LocateCatalogNodeByMangledName( const ExtendedVCB *volume, HFSCatalogNodeID folderID,
                    339:                                                                const unsigned char * name, UInt32 length, CatalogKey *keyPtr,
                    340:                                                                CatalogRecord *dataPtr, UInt32 *hintPtr )
                    341: {
                    342:        HFSCatalogNodeID        fileID;
                    343:        unsigned char           nodeName[64];
                    344:        OSErr                           result;
                    345:        ByteCount                       actualDstLen;
                    346:        ByteCount                       prefixlen;
                    347: 
                    348: 
                    349:        if (name == NULL || name[0] == '\0')
                    350:                return cmNotFound;
                    351: 
                    352:        fileID = GetEmbeddedFileID(name, length, &prefixlen);
                    353: 
                    354:        if ( fileID < kHFSFirstUserCatalogNodeID )
                    355:                return cmNotFound;
                    356:                
                    357:        result = LocateCatalogNode(volume, fileID, NULL, kNoHint, keyPtr, dataPtr, hintPtr);
                    358:        if ( result == cmParentNotFound )       // GetCatalogNode already handled cmParentNotFound case         <CS23>
                    359:                result = cmNotFound;                    // so remap                                                                                                     <CS23>
                    360:        ReturnIfError(result);
                    361:                
                    362:        // first make sure that the parents match
                    363:        if ( folderID != keyPtr->hfsPlus.parentID )
                    364:                return cmNotFound;                      // not the same folder so this is a false match
                    365: 
                    366:        result =  ConvertUnicodeToUTF8( keyPtr->hfsPlus.nodeName.length * sizeof (UniChar),
                    367:                                                                        keyPtr->hfsPlus.nodeName.unicode,
                    368:                                                                        64,
                    369:                                                                        &actualDstLen,
                    370:                                                                        nodeName);
                    371: 
                    372:        if ( (actualDstLen < prefixlen) || bcmp(nodeName, name, prefixlen) != 0)
                    373:                return cmNotFound;      // mangled names didn't match so this is a false match
                    374:        
                    375:        return noErr;   // we found it
                    376: }
                    377: 
                    378: 
                    379: //*******************************************************************************
                    380: //     Routine:        LocateCatalogRecord
                    381: //
                    382: // Function:   Locates the catalog record associated with folderID and name
                    383: //
                    384: //*******************************************************************************
                    385: 
                    386: OSErr
                    387: LocateCatalogRecord(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name,
                    388:                                        UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *newHint)
                    389: {
                    390:        OSErr                   result;
                    391:        CatalogKey              tempKey;        // 518 bytes
                    392:        UInt16                  tempSize;
                    393: 
                    394:        BuildCatalogKey(folderID, name, (volume->vcbSigWord == kHFSPlusSigWord), &tempKey);
                    395: 
                    396:        if ( name == NULL )
                    397:                hint = kNoHint;                 // no CName given so clear the hint
                    398: 
                    399:        result = SearchBTreeRecord(volume->catalogRefNum, &tempKey, hint, keyPtr, dataPtr, &tempSize, newHint);
                    400:        
                    401:        return (result == btNotFound ? cmNotFound : result);    
                    402: }
                    403: 
                    404: 
                    405: //*******************************************************************************
                    406: //     Routine:        LocateCatalogThread
                    407: //
                    408: //     Function:       Locates a catalog thread record in the catalog BTree file and 
                    409: //                             returns a pointer to the data record.
                    410: //
                    411: //*******************************************************************************
                    412: 
                    413: OSErr
                    414: LocateCatalogThread(const ExtendedVCB *volume, HFSCatalogNodeID nodeID, CatalogRecord *threadData, UInt16 *threadSize, UInt32 *threadHint)
                    415: {
                    416:        CatalogKey      threadKey;      // 518 bytes
                    417:        OSErr           result;
                    418: 
                    419:        //--- build key record
                    420: 
                    421:        BuildCatalogKey(nodeID, NULL, (volume->vcbSigWord == kHFSPlusSigWord), &threadKey);
                    422: 
                    423:        //--- locate thread record in BTree
                    424: 
                    425:        result = SearchBTreeRecord( volume->catalogRefNum, &threadKey, kNoHint, &threadKey,
                    426:                                                                threadData, threadSize, threadHint);
                    427:        
                    428:        return (result == btNotFound ? cmNotFound : result);    
                    429: }
                    430: 
                    431: 
                    432: /*
                    433:  *     Routine:        BuildCatalogKey
                    434:  *
                    435:  *     Function:       Constructs a catalog key record (ckr) given the parent
                    436:  *                             folder ID and CName.  Works for both classic and extended
                    437:  *                             HFS volumes.
                    438:  *
                    439:  */
                    440: 
                    441: void
                    442: BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key)
                    443: {
                    444:        if ( isHFSPlus )
                    445:        {
                    446:                key->hfsPlus.keyLength                  = kHFSPlusCatalogKeyMinimumLength;      // initial key length (4 + 2)
                    447:                key->hfsPlus.parentID                   = parentID;             // set parent ID
                    448:                key->hfsPlus.nodeName.length    = 0;                    // null CName length
                    449:                if ( cName != NULL )
                    450:                {
                    451:                        CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus);
                    452:                        key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; // add CName size to key length
                    453:                }
                    454:        }
                    455:        else
                    456:        {
                    457:                key->hfs.keyLength              = kHFSCatalogKeyMinimumLength;  // initial key length (1 + 4 + 1)
                    458:                key->hfs.reserved               = 0;                            // clear unused byte
                    459:                key->hfs.parentID               = parentID;                     // set parent ID
                    460:                key->hfs.nodeName[0]    = 0;                            // null CName length
                    461:                if ( cName != NULL )
                    462:                {
                    463:                        UpdateCatalogName(cName->pstr, key->hfs.nodeName);
                    464:                        key->hfs.keyLength += key->hfs.nodeName[0];             // add CName size to key length
                    465:                }
                    466:        }
                    467: }
                    468: 
                    469: /*
                    470:  * for HFS, only MacRoman is supported. If a non-MacRoman character is found, an error is returned
                    471:  */
                    472: OSErr
                    473: BuildCatalogKeyUTF8(ExtendedVCB *volume, HFSCatalogNodeID parentID, const char *name, UInt32 nameLength,
                    474:                    CatalogKey *key, UInt32 *textEncoding)
                    475: {
                    476:        OSErr err = 0;
                    477: 
                    478:     if ( name == NULL)
                    479:         nameLength = 0;
                    480:     else if (nameLength == kUndefinedStrLen)
                    481:         nameLength = strlen(name);
                    482: 
                    483:        if ( volume->vcbSigWord == kHFSPlusSigWord ) {
                    484:                ByteCount unicodeBytes = 0;
                    485: 
                    486:                key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength;       // initial key length (4 + 2)
                    487:                key->hfsPlus.parentID = parentID;                       // set parent ID
                    488:                key->hfsPlus.nodeName.length = 0;                       // null CName length
                    489:                if ( nameLength > 0 ) {
                    490:                        err = ConvertUTF8ToUnicode(nameLength, name, sizeof(key->hfsPlus.nodeName.unicode),
                    491:                                                                &unicodeBytes, key->hfsPlus.nodeName.unicode);
                    492:                        key->hfsPlus.nodeName.length = unicodeBytes / sizeof(UniChar);
                    493:                        key->hfsPlus.keyLength += unicodeBytes;
                    494:                }
                    495: 
                    496:                if (textEncoding)
                    497:                ExtractTextEncoding(key->hfsPlus.nodeName.length, key->hfsPlus.nodeName.unicode, textEncoding);
                    498:        }
                    499:        else {
                    500:                key->hfs.keyLength              = kHFSCatalogKeyMinimumLength;  // initial key length (1 + 4 + 1)
                    501:                key->hfs.reserved               = 0;                            // clear unused byte
                    502:                key->hfs.parentID               = parentID;                     // set parent ID
                    503:                key->hfs.nodeName[0]    = 0;                            // null CName length
                    504:                if ( nameLength > 0 ) {
                    505:                        err = utf8_to_hfs(volume, nameLength, name, &key->hfs.nodeName[0]);
                    506:                        key->hfs.keyLength += key->hfs.nodeName[0];             // add CName size to key length
                    507:                }
                    508:                if (textEncoding)
                    509:                        *textEncoding = 0;
                    510:        }
                    511: 
                    512:        if (err) {
                    513:                if (err == kTECOutputBufferFullStatus)
                    514:                        err = bdNamErr; /* name is too long */
                    515:                else
                    516:                        err = paramErr; /* name has invalid characters */
                    517:        }
                    518: 
                    519:        return err;
                    520: }
                    521: 
                    522: 
                    523: /*
                    524:  * make a guess at the text encoding value that coresponds to the Unicode characters
                    525:  */
                    526: static void
                    527: ExtractTextEncoding(ItemCount length, ConstUniCharArrayPtr string, UInt32 * textEncoding)
                    528: {
                    529:        int i;
                    530:        UniChar ch;
                    531: 
                    532:        *textEncoding = 0;
                    533: 
                    534:        for (i = 0; i < length; ++i) {
                    535:                ch = string[i];
                    536:                /* CJK codepoints are 0x3000 thru 0x9FFF */
                    537:                if (ch >= 0x3000) {
                    538:                        if (ch < 0xa000) {
                    539:                                *textEncoding = kTextEncodingMacJapanese;
                    540:                                break;
                    541:                        }
                    542: 
                    543:                        /* fullwidth character codepoints are 0xFF00 thru 0xFFEF */
                    544:                        if (ch >= 0xff00 && ch <= 0xffef) {
                    545:                                *textEncoding = kTextEncodingMacJapanese;
                    546:                                break;  
                    547:                        }
                    548:                }
                    549:        }
                    550: }
                    551: 
                    552: 
                    553: //*******************************************************************************
                    554: //     Routine:        FlushCatalog
                    555: //
                    556: // Function:   Flushes the catalog for a specified volume.
                    557: //
                    558: //*******************************************************************************
                    559: 
                    560: OSErr
                    561: FlushCatalog(ExtendedVCB *volume)
                    562: {
                    563:        FCB *   fcb;
                    564:        OSErr   result;
                    565:        
                    566:        fcb = GetFileControlBlock(volume->catalogRefNum);
                    567:        result = BTFlushPath(fcb);
                    568: 
                    569:        if (result == noErr)
                    570:        {
                    571:                //--- check if catalog's fcb is dirty...
                    572:                
                    573:                if ( fcb->fcbFlags & fcbModifiedMask )
                    574:                {
                    575:                        VCB_LOCK(volume);
                    576:                        volume->vcbFlags |= 0xFF00;             // Mark the VCB dirty
                    577:                        volume->vcbLsMod = GetTimeUTC();        // update last modified date
                    578:                        VCB_UNLOCK(volume);
                    579: 
                    580:                        result = FlushVolumeControlBlock(volume);
                    581:                }
                    582:        }
                    583:        
                    584:        return result;
                    585: }
                    586: 
                    587: 
                    588: //�������������������������������������������������������������������������������
                    589: //     Routine:        UpdateCatalogName
                    590: //
                    591: //     Function:       Updates a CName.
                    592: //
                    593: //�������������������������������������������������������������������������������
                    594: 
                    595: void
                    596: UpdateCatalogName(ConstStr31Param srcName, Str31 destName)
                    597: {
                    598:        Size length = srcName[0];
                    599:        
                    600:        if (length > CMMaxCName)
                    601:                length = CMMaxCName;                            // truncate to max
                    602: 
                    603:        destName[0] = length;                                   // set length byte
                    604:        
                    605:        BlockMoveData(&srcName[1], &destName[1], length);
                    606: }
                    607: 
                    608: 
                    609: //*******************************************************************************
                    610: //     Routine:        AdjustVolumeCounts
                    611: //
                    612: //     Function:       Adjusts the folder and file counts in the VCB
                    613: //
                    614: //*******************************************************************************
                    615: 
                    616: void
                    617: AdjustVolumeCounts(ExtendedVCB *volume, SInt16 type, SInt16 delta)
                    618: {
                    619:        //�� also update extended VCB fields...
                    620: 
                    621:        VCB_LOCK(volume);
                    622: 
                    623:        if (type == kHFSFolderRecord || type == kHFSPlusFolderRecord)
                    624:                volume->vcbDirCnt += delta;                     // adjust volume folder count, �� worry about overflow?
                    625:        else
                    626:                volume->vcbFilCnt += delta;                     // adjust volume file count
                    627:        
                    628:        volume->vcbFlags |= 0xFF00;             // Mark the VCB dirty
                    629:        volume->vcbLsMod = GetTimeUTC();        // update last modified date
                    630: 
                    631:        VCB_UNLOCK(volume);
                    632: }
                    633: 
                    634: 
                    635: //*******************************************************************************
                    636: 
                    637: void
                    638: UpdateVolumeEncodings(ExtendedVCB *volume, TextEncoding encoding)
                    639: {
                    640:        UInt32  index;
                    641: 
                    642:        encoding &= 0x7F;
                    643:        
                    644:        index = MapEncodingToIndex(encoding);
                    645: 
                    646:        VCB_LOCK(volume);
                    647: 
                    648:        volume->encodingsBitmap |= (1 << index);
                    649: 
                    650:        VCB_UNLOCK(volume);
                    651:                
                    652:        // vcb should already be marked dirty
                    653: }
                    654: 
                    655: 
                    656: //*******************************************************************************
                    657: 
                    658: OSErr
                    659: UpdateFolderCount( ExtendedVCB *volume, HFSCatalogNodeID parentID, const CatalogName *name, SInt16 newType,
                    660:                                        UInt32 hint, SInt16 valenceDelta)
                    661: {
                    662:        CatalogKey                      tempKey;        // 518 bytes
                    663:        CatalogRecord           tempData;       // 520 bytes
                    664:        UInt32                          tempHint;
                    665:        HFSCatalogNodeID        folderID;
                    666:        UInt16                          recordSize;
                    667:        OSErr                           result;
                    668: 
                    669: #if 0
                    670:        result = SearchBTreeRecord(volume->catalogRefNum, parentKey, hint,
                    671:                                                                &tempKey, &tempData, &recordSize, &tempHint);
                    672:        if (result)
                    673:                return (result == btNotFound ? cmNotFound : result);    
                    674: #else
                    675: 
                    676:        result = LocateCatalogNode(volume, parentID, name, hint, &tempKey, &tempData, &tempHint);
                    677:        ReturnIfError(result);
                    678: #endif
                    679: 
                    680:        if ( volume->vcbSigWord == kHFSPlusSigWord ) // HFS Plus
                    681:        {
                    682:                UInt32          timeStamp;
                    683:                
                    684:                if ( DEBUG_BUILD && tempData.recordType != kHFSPlusFolderRecord )
                    685:                        DebugStr("\p UpdateFolder: found HFS folder on HFS+ volume!");
                    686: 
                    687:                timeStamp = GetTimeUTC();
                    688:                tempData.hfsPlusFolder.valence += valenceDelta;         // adjust valence
                    689:                tempData.hfsPlusFolder.contentModDate = timeStamp;      // set date/time last modified
                    690:                folderID = tempData.hfsPlusFolder.folderID;
                    691:                recordSize = sizeof(tempData.hfsPlusFolder);
                    692:        }
                    693:        else // classic HFS
                    694:        {
                    695:                if ( DEBUG_BUILD && tempData.recordType != kHFSFolderRecord )
                    696:                        DebugStr("\p UpdateFolder: found HFS+ folder on HFS volume!");
                    697: 
                    698:                tempData.hfsFolder.valence += valenceDelta;                             // adjust valence
                    699:                tempData.hfsFolder.modifyDate = GetTimeLocal(true);             // set date/time last modified
                    700:                folderID = tempData.hfsFolder.folderID;
                    701:                recordSize = sizeof(tempData.hfsFolder);
                    702:        }
                    703:        
                    704:        result = ReplaceBTreeRecord(volume->catalogRefNum, &tempKey, tempHint,
                    705:                                                                &tempData, recordSize, &tempHint);
                    706:        ReturnIfError(result);
                    707: 
                    708:        if ( folderID == kHFSRootFolderID )
                    709:        {
                    710:                if (newType == kHFSFolderRecord || newType == kHFSPlusFolderRecord)
                    711:                {
                    712:                        VCB_LOCK(volume);
                    713:                        volume->vcbNmRtDirs += valenceDelta;    // adjust root folder count (undefined for HFS Plus)
                    714:                        VCB_UNLOCK(volume);
                    715:                }
                    716:                else
                    717:                {
                    718:                        VCB_LOCK(volume);
                    719:                        volume->vcbNmFls += valenceDelta;               // adjust root file count (used by GetVolInfo)
                    720:                        VCB_UNLOCK(volume);
                    721:                }
                    722:        }
                    723: 
                    724:        //XXX also update extended VCB fields...
                    725: 
                    726:        return result;
                    727: }
                    728: 
                    729: 
                    730: //*******************************************************************************
                    731: 
                    732: UInt16 
                    733: GetCatalogRecordSize(const CatalogRecord *dataRecord)
                    734: {
                    735:        switch (dataRecord->recordType)
                    736:        {
                    737:                case kHFSFileRecord:
                    738:                        return sizeof(HFSCatalogFile);
                    739: 
                    740:                case kHFSFolderRecord:
                    741:                        return sizeof(HFSCatalogFolder);
                    742: 
                    743:                case kHFSPlusFileRecord:
                    744:                        return sizeof(HFSPlusCatalogFile);
                    745: 
                    746:                case kHFSPlusFolderRecord:
                    747:                        return sizeof(HFSPlusCatalogFolder);
                    748:                        
                    749:                case kHFSFolderThreadRecord:
                    750:                case kHFSFileThreadRecord:
                    751:                        return sizeof(HFSCatalogThread);
                    752: 
                    753:                case kHFSPlusFolderThreadRecord:
                    754:                case kHFSPlusFileThreadRecord:
                    755:                        return sizeof(HFSPlusCatalogThread);
                    756: 
                    757:                default:
                    758:                        return 0;
                    759:        }
                    760: }
                    761: 
                    762: 
                    763: //*******************************************************************************
                    764: 
                    765: void
                    766: CopyCatalogNodeData(const ExtendedVCB *volume, const CatalogRecord *dataPtr, CatalogNodeData *nodeData)
                    767: {
                    768:        /* convert classic hfs records to hfs plus format */
                    769: 
                    770:        if (dataPtr->recordType == kHFSFolderRecord) {
                    771:                nodeData->cnd_type = kCatalogFolderNode;
                    772:                nodeData->cnd_flags = dataPtr->hfsFolder.flags;
                    773:                nodeData->cnd_nodeID = dataPtr->hfsFolder.folderID;
                    774:                nodeData->cnd_createDate = LocalToUTC(dataPtr->hfsFolder.createDate);
                    775:                nodeData->cnd_contentModDate = LocalToUTC(dataPtr->hfsFolder.modifyDate);
                    776:                nodeData->cnd_backupDate = LocalToUTC(dataPtr->hfsFolder.backupDate);
                    777:                nodeData->cnd_valence = dataPtr->hfsFolder.valence;
                    778: 
                    779:                BlockMoveData(&dataPtr->hfsFolder.userInfo, &nodeData->cnd_finderInfo, 32);
                    780:        } else {
                    781:                        UInt32  i;
                    782: 
                    783:                nodeData->cnd_type = kCatalogFileNode;
                    784:                nodeData->cnd_flags = dataPtr->hfsFile.flags;
                    785:                nodeData->cnd_nodeID = dataPtr->hfsFile.fileID;
                    786:                nodeData->cnd_createDate = LocalToUTC(dataPtr->hfsFile.createDate);
                    787:                nodeData->cnd_contentModDate = LocalToUTC(dataPtr->hfsFile.modifyDate);
                    788:                nodeData->cnd_backupDate = LocalToUTC(dataPtr->hfsFile.backupDate);
                    789:                nodeData->cnd_linkCount = 0;
                    790: 
                    791:                BlockMoveData(&dataPtr->hfsFile.userInfo, &nodeData->cnd_finderInfo, 16);
                    792:                BlockMoveData(&dataPtr->hfsFile.finderInfo, (void*)((UInt32)&nodeData->cnd_finderInfo + 16), 16);
                    793: 
                    794:                nodeData->cnd_datafork.logicalSize = dataPtr->hfsFile.dataLogicalSize;
                    795:                nodeData->cnd_datafork.totalBlocks =
                    796:                        dataPtr->hfsFile.dataPhysicalSize / volume->blockSize;
                    797: 
                    798:                nodeData->cnd_rsrcfork.logicalSize  = dataPtr->hfsFile.rsrcLogicalSize;
                    799:                nodeData->cnd_rsrcfork.totalBlocks =
                    800:                        dataPtr->hfsFile.rsrcPhysicalSize / volume->blockSize;
                    801: 
                    802:                for (i = 0; i < kHFSExtentDensity; ++i) {
                    803:                        nodeData->cnd_datafork.extents[i].startBlock =
                    804:                                (UInt32) (dataPtr->hfsFile.dataExtents[i].startBlock);
                    805: 
                    806:                        nodeData->cnd_datafork.extents[i].blockCount =
                    807:                                (UInt32) (dataPtr->hfsFile.dataExtents[i].blockCount);
                    808: 
                    809:                        nodeData->cnd_rsrcfork.extents[i].startBlock =
                    810:                                (UInt32) (dataPtr->hfsFile.rsrcExtents[i].startBlock);
                    811: 
                    812:                        nodeData->cnd_rsrcfork.extents[i].blockCount =
                    813:                                (UInt32) (dataPtr->hfsFile.rsrcExtents[i].blockCount);
                    814:                }
                    815:                for (i = kHFSExtentDensity; i < kHFSPlusExtentDensity; ++i) {
                    816:                        nodeData->cnd_datafork.extents[i].startBlock = 0;
                    817:                        nodeData->cnd_datafork.extents[i].blockCount = 0;
                    818:                        nodeData->cnd_rsrcfork.extents[i].startBlock = 0;
                    819:                        nodeData->cnd_rsrcfork.extents[i].blockCount = 0;
                    820:                }
                    821:        }
                    822: }
                    823: 
                    824: 
                    825: //_______________________________________________________________________
                    826: 
                    827: void
                    828: CopyCatalogName(const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPLus)
                    829: {
                    830:        UInt32  length;
                    831:        
                    832:        if ( srcName == NULL )
                    833:        {
                    834:                if ( dstName != NULL )
                    835:                        dstName->ustr.length = 0;       // set length byte to zero (works for both unicode and pascal)          
                    836:                return;
                    837:        }
                    838:        
                    839:        if (isHFSPLus)
                    840:                length = sizeof(UniChar) * (srcName->ustr.length + 1);
                    841:        else
                    842:                length = sizeof(UInt8) + srcName->pstr[0];
                    843: 
                    844:        if ( length > 1 )
                    845:                BlockMoveData(srcName, dstName, length);
                    846:        else
                    847:                dstName->ustr.length = 0;       // set length byte to zero (works for both unicode and pascal)          
                    848: }
                    849: 
                    850: //_______________________________________________________________________
                    851: 
                    852: UInt32
                    853: CatalogNameLength(const CatalogName *name, Boolean isHFSPlus)
                    854: {
                    855:        if (isHFSPlus)
                    856:                return name->ustr.length;
                    857:        else
                    858:                return name->pstr[0];
                    859: }
                    860: 
                    861: 
                    862: 

unix.superglobalmegacorp.com

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