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