Annotation of XNU/bsd/hfs/hfscommon/Catalog/CatalogUtilities.c, revision 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.