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