1/* 2 * Copyright (c) 1999-2003, 2005-2008 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 File: SUtils.c 25 26 Contains: xxx put contents here xxx 27 28 Version: xxx put version here xxx 29 30 Copyright: � 1997-1999 by Apple Computer, Inc., all rights reserved. 31*/ 32 33#include "Scavenger.h" 34 35static void CompareVolHeaderBTreeSizes( SGlobPtr GPtr, 36 VolumeObjectPtr theVOPtr, 37 HFSPlusVolumeHeader * thePriVHPtr, 38 HFSPlusVolumeHeader * theAltVHPtr ); 39static void GetEmbeddedVolumeHeaders( SGlobPtr GPtr, 40 HFSMasterDirectoryBlock * myMDBPtr, 41 Boolean isPrimaryMDB ); 42static OSErr GetVolumeObjectBlock( VolumeObjectPtr theVOPtr, 43 UInt64 theBlockNum, 44 BlockDescriptor * theBlockDescPtr ); 45static OSErr VolumeObjectFixPrimaryBlock( void ); 46 47/* 48 * utf_encodestr 49 * 50 * Encode a UCS-2 (Unicode) string to UTF-8 51 */ 52int utf_encodestr(ucsp, ucslen, utf8p, utf8len, utf8plen) 53 const u_int16_t * ucsp; 54 size_t ucslen; 55 unsigned char * utf8p; 56 size_t * utf8len; 57 size_t utf8plen; 58{ 59 unsigned char * bufstart; 60 u_int16_t ucs_ch; 61 size_t charcnt; 62 63 bufstart = utf8p; 64 charcnt = ucslen / 2; 65 66 while (charcnt-- > 0 && utf8plen > 0) { 67 ucs_ch = *ucsp++; 68 69 if (ucs_ch < 0x0080) { 70 if (ucs_ch == '\0') 71 continue; /* skip over embedded NULLs */ 72 73 *utf8p++ = ucs_ch; 74 utf8plen--; 75 } else if (ucs_ch < 0x800) { 76 if (utf8plen < 2) /* We're about to over-flow the buffer */ 77 break; 78 utf8plen -= 2; 79 *utf8p++ = (ucs_ch >> 6) | 0xc0; 80 *utf8p++ = (ucs_ch & 0x3f) | 0x80; 81 } else { 82 if (utf8plen < 3) /* We're about to over-flow the buffer */ 83 break; 84 utf8plen -= 3; 85 *utf8p++ = (ucs_ch >> 12) | 0xe0; 86 *utf8p++ = ((ucs_ch >> 6) & 0x3f) | 0x80; 87 *utf8p++ = ((ucs_ch) & 0x3f) | 0x80; 88 } 89 } 90 91 *utf8len = utf8p - bufstart; 92 93 return (0); 94} 95 96 97/* 98 * utf_decodestr 99 * 100 * Decode a UTF-8 string back to UCS-2 (Unicode) 101 * 102 * N.B.: ucslen on input describes the length of the buffer; 103 * on return, it describes how many bytes were used. 104 */ 105int 106utf_decodestr(utf8p, utf8len, ucsp, ucslen, ucsplen) 107 const unsigned char * utf8p; 108 size_t utf8len; 109 u_int16_t* ucsp; 110 size_t *ucslen; 111 size_t ucsplen; 112{ 113 u_int16_t* bufstart; 114 u_int16_t ucs_ch; 115 u_int8_t byte; 116 117 bufstart = ucsp; 118 119 while (utf8len-- > 0 && (byte = *utf8p++) != '\0' && ucsplen > 0) { 120 /* check for ascii */ 121 if (byte < 0x80) { 122 *ucsp++ = byte; 123 ucsplen--; 124 continue; 125 } 126 127 switch (byte & 0xf0) { 128 /* 2 byte sequence*/ 129 case 0xc0: 130 case 0xd0: 131 /* extract bits 6 - 10 from first byte */ 132 ucs_ch = (byte & 0x1F) << 6; 133 if (ucs_ch < 0x0080) 134 return (-1); /* seq not minimal */ 135 break; 136 /* 3 byte sequence*/ 137 case 0xe0: 138 /* extract bits 12 - 15 from first byte */ 139 ucs_ch = (byte & 0x0F) << 6; 140 141 /* extract bits 6 - 11 from second byte */ 142 if (((byte = *utf8p++) & 0xc0) != 0x80) 143 return (-1); 144 145 utf8len--; 146 ucs_ch += (byte & 0x3F); 147 ucs_ch <<= 6; 148 if (ucs_ch < 0x0800) 149 return (-1); /* seq not minimal */ 150 break; 151 default: 152 return (-1); 153 } 154 155 /* extract bits 0 - 5 from final byte */ 156 if (((byte = *utf8p++) & 0xc0) != 0x80) 157 return (-1); 158 159 utf8len--; 160 ucs_ch += (byte & 0x3F); 161 *ucsp++ = ucs_ch; 162 ucsplen--; 163 } 164 165 *ucslen = (u_int8_t*)ucsp - (u_int8_t*)bufstart; 166 167 return (0); 168} 169 170 171OSErr GetFBlk( SGlobPtr GPtr, SInt16 fileRefNum, SInt32 blockNumber, void **bufferH ); 172 173 174UInt32 gDFAStage; 175 176UInt32 GetDFAStage( void ) 177{ 178 return (gDFAStage); 179} 180 181void SetDFAStage( UInt32 stage ) 182{ 183 gDFAStage = stage; 184} 185 186 187/*------------------------------------------------------------------------------ 188 189Routine: RcdError 190 191Function: Record errors detetected by scavenging operation. 192 193Input: GPtr - pointer to scavenger global area. 194 ErrCode - error code 195 196Output: None 197------------------------------------------------------------------------------*/ 198 199void RcdError( SGlobPtr GPtr, OSErr errorCode ) 200{ 201 GPtr->ErrCode = errorCode; 202 203 WriteError( GPtr, errorCode, GPtr->TarID, GPtr->TarBlock ); // log to summary window 204} 205 206 207/*------------------------------------------------------------------------------ 208 209Routine: IntError 210 211Function: Records an internal Scavenger error. 212 213Input: GPtr - pointer to scavenger global area. 214 ErrCode - internal error code 215 216Output: IntError - function result: 217 (E_IntErr for now) 218------------------------------------------------------------------------------*/ 219 220int IntError( SGlobPtr GPtr, OSErr errorCode ) 221{ 222 GPtr->RepLevel = repairLevelUnrepairable; 223 224 if ( errorCode == ioErr ) // Cast I/O errors as read errors 225 errorCode = R_RdErr; 226 227 if( (errorCode == R_RdErr) || (errorCode == R_WrErr) ) 228 { 229 GPtr->ErrCode = GPtr->volumeErrorCode; 230 GPtr->IntErr = 0; 231 return( errorCode ); 232 } 233 else 234 { 235 GPtr->ErrCode = R_IntErr; 236 GPtr->IntErr = errorCode; 237 return( R_IntErr ); 238 } 239 240} // End of IntError 241 242 243 244/*------------------------------------------------------------------------------ 245 246Routine: AllocBTN (Allocate BTree Node) 247 248Function: Allocates an BTree node in a Scavenger BTree bit map. 249 250Input: GPtr - pointer to scavenger global area. 251 StABN - starting allocation block number. 252 NmABlks - number of allocation blocks. 253 254Output: AllocBTN - function result: 255 0 = no error 256 n = error 257------------------------------------------------------------------------------*/ 258 259int AllocBTN( SGlobPtr GPtr, SInt16 fileRefNum, UInt32 nodeNumber ) 260{ 261 UInt16 bitPos; 262 unsigned char mask; 263 char *byteP; 264 BTreeControlBlock *calculatedBTCB = GetBTreeControlBlock( fileRefNum ); 265 266 // Allocate the node 267 if ( calculatedBTCB->refCon == 0) 268 return( noErr ); 269 270 byteP = ( (BTreeExtensionsRec*)calculatedBTCB->refCon)->BTCBMPtr + (nodeNumber / 8 ); // ptr to starting byte 271 bitPos = nodeNumber % 8; // bit offset 272 mask = ( 0x80 >> bitPos ); 273 if ( (*byteP & mask) != 0 ) 274 { 275 RcdError( GPtr, E_OvlNode ); 276 return( E_OvlNode ); // node already allocated 277 } 278 *byteP = *byteP | mask; // allocate it 279 calculatedBTCB->freeNodes--; // decrement free count 280 281 return( noErr ); 282} 283 284 285OSErr GetBTreeHeader( SGlobPtr GPtr, SFCB *fcb, BTHeaderRec *header ) 286{ 287 OSErr err; 288 BTHeaderRec *headerRec; 289 BlockDescriptor block; 290 291 GPtr->TarBlock = kHeaderNodeNum; 292 293 if (fcb->fcbBlockSize == 0) 294 (void) SetFileBlockSize(fcb, 512); 295 296 err = GetFileBlock(fcb, kHeaderNodeNum, kGetBlock, &block); 297 ReturnIfError(err); 298 299 err = hfs_swap_BTNode(&block, fcb, kSwapBTNodeHeaderRecordOnly); 300 if (err != noErr) 301 { 302 (void) ReleaseFileBlock(fcb, &block, kReleaseBlock | kTrashBlock); 303 return err; 304 } 305 306 headerRec = (BTHeaderRec *)((char*)block.buffer + sizeof(BTNodeDescriptor)); 307 CopyMemory(headerRec, header, sizeof(BTHeaderRec)); 308 309 err = hfs_swap_BTNode(&block, fcb, kSwapBTNodeHeaderRecordOnly); 310 if (err != noErr) 311 { 312 (void) ReleaseFileBlock(fcb, &block, kReleaseBlock | kTrashBlock); 313 return err; 314 } 315 316 err = ReleaseFileBlock (fcb, &block, kReleaseBlock); 317 ReturnIfError(err); 318 319 /* Validate Node Size */ 320 switch (header->nodeSize) { 321 case 512: 322 case 1024: 323 case 2048: 324 case 4096: 325 case 8192: 326 case 16384: 327 case 32768: 328 break; 329 330 default: 331 RcdError( GPtr, E_InvalidNodeSize ); 332 err = E_InvalidNodeSize; 333 } 334 335 return( err ); 336} 337 338 339/*------------------------------------------------------------------------------ 340 341Routine: IsDuplicateRepairOrder 342 343Function: Search a duplicate repair order node in the GPtr->MinorRepairP 344 list. This function traverses the entire list of minor 345 repairs, and compares the following fields to determine a 346 match - type, forkType, correct, incorrect, maskBit, hint, 347 and parentID. 348 349Input: GPtr - scavenger globals 350 orig - repair order to search and compare 351 352Output: 0 - no duplicate was found, 353 1 - duplicate was found. 354------------------------------------------------------------------------------*/ 355int IsDuplicateRepairOrder(SGlobPtr GPtr, RepairOrderPtr orig) 356{ 357 RepairOrderPtr cur; 358 int retval = 0; 359 360 cur = GPtr->MinorRepairsP; 361 while (cur) { 362 if (cur != orig) { 363 /* If all these values match, this is a duplicate */ 364 if ((orig->type == cur->type) && 365 (orig->correct == cur->correct) && 366 (orig->incorrect == cur->incorrect) && 367 (orig->parid == cur->parid) && 368 (orig->forkType == cur->forkType) && 369 (orig->maskBit == cur->maskBit) && 370 (orig->hint == cur->hint)) { 371 retval = 1; 372 break; 373 } 374 } 375 cur = cur->link; 376 } 377 378 return retval; 379} 380 381/*------------------------------------------------------------------------------ 382 383Routine: DeleteRepairOrder 384 385Function: Deletes the minor repair order that matches the repair order 386 provided from the list. This function should be called when 387 a duplicate repair order is detected. 388 389Input: GPtr - scavenger globals 390 orig - repair order to remove 391 392Output: Nothing 393------------------------------------------------------------------------------*/ 394void DeleteRepairOrder(SGlobPtr GPtr, RepairOrderPtr orig) 395{ 396 RepairOrderPtr cur; 397 RepairOrderPtr prev = NULL; 398 399 cur = GPtr->MinorRepairsP; 400 while (cur) { 401 if (cur == orig) { 402 if (prev) { 403 prev->link = cur->link; 404 } 405 if (cur == GPtr->MinorRepairsP) { 406 GPtr->MinorRepairsP = cur->link; 407 } 408 DisposeMemory(cur); 409 } 410 prev = cur; 411 cur = cur->link; 412 } 413 414 return; 415} 416 417 418/*------------------------------------------------------------------------------ 419 420Routine: Alloc[Minor/Major]RepairOrder 421 422Function: Allocate a repair order node and link into the 'GPtr->RepairXxxxxP" list. 423 These are descriptions of minor/major repairs that need to be performed; 424 they are compiled during verification, and executed during minor/major repair. 425 426Input: GPtr - scavenger globals 427 n - number of extra bytes needed, in addition to standard node size. 428 429Output: Ptr to node, or NULL if out of memory or other error. 430------------------------------------------------------------------------------*/ 431 432RepairOrderPtr AllocMinorRepairOrder( SGlobPtr GPtr, size_t n ) /* #extra bytes needed */ 433{ 434 RepairOrderPtr p; // the node we allocate 435 436 n += sizeof( RepairOrder ); // add in size of basic node 437 438 p = (RepairOrderPtr) AllocateClearMemory( n ); // get the node 439 440 if ( p != NULL ) // if we got one... 441 { 442 p->link = GPtr->MinorRepairsP; // then link into list of repairs 443 GPtr->MinorRepairsP = p; 444 } 445 else if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) 446 plog( "\t%s - AllocateClearMemory failed to allocate %d bytes \n", __FUNCTION__, n); 447 448 if ( GPtr->RepLevel == repairLevelNoProblemsFound ) 449 GPtr->RepLevel = repairLevelVolumeRecoverable; 450 451 return( p ); // return ptr to node 452} 453 454 455 456void InvalidateCalculatedVolumeBitMap( SGlobPtr GPtr ) 457{ 458 459} 460 461 462 463//------------------------------------------------------------------------------ 464// Routine: GetVolumeFeatures 465// 466// Function: Sets up some OS and volume specific flags 467// 468// Input: GPtr->DrvNum The volume to check 469// 470// Output: GPtr->volumeFeatures Bit vector 471// GPtr->realVCB Real in-memory vcb 472//------------------------------------------------------------------------------ 473 474#if !BSD 475OSErr GetVolumeFeatures( SGlobPtr GPtr ) 476{ 477 OSErr err; 478 HParamBlockRec pb; 479 GetVolParmsInfoBuffer buffer; 480 long response; 481 482 GPtr->volumeFeatures = 0; // Initialize to zero 483 484 // Get the "real" vcb 485 err = GetVCBDriveNum( &GPtr->realVCB, GPtr->DrvNum ); 486 ReturnIfError( err ); 487 488 if ( GPtr->realVCB != nil ) 489 { 490 GPtr->volumeFeatures |= volumeIsMountedMask; 491 492 pb.ioParam.ioNamePtr = nil; 493 pb.ioParam.ioVRefNum = GPtr->realVCB->vcbVRefNum; 494 pb.ioParam.ioBuffer = (Ptr) &buffer; 495 pb.ioParam.ioReqCount = sizeof( buffer ); 496 497 if ( PBHGetVolParms( &pb, false ) == noErr ) 498 { 499 if ( buffer.vMAttrib & (1 << bSupportsTrashVolumeCache) ) 500 GPtr->volumeFeatures |= supportsTrashVolumeCacheFeatureMask; 501 } 502 } 503 // Check if the running system is HFS+ savy 504 err = Gestalt( gestaltFSAttr, &response ); 505 ReturnIfError( err ); 506 if ( (response & (1 << gestaltFSSupportsHFSPlusVols)) != 0 ) 507 GPtr->volumeFeatures |= supportsHFSPlusVolsFeatureMask; 508 509 return( noErr ); 510} 511#endif 512 513 514 515/*------------------------------------------------------------------------------- 516Routine: ClearMemory - clear a block of memory 517 518-------------------------------------------------------------------------------*/ 519#if !BSD 520void ClearMemory( void* start, UInt32 length ) 521{ 522 UInt32 zero = 0; 523 UInt32* dataPtr; 524 UInt8* bytePtr; 525 UInt32 fragCount; // serves as both a length and quadlong count 526 // for the beginning and main fragment 527 528 if ( length == 0 ) 529 return; 530 531 // is request less than 4 bytes? 532 if ( length < 4 ) // length = 1,2 or 3 533 { 534 bytePtr = (UInt8 *) start; 535 536 do 537 { 538 *bytePtr++ = zero; // clear one byte at a time 539 } 540 while ( --length ); 541 542 return; 543 } 544 545 // are we aligned on an odd boundry? 546 fragCount = (UInt32) start & 3; 547 548 if ( fragCount ) // fragCount = 1,2 or 3 549 { 550 bytePtr = (UInt8 *) start; 551 552 do 553 { 554 *bytePtr++ = zero; // clear one byte at a time 555 ++fragCount; 556 --length; 557 } 558 while ( (fragCount < 4) && (length > 0) ); 559 560 if ( length == 0 ) 561 return; 562 563 dataPtr = (UInt32*) (((UInt32) start & 0xFFFFFFFC) + 4); // make it long word aligned 564 } 565 else 566 { 567 dataPtr = (UInt32*) ((UInt32) start & 0xFFFFFFFC); // make it long word aligned 568 } 569 570 // At this point dataPtr is long aligned 571 572 // are there odd bytes to copy? 573 fragCount = length & 3; 574 575 if ( fragCount ) 576 { 577 bytePtr = (UInt8 *) ((UInt32) dataPtr + (UInt32) length - 1); // point to last byte 578 579 length -= fragCount; // adjust remaining length 580 581 do 582 { 583 *bytePtr-- = zero; // clear one byte at a time 584 } 585 while ( --fragCount ); 586 587 if ( length == 0 ) 588 return; 589 } 590 591 // At this point length is a multiple of 4 592 593 #if DEBUG_BUILD 594 if ( length < 4 ) 595 DebugStr("\p ClearMemory: length < 4"); 596 #endif 597 598 // fix up beginning to get us on a 64 byte boundary 599 fragCount = length & (64-1); 600 601 #if DEBUG_BUILD 602 if ( fragCount < 4 && fragCount > 0 ) 603 DebugStr("\p ClearMemory: fragCount < 4"); 604 #endif 605 606 if ( fragCount ) 607 { 608 length -= fragCount; // subtract fragment from length now 609 fragCount >>= 2; // divide by 4 to get a count, for DBRA loop 610 do 611 { 612 // clear 4 bytes at a time... 613 *dataPtr++ = zero; 614 } 615 while (--fragCount); 616 } 617 618 // Are we finished yet? 619 if ( length == 0 ) 620 return; 621 622 // Time to turn on the fire hose 623 length >>= 6; // divide by 64 to get count 624 do 625 { 626 // spray 64 bytes at a time... 627 *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; 628 *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; 629 *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; 630 *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; *dataPtr++ = zero; 631 } 632 while (--length); 633} 634#endif 635 636 637 638void 639CopyCatalogName(const CatalogName *srcName, CatalogName *dstName, Boolean isHFSPLus) 640{ 641 size_t length; 642 643 if ( srcName == NULL ) 644 { 645 if ( dstName != NULL ) 646 dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal) 647 return; 648 } 649 650 if (isHFSPLus) 651 length = sizeof(UniChar) * (srcName->ustr.length + 1); 652 else 653 length = sizeof(UInt8) + srcName->pstr[0]; 654 655 if ( length > 1 ) 656 CopyMemory(srcName, dstName, length); 657 else 658 dstName->ustr.length = 0; // set length byte to zero (works for both unicode and pascal) 659} 660 661 662UInt32 663CatalogNameLength(const CatalogName *name, Boolean isHFSPlus) 664{ 665 if (isHFSPlus) 666 return name->ustr.length; 667 else 668 return name->pstr[0]; 669} 670 671 672UInt32 CatalogNameSize( const CatalogName *name, Boolean isHFSPlus) 673{ 674 UInt32 length = CatalogNameLength( name, isHFSPlus ); 675 676 if ( isHFSPlus ) 677 length *= sizeof(UniChar); 678 679 return( length ); 680} 681 682 683//****************************************************************************** 684// Routine: BuildCatalogKey 685// 686// Function: Constructs a catalog key record (ckr) given the parent 687// folder ID and CName. Works for both classic and extended 688// HFS volumes. 689// 690//****************************************************************************** 691 692void 693BuildCatalogKey(HFSCatalogNodeID parentID, const CatalogName *cName, Boolean isHFSPlus, CatalogKey *key) 694{ 695 if ( isHFSPlus ) 696 { 697 key->hfsPlus.keyLength = kHFSPlusCatalogKeyMinimumLength; // initial key length (4 + 2) 698 key->hfsPlus.parentID = parentID; // set parent ID 699 key->hfsPlus.nodeName.length = 0; // null CName length 700 if ( cName != NULL ) 701 { 702 CopyCatalogName(cName, (CatalogName *) &key->hfsPlus.nodeName, isHFSPlus); 703 key->hfsPlus.keyLength += sizeof(UniChar) * cName->ustr.length; // add CName size to key length 704 } 705 } 706 else 707 { 708 key->hfs.keyLength = kHFSCatalogKeyMinimumLength; // initial key length (1 + 4 + 1) 709 key->hfs.reserved = 0; // clear unused byte 710 key->hfs.parentID = parentID; // set parent ID 711 key->hfs.nodeName[0] = 0; // null CName length 712 if ( cName != NULL ) 713 { 714 UpdateCatalogName(cName->pstr, key->hfs.nodeName); 715 key->hfs.keyLength += key->hfs.nodeName[0]; // add CName size to key length 716 } 717 } 718} 719 720 721// Defined in BTreesPrivate.h, but not implemented in the BTree code? 722// So... here's the implementation 723SInt32 CompareKeys( BTreeControlBlockPtr btreePtr, KeyPtr searchKey, KeyPtr trialKey ) 724{ 725 KeyCompareProcPtr compareProc = (KeyCompareProcPtr)btreePtr->keyCompareProc; 726 727 return( compareProc(searchKey, trialKey) ); 728} 729 730 731void 732UpdateCatalogName(ConstStr31Param srcName, Str31 destName) 733{ 734 Size length = srcName[0]; 735 736 if (length > kHFSMaxFileNameChars) 737 length = kHFSMaxFileNameChars; // truncate to max 738 739 destName[0] = length; // set length byte 740 741 CopyMemory(&srcName[1], &destName[1], length); 742} 743 744 745void 746UpdateVolumeEncodings(SVCB *volume, TextEncoding encoding) 747{ 748 UInt32 index; 749 750 encoding &= 0x7F; 751 752 index = MapEncodingToIndex(encoding); 753 754 volume->vcbEncodingsBitmap |= (u_int64_t)(1ULL << index); 755 756 // vcb should already be marked dirty 757} 758 759 760//****************************************************************************** 761// Routine: VolumeObjectFixPrimaryBlock 762// 763// Function: Use the alternate Volume Header or Master Directory block (depending 764// on the type of volume) to restore the primary block. This routine 765// depends upon our intialization code to set up where are blocks are 766// located. 767// 768// Result: 0 if all is well, noMacDskErr when we do not have a primary block 769// number or whatever GetVolumeObjectAlternateBlock returns. 770//****************************************************************************** 771 772static OSErr VolumeObjectFixPrimaryBlock( void ) 773{ 774 OSErr err; 775 VolumeObjectPtr myVOPtr; 776 UInt64 myPrimaryBlockNum; 777 BlockDescriptor myPrimary; 778 BlockDescriptor myAlternate; 779 780 myVOPtr = GetVolumeObjectPtr( ); 781 myPrimary.buffer = NULL; 782 myAlternate.buffer = NULL; 783 784 GetVolumeObjectPrimaryBlockNum( &myPrimaryBlockNum ); 785 if ( myPrimaryBlockNum == 0 ) 786 return( noMacDskErr ); 787 788 // we don't care if this is a valid primary block since we're 789 // about to write over it 790 err = GetVolumeObjectPrimaryBlock( &myPrimary ); 791 if ( !(err == noErr || err == badMDBErr || err == noMacDskErr) ) 792 goto ExitThisRoutine; 793 794 // restore the primary block from the alternate 795 err = GetVolumeObjectAlternateBlock( &myAlternate ); 796 797 // invalidate if we have not marked the alternate as OK 798 if ( VolumeObjectIsHFS( ) ) { 799 if ( (myVOPtr->flags & kVO_AltMDBOK) == 0 ) 800 err = badMDBErr; 801 } 802 else if ( (myVOPtr->flags & kVO_AltVHBOK) == 0 ) { 803 err = badMDBErr; 804 } 805 806 if ( err == noErr ) { 807 CopyMemory( myAlternate.buffer, myPrimary.buffer, Blk_Size ); 808 (void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myPrimary, kForceWriteBlock ); 809 myPrimary.buffer = NULL; 810 if ( myVOPtr->volumeType == kHFSVolumeType ) 811 myVOPtr->flags |= kVO_PriMDBOK; 812 else 813 myVOPtr->flags |= kVO_PriVHBOK; 814 } 815 816ExitThisRoutine: 817 if ( myPrimary.buffer != NULL ) 818 (void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myPrimary, kReleaseBlock ); 819 if ( myAlternate.buffer != NULL ) 820 (void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myAlternate, kReleaseBlock ); 821 822 return( err ); 823 824} /* VolumeObjectFixPrimaryBlock */ 825 826 827//****************************************************************************** 828// Routine: GetVolumeObjectVHBorMDB 829// 830// Function: Get the Volume Header block or Master Directory block (depending 831// on type of volume). This will normally return the alternate, but 832// it may return the primary when the alternate is damaged or cannot 833// be found. 834// 835// Result: returns 0 when all is well. 836//****************************************************************************** 837OSErr GetVolumeObjectVHBorMDB( BlockDescriptor * theBlockDescPtr ) 838{ 839 UInt64 myBlockNum; 840 VolumeObjectPtr myVOPtr; 841 OSErr err; 842 843 myVOPtr = GetVolumeObjectPtr( ); 844 GetVolumeObjectBlockNum( &myBlockNum ); 845 846 err = GetVolumeObjectBlock( myVOPtr, myBlockNum, theBlockDescPtr ); 847 if ( err == noErr ) 848 { 849 if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType || 850 myVOPtr->volumeType == kPureHFSPlusVolumeType ) 851 { 852 err = ValidVolumeHeader( (HFSPlusVolumeHeader*) theBlockDescPtr->buffer ); 853 } 854 else if ( myVOPtr->volumeType == kHFSVolumeType ) 855 { 856 HFSMasterDirectoryBlock * myMDBPtr; 857 myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer; 858 if ( myMDBPtr->drSigWord != kHFSSigWord ) 859 err = noMacDskErr; 860 } 861 else 862 err = noMacDskErr; 863 } 864 865 return( err ); 866 867} /* GetVolumeObjectVHBorMDB */ 868 869 870//****************************************************************************** 871// Routine: GetVolumeObjectAlternateBlock 872// 873// Function: Get the alternate Volume Header block or Master Directory block 874// (depending on type of volume). 875// Result: returns 0 when all is well. 876//****************************************************************************** 877OSErr GetVolumeObjectAlternateBlock( BlockDescriptor * theBlockDescPtr ) 878{ 879 UInt64 myBlockNum; 880 VolumeObjectPtr myVOPtr; 881 OSErr err; 882 883 myVOPtr = GetVolumeObjectPtr( ); 884 GetVolumeObjectAlternateBlockNum( &myBlockNum ); 885 886 err = GetVolumeObjectBlock( myVOPtr, myBlockNum, theBlockDescPtr ); 887 if ( err == noErr ) 888 { 889 if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType || 890 myVOPtr->volumeType == kPureHFSPlusVolumeType ) 891 { 892 err = ValidVolumeHeader( (HFSPlusVolumeHeader*) theBlockDescPtr->buffer ); 893 } 894 else if ( myVOPtr->volumeType == kHFSVolumeType ) 895 { 896 HFSMasterDirectoryBlock * myMDBPtr; 897 myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer; 898 if ( myMDBPtr->drSigWord != kHFSSigWord ) 899 err = noMacDskErr; 900 } 901 else 902 err = noMacDskErr; 903 } 904 905 return( err ); 906 907} /* GetVolumeObjectAlternateBlock */ 908 909 910//****************************************************************************** 911// Routine: GetVolumeObjectPrimaryBlock 912// 913// Function: Get the primary Volume Header block or Master Directory block 914// (depending on type of volume). 915// Result: returns 0 when all is well. 916//****************************************************************************** 917OSErr GetVolumeObjectPrimaryBlock( BlockDescriptor * theBlockDescPtr ) 918{ 919 UInt64 myBlockNum; 920 VolumeObjectPtr myVOPtr; 921 OSErr err; 922 923 myVOPtr = GetVolumeObjectPtr( ); 924 GetVolumeObjectPrimaryBlockNum( &myBlockNum ); 925 926 err = GetVolumeObjectBlock( myVOPtr, myBlockNum, theBlockDescPtr ); 927 if ( err == noErr ) 928 { 929 if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType || 930 myVOPtr->volumeType == kPureHFSPlusVolumeType ) 931 { 932 err = ValidVolumeHeader( (HFSPlusVolumeHeader*) theBlockDescPtr->buffer ); 933 } 934 else if ( myVOPtr->volumeType == kHFSVolumeType ) 935 { 936 HFSMasterDirectoryBlock * myMDBPtr; 937 myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer; 938 if ( myMDBPtr->drSigWord != kHFSSigWord ) 939 err = noMacDskErr; 940 } 941 else 942 err = noMacDskErr; 943 } 944 945 return( err ); 946 947} /* GetVolumeObjectPrimaryBlock */ 948 949 950//****************************************************************************** 951// Routine: GetVolumeObjectVHB 952// 953// Function: Get the Volume Header block using either the primary or alternate 954// block number as set up by InitializeVolumeObject. This will normally 955// return the alternate, but it may return the primary when the 956// alternate is damaged or cannot be found. 957// 958// Result: returns 0 when all is well or passes results of GetVolumeBlock or 959// ValidVolumeHeader. 960//****************************************************************************** 961OSErr GetVolumeObjectVHB( BlockDescriptor * theBlockDescPtr ) 962{ 963 UInt64 myBlockNum; 964 VolumeObjectPtr myVOPtr; 965 OSErr err; 966 967 myVOPtr = GetVolumeObjectPtr( ); 968 myBlockNum = ((myVOPtr->flags & kVO_AltVHBOK) != 0) ? myVOPtr->alternateVHB : myVOPtr->primaryVHB; 969 err = GetVolumeObjectBlock( myVOPtr, myBlockNum, theBlockDescPtr ); 970 if ( err == noErr ) 971 err = ValidVolumeHeader( (HFSPlusVolumeHeader*) theBlockDescPtr->buffer ); 972 973 return( err ); 974 975} /* GetVolumeObjectVHB */ 976 977 978//****************************************************************************** 979// Routine: GetVolumeObjectAlternateMDB 980// 981// Function: Get the Master Directory Block using the alternate master directory 982// block number as set up by InitializeVolumeObject. 983// 984// Result: returns 0 when all is well. 985//****************************************************************************** 986OSErr GetVolumeObjectAlternateMDB( BlockDescriptor * theBlockDescPtr ) 987{ 988 VolumeObjectPtr myVOPtr; 989 OSErr err; 990 991 myVOPtr = GetVolumeObjectPtr( ); 992 err = GetVolumeObjectBlock( NULL, myVOPtr->alternateMDB, theBlockDescPtr ); 993 if ( err == noErr ) 994 { 995 HFSMasterDirectoryBlock * myMDBPtr; 996 myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer; 997 if ( myMDBPtr->drSigWord != kHFSSigWord ) 998 err = noMacDskErr; 999 } 1000 1001 return( err ); 1002 1003} /* GetVolumeObjectAlternateMDB */ 1004 1005 1006//****************************************************************************** 1007// Routine: GetVolumeObjectPrimaryMDB 1008// 1009// Function: Get the Master Directory Block using the primary master directory 1010// block number as set up by InitializeVolumeObject. 1011// 1012// Result: returns 0 when all is well. 1013//****************************************************************************** 1014OSErr GetVolumeObjectPrimaryMDB( BlockDescriptor * theBlockDescPtr ) 1015{ 1016 VolumeObjectPtr myVOPtr; 1017 OSErr err; 1018 1019 myVOPtr = GetVolumeObjectPtr( ); 1020 err = GetVolumeObjectBlock( NULL, myVOPtr->primaryMDB, theBlockDescPtr ); 1021 if ( err == noErr ) 1022 { 1023 HFSMasterDirectoryBlock * myMDBPtr; 1024 myMDBPtr = (HFSMasterDirectoryBlock *) theBlockDescPtr->buffer; 1025 if ( myMDBPtr->drSigWord != kHFSSigWord ) 1026 err = noMacDskErr; 1027 } 1028 1029 return( err ); 1030 1031} /* GetVolumeObjectPrimaryMDB */ 1032 1033 1034//****************************************************************************** 1035// Routine: GetVolumeObjectBlock 1036// 1037// Function: Get the Volume Header block or Master Directory block using the 1038// given block number. 1039// Result: returns 0 when all is well or passes results of GetVolumeBlock or 1040// ValidVolumeHeader. 1041//****************************************************************************** 1042static OSErr GetVolumeObjectBlock( VolumeObjectPtr theVOPtr, 1043 UInt64 theBlockNum, 1044 BlockDescriptor * theBlockDescPtr ) 1045{ 1046 OSErr err; 1047 1048 if ( theVOPtr == NULL ) 1049 theVOPtr = GetVolumeObjectPtr( ); 1050 1051 err = GetVolumeBlock( theVOPtr->vcbPtr, theBlockNum, kGetBlock, theBlockDescPtr ); 1052 1053 return( err ); 1054 1055} /* GetVolumeObjectBlock */ 1056 1057 1058//****************************************************************************** 1059// Routine: GetVolumeObjectBlockNum 1060// 1061// Function: Extract the appropriate block number for the volume header or 1062// master directory (depanding on volume type) from the VolumeObject. 1063// NOTE - this routine may return the primary or alternate block 1064// depending on which one is valid. Preference is always given to 1065// the alternate. 1066// 1067// Result: returns block number of MDB or VHB or 0 if none are valid or 1068// if volume type is unknown. 1069//****************************************************************************** 1070void GetVolumeObjectBlockNum( UInt64 * theBlockNumPtr ) 1071{ 1072 VolumeObjectPtr myVOPtr; 1073 1074 myVOPtr = GetVolumeObjectPtr( ); 1075 *theBlockNumPtr = 0; // default to none 1076 1077 // NOTE - we use alternate volume header or master directory 1078 // block before the primary because it is less likely to be damaged. 1079 if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType || 1080 myVOPtr->volumeType == kPureHFSPlusVolumeType ) { 1081 if ( (myVOPtr->flags & kVO_AltVHBOK) != 0 ) 1082 *theBlockNumPtr = myVOPtr->alternateVHB; 1083 else 1084 *theBlockNumPtr = myVOPtr->primaryVHB; 1085 } 1086 else if ( myVOPtr->volumeType == kHFSVolumeType ) { 1087 if ( (myVOPtr->flags & kVO_AltMDBOK) != 0 ) 1088 *theBlockNumPtr = myVOPtr->alternateMDB; 1089 else 1090 *theBlockNumPtr = myVOPtr->primaryMDB; 1091 } 1092 1093 return; 1094 1095} /* GetVolumeObjectBlockNum */ 1096 1097 1098//****************************************************************************** 1099// Routine: GetVolumeObjectAlternateBlockNum 1100// 1101// Function: Extract the alternate block number for the volume header or 1102// master directory (depanding on volume type) from the VolumeObject. 1103// 1104// Result: returns block number of alternate MDB or VHB or 0 if none are 1105// valid or if volume type is unknown. 1106//****************************************************************************** 1107void GetVolumeObjectAlternateBlockNum( UInt64 * theBlockNumPtr ) 1108{ 1109 VolumeObjectPtr myVOPtr; 1110 1111 myVOPtr = GetVolumeObjectPtr( ); 1112 *theBlockNumPtr = 0; // default to none 1113 1114 if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType || 1115 myVOPtr->volumeType == kPureHFSPlusVolumeType ) { 1116 *theBlockNumPtr = myVOPtr->alternateVHB; 1117 } 1118 else if ( myVOPtr->volumeType == kHFSVolumeType ) { 1119 *theBlockNumPtr = myVOPtr->alternateMDB; 1120 } 1121 1122 return; 1123 1124} /* GetVolumeObjectAlternateBlockNum */ 1125 1126 1127//****************************************************************************** 1128// Routine: GetVolumeObjectPrimaryBlockNum 1129// 1130// Function: Extract the primary block number for the volume header or 1131// master directory (depanding on volume type) from the VolumeObject. 1132// 1133// Result: returns block number of primary MDB or VHB or 0 if none are valid 1134// or if volume type is unknown. 1135//****************************************************************************** 1136void GetVolumeObjectPrimaryBlockNum( UInt64 * theBlockNumPtr ) 1137{ 1138 VolumeObjectPtr myVOPtr; 1139 1140 myVOPtr = GetVolumeObjectPtr( ); 1141 *theBlockNumPtr = 0; // default to none 1142 1143 if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType || 1144 myVOPtr->volumeType == kPureHFSPlusVolumeType ) { 1145 *theBlockNumPtr = myVOPtr->primaryVHB; 1146 } 1147 else if ( myVOPtr->volumeType == kHFSVolumeType ) { 1148 *theBlockNumPtr = myVOPtr->primaryMDB; 1149 } 1150 1151 return; 1152 1153} /* GetVolumeObjectPrimaryBlockNum */ 1154 1155 1156//****************************************************************************** 1157// Routine: InitializeVolumeObject 1158// 1159// Function: Locate volume headers and / or master directory blocks for this 1160// volume and fill where they are located on the volume and the type 1161// of volume we are dealing with. We have three types of HFS volumes: 1162// � HFS - standard (old format) where primary MDB is 2nd block into 1163// the volume and alternate MDB is 2nd to last block on the volume. 1164// � pure HFS+ - where primary volume header is 2nd block into 1165// the volume and alternate volume header is 2nd to last block on 1166// the volume. 1167// � wrapped HFS+ - where primary MDB is 2nd block into the volume and 1168// alternate MDB is 2nd to last block on the volume. The embedded 1169// HFS+ volume header locations are calculated from drEmbedExtent 1170// (in the MDB). 1171// 1172// Result: returns nothing. Will fill in SGlob.VolumeObject data 1173//****************************************************************************** 1174void InitializeVolumeObject( SGlobPtr GPtr ) 1175{ 1176 OSErr err; 1177 HFSMasterDirectoryBlock * myMDBPtr; 1178 HFSPlusVolumeHeader * myVHPtr; 1179 VolumeObjectPtr myVOPtr; 1180 HFSPlusVolumeHeader myPriVolHeader; 1181 BlockDescriptor myBlockDescriptor; 1182 1183 myBlockDescriptor.buffer = NULL; 1184 myVOPtr = GetVolumeObjectPtr( ); 1185 myVOPtr->flags |= kVO_Inited; 1186 myVOPtr->vcbPtr = GPtr->calculatedVCB; 1187 1188 // Determine volume size in sectors 1189 err = GetDeviceSize( GPtr->calculatedVCB->vcbDriveNumber, 1190 &myVOPtr->totalDeviceSectors, 1191 &myVOPtr->sectorSize ); 1192 if ( (myVOPtr->totalDeviceSectors < 3) || (err != noErr) ) { 1193 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1194 plog("\tinvalid device information for volume - total sectors = %qd sector size = %d \n", 1195 myVOPtr->totalDeviceSectors, myVOPtr->sectorSize); 1196 } 1197 goto ExitRoutine; 1198 } 1199 1200 // get the primary volume header or master directory block (depending on volume type) 1201 // should always be block 2 (relative to 0) into the volume. 1202 err = GetVolumeObjectBlock( myVOPtr, MDB_BlkN, &myBlockDescriptor ); 1203 if ( err == noErr ) { 1204 myMDBPtr = (HFSMasterDirectoryBlock *) myBlockDescriptor.buffer; 1205 if ( myMDBPtr->drSigWord == kHFSPlusSigWord || myMDBPtr->drSigWord == kHFSXSigWord) { 1206 myVHPtr = (HFSPlusVolumeHeader *) myMDBPtr; 1207 1208 myVOPtr->primaryVHB = MDB_BlkN; // save location 1209 myVOPtr->alternateVHB = myVOPtr->totalDeviceSectors - 2; // save location 1210 err = ValidVolumeHeader( myVHPtr ); 1211 if ( err == noErr ) { 1212 myVOPtr->flags |= kVO_PriVHBOK; 1213 bcopy( myVHPtr, &myPriVolHeader, sizeof( *myVHPtr ) ); 1214 } 1215 else { 1216 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1217 plog( "\tInvalid primary volume header - error %d \n", err ); 1218 } 1219 } 1220 } 1221 else if ( myMDBPtr->drSigWord == kHFSSigWord ) { 1222 // we could have an HFS or wrapped HFS+ volume 1223 myVOPtr->primaryMDB = MDB_BlkN; // save location 1224 myVOPtr->alternateMDB = myVOPtr->totalDeviceSectors - 2; // save location 1225 myVOPtr->flags |= kVO_PriMDBOK; 1226 } 1227 else { 1228 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1229 plog( "\tBlock %d is not an MDB or Volume Header \n", MDB_BlkN ); 1230 } 1231 } 1232 (void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock ); 1233 } 1234 else { 1235 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1236 plog( "\tcould not get volume block %d, err %d \n", MDB_BlkN, err ); 1237 } 1238 } 1239 1240 // get the alternate volume header or master directory block (depending on volume type) 1241 // should always be 2nd to last sector. 1242 err = GetVolumeObjectBlock( myVOPtr, myVOPtr->totalDeviceSectors - 2, &myBlockDescriptor ); 1243 if ( err == noErr ) { 1244 myMDBPtr = (HFSMasterDirectoryBlock *) myBlockDescriptor.buffer; 1245 if ( myMDBPtr->drSigWord == kHFSPlusSigWord || myMDBPtr->drSigWord == kHFSXSigWord ) { 1246 myVHPtr = (HFSPlusVolumeHeader *) myMDBPtr; 1247 1248 myVOPtr->primaryVHB = MDB_BlkN; // save location 1249 myVOPtr->alternateVHB = myVOPtr->totalDeviceSectors - 2; // save location 1250 err = ValidVolumeHeader( myVHPtr ); 1251 if ( err == noErr ) { 1252 // check to see if the primary and alternates are in sync. 3137809 1253 myVOPtr->flags |= kVO_AltVHBOK; 1254 CompareVolHeaderBTreeSizes( GPtr, myVOPtr, &myPriVolHeader, myVHPtr ); 1255 } 1256 else { 1257 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1258 plog( "\tInvalid alternate volume header - error %d \n", err ); 1259 } 1260 } 1261 } 1262 else if ( myMDBPtr->drSigWord == kHFSSigWord ) { 1263 myVOPtr->primaryMDB = MDB_BlkN; // save location 1264 myVOPtr->alternateMDB = myVOPtr->totalDeviceSectors - 2; // save location 1265 myVOPtr->flags |= kVO_AltMDBOK; 1266 } 1267 else { 1268 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1269 plog( "\tBlock %qd is not an MDB or Volume Header \n", myVOPtr->totalDeviceSectors - 2 ); 1270 } 1271 } 1272 1273 (void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock ); 1274 } 1275 else { 1276 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1277 plog( "\tcould not get alternate volume header at %qd, err %d \n", 1278 myVOPtr->totalDeviceSectors - 2, err ); 1279 } 1280 } 1281 1282 // get the embedded volume header (if applicable). 1283 if ( (myVOPtr->flags & kVO_AltMDBOK) != 0 ) { 1284 err = GetVolumeObjectBlock( myVOPtr, myVOPtr->alternateMDB, &myBlockDescriptor ); 1285 if ( err == noErr ) { 1286 myMDBPtr = (HFSMasterDirectoryBlock *) myBlockDescriptor.buffer; 1287 GetEmbeddedVolumeHeaders( GPtr, myMDBPtr, false ); 1288 (void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock ); 1289 } 1290 } 1291 1292 // Now we will look for embedded HFS+ volume headers using the primary MDB if 1293 // we haven't already located them. 1294 if ( (myVOPtr->flags & kVO_PriMDBOK) != 0 && 1295 ((myVOPtr->flags & kVO_PriVHBOK) == 0 || (myVOPtr->flags & kVO_AltVHBOK) == 0) ) { 1296 err = GetVolumeObjectBlock( myVOPtr, myVOPtr->primaryMDB, &myBlockDescriptor ); 1297 if ( err == noErr ) { 1298 myMDBPtr = (HFSMasterDirectoryBlock *) myBlockDescriptor.buffer; 1299 GetEmbeddedVolumeHeaders( GPtr, myMDBPtr, true ); 1300 (void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock ); 1301 } 1302 else { 1303 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1304 plog( "\tcould not get primary MDB at block %qd, err %d \n", myVOPtr->primaryMDB, err ); 1305 } 1306 } 1307 } 1308 1309ExitRoutine: 1310 // set the type of volume using the flags we set as we located the various header / master 1311 // blocks. 1312 if ( ((myVOPtr->flags & kVO_PriVHBOK) != 0 || (myVOPtr->flags & kVO_AltVHBOK) != 0) && 1313 ((myVOPtr->flags & kVO_PriMDBOK) != 0 || (myVOPtr->flags & kVO_AltMDBOK) != 0) ) { 1314 myVOPtr->volumeType = kEmbededHFSPlusVolumeType; 1315 } 1316 else if ( ((myVOPtr->flags & kVO_PriVHBOK) != 0 || (myVOPtr->flags & kVO_AltVHBOK) != 0) && 1317 (myVOPtr->flags & kVO_PriMDBOK) == 0 && (myVOPtr->flags & kVO_AltMDBOK) == 0 ) { 1318 myVOPtr->volumeType = kPureHFSPlusVolumeType; 1319 } 1320 else if ( (myVOPtr->flags & kVO_PriVHBOK) == 0 && (myVOPtr->flags & kVO_AltVHBOK) == 0 && 1321 ((myVOPtr->flags & kVO_PriMDBOK) != 0 || (myVOPtr->flags & kVO_AltMDBOK) != 0) ) { 1322 myVOPtr->volumeType = kHFSVolumeType; 1323 } 1324 else 1325 myVOPtr->volumeType = kUnknownVolumeType; 1326 1327 return; 1328 1329} /* InitializeVolumeObject */ 1330 1331 1332//****************************************************************************** 1333// Routine: PrintVolumeObject 1334// 1335// Function: Print out some helpful info about the state of our VolumeObject. 1336// 1337// Result: returns nothing. 1338//****************************************************************************** 1339void PrintVolumeObject( void ) 1340{ 1341 VolumeObjectPtr myVOPtr; 1342 1343 myVOPtr = GetVolumeObjectPtr( ); 1344 1345 if ( myVOPtr->volumeType == kHFSVolumeType ) 1346 plog( "\tvolume type is HFS \n" ); 1347 else if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ) 1348 plog( "\tvolume type is embedded HFS+ \n" ); 1349 else if ( myVOPtr->volumeType == kPureHFSPlusVolumeType ) 1350 plog( "\tvolume type is pure HFS+ \n" ); 1351 else 1352 plog( "\tunknown volume type \n" ); 1353 1354 plog( "\tprimary MDB is at block %qd 0x%02qx \n", myVOPtr->primaryMDB, myVOPtr->primaryMDB ); 1355 plog( "\talternate MDB is at block %qd 0x%02qx \n", myVOPtr->alternateMDB, myVOPtr->alternateMDB ); 1356 plog( "\tprimary VHB is at block %qd 0x%02qx \n", myVOPtr->primaryVHB, myVOPtr->primaryVHB ); 1357 plog( "\talternate VHB is at block %qd 0x%02qx \n", myVOPtr->alternateVHB, myVOPtr->alternateVHB ); 1358 plog( "\tsector size = %d 0x%02x \n", myVOPtr->sectorSize, myVOPtr->sectorSize ); 1359 plog( "\tVolumeObject flags = 0x%02X \n", myVOPtr->flags ); 1360 plog( "\ttotal sectors for volume = %qd 0x%02qx \n", 1361 myVOPtr->totalDeviceSectors, myVOPtr->totalDeviceSectors ); 1362 plog( "\ttotal sectors for embedded volume = %qd 0x%02qx \n", 1363 myVOPtr->totalEmbeddedSectors, myVOPtr->totalEmbeddedSectors ); 1364 1365 return; 1366 1367} /* PrintVolumeObject */ 1368 1369 1370//****************************************************************************** 1371// Routine: GetEmbeddedVolumeHeaders 1372// 1373// Function: Given a MDB (Master Directory Block) from an HFS volume, check 1374// to see if there is an embedded HFS+ volume. If we find an 1375// embedded HFS+ volume fill in relevant SGlob.VolumeObject data. 1376// 1377// Result: returns nothing. Will fill in VolumeObject data 1378//****************************************************************************** 1379 1380static void GetEmbeddedVolumeHeaders( SGlobPtr GPtr, 1381 HFSMasterDirectoryBlock * theMDBPtr, 1382 Boolean isPrimaryMDB ) 1383{ 1384 OSErr err; 1385 HFSPlusVolumeHeader * myVHPtr; 1386 VolumeObjectPtr myVOPtr; 1387 UInt64 myHFSPlusSectors; 1388 UInt64 myPrimaryBlockNum; 1389 UInt64 myAlternateBlockNum; 1390 HFSPlusVolumeHeader myAltVolHeader; 1391 BlockDescriptor myBlockDescriptor; 1392 1393 myBlockDescriptor.buffer = NULL; 1394 myVOPtr = GetVolumeObjectPtr( ); 1395 1396 // NOTE - If all of the embedded volume information is zero, then assume 1397 // this really is a plain HFS disk like it says. There could be ghost 1398 // volume headers left over when someone reinitializes a large HFS Plus 1399 // volume as HFS. The original embedded primary volume header and 1400 // alternate volume header are not zeroed out. 1401 if ( theMDBPtr->drEmbedSigWord == 0 && 1402 theMDBPtr->drEmbedExtent.blockCount == 0 && 1403 theMDBPtr->drEmbedExtent.startBlock == 0 ) { 1404 goto ExitRoutine; 1405 } 1406 1407 // number of sectors in our embedded HFS+ volume 1408 myHFSPlusSectors = (theMDBPtr->drAlBlkSiz / Blk_Size) * theMDBPtr->drEmbedExtent.blockCount; 1409 1410 // offset of embedded HFS+ volume (in bytes) into HFS wrapper volume 1411 // NOTE - UInt32 is OK since we don't support HFS Wrappers on TB volumes 1412 myVOPtr->embeddedOffset = 1413 (theMDBPtr->drEmbedExtent.startBlock * theMDBPtr->drAlBlkSiz) + 1414 (theMDBPtr->drAlBlSt * Blk_Size); 1415 1416 // Embedded alternate volume header is always 2nd to last sector 1417 myAlternateBlockNum = 1418 theMDBPtr->drAlBlSt + 1419 ((theMDBPtr->drAlBlkSiz / Blk_Size) * theMDBPtr->drEmbedExtent.startBlock) + 1420 myHFSPlusSectors - 2; 1421 1422 // Embedded primary volume header should always be block 2 (relative to 0) 1423 // into the embedded volume 1424 myPrimaryBlockNum = (theMDBPtr->drEmbedExtent.startBlock * theMDBPtr->drAlBlkSiz / Blk_Size) + 1425 theMDBPtr->drAlBlSt + 2; 1426 1427 // get the embedded alternate volume header 1428 err = GetVolumeObjectBlock( myVOPtr, myAlternateBlockNum, &myBlockDescriptor ); 1429 if ( err == noErr ) { 1430 myVHPtr = (HFSPlusVolumeHeader *) myBlockDescriptor.buffer; 1431 if ( myVHPtr->signature == kHFSPlusSigWord ) { 1432 1433 myVOPtr->alternateVHB = myAlternateBlockNum; // save location 1434 myVOPtr->primaryVHB = myPrimaryBlockNum; // save location 1435 err = ValidVolumeHeader( myVHPtr ); 1436 if ( err == noErr ) { 1437 myVOPtr->flags |= kVO_AltVHBOK; 1438 myVOPtr->totalEmbeddedSectors = myHFSPlusSectors; 1439 bcopy( myVHPtr, &myAltVolHeader, sizeof( *myVHPtr ) ); 1440 } 1441 else { 1442 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1443 plog( "\tInvalid embedded alternate volume header at block %qd - error %d \n", myAlternateBlockNum, err ); 1444 } 1445 } 1446 } 1447 else { 1448 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1449 plog( "\tBlock number %qd is not embedded alternate volume header \n", myAlternateBlockNum ); 1450 } 1451 } 1452 (void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock ); 1453 } 1454 else { 1455 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1456 plog( "\tcould not get embedded alternate volume header at %qd, err %d \n", 1457 myAlternateBlockNum, err ); 1458 } 1459 } 1460 1461 // get the embedded primary volume header 1462 err = GetVolumeObjectBlock( myVOPtr, myPrimaryBlockNum, &myBlockDescriptor ); 1463 if ( err == noErr ) { 1464 myVHPtr = (HFSPlusVolumeHeader *) myBlockDescriptor.buffer; 1465 if ( myVHPtr->signature == kHFSPlusSigWord ) { 1466 1467 myVOPtr->primaryVHB = myPrimaryBlockNum; // save location 1468 myVOPtr->alternateVHB = myAlternateBlockNum; // save location 1469 err = ValidVolumeHeader( myVHPtr ); 1470 if ( err == noErr ) { 1471 myVOPtr->flags |= kVO_PriVHBOK; 1472 myVOPtr->totalEmbeddedSectors = myHFSPlusSectors; 1473 1474 // check to see if the primary and alternates are in sync. 3137809 1475 CompareVolHeaderBTreeSizes( GPtr, myVOPtr, myVHPtr, &myAltVolHeader ); 1476 } 1477 else { 1478 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1479 plog( "\tInvalid embedded primary volume header at block %qd - error %d \n", myPrimaryBlockNum, err ); 1480 } 1481 } 1482 } 1483 else { 1484 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1485 plog( "\tBlock number %qd is not embedded primary volume header \n", myPrimaryBlockNum ); 1486 } 1487 } 1488 (void) ReleaseVolumeBlock( GPtr->calculatedVCB, &myBlockDescriptor, kReleaseBlock ); 1489 } 1490 else { 1491 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1492 plog( "\tcould not get embedded primary volume header at %qd, err %d \n", 1493 myPrimaryBlockNum, err ); 1494 } 1495 } 1496 1497ExitRoutine: 1498 return; 1499 1500} /* GetEmbeddedVolumeHeaders */ 1501 1502 1503//****************************************************************************** 1504// Routine: CompareVolHeaderBTreeSizes 1505// 1506// Function: checks to see if the primary and alternate volume headers are in 1507// sync with regards to the catalog and extents btree file size. If 1508// we find an anomaly we will give preference to the volume header 1509// with the larger of the btree files since these files never shrink. 1510// Added for radar #3137809. 1511// 1512// Result: returns nothing. 1513//****************************************************************************** 1514static void CompareVolHeaderBTreeSizes( SGlobPtr GPtr, 1515 VolumeObjectPtr theVOPtr, 1516 HFSPlusVolumeHeader * thePriVHPtr, 1517 HFSPlusVolumeHeader * theAltVHPtr ) 1518{ 1519 int weDisagree; 1520 int usePrimary; 1521 int useAlternate; 1522 1523 weDisagree = usePrimary = useAlternate = 0; 1524 1525 // we only check if both volume headers appear to be OK 1526 if ( (theVOPtr->flags & kVO_PriVHBOK) == 0 || (theVOPtr->flags & kVO_AltVHBOK) == 0 ) 1527 return; 1528 1529 if ( thePriVHPtr->catalogFile.totalBlocks != theAltVHPtr->catalogFile.totalBlocks ) { 1530 // only continue if the B*Tree files both start at the same block number 1531 if ( thePriVHPtr->catalogFile.extents[0].startBlock == theAltVHPtr->catalogFile.extents[0].startBlock ) { 1532 weDisagree = 1; 1533 if ( thePriVHPtr->catalogFile.totalBlocks > theAltVHPtr->catalogFile.totalBlocks ) 1534 usePrimary = 1; 1535 else 1536 useAlternate = 1; 1537 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1538 plog( "\tvolume headers disagree on catalog file total blocks - primary %d alternate %d \n", 1539 thePriVHPtr->catalogFile.totalBlocks, theAltVHPtr->catalogFile.totalBlocks ); 1540 } 1541 } 1542 } 1543 1544 if ( thePriVHPtr->extentsFile.totalBlocks != theAltVHPtr->extentsFile.totalBlocks ) { 1545 // only continue if the B*Tree files both start at the same block number 1546 if ( thePriVHPtr->extentsFile.extents[0].startBlock == theAltVHPtr->extentsFile.extents[0].startBlock ) { 1547 weDisagree = 1; 1548 if ( thePriVHPtr->extentsFile.totalBlocks > theAltVHPtr->extentsFile.totalBlocks ) 1549 usePrimary = 1; 1550 else 1551 useAlternate = 1; 1552 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1553 plog( "\tvolume headers disagree on extents file total blocks - primary %d alternate %d \n", 1554 thePriVHPtr->extentsFile.totalBlocks, theAltVHPtr->extentsFile.totalBlocks ); 1555 } 1556 } 1557 } 1558 1559 if ( weDisagree == 0 ) 1560 return; 1561 1562 // we have a disagreement. we resolve the issue by using the larger of the two. 1563 if ( usePrimary == 1 && useAlternate == 1 ) { 1564 // this should never happen, but if it does, bail without choosing a preference 1565 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1566 plog( "\tvolume headers disagree but there is confusion on which to use \n" ); 1567 } 1568 return; 1569 } 1570 1571 if ( usePrimary == 1 ) { 1572 // mark alternate as bogus 1573 theVOPtr->flags &= ~kVO_AltVHBOK; 1574 } 1575 else if ( useAlternate == 1 ) { 1576 // mark primary as bogus 1577 theVOPtr->flags &= ~kVO_PriVHBOK; 1578 } 1579 1580 return; 1581 1582} /* CompareVolHeaderBTreeSizes */ 1583 1584 1585/* 1586 * This code should be removed after debugging is completed. 1587 */ 1588#include <ctype.h> 1589 1590#ifndef MIN 1591#define MIN(a, b) \ 1592 ({ __typeof(a) _a = (a); __typeof(b) _b = (b); \ 1593 (_a < _b) ? _a : _b; }) 1594#endif 1595 1596 1597enum { WIDTH = 16, }; 1598 1599void 1600DumpData(const void *data, size_t len) 1601{ 1602 unsigned char *base = (unsigned char*)data; 1603 unsigned char *end = base + len; 1604 unsigned char *cp = base; 1605 int allzeroes = 0; 1606 1607 while (cp < end) { 1608 unsigned char *tend = MIN(end, cp + WIDTH); 1609 unsigned char *tmp; 1610 int i; 1611 size_t gap = (cp + WIDTH) - tend; 1612 1613 if (gap != 0 || tend == end) 1614 allzeroes = 0; 1615 if (allzeroes) { 1616 for (tmp = cp; tmp < tend; tmp++) { 1617 if (*tmp) { 1618 allzeroes = 0; 1619 break; 1620 } 1621 } 1622 if (allzeroes == 1) { 1623 fprintf(stderr, ". . .\n"); 1624 allzeroes = 2; 1625 } 1626 if (allzeroes) { 1627 cp += WIDTH; 1628 continue; 1629 } 1630 } 1631 allzeroes = 1; 1632 1633 fprintf(stderr, "%04x: ", (int)(cp - base)); 1634 for (i = 0, tmp = cp; tmp < tend; tmp++) { 1635 fprintf(stderr, "%02x", *tmp); 1636 if (++i % 2 == 0) 1637 fprintf(stderr, " "); 1638 if (*tmp) 1639 allzeroes = 0; 1640 } 1641 for (i = gap; i >= 0; i--) { 1642 fprintf(stderr, " "); 1643 if (i % 2 == 1) 1644 fprintf(stderr, " "); 1645 } 1646 fprintf(stderr, " |"); 1647 for (tmp = cp; tmp < tend; tmp++) { 1648 fprintf(stderr, "%c", isalnum(*tmp) ? *tmp : '.'); 1649 } 1650 for (i = 0; i < gap; i++) { 1651 fprintf(stderr, " "); 1652 } 1653 fprintf(stderr, "|\n"); 1654 cp += WIDTH; 1655 } 1656 1657 return; 1658 1659} 1660//****************************************************************************** 1661// Routine: VolumeObjectIsValid 1662// 1663// Function: determine if the volume represented by our VolumeObject is a 1664// valid volume type (i.e. not unknown type) 1665// 1666// Result: returns true if volume is known volume type (i.e. HFS, HFS+) 1667// false otherwise. 1668//****************************************************************************** 1669Boolean VolumeObjectIsValid(void) 1670{ 1671 VolumeObjectPtr myVOPtr = GetVolumeObjectPtr(); 1672 Boolean retval = false; 1673 1674 /* Check if the type is unknown type */ 1675 if (myVOPtr->volumeType == kUnknownVolumeType) { 1676 pwarn("volumeType is %d\n", kUnknownVolumeType); 1677 goto done; 1678 } 1679 1680 /* Check if it is HFS+ volume */ 1681 if (VolumeObjectIsHFSPlus() == true) { 1682 retval = true; 1683 goto done; 1684 } 1685 1686 /* Check if it is HFS volume */ 1687 if (VolumeObjectIsHFS() == true) { 1688 retval = true; 1689 goto done; 1690 } 1691 1692done: 1693 /* 1694 * This code should be removed after debugging is done. 1695 */ 1696 if (retval == false) { 1697 UInt64 myBlockNum; 1698 VolumeObjectPtr myVOPtr; 1699 BlockDescriptor theBlockDesc; 1700 OSErr err; 1701 1702 myVOPtr = GetVolumeObjectPtr(); 1703 GetVolumeObjectBlockNum(&myBlockNum); 1704 err = GetVolumeBlock(myVOPtr->vcbPtr, myBlockNum, kGetBlock, &theBlockDesc); 1705 if (err != noErr) { 1706 fprintf(stderr, "%s: Cannot GetVolumetBlock: %d\n", __FUNCTION__, err); 1707 } else { 1708 uint8_t *ptr = (uint8_t*)theBlockDesc.buffer; 1709 DumpData(ptr, theBlockDesc.blockSize); 1710 ReleaseVolumeBlock(myVOPtr->vcbPtr, &theBlockDesc, kReleaseBlock); 1711 } 1712 } 1713 return retval; 1714} /* VolumeObjectIsValid */ 1715 1716//****************************************************************************** 1717// Routine: VolumeObjectIsHFSPlus 1718// 1719// Function: determine if the volume represented by our VolumeObject is an 1720// HFS+ volume (pure or embedded). 1721// 1722// Result: returns true if volume is pure HFS+ or embedded HFS+ else false. 1723//****************************************************************************** 1724Boolean VolumeObjectIsHFSPlus( void ) 1725{ 1726 VolumeObjectPtr myVOPtr; 1727 1728 myVOPtr = GetVolumeObjectPtr( ); 1729 1730 if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType || 1731 myVOPtr->volumeType == kPureHFSPlusVolumeType ) { 1732 return( true ); 1733 } 1734 1735 return( false ); 1736 1737} /* VolumeObjectIsHFSPlus */ 1738 1739 1740//****************************************************************************** 1741// Routine: VolumeObjectIsHFSX 1742// 1743// Function: determine if the volume represented by our VolumeObject is an 1744// HFSX volume (pure or embedded) 1745// 1746// Result: returns true if volume is pure HFSX or embedded HFSX else false. 1747//****************************************************************************** 1748 1749Boolean VolumeObjectIsHFSX(SGlobPtr GPtr) 1750{ 1751 OSErr err; 1752 int result = false; 1753 HFSMasterDirectoryBlock *mdbp; 1754 SVCB *vcb = GPtr->calculatedVCB; 1755 BlockDescriptor block; 1756 1757#define kIDSector 2 1758 err = GetVolumeBlock(vcb, kIDSector, kGetBlock, &block); 1759 if (err) return (false); 1760 1761 mdbp = (HFSMasterDirectoryBlock *)block.buffer; 1762 if (mdbp->drSigWord == kHFSXSigWord) { 1763 result = true; 1764 } else if (mdbp->drSigWord == kHFSSigWord) { 1765 if (mdbp->drEmbedSigWord == kHFSXSigWord) { 1766 result = true; 1767 } 1768 } 1769 1770 (void) ReleaseVolumeBlock(vcb, &block, kReleaseBlock); 1771 1772 return( result ); 1773} /* VolumeObjectIsHFSX */ 1774 1775//****************************************************************************** 1776// Routine: VolumeObjectIsHFS 1777// 1778// Function: determine if the volume represented by our VolumeObject is an 1779// HFS (standard) volume. 1780// 1781// Result: returns true if HFS (standard) volume. 1782//****************************************************************************** 1783Boolean VolumeObjectIsHFS( void ) 1784{ 1785 VolumeObjectPtr myVOPtr; 1786 1787 myVOPtr = GetVolumeObjectPtr( ); 1788 1789 if ( myVOPtr->volumeType == kHFSVolumeType ) 1790 return( true ); 1791 1792 return( false ); 1793 1794} /* VolumeObjectIsHFS */ 1795 1796 1797//****************************************************************************** 1798// Routine: VolumeObjectIsEmbeddedHFSPlus 1799// 1800// Function: determine if the volume represented by our VolumeObject is an 1801// embedded HFS plus volume. 1802// 1803// Result: returns true if embedded HFS plus volume. 1804//****************************************************************************** 1805Boolean VolumeObjectIsEmbeddedHFSPlus( void ) 1806{ 1807 VolumeObjectPtr myVOPtr; 1808 1809 myVOPtr = GetVolumeObjectPtr( ); 1810 1811 if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ) 1812 return( true ); 1813 1814 return( false ); 1815 1816} /* VolumeObjectIsEmbeddedHFSPlus */ 1817 1818 1819//****************************************************************************** 1820// Routine: VolumeObjectIsPureHFSPlus 1821// 1822// Function: determine if the volume represented by our VolumeObject is an 1823// pure HFS plus volume. 1824// 1825// Result: returns true if pure HFS plus volume. 1826//****************************************************************************** 1827Boolean VolumeObjectIsPureHFSPlus( void ) 1828{ 1829 VolumeObjectPtr myVOPtr; 1830 1831 myVOPtr = GetVolumeObjectPtr( ); 1832 1833 if ( myVOPtr->volumeType == kPureHFSPlusVolumeType ) 1834 return( true ); 1835 1836 return( false ); 1837 1838} /* VolumeObjectIsPureHFSPlus */ 1839 1840 1841//****************************************************************************** 1842// Routine: GetVolumeObjectPtr 1843// 1844// Function: Accessor routine to get a pointer to our VolumeObject structure. 1845// 1846// Result: returns pointer to our VolumeObject. 1847//****************************************************************************** 1848VolumeObjectPtr GetVolumeObjectPtr( void ) 1849{ 1850 static VolumeObject myVolumeObject; 1851 static int myInited = 0; 1852 1853 if ( myInited == 0 ) { 1854 myInited++; 1855 bzero( &myVolumeObject, sizeof(myVolumeObject) ); 1856 } 1857 1858 return( &myVolumeObject ); 1859 1860} /* GetVolumeObjectPtr */ 1861 1862 1863//****************************************************************************** 1864// Routine: CheckEmbeddedVolInfoInMDBs 1865// 1866// Function: Check the primary and alternate MDB to see if the embedded volume 1867// information (drEmbedSigWord and drEmbedExtent) match. 1868// 1869// Result: NA 1870//****************************************************************************** 1871void CheckEmbeddedVolInfoInMDBs( SGlobPtr GPtr ) 1872{ 1873 OSErr err; 1874 Boolean primaryIsDamaged = false; 1875 Boolean alternateIsDamaged = false; 1876 VolumeObjectPtr myVOPtr; 1877 HFSMasterDirectoryBlock * myPriMDBPtr; 1878 HFSMasterDirectoryBlock * myAltMDBPtr; 1879 UInt64 myOffset; 1880 UInt64 mySectors; 1881 BlockDescriptor myPrimary; 1882 BlockDescriptor myAlternate; 1883 1884 myVOPtr = GetVolumeObjectPtr( ); 1885 myPrimary.buffer = NULL; 1886 myAlternate.buffer = NULL; 1887 1888 // we only check this if primary and alternate are OK at this point. OK means 1889 // that the primary and alternate MDBs have the correct signature and at least 1890 // one of them points to a valid embedded HFS+ volume. 1891 if ( VolumeObjectIsEmbeddedHFSPlus( ) == false || 1892 (myVOPtr->flags & kVO_PriMDBOK) == 0 || (myVOPtr->flags & kVO_AltMDBOK) == 0 ) 1893 return; 1894 1895 err = GetVolumeObjectPrimaryMDB( &myPrimary ); 1896 if ( err != noErr ) { 1897 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1898 plog( "\tcould not get primary MDB \n" ); 1899 } 1900 goto ExitThisRoutine; 1901 } 1902 myPriMDBPtr = (HFSMasterDirectoryBlock *) myPrimary.buffer; 1903 err = GetVolumeObjectAlternateMDB( &myAlternate ); 1904 if ( err != noErr ) { 1905 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) { 1906 plog( "\tcould not get alternate MDB \n" ); 1907 } 1908 goto ExitThisRoutine; 1909 } 1910 myAltMDBPtr = (HFSMasterDirectoryBlock *) myAlternate.buffer; 1911 1912 // bail if everything looks good. NOTE - we can bail if drEmbedExtent info 1913 // is the same in the primary and alternate MDB because we know one of them is 1914 // valid (or VolumeObjectIsEmbeddedHFSPlus would be false and we would not be 1915 // here). 1916 if ( myPriMDBPtr->drEmbedSigWord == kHFSPlusSigWord && 1917 myAltMDBPtr->drEmbedSigWord == kHFSPlusSigWord && 1918 myPriMDBPtr->drEmbedExtent.blockCount == myAltMDBPtr->drEmbedExtent.blockCount && 1919 myPriMDBPtr->drEmbedExtent.startBlock == myAltMDBPtr->drEmbedExtent.startBlock ) 1920 goto ExitThisRoutine; 1921 1922 // we know that VolumeObject.embeddedOffset and VolumeObject.totalEmbeddedSectors 1923 // are correct so we will verify the info in each MDB calculates to these values. 1924 myOffset = (myPriMDBPtr->drEmbedExtent.startBlock * myPriMDBPtr->drAlBlkSiz) + 1925 (myPriMDBPtr->drAlBlSt * Blk_Size); 1926 mySectors = (myPriMDBPtr->drAlBlkSiz / Blk_Size) * myPriMDBPtr->drEmbedExtent.blockCount; 1927 1928 if ( myOffset != myVOPtr->embeddedOffset || mySectors != myVOPtr->totalEmbeddedSectors ) 1929 primaryIsDamaged = true; 1930 1931 myOffset = (myAltMDBPtr->drEmbedExtent.startBlock * myAltMDBPtr->drAlBlkSiz) + 1932 (myAltMDBPtr->drAlBlSt * Blk_Size); 1933 mySectors = (myAltMDBPtr->drAlBlkSiz / Blk_Size) * myAltMDBPtr->drEmbedExtent.blockCount; 1934 1935 if ( myOffset != myVOPtr->embeddedOffset || mySectors != myVOPtr->totalEmbeddedSectors ) 1936 alternateIsDamaged = true; 1937 1938 // now check drEmbedSigWord if everything else is OK 1939 if ( primaryIsDamaged == false && alternateIsDamaged == false ) { 1940 if ( myPriMDBPtr->drEmbedSigWord != kHFSPlusSigWord ) 1941 primaryIsDamaged = true; 1942 else if ( myAltMDBPtr->drEmbedSigWord != kHFSPlusSigWord ) 1943 alternateIsDamaged = true; 1944 } 1945 1946 if ( primaryIsDamaged || alternateIsDamaged ) { 1947 GPtr->VIStat |= S_WMDB; 1948 WriteError( GPtr, E_MDBDamaged, 7, 0 ); 1949 if ( primaryIsDamaged ) { 1950 myVOPtr->flags &= ~kVO_PriMDBOK; // mark the primary MDB as damaged 1951 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) 1952 plog("\tinvalid primary wrapper MDB \n"); 1953 } 1954 else { 1955 myVOPtr->flags &= ~kVO_AltMDBOK; // mark the alternate MDB as damaged 1956 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) 1957 plog("\tinvalid alternate wrapper MDB \n"); 1958 } 1959 } 1960 1961ExitThisRoutine: 1962 if ( myPrimary.buffer != NULL ) 1963 (void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myPrimary, kReleaseBlock ); 1964 if ( myAlternate.buffer != NULL ) 1965 (void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myAlternate, kReleaseBlock ); 1966 1967 return; 1968 1969} /* CheckEmbeddedVolInfoInMDBs */ 1970 1971 1972//****************************************************************************** 1973// Routine: ValidVolumeHeader 1974// 1975// Function: Run some sanity checks to make sure the HFSPlusVolumeHeader is valid 1976// 1977// Result: error 1978//****************************************************************************** 1979OSErr ValidVolumeHeader( HFSPlusVolumeHeader *volumeHeader ) 1980{ 1981 OSErr err; 1982 1983 if ((volumeHeader->signature == kHFSPlusSigWord && volumeHeader->version == kHFSPlusVersion) || 1984 (volumeHeader->signature == kHFSXSigWord && volumeHeader->version == kHFSXVersion)) 1985 { 1986 if ( (volumeHeader->blockSize != 0) && ((volumeHeader->blockSize & 0x01FF) == 0) ) // non zero multiple of 512 1987 err = noErr; 1988 else 1989 err = badMDBErr; //�� I want badVolumeHeaderErr in Errors.i 1990 } 1991 else 1992 { 1993 err = noMacDskErr; 1994 } 1995 1996 return( err ); 1997} 1998 1999 2000//_______________________________________________________________________ 2001// 2002// InitBTreeHeader 2003// 2004// This routine initializes a B-Tree header. 2005// 2006// Note: Since large volumes will have bigger b-trees they need to 2007// have map nodes setup. 2008//_______________________________________________________________________ 2009 2010void InitBTreeHeader (UInt32 fileSize, UInt32 clumpSize, UInt16 nodeSize, UInt16 recordCount, UInt16 keySize, 2011 UInt32 attributes, UInt32 *mapNodes, void *buffer) 2012{ 2013 UInt32 nodeCount; 2014 UInt32 usedNodes; 2015 UInt32 nodeBitsInHeader; 2016 BTHeaderRec *bth; 2017 BTNodeDescriptor *ndp; 2018 UInt32 *bitMapPtr; 2019 SInt16 *offsetPtr; 2020 2021 2022 ClearMemory(buffer, nodeSize); // start out with clean node 2023 2024 nodeCount = fileSize / nodeSize; 2025 nodeBitsInHeader = 8 * (nodeSize - sizeof(BTNodeDescriptor) - sizeof(BTHeaderRec) - kBTreeHeaderUserBytes - 4*sizeof(SInt16)); 2026 2027 usedNodes = 1; // header takes up one node 2028 *mapNodes = 0; // number of map nodes initially (0) 2029 2030 2031 // FILL IN THE NODE DESCRIPTOR: 2032 ndp = (BTNodeDescriptor*) buffer; // point to node descriptor 2033 2034 ndp->kind = kBTHeaderNode; // this node contains the B-tree header 2035 ndp->numRecords = 3; // there are 3 records (header, map, and user) 2036 2037 if (nodeCount > nodeBitsInHeader) // do we need additional map nodes? 2038 { 2039 UInt32 nodeBitsInMapNode; 2040 2041 nodeBitsInMapNode = 8 * (nodeSize - sizeof(BTNodeDescriptor) - 2*sizeof(SInt16) - 2); //�� why (-2) at end??? 2042 2043 if (recordCount > 0) // catalog B-tree? 2044 ndp->fLink = 2; // link points to initial map node 2045 //�� Assumes all records will fit in one node. It would be better 2046 //�� to put the map node(s) first, then the records. 2047 else 2048 ndp->fLink = 1; // link points to initial map node 2049 2050 *mapNodes = (nodeCount - nodeBitsInHeader + (nodeBitsInMapNode - 1)) / nodeBitsInMapNode; 2051 usedNodes += *mapNodes; 2052 } 2053 2054 // FILL IN THE HEADER RECORD: 2055 bth = (BTHeaderRec*) ((char*)buffer + sizeof(BTNodeDescriptor)); // point to header 2056 2057 if (recordCount > 0) 2058 { 2059 ++usedNodes; // one more node will be used 2060 2061 bth->treeDepth = 1; // tree depth is one level (leaf) 2062 bth->rootNode = 1; // root node is also leaf 2063 bth->firstLeafNode = 1; // first leaf node 2064 bth->lastLeafNode = 1; // last leaf node 2065 } 2066 2067 bth->attributes = attributes; // flags for 16-bit key lengths, and variable sized index keys 2068 bth->leafRecords = recordCount; // total number of data records 2069 bth->nodeSize = nodeSize; // size of a node 2070 bth->maxKeyLength = keySize; // maximum length of a key 2071 bth->totalNodes = nodeCount; // total number of nodes 2072 bth->freeNodes = nodeCount - usedNodes; // number of free nodes 2073 bth->clumpSize = clumpSize; // 2074// bth->btreeType = 0; // 0 = meta data B-tree 2075 2076 2077 // FILL IN THE MAP RECORD: 2078 bitMapPtr = (UInt32*) ((Byte*) buffer + sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec) + kBTreeHeaderUserBytes); // point to bitmap 2079 2080 // MARK NODES THAT ARE IN USE: 2081 // Note - worst case (32MB alloc blk) will have only 18 nodes in use. 2082 *bitMapPtr = ~((UInt32) 0xFFFFFFFF >> usedNodes); 2083 2084 2085 // PLACE RECORD OFFSETS AT THE END OF THE NODE: 2086 offsetPtr = (SInt16*) ((Byte*) buffer + nodeSize - 4*sizeof(SInt16)); 2087 2088 *offsetPtr++ = sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec) + kBTreeHeaderUserBytes + nodeBitsInHeader/8; // offset to free space 2089 *offsetPtr++ = sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec) + kBTreeHeaderUserBytes; // offset to allocation map 2090 *offsetPtr++ = sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec); // offset to user space 2091 *offsetPtr = sizeof(BTNodeDescriptor); // offset to BTH 2092} 2093 2094/*------------------------------------------------------------------------------ 2095 2096Routine: CalculateItemCount 2097 2098Function: determines number of items for progress feedback 2099 2100Input: vRefNum: the volume to count items 2101 2102Output: number of items 2103 2104------------------------------------------------------------------------------*/ 2105 2106void CalculateItemCount( SGlob *GPtr, UInt64 *itemCount, UInt64 *onePercent ) 2107{ 2108 BTreeControlBlock *btcb; 2109 VolumeObjectPtr myVOPtr; 2110 UInt64 items; 2111 UInt32 realFreeNodes; 2112 SVCB *vcb = GPtr->calculatedVCB; 2113 2114 /* each bitmap segment is an item */ 2115 myVOPtr = GetVolumeObjectPtr( ); 2116 items = GPtr->calculatedVCB->vcbTotalBlocks / 1024; 2117 2118 // 2119 // Items is the used node count and leaf record count for each btree... 2120 // 2121 2122 btcb = (BTreeControlBlock*) vcb->vcbCatalogFile->fcbBtree; 2123 realFreeNodes = ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount; 2124 items += (2 * btcb->leafRecords) + (btcb->totalNodes - realFreeNodes); 2125 2126 btcb = (BTreeControlBlock*) vcb->vcbExtentsFile->fcbBtree; 2127 realFreeNodes = ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount; 2128 items += btcb->leafRecords + (btcb->totalNodes - realFreeNodes); 2129 2130 if ( vcb->vcbAttributesFile != NULL ) 2131 { 2132 btcb = (BTreeControlBlock*) vcb->vcbAttributesFile->fcbBtree; 2133 realFreeNodes = ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount; 2134 2135 items += (btcb->leafRecords + (btcb->totalNodes - realFreeNodes)); 2136 } 2137 2138 *onePercent = items/ 100; 2139 2140 // 2141 // [2239291] We're calculating the progress for the wrapper and the embedded volume separately, which 2142 // confuses the caller (since they see the progress jump to a large percentage while checking the wrapper, 2143 // then jump to a small percentage when starting to check the embedded volume). To avoid this behavior, 2144 // we pretend the wrapper has 100 times as many items as it really does. This means the progress will 2145 // never exceed 1% for the wrapper. 2146 // 2147/* fsck_hfs doesn't deal wih the wrapper at this time (8.29.2002) 2148 if ( (myVOPtr->volumeType == kEmbededHFSPlusVolumeType) && (GPtr->inputFlags & examineWrapperMask) ) 2149 items *= 100; */ 2150 2151 // Add en extra � 5% to smooth the progress 2152 items += *onePercent * 5; 2153 2154 *itemCount = items; 2155} 2156 2157 2158SFCB* ResolveFCB(short fileRefNum) 2159{ 2160 return( (SFCB*)((unsigned long)GetFCBSPtr() + (unsigned long)fileRefNum) ); 2161} 2162 2163 2164//****************************************************************************** 2165// Routine: SetupFCB fills in the FCB info 2166// 2167// Returns: The filled up FCB 2168//****************************************************************************** 2169void SetupFCB( SVCB *vcb, SInt16 refNum, UInt32 fileID, UInt32 fileClumpSize ) 2170{ 2171 SFCB *fcb; 2172 2173 fcb = ResolveFCB(refNum); 2174 2175 fcb->fcbFileID = fileID; 2176 fcb->fcbVolume = vcb; 2177 fcb->fcbClumpSize = fileClumpSize; 2178} 2179 2180 2181//****************************************************************************** 2182// 2183// Routine: ResolveFileRefNum 2184// 2185// Purpose: Return a file reference number for a given file control block 2186// pointer. 2187// 2188// Input: 2189// fileCtrlBlockPtr Pointer to the SFCB 2190// 2191// Output: 2192// result File reference number, 2193// or 0 if fileCtrlBlockPtr is invalid 2194// 2195pascal short ResolveFileRefNum(SFCB * fileCtrlBlockPtr) 2196{ 2197 return( (unsigned long)fileCtrlBlockPtr - (unsigned long)GetFCBSPtr() ); 2198} 2199 2200 2201 2202Ptr gFCBSPtr; 2203 2204void SetFCBSPtr( Ptr value ) 2205{ 2206 gFCBSPtr = value; 2207} 2208 2209Ptr GetFCBSPtr( void ) 2210{ 2211 return (gFCBSPtr); 2212} 2213 2214 2215//_______________________________________________________________________ 2216// 2217// Routine: FlushVolumeControlBlock 2218// Arguments: SVCB *vcb 2219// Output: OSErr err 2220// 2221// Function: Flush volume information to either the HFSPlusVolumeHeader 2222// of the Master Directory Block 2223//_______________________________________________________________________ 2224 2225OSErr FlushVolumeControlBlock( SVCB *vcb ) 2226{ 2227 OSErr err; 2228 HFSPlusVolumeHeader *volumeHeader; 2229 SFCB *fcb; 2230 BlockDescriptor block; 2231 2232 if ( ! IsVCBDirty( vcb ) ) // if it's not dirty 2233 return( noErr ); 2234 2235 block.buffer = NULL; 2236 err = GetVolumeObjectPrimaryBlock( &block ); 2237 if ( err != noErr ) 2238 { 2239 // attempt to fix the primary with alternate 2240 if ( block.buffer != NULL ) { 2241 (void) ReleaseVolumeBlock( vcb, &block, kReleaseBlock ); 2242 block.buffer = NULL; 2243 } 2244 2245 err = VolumeObjectFixPrimaryBlock( ); 2246 ReturnIfError( err ); 2247 2248 // should be able to get it now 2249 err = GetVolumeObjectPrimaryBlock( &block ); 2250 ReturnIfError( err ); 2251 } 2252 2253 if ( vcb->vcbSignature == kHFSPlusSigWord ) 2254 { 2255 volumeHeader = (HFSPlusVolumeHeader *) block.buffer; 2256 2257 // 2005507, Keep the MDB creation date and HFSPlusVolumeHeader creation date in sync. 2258 if ( vcb->vcbEmbeddedOffset != 0 ) // It's a wrapped HFS+ volume 2259 { 2260 HFSMasterDirectoryBlock *mdb; 2261 BlockDescriptor mdb_block; 2262 2263 mdb_block.buffer = NULL; 2264 err = GetVolumeObjectPrimaryMDB( &mdb_block ); 2265 if ( err == noErr ) 2266 { 2267 mdb = (HFSMasterDirectoryBlock *) mdb_block.buffer; 2268 if ( mdb->drCrDate != vcb->vcbCreateDate ) // The creation date changed 2269 { 2270 mdb->drCrDate = vcb->vcbCreateDate; 2271 (void) ReleaseVolumeBlock(vcb, &mdb_block, kForceWriteBlock); 2272 mdb_block.buffer = NULL; 2273 } 2274 } 2275 if ( mdb_block.buffer != NULL ) 2276 (void) ReleaseVolumeBlock(vcb, &mdb_block, kReleaseBlock); 2277 } 2278 2279 volumeHeader->attributes = vcb->vcbAttributes; 2280 volumeHeader->lastMountedVersion = kFSCKMountVersion; 2281 volumeHeader->createDate = vcb->vcbCreateDate; // NOTE: local time, not GMT! 2282 volumeHeader->modifyDate = vcb->vcbModifyDate; 2283 volumeHeader->backupDate = vcb->vcbBackupDate; 2284 volumeHeader->checkedDate = vcb->vcbCheckedDate; 2285 volumeHeader->fileCount = vcb->vcbFileCount; 2286 volumeHeader->folderCount = vcb->vcbFolderCount; 2287 volumeHeader->blockSize = vcb->vcbBlockSize; 2288 volumeHeader->totalBlocks = vcb->vcbTotalBlocks; 2289 volumeHeader->freeBlocks = vcb->vcbFreeBlocks; 2290 volumeHeader->nextAllocation = vcb->vcbNextAllocation; 2291 volumeHeader->rsrcClumpSize = vcb->vcbRsrcClumpSize; 2292 volumeHeader->dataClumpSize = vcb->vcbDataClumpSize; 2293 volumeHeader->nextCatalogID = vcb->vcbNextCatalogID; 2294 volumeHeader->writeCount = vcb->vcbWriteCount; 2295 volumeHeader->encodingsBitmap = vcb->vcbEncodingsBitmap; 2296 2297 //���should we use the vcb or fcb clumpSize values ????? -djb 2298 volumeHeader->allocationFile.clumpSize = vcb->vcbAllocationFile->fcbClumpSize; 2299 volumeHeader->extentsFile.clumpSize = vcb->vcbExtentsFile->fcbClumpSize; 2300 volumeHeader->catalogFile.clumpSize = vcb->vcbCatalogFile->fcbClumpSize; 2301 2302 CopyMemory( vcb->vcbFinderInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo) ); 2303 2304 fcb = vcb->vcbExtentsFile; 2305 CopyMemory( fcb->fcbExtents32, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) ); 2306 volumeHeader->extentsFile.logicalSize = fcb->fcbLogicalSize; 2307 volumeHeader->extentsFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize; 2308 2309 fcb = vcb->vcbCatalogFile; 2310 CopyMemory( fcb->fcbExtents32, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) ); 2311 volumeHeader->catalogFile.logicalSize = fcb->fcbLogicalSize; 2312 volumeHeader->catalogFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize; 2313 2314 fcb = vcb->vcbAllocationFile; 2315 CopyMemory( fcb->fcbExtents32, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) ); 2316 volumeHeader->allocationFile.logicalSize = fcb->fcbLogicalSize; 2317 volumeHeader->allocationFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize; 2318 2319 if (vcb->vcbAttributesFile != NULL) // Only update fields if an attributes file existed and was open 2320 { 2321 fcb = vcb->vcbAttributesFile; 2322 CopyMemory( fcb->fcbExtents32, volumeHeader->attributesFile.extents, sizeof(HFSPlusExtentRecord) ); 2323 volumeHeader->attributesFile.logicalSize = fcb->fcbLogicalSize; 2324 volumeHeader->attributesFile.clumpSize = fcb->fcbClumpSize; 2325 volumeHeader->attributesFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize; 2326 } 2327 } 2328 else 2329 { 2330 HFSMasterDirectoryBlock *mdbP; 2331 2332 mdbP = (HFSMasterDirectoryBlock *) block.buffer; 2333 2334 mdbP->drCrDate = vcb->vcbCreateDate; 2335 mdbP->drLsMod = vcb->vcbModifyDate; 2336 mdbP->drAtrb = (UInt16)vcb->vcbAttributes; 2337 mdbP->drClpSiz = vcb->vcbDataClumpSize; 2338 mdbP->drNxtCNID = vcb->vcbNextCatalogID; 2339 mdbP->drFreeBks = vcb->vcbFreeBlocks; 2340 mdbP->drXTClpSiz = vcb->vcbExtentsFile->fcbClumpSize; 2341 mdbP->drCTClpSiz = vcb->vcbCatalogFile->fcbClumpSize; 2342 2343 mdbP->drNmFls = vcb->vcbNmFls; 2344 mdbP->drNmRtDirs = vcb->vcbNmRtDirs; 2345 mdbP->drFilCnt = vcb->vcbFileCount; 2346 mdbP->drDirCnt = vcb->vcbFolderCount; 2347 2348 fcb = vcb->vcbExtentsFile; 2349 CopyMemory( fcb->fcbExtents16, mdbP->drXTExtRec, sizeof( mdbP->drXTExtRec ) ); 2350 2351 fcb = vcb->vcbCatalogFile; 2352 CopyMemory( fcb->fcbExtents16, mdbP->drCTExtRec, sizeof( mdbP->drCTExtRec ) ); 2353 } 2354 2355 //-- Write the VHB/MDB out by releasing the block dirty 2356 if ( block.buffer != NULL ) { 2357 err = ReleaseVolumeBlock(vcb, &block, kForceWriteBlock); 2358 block.buffer = NULL; 2359 } 2360 MarkVCBClean( vcb ); 2361 2362 return( err ); 2363} 2364 2365 2366//_______________________________________________________________________ 2367// 2368// Routine: FlushAlternateVolumeControlBlock 2369// Arguments: SVCB *vcb 2370// Boolean ifHFSPlus 2371// Output: OSErr err 2372// 2373// Function: Flush volume information to either the Alternate HFSPlusVolumeHeader or the 2374// Alternate Master Directory Block. Called by the BTree when the catalog 2375// or extent files grow. Simply BlockMoves the original to the alternate 2376// location. 2377//_______________________________________________________________________ 2378 2379OSErr FlushAlternateVolumeControlBlock( SVCB *vcb, Boolean isHFSPlus ) 2380{ 2381 OSErr err; 2382 VolumeObjectPtr myVOPtr; 2383 UInt64 myBlockNum; 2384 BlockDescriptor pri_block, alt_block; 2385 2386 pri_block.buffer = NULL; 2387 alt_block.buffer = NULL; 2388 myVOPtr = GetVolumeObjectPtr( ); 2389 2390 err = FlushVolumeControlBlock( vcb ); 2391 err = GetVolumeObjectPrimaryBlock( &pri_block ); 2392 2393 // invalidate if we have not marked the primary as OK 2394 if ( VolumeObjectIsHFS( ) ) { 2395 if ( (myVOPtr->flags & kVO_PriMDBOK) == 0 ) 2396 err = badMDBErr; 2397 } 2398 else if ( (myVOPtr->flags & kVO_PriVHBOK) == 0 ) { 2399 err = badMDBErr; 2400 } 2401 if ( err != noErr ) 2402 goto ExitThisRoutine; 2403 2404 GetVolumeObjectAlternateBlockNum( &myBlockNum ); 2405 if ( myBlockNum != 0 ) { 2406 // we don't care if this is an invalid MDB / VHB since we will write over it 2407 err = GetVolumeObjectAlternateBlock( &alt_block ); 2408 if ( err == noErr || err == badMDBErr || err == noMacDskErr ) { 2409 CopyMemory( pri_block.buffer, alt_block.buffer, Blk_Size ); 2410 (void) ReleaseVolumeBlock(vcb, &alt_block, kForceWriteBlock); 2411 alt_block.buffer = NULL; 2412 } 2413 } 2414 2415ExitThisRoutine: 2416 if ( pri_block.buffer != NULL ) 2417 (void) ReleaseVolumeBlock( vcb, &pri_block, kReleaseBlock ); 2418 if ( alt_block.buffer != NULL ) 2419 (void) ReleaseVolumeBlock( vcb, &alt_block, kReleaseBlock ); 2420 2421 return( err ); 2422} 2423 2424void 2425ConvertToHFSPlusExtent( const HFSExtentRecord oldExtents, HFSPlusExtentRecord newExtents) 2426{ 2427 UInt16 i; 2428 2429 // go backwards so we can convert in place! 2430 2431 for (i = kHFSPlusExtentDensity-1; i > 2; --i) 2432 { 2433 newExtents[i].blockCount = 0; 2434 newExtents[i].startBlock = 0; 2435 } 2436 2437 newExtents[2].blockCount = oldExtents[2].blockCount; 2438 newExtents[2].startBlock = oldExtents[2].startBlock; 2439 newExtents[1].blockCount = oldExtents[1].blockCount; 2440 newExtents[1].startBlock = oldExtents[1].startBlock; 2441 newExtents[0].blockCount = oldExtents[0].blockCount; 2442 newExtents[0].startBlock = oldExtents[0].startBlock; 2443} 2444 2445 2446 2447OSErr CacheWriteInPlace( SVCB *vcb, UInt32 fileRefNum, HIOParam *iopb, UInt64 currentPosition, UInt32 maximumBytes, UInt32 *actualBytes ) 2448{ 2449 OSErr err; 2450 UInt64 diskBlock; 2451 UInt32 contiguousBytes; 2452 void* buffer; 2453 2454 *actualBytes = 0; 2455 buffer = (char*)iopb->ioBuffer + iopb->ioActCount; 2456 2457 err = MapFileBlockC(vcb, ResolveFCB(fileRefNum), maximumBytes, (currentPosition >> kSectorShift), 2458 &diskBlock, &contiguousBytes ); 2459 if (err) 2460 return (err); 2461 2462 err = DeviceWrite(vcb->vcbDriverWriteRef, vcb->vcbDriveNumber, buffer, (diskBlock << Log2BlkLo), contiguousBytes, actualBytes); 2463 2464 return( err ); 2465} 2466 2467 2468void PrintName( int theCount, const UInt8 *theNamePtr, Boolean isUnicodeString ) 2469{ 2470 int myCount; 2471 int i; 2472 2473 myCount = (isUnicodeString) ? (theCount * 2) : theCount; 2474 for ( i = 0; i < myCount; i++ ) 2475 plog( "%02X ", *(theNamePtr + i) ); 2476 plog( "\n" ); 2477 2478} /* PrintName */ 2479 2480/* Function: add_prime_bucket_uint32 2481 * 2482 * Description: 2483 * This function increments the prime number buckets in the prime bucket 2484 * set based on the uint32_t number provided. This function increments 2485 * each prime number bucket by one at an offset of the corresponding 2486 * remainder of the division. This function is based on Chinese Remainder 2487 * Theorem and adds the given number to the set to compare later. 2488 * 2489 * Input: 2490 * 1. Corresponding prime bucket to increment. 2491 * 2. uint32_t number to add to the set. 2492 * 2493 * Output: nil 2494 */ 2495void add_prime_bucket_uint32(PrimeBuckets *cur, uint32_t num) 2496{ 2497 int r32, r27, r25, r7, r11, r13, r17, r19, r23, r29, r31; 2498 2499 if (!cur) { 2500 return; 2501 } 2502 2503 /* Perform the necessary divisions here */ 2504 r32 = num % 32; 2505 r27 = num % 27; 2506 r25 = num % 25; 2507 r7 = num % 7; 2508 r11 = num % 11; 2509 r13 = num % 13; 2510 r17 = num % 17; 2511 r19 = num % 19; 2512 r23 = num % 23; 2513 r29 = num % 29; 2514 r31 = num % 31; 2515 2516 /* Update bucket for attribute bit */ 2517 cur->n32[r32]++; 2518 cur->n27[r27]++; 2519 cur->n25[r25]++; 2520 cur->n7[r7]++; 2521 cur->n11[r11]++; 2522 cur->n13[r13]++; 2523 cur->n17[r17]++; 2524 cur->n19[r19]++; 2525 cur->n23[r23]++; 2526 cur->n29[r29]++; 2527 cur->n31[r31]++; 2528 2529 return; 2530} 2531 2532/* Function: add_prime_bucket_uint64 2533 * 2534 * Description: 2535 * This function increments the prime number buckets in the prime bucket 2536 * set based on the uint64_t number provided. This function increments 2537 * each prime number bucket by one at an offset of the corresponding 2538 * remainder of the division. This function is based on Chinese Remainder 2539 * Theorem and adds the given number to the set to compare later. 2540 * 2541 * Input: 2542 * 1. Corresponding prime bucket to increment. 2543 * 2. uint64_t number to add to the set. 2544 * 2545 * Output: nil 2546 */ 2547void add_prime_bucket_uint64(PrimeBuckets *cur, uint64_t num) 2548{ 2549 size_t r32, r27, r25, r7, r11, r13, r17, r19, r23, r29, r31; 2550 2551 if (!cur) { 2552 return; 2553 } 2554 2555 /* Perform the necessary divisions here */ 2556 r32 = num % 32; 2557 r27 = num % 27; 2558 r25 = num % 25; 2559 r7 = num % 7; 2560 r11 = num % 11; 2561 r13 = num % 13; 2562 r17 = num % 17; 2563 r19 = num % 19; 2564 r23 = num % 23; 2565 r29 = num % 29; 2566 r31 = num % 31; 2567 2568 /* Update bucket for attribute bit */ 2569 cur->n32[r32]++; 2570 cur->n27[r27]++; 2571 cur->n25[r25]++; 2572 cur->n7[r7]++; 2573 cur->n11[r11]++; 2574 cur->n13[r13]++; 2575 cur->n17[r17]++; 2576 cur->n19[r19]++; 2577 cur->n23[r23]++; 2578 cur->n29[r29]++; 2579 cur->n31[r31]++; 2580 2581 return; 2582} 2583 2584/* Compares the two prime buckets provided. 2585 * Returns - 2586 * zero - If the two buckets are same. 2587 * non-zero - If the two buckets do not match. 2588 */ 2589int compare_prime_buckets(PrimeBuckets *bucket1, PrimeBuckets *bucket2) 2590{ 2591 int retval = 1; 2592 int i; 2593 2594 for (i=0; i<32; i++) { 2595 if (bucket1->n32[i] != bucket2->n32[i]) { 2596 goto out; 2597 } 2598 } 2599 2600 for (i=0; i<27; i++) { 2601 if (bucket1->n27[i] != bucket2->n27[i]) { 2602 goto out; 2603 } 2604 } 2605 2606 for (i=0; i<25; i++) { 2607 if (bucket1->n25[i] != bucket2->n25[i]) { 2608 goto out; 2609 } 2610 } 2611 2612 for (i=0; i<7; i++) { 2613 if (bucket1->n7[i] != bucket2->n7[i]) { 2614 goto out; 2615 } 2616 } 2617 2618 for (i=0; i<11; i++) { 2619 if (bucket1->n11[i] != bucket2->n11[i]) { 2620 goto out; 2621 } 2622 } 2623 2624 for (i=0; i<13; i++) { 2625 if (bucket1->n13[i] != bucket2->n13[i]) { 2626 goto out; 2627 } 2628 } 2629 2630 for (i=0; i<17; i++) { 2631 if (bucket1->n17[i] != bucket2->n17[i]) { 2632 goto out; 2633 } 2634 } 2635 2636 for (i=0; i<19; i++) { 2637 if (bucket1->n19[i] != bucket2->n19[i]) { 2638 goto out; 2639 } 2640 } 2641 2642 for (i=0; i<23; i++) { 2643 if (bucket1->n23[i] != bucket2->n23[i]) { 2644 goto out; 2645 } 2646 } 2647 2648 for (i=0; i<29; i++) { 2649 if (bucket1->n29[i] != bucket2->n29[i]) { 2650 goto out; 2651 } 2652 } 2653 2654 for (i=0; i<31; i++) { 2655 if (bucket1->n31[i] != bucket2->n31[i]) { 2656 goto out; 2657 } 2658 } 2659 2660 retval = 0; 2661 2662out: 2663 return retval; 2664} 2665 2666/* Prints the prime number bucket for the passed pointer */ 2667void print_prime_buckets(PrimeBuckets *cur) 2668{ 2669 int i; 2670 2671 plog ("n32 = { "); 2672 for (i=0; i<32; i++) { 2673 plog ("%d,", cur->n32[i]); 2674 } 2675 plog ("}\n"); 2676 2677 plog ("n27 = { "); 2678 for (i=0; i<27; i++) { 2679 plog ("%d,", cur->n27[i]); 2680 } 2681 plog ("}\n"); 2682 2683 plog ("n25 = { "); 2684 for (i=0; i<25; i++) { 2685 plog ("%d,", cur->n25[i]); 2686 } 2687 plog ("}\n"); 2688 2689 plog ("n7 = { "); 2690 for (i=0; i<7; i++) { 2691 plog ("%d,", cur->n7[i]); 2692 } 2693 plog ("}\n"); 2694 2695 plog ("n11 = { "); 2696 for (i=0; i<11; i++) { 2697 plog ("%d,", cur->n11[i]); 2698 } 2699 plog ("}\n"); 2700 2701 plog ("n13 = { "); 2702 for (i=0; i<13; i++) { 2703 plog ("%d,", cur->n13[i]); 2704 } 2705 plog ("}\n"); 2706 2707 plog ("n17 = { "); 2708 for (i=0; i<17; i++) { 2709 plog ("%d,", cur->n17[i]); 2710 } 2711 plog ("}\n"); 2712 2713 plog ("n19 = { "); 2714 for (i=0; i<19; i++) { 2715 plog ("%d,", cur->n19[i]); 2716 } 2717 plog ("}\n"); 2718 2719 plog ("n23 = { "); 2720 for (i=0; i<23; i++) { 2721 plog ("%d,", cur->n23[i]); 2722 } 2723 plog ("}\n"); 2724 2725 plog ("n29 = { "); 2726 for (i=0; i<29; i++) { 2727 plog ("%d,", cur->n29[i]); 2728 } 2729 plog ("}\n"); 2730 2731 plog ("n31 = { "); 2732 for (i=0; i<31; i++) { 2733 plog ("%d,", cur->n31[i]); 2734 } 2735 plog ("}\n"); 2736} 2737