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