~ubuntu-branches/ubuntu/maverick/hfsprogs/maverick

« back to all changes in this revision

Viewing changes to .pc/10-linux_specific_code.patch/fsck_hfs.tproj/dfalib/SUtils.c

  • Committer: Bazaar Package Importer
  • Author(s): Rogério Brito
  • Date: 2010-01-31 07:01:54 UTC
  • mfrom: (5.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20100131070154-tn5dfg5fjiejd6hn
Tags: 332.25-8
* Use a FTBFS bug revealed by the kfreebsd-* ports.
  This was reported by Cyril Brulebois, and patched by: Petr Salinger.
  Closes: #566916
* Remove b-dep on kfreebsd-kernel-headers, as it is build-essential.

Show diffs side-by-side

added added

removed removed

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