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

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

unix.superglobalmegacorp.com

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