|
|
1.1 root 1: /*
2: * Copyright (c) 1999 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.1 (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: /*
26: File: BTreeWrapper.c
27:
28: Contains: Interface glue for new B-tree manager.
29:
30: Version: HFS Plus 1.0
31:
32: Copyright: � 1996-1998 by Apple Computer, Inc., all rights reserved.
33:
34: File Ownership:
35:
36: DRI: Don Brady
37:
38: Other Contact: Mark Day
39:
40: Technology: xxx put technology here xxx
41:
42: Writers:
43:
44: (msd) Mark Day
45: (DSH) Deric Horn
46: (djb) Don Brady
47:
48: Change History (most recent first):
49: <Rhap> 8/10/98 djb Removed all references to btcb global iterator (lastIterator).
50: <Rhap> 04/02/98 djb GetBTreeRecord is only used for MacOS builds.
51: <Rhap> 03/31/98 djb Sync up with final HFSVolumes.h header file.
52: <CS18> 9/4/97 msd Fix ValidHFSRecord to determine the type of B-tree by FileID,
53: not record size. Add better checking for attribute b-tree keys.
54: <CS17> 8/22/97 djb Get blockReadFromDisk flag from GetCacheBlock call.
55: <CS16> 8/14/97 djb Remove reserved field checks in ValidHFSRecord (radar #1649593).
56: Only call if ValidHFSRecord DEBUG_BUILD is true.
57: <CS15> 8/11/97 djb Bug 1670441. In SetEndOfForkProc, don't DebugStr if the disk is
58: full.
59: <CS14> 7/25/97 DSH Pass heuristicHint to BTSearchRecord from SearchBTreeRecord.
60: <CS13> 7/24/97 djb CallBackProcs now take a file refNum instead of an FCB.
61: GetBlockProc now reports if block came from disk.
62: <CS12> 7/22/97 djb Move all trace points to BTree.c file.
63: <CS11> 7/21/97 djb LogEndTime now takes an error code.
64: <CS10> 7/16/97 DSH FilesInternal.x -> FileMgrInternal.x to avoid name collision
65: <CS9> 7/15/97 msd Bug #1664103. OpenBTree is not propagating errors from
66: BTOpenPath.
67: <CS8> 7/9/97 djb Remove maxCNID check from ValidHFSRecord (radar #1649593).
68: <CS7> 6/13/97 djb In ValidHFSRecord HFSPlus threads names can be > 31 chars.
69: <CS6> 6/2/97 DSH Also flush AlternateVolumeHeader whenever Attributes or Startup
70: files change size.
71: <CS5> 5/28/97 msd In ValidHFSRecord, check for attribute keys.
72: <CS4> 5/19/97 djb Move summary traces from GetBTreeRecord to BTIterateRecord.
73: <CS3> 5/9/97 djb Get in sync with new FilesInternal.i.
74: <CS2> 5/7/97 djb Add summary traces to B-tree SPI.
75: <CS1> 4/24/97 djb first checked in
76: <HFS18> 4/16/97 djb Always use new B-tree code.
77: <HFS17> 4/4/97 djb Remove clumpSize test from ValidHFSRecord.
78: <HFS16> 4/4/97 djb Get in sync with volume format changes.
79: <HFS15> 3/17/97 DSH Casting for SC, BlockProcs are now not static.
80: <HFS14> 3/3/97 djb Call trash block after closing btree!
81: <HFS13> 2/19/97 djb Add support for accessing bigger B-tree nodes.
82: <HFS12> 2/6/97 msd In CheckBTreeKey, remove test and DebugStr for parent ID being
83: too big.
84: <HFS11> 1/23/97 DSH SetEndOfForkProc now calls through to update the Alternate MDB
85: or VolumeHeader.
86: <HFS10> 1/16/97 djb Switched to dynamic lengths for BufferDescriptor length field in
87: SearchBTreeRecord and GetBTreeRecord. Round up to clump size in
88: SetEndOfForkProc.
89: <HFS9> 1/15/97 djb Don't return errors for bad file ids in key.
90: <HFS8> 1/13/97 djb Adding support for getting current record. ValidHFSRecord now
91: supports variable sized thread records.
92: <HFS7> 1/9/97 djb Call CheckBTreeKey before using key length in a BlockMoveData
93: call.
94: <HFS6> 1/6/97 djb Implement SetEndOfForkProc.
95: <HFS5> 1/6/97 djb Added HFS Plus support to CheckBTreeKey and ValidHFSRecord.
96: <HFS4> 1/3/97 djb Added support for large keys. Integrated latest HFSVolumesPriv.h
97: changes.
98: <HFS3> 12/23/96 djb Fixed problem in SearchBTreeRecord (dataSize is an output so it
99: was undefined). Added some debugging code.
100: <HFS2> 12/20/96 msd Fix OpenBTree to use the real data type for the key compare proc
101: pointer (not void *). Fixed problem in SearchBTreeRecord that
102: assigns a pointer to a buffer size field (forgot to dereference
103: the pointer).
104: <HFS1> 12/19/96 djb first checked in
105:
106: */
107:
108: #include "../headers/FileMgrInternal.h"
109:
110: #include "../headers/BTreesInternal.h"
111: #include "../headers/BTreesPrivate.h"
112:
113:
114:
115:
116: // B-tree callbacks...
117: #if TARGET_OS_MAC
118: OSStatus GetBlockProc ( FileReference fileRefNum, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block );
119: OSStatus ReleaseBlockProc ( FileReference fileRefNum, BlockDescPtr blockPtr, ReleaseBlockOptions options );
120: OSStatus SetBlockSizeProc ( FileReference fileRefNum, ByteCount blockSize, ItemCount minBlockCount );
121: #endif
122:
123:
124: // local routines
125: static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb);
126: static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, UInt16 recordSize);
127:
128:
129: #if TARGET_OS_MAC
130: OSErr OpenBTree(FileReference refNum, KeyCompareProcPtr keyCompareProc)
131: {
132: FCB *fcb;
133: OSStatus result;
134:
135:
136: fcb = GetFileControlBlock(refNum);
137:
138: result = BTOpenPath (fcb, keyCompareProc, GetBlockProc, ReleaseBlockProc, SetEndOfForkProc, SetBlockSizeProc);
139: ExitOnError(result);
140:
141: ErrorExit:
142:
143: return result;
144: }
145: #endif /* TARGET_OS_MAC */
146:
147:
148: #if TARGET_OS_MAC
149: OSErr CloseBTree(FileReference refNum)
150: {
151: OSErr result;
152:
153:
154: result = BTClosePath ( GetFileControlBlock(refNum) );
155: ExitOnError(result);
156:
157: TrashCacheBlocks (refNum);
158:
159: ErrorExit:
160:
161: return result;
162: }
163: #endif
164:
165:
166: #if TARGET_OS_MAC
167: OSErr FlushBTree(FileReference refNum)
168: {
169: OSErr result;
170:
171:
172: result = BTFlushPath( GetFileControlBlock(refNum) );
173:
174: return result;
175: }
176: #endif
177:
178:
179: OSErr SearchBTreeRecord(FileReference refNum, const void* key, UInt32 hint, void* foundKey, void* data, UInt16 *dataSize, UInt32 *newHint)
180: {
181: FSBufferDescriptor btRecord;
182: BTreeIterator searchIterator;
183: FCB *fcb;
184: BTreeControlBlock *btcb;
185: OSStatus result;
186:
187:
188: fcb = GetFileControlBlock(refNum);
189: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
190:
191: btRecord.bufferAddress = data;
192: btRecord.itemCount = 1;
193: if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength )
194: btRecord.itemSize = sizeof(HFSExtentRecord);
195: else if ( btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength )
196: btRecord.itemSize = sizeof(HFSPlusExtentRecord);
197: else
198: btRecord.itemSize = sizeof(CatalogRecord);
199:
200: searchIterator.hint.writeCount = 0; // clear these out for debugging...
201: searchIterator.hint.reserved1 = 0;
202: searchIterator.hint.reserved2 = 0;
203:
204: searchIterator.hint.nodeNum = hint;
205: searchIterator.hint.index = 0;
206:
207: result = CheckBTreeKey((BTreeKey *) key, btcb);
208: ExitOnError(result);
209:
210: BlockMoveData(key, &searchIterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen?
211:
212: // We only optimize for catalog records
213: if( btRecord.itemSize == sizeof(CatalogRecord) )
214: {
215: UInt32 heuristicHint;
216: UInt32 *cachedHint;
217: Ptr hintCachePtr = fcb->fcbVPtr->hintCachePtr;
218:
219: // We pass a 2nd hint/guess into BTSearchRecord. The heuristicHint is a mapping of
220: // dirID and nodeNumber, in hopes that the current search will be in the same node
221: // as the last search with the same parentID.
222: result = GetMRUCacheBlock( ((HFSCatalogKey *)key)->parentID, hintCachePtr, (Ptr *)&cachedHint );
223: heuristicHint = (result == noErr) ? *cachedHint : kInvalidMRUCacheKey;
224:
225: result = BTSearchRecord( fcb, &searchIterator, heuristicHint, &btRecord, dataSize, &searchIterator );
226:
227: InsertMRUCacheBlock( hintCachePtr, ((HFSCatalogKey *)key)->parentID, (Ptr) &(searchIterator.hint.nodeNum) );
228: }
229: else
230: {
231: result = BTSearchRecord( fcb, &searchIterator, kInvalidMRUCacheKey, &btRecord, dataSize, &searchIterator );
232: }
233:
234: if (result == noErr)
235: {
236: *newHint = searchIterator.hint.nodeNum;
237:
238: result = CheckBTreeKey(&searchIterator.key, btcb);
239: ExitOnError(result);
240:
241: BlockMoveData(&searchIterator.key, foundKey, CalcKeySize(btcb, &searchIterator.key)); //�� warning, this could overflow user's buffer!!!
242:
243: if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, *dataSize) )
244: DebugStr("\pSearchBTreeRecord: bad record?");
245: }
246:
247: ErrorExit:
248:
249: return result;
250: }
251:
252:
253:
254: // Note
255: // The new B-tree manager differs from the original b-tree in how it does iteration. We need
256: // to account for these differences here. We save an iterator in the BTree control block so
257: // that we have a context in which to perfrom the iteration. Also note that the old B-tree
258: // allowed you to specify any number relative to the last operation (including 0) whereas the
259: // new B-tree only allows next/previous.
260: #if TARGET_OS_MAC
261: OSErr GetBTreeRecord(FileReference refNum, SInt16 selectionIndex, void* key, void* data, UInt16 *dataSize, UInt32 *newHint)
262: {
263: FSBufferDescriptor btRecord;
264: BTreeIterator *iterator;
265: FCB *fcb;
266: BTreeControlBlock *btcb;
267: OSStatus result;
268: UInt16 operation;
269:
270:
271: fcb = GetFileControlBlock(refNum);
272:
273: // pick up our iterator in the BTCB for context...
274:
275: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
276: iterator = &btcb->lastIterator;
277:
278: btRecord.bufferAddress = data;
279: btRecord.itemCount = 1;
280: if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength )
281: btRecord.itemSize = sizeof(HFSExtentRecord);
282: else if ( btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength )
283: btRecord.itemSize = sizeof(HFSPlusExtentRecord);
284: else
285: btRecord.itemSize = sizeof(CatalogRecord);
286:
287: // now we have to map index into next/prev operations...
288:
289: if (selectionIndex == 1)
290: {
291: operation = kBTreeNextRecord;
292: }
293: else if (selectionIndex == -1)
294: {
295: operation = kBTreePrevRecord;
296: }
297: else if (selectionIndex == 0)
298: {
299: operation = kBTreeCurrentRecord;
300: }
301: else if (selectionIndex == (SInt16) 0x8001)
302: {
303: operation = kBTreeFirstRecord;
304: }
305: else if (selectionIndex == (SInt16) 0x7FFF)
306: {
307: operation = kBTreeLastRecord;
308: }
309: else if (selectionIndex > 1)
310: {
311: UInt32 i;
312:
313: for (i = 1; i < selectionIndex; ++i)
314: {
315: result = BTIterateRecord( fcb, kBTreeNextRecord, iterator, &btRecord, dataSize );
316: ExitOnError(result);
317: }
318: operation = kBTreeNextRecord;
319: }
320: else // (selectionIndex < -1)
321: {
322: SInt32 i;
323:
324: for (i = -1; i > selectionIndex; --i)
325: {
326: result = BTIterateRecord( fcb, kBTreePrevRecord, iterator, &btRecord, dataSize );
327: ExitOnError(result);
328: }
329: operation = kBTreePrevRecord;
330: }
331:
332: result = BTIterateRecord( fcb, operation, iterator, &btRecord, dataSize );
333:
334: if (result == noErr)
335: {
336: *newHint = iterator->hint.nodeNum;
337:
338: result = CheckBTreeKey(&iterator->key, btcb);
339: ExitOnError(result);
340:
341: BlockMoveData(&iterator->key, key, CalcKeySize(btcb, &iterator->key)); //�� warning, this could overflow user's buffer!!!
342:
343: if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, *dataSize) )
344: DebugStr("\pGetBTreeRecord: bad record?");
345:
346: }
347:
348: ErrorExit:
349:
350: return result;
351: }
352: #endif /* TARGET_OS_MAC */
353:
354:
355: OSErr InsertBTreeRecord(FileReference refNum, void* key, void* data, UInt16 dataSize, UInt32 *newHint)
356: {
357: FSBufferDescriptor btRecord;
358: BTreeIterator iterator;
359: FCB *fcb;
360: BTreeControlBlock *btcb;
361: OSStatus result;
362:
363:
364: fcb = GetFileControlBlock(refNum);
365: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
366:
367: btRecord.bufferAddress = data;
368: btRecord.itemSize = dataSize;
369: btRecord.itemCount = 1;
370:
371: iterator.hint.nodeNum = 0; // no hint
372:
373: result = CheckBTreeKey((BTreeKey *) key, btcb);
374: ExitOnError(result);
375:
376: BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen?
377:
378: if ( DEBUG_BUILD && !ValidHFSRecord(data, btcb, dataSize) )
379: DebugStr("\pInsertBTreeRecord: bad record?");
380:
381: result = BTInsertRecord( fcb, &iterator, &btRecord, dataSize );
382:
383: *newHint = iterator.hint.nodeNum;
384:
385: ErrorExit:
386:
387: return result;
388: }
389:
390:
391: OSErr DeleteBTreeRecord(FileReference refNum, void* key)
392: {
393: BTreeIterator iterator;
394: FCB *fcb;
395: BTreeControlBlock *btcb;
396: OSStatus result;
397:
398:
399: fcb = GetFileControlBlock(refNum);
400: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
401:
402: iterator.hint.nodeNum = 0; // no hint
403:
404: result = CheckBTreeKey((BTreeKey *) key, btcb);
405: ExitOnError(result);
406:
407: BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen?
408:
409: result = BTDeleteRecord( fcb, &iterator );
410:
411: ErrorExit:
412:
413: return result;
414: }
415:
416:
417: OSErr ReplaceBTreeRecord(FileReference refNum, const void* key, UInt32 hint, void *newData, UInt16 dataSize, UInt32 *newHint)
418: {
419: FSBufferDescriptor btRecord;
420: BTreeIterator iterator;
421: FCB *fcb;
422: BTreeControlBlock *btcb;
423: OSStatus result;
424:
425:
426: fcb = GetFileControlBlock(refNum);
427: btcb = (BTreeControlBlock*) fcb->fcbBTCBPtr;
428:
429: btRecord.bufferAddress = newData;
430: btRecord.itemSize = dataSize;
431: btRecord.itemCount = 1;
432:
433: iterator.hint.nodeNum = hint;
434:
435: result = CheckBTreeKey((BTreeKey *) key, btcb);
436: ExitOnError(result);
437:
438: BlockMoveData(key, &iterator.key, CalcKeySize(btcb, (BTreeKey *) key)); //�� should we range check against maxkeylen?
439:
440: if ( DEBUG_BUILD && !ValidHFSRecord(newData, btcb, dataSize) )
441: DebugStr("\pReplaceBTreeRecord: bad record?");
442:
443: result = BTReplaceRecord( fcb, &iterator, &btRecord, dataSize );
444:
445: *newHint = iterator.hint.nodeNum;
446:
447: //���do we need to invalidate the iterator?
448:
449: ErrorExit:
450:
451: return result;
452: }
453:
454:
455:
456: #if TARGET_OS_MAC
457: OSStatus GetBlockProc ( FileReference fileRefNum, UInt32 blockNum, GetBlockOptions options, BlockDescriptor *block )
458: {
459: OSStatus result;
460: short cacheOptions = 0;
461:
462: if (options == kGetBlock)
463: cacheOptions = gbDefault;
464: else if (options & kForceReadBlock)
465: cacheOptions = gbReadMask;
466: else if (options & kGetEmptyBlock)
467: cacheOptions = gbNoReadMask;
468: else
469: Panic ("\pGetBlockProc: Invalid option!");
470:
471: if ( block->blockSize == 512 )
472: {
473: result = GetBlock_glue( cacheOptions, blockNum, (Ptr *)&block->buffer, fileRefNum, GetFileControlBlock(fileRefNum)->fcbVPtr );
474: block->blockReadFromDisk = BlockCameFromDisk();
475: }
476: else
477: {
478: result = GetCacheBlock( fileRefNum, blockNum, block->blockSize, cacheOptions, &block->buffer, &block->blockReadFromDisk);
479: }
480:
481: return result;
482: }
483: #endif /* TARGET_OS_MAC */
484:
485:
486: #if TARGET_OS_MAC
487: OSStatus ReleaseBlockProc ( FileReference fileRefNum, BlockDescPtr blockPtr, ReleaseBlockOptions options )
488: {
489: #pragma unused (fileRefNum)
490:
491: OSStatus result;
492: short cacheOptions = 0;
493:
494:
495: if (options == kReleaseBlock)
496: cacheOptions = rbDefault;
497: else if (options & kMarkBlockDirty)
498: cacheOptions = rbDirtyMask;
499: else if (options & kForceWriteBlock)
500: cacheOptions = rbWriteMask;
501: else if (options & kTrashBlock)
502: cacheOptions = rbTrashMask;
503: else
504: Panic ("\pGetBlockProc: Invalid option!");
505:
506: //�� if kReleaseBlock and just markdirty should we call markblock??
507:
508: if ( blockPtr->blockSize == 512 )
509: result = RelBlock_glue( blockPtr->buffer, cacheOptions );
510: else
511: result = ReleaseCacheBlock( blockPtr->buffer, cacheOptions );
512:
513: return result;
514: }
515: #endif /* TARGET_OS_MAC */
516:
517:
518: #if TARGET_OS_MAC
519: OSStatus
520: SetBlockSizeProc ( FileReference fileRefNum, ByteCount blockSize, ItemCount minBlockCount)
521: {
522: #pragma unused (fileRefNum)
523:
524: OSStatus result;
525:
526: // for HFS Plus volumes we'll need to set up a big node cache...
527:
528: if ( blockSize > 512 )
529: result = InitializeBlockCache (blockSize, minBlockCount);
530: else
531: result = noErr;
532:
533: return result;
534: }
535: #endif /* TARGET_OS_MAC */
536:
537:
538:
539: OSStatus
540: SetEndOfForkProc ( FileReference fileRefNum, FSSize minEOF, FSSize maxEOF )
541: {
542: #pragma unused (maxEOF)
543:
544: OSStatus result;
545: UInt32 actualBytesAdded;
546: UInt32 bytesToAdd;
547: ExtendedVCB *vcb;
548: FCB *filePtr;
549:
550:
551: filePtr = GetFileControlBlock(fileRefNum);
552:
553: if ( minEOF > filePtr->fcbEOF )
554: {
555: bytesToAdd = minEOF - filePtr->fcbEOF;
556:
557: if (bytesToAdd < filePtr->fcbClmpSize)
558: bytesToAdd = filePtr->fcbClmpSize; //���why not always be a mutiple of clump size ???
559: }
560: else
561: {
562: if ( DEBUG_BUILD )
563: DebugStr("\pSetEndOfForkProc: minEOF is smaller than current size!");
564: return -1;
565: }
566:
567: vcb = filePtr->fcbVPtr;
568: result = ExtendFileC ( vcb, filePtr, bytesToAdd, 0, &actualBytesAdded );
569: ReturnIfError(result);
570:
571: if (DEBUG_BUILD && actualBytesAdded < bytesToAdd)
572: DebugStr("\pSetEndOfForkProc: actualBytesAdded < bytesToAdd!");
573:
574: filePtr->fcbEOF = filePtr->fcbPLen; // new B-tree looks at fcbEOF
575:
576: //
577: // Update the Alternate MDB or Alternate VolumeHeader
578: //
579: if ( vcb->vcbSigWord == kHFSPlusSigWord )
580: {
581: // If any of the HFS+ private files change size, flush them back to the Alternate volume header
582: if ( (filePtr->fcbFlNm == kHFSExtentsFileID)
583: || (filePtr->fcbFlNm == kHFSCatalogFileID)
584: || (filePtr->fcbFlNm == kHFSStartupFileID)
585: || (filePtr->fcbFlNm == kHFSAttributesFileID) )
586: {
587: MarkVCBDirty( vcb );
588: result = FlushAlternateVolumeControlBlock( vcb, true );
589: }
590: }
591: else if ( vcb->vcbSigWord == kHFSSigWord )
592: {
593: if ( filePtr->fcbFlNm == kHFSExtentsFileID )
594: {
595: vcb->vcbXTAlBlks = filePtr->fcbPLen / vcb->blockSize;
596: MarkVCBDirty( vcb );
597: result = FlushAlternateVolumeControlBlock( vcb, false );
598: }
599: else if ( filePtr->fcbFlNm == kHFSCatalogFileID )
600: {
601: vcb->vcbCTAlBlks = filePtr->fcbPLen / vcb->blockSize;
602: MarkVCBDirty( vcb );
603: result = FlushAlternateVolumeControlBlock( vcb, false );
604: }
605: }
606:
607: return result;
608:
609: } // end SetEndOfForkProc
610:
611:
612: static OSErr CheckBTreeKey(const BTreeKey *key, const BTreeControlBlock *btcb)
613: {
614: UInt16 keyLen;
615:
616: if ( btcb->attributes & kBTBigKeysMask )
617: keyLen = key->length16;
618: else
619: keyLen = key->length8;
620:
621: if ( (keyLen < 6) || (keyLen > btcb->maxKeyLength) )
622: {
623: if ( DEBUG_BUILD )
624: DebugStr("\pCheckBTreeKey: bad key length!");
625: return fsBTInvalidKeyLengthErr;
626: }
627:
628: return noErr;
629: }
630:
631:
632: static Boolean ValidHFSRecord(const void *record, const BTreeControlBlock *btcb, UInt16 recordSize)
633: {
634: UInt32 cNodeID;
635:
636: if ( btcb->maxKeyLength == kHFSExtentKeyMaximumLength )
637: {
638: return ( recordSize == sizeof(HFSExtentRecord) );
639: }
640: else if (btcb->maxKeyLength == kHFSPlusExtentKeyMaximumLength )
641: {
642: return ( recordSize == sizeof(HFSPlusExtentRecord) );
643: }
644: else if (btcb->maxKeyLength == kAttributeKeyMaximumLength )
645: {
646: HFSPlusAttrRecord *attributeRecord = (HFSPlusAttrRecord *) record;
647:
648: switch (attributeRecord->recordType) {
649: case kHFSPlusAttrInlineData:
650: break;
651:
652: case kHFSPlusAttrForkData:
653: break;
654:
655: case kHFSPlusAttrExtents:
656: break;
657: }
658: }
659: else // Catalog record
660: {
661: CatalogRecord *catalogRecord = (CatalogRecord*) record;
662:
663: switch(catalogRecord->recordType)
664: {
665: case kHFSFolderRecord:
666: {
667: if ( recordSize != sizeof(HFSCatalogFolder) )
668: return false;
669: if ( catalogRecord->hfsFolder.flags != 0 )
670: return false;
671: if ( catalogRecord->hfsFolder.valence > 0x7FFF )
672: return false;
673:
674: cNodeID = catalogRecord->hfsFolder.folderID;
675:
676: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
677: return false;
678: }
679: break;
680:
681: case kHFSPlusFolderRecord:
682: {
683: if ( recordSize != sizeof(HFSPlusCatalogFolder) )
684: return false;
685: if ( catalogRecord->hfsPlusFolder.flags != 0 )
686: return false;
687: if ( catalogRecord->hfsPlusFolder.valence > 0x7FFF )
688: return false;
689:
690: cNodeID = catalogRecord->hfsPlusFolder.folderID;
691:
692: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
693: return false;
694: }
695: break;
696:
697: case kHFSFileRecord:
698: {
699: // UInt16 i;
700: HFSExtentDescriptor *dataExtent;
701: HFSExtentDescriptor *rsrcExtent;
702:
703: if ( recordSize != sizeof(HFSCatalogFile) )
704: return false;
705: if ( (catalogRecord->hfsFile.flags & ~(0x83)) != 0 )
706: return false;
707:
708: cNodeID = catalogRecord->hfsFile.fileID;
709:
710: if ( cNodeID < 16 )
711: return false;
712:
713: // make sure 0 � LEOF � PEOF for both forks
714:
715: if ( catalogRecord->hfsFile.dataLogicalSize < 0 )
716: return false;
717: if ( catalogRecord->hfsFile.dataPhysicalSize < catalogRecord->hfsFile.dataLogicalSize )
718: return false;
719: if ( catalogRecord->hfsFile.rsrcLogicalSize < 0 )
720: return false;
721: if ( catalogRecord->hfsFile.rsrcPhysicalSize < catalogRecord->hfsFile.rsrcLogicalSize )
722: return false;
723:
724: dataExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.dataExtents;
725: rsrcExtent = (HFSExtentDescriptor*) &catalogRecord->hfsFile.rsrcExtents;
726:
727: #if 0
728: for (i = 0; i < kHFSExtentDensity; ++i)
729: {
730: if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
731: return false;
732: if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
733: return false;
734: }
735: #endif
736: }
737: break;
738:
739: case kHFSPlusFileRecord:
740: {
741: // UInt16 i;
742: HFSPlusExtentDescriptor *dataExtent;
743: HFSPlusExtentDescriptor *rsrcExtent;
744:
745: if ( recordSize != sizeof(HFSPlusCatalogFile) )
746: return false;
747: if ( (catalogRecord->hfsPlusFile.flags & ~(0x83)) != 0 )
748: return false;
749:
750: cNodeID = catalogRecord->hfsPlusFile.fileID;
751:
752: if ( cNodeID < 16 )
753: return false;
754:
755: // make sure 0 � LEOF � PEOF for both forks
756:
757: if ( catalogRecord->hfsPlusFile.dataFork.logicalSize.hi != 0 )
758: return false;
759: if ( catalogRecord->hfsPlusFile.resourceFork.logicalSize.hi != 0 )
760: return false;
761:
762: dataExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.dataFork.extents;
763: rsrcExtent = (HFSPlusExtentDescriptor*) &catalogRecord->hfsPlusFile.resourceFork.extents;
764:
765: #if 0
766: for (i = 0; i < kHFSPlusExtentDensity; ++i)
767: {
768: if ( (dataExtent[i].blockCount > 0) && (dataExtent[i].startBlock == 0) )
769: return false;
770: if ( (rsrcExtent[i].blockCount > 0) && (rsrcExtent[i].startBlock == 0) )
771: return false;
772: }
773: #endif
774: }
775: break;
776:
777: case kHFSFolderThreadRecord:
778: case kHFSFileThreadRecord:
779: {
780: if ( recordSize != sizeof(HFSCatalogThread) )
781: return false;
782:
783: cNodeID = catalogRecord->hfsThread.parentID;
784: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
785: return false;
786:
787: if ( (catalogRecord->hfsThread.nodeName[0] == 0) ||
788: (catalogRecord->hfsThread.nodeName[0] > 31) )
789: return false;
790: }
791: break;
792:
793: case kHFSPlusFolderThreadRecord:
794: case kHFSPlusFileThreadRecord:
795: {
796: if ( recordSize > sizeof(HFSPlusCatalogThread) || recordSize < (sizeof(HFSPlusCatalogThread) - sizeof(HFSUniStr255)))
797: return false;
798:
799: cNodeID = catalogRecord->hfsPlusThread.parentID;
800: if ( (cNodeID == 0) || (cNodeID < 16 && cNodeID > 2) )
801: return false;
802:
803: if ( (catalogRecord->hfsPlusThread.nodeName.length == 0) ||
804: (catalogRecord->hfsPlusThread.nodeName.length > 255) )
805: return false;
806: }
807: break;
808:
809: default:
810: return false;
811: }
812: }
813:
814: return true; // record appears to be OK
815: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.