]> git.saurik.com Git - apple/hfs.git/blob - fsck_hfs/dfalib/SUtils.c
hfs-522.0.9.tar.gz
[apple/hfs.git] / fsck_hfs / dfalib / SUtils.c
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
35 static void CompareVolHeaderBTreeSizes( SGlobPtr GPtr,
36 VolumeObjectPtr theVOPtr,
37 HFSPlusVolumeHeader * thePriVHPtr,
38 HFSPlusVolumeHeader * theAltVHPtr );
39 static void GetEmbeddedVolumeHeaders( SGlobPtr GPtr,
40 HFSMasterDirectoryBlock * myMDBPtr,
41 Boolean isPrimaryMDB );
42 static OSErr GetVolumeObjectBlock( VolumeObjectPtr theVOPtr,
43 UInt64 theBlockNum,
44 BlockDescriptor * theBlockDescPtr );
45 static OSErr VolumeObjectFixPrimaryBlock( void );
46
47 /*
48 * utf_encodestr
49 *
50 * Encode a UCS-2 (Unicode) string to UTF-8
51 */
52 int 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 */
105 int
106 utf_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
171 OSErr GetFBlk( SGlobPtr GPtr, SInt16 fileRefNum, SInt32 blockNumber, void **bufferH );
172
173
174 UInt32 gDFAStage;
175
176 UInt32 GetDFAStage( void )
177 {
178 return (gDFAStage);
179 }
180
181 void SetDFAStage( UInt32 stage )
182 {
183 gDFAStage = stage;
184 }
185
186
187 /*------------------------------------------------------------------------------
188
189 Routine: RcdError
190
191 Function: Record errors detetected by scavenging operation.
192
193 Input: GPtr - pointer to scavenger global area.
194 ErrCode - error code
195
196 Output: None
197 ------------------------------------------------------------------------------*/
198
199 void 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
209 Routine: IntError
210
211 Function: Records an internal Scavenger error.
212
213 Input: GPtr - pointer to scavenger global area.
214 ErrCode - internal error code
215
216 Output: IntError - function result:
217 (E_IntErr for now)
218 ------------------------------------------------------------------------------*/
219
220 int 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
246 Routine: AllocBTN (Allocate BTree Node)
247
248 Function: Allocates an BTree node in a Scavenger BTree bit map.
249
250 Input: GPtr - pointer to scavenger global area.
251 StABN - starting allocation block number.
252 NmABlks - number of allocation blocks.
253
254 Output: AllocBTN - function result:
255 0 = no error
256 n = error
257 ------------------------------------------------------------------------------*/
258
259 int 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
285 OSErr 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
341 Routine: IsDuplicateRepairOrder
342
343 Function: 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
349 Input: GPtr - scavenger globals
350 orig - repair order to search and compare
351
352 Output: 0 - no duplicate was found,
353 1 - duplicate was found.
354 ------------------------------------------------------------------------------*/
355 int 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
383 Routine: DeleteRepairOrder
384
385 Function: 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
389 Input: GPtr - scavenger globals
390 orig - repair order to remove
391
392 Output: Nothing
393 ------------------------------------------------------------------------------*/
394 void 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
420 Routine: Alloc[Minor/Major]RepairOrder
421
422 Function: 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
426 Input: GPtr - scavenger globals
427 n - number of extra bytes needed, in addition to standard node size.
428
429 Output: Ptr to node, or NULL if out of memory or other error.
430 ------------------------------------------------------------------------------*/
431
432 RepairOrderPtr 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
456 void 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
475 OSErr 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 /*-------------------------------------------------------------------------------
516 Routine: ClearMemory - clear a block of memory
517
518 -------------------------------------------------------------------------------*/
519 #if !BSD
520 void 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
638 void
639 CopyCatalogName(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
662 UInt32
663 CatalogNameLength(const CatalogName *name, Boolean isHFSPlus)
664 {
665 if (isHFSPlus)
666 return name->ustr.length;
667 else
668 return name->pstr[0];
669 }
670
671
672 UInt32 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
692 void
693 BuildCatalogKey(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
723 SInt32 CompareKeys( BTreeControlBlockPtr btreePtr, KeyPtr searchKey, KeyPtr trialKey )
724 {
725 KeyCompareProcPtr compareProc = (KeyCompareProcPtr)btreePtr->keyCompareProc;
726
727 return( compareProc(searchKey, trialKey) );
728 }
729
730
731 void
732 UpdateCatalogName(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
745 void
746 UpdateVolumeEncodings(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
772 static 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
816 ExitThisRoutine:
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 //******************************************************************************
837 OSErr 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 //******************************************************************************
877 OSErr 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 //******************************************************************************
917 OSErr 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 //******************************************************************************
961 OSErr 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 //******************************************************************************
986 OSErr 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 //******************************************************************************
1014 OSErr 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 //******************************************************************************
1042 static 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 //******************************************************************************
1070 void 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 //******************************************************************************
1107 void 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 //******************************************************************************
1136 void 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 //******************************************************************************
1174 void 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
1309 ExitRoutine:
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 //******************************************************************************
1339 void 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
1380 static 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
1497 ExitRoutine:
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 //******************************************************************************
1514 static 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
1597 enum { WIDTH = 16, };
1598
1599 void
1600 DumpData(const void *data, size_t len, char *label)
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 if (label == NULL) {
1633 fprintf(stderr, "%04x: ", (int)(cp - base));
1634 }
1635 else {
1636 fprintf(stderr, "%s %04x: ", label, (int)(cp - base));
1637 }
1638 for (i = 0, tmp = cp; tmp < tend; tmp++) {
1639 fprintf(stderr, "%02x", *tmp);
1640 if (++i % 2 == 0)
1641 fprintf(stderr, " ");
1642 if (*tmp)
1643 allzeroes = 0;
1644 }
1645 for (i = gap; i >= 0; i--) {
1646 fprintf(stderr, " ");
1647 if (i % 2 == 1)
1648 fprintf(stderr, " ");
1649 }
1650 fprintf(stderr, " |");
1651 for (tmp = cp; tmp < tend; tmp++) {
1652 fprintf(stderr, "%c", isalnum(*tmp) ? *tmp : '.');
1653 }
1654 for (i = 0; i < gap; i++) {
1655 fprintf(stderr, " ");
1656 }
1657 fprintf(stderr, "|\n");
1658 cp += WIDTH;
1659 }
1660
1661 return;
1662
1663 }
1664 //******************************************************************************
1665 // Routine: VolumeObjectIsValid
1666 //
1667 // Function: determine if the volume represented by our VolumeObject is a
1668 // valid volume type (i.e. not unknown type)
1669 //
1670 // Result: returns true if volume is known volume type (i.e. HFS, HFS+)
1671 // false otherwise.
1672 //******************************************************************************
1673 Boolean VolumeObjectIsValid(SGlobPtr gptr)
1674 {
1675 VolumeObjectPtr myVOPtr = GetVolumeObjectPtr();
1676 Boolean retval = false;
1677
1678 /* Check if the type is unknown type */
1679 if (myVOPtr->volumeType == kUnknownVolumeType) {
1680 pwarn("volumeType is %d\n", kUnknownVolumeType);
1681 goto done;
1682 }
1683
1684 /* Check if it is HFS+ volume */
1685 if (VolumeObjectIsHFSPlus() == true) {
1686 retval = true;
1687 goto done;
1688 }
1689
1690 /* Check if it is HFS volume */
1691 if (VolumeObjectIsHFS() == true) {
1692 retval = true;
1693 goto done;
1694 }
1695
1696 done:
1697 /*
1698 * This code should be removed after debugging is done.
1699 */
1700 if (retval == false) {
1701 UInt64 myBlockNum;
1702 VolumeObjectPtr myVOPtr;
1703 BlockDescriptor theBlockDesc;
1704 OSErr err;
1705
1706 myVOPtr = GetVolumeObjectPtr();
1707 GetVolumeObjectBlockNum(&myBlockNum);
1708 err = GetVolumeBlock(myVOPtr->vcbPtr, myBlockNum, kGetBlock, &theBlockDesc);
1709 if (err != noErr) {
1710 fprintf(stderr, "%s: Cannot GetVolumeBlock: %d\n", __FUNCTION__, err);
1711 } else {
1712 uint8_t *ptr = (uint8_t*)theBlockDesc.buffer;
1713 DumpData(ptr, theBlockDesc.blockSize, gptr->deviceNode);
1714 ReleaseVolumeBlock(myVOPtr->vcbPtr, &theBlockDesc, kReleaseBlock);
1715 }
1716 }
1717 return retval;
1718 } /* VolumeObjectIsValid */
1719
1720 //******************************************************************************
1721 // Routine: VolumeObjectIsHFSPlus
1722 //
1723 // Function: determine if the volume represented by our VolumeObject is an
1724 // HFS+ volume (pure or embedded).
1725 //
1726 // Result: returns true if volume is pure HFS+ or embedded HFS+ else false.
1727 //******************************************************************************
1728 Boolean VolumeObjectIsHFSPlus( void )
1729 {
1730 VolumeObjectPtr myVOPtr;
1731
1732 myVOPtr = GetVolumeObjectPtr( );
1733
1734 if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType ||
1735 myVOPtr->volumeType == kPureHFSPlusVolumeType ) {
1736 return( true );
1737 }
1738
1739 return( false );
1740
1741 } /* VolumeObjectIsHFSPlus */
1742
1743
1744 //******************************************************************************
1745 // Routine: VolumeObjectIsHFSX
1746 //
1747 // Function: determine if the volume represented by our VolumeObject is an
1748 // HFSX volume (pure or embedded)
1749 //
1750 // Result: returns true if volume is pure HFSX or embedded HFSX else false.
1751 //******************************************************************************
1752
1753 Boolean VolumeObjectIsHFSX(SGlobPtr GPtr)
1754 {
1755 OSErr err;
1756 int result = false;
1757 HFSMasterDirectoryBlock *mdbp;
1758 SVCB *vcb = GPtr->calculatedVCB;
1759 BlockDescriptor block;
1760
1761 #define kIDSector 2
1762 err = GetVolumeBlock(vcb, kIDSector, kGetBlock, &block);
1763 if (err) return (false);
1764
1765 mdbp = (HFSMasterDirectoryBlock *)block.buffer;
1766 if (mdbp->drSigWord == kHFSXSigWord) {
1767 result = true;
1768 } else if (mdbp->drSigWord == kHFSSigWord) {
1769 if (mdbp->drEmbedSigWord == kHFSXSigWord) {
1770 result = true;
1771 }
1772 }
1773
1774 (void) ReleaseVolumeBlock(vcb, &block, kReleaseBlock);
1775
1776 return( result );
1777 } /* VolumeObjectIsHFSX */
1778
1779 //******************************************************************************
1780 // Routine: VolumeObjectIsHFS
1781 //
1782 // Function: determine if the volume represented by our VolumeObject is an
1783 // HFS (standard) volume.
1784 //
1785 // Result: returns true if HFS (standard) volume.
1786 //******************************************************************************
1787 Boolean VolumeObjectIsHFS( void )
1788 {
1789 VolumeObjectPtr myVOPtr;
1790
1791 myVOPtr = GetVolumeObjectPtr( );
1792
1793 if ( myVOPtr->volumeType == kHFSVolumeType )
1794 return( true );
1795
1796 return( false );
1797
1798 } /* VolumeObjectIsHFS */
1799
1800
1801 //******************************************************************************
1802 // Routine: VolumeObjectIsEmbeddedHFSPlus
1803 //
1804 // Function: determine if the volume represented by our VolumeObject is an
1805 // embedded HFS plus volume.
1806 //
1807 // Result: returns true if embedded HFS plus volume.
1808 //******************************************************************************
1809 Boolean VolumeObjectIsEmbeddedHFSPlus( void )
1810 {
1811 VolumeObjectPtr myVOPtr;
1812
1813 myVOPtr = GetVolumeObjectPtr( );
1814
1815 if ( myVOPtr->volumeType == kEmbededHFSPlusVolumeType )
1816 return( true );
1817
1818 return( false );
1819
1820 } /* VolumeObjectIsEmbeddedHFSPlus */
1821
1822
1823 //******************************************************************************
1824 // Routine: VolumeObjectIsPureHFSPlus
1825 //
1826 // Function: determine if the volume represented by our VolumeObject is an
1827 // pure HFS plus volume.
1828 //
1829 // Result: returns true if pure HFS plus volume.
1830 //******************************************************************************
1831 Boolean VolumeObjectIsPureHFSPlus( void )
1832 {
1833 VolumeObjectPtr myVOPtr;
1834
1835 myVOPtr = GetVolumeObjectPtr( );
1836
1837 if ( myVOPtr->volumeType == kPureHFSPlusVolumeType )
1838 return( true );
1839
1840 return( false );
1841
1842 } /* VolumeObjectIsPureHFSPlus */
1843
1844
1845 //******************************************************************************
1846 // Routine: GetVolumeObjectPtr
1847 //
1848 // Function: Accessor routine to get a pointer to our VolumeObject structure.
1849 //
1850 // Result: returns pointer to our VolumeObject.
1851 //******************************************************************************
1852 VolumeObjectPtr GetVolumeObjectPtr( void )
1853 {
1854 static VolumeObject myVolumeObject;
1855 static int myInited = 0;
1856
1857 if ( myInited == 0 ) {
1858 myInited++;
1859 bzero( &myVolumeObject, sizeof(myVolumeObject) );
1860 }
1861
1862 return( &myVolumeObject );
1863
1864 } /* GetVolumeObjectPtr */
1865
1866
1867 //******************************************************************************
1868 // Routine: CheckEmbeddedVolInfoInMDBs
1869 //
1870 // Function: Check the primary and alternate MDB to see if the embedded volume
1871 // information (drEmbedSigWord and drEmbedExtent) match.
1872 //
1873 // Result: NA
1874 //******************************************************************************
1875 void CheckEmbeddedVolInfoInMDBs( SGlobPtr GPtr )
1876 {
1877 OSErr err;
1878 Boolean primaryIsDamaged = false;
1879 Boolean alternateIsDamaged = false;
1880 VolumeObjectPtr myVOPtr;
1881 HFSMasterDirectoryBlock * myPriMDBPtr;
1882 HFSMasterDirectoryBlock * myAltMDBPtr;
1883 UInt64 myOffset;
1884 UInt64 mySectors;
1885 BlockDescriptor myPrimary;
1886 BlockDescriptor myAlternate;
1887
1888 myVOPtr = GetVolumeObjectPtr( );
1889 myPrimary.buffer = NULL;
1890 myAlternate.buffer = NULL;
1891
1892 // we only check this if primary and alternate are OK at this point. OK means
1893 // that the primary and alternate MDBs have the correct signature and at least
1894 // one of them points to a valid embedded HFS+ volume.
1895 if ( VolumeObjectIsEmbeddedHFSPlus( ) == false ||
1896 (myVOPtr->flags & kVO_PriMDBOK) == 0 || (myVOPtr->flags & kVO_AltMDBOK) == 0 )
1897 return;
1898
1899 err = GetVolumeObjectPrimaryMDB( &myPrimary );
1900 if ( err != noErr ) {
1901 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) {
1902 plog( "\tcould not get primary MDB \n" );
1903 }
1904 goto ExitThisRoutine;
1905 }
1906 myPriMDBPtr = (HFSMasterDirectoryBlock *) myPrimary.buffer;
1907 err = GetVolumeObjectAlternateMDB( &myAlternate );
1908 if ( err != noErr ) {
1909 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog ) {
1910 plog( "\tcould not get alternate MDB \n" );
1911 }
1912 goto ExitThisRoutine;
1913 }
1914 myAltMDBPtr = (HFSMasterDirectoryBlock *) myAlternate.buffer;
1915
1916 // bail if everything looks good. NOTE - we can bail if drEmbedExtent info
1917 // is the same in the primary and alternate MDB because we know one of them is
1918 // valid (or VolumeObjectIsEmbeddedHFSPlus would be false and we would not be
1919 // here).
1920 if ( myPriMDBPtr->drEmbedSigWord == kHFSPlusSigWord &&
1921 myAltMDBPtr->drEmbedSigWord == kHFSPlusSigWord &&
1922 myPriMDBPtr->drEmbedExtent.blockCount == myAltMDBPtr->drEmbedExtent.blockCount &&
1923 myPriMDBPtr->drEmbedExtent.startBlock == myAltMDBPtr->drEmbedExtent.startBlock )
1924 goto ExitThisRoutine;
1925
1926 // we know that VolumeObject.embeddedOffset and VolumeObject.totalEmbeddedSectors
1927 // are correct so we will verify the info in each MDB calculates to these values.
1928 myOffset = (myPriMDBPtr->drEmbedExtent.startBlock * myPriMDBPtr->drAlBlkSiz) +
1929 (myPriMDBPtr->drAlBlSt * Blk_Size);
1930 mySectors = (myPriMDBPtr->drAlBlkSiz / Blk_Size) * myPriMDBPtr->drEmbedExtent.blockCount;
1931
1932 if ( myOffset != myVOPtr->embeddedOffset || mySectors != myVOPtr->totalEmbeddedSectors )
1933 primaryIsDamaged = true;
1934
1935 myOffset = (myAltMDBPtr->drEmbedExtent.startBlock * myAltMDBPtr->drAlBlkSiz) +
1936 (myAltMDBPtr->drAlBlSt * Blk_Size);
1937 mySectors = (myAltMDBPtr->drAlBlkSiz / Blk_Size) * myAltMDBPtr->drEmbedExtent.blockCount;
1938
1939 if ( myOffset != myVOPtr->embeddedOffset || mySectors != myVOPtr->totalEmbeddedSectors )
1940 alternateIsDamaged = true;
1941
1942 // now check drEmbedSigWord if everything else is OK
1943 if ( primaryIsDamaged == false && alternateIsDamaged == false ) {
1944 if ( myPriMDBPtr->drEmbedSigWord != kHFSPlusSigWord )
1945 primaryIsDamaged = true;
1946 else if ( myAltMDBPtr->drEmbedSigWord != kHFSPlusSigWord )
1947 alternateIsDamaged = true;
1948 }
1949
1950 if ( primaryIsDamaged || alternateIsDamaged ) {
1951 GPtr->VIStat |= S_WMDB;
1952 WriteError( GPtr, E_MDBDamaged, 7, 0 );
1953 if ( primaryIsDamaged ) {
1954 myVOPtr->flags &= ~kVO_PriMDBOK; // mark the primary MDB as damaged
1955 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog )
1956 plog("\tinvalid primary wrapper MDB \n");
1957 }
1958 else {
1959 myVOPtr->flags &= ~kVO_AltMDBOK; // mark the alternate MDB as damaged
1960 if ( fsckGetVerbosity(GPtr->context) >= kDebugLog )
1961 plog("\tinvalid alternate wrapper MDB \n");
1962 }
1963 }
1964
1965 ExitThisRoutine:
1966 if ( myPrimary.buffer != NULL )
1967 (void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myPrimary, kReleaseBlock );
1968 if ( myAlternate.buffer != NULL )
1969 (void) ReleaseVolumeBlock( myVOPtr->vcbPtr, &myAlternate, kReleaseBlock );
1970
1971 return;
1972
1973 } /* CheckEmbeddedVolInfoInMDBs */
1974
1975
1976 //******************************************************************************
1977 // Routine: ValidVolumeHeader
1978 //
1979 // Function: Run some sanity checks to make sure the HFSPlusVolumeHeader is valid
1980 //
1981 // Result: error
1982 //******************************************************************************
1983 OSErr ValidVolumeHeader( HFSPlusVolumeHeader *volumeHeader )
1984 {
1985 OSErr err;
1986
1987 if ((volumeHeader->signature == kHFSPlusSigWord && volumeHeader->version == kHFSPlusVersion) ||
1988 (volumeHeader->signature == kHFSXSigWord && volumeHeader->version == kHFSXVersion))
1989 {
1990 if ( (volumeHeader->blockSize != 0) && ((volumeHeader->blockSize & 0x01FF) == 0) ) // non zero multiple of 512
1991 err = noErr;
1992 else
1993 err = badMDBErr; //¥¥ I want badVolumeHeaderErr in Errors.i
1994 }
1995 else
1996 {
1997 err = noMacDskErr;
1998 }
1999
2000 return( err );
2001 }
2002
2003
2004 //_______________________________________________________________________
2005 //
2006 // InitBTreeHeader
2007 //
2008 // This routine initializes a B-Tree header.
2009 //
2010 // Note: Since large volumes will have bigger b-trees they need to
2011 // have map nodes setup.
2012 //_______________________________________________________________________
2013
2014 void InitBTreeHeader (UInt32 fileSize, UInt32 clumpSize, UInt16 nodeSize, UInt16 recordCount, UInt16 keySize,
2015 UInt32 attributes, UInt32 *mapNodes, void *buffer)
2016 {
2017 UInt32 nodeCount;
2018 UInt32 usedNodes;
2019 UInt32 nodeBitsInHeader;
2020 BTHeaderRec *bth;
2021 BTNodeDescriptor *ndp;
2022 UInt32 *bitMapPtr;
2023 SInt16 *offsetPtr;
2024
2025
2026 ClearMemory(buffer, nodeSize); // start out with clean node
2027
2028 nodeCount = fileSize / nodeSize;
2029 nodeBitsInHeader = 8 * (nodeSize - sizeof(BTNodeDescriptor) - sizeof(BTHeaderRec) - kBTreeHeaderUserBytes - 4*sizeof(SInt16));
2030
2031 usedNodes = 1; // header takes up one node
2032 *mapNodes = 0; // number of map nodes initially (0)
2033
2034
2035 // FILL IN THE NODE DESCRIPTOR:
2036 ndp = (BTNodeDescriptor*) buffer; // point to node descriptor
2037
2038 ndp->kind = kBTHeaderNode; // this node contains the B-tree header
2039 ndp->numRecords = 3; // there are 3 records (header, map, and user)
2040
2041 if (nodeCount > nodeBitsInHeader) // do we need additional map nodes?
2042 {
2043 UInt32 nodeBitsInMapNode;
2044
2045 nodeBitsInMapNode = 8 * (nodeSize - sizeof(BTNodeDescriptor) - 2*sizeof(SInt16) - 2); //¥¥ why (-2) at end???
2046
2047 if (recordCount > 0) // catalog B-tree?
2048 ndp->fLink = 2; // link points to initial map node
2049 //¥¥ Assumes all records will fit in one node. It would be better
2050 //¥¥ to put the map node(s) first, then the records.
2051 else
2052 ndp->fLink = 1; // link points to initial map node
2053
2054 *mapNodes = (nodeCount - nodeBitsInHeader + (nodeBitsInMapNode - 1)) / nodeBitsInMapNode;
2055 usedNodes += *mapNodes;
2056 }
2057
2058 // FILL IN THE HEADER RECORD:
2059 bth = (BTHeaderRec*) ((char*)buffer + sizeof(BTNodeDescriptor)); // point to header
2060
2061 if (recordCount > 0)
2062 {
2063 ++usedNodes; // one more node will be used
2064
2065 bth->treeDepth = 1; // tree depth is one level (leaf)
2066 bth->rootNode = 1; // root node is also leaf
2067 bth->firstLeafNode = 1; // first leaf node
2068 bth->lastLeafNode = 1; // last leaf node
2069 }
2070
2071 bth->attributes = attributes; // flags for 16-bit key lengths, and variable sized index keys
2072 bth->leafRecords = recordCount; // total number of data records
2073 bth->nodeSize = nodeSize; // size of a node
2074 bth->maxKeyLength = keySize; // maximum length of a key
2075 bth->totalNodes = nodeCount; // total number of nodes
2076 bth->freeNodes = nodeCount - usedNodes; // number of free nodes
2077 bth->clumpSize = clumpSize; //
2078 // bth->btreeType = 0; // 0 = meta data B-tree
2079
2080
2081 // FILL IN THE MAP RECORD:
2082 bitMapPtr = (UInt32*) ((Byte*) buffer + sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec) + kBTreeHeaderUserBytes); // point to bitmap
2083
2084 // MARK NODES THAT ARE IN USE:
2085 // Note - worst case (32MB alloc blk) will have only 18 nodes in use.
2086 *bitMapPtr = ~((UInt32) 0xFFFFFFFF >> usedNodes);
2087
2088
2089 // PLACE RECORD OFFSETS AT THE END OF THE NODE:
2090 offsetPtr = (SInt16*) ((Byte*) buffer + nodeSize - 4*sizeof(SInt16));
2091
2092 *offsetPtr++ = sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec) + kBTreeHeaderUserBytes + nodeBitsInHeader/8; // offset to free space
2093 *offsetPtr++ = sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec) + kBTreeHeaderUserBytes; // offset to allocation map
2094 *offsetPtr++ = sizeof(BTNodeDescriptor) + sizeof(BTHeaderRec); // offset to user space
2095 *offsetPtr = sizeof(BTNodeDescriptor); // offset to BTH
2096 }
2097
2098 /*------------------------------------------------------------------------------
2099
2100 Routine: CalculateItemCount
2101
2102 Function: determines number of items for progress feedback
2103
2104 Input: vRefNum: the volume to count items
2105
2106 Output: number of items
2107
2108 ------------------------------------------------------------------------------*/
2109
2110 void CalculateItemCount( SGlob *GPtr, UInt64 *itemCount, UInt64 *onePercent )
2111 {
2112 BTreeControlBlock *btcb;
2113 VolumeObjectPtr myVOPtr;
2114 UInt64 items;
2115 UInt32 realFreeNodes;
2116 SVCB *vcb = GPtr->calculatedVCB;
2117
2118 /* each bitmap segment is an item */
2119 myVOPtr = GetVolumeObjectPtr( );
2120 items = GPtr->calculatedVCB->vcbTotalBlocks / 1024;
2121
2122 //
2123 // Items is the used node count and leaf record count for each btree...
2124 //
2125
2126 btcb = (BTreeControlBlock*) vcb->vcbCatalogFile->fcbBtree;
2127 realFreeNodes = ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount;
2128 items += (2 * btcb->leafRecords) + (btcb->totalNodes - realFreeNodes);
2129
2130 btcb = (BTreeControlBlock*) vcb->vcbExtentsFile->fcbBtree;
2131 realFreeNodes = ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount;
2132 items += btcb->leafRecords + (btcb->totalNodes - realFreeNodes);
2133
2134 if ( vcb->vcbAttributesFile != NULL )
2135 {
2136 btcb = (BTreeControlBlock*) vcb->vcbAttributesFile->fcbBtree;
2137 realFreeNodes = ((BTreeExtensionsRec*)btcb->refCon)->realFreeNodeCount;
2138
2139 items += (btcb->leafRecords + (btcb->totalNodes - realFreeNodes));
2140 }
2141
2142 *onePercent = items/ 100;
2143
2144 //
2145 // [2239291] We're calculating the progress for the wrapper and the embedded volume separately, which
2146 // confuses the caller (since they see the progress jump to a large percentage while checking the wrapper,
2147 // then jump to a small percentage when starting to check the embedded volume). To avoid this behavior,
2148 // we pretend the wrapper has 100 times as many items as it really does. This means the progress will
2149 // never exceed 1% for the wrapper.
2150 //
2151 /* fsck_hfs doesn't deal wih the wrapper at this time (8.29.2002)
2152 if ( (myVOPtr->volumeType == kEmbededHFSPlusVolumeType) && (GPtr->inputFlags & examineWrapperMask) )
2153 items *= 100; */
2154
2155 // Add en extra Å 5% to smooth the progress
2156 items += *onePercent * 5;
2157
2158 *itemCount = items;
2159 }
2160
2161
2162 SFCB* ResolveFCB(short fileRefNum)
2163 {
2164 return( (SFCB*)((unsigned long)GetFCBSPtr() + (unsigned long)fileRefNum) );
2165 }
2166
2167
2168 //******************************************************************************
2169 // Routine: SetupFCB fills in the FCB info
2170 //
2171 // Returns: The filled up FCB
2172 //******************************************************************************
2173 void SetupFCB( SVCB *vcb, SInt16 refNum, UInt32 fileID, UInt32 fileClumpSize )
2174 {
2175 SFCB *fcb;
2176
2177 fcb = ResolveFCB(refNum);
2178
2179 fcb->fcbFileID = fileID;
2180 fcb->fcbVolume = vcb;
2181 fcb->fcbClumpSize = fileClumpSize;
2182 }
2183
2184
2185 //******************************************************************************
2186 //
2187 // Routine: ResolveFileRefNum
2188 //
2189 // Purpose: Return a file reference number for a given file control block
2190 // pointer.
2191 //
2192 // Input:
2193 // fileCtrlBlockPtr Pointer to the SFCB
2194 //
2195 // Output:
2196 // result File reference number,
2197 // or 0 if fileCtrlBlockPtr is invalid
2198 //
2199 pascal short ResolveFileRefNum(SFCB * fileCtrlBlockPtr)
2200 {
2201 return( (unsigned long)fileCtrlBlockPtr - (unsigned long)GetFCBSPtr() );
2202 }
2203
2204
2205
2206 Ptr gFCBSPtr;
2207
2208 void SetFCBSPtr( Ptr value )
2209 {
2210 gFCBSPtr = value;
2211 }
2212
2213 Ptr GetFCBSPtr( void )
2214 {
2215 return (gFCBSPtr);
2216 }
2217
2218
2219 //_______________________________________________________________________
2220 //
2221 // Routine: FlushVolumeControlBlock
2222 // Arguments: SVCB *vcb
2223 // Output: OSErr err
2224 //
2225 // Function: Flush volume information to either the HFSPlusVolumeHeader
2226 // of the Master Directory Block
2227 //_______________________________________________________________________
2228
2229 OSErr FlushVolumeControlBlock( SVCB *vcb )
2230 {
2231 OSErr err;
2232 HFSPlusVolumeHeader *volumeHeader;
2233 SFCB *fcb;
2234 BlockDescriptor block;
2235
2236 if ( ! IsVCBDirty( vcb ) ) // if it's not dirty
2237 return( noErr );
2238
2239 block.buffer = NULL;
2240 err = GetVolumeObjectPrimaryBlock( &block );
2241 if ( err != noErr )
2242 {
2243 // attempt to fix the primary with alternate
2244 if ( block.buffer != NULL ) {
2245 (void) ReleaseVolumeBlock( vcb, &block, kReleaseBlock );
2246 block.buffer = NULL;
2247 }
2248
2249 err = VolumeObjectFixPrimaryBlock( );
2250 ReturnIfError( err );
2251
2252 // should be able to get it now
2253 err = GetVolumeObjectPrimaryBlock( &block );
2254 ReturnIfError( err );
2255 }
2256
2257 if ( vcb->vcbSignature == kHFSPlusSigWord )
2258 {
2259 volumeHeader = (HFSPlusVolumeHeader *) block.buffer;
2260
2261 // 2005507, Keep the MDB creation date and HFSPlusVolumeHeader creation date in sync.
2262 if ( vcb->vcbEmbeddedOffset != 0 ) // It's a wrapped HFS+ volume
2263 {
2264 HFSMasterDirectoryBlock *mdb;
2265 BlockDescriptor mdb_block;
2266
2267 mdb_block.buffer = NULL;
2268 err = GetVolumeObjectPrimaryMDB( &mdb_block );
2269 if ( err == noErr )
2270 {
2271 mdb = (HFSMasterDirectoryBlock *) mdb_block.buffer;
2272 if ( mdb->drCrDate != vcb->vcbCreateDate ) // The creation date changed
2273 {
2274 mdb->drCrDate = vcb->vcbCreateDate;
2275 (void) ReleaseVolumeBlock(vcb, &mdb_block, kForceWriteBlock);
2276 mdb_block.buffer = NULL;
2277 }
2278 }
2279 if ( mdb_block.buffer != NULL )
2280 (void) ReleaseVolumeBlock(vcb, &mdb_block, kReleaseBlock);
2281 }
2282
2283 volumeHeader->attributes = vcb->vcbAttributes;
2284 volumeHeader->lastMountedVersion = kFSCKMountVersion;
2285 volumeHeader->createDate = vcb->vcbCreateDate; // NOTE: local time, not GMT!
2286 volumeHeader->modifyDate = vcb->vcbModifyDate;
2287 volumeHeader->backupDate = vcb->vcbBackupDate;
2288 volumeHeader->checkedDate = vcb->vcbCheckedDate;
2289 volumeHeader->fileCount = vcb->vcbFileCount;
2290 volumeHeader->folderCount = vcb->vcbFolderCount;
2291 volumeHeader->blockSize = vcb->vcbBlockSize;
2292 volumeHeader->totalBlocks = vcb->vcbTotalBlocks;
2293 volumeHeader->freeBlocks = vcb->vcbFreeBlocks;
2294 volumeHeader->nextAllocation = vcb->vcbNextAllocation;
2295 volumeHeader->rsrcClumpSize = vcb->vcbRsrcClumpSize;
2296 volumeHeader->dataClumpSize = vcb->vcbDataClumpSize;
2297 volumeHeader->nextCatalogID = vcb->vcbNextCatalogID;
2298 volumeHeader->writeCount = vcb->vcbWriteCount;
2299 volumeHeader->encodingsBitmap = vcb->vcbEncodingsBitmap;
2300
2301 //¥¥Êshould we use the vcb or fcb clumpSize values ????? -djb
2302 volumeHeader->allocationFile.clumpSize = vcb->vcbAllocationFile->fcbClumpSize;
2303 volumeHeader->extentsFile.clumpSize = vcb->vcbExtentsFile->fcbClumpSize;
2304 volumeHeader->catalogFile.clumpSize = vcb->vcbCatalogFile->fcbClumpSize;
2305
2306 CopyMemory( vcb->vcbFinderInfo, volumeHeader->finderInfo, sizeof(volumeHeader->finderInfo) );
2307
2308 fcb = vcb->vcbExtentsFile;
2309 CopyMemory( fcb->fcbExtents32, volumeHeader->extentsFile.extents, sizeof(HFSPlusExtentRecord) );
2310 volumeHeader->extentsFile.logicalSize = fcb->fcbLogicalSize;
2311 volumeHeader->extentsFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize;
2312
2313 fcb = vcb->vcbCatalogFile;
2314 CopyMemory( fcb->fcbExtents32, volumeHeader->catalogFile.extents, sizeof(HFSPlusExtentRecord) );
2315 volumeHeader->catalogFile.logicalSize = fcb->fcbLogicalSize;
2316 volumeHeader->catalogFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize;
2317
2318 fcb = vcb->vcbAllocationFile;
2319 CopyMemory( fcb->fcbExtents32, volumeHeader->allocationFile.extents, sizeof(HFSPlusExtentRecord) );
2320 volumeHeader->allocationFile.logicalSize = fcb->fcbLogicalSize;
2321 volumeHeader->allocationFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize;
2322
2323 if (vcb->vcbAttributesFile != NULL) // Only update fields if an attributes file existed and was open
2324 {
2325 fcb = vcb->vcbAttributesFile;
2326 CopyMemory( fcb->fcbExtents32, volumeHeader->attributesFile.extents, sizeof(HFSPlusExtentRecord) );
2327 volumeHeader->attributesFile.logicalSize = fcb->fcbLogicalSize;
2328 volumeHeader->attributesFile.clumpSize = fcb->fcbClumpSize;
2329 volumeHeader->attributesFile.totalBlocks = fcb->fcbPhysicalSize / vcb->vcbBlockSize;
2330 }
2331 }
2332 else
2333 {
2334 HFSMasterDirectoryBlock *mdbP;
2335
2336 mdbP = (HFSMasterDirectoryBlock *) block.buffer;
2337
2338 mdbP->drCrDate = vcb->vcbCreateDate;
2339 mdbP->drLsMod = vcb->vcbModifyDate;
2340 mdbP->drAtrb = (UInt16)vcb->vcbAttributes;
2341 mdbP->drClpSiz = vcb->vcbDataClumpSize;
2342 mdbP->drNxtCNID = vcb->vcbNextCatalogID;
2343 mdbP->drFreeBks = vcb->vcbFreeBlocks;
2344 mdbP->drXTClpSiz = vcb->vcbExtentsFile->fcbClumpSize;
2345 mdbP->drCTClpSiz = vcb->vcbCatalogFile->fcbClumpSize;
2346
2347 mdbP->drNmFls = vcb->vcbNmFls;
2348 mdbP->drNmRtDirs = vcb->vcbNmRtDirs;
2349 mdbP->drFilCnt = vcb->vcbFileCount;
2350 mdbP->drDirCnt = vcb->vcbFolderCount;
2351
2352 fcb = vcb->vcbExtentsFile;
2353 CopyMemory( fcb->fcbExtents16, mdbP->drXTExtRec, sizeof( mdbP->drXTExtRec ) );
2354
2355 fcb = vcb->vcbCatalogFile;
2356 CopyMemory( fcb->fcbExtents16, mdbP->drCTExtRec, sizeof( mdbP->drCTExtRec ) );
2357 }
2358
2359 //-- Write the VHB/MDB out by releasing the block dirty
2360 if ( block.buffer != NULL ) {
2361 err = ReleaseVolumeBlock(vcb, &block, kForceWriteBlock);
2362 block.buffer = NULL;
2363 }
2364 MarkVCBClean( vcb );
2365
2366 return( err );
2367 }
2368
2369
2370 //_______________________________________________________________________
2371 //
2372 // Routine: FlushAlternateVolumeControlBlock
2373 // Arguments: SVCB *vcb
2374 // Boolean ifHFSPlus
2375 // Output: OSErr err
2376 //
2377 // Function: Flush volume information to either the Alternate HFSPlusVolumeHeader or the
2378 // Alternate Master Directory Block. Called by the BTree when the catalog
2379 // or extent files grow. Simply BlockMoves the original to the alternate
2380 // location.
2381 //_______________________________________________________________________
2382
2383 OSErr FlushAlternateVolumeControlBlock( SVCB *vcb, Boolean isHFSPlus )
2384 {
2385 OSErr err;
2386 VolumeObjectPtr myVOPtr;
2387 UInt64 myBlockNum;
2388 BlockDescriptor pri_block, alt_block;
2389
2390 pri_block.buffer = NULL;
2391 alt_block.buffer = NULL;
2392 myVOPtr = GetVolumeObjectPtr( );
2393
2394 err = FlushVolumeControlBlock( vcb );
2395 err = GetVolumeObjectPrimaryBlock( &pri_block );
2396
2397 // invalidate if we have not marked the primary as OK
2398 if ( VolumeObjectIsHFS( ) ) {
2399 if ( (myVOPtr->flags & kVO_PriMDBOK) == 0 )
2400 err = badMDBErr;
2401 }
2402 else if ( (myVOPtr->flags & kVO_PriVHBOK) == 0 ) {
2403 err = badMDBErr;
2404 }
2405 if ( err != noErr )
2406 goto ExitThisRoutine;
2407
2408 GetVolumeObjectAlternateBlockNum( &myBlockNum );
2409 if ( myBlockNum != 0 ) {
2410 // we don't care if this is an invalid MDB / VHB since we will write over it
2411 err = GetVolumeObjectAlternateBlock( &alt_block );
2412 if ( err == noErr || err == badMDBErr || err == noMacDskErr ) {
2413 CopyMemory( pri_block.buffer, alt_block.buffer, Blk_Size );
2414 (void) ReleaseVolumeBlock(vcb, &alt_block, kForceWriteBlock);
2415 alt_block.buffer = NULL;
2416 }
2417 }
2418
2419 ExitThisRoutine:
2420 if ( pri_block.buffer != NULL )
2421 (void) ReleaseVolumeBlock( vcb, &pri_block, kReleaseBlock );
2422 if ( alt_block.buffer != NULL )
2423 (void) ReleaseVolumeBlock( vcb, &alt_block, kReleaseBlock );
2424
2425 return( err );
2426 }
2427
2428 void
2429 ConvertToHFSPlusExtent( const HFSExtentRecord oldExtents, HFSPlusExtentRecord newExtents)
2430 {
2431 UInt16 i;
2432
2433 // go backwards so we can convert in place!
2434
2435 for (i = kHFSPlusExtentDensity-1; i > 2; --i)
2436 {
2437 newExtents[i].blockCount = 0;
2438 newExtents[i].startBlock = 0;
2439 }
2440
2441 newExtents[2].blockCount = oldExtents[2].blockCount;
2442 newExtents[2].startBlock = oldExtents[2].startBlock;
2443 newExtents[1].blockCount = oldExtents[1].blockCount;
2444 newExtents[1].startBlock = oldExtents[1].startBlock;
2445 newExtents[0].blockCount = oldExtents[0].blockCount;
2446 newExtents[0].startBlock = oldExtents[0].startBlock;
2447 }
2448
2449
2450
2451 OSErr CacheWriteInPlace( SVCB *vcb, UInt32 fileRefNum, HIOParam *iopb, UInt64 currentPosition, UInt32 maximumBytes, UInt32 *actualBytes )
2452 {
2453 OSErr err;
2454 UInt64 diskBlock;
2455 UInt32 contiguousBytes;
2456 void* buffer;
2457
2458 *actualBytes = 0;
2459 buffer = (char*)iopb->ioBuffer + iopb->ioActCount;
2460
2461 err = MapFileBlockC(vcb, ResolveFCB(fileRefNum), maximumBytes, (currentPosition >> kSectorShift),
2462 &diskBlock, &contiguousBytes );
2463 if (err)
2464 return (err);
2465
2466 err = DeviceWrite(vcb->vcbDriverWriteRef, vcb->vcbDriveNumber, buffer, (diskBlock << Log2BlkLo), contiguousBytes, actualBytes);
2467
2468 return( err );
2469 }
2470
2471
2472 void PrintName( int theCount, const UInt8 *theNamePtr, Boolean isUnicodeString )
2473 {
2474 int myCount;
2475 int i;
2476
2477 myCount = (isUnicodeString) ? (theCount * 2) : theCount;
2478 for ( i = 0; i < myCount; i++ )
2479 plog( "%02X ", *(theNamePtr + i) );
2480 plog( "\n" );
2481
2482 } /* PrintName */
2483
2484 /* Function: add_prime_bucket_uint32
2485 *
2486 * Description:
2487 * This function increments the prime number buckets in the prime bucket
2488 * set based on the uint32_t number provided. This function increments
2489 * each prime number bucket by one at an offset of the corresponding
2490 * remainder of the division. This function is based on Chinese Remainder
2491 * Theorem and adds the given number to the set to compare later.
2492 *
2493 * Input:
2494 * 1. Corresponding prime bucket to increment.
2495 * 2. uint32_t number to add to the set.
2496 *
2497 * Output: nil
2498 */
2499 void add_prime_bucket_uint32(PrimeBuckets *cur, uint32_t num)
2500 {
2501 int r32, r27, r25, r7, r11, r13, r17, r19, r23, r29, r31;
2502
2503 if (!cur) {
2504 return;
2505 }
2506
2507 /* Perform the necessary divisions here */
2508 r32 = num % 32;
2509 r27 = num % 27;
2510 r25 = num % 25;
2511 r7 = num % 7;
2512 r11 = num % 11;
2513 r13 = num % 13;
2514 r17 = num % 17;
2515 r19 = num % 19;
2516 r23 = num % 23;
2517 r29 = num % 29;
2518 r31 = num % 31;
2519
2520 /* Update bucket for attribute bit */
2521 cur->n32[r32]++;
2522 cur->n27[r27]++;
2523 cur->n25[r25]++;
2524 cur->n7[r7]++;
2525 cur->n11[r11]++;
2526 cur->n13[r13]++;
2527 cur->n17[r17]++;
2528 cur->n19[r19]++;
2529 cur->n23[r23]++;
2530 cur->n29[r29]++;
2531 cur->n31[r31]++;
2532
2533 return;
2534 }
2535
2536 /* Function: add_prime_bucket_uint64
2537 *
2538 * Description:
2539 * This function increments the prime number buckets in the prime bucket
2540 * set based on the uint64_t number provided. This function increments
2541 * each prime number bucket by one at an offset of the corresponding
2542 * remainder of the division. This function is based on Chinese Remainder
2543 * Theorem and adds the given number to the set to compare later.
2544 *
2545 * Input:
2546 * 1. Corresponding prime bucket to increment.
2547 * 2. uint64_t number to add to the set.
2548 *
2549 * Output: nil
2550 */
2551 void add_prime_bucket_uint64(PrimeBuckets *cur, uint64_t num)
2552 {
2553 size_t r32, r27, r25, r7, r11, r13, r17, r19, r23, r29, r31;
2554
2555 if (!cur) {
2556 return;
2557 }
2558
2559 /* Perform the necessary divisions here */
2560 r32 = num % 32;
2561 r27 = num % 27;
2562 r25 = num % 25;
2563 r7 = num % 7;
2564 r11 = num % 11;
2565 r13 = num % 13;
2566 r17 = num % 17;
2567 r19 = num % 19;
2568 r23 = num % 23;
2569 r29 = num % 29;
2570 r31 = num % 31;
2571
2572 /* Update bucket for attribute bit */
2573 cur->n32[r32]++;
2574 cur->n27[r27]++;
2575 cur->n25[r25]++;
2576 cur->n7[r7]++;
2577 cur->n11[r11]++;
2578 cur->n13[r13]++;
2579 cur->n17[r17]++;
2580 cur->n19[r19]++;
2581 cur->n23[r23]++;
2582 cur->n29[r29]++;
2583 cur->n31[r31]++;
2584
2585 return;
2586 }
2587
2588 /* Compares the two prime buckets provided.
2589 * Returns -
2590 * zero - If the two buckets are same.
2591 * non-zero - If the two buckets do not match.
2592 */
2593 int compare_prime_buckets(PrimeBuckets *bucket1, PrimeBuckets *bucket2)
2594 {
2595 int retval = 1;
2596 int i;
2597
2598 for (i=0; i<32; i++) {
2599 if (bucket1->n32[i] != bucket2->n32[i]) {
2600 goto out;
2601 }
2602 }
2603
2604 for (i=0; i<27; i++) {
2605 if (bucket1->n27[i] != bucket2->n27[i]) {
2606 goto out;
2607 }
2608 }
2609
2610 for (i=0; i<25; i++) {
2611 if (bucket1->n25[i] != bucket2->n25[i]) {
2612 goto out;
2613 }
2614 }
2615
2616 for (i=0; i<7; i++) {
2617 if (bucket1->n7[i] != bucket2->n7[i]) {
2618 goto out;
2619 }
2620 }
2621
2622 for (i=0; i<11; i++) {
2623 if (bucket1->n11[i] != bucket2->n11[i]) {
2624 goto out;
2625 }
2626 }
2627
2628 for (i=0; i<13; i++) {
2629 if (bucket1->n13[i] != bucket2->n13[i]) {
2630 goto out;
2631 }
2632 }
2633
2634 for (i=0; i<17; i++) {
2635 if (bucket1->n17[i] != bucket2->n17[i]) {
2636 goto out;
2637 }
2638 }
2639
2640 for (i=0; i<19; i++) {
2641 if (bucket1->n19[i] != bucket2->n19[i]) {
2642 goto out;
2643 }
2644 }
2645
2646 for (i=0; i<23; i++) {
2647 if (bucket1->n23[i] != bucket2->n23[i]) {
2648 goto out;
2649 }
2650 }
2651
2652 for (i=0; i<29; i++) {
2653 if (bucket1->n29[i] != bucket2->n29[i]) {
2654 goto out;
2655 }
2656 }
2657
2658 for (i=0; i<31; i++) {
2659 if (bucket1->n31[i] != bucket2->n31[i]) {
2660 goto out;
2661 }
2662 }
2663
2664 retval = 0;
2665
2666 out:
2667 return retval;
2668 }
2669
2670 /* Prints the prime number bucket for the passed pointer */
2671 void print_prime_buckets(PrimeBuckets *cur)
2672 {
2673 int i;
2674
2675 plog ("n32 = { ");
2676 for (i=0; i<32; i++) {
2677 plog ("%d,", cur->n32[i]);
2678 }
2679 plog ("}\n");
2680
2681 plog ("n27 = { ");
2682 for (i=0; i<27; i++) {
2683 plog ("%d,", cur->n27[i]);
2684 }
2685 plog ("}\n");
2686
2687 plog ("n25 = { ");
2688 for (i=0; i<25; i++) {
2689 plog ("%d,", cur->n25[i]);
2690 }
2691 plog ("}\n");
2692
2693 plog ("n7 = { ");
2694 for (i=0; i<7; i++) {
2695 plog ("%d,", cur->n7[i]);
2696 }
2697 plog ("}\n");
2698
2699 plog ("n11 = { ");
2700 for (i=0; i<11; i++) {
2701 plog ("%d,", cur->n11[i]);
2702 }
2703 plog ("}\n");
2704
2705 plog ("n13 = { ");
2706 for (i=0; i<13; i++) {
2707 plog ("%d,", cur->n13[i]);
2708 }
2709 plog ("}\n");
2710
2711 plog ("n17 = { ");
2712 for (i=0; i<17; i++) {
2713 plog ("%d,", cur->n17[i]);
2714 }
2715 plog ("}\n");
2716
2717 plog ("n19 = { ");
2718 for (i=0; i<19; i++) {
2719 plog ("%d,", cur->n19[i]);
2720 }
2721 plog ("}\n");
2722
2723 plog ("n23 = { ");
2724 for (i=0; i<23; i++) {
2725 plog ("%d,", cur->n23[i]);
2726 }
2727 plog ("}\n");
2728
2729 plog ("n29 = { ");
2730 for (i=0; i<29; i++) {
2731 plog ("%d,", cur->n29[i]);
2732 }
2733 plog ("}\n");
2734
2735 plog ("n31 = { ");
2736 for (i=0; i<31; i++) {
2737 plog ("%d,", cur->n31[i]);
2738 }
2739 plog ("}\n");
2740 }