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

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

unix.superglobalmegacorp.com

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