|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: File: CatalogUtilities.c ! 24: ! 25: Contains: Private Catalog Manager support routines. ! 26: ! 27: Version: HFS Plus 1.0 ! 28: ! 29: Copyright: � 1997-2000 by Apple Computer, Inc., all rights reserved. ! 30: ! 31: File Ownership: ! 32: ! 33: DRI: Don Brady ! 34: ! 35: Other Contact: Mark Day ! 36: ! 37: Technology: xxx put technology here xxx ! 38: ! 39: Writers: ! 40: ! 41: (DSH) Deric Horn ! 42: (msd) Mark Day ! 43: (djb) Don Brady ! 44: ! 45: Change History (most recent first): ! 46: <MacOSX> 1/8/99 djb Fixing LocateCatalogNodeByMangledName... ! 47: <MacOSX> 1/7/99 djb In BuildCatalogKeyUTF8 check name length against NAME_MAX. ! 48: <MacOSX> 12/7/98 djb Add ExtractTextEncoding routine to get text encodings. ! 49: <MacOSX> 11/20/98 djb Add support for UTF-8 names. ! 50: <MacOSX> 8/31/98 djb GetTimeLocal now takes an input. ! 51: <MacOSX> 4/17/98 djb Add VCB locking. ! 52: <MacOSX> 4/3/98 djb Removed last name conversion cache from LocateCatalogNodeWithRetry. ! 53: <MacOSX> 4/2/98 djb InvalidateCatalogNodeCache and TrashCatalogNodeCache are not used in MacOS X. ! 54: <MacOSX> 03/31/98 djb Sync up with final HFSVolumes.h header file. ! 55: ! 56: <CS24> 1/29/98 DSH Add TrashCatalogNodeCache for TrashAllFSCaches API support. ! 57: <CS23> 12/15/97 djb Radar #2202860, In LocateCatalogNodeByMangledName remap ! 58: cmParentNotFound error code to cmNotFound. ! 59: <CS22> 12/10/97 DSH 2201501, Pin the leof and peof to multiple of allocation blocks ! 60: under 2 Gig. ! 61: <CS21> 12/9/97 DSH 2201501, Pin returned leof values to 2^31-1 (SInt32), instead of ! 62: 2^32-1 ! 63: <CS20> 11/26/97 djb Radar #2005688, 2005461 - need to handle kTextMalformedInputErr. ! 64: <CS19> 11/25/97 djb Radar #2002357 (again) fix new bug introduced in <CS18>. ! 65: <CS18> 11/17/97 djb PrepareInputName routine now returns an error. ! 66: <CS17> 10/19/97 msd Bug 1684586. GetCatInfo and SetCatInfo use only contentModDate. ! 67: <CS16> 10/17/97 djb Add ConvertInputNameToUnicode for Catalog Create/Rename. ! 68: <CS15> 10/14/97 djb Fix LocateCatalogNode's MakeFSSpec optimization (radar #1683166) ! 69: <CS14> 10/13/97 djb Copy text encoding in CopyCatalogNodeData. Fix cut/paste error ! 70: in VolumeHasEncodings macro. When accessing encoding bitmap use ! 71: the MapEncodingToIndex and MapIndexToEncoding macros. ! 72: <CS13> 10/1/97 djb Remove old Catalog Iterator code... ! 73: <CS12> 9/8/97 msd Make sure a folder's modifyDate is set whenever its ! 74: contentModDate is set. ! 75: <CS11> 9/4/97 djb Add MakeFSSpec optimization. ! 76: <CS10> 9/4/97 msd In CatalogNodeData, change attributeModDate to modifyDate. ! 77: <CS9> 8/26/97 djb Back out <CS4> (UpdateFolderCount must maintain vcbNmFls for HFS ! 78: Plus volumes too). ! 79: <CS8> 8/14/97 djb Remove hard link support. ! 80: <CS7> 7/18/97 msd Include LowMemPriv.h. ! 81: <CS6> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name ! 82: collision ! 83: <CS5> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line ! 84: <CS4> 6/27/97 msd UpdateFolderCount should update number of root files/folders for ! 85: HFS volumes, not HFS Plus. ! 86: <CS3> 6/24/97 djb LocateCatalogNodeWithRetry did not always set result code. ! 87: <CS2> 6/24/97 djb Add LocateCatalogNodeByMangledName routine ! 88: <CS1> 6/24/97 djb first checked in ! 89: */ ! 90: ! 91: #include "../headers/FileMgrInternal.h" ! 92: #include "../headers/BTreesInternal.h" ! 93: #include "../headers/CatalogPrivate.h" ! 94: #include "../headers/HFSUnicodeWrappers.h" ! 95: #include <string.h> ! 96: ! 97: static void ExtractTextEncoding (ItemCount length, ConstUniCharArrayPtr string, UInt32 * textEncoding); ! 98: ! 99: //******************************************************************************* ! 100: // Routine: LocateCatalogNode ! 101: // ! 102: // Function: Locates the catalog record for an existing folder or file ! 103: // CNode and returns pointers to the key and data records. ! 104: // ! 105: //******************************************************************************* ! 106: ! 107: OSErr ! 108: LocateCatalogNode(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name, ! 109: UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *newHint) ! 110: { ! 111: OSErr result; ! 112: CatalogName *nodeName = NULL; /* To ward off uninitialized use warnings from compiler */ ! 113: HFSCatalogNodeID threadParentID; ! 114: ! 115: ! 116: result = LocateCatalogRecord(volume, folderID, name, hint, keyPtr, dataPtr, newHint); ! 117: ReturnIfError(result); ! 118: ! 119: // if we got a thread record, then go look up real record ! 120: switch ( dataPtr->recordType ) ! 121: { ! 122: case kHFSFileThreadRecord: ! 123: case kHFSFolderThreadRecord: ! 124: threadParentID = dataPtr->hfsThread.parentID; ! 125: nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName; ! 126: break; ! 127: ! 128: case kHFSPlusFileThreadRecord: ! 129: case kHFSPlusFolderThreadRecord: ! 130: threadParentID = dataPtr->hfsPlusThread.parentID; ! 131: nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName; ! 132: break; ! 133: ! 134: default: ! 135: threadParentID = 0; ! 136: break; ! 137: } ! 138: ! 139: if ( threadParentID ) // found a thread ! 140: result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint); ! 141: ! 142: return result; ! 143: } ! 144: ! 145: // ! 146: // Routine: LocateCatalogNodeByKey ! 147: // ! 148: // Function: Locates the catalog record for an existing folder or file ! 149: // CNode and returns the key and data records. ! 150: // ! 151: ! 152: OSErr ! 153: LocateCatalogNodeByKey(const ExtendedVCB *volume, UInt32 hint, CatalogKey *keyPtr, ! 154: CatalogRecord *dataPtr, UInt32 *newHint) ! 155: { ! 156: OSErr result; ! 157: CatalogName *nodeName = NULL; /* To ward off uninitialized use warnings from compiler */ ! 158: HFSCatalogNodeID threadParentID; ! 159: UInt16 tempSize; ! 160: ! 161: ! 162: result = SearchBTreeRecord(volume->catalogRefNum, keyPtr, hint, keyPtr, ! 163: dataPtr, &tempSize, newHint); ! 164: if (result == btNotFound) ! 165: result = cmNotFound; ! 166: ReturnIfError(result); ! 167: ! 168: // if we got a thread record, then go look up real record ! 169: switch ( dataPtr->recordType ) ! 170: { ! 171: case kHFSFileThreadRecord: ! 172: case kHFSFolderThreadRecord: ! 173: threadParentID = dataPtr->hfsThread.parentID; ! 174: nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName; ! 175: break; ! 176: ! 177: case kHFSPlusFileThreadRecord: ! 178: case kHFSPlusFolderThreadRecord: ! 179: threadParentID = dataPtr->hfsPlusThread.parentID; ! 180: nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName; ! 181: break; ! 182: ! 183: default: ! 184: threadParentID = 0; ! 185: break; ! 186: } ! 187: ! 188: if ( threadParentID ) // found a thread ! 189: result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint); ! 190: ! 191: return result; ! 192: } ! 193: ! 194: ! 195: #if 0 ! 196: //******************************************************************************* ! 197: // Routine: LocateCatalogNodeWithRetry ! 198: // ! 199: // Function: Locates the catalog record for an existing folder or file node. ! 200: // For HFS Plus volumes a retry is performed when a catalog node is ! 201: // not found and the volume contains more than one text encoding. ! 202: // ! 203: //������������������������������������������������������������������������������� ! 204: ! 205: #define VolumeHasEncodings(v) \ ! 206: ( ((v)->encodingsBitmap != 0 ) ! 207: ! 208: #define EncodingInstalled(i) \ ! 209: ( (fsVars)->gConversionContext[(i)].toUnicode != 0 ) ! 210: ! 211: #define EncodingUsedByVolume(v,i) \ ! 212: ( ((v)->encodingsBitmap & (1 << (i))) ) ! 213: ! 214: ! 215: OSErr ! 216: LocateCatalogNodeWithRetry (const ExtendedVCB *volume, HFSCatalogNodeID folderID, ConstStr31Param pascalName, CatalogName *unicodeName, ! 217: UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *newHint) ! 218: { ! 219: TextEncoding defaultEncoding; ! 220: TextEncoding encoding; ! 221: ItemCount encodingsToTry; ! 222: FSVarsRec *fsVars; ! 223: OSErr result = cmNotFound; ! 224: ! 225: fsVars = (FSVarsRec*) LMGetFSMVars(); // used by macros ! 226: ! 227: defaultEncoding = GetDefaultTextEncoding(); ! 228: encodingsToTry = CountInstalledEncodings(); ! 229: ! 230: // 1. Try finding file using default encoding (typical case) ! 231: ! 232: { ! 233: --encodingsToTry; ! 234: result = PrepareInputName(pascalName, true, defaultEncoding, unicodeName); ! 235: if (result == noErr) ! 236: result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint); ! 237: else ! 238: result = cmNotFound; ! 239: ! 240: if ( result != cmNotFound || encodingsToTry == 0) ! 241: return result; ! 242: } ! 243: ! 244: // ! 245: // XXX if the pascal string contains all 7-bit ascii then we don't need to do anymore retries ! 246: // ! 247: ! 248: // 2. Try finding file using Mac Roman (if not already tried above) ! 249: ! 250: if ( defaultEncoding != kTextEncodingMacRoman ) ! 251: { ! 252: --encodingsToTry; ! 253: result = PrepareInputName(pascalName, true, kTextEncodingMacRoman, unicodeName); ! 254: if (result == noErr) ! 255: result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint); ! 256: else ! 257: result = cmNotFound; ! 258: ! 259: if ( result != cmNotFound || encodingsToTry == 0 ) ! 260: return result; ! 261: } ! 262: ! 263: // 3. Try with encodings from disk (if any) ! 264: ! 265: if ( VolumeHasEncodings(volume) ) // any left to try? ! 266: { ! 267: UInt32 index; ! 268: ! 269: index = 0; // since we pre increment this will skip MacRoman (which was already tried above) ! 270: ! 271: while ( index < kMacBaseEncodingCount ) ! 272: { ! 273: ++index; ! 274: ! 275: encoding = MapIndexToEncoding(index); ! 276: ! 277: if ( encoding == defaultEncoding ) ! 278: continue; // we did this one already ! 279: ! 280: if ( EncodingInstalled(index) && EncodingUsedByVolume(volume, index) ) ! 281: { ! 282: --encodingsToTry; ! 283: result = PrepareInputName(pascalName, true, encoding, unicodeName); ! 284: if (result == noErr) ! 285: result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint); ! 286: else ! 287: result = cmNotFound; ! 288: ! 289: if ( result != cmNotFound || encodingsToTry == 0 ) ! 290: return result; ! 291: } ! 292: } ! 293: } ! 294: ! 295: // 4. Try any remaining encodings (if any) ! 296: ! 297: { ! 298: UInt32 index; ! 299: ! 300: index = 0; // since we pre increment this will skip MacRoman (which was already tried above) ! 301: ! 302: while ( (encodingsToTry > 0) && (index < kMacBaseEncodingCount) ) ! 303: { ! 304: ++index; ! 305: ! 306: encoding = MapIndexToEncoding(index); ! 307: ! 308: if ( encoding == defaultEncoding ) ! 309: continue; // we did this one already ! 310: ! 311: if ( EncodingInstalled(index) && EncodingUsedByVolume(volume, index) == false ) ! 312: { ! 313: --encodingsToTry; ! 314: result = PrepareInputName(pascalName, true, encoding, unicodeName); ! 315: if (result == noErr) ! 316: result = LocateCatalogNode(volume, folderID, unicodeName, hint, keyPtr, dataPtr, newHint); ! 317: else ! 318: result = cmNotFound; ! 319: ! 320: if ( result != cmNotFound || encodingsToTry == 0 ) ! 321: return result; ! 322: } ! 323: } ! 324: } ! 325: ! 326: return cmNotFound; ! 327: } ! 328: #endif ! 329: ! 330: //******************************************************************************* ! 331: // Routine: LocateCatalogNodeByMangledName ! 332: // ! 333: // Function: Locates the catalog record associated with a mangled name (if any) ! 334: // ! 335: //******************************************************************************* ! 336: ! 337: OSErr ! 338: LocateCatalogNodeByMangledName( const ExtendedVCB *volume, HFSCatalogNodeID folderID, ! 339: const unsigned char * name, UInt32 length, CatalogKey *keyPtr, ! 340: CatalogRecord *dataPtr, UInt32 *hintPtr ) ! 341: { ! 342: HFSCatalogNodeID fileID; ! 343: unsigned char nodeName[64]; ! 344: OSErr result; ! 345: ByteCount actualDstLen; ! 346: ByteCount prefixlen; ! 347: ! 348: ! 349: if (name == NULL || name[0] == '\0') ! 350: return cmNotFound; ! 351: ! 352: fileID = GetEmbeddedFileID(name, length, &prefixlen); ! 353: ! 354: if ( fileID < kHFSFirstUserCatalogNodeID ) ! 355: return cmNotFound; ! 356: ! 357: result = LocateCatalogNode(volume, fileID, NULL, kNoHint, keyPtr, dataPtr, hintPtr); ! 358: if ( result == cmParentNotFound ) // GetCatalogNode already handled cmParentNotFound case <CS23> ! 359: result = cmNotFound; // so remap <CS23> ! 360: ReturnIfError(result); ! 361: ! 362: // first make sure that the parents match ! 363: if ( folderID != keyPtr->hfsPlus.parentID ) ! 364: return cmNotFound; // not the same folder so this is a false match ! 365: ! 366: result = ConvertUnicodeToUTF8( keyPtr->hfsPlus.nodeName.length * sizeof (UniChar), ! 367: keyPtr->hfsPlus.nodeName.unicode, ! 368: 64, ! 369: &actualDstLen, ! 370: nodeName); ! 371: ! 372: if ( (actualDstLen < prefixlen) || bcmp(nodeName, name, prefixlen) != 0) ! 373: return cmNotFound; // mangled names didn't match so this is a false match ! 374: ! 375: return noErr; // we found it ! 376: } ! 377: ! 378: ! 379: //******************************************************************************* ! 380: // Routine: LocateCatalogRecord ! 381: // ! 382: // Function: Locates the catalog record associated with folderID and name ! 383: // ! 384: //******************************************************************************* ! 385: ! 386: OSErr ! 387: LocateCatalogRecord(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name, ! 388: UInt32 hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, UInt32 *newHint) ! 389: { ! 390: OSErr result; ! 391: CatalogKey tempKey; // 518 bytes ! 392: UInt16 tempSize; ! 393: ! 394: BuildCatalogKey(folderID, name, (volume->vcbSigWord == kHFSPlusSigWord), &tempKey); ! 395: ! 396: if ( name == NULL ) ! 397: hint = kNoHint; // no CName given so clear the hint ! 398: ! 399: result = SearchBTreeRecord(volume->catalogRefNum, &tempKey, hint, keyPtr, dataPtr, &tempSize, newHint); ! 400: ! 401: return (result == btNotFound ? cmNotFound : result); ! 402: } ! 403: ! 404: ! 405: //******************************************************************************* ! 406: // Routine: LocateCatalogThread ! 407: // ! 408: // Function: Locates a catalog thread record in the catalog BTree file and ! 409: // returns a pointer to the data record. ! 410: // ! 411: //******************************************************************************* ! 412: ! 413: OSErr ! 414: LocateCatalogThread(const ExtendedVCB *volume, HFSCatalogNodeID nodeID, CatalogRecord *threadData, UInt16 *threadSize, UInt32 *threadHint) ! 415: { ! 416: CatalogKey threadKey; // 518 bytes ! 417: OSErr result; ! 418: ! 419: //--- build key record ! 420: ! 421: BuildCatalogKey(nodeID, NULL, (volume->vcbSigWord == kHFSPlusSigWord), &threadKey); ! 422: ! 423: //--- locate thread record in BTree ! 424: ! 425: result = SearchBTreeRecord( volume->catalogRefNum, &threadKey, kNoHint, &threadKey, ! 426: threadData, threadSize, threadHint); ! 427: ! 428: return (result == btNotFound ? cmNotFound : result); ! 429: } ! 430: ! 431: ! 432: /* ! 433: * Routine: BuildCatalogKey ! 434: * ! 435: * Function: Constructs a catalog key record (ckr) given the parent ! 436: * folder ID and CName. Works for both classic and extended ! 437: * HFS volumes. ! 438: * ! 439: */ ! 440: ! 441: void ! 442: BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key) ! 443: { ! 444: if ( isHFSPlus ) ! 445: { ! 446: key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2) ! 447: key->hfsPlus.parentID = parentID; // set parent ID ! 448: key->hfsPlus.nodeName.length = 0; // null CName length ! 449: if ( cName != NULL ) ! 450: { ! 451: CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus); ! 452: key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; // add CName size to key length ! 453: } ! 454: } ! 455: else ! 456: { ! 457: key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1) ! 458: key->hfs.reserved = 0; // clear unused byte ! 459: key->hfs.parentID = parentID; // set parent ID ! 460: key->hfs.nodeName[0] = 0; // null CName length ! 461: if ( cName != NULL ) ! 462: { ! 463: UpdateCatalogName(cName->pstr, key->hfs.nodeName); ! 464: key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length ! 465: } ! 466: } ! 467: } ! 468: ! 469: /* ! 470: * for HFS, only MacRoman is supported. If a non-MacRoman character is found, an error is returned ! 471: */ ! 472: OSErr ! 473: BuildCatalogKeyUTF8(ExtendedVCB *volume, HFSCatalogNodeID parentID, const char *name, UInt32 nameLength, ! 474: CatalogKey *key, UInt32 *textEncoding) ! 475: { ! 476: OSErr err = 0; ! 477: ! 478: if ( name == NULL) ! 479: nameLength = 0; ! 480: else if (nameLength == kUndefinedStrLen) ! 481: nameLength = strlen(name); ! 482: ! 483: if ( volume->vcbSigWord == kHFSPlusSigWord ) { ! 484: ByteCount unicodeBytes = 0; ! 485: ! 486: key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2) ! 487: key->hfsPlus.parentID = parentID; // set parent ID ! 488: key->hfsPlus.nodeName.length = 0; // null CName length ! 489: if ( nameLength > 0 ) { ! 490: err = ConvertUTF8ToUnicode(nameLength, name, sizeof(key->hfsPlus.nodeName.unicode), ! 491: &unicodeBytes, key->hfsPlus.nodeName.unicode); ! 492: key->hfsPlus.nodeName.length = unicodeBytes / sizeof(UniChar); ! 493: key->hfsPlus.keyLength += unicodeBytes; ! 494: } ! 495: ! 496: if (textEncoding) ! 497: ExtractTextEncoding(key->hfsPlus.nodeName.length, key->hfsPlus.nodeName.unicode, textEncoding); ! 498: } ! 499: else { ! 500: key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1) ! 501: key->hfs.reserved = 0; // clear unused byte ! 502: key->hfs.parentID = parentID; // set parent ID ! 503: key->hfs.nodeName[0] = 0; // null CName length ! 504: if ( nameLength > 0 ) { ! 505: err = utf8_to_hfs(volume, nameLength, name, &key->hfs.nodeName[0]); ! 506: key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length ! 507: } ! 508: if (textEncoding) ! 509: *textEncoding = 0; ! 510: } ! 511: ! 512: if (err) { ! 513: if (err == kTECOutputBufferFullStatus) ! 514: err = bdNamErr; /* name is too long */ ! 515: else ! 516: err = paramErr; /* name has invalid characters */ ! 517: } ! 518: ! 519: return err; ! 520: } ! 521: ! 522: ! 523: /* ! 524: * make a guess at the text encoding value that coresponds to the Unicode characters ! 525: */ ! 526: static void ! 527: ExtractTextEncoding(ItemCount length, ConstUniCharArrayPtr string, UInt32 * textEncoding) ! 528: { ! 529: int i; ! 530: UniChar ch; ! 531: ! 532: *textEncoding = 0; ! 533: ! 534: for (i = 0; i < length; ++i) { ! 535: ch = string[i]; ! 536: /* CJK codepoints are 0x3000 thru 0x9FFF */ ! 537: if (ch >= 0x3000) { ! 538: if (ch < 0xa000) { ! 539: *textEncoding = kTextEncodingMacJapanese; ! 540: break; ! 541: } ! 542: ! 543: /* fullwidth character codepoints are 0xFF00 thru 0xFFEF */ ! 544: if (ch >= 0xff00 && ch <= 0xffef) { ! 545: *textEncoding = kTextEncodingMacJapanese; ! 546: break; ! 547: } ! 548: } ! 549: } ! 550: } ! 551: ! 552: ! 553: //******************************************************************************* ! 554: // Routine: FlushCatalog ! 555: // ! 556: // Function: Flushes the catalog for a specified volume. ! 557: // ! 558: //******************************************************************************* ! 559: ! 560: OSErr ! 561: FlushCatalog(ExtendedVCB *volume) ! 562: { ! 563: FCB * fcb; ! 564: OSErr result; ! 565: ! 566: fcb = GetFileControlBlock(volume->catalogRefNum); ! 567: result = BTFlushPath(fcb); ! 568: ! 569: if (result == noErr) ! 570: { ! 571: //--- check if catalog's fcb is dirty... ! 572: ! 573: if ( fcb->fcbFlags & fcbModifiedMask ) ! 574: { ! 575: VCB_LOCK(volume); ! 576: volume->vcbFlags |= 0xFF00; // Mark the VCB dirty ! 577: volume->vcbLsMod = GetTimeUTC(); // update last modified date ! 578: VCB_UNLOCK(volume); ! 579: ! 580: result = FlushVolumeControlBlock(volume); ! 581: } ! 582: } ! 583: ! 584: return result; ! 585: } ! 586: ! 587: ! 588: //������������������������������������������������������������������������������� ! 589: // Routine: UpdateCatalogName ! 590: // ! 591: // Function: Updates a CName. ! 592: // ! 593: //������������������������������������������������������������������������������� ! 594: ! 595: void ! 596: UpdateCatalogName(ConstStr31Param srcName, Str31 destName) ! 597: { ! 598: Size length = srcName[0]; ! 599: ! 600: if (length > CMMaxCName) ! 601: length = CMMaxCName; // truncate to max ! 602: ! 603: destName[0] = length; // set length byte ! 604: ! 605: BlockMoveData(&srcName[1], &destName[1], length); ! 606: } ! 607: ! 608: ! 609: //******************************************************************************* ! 610: // Routine: AdjustVolumeCounts ! 611: // ! 612: // Function: Adjusts the folder and file counts in the VCB ! 613: // ! 614: //******************************************************************************* ! 615: ! 616: void ! 617: AdjustVolumeCounts(ExtendedVCB *volume, SInt16 type, SInt16 delta) ! 618: { ! 619: //�� also update extended VCB fields... ! 620: ! 621: VCB_LOCK(volume); ! 622: ! 623: if (type == kHFSFolderRecord || type == kHFSPlusFolderRecord) ! 624: volume->vcbDirCnt += delta; // adjust volume folder count, �� worry about overflow? ! 625: else ! 626: volume->vcbFilCnt += delta; // adjust volume file count ! 627: ! 628: volume->vcbFlags |= 0xFF00; // Mark the VCB dirty ! 629: volume->vcbLsMod = GetTimeUTC(); // update last modified date ! 630: ! 631: VCB_UNLOCK(volume); ! 632: } ! 633: ! 634: ! 635: //******************************************************************************* ! 636: ! 637: void ! 638: UpdateVolumeEncodings(ExtendedVCB *volume, TextEncoding encoding) ! 639: { ! 640: UInt32 index; ! 641: ! 642: encoding &= 0x7F; ! 643: ! 644: index = MapEncodingToIndex(encoding); ! 645: ! 646: VCB_LOCK(volume); ! 647: ! 648: volume->encodingsBitmap |= (1 << index); ! 649: ! 650: VCB_UNLOCK(volume); ! 651: ! 652: // vcb should already be marked dirty ! 653: } ! 654: ! 655: ! 656: //******************************************************************************* ! 657: ! 658: OSErr ! 659: UpdateFolderCount( ExtendedVCB *volume, HFSCatalogNodeID parentID, const CatalogName *name, SInt16 newType, ! 660: UInt32 hint, SInt16 valenceDelta) ! 661: { ! 662: CatalogKey tempKey; // 518 bytes ! 663: CatalogRecord tempData; // 520 bytes ! 664: UInt32 tempHint; ! 665: HFSCatalogNodeID folderID; ! 666: UInt16 recordSize; ! 667: OSErr result; ! 668: ! 669: #if 0 ! 670: result = SearchBTreeRecord(volume->catalogRefNum, parentKey, hint, ! 671: &tempKey, &tempData, &recordSize, &tempHint); ! 672: if (result) ! 673: return (result == btNotFound ? cmNotFound : result); ! 674: #else ! 675: ! 676: result = LocateCatalogNode(volume, parentID, name, hint, &tempKey, &tempData, &tempHint); ! 677: ReturnIfError(result); ! 678: #endif ! 679: ! 680: if ( volume->vcbSigWord == kHFSPlusSigWord ) // HFS Plus ! 681: { ! 682: UInt32 timeStamp; ! 683: ! 684: if ( DEBUG_BUILD && tempData.recordType != kHFSPlusFolderRecord ) ! 685: DebugStr("\p UpdateFolder: found HFS folder on HFS+ volume!"); ! 686: ! 687: timeStamp = GetTimeUTC(); ! 688: tempData.hfsPlusFolder.valence += valenceDelta; // adjust valence ! 689: tempData.hfsPlusFolder.contentModDate = timeStamp; // set date/time last modified ! 690: folderID = tempData.hfsPlusFolder.folderID; ! 691: recordSize = sizeof(tempData.hfsPlusFolder); ! 692: } ! 693: else // classic HFS ! 694: { ! 695: if ( DEBUG_BUILD && tempData.recordType != kHFSFolderRecord ) ! 696: DebugStr("\p UpdateFolder: found HFS+ folder on HFS volume!"); ! 697: ! 698: tempData.hfsFolder.valence += valenceDelta; // adjust valence ! 699: tempData.hfsFolder.modifyDate = GetTimeLocal(true); // set date/time last modified ! 700: folderID = tempData.hfsFolder.folderID; ! 701: recordSize = sizeof(tempData.hfsFolder); ! 702: } ! 703: ! 704: result = ReplaceBTreeRecord(volume->catalogRefNum, &tempKey, tempHint, ! 705: &tempData, recordSize, &tempHint); ! 706: ReturnIfError(result); ! 707: ! 708: if ( folderID == kHFSRootFolderID ) ! 709: { ! 710: if (newType == kHFSFolderRecord || newType == kHFSPlusFolderRecord) ! 711: { ! 712: VCB_LOCK(volume); ! 713: volume->vcbNmRtDirs += valenceDelta; // adjust root folder count (undefined for HFS Plus) ! 714: VCB_UNLOCK(volume); ! 715: } ! 716: else ! 717: { ! 718: VCB_LOCK(volume); ! 719: volume->vcbNmFls += valenceDelta; // adjust root file count (used by GetVolInfo) ! 720: VCB_UNLOCK(volume); ! 721: } ! 722: } ! 723: ! 724: //XXX also update extended VCB fields... ! 725: ! 726: return result; ! 727: } ! 728: ! 729: ! 730: //******************************************************************************* ! 731: ! 732: UInt16 ! 733: GetCatalogRecordSize(const CatalogRecord *dataRecord) ! 734: { ! 735: switch (dataRecord->recordType) ! 736: { ! 737: case kHFSFileRecord: ! 738: return sizeof(HFSCatalogFile); ! 739: ! 740: case kHFSFolderRecord: ! 741: return sizeof(HFSCatalogFolder); ! 742: ! 743: case kHFSPlusFileRecord: ! 744: return sizeof(HFSPlusCatalogFile); ! 745: ! 746: case kHFSPlusFolderRecord: ! 747: return sizeof(HFSPlusCatalogFolder); ! 748: ! 749: case kHFSFolderThreadRecord: ! 750: case kHFSFileThreadRecord: ! 751: return sizeof(HFSCatalogThread); ! 752: ! 753: case kHFSPlusFolderThreadRecord: ! 754: case kHFSPlusFileThreadRecord: ! 755: return sizeof(HFSPlusCatalogThread); ! 756: ! 757: default: ! 758: return 0; ! 759: } ! 760: } ! 761: ! 762: ! 763: //******************************************************************************* ! 764: ! 765: void ! 766: CopyCatalogNodeData(const ExtendedVCB *volume, const CatalogRecord *dataPtr, CatalogNodeData *nodeData) ! 767: { ! 768: /* convert classic hfs records to hfs plus format */ ! 769: ! 770: if (dataPtr->recordType == kHFSFolderRecord) { ! 771: nodeData->cnd_type = kCatalogFolderNode; ! 772: nodeData->cnd_flags = dataPtr->hfsFolder.flags; ! 773: nodeData->cnd_nodeID = dataPtr->hfsFolder.folderID; ! 774: nodeData->cnd_createDate = LocalToUTC(dataPtr->hfsFolder.createDate); ! 775: nodeData->cnd_contentModDate = LocalToUTC(dataPtr->hfsFolder.modifyDate); ! 776: nodeData->cnd_backupDate = LocalToUTC(dataPtr->hfsFolder.backupDate); ! 777: nodeData->cnd_valence = dataPtr->hfsFolder.valence; ! 778: ! 779: BlockMoveData(&dataPtr->hfsFolder.userInfo, &nodeData->cnd_finderInfo, 32); ! 780: } else { ! 781: UInt32 i; ! 782: ! 783: nodeData->cnd_type = kCatalogFileNode; ! 784: nodeData->cnd_flags = dataPtr->hfsFile.flags; ! 785: nodeData->cnd_nodeID = dataPtr->hfsFile.fileID; ! 786: nodeData->cnd_createDate = LocalToUTC(dataPtr->hfsFile.createDate); ! 787: nodeData->cnd_contentModDate = LocalToUTC(dataPtr->hfsFile.modifyDate); ! 788: nodeData->cnd_backupDate = LocalToUTC(dataPtr->hfsFile.backupDate); ! 789: nodeData->cnd_linkCount = 0; ! 790: ! 791: BlockMoveData(&dataPtr->hfsFile.userInfo, &nodeData->cnd_finderInfo, 16); ! 792: BlockMoveData(&dataPtr->hfsFile.finderInfo, (void*)((UInt32)&nodeData->cnd_finderInfo + 16), 16); ! 793: ! 794: nodeData->cnd_datafork.logicalSize = dataPtr->hfsFile.dataLogicalSize; ! 795: nodeData->cnd_datafork.totalBlocks = ! 796: dataPtr->hfsFile.dataPhysicalSize / volume->blockSize; ! 797: ! 798: nodeData->cnd_rsrcfork.logicalSize = dataPtr->hfsFile.rsrcLogicalSize; ! 799: nodeData->cnd_rsrcfork.totalBlocks = ! 800: dataPtr->hfsFile.rsrcPhysicalSize / volume->blockSize; ! 801: ! 802: for (i = 0; i < kHFSExtentDensity; ++i) { ! 803: nodeData->cnd_datafork.extents[i].startBlock = ! 804: (UInt32) (dataPtr->hfsFile.dataExtents[i].startBlock); ! 805: ! 806: nodeData->cnd_datafork.extents[i].blockCount = ! 807: (UInt32) (dataPtr->hfsFile.dataExtents[i].blockCount); ! 808: ! 809: nodeData->cnd_rsrcfork.extents[i].startBlock = ! 810: (UInt32) (dataPtr->hfsFile.rsrcExtents[i].startBlock); ! 811: ! 812: nodeData->cnd_rsrcfork.extents[i].blockCount = ! 813: (UInt32) (dataPtr->hfsFile.rsrcExtents[i].blockCount); ! 814: } ! 815: for (i = kHFSExtentDensity; i < kHFSPlusExtentDensity; ++i) { ! 816: nodeData->cnd_datafork.extents[i].startBlock = 0; ! 817: nodeData->cnd_datafork.extents[i].blockCount = 0; ! 818: nodeData->cnd_rsrcfork.extents[i].startBlock = 0; ! 819: nodeData->cnd_rsrcfork.extents[i].blockCount = 0; ! 820: } ! 821: } ! 822: } ! 823: ! 824: ! 825: //_______________________________________________________________________ ! 826: ! 827: void ! 828: CopyCatalogName(const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPLus) ! 829: { ! 830: UInt32 length; ! 831: ! 832: if ( srcName == NULL ) ! 833: { ! 834: if ( dstName != NULL ) ! 835: dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal) ! 836: return; ! 837: } ! 838: ! 839: if (isHFSPLus) ! 840: length = sizeof(UniChar) * (srcName->ustr.length + 1); ! 841: else ! 842: length = sizeof(UInt8) + srcName->pstr[0]; ! 843: ! 844: if ( length > 1 ) ! 845: BlockMoveData(srcName, dstName, length); ! 846: else ! 847: dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal) ! 848: } ! 849: ! 850: //_______________________________________________________________________ ! 851: ! 852: UInt32 ! 853: CatalogNameLength(const CatalogName *name, Boolean isHFSPlus) ! 854: { ! 855: if (isHFSPlus) ! 856: return name->ustr.length; ! 857: else ! 858: return name->pstr[0]; ! 859: } ! 860: ! 861: ! 862:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.