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