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

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /*
                     26:        File:           Catalog.c
                     27: 
                     28:        Contains:       Catalog Manager Implementation
                     29: 
                     30:        Version:        HFS Plus 1.0
                     31: 
                     32:        Copyright:      � 1996-1999 by Apple Computer, Inc., all rights reserved.
                     33: 
                     34:        File Ownership:
                     35: 
                     36:                DRI:                            Don Brady
                     37: 
                     38:                Other Contact:          Mark Day
                     39: 
                     40:                Technology:                     xxx put technology here xxx
                     41: 
                     42:        Writers:
                     43: 
                     44:                (msd)   Mark Day
                     45:                (DSH)   Deric Horn
                     46:                (djb)   Don Brady
                     47: 
                     48:        Change History (most recent first):
                     49:          <Rhap>          2/2/99        djb             Fix CreateFileIDRef to copy entire name when creating thread record.
                     50:          <Rhap>          1/7/99        djb             Use a max bytes of 256 in calls to ConvertUnicodeToUTF8.
                     51:          <Rhap>         12/9/98        djb             UpdateCatalogNode only updates vcbLsMod if contentModDate changes.
                     52:          <Rhap>         11/5/98        djb             Add support for UTF-8 names.
                     53:          <Rhap>         8/31/98        djb             GetTimeLocal now takes an input.
                     54:          <Rhap>          7/8/98        ser             Added accessDate and AttributeModDate init. to create routine.
                     55:          <Rhap>          6/5/98        djb             Added CreateFileIDRef routine.
                     56:          <Rhap>          6/3/98        djb             Merge MoveCatalogRecord and RenameCatalogRecord into one routine.
                     57:          <Rhap>         4/17/98        djb             Add VCB locking.
                     58:          <Rhap>          4/6/98        djb             Catalog iterators now need to be released.
                     59:          <Rhap>          4/6/98        djb             Removed CreateVolumeCatalogCache and DisposeVolumeCatalogCache (obsolete).
                     60:          <Rhap>         3/31/98        djb             Make UpdateCatalogNode interface thread-safe.
                     61:          <Rhap>         3/31/98        djb             Sync up with final HFSVolumes.h header file.
                     62:          <Rhap>         3/17/98        djb             Fixed CreateCatalogNode interface to take kCatalogFolderNode and
                     63:                                                                        kCatalogFileNode as type input.
                     64: 
                     65:          <CS36>        12/10/97        DSH             2201501, UpdateCatalogNode to only update CatalogRecords which
                     66:                                                                        are under 2 Gig by checking the overloaded valence field.
                     67:          <CS35>        11/20/97        djb             Radar #2002357. Fixing retry mechanism.
                     68:          <CS34>        11/17/97        djb             PrepareInputName routine now returns an error.
                     69:          <CS33>        11/13/97        djb             Radar #1683572. Add new GetCatalogOffspringFile routine for
                     70:                                                                        PBGetFileInfo calls (support used to be in HFSPathnameCalls.a).
                     71:          <CS32>         11/7/97        msd             Change calls to the wrapper routine CompareUnicodeNames() to use
                     72:                                                                        the underlying routine FastUnicodeCompare() instead.
                     73:          <CS31>        10/19/97        msd             Bug 1684586. GetCatInfo and SetCatInfo use only contentModDate.
                     74:          <CS30>        10/17/97        djb             Change Catalog Create/Rename to use ConvertInputNameToUnicode.
                     75:          <CS29>        10/13/97        djb             Update volumeNameEncodingHint when changing volume name. Change
                     76:                                                                        name of GetSystemTextEncoding to GetDefaultTextEncoding.
                     77:          <CS28>         10/1/97        djb             Add new catalog iterators and node cache to improve performance.
                     78:          <CS27>         9/12/97        msd             In CreateCatalogNode, make sure parent is a folder, not a file.
                     79:          <CS26>         9/10/97        msd             In RenameCatalogNodeUnicode, remove HFS-only code and make sure
                     80:                                                                        the conversion context is set up and marked in the volume's
                     81:                                                                        bitmap.
                     82:          <CS25>          9/9/97        DSH             Added RelString_Glue to avoid having to link DFAEngine with
                     83:                                                                        Interface.o
                     84:          <CS24>          9/8/97        msd             Make sure a folder's modifyDate is set whenever its
                     85:                                                                        contentModDate is set. In UpdateCatalogNode, make sure the
                     86:                                                                        modifyDate is greater or equal to contentModDate; do a DebugStr
                     87:                                                                        only for debug builds.
                     88:          <CS23>          9/7/97        djb             Make some DebuStrs DEBUG_BUILD only.
                     89:          <CS22>          9/4/97        djb             Add more Catalog Iterators, Instrument RelString.
                     90:          <CS21>          9/4/97        msd             Remove call to PropertyDeleteObject.
                     91:          <CS20>         8/18/97        DSH             Use RelString instead of FastRelString in DFA to avoid loading
                     92:                                                                        branch island instead of table.
                     93:          <CS19>         8/14/97        djb             Remove hard link support. Switch over to FastRelString.
                     94:          <CS18>          8/8/97        djb             Fixed bugs in LinkCatalogNode.
                     95:          <CS17>          8/5/97        djb             Don't restore vcbNxtCNID if thread exists (radar #1670614).
                     96:          <CS16>         7/25/97        DSH             Pass heuristicHint to BTSearchRecord from GetCatalogOffspring.
                     97:          <CS15>         7/18/97        msd             Include LowMemPriv.h. In LinkCatalogNode, now sets the
                     98:                                                                        kInsertedFileThread2 flag correctly; should only affect error
                     99:                                                                        recovery code.
                    100:          <CS14>         7/16/97        DSH             FilesInternal.i renamed FileMgrInternal.i to avoid name
                    101:                                                                        collision
                    102:          <CS13>          7/8/97        DSH             Loading PrecompiledHeaders from define passed in on C line
                    103:          <CS12>         6/27/97        msd             Add PBLongRename SPI. Added RenameCatalogNodeUnicode call, which
                    104:                                                                        takes Unicode names for HFS Plus volumes. Removed calls to
                    105:                                                                        Attributes module when creating, renaming or moving nodes.
                    106:          <CS11>         6/24/97        djb             Validate the mangled name matches in
                    107:                                                                        LocateCatalogNodeByMangledName.
                    108:          <CS10>         6/24/97        djb             Add hard link support.
                    109:           <CS9>         6/20/97        msd             Use contentModDate and attributeModDate fields instead of
                    110:                                                                        modifyDate. Made CopyCatalogNodeData public.
                    111:           <CS8>         6/18/97        djb             Add routines LocateCatalogNodeWithRetry & UpdateVolumeEncodings.
                    112:                                                                        Add mangled name retry to DeleteCatalogNode, MoveCatalogNode and
                    113:                                                                        RenameCatalogNode.
                    114:           <CS7>         6/13/97        djb             Major changes for longname support and multiple scripts.
                    115:           <CS6>          6/9/97        msd             Instead of calling GetDateTime, call GetTimeUTC or GetTimeLocal.
                    116:                                                                        Dates on an HFS Plus volume need to be converted to/from UTC.
                    117:           <CS5>          6/4/97        djb             Set textEncoding hint in Rename and Create. TrashCatalogIterator
                    118:                                                                        was not always called with the correct folder ID.
                    119:           <CS4>         5/21/97        djb             Turn off recursive iterators.
                    120:           <CS3>         5/19/97        djb             Add support for B-tree iterators to GetCatalogOffspring.
                    121:           <CS2>          5/9/97        djb             Get in sync with FilesInternal.i.
                    122:           <CS1>         4/24/97        djb             First checked into Common System Project.
                    123:         <HFS26>         4/11/97        DSH             Use extended VCB fields catalogRefNum, and extentsRefNum.
                    124:         <HFS25>          4/4/97        djb             Get in sync with volume format changes.
                    125:         <HFS24>         3/31/97        djb             Additional HFS Plus optimization added to GetCatalogNode.
                    126:         <HFS23>         3/28/97        djb             Add Optimization to GetCatalogNode.
                    127:         <HFS22>         3/27/97        djb             Unicode conversion routines now use byte counts.
                    128:         <HFS21>         3/17/97        DSH             Casting to compile with SC, GetRecordSize ->
                    129:                                                                        GetCatalogRecordSize, moved some prototypes to extern.
                    130:         <HFS20>          3/5/97        msd             Add calls to Property Manager when catalog entries are created,
                    131:                                                                        deleted, moved, renamed.
                    132:         <HFS19>         2/19/97        djb             HFS Plus catalog keys no longer have a pad word.
                    133:         <HFS18>         1/24/97        DSH             (djb) GetCatalogOffSpring() fix volume->vcbDirIDM = 0
                    134:         <HFS17>         1/23/97        DSH             Truncate name to CMMaxCName characters in PrepareInputName().
                    135:         <HFS16>         1/14/97        djb             Fixed RenameCatalogNode for case when just a cnid is passed.
                    136:         <HFS15>         1/13/97        djb             Added support for varaible sized thread records in HFS+.
                    137:         <HFS14>         1/11/97        DSH             Moving PrepareInputName() declaration fo FilesInternal.h
                    138:         <HFS13>         1/10/97        djb             CopyCatalogNodeData was trashing the resource extents on HFS+.
                    139:         <HFS12>         1/10/97        djb             CopyCatalogNodeData was trashing dataLogicalSize on HFS+ disks.
                    140:         <HFS11>          1/9/97        djb             Get in sync with new HFSVolumesPriv.i.
                    141:         <HFS10>          1/6/97        djb             Added name length checking to CompareExtendedCatalogKeys. Fixed
                    142:                                                                        GetCatalogOffspring - it was not correctly passing the HFS+ flag
                    143:                                                                        to PrepareOutputName. Fixed BuildKey for HFS+ keys.
                    144:          <HFS9>          1/3/97        djb             Fixed termination bug in GetCatalogOffspring. Added support for
                    145:                                                                        large keys. Integrated latest HFSVolumesPriv.h changes.
                    146:          <HFS8>        12/19/96        DSH             Changed call from C_FlushMDB to HFS+ savy
                    147:                                                                        FlushVolumeControlBlock()
                    148:          <HFS7>        12/19/96        djb             Add new B-tree manager...
                    149:          <HFS6>        12/13/96        djb             Fixing bugs for HFS+. Switch to HFSUnicodeWrappers routines.
                    150:          <HFS5>        12/12/96        djb             Changed the SPI for GetCatalogNode, GetCatalogOffspring, and
                    151:                                                                        UpdateCatalogNode.
                    152:          <HFS4>        12/12/96        DSH             Removed static function declarations for functions used by
                    153:                                                                        FileIDServices.c.
                    154:          <HFS3>        11/11/96        djb             Added support for HFS+ Unicode names. Major changes throughout.
                    155:          <HFS2>         11/4/96        djb             Added FSSpec output to GetCatalogNode and GetCatalogOffspring
                    156:                                                                        routines.
                    157:          <HFS1>        10/29/96        djb             first checked in
                    158: 
                    159: */
                    160: 
                    161: #pragma segment Catalog
                    162: 
                    163: #if ( PRAGMA_LOAD_SUPPORTED )
                    164:         #pragma        load    PrecompiledHeaders
                    165: #else
                    166:         #if TARGET_OS_MAC
                    167:                        #include        <Errors.h>
                    168:                        #include        <Files.h>
                    169:                        #include        <FSM.h>
                    170:                        #include        <Memory.h>
                    171:                        #include        <TextUtils.h>
                    172:                        #include        <Types.h>
                    173:                        #include        <LowMemPriv.h>
                    174:         #else
                    175:                        #include "../headers/system/MacOSTypes.h"
                    176:                        #include "../headers/system/MacOSStubs.h"
                    177:         #endif         /* TARGET_OS_MAC */
                    178: #endif /* PRAGMA_LOAD_SUPPORTED */
                    179: 
                    180: #include       "../headers/FileMgrInternal.h"
                    181: #include       "../headers/BTreesInternal.h"
                    182: #include       "../headers/HFSVolumes.h"
                    183: #include       "../headers/system/HFSUnicodeWrappers.h"
                    184: #include       "../headers/system/HFSInstrumentation.h"
                    185: #include       "../headers/CatalogPrivate.h"
                    186: 
                    187: 
                    188: // External routines
                    189: 
                    190: extern SInt32 FastRelString( ConstStr255Param str1, ConstStr255Param str2 );
                    191: 
                    192: extern SInt16 RelString_Glue(StringPtr pStr1, StringPtr pStr2);
                    193: 
                    194: 
                    195: // Internal routines
                    196: 
                    197: static OSErr   IterateCatalogNode( ExtendedVCB *volume, CatalogIterator *catalogIterator, UInt16 index,
                    198:                                                                        FSSpec *nodeSpec, CatalogNodeData *nodeData, UInt32 *hint );
                    199: 
                    200: void InitCatalogThreadRecord(ExtendedVCB *volume, UInt32 nodeType, CatalogKey *nodeKey,
                    201:                                                         CatalogRecord *record, UInt32 *threadSize);
                    202: 
                    203: void InitCatalogRecord(ExtendedVCB *volume, UInt32 nodeType, UInt32 textEncoding,
                    204:                                         CatalogRecord *record, UInt32 *recordSize, HFSCatalogNodeID *catalogNodeID);
                    205: 
                    206: #if TARGET_OS_RHAPSODY && DIAGNOSTIC
                    207:                #include <sys/systm.h>
                    208:            #define PRINTIT(A) kprintf A;
                    209: #else
                    210:            #define PRINTIT(A)
                    211: #endif
                    212: 
                    213: //_________________________________________________________________________________
                    214: //     Exported Routines
                    215: //
                    216: //             CreateCatalogNode               -  Creates a new folder or file CNode.
                    217: //             DeleteCatalogNode               -  Deletes an existing folder or file CNode.
                    218: //             GetCatalogNode                  -  Locates an existing folder or file CNode.
                    219: //             GetCatalogOffspringFile -  Gets an offspring file record from a folder.
                    220: //             GetCatalogOffspring             -  Gets an offspring record from a folder.
                    221: //             MoveRenameCatalogNode   -  Moves/Renames an existing folder or file CNode.
                    222: //             UpdateCatalogNode               -  Marks a Catalog BTree node as 'dirty'.
                    223: //             CreateFileIDRef                 -  Creates a file thread record for hfs file node
                    224: //             CompareCatalogKeys              -  Compares two catalog keys.
                    225: //
                    226: //_________________________________________________________________________________
                    227: 
                    228: 
                    229: //_________________________________________________________________________________
                    230: //
                    231: //     About date/time values:
                    232: //
                    233: //     Date/time values stored in control blocks and generic structures (such as
                    234: //     CatalogNodeData) are always stored in local time.  Values stored in HFS volume
                    235: //     format structures (such as B-tree records) are also stored in local time.
                    236: //     Values stored in HFS Plus format structures are stored in UTC.
                    237: //_________________________________________________________________________________
                    238: 
                    239: 
                    240: // Implementation
                    241: 
                    242: 
                    243: //_________________________________________________________________________________
                    244: //     Routine:        CreateCatalogNode
                    245: //
                    246: //     Function:       Creates a new folder or file CNode.     A new folder or file
                    247: //                             record is added to the catalog BTree.  If a folder CNode is
                    248: //                             being created, a new thread record is also added.
                    249: //
                    250: //_________________________________________________________________________________
                    251: 
                    252: OSErr
                    253: CreateCatalogNode ( ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name,
                    254:                                        UInt32 nodeType, HFSCatalogNodeID *catalogNodeID, UInt32 *catalogHint)
                    255: {
                    256:        CatalogKey              nodeKey;                        // 518 bytes
                    257:        CatalogRecord   nodeData;                       // 520 bytes
                    258:        UInt32                  nodeDataSize;
                    259:        CatalogRecord   parentThreadData;       // 520 bytes
                    260:        HFSCatalogNodeID parentsParentID;
                    261:        CatalogName             *parentNamePtr;
                    262:        UInt32                  tempHint;
                    263:        UInt32                  textEncoding;
                    264:        UInt16                  tempSize;
                    265:        OSErr                   result;
                    266:        Boolean                 isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord);
                    267: 
                    268:        if (nodeType != kCatalogFolderNode && nodeType != kCatalogFileNode)
                    269:                return paramErr;
                    270: 
                    271:        //--- make sure parent exists (by locating the parent's thread record)
                    272:                        
                    273:        result = LocateCatalogThread(volume, parentID, &parentThreadData, &tempSize, &tempHint);
                    274:        ReturnIfError(result);
                    275: 
                    276:        TrashCatalogIterator(volume, parentID);         // invalidate any iterators for this parentID
                    277: 
                    278:        // save copy of parent's parentID and name.
                    279: 
                    280:        if (isHFSPlus)
                    281:        {
                    282:                if (parentThreadData.recordType != kHFSPlusFolderThreadRecord)
                    283:                        return dirNFErr;
                    284:                
                    285:                parentsParentID = parentThreadData.hfsPlusThread.parentID;
                    286:                parentNamePtr = (CatalogName*) &parentThreadData.hfsPlusThread.nodeName;
                    287:        }
                    288:        else
                    289:        {
                    290:                if (parentThreadData.recordType != kHFSFolderThreadRecord)
                    291:                        return dirNFErr;
                    292:                
                    293:                parentsParentID = parentThreadData.hfsThread.parentID;
                    294:                parentNamePtr = (CatalogName*) &parentThreadData.hfsThread.nodeName;
                    295:        }
                    296:        
                    297:        // invalidate cache for parent since its about to change
                    298:        InvalidateCatalogNodeCache(volume, parentsParentID);    
                    299: 
                    300:        //--- build key for new catalog node
                    301:        result = BuildCatalogKeyUTF8(parentID, name, isHFSPlus, &nodeKey, &textEncoding);
                    302:        ReturnIfError(result);
                    303: 
                    304:        //--- initialize catalog data record (for folder or file)
                    305:        InitCatalogRecord(volume, nodeType, textEncoding, &nodeData, &nodeDataSize, catalogNodeID);
                    306: 
                    307:        //--- add new folder/file record to catalog BTree
                    308:        result = InsertBTreeRecord(volume->catalogRefNum, &nodeKey, &nodeData, nodeDataSize, catalogHint);
                    309:        if (result)
                    310:        {
                    311:                if (result == btExists)
                    312:                        result = cmExists;
                    313:                return result;
                    314:        }
                    315: 
                    316:        //--- build thread record for new CNode
                    317:        if (isHFSPlus || nodeType == kCatalogFolderNode)
                    318:        {
                    319:                HFSCatalogKey   threadKey;      // use the smaller key since name is null
                    320:                CatalogRecord   threadData;     // 520 bytes
                    321:                UInt32                  threadSize;
                    322:                
                    323:                BuildCatalogKey(*catalogNodeID, NULL, isHFSPlus, (CatalogKey*) &threadKey);
                    324: 
                    325:                InitCatalogThreadRecord(volume, nodeType, &nodeKey, &threadData, &threadSize);
                    326: 
                    327:                //--- add thread record to catalog BTree
                    328:        
                    329:                result = InsertBTreeRecord(volume->catalogRefNum, &threadKey, &threadData, threadSize, &tempHint);
                    330: 
                    331:                //--- couldn't add thread record, delete newly created folder record and exit
                    332:                if (result)
                    333:                {
                    334:                        (void) DeleteBTreeRecord(volume->catalogRefNum, &nodeKey);
                    335: 
                    336:                        if ( result == btExists )               // <CS17>
                    337:                                result = cmExists;                      // remap to a catalog error
                    338: 
                    339:                        return result;
                    340:                }
                    341:        }
                    342: 
                    343:        //--- update counters...
                    344: 
                    345:        result = UpdateFolderCount( volume, parentsParentID, parentNamePtr, nodeData.recordType, kNoHint, +1);
                    346:        ReturnIfError(result);  /* XXX what about cleanup ??? */
                    347:        
                    348:        AdjustVolumeCounts(volume, nodeData.recordType, +1);
                    349: 
                    350:        result = FlushCatalog(volume);
                    351: 
                    352:        return result;
                    353: 
                    354: } // end CreateCatalogNode
                    355: 
                    356: 
                    357: /*
                    358:  * initialize catalog data record (for folder or file)
                    359:  */
                    360: void InitCatalogRecord(ExtendedVCB *volume, UInt32 nodeType, UInt32 textEncoding, CatalogRecord *record, UInt32 *recordSize, HFSCatalogNodeID *catalogNodeID)
                    361: {
                    362:        HFSCatalogNodeID nodeID;
                    363:        UInt32 timeStamp;
                    364: 
                    365:        ClearMemory(record, sizeof(CatalogRecord));     // first clear the record
                    366: 
                    367:        VCB_LOCK(volume);
                    368:        nodeID = volume->vcbNxtCNID++;          // get CNID and bump next available CNode ID
                    369:        VCB_UNLOCK(volume);
                    370:        *catalogNodeID = nodeID;                        // make sure it gets passed back
                    371:        
                    372:        if (volume->vcbSigWord == kHFSPlusSigWord)
                    373:        {
                    374:                timeStamp = GetTimeUTC();               // get current date/time (universal)
                    375: 
                    376:                UpdateVolumeEncodings(volume, textEncoding);
                    377: 
                    378:                if (nodeType == kCatalogFolderNode )
                    379:                {
                    380:                        record->recordType = kHFSPlusFolderRecord;
                    381:                        record->hfsPlusFolder.folderID = nodeID;
                    382:                        record->hfsPlusFolder.createDate = timeStamp;
                    383:                        record->hfsPlusFolder.contentModDate = timeStamp;
                    384:             record->hfsPlusFolder.accessDate = timeStamp;
                    385:             record->hfsPlusFolder.attributeModDate     = timeStamp;
                    386:                        record->hfsPlusFolder.textEncoding = textEncoding;
                    387:                        *recordSize = sizeof(HFSPlusCatalogFolder);
                    388:                //      threadType = kHFSPlusFolderThreadRecord;
                    389:                }
                    390:                else if (nodeType == kCatalogFileNode )
                    391:                {
                    392:                        record->recordType = kHFSPlusFileRecord;
                    393:                        record->hfsPlusFile.fileID = nodeID;
                    394:                        record->hfsPlusFile.createDate = timeStamp;
                    395:             record->hfsPlusFile.contentModDate = timeStamp;
                    396:             record->hfsPlusFile.accessDate = timeStamp;
                    397:             record->hfsPlusFile.attributeModDate = timeStamp;
                    398:                        record->hfsPlusFile.flags |= kHFSThreadExistsMask;
                    399:                        record->hfsPlusFile.textEncoding = textEncoding;
                    400:                        *recordSize = sizeof(HFSPlusCatalogFile);
                    401:                //      threadType = kHFSPlusFileThreadRecord;
                    402:                }
                    403:        }
                    404:        else /* standard hfs */
                    405:        {
                    406:                timeStamp = GetTimeLocal(true);         // get current local date/time
                    407: 
                    408:                if (nodeType == kCatalogFolderNode )
                    409:                {
                    410:                        record->recordType = kHFSFolderRecord;
                    411:                        record->hfsFolder.folderID = nodeID;
                    412:                        record->hfsFolder.createDate = timeStamp;
                    413:                        record->hfsFolder.modifyDate = timeStamp;
                    414:                        *recordSize = sizeof(HFSCatalogFolder);
                    415:                //      threadType = kHFSFolderThreadRecord;
                    416:                }
                    417:                else if (nodeType == kCatalogFileNode )
                    418:                {
                    419:                        record->recordType = kHFSFileRecord;
                    420:                        record->hfsFile.fileID = nodeID;
                    421:                        record->hfsFile.createDate = timeStamp;
                    422:                        record->hfsFile.modifyDate = timeStamp;
                    423:                        *recordSize = sizeof(HFSCatalogFile);
                    424:                }
                    425:        }
                    426: }
                    427: 
                    428: 
                    429: void InitCatalogThreadRecord(ExtendedVCB *volume, UInt32 nodeType, CatalogKey *nodeKey,
                    430:                                                         CatalogRecord *record, UInt32 *threadSize)
                    431: {      
                    432:        ClearMemory(record, sizeof(CatalogRecord) );    // first clear the record
                    433: 
                    434:        if (volume->vcbSigWord == kHFSPlusSigWord)
                    435:        {
                    436:                if (nodeType == kCatalogFolderNode)
                    437:                        record->recordType = kHFSPlusFolderThreadRecord;
                    438:                else
                    439:                        record->recordType = kHFSPlusFileThreadRecord;
                    440:                record->hfsPlusThread.parentID = nodeKey->hfsPlus.parentID;                     
                    441:                *threadSize = sizeof(record->hfsPlusThread);
                    442: 
                    443:                // HFS Plus has varaible sized threads so adjust to actual length
                    444:                *threadSize -= ( sizeof(record->hfsPlusThread.nodeName.unicode) -
                    445:                                                (nodeKey->hfsPlus.nodeName.length * sizeof(UniChar)) );
                    446:                BlockMoveData(&nodeKey->hfsPlus.nodeName, &record->hfsPlusThread.nodeName,
                    447:                                          sizeof(UniChar) * (nodeKey->hfsPlus.nodeName.length + 1));
                    448:     }
                    449:     else // classic HFS
                    450:     {
                    451:                if (nodeType == kCatalogFolderNode)
                    452:                        record->recordType = kHFSFolderThreadRecord;
                    453:                else
                    454:                        record->recordType = kHFSFileThreadRecord;
                    455:                record->hfsThread.parentID = nodeKey->hfs.parentID;     
                    456:                *threadSize = sizeof(record->hfsThread);
                    457:                BlockMoveData(&nodeKey->hfs.nodeName, &record->hfsThread.nodeName,
                    458:                                          nodeKey->hfs.nodeName[0] + 1);
                    459:     }
                    460: }
                    461: 
                    462: 
                    463: //_________________________________________________________________________________
                    464: //     Routine:        DeleteCatalogNode
                    465: //
                    466: //     Function:       Deletes an existing folder or file CNode. The thread record
                    467: //                             is also deleted for directories and files that have thread
                    468: //                             records.
                    469: //
                    470: //                             The valence for a folder must be zero before it can be deleted.
                    471: //                             The rootfolder cannot be deleted.
                    472: //
                    473: //_________________________________________________________________________________
                    474: 
                    475: OSErr
                    476: DeleteCatalogNode(ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name, UInt32 hint)
                    477: {
                    478:        CatalogKey                      key;            // 518 bytes
                    479:        CatalogRecord           data;           // 520 bytes
                    480:        UInt32                          nodeHint;
                    481:        HFSCatalogNodeID        nodeID;
                    482:        HFSCatalogNodeID        nodeParentID;
                    483:        UInt32                          textEncoding;
                    484:        UInt16                          nodeType;
                    485:        OSErr                           result;
                    486:        Boolean                         isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord);
                    487:        
                    488:        //--- locate subject catalog node
                    489: 
                    490:        result = BuildCatalogKeyUTF8(parentID, name, isHFSPlus, &key, &textEncoding);
                    491:        ReturnIfError(result);
                    492: 
                    493:        result = LocateCatalogNodeByKey(volume, hint, &key, &data, &nodeHint);
                    494: 
                    495:        // if we did not find it by name, then look for an embedded file ID in a mangled name
                    496:        if ( (result == cmNotFound) && isHFSPlus )
                    497:                result = LocateCatalogNodeByMangledName(volume, parentID, name, &key, &data, &nodeHint);
                    498:        ReturnIfError(result);
                    499: 
                    500:        nodeParentID = isHFSPlus ? key.hfsPlus.parentID : key.hfs.parentID;     // establish real parent cnid
                    501:        nodeType = data.recordType;             // establish cnode type
                    502:        nodeID = 0;
                    503: 
                    504:        switch (nodeType)
                    505:        {
                    506:                case kHFSFolderRecord:
                    507:                        if (data.hfsFolder.valence != 0)                // is it empty?
                    508:                                return cmNotEmpty;
                    509:                        
                    510:                        nodeID = data.hfsFolder.folderID;
                    511:                        break;
                    512: 
                    513:                case kHFSPlusFolderRecord:
                    514:                        if (data.hfsPlusFolder.valence != 0)            // is it empty?
                    515:                                return cmNotEmpty;
                    516:                        
                    517:                        nodeID = data.hfsPlusFolder.folderID;
                    518:                        break;
                    519: 
                    520:                case kHFSFileRecord:
                    521:                        if (data.hfsFile.flags & kHFSThreadExistsMask)
                    522:                                nodeID = data.hfsFile.fileID;
                    523:                        break;
                    524: 
                    525:                case kHFSPlusFileRecord:
                    526:                        nodeID = data.hfsPlusFile.fileID;       // note: HFS Plus files always have a thread
                    527:                        break;
                    528: 
                    529:                default:
                    530:                        return cmNotFound;
                    531:        }
                    532: 
                    533: 
                    534:        if (nodeID == fsRtDirID)        // is this the root folder?
                    535:                return cmRootCN;                // sorry, you can't delete the root!
                    536: 
                    537:        TrashCatalogIterator(volume, nodeParentID);                     // invalidate any iterators for this parentID
                    538:        InvalidateCatalogNodeCache(volume, nodeParentID);       // and invalidate node cache
                    539: 
                    540:        //--- delete catalog records for CNode and file threads if they exist
                    541: 
                    542:        result = DeleteBTreeRecord(volume->catalogRefNum, &key);
                    543:        ReturnIfError(result);
                    544: 
                    545:        if ( nodeID ) 
                    546:        {
                    547:                CatalogKey threadKey;   // 518 bytes
                    548:                
                    549:                BuildCatalogKey(nodeID, NULL, isHFSPlus, &threadKey);
                    550:                
                    551:                (void) DeleteBTreeRecord(volume->catalogRefNum, &threadKey);    // ignore errors for thread deletes
                    552:        }
                    553: 
                    554:        //--- update counters...
                    555: 
                    556:        result = UpdateFolderCount(volume, nodeParentID, NULL, nodeType, kNoHint, -1);
                    557:        ReturnIfError(result);
                    558: 
                    559:        AdjustVolumeCounts(volume, nodeType, -1);       // all done with this file or folder
                    560: 
                    561:        result = FlushCatalog(volume);
                    562: 
                    563:        return result;
                    564: 
                    565: } // end DeleteCatalogNode
                    566: 
                    567: 
                    568: //_________________________________________________________________________________
                    569: //     Routine:        GetCatalogNode
                    570: //
                    571: //     Function:       Locates an existing folder or file CNode and returns an FSSpec for
                    572: //                             the CNode and a pointer to the CNode data record.
                    573: //
                    574: //_________________________________________________________________________________
                    575: 
                    576: OSErr
                    577: GetCatalogNode( ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name, UInt32 hint,
                    578:                                FSSpec *nodeSpec, CatalogNodeData *nodeData, UInt32 *newHint)
                    579: {
                    580:        CatalogKey              *key;
                    581:        CatalogRecord   *record;
                    582:        OSErr                   result = noErr;
                    583:        Boolean                 isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord);
                    584:        UInt32                  textEncoding;
                    585:        CatalogRecord   catalogRecord;  // 520 bytes
                    586:        CatalogKey              catalogKey;             // 518 bytes
                    587:        ByteCount               actualDstLen;
                    588: 
                    589:        record = &catalogRecord;
                    590:        key        = &catalogKey;
                    591: 
                    592:        //--- Locate folder/file BTree record for the CNode
                    593:        result = BuildCatalogKeyUTF8(parentID, name, isHFSPlus, key, &textEncoding);
                    594:        ReturnIfError(result);
                    595:        result = LocateCatalogNodeByKey(volume, hint, key, record, newHint);
                    596:  
                    597:    // if we did not find it by name, then look for an embedded file ID in a mangled name
                    598:     if ( result == cmNotFound && isHFSPlus)
                    599:         result = LocateCatalogNodeByMangledName(volume, parentID, name, key, record, newHint);
                    600:        ReturnIfError(result);
                    601: 
                    602:        //--- Fill out the FSSpec (output)
                    603:        
                    604:        nodeSpec->vRefNum = volume->vcbVRefNum;
                    605:        nodeSpec->parID = isHFSPlus ? key->hfsPlus.parentID : key->hfs.parentID;
                    606:        
                    607:        if ( isHFSPlus )
                    608:        {
                    609:        //      if ( UnicodeBinaryCompare(&key->hfsPlus.nodeName, &nodeName.ustr) )
                    610:        //      {
                    611:     //         // HFS Plus Optimization: since nodeName == key->ckrCName just copy the original name!
                    612:     //         // Omit _expensive_ conversion back to ascii
                    613:        //
                    614:     //         BlockMoveData(name, nodeSpec->name, name[0] + 1);
                    615:        //      }
                    616:        //      else
                    617:                {
                    618:                        result = ConvertUnicodeToUTF8(key->hfsPlus.nodeName.length * sizeof(UniChar),
                    619:                                                                                  key->hfsPlus.nodeName.unicode,
                    620:                                                                                  NAME_MAX + 1, /* 255 + termination byte */
                    621:                                                                                  &actualDstLen,
                    622:                                                                                  nodeSpec->name);
                    623:                }
                    624:        }
                    625:        else // classic HFS
                    626:        {
                    627:                result = ConvertMacRomanToUTF8(key->hfs.nodeName, NAME_MAX + 1, &actualDstLen, nodeSpec->name);
                    628:        }
                    629: 
                    630:        //--- Fill out universal data record...
                    631:        CopyCatalogNodeData(volume, record, nodeData);
                    632: 
                    633:   #if DEBUG_BUILD
                    634:        if ( nodeData->nodeType != '????' )
                    635:                if ( nodeData->nodeID > volume->vcbNxtCNID || nodeData->nodeID == 0)
                    636:                        DebugStr("\pGetCatalogOffspring: bad file ID found!");
                    637:   #endif
                    638:  
                    639:        return result;
                    640: 
                    641: } // end GetCatalogNode
                    642: 
                    643: 
                    644: 
                    645: //_________________________________________________________________________________
                    646: //     Routine:        GetCatalogOffspringFile
                    647: //
                    648: //     Function:       Gets an offspring file from a specified folder. The folder
                    649: //                             is identified by it's folderID.  The desired offspring file is
                    650: //                             indicated by the value of the file index (1 = 1st file offspring,
                    651: //                             2 = 2nd file offspring, etc.).
                    652: //
                    653: //_________________________________________________________________________________
                    654: 
                    655: OSErr
                    656: GetCatalogOffspringFile( ExtendedVCB *volume, HFSCatalogNodeID folderID, UInt16 fileIndex,
                    657:                                         FSSpec *nodeSpec, CatalogNodeData *nodeData, UInt32 *hint )
                    658: {
                    659:        CatalogIterator *       catalogIterator;
                    660:        UInt16                          index;
                    661:        UInt16                          fileCounter;
                    662:        OSErr                           result = noErr;
                    663: 
                    664: 
                    665:        if ( folderID == 0 )
                    666:                return cmNotFound;
                    667: 
                    668:        // get the best catalog iterator...
                    669:        catalogIterator = GetCatalogIterator(volume, folderID, fileIndex, kIterateFilesOnly);
                    670: 
                    671:        index = catalogIterator->currentIndex;                  // Get last search's folder offset
                    672: 
                    673:        // make sure we're not looking for a file beyond this one...
                    674:        if ( index == 0 || catalogIterator->fileIndex > fileIndex )
                    675:        {
                    676:                index = 1;                                      // Start with the first item in the folder
                    677:                fileCounter = fileIndex;        // Need to look at all files up to and including fileIndex
                    678:        }
                    679:        else
                    680:        {
                    681:                fileCounter = fileIndex - catalogIterator->fileIndex + 1;
                    682:                
                    683:                if (fileCounter == 2)           // if difference is one then no need to read previous file
                    684:                {
                    685:                        ++index;                                // go to next entry
                    686:                        fileCounter = 1;                // were looking for 1 file (the next one we find)
                    687:                }
                    688:        }
                    689: 
                    690:        while ( fileCounter > 0 ) 
                    691:        {
                    692:                result = IterateCatalogNode(volume, catalogIterator, index++, nodeSpec, nodeData, hint);
                    693: 
                    694:                if (result != noErr)
                    695:                        break;
                    696: 
                    697:                if ( nodeData->nodeType == kCatalogFileNode )
                    698:                        --fileCounter;                  // one down
                    699:        }
                    700: 
                    701:        if ( result == noErr )
                    702:                catalogIterator->fileIndex = fileIndex;         // update current file index for next time
                    703: 
                    704:        (void) ReleaseCatalogIterator(catalogIterator);
                    705: 
                    706:        return result;
                    707: 
                    708: } // end GetCatalogOffspringFile
                    709: 
                    710: 
                    711: //_________________________________________________________________________________
                    712: //     Routine:        GetCatalogOffspring
                    713: //
                    714: //     Function:       Gets an offspring record from a specified folder. The folder
                    715: //                             is identified by it's folderID.  The desired offspring CNode is
                    716: //                             indicated by the value of the offspring index (1 = 1st offspring
                    717: //                             CNode, 2 = 2nd offspring CNode, etc.).
                    718: //
                    719: //_________________________________________________________________________________
                    720: 
                    721: OSErr
                    722: GetCatalogOffspring( ExtendedVCB *volume, HFSCatalogNodeID folderID, UInt16 index,
                    723:                                         FSSpec *nodeSpec, CatalogNodeData *nodeData, UInt32 *hint )
                    724: {
                    725:        CatalogIterator *       catalogIterator;
                    726:        OSErr                           result;
                    727: 
                    728: 
                    729:        if ( folderID == 0 )
                    730:                return cmNotFound;
                    731: 
                    732:        // get best catalog iterator...
                    733:        catalogIterator = GetCatalogIterator(volume, folderID, index, kIterateAll);
                    734:        
                    735:        result = IterateCatalogNode(volume, catalogIterator, index, nodeSpec, nodeData, hint);
                    736: 
                    737:        (void) ReleaseCatalogIterator(catalogIterator);
                    738: 
                    739:        return result;
                    740: 
                    741: } // end GetCatalogOffspring
                    742: 
                    743: 
                    744: //_________________________________________________________________________________
                    745: //     Routine:        IterateCatalogNode
                    746: //
                    747: //     Function:       Gets an offspring record from a specified folder. The folder
                    748: //                             is identified by it's folderID.  The desired offspring CNode is
                    749: //                             indicated by the value of the offspring index (1 = 1st offspring
                    750: //                             CNode, 2 = 2nd offspring CNode, etc.).
                    751: //
                    752: //_________________________________________________________________________________
                    753: 
                    754: static OSErr
                    755: IterateCatalogNode( ExtendedVCB *volume, CatalogIterator *catalogIterator, UInt16 index,
                    756:                                         FSSpec *nodeSpec, CatalogNodeData *nodeData, UInt32 *hint )
                    757: {
                    758:        HFSCatalogNodeID        offspringParentID;
                    759:        CatalogKey *            offspringKey;
                    760:        CatalogRecord *         offspringData;
                    761:        CatalogName *           offspringName;
                    762:        BTreeIterator           btreeIterator;
                    763:        FSBufferDescriptor      btRecord;
                    764:        FCB *                           fcb;
                    765:        SInt16                          selectionIndex;
                    766:        UInt16                          tempSize;
                    767:        UInt16                          operation;
                    768:        OSErr                           result;
                    769:        Boolean                         isHFSPlus;
                    770:        CatalogRecord           catalogRecord;  // 520 bytes
                    771:        ByteCount                       actualDstLen;
                    772: 
                    773:        offspringData = &catalogRecord;
                    774: 
                    775:        isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord);
                    776:        fcb = GetFileControlBlock(volume->catalogRefNum);
                    777: 
                    778:        // make a btree iterator from catalog iterator
                    779:        UpdateBtreeIterator(catalogIterator, &btreeIterator);
                    780: 
                    781:        btRecord.bufferAddress  = offspringData;
                    782:        btRecord.itemCount              = 1;
                    783:        btRecord.itemSize               = sizeof(CatalogRecord);
                    784: 
                    785:        //--- if neccessary position the iterator at the thread record for the specified folder
                    786: 
                    787:        if ( catalogIterator->currentIndex == 0 )       // is this a new iterator?
                    788:        {
                    789:                UInt32  heuristicHint;
                    790:                UInt32  *cachedHint;
                    791: 
                    792:                //      We pass a 2nd hint/guess into BTSearchRecord.  The heuristicHint is a mapping of
                    793:                //      dirID and nodeNumber, in hopes that the current search will be in the same node
                    794:                //      as the last search with the same parentID.
                    795:                result = GetMRUCacheBlock( catalogIterator->folderID, volume->hintCachePtr, (Ptr *)&cachedHint );
                    796:                heuristicHint = (result == noErr) ? *cachedHint : kInvalidMRUCacheKey;
                    797: 
                    798:                result = BTSearchRecord( fcb, &btreeIterator, heuristicHint, &btRecord, &tempSize, &btreeIterator );
                    799:                ExitOnError(result);
                    800:                
                    801:                UpdateCatalogIterator(&btreeIterator, catalogIterator); // update btree hint and key
                    802: 
                    803:                InsertMRUCacheBlock( volume->hintCachePtr, catalogIterator->folderID, (Ptr) &btreeIterator.hint.nodeNum );
                    804:        }
                    805: 
                    806:        //--- get offspring record (relative to catalogIterator's position)
                    807: 
                    808:        selectionIndex = index - catalogIterator->currentIndex;
                    809: 
                    810:        // now we have to map index into next/prev operations...
                    811:        if (selectionIndex == 1)
                    812:        {
                    813:                operation = kBTreeNextRecord;
                    814:        }
                    815:        else if (selectionIndex == -1)
                    816:        {
                    817:                operation = kBTreePrevRecord;
                    818:        }
                    819:        else if (selectionIndex == 0)
                    820:        {
                    821:                operation = kBTreeCurrentRecord;
                    822:        }
                    823:        else if (selectionIndex > 1)
                    824:        {
                    825:                UInt32  i;
                    826:                
                    827:                for (i = 1; i < selectionIndex; ++i)
                    828:                {
                    829:                        result = BTIterateRecord( fcb, kBTreeNextRecord, &btreeIterator, &btRecord, &tempSize );
                    830:                        ExitOnError(result);
                    831:                }
                    832:                operation = kBTreeNextRecord;
                    833:        }
                    834:        else // (selectionIndex < -1)
                    835:        {
                    836:                SInt32  i;
                    837: 
                    838:                for (i = -1; i > selectionIndex; --i)
                    839:                {
                    840:                        result = BTIterateRecord( fcb, kBTreePrevRecord, &btreeIterator, &btRecord, &tempSize );
                    841:                        ExitOnError(result);
                    842:                }
                    843:                operation = kBTreePrevRecord;
                    844:        }
                    845: 
                    846:        result = BTIterateRecord( fcb, operation, &btreeIterator, &btRecord, &tempSize );
                    847:        ExitOnError(result);
                    848: 
                    849:        offspringKey = (CatalogKey*) &btreeIterator.key;
                    850: 
                    851:        if (isHFSPlus)
                    852:        {
                    853:                offspringParentID = offspringKey->hfsPlus.parentID;
                    854:                offspringName = (CatalogName*) &offspringKey->hfsPlus.nodeName;
                    855:        }
                    856:        else
                    857:        {
                    858:                offspringParentID = offspringKey->hfs.parentID;
                    859:                offspringName = (CatalogName*) offspringKey->hfs.nodeName;
                    860:        }
                    861: 
                    862:        if (offspringParentID != catalogIterator->folderID)             // different parent?
                    863:        {
                    864:                AgeCatalogIterator(catalogIterator);    // we reached the end, so don't hog the cache!
                    865: 
                    866:                result = cmNotFound;                            // must be done with this folder
                    867:                goto ErrorExit;
                    868:        }
                    869: 
                    870:        UpdateCatalogIterator(&btreeIterator, catalogIterator);         // update btree hint and key
                    871:        catalogIterator->currentIndex = index;                                          // update the offspring index marker
                    872: 
                    873:        *hint = btreeIterator.hint.nodeNum;             // return an old-style hint
                    874: 
                    875:        //--- Fill out the FSSpec...
                    876: 
                    877:        nodeSpec->vRefNum = volume->vcbVRefNum;
                    878:        nodeSpec->parID = offspringParentID;
                    879: 
                    880:        if (isHFSPlus)
                    881:        {
                    882:                result = ConvertUnicodeToUTF8(offspringName->ustr.length * sizeof(UniChar),
                    883:                                                                          offspringName->ustr.unicode,
                    884:                                                                          NAME_MAX + 1, /* 255 + termination byte */
                    885:                                                                          &actualDstLen,
                    886:                                                                          nodeSpec->name);
                    887:        }
                    888:        else /* hfs name */
                    889:        {
                    890:                result = ConvertMacRomanToUTF8(offspringName->pstr, NAME_MAX + 1, &actualDstLen, nodeSpec->name);
                    891:        }
                    892: 
                    893:        //--- Fill out universal data record...
                    894:        CopyCatalogNodeData(volume, offspringData, nodeData);
                    895: 
                    896: 
                    897:   #if DEBUG_BUILD
                    898:        if ( nodeData->nodeType != '????' )
                    899:                if ( nodeData->nodeID > volume->vcbNxtCNID || nodeData->nodeID == 0)
                    900:                        DebugStr("\pGetCatalogOffspring: bad file ID found!");
                    901:   #endif
                    902:        
                    903:        return result;
                    904: 
                    905: ErrorExit:
                    906: 
                    907:        if ( result == btNotFound )
                    908:                result = cmNotFound;
                    909: 
                    910:        return result;
                    911: 
                    912: } // end IterateCatalogNode
                    913: 
                    914: 
                    915: //_________________________________________________________________________________
                    916: //     Routine:        MoveRenameCatalogNode
                    917: //
                    918: //     Function:       Moves and/or rename an existing folder or file CNode.
                    919: //                             Note that when moving a folder, all decendants (its offspring,
                    920: //                             their offspring, etc.) are also moved.
                    921: //
                    922: // Assumes srcHint contains a text encoding that was set by a GetCatalogNode call
                    923: //_________________________________________________________________________________
                    924: 
                    925: OSErr
                    926: MoveRenameCatalogNode(ExtendedVCB *volume, HFSCatalogNodeID srcParentID, ConstUTF8Param srcName,
                    927:                                          UInt32 srcHint, HFSCatalogNodeID dstParentID, ConstUTF8Param dstName, UInt32 *newHint)
                    928: {
                    929:        CatalogKey                      srcKey;                 // 518 bytes
                    930:        CatalogRecord           srcRecord;              // 520 bytes
                    931:        CatalogKey                      dstKey;                 // 518 bytes
                    932:        CatalogKey                      dstFolderKey;   // 518 bytes
                    933:        HFSCatalogNodeID        dstFolderParentID = 0;
                    934:        UInt32                          dstFolderHint;
                    935:        CatalogName                *dstFolderNamePtr = NULL;
                    936:        CatalogRecord           tmpRecord;              // 520 bytes
                    937:        HFSCatalogNodeID        threadID;
                    938:        UInt32                          textEncoding;
                    939:        OSErr                           result;
                    940:        Boolean                         isNewName;
                    941:        Boolean                         isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord);
                    942:        Boolean                         isOrigDeleted = false;
                    943:        short srcNameLen;
                    944:        short dstNameLen;
                    945: 
                    946:  
                    947:        result = BuildCatalogKeyUTF8(srcParentID, srcName, isHFSPlus, &srcKey, &textEncoding);
                    948:        ReturnIfError(result);
                    949: 
                    950:        /* XXX can strlen and bcmp handle NULL pointers? */
                    951: 
                    952:        srcNameLen = strlen(srcName);
                    953:        dstNameLen = strlen(dstName);
                    954: 
                    955:        //--- check if names match
                    956: 
                    957:        if ((srcNameLen == dstNameLen) && (bcmp(srcName, dstName, srcNameLen) == 0))
                    958:        {
                    959:                isNewName = false;
                    960:                dstKey = srcKey;
                    961:         if ( isHFSPlus ) {
                    962:             dstKey.hfsPlus.parentID = dstParentID;                     // set parent ID
                    963:         }
                    964:         else {
                    965:             dstKey.hfs.parentID                = dstParentID;                  // set parent ID
                    966:                }
                    967:        }
                    968:        else /* names are different */
                    969:        {
                    970:                isNewName = true;
                    971:                result = BuildCatalogKeyUTF8(dstParentID, dstName, isHFSPlus, &dstKey, &textEncoding);
                    972:                ReturnIfError(result);
                    973:        }
                    974: 
                    975:        //--- make sure source record exists
                    976:        
                    977:        result = LocateCatalogNodeByKey(volume, srcHint, &srcKey, &srcRecord, &srcHint);
                    978: 
                    979:        // if we did not find it by name, then look for an embedded file ID in a mangled name
                    980:        if ( (result == cmNotFound) && isHFSPlus )
                    981:                result = LocateCatalogNodeByMangledName(volume, srcParentID, srcName, &srcKey, &srcRecord, &srcHint);
                    982:        ReturnIfError(result);
                    983: 
                    984:        srcParentID = (isHFSPlus ? srcKey.hfsPlus.parentID : srcKey.hfs.parentID);
                    985: 
                    986:        // if we're moving then do some additional preflighting...
                    987: 
                    988:        if (srcParentID != dstParentID)
                    989:        {
                    990:                //--- make sure destination folder exists
                    991: 
                    992:                result = LocateCatalogNode(volume, dstParentID, NULL, kNoHint, &dstFolderKey, &tmpRecord, &dstFolderHint);
                    993:                ReturnIfError(result);
                    994:                        
                    995:                if (tmpRecord.recordType == kHFSPlusFolderRecord)
                    996:                {
                    997:                        dstParentID = tmpRecord.hfsPlusFolder.folderID;
                    998:                        dstFolderParentID = dstFolderKey.hfsPlus.parentID;
                    999:                        dstFolderNamePtr = (CatalogName*) &dstFolderKey.hfsPlus.nodeName;
                   1000:                }
                   1001:                else if (tmpRecord.recordType == kHFSFolderRecord)
                   1002:                {
                   1003:                        dstParentID = tmpRecord.hfsFolder.folderID;
                   1004:                        dstFolderParentID = dstFolderKey.hfs.parentID;
                   1005:                        dstFolderNamePtr = (CatalogName*) &dstFolderKey.hfs.nodeName;
                   1006:                }
                   1007:                else
                   1008:                {
                   1009:                        return badMovErr;
                   1010:                }
                   1011:        
                   1012:                //--- if source is a folder, make sure its a proper move
                   1013:        
                   1014:                if (srcRecord.recordType == kHFSPlusFolderRecord || srcRecord.recordType == kHFSFolderRecord)
                   1015:                {
                   1016:                        HFSCatalogNodeID srcFolderID;
                   1017:                        HFSCatalogNodeID ancestorParentID;
                   1018:                        CatalogKey              tempKey;        // 518 bytes
                   1019:                        UInt32                  tempHint;
                   1020:        
                   1021:                        if (isHFSPlus)
                   1022:                        {
                   1023:                                srcFolderID = srcRecord.hfsPlusFolder.folderID;
                   1024:                                ancestorParentID = dstFolderKey.hfsPlus.parentID;
                   1025:                        }
                   1026:                        else
                   1027:                        {
                   1028:                                srcFolderID = srcRecord.hfsFolder.folderID;
                   1029:                                ancestorParentID = dstFolderKey.hfs.parentID;
                   1030:                        }
                   1031:        
                   1032:                        if ( srcFolderID == fsRtDirID   ||              // source == root?
                   1033:                                 srcFolderID == dstParentID     ||              // source == destination?
                   1034:                                 srcFolderID == ancestorParentID )      // source == destination's parent?
                   1035:                        {
                   1036:                                return badMovErr;
                   1037:                        }
                   1038:        
                   1039:                        while (ancestorParentID > fsRtDirID)    // loop until we reach the root folder
                   1040:                        {
                   1041:                                // locate next folder up the tree...    
                   1042:                                result = LocateCatalogNode(volume, ancestorParentID, NULL, kNoHint, &tempKey, &tmpRecord, &tempHint);
                   1043:                                ReturnIfError(result);
                   1044:                                
                   1045:                                ancestorParentID = isHFSPlus ? tempKey.hfsPlus.parentID : tempKey.hfs.parentID;
                   1046:        
                   1047:                                if (srcFolderID == ancestorParentID)    // source = destination ancestor?
                   1048:                                        return badMovErr;
                   1049:                        }
                   1050:                }
                   1051: 
                   1052:                TrashCatalogIterator(volume, dstParentID);              // invalidate any iterators for destination parentID
                   1053:        }
                   1054:        else /* (srcParentID == dstParentID) */
                   1055:        {
                   1056:                if ( !isNewName )
                   1057:                {
                   1058:                        *newHint = srcHint;             // they match, so we're all done!
                   1059:                        return noErr;
                   1060:                }
                   1061:        }
                   1062: 
                   1063:        TrashCatalogIterator(volume, srcParentID);                      // invalidate any iterators for source's parentID
                   1064:        InvalidateCatalogNodeCache(volume, srcParentID);        // invalidate node cache since parent changed
                   1065: 
                   1066:        if (isNewName && isHFSPlus)
                   1067:        {
                   1068:                // update textEncoding hint (works for folders and files)
                   1069:                srcRecord.hfsPlusFolder.textEncoding = textEncoding;
                   1070: 
                   1071:                UpdateVolumeEncodings(volume, textEncoding);
                   1072:        }
                   1073: 
                   1074:        //--- insert source CNode record in BTree with new key (a new parent id and/or new name)
                   1075: 
                   1076:        result = InsertBTreeRecord(volume->catalogRefNum, &dstKey, &srcRecord, GetCatalogRecordSize(&srcRecord), newHint);
                   1077: 
                   1078:        if (result == btExists)
                   1079:        {
                   1080:                UInt16 dataSize;
                   1081: 
                   1082:                /* XXX what about the case: move id1,foo to id2,FOO ?? */
                   1083:                if (srcParentID != dstParentID || isNewName == false)
                   1084:                        return cmExists;
                   1085: 
                   1086:                //--- new CNode name already exists in the same folder, locate the existing one
                   1087:                result = SearchBTreeRecord(volume->catalogRefNum, &dstKey, srcHint,
                   1088:                                                                        &dstFolderKey, &tmpRecord, &dataSize, newHint);
                   1089: 
                   1090:                if (result == btNotFound)
                   1091:                        result = cmNotFound;    
                   1092:                ReturnIfError(result);
                   1093: 
                   1094:                //--- check if its the same CNode (same name but different upper/lower case)
                   1095:                        
                   1096:                if (srcRecord.recordType != tmpRecord.recordType)
                   1097:                        return cmExists;
                   1098: 
                   1099:                switch (srcRecord.recordType)
                   1100:                {
                   1101:                        case kHFSPlusFileRecord:        /* HFS Plus records share same cnid location */
                   1102:                        case kHFSPlusFolderRecord:
                   1103:                                if (srcRecord.hfsPlusFolder.folderID != tmpRecord.hfsPlusFolder.folderID)
                   1104:                                        return cmExists;
                   1105:                                break;
                   1106: 
                   1107:                        case kHFSFolderRecord:
                   1108:                                if (srcRecord.hfsFolder.folderID != tmpRecord.hfsFolder.folderID)
                   1109:                                        return cmExists;
                   1110:                                break;
                   1111: 
                   1112:                        case kHFSFileRecord:
                   1113:                                if (srcRecord.hfsFile.fileID != tmpRecord.hfsFile.fileID)
                   1114:                                        return cmExists;
                   1115:                                break;
                   1116:                        
                   1117:                        default:
                   1118:                                return cmExists;
                   1119:                }
                   1120: 
                   1121:                //--- same name but different case, so delete old and insert with new name...
                   1122:        
                   1123:                result = DeleteBTreeRecord(volume->catalogRefNum, &srcKey);
                   1124:                ReturnIfError(result);
                   1125:         isOrigDeleted = true;  // So we dont delete it again down below
                   1126: 
                   1127:                result = InsertBTreeRecord(volume->catalogRefNum, &dstKey, &srcRecord, dataSize, newHint);
                   1128:        }
                   1129:        ReturnIfError(result);
                   1130: 
                   1131:        //
                   1132:        // from this point on we need to cleanup (ie delete the new record) if we encounter errors!     
                   1133:        //
                   1134: 
                   1135:        //--- update thread record for node (if it exists)
                   1136:        
                   1137:        switch (srcRecord.recordType)
                   1138:        {
                   1139:                case kHFSPlusFileRecord:
                   1140:                case kHFSPlusFolderRecord:
                   1141:                        threadID = srcRecord.hfsPlusFolder.folderID;
                   1142:                        break;
                   1143: 
                   1144:                case kHFSFolderRecord:
                   1145:                        threadID = srcRecord.hfsFolder.folderID;
                   1146:                        break;
                   1147: 
                   1148:                case kHFSFileRecord:
                   1149:                        if (srcRecord.hfsFile.flags & kHFSThreadExistsMask)
                   1150:                        {
                   1151:                                threadID = srcRecord.hfsFile.fileID;
                   1152:                                break;
                   1153:                        }
                   1154:                        /* fall through if no thread... */
                   1155: 
                   1156:                default:
                   1157:                        threadID = 0;
                   1158:        }
                   1159: 
                   1160:        if (threadID)
                   1161:        {
                   1162:                UInt32                  threadHint;
                   1163:                CatalogKey              threadKey;              // 518 bytes
                   1164:                CatalogRecord   threadRecord;   // 520 bytes
                   1165:                UInt16                  threadSize;
                   1166: 
                   1167:                result = LocateCatalogRecord(volume, threadID, NULL, kNoHint, &threadKey, &threadRecord, &threadHint);
                   1168:                if (result != noErr) goto Exit_Delete;
                   1169:                
                   1170:                if (isHFSPlus)
                   1171:                {
                   1172:                        if (srcParentID != dstParentID)
                   1173:                                threadRecord.hfsPlusThread.parentID = dstParentID;
                   1174:                        if (isNewName)
                   1175:                                CopyCatalogName((CatalogName *)&dstKey.hfsPlus.nodeName, (CatalogName *) &threadRecord.hfsPlusThread.nodeName, isHFSPlus);
                   1176: 
                   1177:                        threadSize = sizeof(threadRecord.hfsPlusThread);
                   1178:                        // HFS Plus has varaible sized threads so adjust to actual length
                   1179:                        threadSize -= ( sizeof(threadRecord.hfsPlusThread.nodeName.unicode) - (threadRecord.hfsPlusThread.nodeName.length * sizeof(UniChar)) );
                   1180:                }
                   1181:                else
                   1182:                {
                   1183:                        if (srcParentID != dstParentID)
                   1184:                                threadRecord.hfsThread.parentID = dstParentID;
                   1185:                        if (isNewName)
                   1186:                                CopyCatalogName((CatalogName *)&dstKey.hfs.nodeName,(CatalogName *) threadRecord.hfsThread.nodeName, isHFSPlus);
                   1187: 
                   1188:                        threadSize = sizeof(threadRecord.hfsThread);
                   1189:                }
                   1190: 
                   1191:                result = DeleteBTreeRecord(volume->catalogRefNum, &threadKey);
                   1192:                if (result != noErr) goto Exit_Delete;
                   1193: 
                   1194:                result = InsertBTreeRecord(volume->catalogRefNum, &threadKey, &threadRecord, threadSize, &threadHint);
                   1195:                if (result != noErr) goto Exit_Delete;  //XXX exiting with a missing thread!
                   1196:        }
                   1197: 
                   1198:        //--- we successfully added the new node so delete the old source CNode record
                   1199: 
                   1200:     if (! isOrigDeleted) {
                   1201:         result = DeleteBTreeRecord(volume->catalogRefNum, &srcKey);
                   1202:         if (result)
                   1203:             {
                   1204:             // uh oh, we could not delete the original
                   1205:             // so we better get rid of the new node...
                   1206: 
                   1207:             (void) DeleteBTreeRecord(volume->catalogRefNum, &dstKey);
                   1208: 
                   1209:             //XXX also need to fix up the thread...
                   1210: 
                   1211:             return result;
                   1212:             }
                   1213:     }
                   1214: 
                   1215:        if (srcParentID != dstParentID)
                   1216:        {
                   1217:                result = UpdateFolderCount(volume, srcParentID, NULL, srcRecord.recordType, kNoHint, -1);
                   1218:                result = UpdateFolderCount(volume, dstFolderParentID, dstFolderNamePtr, srcRecord.recordType, dstFolderHint, +1);
                   1219:        }
                   1220: 
                   1221:        //--- make sure changes get flushed out
                   1222:        VCB_LOCK(volume);
                   1223:         volume->vcbFlags |= 0xFF00;            // Mark the VCB dirty
                   1224:         volume->vcbLsMod = GetTimeLocal(!isHFSPlus);   // update last modified date
                   1225:        VCB_UNLOCK(volume);
                   1226: 
                   1227:        (void) FlushCatalog(volume);
                   1228:        
                   1229:        return result;
                   1230: 
                   1231: 
                   1232: Exit_Delete:
                   1233:        (void) DeleteBTreeRecord(volume->catalogRefNum, &dstKey);
                   1234: 
                   1235:        return result;
                   1236: 
                   1237: } // end MoveRenameCatalogNode
                   1238: 
                   1239: 
                   1240: //_________________________________________________________________________________
                   1241: //     Routine:        UpdateCatalogNode
                   1242: //
                   1243: //     Function:       Marks the Catalog BTree node identified by the given catalog hint
                   1244: //                             as 'dirty'.
                   1245: //
                   1246: //_________________________________________________________________________________
                   1247: 
                   1248: 
                   1249: OSErr
                   1250: UpdateCatalogNode(ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name,
                   1251:                                  UInt32 catalogHint, const CatalogNodeData *nodeData)
                   1252: {
                   1253:        CatalogKey              *key;
                   1254:        CatalogRecord   *record;
                   1255:        UInt32                  hint;
                   1256:        UInt16                  recordSize;
                   1257:        OSErr                   result;         
                   1258:        TextEncoding    textEncoding;
                   1259:        CatalogKey              catalogKey;             // 518 bytes
                   1260:        CatalogRecord   catalogRecord;  // 520 bytes
                   1261:        Boolean                 isHFSPlus = volume->vcbSigWord == kHFSPlusSigWord;
                   1262: 
                   1263:        /* XXX no reason to have ptrs to local variables... */
                   1264:        key        = &catalogKey;
                   1265:        record = &catalogRecord;
                   1266:        
                   1267:        result = BuildCatalogKeyUTF8(parentID, name, isHFSPlus, key, &textEncoding);
                   1268:        ReturnIfError(result);
                   1269: 
                   1270:        //--- locate subject catalog node
                   1271: 
                   1272:        result = LocateCatalogNodeByKey(volume, catalogHint, key, record, &hint);
                   1273: 
                   1274:        // if we did not find it by name, then look for an embedded file ID in a mangled name
                   1275:        if ( (result == cmNotFound) && isHFSPlus )
                   1276:                result = LocateCatalogNodeByMangledName(volume, parentID, name, key, record, &hint);
                   1277: 
                   1278:        if (result == btNotFound)
                   1279:                result = cmNotFound;
                   1280: 
                   1281:        if (catalogHint != hint)
                   1282:                PRINTIT(("UpdateCatalogNode: catalogHint does not match (in: %ld, out: %ld)\n", catalogHint, hint));
                   1283:        ReturnIfError(result);
                   1284: 
                   1285:        // update user modifiable fields in the catalog node record...
                   1286: 
                   1287:        switch (record->recordType)
                   1288:        {
                   1289:                case kHFSFolderRecord:
                   1290:                {
                   1291:                  #if DEBUG_BUILD
                   1292:                        if (nodeData->nodeType != kCatalogFolderNode)
                   1293:                                DebugStr("\p UpdateCatalogNode: folder/file mismatch!");
                   1294:                  #endif
                   1295: 
                   1296:                        record->hfsFolder.createDate = nodeData->createDate;
                   1297:                        record->hfsFolder.modifyDate = nodeData->contentModDate;
                   1298:                        record->hfsFolder.backupDate = nodeData->backupDate;
                   1299: 
                   1300:                        *(DInfo*) &record->hfsFolder.userInfo = *(DInfo*) &nodeData->finderInfo;
                   1301:                        *(DXInfo*) &record->hfsFolder.finderInfo = *(DXInfo*) &nodeData->extFinderInfo;
                   1302: 
                   1303:                        recordSize = sizeof(HFSCatalogFolder);
                   1304:                        break;
                   1305:                }
                   1306: 
                   1307:                case kHFSFileRecord:
                   1308:                {
                   1309:                        UInt32  i;
                   1310:                        
                   1311:                  #if DEBUG_BUILD
                   1312:                        if (nodeData->nodeType != kCatalogFileNode)
                   1313:                                DebugStr("\p UpdateCatalogNode: folder/file mismatch!");
                   1314:                  #endif
                   1315: 
                   1316:                        record->hfsFile.flags = (UInt8) nodeData->nodeFlags;
                   1317:                        record->hfsFile.createDate = nodeData->createDate;
                   1318:                        record->hfsFile.modifyDate = nodeData->contentModDate;
                   1319:                        record->hfsFile.backupDate = nodeData->backupDate;
                   1320: 
                   1321:                        record->hfsFile.dataLogicalSize  = nodeData->dataLogicalSize;
                   1322:                        record->hfsFile.dataPhysicalSize = nodeData->dataPhysicalSize;
                   1323:                        record->hfsFile.rsrcLogicalSize  = nodeData->rsrcLogicalSize;
                   1324:                        record->hfsFile.rsrcPhysicalSize = nodeData->rsrcPhysicalSize;
                   1325: 
                   1326:                        *(FInfo*) &record->hfsFile.userInfo = *(FInfo*) &nodeData->finderInfo;
                   1327:                        *(FXInfo*) &record->hfsFile.finderInfo = *(FXInfo*) &nodeData->extFinderInfo;
                   1328: 
                   1329:                        // copy extent info
                   1330:                        for (i = 0; i < kHFSExtentDensity; ++i)
                   1331:                        {
                   1332:                                record->hfsFile.dataExtents[i].startBlock       = (UInt16) nodeData->dataExtents[i].startBlock;
                   1333:                                record->hfsFile.dataExtents[i].blockCount       = (UInt16) nodeData->dataExtents[i].blockCount;
                   1334: 
                   1335:                                record->hfsFile.rsrcExtents[i].startBlock       = (UInt16) nodeData->rsrcExtents[i].startBlock;
                   1336:                                record->hfsFile.rsrcExtents[i].blockCount       = (UInt16) nodeData->rsrcExtents[i].blockCount;
                   1337:                        }
                   1338: 
                   1339:                        recordSize = sizeof(HFSCatalogFile);
                   1340:                        break;
                   1341:                }
                   1342: 
                   1343:                case kHFSPlusFolderRecord:
                   1344:                {
                   1345:                        record->hfsPlusFolder.createDate                = LocalToUTC(nodeData->createDate);
                   1346:                        record->hfsPlusFolder.contentModDate    = LocalToUTC(nodeData->contentModDate);
                   1347:                        record->hfsPlusFolder.backupDate                = LocalToUTC(nodeData->backupDate);
                   1348: #if TARGET_OS_RHAPSODY
                   1349:             record->hfsPlusFolder.accessDate           = LocalToUTC(nodeData->accessDate);
                   1350:             record->hfsPlusFolder.attributeModDate     = LocalToUTC(nodeData->attributeModDate);
                   1351:             record->hfsPlusFolder.permissions          = nodeData->permissions;
                   1352: #endif
                   1353: 
                   1354:                        BlockMoveData(&nodeData->finderInfo, &record->hfsPlusFolder.userInfo, 32);      // copy all of finder data
                   1355: 
                   1356:                        recordSize = sizeof(HFSPlusCatalogFolder);
                   1357:                        break;
                   1358:                }
                   1359: 
                   1360:                case kHFSPlusFileRecord:
                   1361:                {
                   1362:                        record->hfsPlusFile.flags                        = nodeData->nodeFlags;
                   1363:                        record->hfsPlusFile.createDate   = LocalToUTC(nodeData->createDate);
                   1364:                        record->hfsPlusFile.contentModDate = LocalToUTC(nodeData->contentModDate);
                   1365:                        record->hfsPlusFile.backupDate   = LocalToUTC(nodeData->backupDate);
                   1366: #if TARGET_OS_RHAPSODY
                   1367:             record->hfsPlusFile.accessDate      = LocalToUTC(nodeData->accessDate);
                   1368:             record->hfsPlusFile.attributeModDate        = LocalToUTC(nodeData->attributeModDate);
                   1369:             record->hfsPlusFile.permissions     = nodeData->permissions;
                   1370: #endif
                   1371: 
                   1372:                        record->hfsPlusFile.dataFork.logicalSize.lo = nodeData->dataLogicalSize;
                   1373:                        record->hfsPlusFile.dataFork.totalBlocks = nodeData->dataPhysicalSize / volume->blockSize;
                   1374:                        BlockMoveData(&nodeData->dataExtents, &record->hfsPlusFile.dataFork.extents, sizeof(HFSPlusExtentRecord));
                   1375: 
                   1376:                        record->hfsPlusFile.resourceFork.logicalSize.lo = nodeData->rsrcLogicalSize;
                   1377:                        record->hfsPlusFile.resourceFork.totalBlocks = nodeData->rsrcPhysicalSize / volume->blockSize;
                   1378:                        BlockMoveData(&nodeData->rsrcExtents, &record->hfsPlusFile.resourceFork.extents, sizeof(HFSPlusExtentRecord));
                   1379:                        
                   1380:                        BlockMoveData(&nodeData->finderInfo, &record->hfsPlusFile.userInfo, 32);        // copy all of 32 bytes of Finder data
                   1381: 
                   1382:                        recordSize = sizeof(HFSPlusCatalogFile);
                   1383:                        break;
                   1384:                }
                   1385: 
                   1386:                default:
                   1387:                        return cmNotFound;
                   1388:        }
                   1389: 
                   1390:        result = ReplaceBTreeRecord(volume->catalogRefNum, key, catalogHint, record, recordSize, &hint);
                   1391:        
                   1392:        if ( result == btNotFound )
                   1393:        {
                   1394:                result = cmNotFound;
                   1395:        }
                   1396:        else if ( result == noErr )
                   1397:        {
                   1398:                /* if we're just updating the accessDate then no need to change volume mod date */
                   1399:                if (nodeData->contentModDate > volume->vcbLsMod ||
                   1400:                        (isHFSPlus && nodeData->attributeModDate > volume->vcbLsMod))
                   1401:                {
                   1402:                        VCB_LOCK(volume);
                   1403:                        volume->vcbFlags |= 0xFF00;                     // Mark the VCB dirty
                   1404:                        volume->vcbLsMod = GetTimeLocal(!isHFSPlus);    // update last modified date
                   1405:                        VCB_UNLOCK(volume);
                   1406:                }
                   1407: 
                   1408:                result = FlushCatalog(volume);          // flush the catalog
                   1409:        }
                   1410: 
                   1411:        return result;
                   1412: }
                   1413: 
                   1414: 
                   1415: //_________________________________________________________________________________
                   1416: //     Routine:        CreateFileIDRef
                   1417: //
                   1418: //     Function:       Creates a file thread record for hfs file node
                   1419: //
                   1420: //_________________________________________________________________________________
                   1421: 
                   1422: OSErr
                   1423: CreateFileIDRef(ExtendedVCB *volume, HFSCatalogNodeID parentID, ConstUTF8Param name, UInt32 hint, HFSCatalogNodeID *threadID)
                   1424: {
                   1425:        CatalogKey                      nodeKey;        // 518 bytes
                   1426:        CatalogRecord           nodeData;       // 520 bytes
                   1427:        HFSCatalogKey           threadKey;
                   1428:        HFSCatalogThread        threadData;
                   1429:        UInt32                          nodeHint;
                   1430:        UInt32                          tempHint;
                   1431:        OSErr                           result;
                   1432:        Boolean                         isHFSPlus = (volume->vcbSigWord == kHFSPlusSigWord);
                   1433:        UInt32                          textEncoding;
                   1434:        
                   1435:        *threadID = 0;
                   1436:        
                   1437:        result = BuildCatalogKeyUTF8(parentID, name, isHFSPlus, &nodeKey, &textEncoding);
                   1438:        ReturnIfError(result);
                   1439: 
                   1440:        //--- locate subject catalog node
                   1441: 
                   1442:        result = LocateCatalogNodeByKey(volume, hint, &nodeKey, &nodeData, &nodeHint);
                   1443: 
                   1444:        // if we did not find it by name, then look for an embedded file ID in a mangled name
                   1445:        if ( (result == cmNotFound) && isHFSPlus )
                   1446:                result = LocateCatalogNodeByMangledName(volume, parentID, name, &nodeKey, &nodeData, &nodeHint);
                   1447:        ReturnIfError(result);
                   1448:        
                   1449:     if (nodeData.recordType == kHFSPlusFileRecord)
                   1450:        {
                   1451:                *threadID = nodeData.hfsPlusFile.fileID;
                   1452:                return noErr;   // already have one
                   1453:        }
                   1454:        
                   1455:        if (nodeData.recordType != kHFSFileRecord)
                   1456:        {
                   1457:                return notAFileErr;
                   1458:        }
                   1459: 
                   1460: 
                   1461:        if (nodeData.hfsFile.flags & kHFSThreadExistsMask)
                   1462:        {
                   1463:                *threadID = nodeData.hfsFile.fileID;
                   1464:                return noErr;   // already have one
                   1465:        }
                   1466: 
                   1467:        result = VolumeWritable( volume );
                   1468:        if ( result != noErr ) return result;
                   1469: 
                   1470:        //
                   1471:        // need to insert a thread record
                   1472:        //              
                   1473:     BuildCatalogKey(nodeData.hfsFile.fileID, NULL, false, (CatalogKey *)&threadKey);
                   1474:        
                   1475:        ClearMemory(&threadData, sizeof(HFSCatalogThread));
                   1476:     threadData.recordType = kHFSFileThreadRecord;
                   1477:        threadData.parentID = nodeKey.hfs.parentID;     
                   1478:        BlockMoveData(&nodeKey.hfs.nodeName, &threadData.nodeName, nodeKey.hfs.nodeName[0] + 1);
                   1479: 
                   1480:        result = InsertBTreeRecord(volume->catalogRefNum, &threadKey, &threadData, sizeof(HFSCatalogThread), &tempHint);
                   1481:        if (result == btExists) result = noErr;         //XXX could return cmExists or fidExists
                   1482:        ReturnIfError(result);
                   1483: 
                   1484:        //
                   1485:        //      Finally, set the flag in the file record to say this file has a thread record.
                   1486:        //
                   1487:        nodeData.hfsFile.flags |= kHFSThreadExistsMask;
                   1488:        result = ReplaceBTreeRecord(volume->catalogRefNum, &nodeKey, nodeHint, &nodeData, sizeof(HFSCatalogFile), &nodeHint );
                   1489: 
                   1490:        if (result == noErr) {
                   1491:                (void) FlushCatalog(volume);
                   1492:                *threadID = nodeData.hfsFile.fileID;
                   1493:        }
                   1494: 
                   1495:        return result;
                   1496: }
                   1497: 
                   1498: 
                   1499: //_________________________________________________________________________________
                   1500: //     Routine:        CompareCatalogKeys
                   1501: //
                   1502: //     Function:       Compares two catalog keys (a search key and a trial key).
                   1503: //
                   1504: //     Result:         +n  search key > trial key
                   1505: //                              0  search key = trial key
                   1506: //                             -n  search key < trial key
                   1507: //_________________________________________________________________________________
                   1508: 
                   1509: SInt32
                   1510: CompareCatalogKeys(HFSCatalogKey *searchKey, HFSCatalogKey *trialKey)
                   1511: {
                   1512:        HFSCatalogNodeID        searchParentID, trialParentID;
                   1513:        SInt32  result;
                   1514: 
                   1515:        searchParentID = searchKey->parentID;
                   1516:        trialParentID = trialKey->parentID;
                   1517: 
                   1518:        if ( searchParentID > trialParentID )   // parent dirID is unsigned
                   1519:                result = 1;
                   1520:        else if ( searchParentID < trialParentID )
                   1521:                result = -1;
                   1522:        else // parent dirID's are equal, compare names
                   1523:        {
                   1524:          #if ( ! FORDISKFIRSTAID )
                   1525:                LogStartTime(kTraceRelString);
                   1526: 
                   1527:                result = FastRelString(searchKey->nodeName, trialKey->nodeName);
                   1528: 
                   1529:                LogEndTime(kTraceRelString, noErr);
                   1530:          #else
                   1531:                result = (SInt32) RelString_Glue(searchKey->nodeName, trialKey->nodeName);
                   1532:          #endif
                   1533:        }
                   1534: 
                   1535:        return result;
                   1536: }
                   1537: 
                   1538: 
                   1539: //_________________________________________________________________________________
                   1540: //     Routine:        CompareExtendedCatalogKeys
                   1541: //
                   1542: //     Function:       Compares two large catalog keys (a search key and a trial key).
                   1543: //
                   1544: //     Result:         +n  search key > trial key
                   1545: //                              0  search key = trial key
                   1546: //                             -n  search key < trial key
                   1547: //_________________________________________________________________________________
                   1548: 
                   1549: SInt32
                   1550: CompareExtendedCatalogKeys(HFSPlusCatalogKey *searchKey, HFSPlusCatalogKey *trialKey)
                   1551: {
                   1552:        SInt32                  result;
                   1553:        HFSCatalogNodeID        searchParentID, trialParentID;
                   1554: 
                   1555:        searchParentID = searchKey->parentID;
                   1556:        trialParentID = trialKey->parentID;
                   1557:        
                   1558:        if ( searchParentID > trialParentID )   // parent node IDs are unsigned
                   1559:        {
                   1560:                result = 1;
                   1561:        }
                   1562:        else if ( searchParentID < trialParentID )
                   1563:        {
                   1564:                result = -1;
                   1565:        }
                   1566:        else // parent node ID's are equal, compare names
                   1567:        {
                   1568:                if ( searchKey->nodeName.length == 0 || trialKey->nodeName.length == 0 )
                   1569:                        result = searchKey->nodeName.length - trialKey->nodeName.length;
                   1570:                else
                   1571:                        result = FastUnicodeCompare(&searchKey->nodeName.unicode[0], searchKey->nodeName.length,
                   1572:                                                                                &trialKey->nodeName.unicode[0], trialKey->nodeName.length);
                   1573:        }
                   1574: 
                   1575:        return result;
                   1576: }
                   1577: 

unix.superglobalmegacorp.com

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