|
|
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: BTree.c
27:
28: Contains: Implementation of public interface routines for B-tree manager.
29:
30: Version: HFS Plus 1.0
31:
32: Written by: Gordon Sheridan and Bill Bruffey
33:
34: Copyright: � 1992-1998 by Apple Computer, Inc., all rights reserved.
35:
36: File Ownership:
37:
38: DRI: Don Brady
39:
40: Other Contact: Mark Day
41:
42: Technology: File Systems
43:
44: Writers:
45:
46: (msd) Mark Day
47: (DSH) Deric Horn
48: (djb) Don Brady
49:
50: Change History (most recent first):
51: <Rhap> 6/30/98 djb In BTOpenPath make sure nodes are contiguous on disk (radar #2249539).
52: <Rhap> 4/15/98 djb In BTOpenPath need to clear nodeRec.buffer if GetBlockProc fails.
53: <Rhap> 4/11/98 djb Add RequireFileLock checking to all external entry points.
54:
55: <Rhap> 03/23/98 djb In BTOpenPath use kTrashBlock option when releasing the header so
56: that we get a full node when we call GetNode.
57:
58: <CS9> 12/12/97 djb Radar #2202682, BTIterateRecord with kBTreeCurrentRecord was not
59: checking if we had a record and could call BlockMove with an
60: uninitialize source pointer (causing a bus error).
61: <CS8> 10/24/97 msd In BTIterateRecord, when moving to the previous or next record
62: and we have to move to another node, see if we need to release
63: the node about to be "shifted out" (opposite sibling of the
64: direction we need to move).
65: <CS7> 7/25/97 DSH BTSearchRecord now takes a heuristicHint, nodeNum, and tries it
66: before calling SearchBTree
67: <CS6> 7/24/97 djb GetBlockProc now take a file refnum instead of an FCB ptr.
68: <CS5> 7/22/97 djb Move trace points from BTreeWrapper.c to here.
69: <CS4> 7/21/97 djb LogEndTime now takes an error code.
70: <CS3> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name
71: collision
72: <CS2> 5/19/97 djb Add summary traces to BTIterateRecord.
73: <CS1> 4/23/97 djb first checked in
74:
75: <HFS7> 2/19/97 djb Enable variable sized index keys for HFS+ volumes. Added node
76: cache to support nodes larger than 512 bytes.
77: <HFS6> 1/27/97 djb Calls to InsertTree and DeleteTree are now recursive (to support
78: variable sized index keys).
79: <HFS5> 1/13/97 djb Added support for getting current record to BTIterateRecord.
80: <HFS4> 1/6/97 djb Initialize "BigKeys" attribute in BTOpen.
81: <HFS3> 1/3/97 djb Added support for large keys.
82: <HFS2> 12/23/96 djb On exit map fsBTEmptyErr and fsBTEndOfIterationErr to
83: fsBTRecordNotFoundErr.
84: <HFS1> 12/19/96 djb first checked in
85:
86: History applicable to original Scarecrow Design:
87:
88: <13> 10/25/96 ser Changing for new VFPI
89: <12> 10/18/96 ser Converting over VFPI changes
90: <11> 9/17/96 dkh More BTree statistics. Modified hint checks to not bail out when
91: an error is returned from GetNode.
92: <10> 9/16/96 dkh Revised BTree statistics.
93: <9> 8/23/96 dkh Remove checks for multiple paths to BTree file. Need to add
94: equivalent mechanism later.
95: <8> 6/20/96 dkh Radar #1358740. Switch from using Pools to debug MemAllocators.
96: <7> 3/14/96 jev Fix BTreeSetRecord, recordFound was not set for the case of a
97: simple replace causing the leafRecords count to get bumped even
98: though we didn't have to add a record.
99: <6> 3/1/96 prp Fix lint problems. Bug in BTSetRecord that does not initialize
100: recordFound.
101: <5> 1/22/96 dkh Add #include Memory.h
102: <4> 1/10/96 msd Use the real function names from Math64.i.
103: <3> 1/4/96 jev Fix BTItererateRecord for the condition when the iterator
104: position routine does not find the record and we are looking for
105: the next record. In such a case, if the node's forrward link is
106: non-zero, we have to keep iterating next and not return
107: fsBTEndOfIterationErr error.
108: <2> 12/7/95 dkh D10E2 build. Changed usage of Ref data type to LogicalAddress.
109: <1> 10/18/95 rst Moved from Scarecrow project.
110:
111: <24> 7/18/95 mbb Change MoveData & ClearBytes to BlockMoveData & BlockZero.
112: <23> 1/31/95 prp GetBlockProc interface uses a 64 bit node number.
113: <22> 1/12/95 wjk Adopt Model FileSystem changes in D5.
114: <21> 11/16/94 prp Add IsItAHint routine and use it whenever hint's node number was
115: used for testing.
116: <20> 11/10/94 prp BTGetInfo name collides with the same name in FileManagerPriv.i.
117: Change it to BTGetInformation.
118: <19> 9/30/94 prp Get in sync with D2 interface changes.
119: <18> 7/22/94 wjk Convert to the new set of header files.
120: <17> 12/9/93 wjk Cleanup usage of char, Byte, int8, UInt8, etc.
121: <16> 12/2/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and
122: NRCmds environments.
123: <15> 11/30/93 wjk Move from Makefiles to BuildFiles. Fit into the ModernOS and
124: NRCmds environments.
125: <14> 9/30/93 gs Rename E_NoGetNodeProc and E_NoReleaseNodeProc to
126: E_NoXxxxBlockProc.
127: <13> 8/31/93 prp Use Set64U instead of Set64.
128: <12> 8/16/93 prp In BTSearchRecord, if the input hint found the node and record,
129: set the local nodeNum variable correctly so that the resultant
130: iterator gets set correctly.
131: <11> 7/1/93 gs Fix bug in BTIterateRecord related to kBTreePrevRecord
132: operation.
133: <10> 6/2/93 gs Update for changes to FSErrors.h and add some comments.
134: <9> 5/24/93 gs Fix bug in BTInsert/Set/ReplaceRecord which didn't set node hint
135: properly in some cases.
136: <8> 5/24/93 gs Do NOT map fsBTEmptyErr to fsBTRecordNotFoundErr in BTSearchRecord.
137: <7> 5/24/93 gs Rename BTFlush to BTFlushPath.
138: <6> 5/21/93 gs Add hint optimization to Set/Replace routines.
139: <5> 5/10/93 gs Remove Panic from BTInitialize for small logicalEOF. Implement
140: Insert, Set, Replace, and Delete.
141: <4> 3/23/93 gs Finish BTInitialize.
142: <3> 2/8/93 gs Implement BTSearchRecord and BTIterateRecord.
143: <2> 12/8/92 gs Implement Open and Close routines.
144: <1> 11/15/92 gs first checked in
145:
146: */
147:
148: #if TARGET_OS_MAC
149: #include <Memory.h>
150: #else
151: #include "../headers/system/MacOSTypes.h"
152: #endif /* TARGET_OS_MAC */
153:
154:
155: #include "../headers/FileMgrInternal.h"
156: #include "../headers/HFSBtreesPriv.h"
157:
158: #include "../headers/BTreesPrivate.h"
159:
160: #include "../headers/system/HFSInstrumentation.h"
161:
162:
163: #if TARGET_OS_RHAPSODY && DIAGNOSTIC
164: #if DIAGNOSTIC
165: extern void RequireFileLock(FileReference file, int shareable);
166: #else
167: #define RequireFileLock(f,s)
168: #endif
169: #endif
170:
171:
172: //////////////////////////////////// Globals ////////////////////////////////////
173:
174:
175: /////////////////////////// BTree Module Entry Points ///////////////////////////
176:
177:
178: /*-------------------------------------------------------------------------------
179: Routine: InitBTreeModule - Initialize BTree Module Global(s).
180:
181: Function: Initialize BTree code, if necessary
182:
183: Input: none
184:
185: Output: none
186:
187: Result: noErr - success
188: != noErr - can't happen
189: -------------------------------------------------------------------------------*/
190:
191: OSStatus InitBTreeModule(void)
192: {
193: return noErr;
194: }
195:
196:
197: /*-------------------------------------------------------------------------------
198: Routine: BTInitialize - Initialize a fork for access as a B*Tree.
199:
200: Function: Write Header node and create any map nodes necessary to map the fork
201: as a B*Tree. If the fork is not large enough for the header node, the
202: FS Agent is called to extend the LEOF. Additional map nodes will be
203: allocated if necessary to represent the size of the fork. This allows
204: the FS Agent to specify the initial size of B*Tree files.
205:
206:
207: Input: pathPtr - pointer to path control block
208: maxKeyLength - maximum length that will be used for any key in this B*Tree
209: nodeSize - node size for B*Tree (must be 2^n, 9 >= n >= 15)
210: btreeType - type of B*Tree
211: keyDescPtr - pointer to key descriptor (optional if key compare proc is used)
212:
213: Output: none
214:
215: Result: noErr - success
216: paramErr - mandatory parameter was missing
217: E_NoGetBlockProc - FS Agent CB has no GetNodeProcPtr
218: E_NoReleaseBlockProc - FS Agent CB has no ReleaseNodeProcPtr
219: E_NoSetEndOfForkProc - FS Agent CB has no SetEndOfForkProcPtr
220: E_NoSetBlockSizeProc - FS Agent CB has no SetBlockSizeProcPtr
221: fsBTrFileAlreadyOpenErr - fork is already open as a B*Tree
222: fsBTInvalidKeyLengthErr - maximum key length is out of range
223: E_BadNodeType - node size is an illegal value
224: fsBTUnknownVersionErr - the B*Tree type is unknown by this module
225: memFullErr - not enough memory to initialize B*Tree
226: != noErr - failure
227: -------------------------------------------------------------------------------*/
228: #if 0
229: OSStatus BTInitialize (FCB *filePtr,
230: UInt16 maxKeyLength,
231: UInt16 nodeSize,
232: UInt8 btreeType,
233: KeyDescriptorPtr keyDescPtr )
234: {
235: OSStatus err;
236: FSForkControlBlockPtr forkPtr;
237: BTreeControlBlockPtr btreePtr;
238: BlockDescriptor headerNode;
239: HeaderPtr header;
240: Ptr pos;
241: FSSize minEOF, maxEOF;
242: SetEndOfForkProcPtr setEndOfForkProc;
243: SetBlockSizeProcPtr setBlockSizeProc;
244:
245: ////////////////////// Preliminary Error Checking ///////////////////////////
246:
247: headerNode.buffer = nil;
248:
249: if (pathPtr == nil) return paramErr;
250:
251: setEndOfForkProc = pathPtr->agentPtr->agent.setEndOfForkProc;
252: setBlockSizeProc = pathPtr->agentPtr->agent.setBlockSizeProc;
253:
254: if (pathPtr->agentPtr->agent.getBlockProc == nil) return E_NoGetBlockProc;
255: if (pathPtr->agentPtr->agent.releaseBlockProc == nil) return E_NoReleaseBlockProc;
256: if (setEndOfForkProc == nil) return E_NoSetEndOfForkProc;
257: if (setBlockSizeProc == nil) return E_NoSetBlockSizeProc;
258:
259: forkPtr = pathPtr->path.forkPtr;
260:
261: if (forkPtr->fork.btreePtr != nil) return fsBTrFileAlreadyOpenErr;
262:
263: if ((maxKeyLength == 0) ||
264: (maxKeyLength > kMaxKeyLength)) return fsBTInvalidKeyLengthErr;
265:
266: if ( M_IsEven (maxKeyLength)) ++maxKeyLength; // len byte + even bytes + pad byte
267:
268: switch (nodeSize) // node size == 512*2^n
269: {
270: case 512:
271: case 1024:
272: case 2048:
273: case 4096:
274: case 8192:
275: case 16384:
276: case 32768: break;
277: default: return E_BadNodeType;
278: }
279:
280: switch (btreeType)
281: {
282: case kHFSBTreeType:
283: case kUserBTreeType:
284: case kReservedBTreeType: break;
285:
286: default: return fsBTUnknownVersionErr; //�� right?
287: }
288:
289:
290: //////////////////////// Allocate Control Block /////////////////////////////
291:
292: M_RESIDENT_ALLOCATE_FIXED_CLEAR( &btreePtr, sizeof( BTreeControlBlock ), kFSBTreeControlBlockType );
293: if (btreePtr == nil)
294: {
295: err = memFullErr;
296: goto ErrorExit;
297: }
298:
299: btreePtr->version = kBTreeVersion; //�� what is the version?
300: btreePtr->reserved1 = 0;
301: btreePtr->flags = 0;
302: btreePtr->attributes = 0;
303: btreePtr->forkPtr = forkPtr;
304: btreePtr->keyCompareProc = nil;
305: btreePtr->keyDescPtr = keyDescPtr;
306: btreePtr->btreeType = btreeType;
307: btreePtr->treeDepth = 0;
308: btreePtr->rootNode = 0;
309: btreePtr->leafRecords = 0;
310: btreePtr->firstLeafNode = 0;
311: btreePtr->lastLeafNode = 0;
312: btreePtr->nodeSize = nodeSize;
313: btreePtr->maxKeyLength = maxKeyLength;
314: btreePtr->totalNodes = 1; // so ExtendBTree adds maps nodes properly
315: btreePtr->freeNodes = 0;
316: btreePtr->writeCount = 0;
317:
318: // set block size = nodeSize
319: err = setBlockSizeProc (forkPtr, nodeSize);
320: M_ExitOnError (err);
321:
322: ////////////////////////////// Check LEOF ///////////////////////////////////
323:
324: minEOF = S64Set ((SInt32) nodeSize); //�� until real 64-bit math wjk 94.12.27
325: if ( S64Compare (forkPtr->fork.logicalEOF, minEOF) < 0)
326: {
327: // allocate more space if necessary
328:
329: //��
330: //�� until real 64-bit math wjk 94.12.27
331: //�� ???? Does this B*Tree pack stop working when LEOF > 2^32-1?
332: //��
333: maxEOF.hi = 0;
334: maxEOF.lo = ((UInt32)0xFFFFFFFFL);
335:
336: err = setEndOfForkProc (forkPtr, minEOF, maxEOF);
337: M_ExitOnError (err);
338: };
339:
340:
341: //////////////////////// Initialize Header Node /////////////////////////////
342:
343: err = GetNewNode (btreePtr, kHeaderNodeNum, &headerNode);
344: M_ExitOnError (err);
345:
346: header = headerNode.buffer;
347:
348: header->node.type = kHeaderNode;
349: header->node.numRecords = 3; // header rec, key desc, map rec
350:
351: header->nodeSize = nodeSize;
352: header->maxKeyLength = maxKeyLength;
353: header->btreeType = btreeType;
354: header->totalNodes = btreePtr->totalNodes;
355: header->freeNodes = btreePtr->totalNodes - 1;
356: // ignore header->clumpSize; //�� rename this field?
357:
358: // mark header node allocated in map record
359: pos = ((Ptr)headerNode.buffer) + kHeaderMapRecOffset;
360: *pos = 0x80;
361:
362: // set node offsets ( nodeSize-8, F8, 78, 0E)
363: pos = ((Ptr)headerNode.buffer) + nodeSize;
364: pos -= 2; *((UInt16 *)pos) = kHeaderRecOffset;
365: pos -= 2; *((UInt16 *)pos) = kKeyDescRecOffset;
366: pos -= 2; *((UInt16 *)pos) = kHeaderMapRecOffset;
367: pos -= 2; *((UInt16 *)pos) = nodeSize - 8;
368:
369:
370: ///////////////////// Copy Key Descriptor To Header /////////////////////////
371: #if SupportsKeyDescriptors
372: if (keyDescPtr != nil)
373: {
374: err = CheckKeyDescriptor (keyDescPtr, maxKeyLength);
375: M_ExitOnError (err);
376:
377: // copy to header node
378: pos = ((Ptr)headerNode.buffer) + kKeyDescRecOffset;
379: BlockMoveData (keyDescPtr, pos, keyDescPtr->length + 1);
380: }
381: #endif
382:
383: // write header node
384: err = UpdateNode (btreePtr, &headerNode);
385: M_ExitOnError (err);
386:
387:
388: ////////////////////////// Allocate Map Nodes ///////////////////////////////
389:
390: err = ExtendBTree (btreePtr, forkPtr->fork.logicalEOF.lo / nodeSize); // sets totalNodes
391: M_ExitOnError (err);
392:
393:
394: ////////////////////////////// Close BTree //////////////////////////////////
395:
396: err = UpdateHeader (btreePtr);
397: M_ExitOnError (err);
398:
399: pathPtr->path.forkPtr->fork.btreePtr = nil;
400: M_RESIDENT_DEALLOCATE_FIXED( btreePtr, sizeof( BTreeControlBlock ), kFSBTreeControlBlockType );
401:
402: return noErr;
403:
404:
405: /////////////////////// Error - Clean up and Exit ///////////////////////////
406:
407: ErrorExit:
408:
409: (void) ReleaseNode (btreePtr, &headerNode);
410: if (btreePtr != nil)
411: M_RESIDENT_DEALLOCATE_FIXED( btreePtr, sizeof( BTreeControlBlock ), kFSBTreeControlBlockType );
412:
413: return err;
414: }
415: #endif
416:
417:
418: /*-------------------------------------------------------------------------------
419: Routine: BTOpenPath - Open a file for access as a B*Tree.
420:
421: Function: Create BTree control block for a file, if necessary. Validates the
422: file to be sure it looks like a BTree file.
423:
424:
425: Input: filePtr - pointer to file to open as a B-tree
426: keyCompareProc - pointer to client's KeyCompare function
427: getBlockProc - pointer to client's GetBlock function
428: releaseBlockProc - pointer to client's ReleaseBlock function
429: setEndOfForkProc - pointer to client's SetEOF function
430:
431: Result: noErr - success
432: paramErr - required ptr was nil
433: fsBTInvalidFileErr -
434: memFullErr -
435: != noErr - failure
436: -------------------------------------------------------------------------------*/
437:
438: OSStatus BTOpenPath (FCB *filePtr,
439: KeyCompareProcPtr keyCompareProc,
440: GetBlockProcPtr getBlockProc,
441: ReleaseBlockProcPtr releaseBlockProc,
442: SetEndOfForkProcPtr setEndOfForkProc,
443: SetBlockSizeProcPtr setBlockSizeProc )
444: {
445: OSStatus err;
446: BTreeControlBlockPtr btreePtr;
447: HeaderPtr header;
448: NodeRec nodeRec;
449:
450: LogStartTime(kTraceOpenBTree);
451:
452: ////////////////////// Preliminary Error Checking ///////////////////////////
453:
454: if ( filePtr == nil ||
455: getBlockProc == nil ||
456: releaseBlockProc == nil ||
457: setEndOfForkProc == nil ||
458: setBlockSizeProc == nil )
459: {
460: return paramErr;
461: }
462:
463: if ( filePtr->fcbBTCBPtr != nil ) // already has a BTreeCB
464: return noErr;
465:
466: // is file large enough to contain header node?
467: if ( filePtr->fcbEOF < kMinNodeSize )
468: return fsBTInvalidFileErr; //�� or E_BadHeader?
469:
470:
471: //////////////////////// Allocate Control Block /////////////////////////////
472:
473: btreePtr = (BTreeControlBlock*) NewPtrSysClear( sizeof( BTreeControlBlock ) );
474: if (btreePtr == nil)
475: {
476: Panic ("\pBTOpen: no memory for btreePtr.");
477: return memFullErr;
478: }
479:
480: btreePtr->getBlockProc = getBlockProc;
481: btreePtr->releaseBlockProc = releaseBlockProc;
482: btreePtr->setEndOfForkProc = setEndOfForkProc;
483: btreePtr->keyCompareProc = keyCompareProc;
484:
485: /////////////////////////// Read Header Node ////////////////////////////////
486:
487: nodeRec.buffer = nil; // so we can call ReleaseNode
488: nodeRec.blockSize = kMinNodeSize;
489: btreePtr->fileRefNum = GetFileRefNumFromFCB(filePtr);
490: filePtr->fcbBTCBPtr = (Ptr) btreePtr; // attach btree cb to file
491:
492: #if TARGET_OS_RHAPSODY
493: RequireFileLock(btreePtr->fileRefNum, false);
494: #endif
495:
496: // it is now safe to call M_ExitOnError (err)
497:
498: err = setBlockSizeProc (btreePtr->fileRefNum, kMinNodeSize, 1);
499: M_ExitOnError (err);
500:
501:
502: err = getBlockProc (btreePtr->fileRefNum,
503: kHeaderNodeNum,
504: kGetBlock,
505: &nodeRec );
506: if (err != noErr)
507: {
508: nodeRec.buffer = nil;
509: nodeRec.blockHeader = nil;
510: Panic("\pBTOpen: getNodeProc returned error getting header node.");
511: goto ErrorExit;
512: }
513:
514: header = nodeRec.buffer;
515:
516:
517: ///////////////////////////// verify header /////////////////////////////////
518:
519: err = VerifyHeader (filePtr, header);
520: M_ExitOnError (err);
521:
522:
523: ///////////////////// Initalize fields from header //////////////////////////
524:
525: PanicIf ( (filePtr->fcbVPtr->vcbSigWord != 0x4244) && (btreePtr->nodeSize == 512), "\p BTOpenPath: wrong node size for HFS+ volume!"); // 0x4244 = 'BD'
526:
527: btreePtr->treeDepth = header->treeDepth;
528: btreePtr->rootNode = header->rootNode;
529: btreePtr->leafRecords = header->leafRecords;
530: btreePtr->firstLeafNode = header->firstLeafNode;
531: btreePtr->lastLeafNode = header->lastLeafNode;
532: btreePtr->nodeSize = header->nodeSize;
533: btreePtr->maxKeyLength = header->maxKeyLength;
534: btreePtr->totalNodes = header->totalNodes;
535: btreePtr->freeNodes = header->freeNodes;
536: // ignore header->clumpSize; //�� rename this field?
537: btreePtr->btreeType = header->btreeType;
538:
539: btreePtr->attributes = header->attributes;
540:
541: if ( btreePtr->maxKeyLength > 40 )
542: btreePtr->attributes |= (kBTBigKeysMask + kBTVariableIndexKeysMask); //�� we need a way to save these attributes
543:
544: /////////////////////// Initialize dynamic fields ///////////////////////////
545:
546: btreePtr->version = kBTreeVersion;
547: btreePtr->flags = 0;
548: btreePtr->writeCount = 0;
549:
550: btreePtr->numGetNodes = 1; // for earlier call to getNodeProc
551:
552: /////////////////////////// Check Header Node ///////////////////////////////
553:
554: //�� set kBadClose attribute bit, and UpdateNode
555:
556: // if nodeSize is 512 then we don't need to release, just CheckNode
557:
558: if ( btreePtr->nodeSize == kMinNodeSize )
559: {
560: err = CheckNode (btreePtr, nodeRec.buffer);
561: M_ExitOnError (err);
562: }
563: else
564: {
565: err = setBlockSizeProc (btreePtr->fileRefNum, btreePtr->nodeSize, 32); //���we should try and get this down to 8
566: M_ExitOnError (err);
567:
568: #if TARGET_OS_RHAPSODY
569: /*
570: * Need to use kTrashBlock option to force the
571: * buffer cache to read the entire node
572: */
573: err = releaseBlockProc(btreePtr->fileRefNum, &nodeRec, kTrashBlock);
574: #else
575: err = ReleaseNode (btreePtr, &nodeRec);
576: #endif
577: M_ExitOnError (err);
578:
579: err = GetNode (btreePtr, kHeaderNodeNum, &nodeRec ); // calls CheckNode...
580: M_ExitOnError (err);
581: }
582:
583: //�� total nodes * node size <= LEOF?
584:
585:
586: ////////////////////////// Get Key Descriptor ///////////////////////////////
587: #if SupportsKeyDescriptors
588: if ( keyCompareProc == nil ) // if no key compare proc then get key descriptor
589: {
590: err = GetKeyDescriptor (btreePtr, nodeRec.buffer); //�� it should check amount of memory allocated...
591: M_ExitOnError (err);
592:
593: err = CheckKeyDescriptor (btreePtr->keyDescPtr, btreePtr->maxKeyLength);
594: M_ExitOnError (err);
595:
596: }
597: else
598: #endif
599: {
600: btreePtr->keyDescPtr = nil; // clear it so we don't dispose garbage later
601: }
602:
603: err = ReleaseNode (btreePtr, &nodeRec);
604: M_ExitOnError (err);
605:
606: #if TARGET_OS_RHAPSODY
607: /*
608: * Under Mac OS, b-tree nodes can be non-contiguous on disk when the
609: * allocation block size is smaller than the b-tree node size.
610: */
611: if ( !NodesAreContiguous(filePtr->fcbVPtr, filePtr, btreePtr->nodeSize) )
612: return fsBTInvalidNodeErr;
613: #endif
614:
615: //////////////////////////////// Success ////////////////////////////////////
616:
617: //�� align LEOF to multiple of node size? - just on close
618:
619: LogEndTime(kTraceOpenBTree, noErr);
620:
621: return noErr;
622:
623:
624: /////////////////////// Error - Clean up and Exit ///////////////////////////
625:
626: ErrorExit:
627:
628: filePtr->fcbBTCBPtr = nil;
629: (void) ReleaseNode (btreePtr, &nodeRec);
630: DisposePtr( (Ptr) btreePtr );
631:
632: LogEndTime(kTraceOpenBTree, err);
633:
634: return err;
635: }
636:
637:
638:
639: /*-------------------------------------------------------------------------------
640: Routine: BTClosePath - Flush BTree Header and Deallocate Memory for BTree.
641:
642: Function: Flush the BTreeControlBlock fields to header node, and delete BTree control
643: block and key descriptor associated with the file if filePtr is last
644: path of type kBTreeType ('btre').
645:
646:
647: Input: filePtr - pointer to file to delete BTree control block for.
648:
649: Result: noErr - success
650: fsBTInvalidFileErr -
651: != noErr - failure
652: -------------------------------------------------------------------------------*/
653:
654: OSStatus BTClosePath (FCB *filePtr)
655: {
656: OSStatus err;
657: BTreeControlBlockPtr btreePtr;
658: #if 0
659: FSPathControlBlockPtr tempPath;
660: Boolean otherBTreePathsOpen;
661: #endif
662:
663: LogStartTime(kTraceCloseBTree);
664:
665: btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
666:
667: if (btreePtr == nil)
668: return fsBTInvalidFileErr;
669:
670: #if TARGET_OS_RHAPSODY
671: RequireFileLock(btreePtr->fileRefNum, false);
672: #endif
673:
674: ////////////////////// Check for other BTree Paths //////////////////////////
675:
676: #if 0
677: //�� Need replacement field for pathType
678: otherBTreePathsOpen = false;
679: tempPath = forkPtr->fork.pathList.head;
680: while ( (tempPath != (FSPathControlBlockPtr) &forkPtr->fork.pathList) &&
681: (otherBTreePathsOpen == false) )
682: {
683: if ((tempPath != pathPtr) && (tempPath->path.pathType == kBTreeType))
684: {
685: otherBTreePathsOpen = true;
686: break; // done with loop check
687: }
688:
689: tempPath = tempPath->next;
690: }
691:
692: ////////////////////////// Update Header Node ///////////////////////////////
693:
694:
695: if (otherBTreePathsOpen == true)
696: {
697: err = UpdateHeader (btreePtr); // update header even if we aren't closing
698: return err; // we only clean up after the last user...
699: }
700: #endif
701:
702: btreePtr->attributes &= ~kBTBadCloseMask; // clear "bad close" attribute bit
703: err = UpdateHeader (btreePtr);
704: M_ExitOnError (err);
705:
706: #if SupportsKeyDescriptors
707: if (btreePtr->keyDescPtr != nil) // deallocate keyDescriptor, if any
708: {
709: DisposePtr( (Ptr) btreePtr->keyDescPtr );
710: }
711: #endif
712:
713: DisposePtr( (Ptr) btreePtr );
714: filePtr->fcbBTCBPtr = nil;
715:
716: LogEndTime(kTraceCloseBTree, noErr);
717:
718: return noErr;
719:
720: /////////////////////// Error - Clean Up and Exit ///////////////////////////
721:
722: ErrorExit:
723:
724: LogEndTime(kTraceCloseBTree, err);
725:
726: return err;
727: }
728:
729:
730:
731: /*-------------------------------------------------------------------------------
732: Routine: BTSearchRecord - Search BTree for a record with a matching key.
733:
734: Function: Search for position in B*Tree indicated by searchKey. If a valid node hint
735: is provided, it will be searched first, then SearchTree will be called.
736: If a BTreeIterator is provided, it will be set to the position found as
737: a result of the search. If a record exists at that position, and a BufferDescriptor
738: is supplied, the record will be copied to the buffer (as much as will fit),
739: and recordLen will be set to the length of the record.
740:
741: If an error other than fsBTRecordNotFoundErr occurs, the BTreeIterator, if any,
742: is invalidated, and recordLen is set to 0.
743:
744:
745: Input: pathPtr - pointer to path for BTree file.
746: searchKey - pointer to search key to match.
747: hintPtr - pointer to hint (may be nil)
748:
749: Output: record - pointer to BufferDescriptor containing record
750: recordLen - length of data at recordPtr
751: iterator - pointer to BTreeIterator indicating position result of search
752:
753: Result: noErr - success, record contains copy of record found
754: fsBTRecordNotFoundErr - record was not found, no data copied
755: fsBTInvalidFileErr - no BTreeControlBlock is allocated for the fork
756: fsBTInvalidKeyLengthErr -
757: != noErr - failure
758: -------------------------------------------------------------------------------*/
759:
760: OSStatus BTSearchRecord (FCB *filePtr,
761: BTreeIterator *searchIterator,
762: UInt32 heuristicHint,
763: FSBufferDescriptor *record,
764: UInt16 *recordLen,
765: BTreeIterator *resultIterator )
766: {
767: OSStatus err;
768: BTreeControlBlockPtr btreePtr;
769: TreePathTable treePathTable;
770: UInt32 nodeNum;
771: BlockDescriptor node;
772: UInt16 index;
773: BTreeKeyPtr keyPtr;
774: RecordPtr recordPtr;
775: UInt16 len;
776: Boolean foundRecord;
777: Boolean validHint;
778:
779:
780: LogStartTime(kTraceSearchBTree);
781:
782: if (filePtr == nil) return paramErr;
783: if (searchIterator == nil) return paramErr;
784:
785: btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
786: if (btreePtr == nil) return fsBTInvalidFileErr;
787:
788: #if TARGET_OS_RHAPSODY
789: RequireFileLock(btreePtr->fileRefNum, true);
790: #endif
791:
792: #if SupportsKeyDescriptors
793: if (btreePtr->keyCompareProc == nil) // CheckKey if we using Key Descriptor
794: {
795: err = CheckKey (&searchIterator->key, btreePtr->keyDescPtr, btreePtr->maxKeyLength);
796: M_ExitOnError (err);
797: }
798: #endif
799:
800: foundRecord = false;
801:
802: ////////////////////////////// Take A Hint //////////////////////////////////
803:
804: err = IsItAHint (btreePtr, searchIterator, &validHint);
805: M_ExitOnError (err);
806:
807: if (validHint)
808: {
809: nodeNum = searchIterator->hint.nodeNum;
810:
811: err = GetNode (btreePtr, nodeNum, &node);
812: if( err == noErr )
813: {
814: if ( ((BTNodeDescriptor*) node.buffer)->type == kLeafNode &&
815: ((BTNodeDescriptor*) node.buffer)->numRecords > 0 )
816: {
817: foundRecord = SearchNode (btreePtr, node.buffer, &searchIterator->key, &index);
818:
819: //�� if !foundRecord, we could still skip tree search if ( 0 < index < numRecords )
820: }
821:
822: if (foundRecord == false)
823: {
824: err = ReleaseNode (btreePtr, &node);
825: M_ExitOnError (err);
826: }
827: else
828: {
829: ++btreePtr->numValidHints;
830: }
831: }
832:
833: if( foundRecord == false )
834: (void) BTInvalidateHint( searchIterator );
835: }
836:
837: ////////////////////////////// Try the heuristicHint //////////////////////////////////
838:
839: if ( (foundRecord == false) && (heuristicHint != kInvalidMRUCacheKey) && (nodeNum != heuristicHint) )
840: {
841: LogStartTime(kHeuristicHint);
842: nodeNum = heuristicHint;
843:
844: err = GetNode (btreePtr, nodeNum, &node);
845: if( err == noErr )
846: {
847: if ( ((BTNodeDescriptor*) node.buffer)->type == kLeafNode &&
848: ((BTNodeDescriptor*) node.buffer)->numRecords > 0 )
849: {
850: foundRecord = SearchNode (btreePtr, node.buffer, &searchIterator->key, &index);
851: }
852:
853: if (foundRecord == false)
854: {
855: err = ReleaseNode (btreePtr, &node);
856: M_ExitOnError (err);
857: }
858: }
859: LogEndTime(kHeuristicHint, (foundRecord == false));
860: }
861:
862: //////////////////////////// Search The Tree ////////////////////////////////
863:
864: if (foundRecord == false)
865: {
866: err = SearchTree ( btreePtr, &searchIterator->key, treePathTable, &nodeNum, &node, &index);
867: switch (err)
868: {
869: case noErr: foundRecord = true; break;
870: case fsBTRecordNotFoundErr: break;
871: default: goto ErrorExit;
872: }
873: }
874:
875:
876: //////////////////////////// Get the Record /////////////////////////////////
877:
878: if (foundRecord == true)
879: {
880: //XXX Should check for errors! Or BlockMove could choke on recordPtr!!!
881: GetRecordByIndex (btreePtr, node.buffer, index, &keyPtr, &recordPtr, &len);
882:
883: if (recordLen != nil) *recordLen = len;
884:
885: if (record != nil)
886: {
887: ByteCount recordSize;
888:
889: recordSize = record->itemCount * record->itemSize;
890:
891: PanicIf(len > recordSize, "\pBTSearchRecord: truncating record!");
892:
893: if (len > recordSize) len = recordSize;
894:
895: BlockMoveData (recordPtr, record->bufferAddress, len);
896: }
897: }
898:
899:
900: /////////////////////// Success - Update Iterator ///////////////////////////
901:
902: if (resultIterator != nil)
903: {
904: resultIterator->hint.writeCount = btreePtr->writeCount;
905: resultIterator->hint.nodeNum = nodeNum;
906: resultIterator->hint.index = index;
907: resultIterator->hint.reserved1 = 0;
908: resultIterator->hint.reserved2 = 0;
909:
910: resultIterator->version = 0;
911: resultIterator->reserved = 0;
912:
913: // copy the key in the BTree when found rather than searchIterator->key to get proper case/diacriticals
914: if (foundRecord == true)
915: BlockMoveData ((Ptr)keyPtr, (Ptr)&resultIterator->key, CalcKeySize(btreePtr, keyPtr));
916: else
917: BlockMoveData ((Ptr)&searchIterator->key, (Ptr)&resultIterator->key, CalcKeySize(btreePtr, &searchIterator->key));
918: }
919:
920: err = ReleaseNode (btreePtr, &node);
921: M_ExitOnError (err);
922:
923: LogEndTime(kTraceSearchBTree, (foundRecord == false));
924:
925: if (foundRecord == false) return fsBTRecordNotFoundErr;
926: else return noErr;
927:
928:
929: /////////////////////// Error - Clean Up and Exit ///////////////////////////
930:
931: ErrorExit:
932:
933: if (recordLen != nil)
934: *recordLen = 0;
935:
936: if (resultIterator != nil)
937: {
938: resultIterator->hint.writeCount = 0;
939: resultIterator->hint.nodeNum = 0;
940: resultIterator->hint.index = 0;
941: resultIterator->hint.reserved1 = 0;
942: resultIterator->hint.reserved2 = 0;
943:
944: resultIterator->version = 0;
945: resultIterator->reserved = 0;
946: resultIterator->key.length16 = 0; // zero out two bytes to cover both types of keys
947: }
948:
949: if ( err == fsBTEmptyErr )
950: err = fsBTRecordNotFoundErr;
951:
952: LogEndTime(kTraceSearchBTree, err);
953:
954: return err;
955: }
956:
957:
958:
959: /*-------------------------------------------------------------------------------
960: Routine: BTIterateRecord - Find the first, next, previous, or last record.
961:
962: Function: Find the first, next, previous, or last record in the BTree
963:
964: Input: pathPtr - pointer to path iterate records for.
965: operation - iteration operation (first,next,prev,last)
966: iterator - pointer to iterator indicating start position
967:
968: Output: iterator - iterator is updated to indicate new position
969: newKeyPtr - pointer to buffer to copy key found by iteration
970: record - pointer to buffer to copy record found by iteration
971: recordLen - length of record
972:
973: Result: noErr - success
974: != noErr - failure
975: -------------------------------------------------------------------------------*/
976:
977: OSStatus BTIterateRecord (FCB *filePtr,
978: BTreeIterationOperation operation,
979: BTreeIterator *iterator,
980: FSBufferDescriptor *record,
981: UInt16 *recordLen )
982: {
983: OSStatus err;
984: BTreeControlBlockPtr btreePtr;
985: BTreeKeyPtr keyPtr;
986: RecordPtr recordPtr;
987: UInt16 len;
988:
989: Boolean foundRecord;
990: UInt32 nodeNum;
991:
992: BlockDescriptor left, node, right;
993: UInt16 index;
994:
995:
996: LogStartTime(kTraceGetBTreeRecord);
997:
998: ////////////////////////// Priliminary Checks ///////////////////////////////
999:
1000: left.buffer = nil;
1001: right.buffer = nil;
1002: node.buffer = nil;
1003:
1004:
1005: if (filePtr == nil)
1006: {
1007: return paramErr;
1008: }
1009:
1010: btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
1011: if (btreePtr == nil)
1012: {
1013: return fsBTInvalidFileErr; //�� handle properly
1014: }
1015:
1016: #if TARGET_OS_RHAPSODY
1017: RequireFileLock(btreePtr->fileRefNum, true);
1018: #endif
1019:
1020: if ((operation != kBTreeFirstRecord) &&
1021: (operation != kBTreeNextRecord) &&
1022: (operation != kBTreeCurrentRecord) &&
1023: (operation != kBTreePrevRecord) &&
1024: (operation != kBTreeLastRecord))
1025: {
1026: err = fsInvalidIterationMovmentErr;
1027: goto ErrorExit;
1028: }
1029:
1030: /////////////////////// Find First or Last Record ///////////////////////////
1031:
1032: if ((operation == kBTreeFirstRecord) || (operation == kBTreeLastRecord))
1033: {
1034: if (operation == kBTreeFirstRecord) nodeNum = btreePtr->firstLeafNode;
1035: else nodeNum = btreePtr->lastLeafNode;
1036:
1037: if (nodeNum == 0)
1038: {
1039: err = fsBTEmptyErr;
1040: goto ErrorExit;
1041: }
1042:
1043: err = GetNode (btreePtr, nodeNum, &node);
1044: M_ExitOnError (err);
1045:
1046: if ( ((NodeDescPtr) node.buffer)->type != kLeafNode ||
1047: ((NodeDescPtr) node.buffer)->numRecords <= 0 )
1048: {
1049: err = ReleaseNode (btreePtr, &node);
1050: M_ExitOnError (err);
1051:
1052: err = fsBTInvalidNodeErr;
1053: goto ErrorExit;
1054: }
1055:
1056: if (operation == kBTreeFirstRecord) index = 0;
1057: else index = ((BTNodeDescriptor*) node.buffer)->numRecords - 1;
1058:
1059: goto CopyData; //�� is there a cleaner way?
1060: }
1061:
1062:
1063: //////////////////////// Find Iterator Position /////////////////////////////
1064:
1065: err = FindIteratorPosition (btreePtr, iterator,
1066: &left, &node, &right, &nodeNum, &index, &foundRecord);
1067: M_ExitOnError (err);
1068:
1069:
1070: ///////////////////// Find Next Or Previous Record //////////////////////////
1071:
1072: if (operation == kBTreePrevRecord)
1073: {
1074: if (index > 0)
1075: {
1076: --index;
1077: }
1078: else
1079: {
1080: if (left.buffer == nil)
1081: {
1082: nodeNum = ((NodeDescPtr) node.buffer)->bLink;
1083: if ( nodeNum > 0)
1084: {
1085: err = GetNode (btreePtr, nodeNum, &left);
1086: M_ExitOnError (err);
1087: } else {
1088: err = fsBTStartOfIterationErr;
1089: goto ErrorExit;
1090: }
1091: }
1092: // Before we stomp on "right", we'd better release it if needed
1093: if (right.buffer != nil) {
1094: err = ReleaseNode(btreePtr, &right);
1095: M_ExitOnError(err);
1096: }
1097: right = node;
1098: node = left;
1099: left.buffer = nil;
1100: index = ((NodeDescPtr) node.buffer)->numRecords -1;
1101: }
1102: }
1103: else if (operation == kBTreeNextRecord)
1104: {
1105: if ((foundRecord != true) &&
1106: (((NodeDescPtr) node.buffer)->fLink == 0) &&
1107: (index == ((NodeDescPtr) node.buffer)->numRecords))
1108: {
1109: err = fsBTEndOfIterationErr;
1110: goto ErrorExit;
1111: }
1112:
1113: // we did not find the record but the index is already positioned correctly
1114: if ((foundRecord == false) && (index != ((NodeDescPtr) node.buffer)->numRecords))
1115: goto CopyData;
1116:
1117: // we found the record OR we have to look in the next node
1118: if (index < ((NodeDescPtr) node.buffer)->numRecords -1)
1119: {
1120: ++index;
1121: }
1122: else
1123: {
1124: if (right.buffer == nil)
1125: {
1126: nodeNum = ((NodeDescPtr) node.buffer)->fLink;
1127: if ( nodeNum > 0)
1128: {
1129: err = GetNode (btreePtr, nodeNum, &right);
1130: M_ExitOnError (err);
1131: } else {
1132: err = fsBTEndOfIterationErr;
1133: goto ErrorExit;
1134: }
1135: }
1136: // Before we stomp on "left", we'd better release it if needed
1137: if (left.buffer != nil) {
1138: err = ReleaseNode(btreePtr, &left);
1139: M_ExitOnError(err);
1140: }
1141: left = node;
1142: node = right;
1143: right.buffer = nil;
1144: index = 0;
1145: }
1146: }
1147: else // operation == kBTreeCurrentRecord
1148: {
1149: // make sure we have something... <CS9>
1150: if ((foundRecord != true) &&
1151: (index >= ((NodeDescPtr) node.buffer)->numRecords))
1152: {
1153: err = fsBTEndOfIterationErr;
1154: goto ErrorExit;
1155: }
1156: }
1157:
1158: //////////////////// Copy Record And Update Iterator ////////////////////////
1159:
1160: CopyData:
1161:
1162: // added check for errors <CS9>
1163: err = GetRecordByIndex (btreePtr, node.buffer, index, &keyPtr, &recordPtr, &len);
1164: M_ExitOnError (err);
1165:
1166: if (recordLen != nil) *recordLen = len;
1167:
1168: if (record != nil)
1169: {
1170: ByteCount recordSize;
1171:
1172: recordSize = record->itemCount * record->itemSize;
1173:
1174: PanicIf(len > recordSize, "\pBTIterateRecord: truncating record!");
1175:
1176: if (len > recordSize) len = recordSize;
1177:
1178: BlockMoveData (recordPtr, record->bufferAddress, len);
1179: }
1180:
1181: if (iterator != nil) // first & last do not require iterator
1182: {
1183: iterator->hint.writeCount = btreePtr->writeCount;
1184: iterator->hint.nodeNum = nodeNum;
1185: iterator->hint.index = index;
1186: iterator->hint.reserved1 = 0;
1187: iterator->hint.reserved2 = 0;
1188:
1189: iterator->version = 0;
1190: iterator->reserved = 0;
1191:
1192: BlockMoveData ((Ptr)keyPtr, (Ptr)&iterator->key, CalcKeySize(btreePtr, keyPtr));
1193: }
1194:
1195:
1196: ///////////////////////////// Release Nodes /////////////////////////////////
1197:
1198: err = ReleaseNode (btreePtr, &node);
1199: M_ExitOnError (err);
1200:
1201: if (left.buffer != nil)
1202: {
1203: err = ReleaseNode (btreePtr, &left);
1204: M_ExitOnError (err);
1205: }
1206:
1207: if (right.buffer != nil)
1208: {
1209: err = ReleaseNode (btreePtr, &right);
1210: M_ExitOnError (err);
1211: }
1212:
1213: LogEndTime(kTraceGetBTreeRecord, noErr);
1214:
1215: return noErr;
1216:
1217: /////////////////////// Error - Clean Up and Exit ///////////////////////////
1218:
1219: ErrorExit:
1220:
1221: (void) ReleaseNode (btreePtr, &left);
1222: (void) ReleaseNode (btreePtr, &node);
1223: (void) ReleaseNode (btreePtr, &right);
1224:
1225: if (recordLen != nil)
1226: *recordLen = 0;
1227:
1228: if (iterator != nil)
1229: {
1230: iterator->hint.writeCount = 0;
1231: iterator->hint.nodeNum = 0;
1232: iterator->hint.index = 0;
1233: iterator->hint.reserved1 = 0;
1234: iterator->hint.reserved2 = 0;
1235:
1236: iterator->version = 0;
1237: iterator->reserved = 0;
1238: iterator->key.length16 = 0;
1239: }
1240:
1241: if ( err == fsBTEmptyErr || err == fsBTEndOfIterationErr )
1242: err = fsBTRecordNotFoundErr;
1243:
1244: LogEndTime(kTraceGetBTreeRecord, err);
1245:
1246: return err;
1247: }
1248:
1249:
1250: //////////////////////////////// BTInsertRecord /////////////////////////////////
1251:
1252: OSStatus BTInsertRecord (FCB *filePtr,
1253: BTreeIterator *iterator,
1254: FSBufferDescriptor *record,
1255: UInt16 recordLen )
1256: {
1257: OSStatus err;
1258: BTreeControlBlockPtr btreePtr;
1259: TreePathTable treePathTable;
1260: SInt32 nodesNeeded;
1261: BlockDescriptor nodeRec;
1262: UInt32 insertNodeNum;
1263: UInt16 index;
1264: Boolean recordFit;
1265:
1266:
1267: ////////////////////////// Priliminary Checks ///////////////////////////////
1268:
1269: nodeRec.buffer = nil; // so we can call ReleaseNode
1270:
1271: err = CheckInsertParams (filePtr, iterator, record, recordLen);
1272: if (err != noErr)
1273: return err;
1274:
1275: LogStartTime(kTraceInsertBTreeRecord);
1276:
1277: btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
1278:
1279: #if TARGET_OS_RHAPSODY
1280: RequireFileLock(btreePtr->fileRefNum, false);
1281: #endif
1282:
1283: ///////////////////////// Find Insert Position //////////////////////////////
1284:
1285: // always call SearchTree for Insert
1286: err = SearchTree (btreePtr, &iterator->key, treePathTable, &insertNodeNum, &nodeRec, &index);
1287:
1288: switch (err) // set/replace/insert decision point
1289: {
1290: case noErr: err = fsBTDuplicateRecordErr;
1291: goto ErrorExit;
1292:
1293: case fsBTRecordNotFoundErr: break;
1294:
1295: case fsBTEmptyErr: // if tree empty add 1st leaf node
1296:
1297: if (btreePtr->freeNodes == 0)
1298: {
1299: err = ExtendBTree (btreePtr, btreePtr->totalNodes + 1);
1300: M_ExitOnError (err);
1301: }
1302:
1303: err = AllocateNode (btreePtr, &insertNodeNum);
1304: M_ExitOnError (err);
1305:
1306: err = GetNewNode (btreePtr, insertNodeNum, &nodeRec);
1307: M_ExitOnError (err);
1308:
1309: ((NodeDescPtr)nodeRec.buffer)->type = kLeafNode;
1310: ((NodeDescPtr)nodeRec.buffer)->height = 1;
1311:
1312: recordFit = InsertKeyRecord (btreePtr, nodeRec.buffer, 0,
1313: &iterator->key, KeyLength(btreePtr, &iterator->key),
1314: record->bufferAddress, recordLen );
1315: if (recordFit != true)
1316: {
1317: err = fsBTRecordTooLargeErr;
1318: goto ErrorExit;
1319: }
1320:
1321: err = UpdateNode (btreePtr, &nodeRec);
1322: M_ExitOnError (err);
1323:
1324: // update BTreeControlBlock
1325: btreePtr->treeDepth = 1;
1326: btreePtr->rootNode = insertNodeNum;
1327: btreePtr->firstLeafNode = insertNodeNum;
1328: btreePtr->lastLeafNode = insertNodeNum;
1329: M_BTreeHeaderDirty (btreePtr);
1330:
1331: goto Success;
1332:
1333: default: goto ErrorExit;
1334: }
1335:
1336: if (index > 0)
1337: {
1338: recordFit = InsertKeyRecord (btreePtr, nodeRec.buffer, index,
1339: &iterator->key, KeyLength(btreePtr, &iterator->key),
1340: record->bufferAddress, recordLen);
1341: if (recordFit == true)
1342: {
1343: err = UpdateNode (btreePtr, &nodeRec);
1344: M_ExitOnError (err);
1345:
1346: goto Success;
1347: }
1348: }
1349:
1350: /////////////////////// Extend File If Necessary ////////////////////////////
1351:
1352: nodesNeeded = btreePtr->treeDepth + 1 - btreePtr->freeNodes; //�� math limit
1353: if (nodesNeeded > 0)
1354: {
1355: nodesNeeded += btreePtr->totalNodes;
1356: if (nodesNeeded > CalcMapBits (btreePtr)) // we'll need to add a map node too!
1357: ++nodesNeeded;
1358:
1359: err = ExtendBTree (btreePtr, nodesNeeded);
1360: M_ExitOnError (err);
1361: }
1362:
1363: // no need to delete existing record
1364:
1365: err = InsertTree (btreePtr, treePathTable, &iterator->key, record->bufferAddress,
1366: recordLen, &nodeRec, index, 1, kInsertRecord, &insertNodeNum);
1367: M_ExitOnError (err);
1368:
1369:
1370: //////////////////////////////// Success ////////////////////////////////////
1371:
1372: Success:
1373: ++btreePtr->leafRecords;
1374: M_BTreeHeaderDirty (btreePtr);
1375:
1376: // create hint
1377: iterator->hint.writeCount = btreePtr->writeCount; //�� currently unused
1378: iterator->hint.nodeNum = insertNodeNum;
1379: iterator->hint.index = 0; // unused
1380: iterator->hint.reserved1 = 0;
1381: iterator->hint.reserved2 = 0;
1382:
1383: LogEndTime(kTraceInsertBTreeRecord, noErr);
1384:
1385: return noErr;
1386:
1387:
1388: ////////////////////////////// Error Exit ///////////////////////////////////
1389:
1390: ErrorExit:
1391:
1392: (void) ReleaseNode (btreePtr, &nodeRec);
1393:
1394: iterator->hint.writeCount = 0;
1395: iterator->hint.nodeNum = 0;
1396: iterator->hint.index = 0;
1397: iterator->hint.reserved1 = 0;
1398: iterator->hint.reserved2 = 0;
1399:
1400: if (err == fsBTEmptyErr)
1401: err = fsBTRecordNotFoundErr;
1402:
1403: LogEndTime(kTraceInsertBTreeRecord, err);
1404:
1405: return err;
1406: }
1407:
1408:
1409:
1410: ////////////////////////////////// BTSetRecord //////////////////////////////////
1411:
1412: OSStatus BTSetRecord (FCB *filePtr,
1413: BTreeIterator *iterator,
1414: FSBufferDescriptor *record,
1415: UInt16 recordLen )
1416: {
1417: OSStatus err;
1418: BTreeControlBlockPtr btreePtr;
1419: TreePathTable treePathTable;
1420: SInt32 nodesNeeded;
1421: BlockDescriptor nodeRec;
1422: UInt32 insertNodeNum;
1423: UInt16 index;
1424: Boolean recordFound = false;
1425: Boolean recordFit;
1426: Boolean operation;
1427: Boolean validHint;
1428:
1429:
1430: ////////////////////////// Priliminary Checks ///////////////////////////////
1431:
1432: nodeRec.buffer = nil; // so we can call ReleaseNode
1433:
1434: err = CheckInsertParams (filePtr, iterator, record, recordLen);
1435: if (err != noErr)
1436: return err;
1437:
1438: btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
1439:
1440: #if TARGET_OS_RHAPSODY
1441: RequireFileLock(btreePtr->fileRefNum, false);
1442: #endif
1443:
1444: ///////////////////////// Find Insert Position //////////////////////////////
1445:
1446: err = IsItAHint (btreePtr, iterator, &validHint);
1447: M_ExitOnError (err);
1448:
1449: if (validHint)
1450: {
1451: insertNodeNum = iterator->hint.nodeNum;
1452:
1453: err = GetNode (btreePtr, insertNodeNum, &nodeRec);
1454: if( err == noErr )
1455: {
1456: err = TrySimpleReplace (btreePtr, nodeRec.buffer, iterator, record, recordLen, &recordFit);
1457: M_ExitOnError (err);
1458:
1459: if (recordFit)
1460: {
1461: err = UpdateNode (btreePtr, &nodeRec);
1462: M_ExitOnError (err);
1463:
1464: recordFound = true;
1465: ++btreePtr->numValidHints;
1466: goto Success;
1467: } // else
1468: else
1469: {
1470: (void) BTInvalidateHint( iterator );
1471: }
1472:
1473: err = ReleaseNode (btreePtr, &nodeRec);
1474: M_ExitOnError (err);
1475: }
1476: }
1477:
1478: err = SearchTree (btreePtr, &iterator->key, treePathTable, &insertNodeNum, &nodeRec, &index);
1479:
1480: switch (err) // set/replace/insert decision point
1481: {
1482: case noErr: recordFound = true;
1483: break;
1484:
1485: case fsBTRecordNotFoundErr: break;
1486:
1487: case fsBTEmptyErr: // if tree empty add 1st leaf node
1488:
1489: if (btreePtr->freeNodes == 0)
1490: {
1491: err = ExtendBTree (btreePtr, btreePtr->totalNodes + 1);
1492: M_ExitOnError (err);
1493: }
1494:
1495: err = AllocateNode (btreePtr, &insertNodeNum);
1496: M_ExitOnError (err);
1497:
1498: err = GetNewNode (btreePtr, insertNodeNum, &nodeRec);
1499: M_ExitOnError (err);
1500:
1501: ((NodeDescPtr)nodeRec.buffer)->type = kLeafNode;
1502: ((NodeDescPtr)nodeRec.buffer)->height = 1;
1503:
1504: recordFit = InsertKeyRecord (btreePtr, nodeRec.buffer, 0,
1505: &iterator->key, KeyLength(btreePtr, &iterator->key),
1506: record->bufferAddress, recordLen );
1507: if (recordFit != true)
1508: {
1509: err = fsBTRecordTooLargeErr;
1510: goto ErrorExit;
1511: }
1512:
1513: err = UpdateNode (btreePtr, &nodeRec);
1514: M_ExitOnError (err);
1515:
1516: // update BTreeControlBlock
1517: btreePtr->rootNode = insertNodeNum;
1518: btreePtr->treeDepth = 1;
1519: btreePtr->flags |= kBTHeaderDirty;
1520:
1521: goto Success;
1522:
1523: default: goto ErrorExit;
1524: }
1525:
1526:
1527: if (recordFound == true) // Simple Replace - optimization avoids unecessary ExtendBTree
1528: {
1529: err = TrySimpleReplace (btreePtr, nodeRec.buffer, iterator, record, recordLen, &recordFit);
1530: M_ExitOnError (err);
1531:
1532: if (recordFit)
1533: {
1534: err = UpdateNode (btreePtr, &nodeRec);
1535: M_ExitOnError (err);
1536:
1537: goto Success;
1538: }
1539: }
1540:
1541:
1542: /////////////////////// Extend File If Necessary ////////////////////////////
1543:
1544: nodesNeeded = btreePtr->treeDepth + 1 - btreePtr->freeNodes; //�� math limit
1545: if (nodesNeeded > 0)
1546: {
1547: nodesNeeded += btreePtr->totalNodes;
1548: if (nodesNeeded > CalcMapBits (btreePtr)) // we'll need to add a map node too!
1549: ++nodesNeeded;
1550:
1551: err = ExtendBTree (btreePtr, nodesNeeded);
1552: M_ExitOnError (err);
1553: }
1554:
1555:
1556: if (recordFound == true) // Delete existing record
1557: {
1558: DeleteRecord (btreePtr, nodeRec.buffer, index);
1559: operation = kReplaceRecord;
1560: } else {
1561: operation = kInsertRecord;
1562: }
1563:
1564: err = InsertTree (btreePtr, treePathTable, &iterator->key, record->bufferAddress,
1565: recordLen, &nodeRec, index, 1, operation, &insertNodeNum);
1566: M_ExitOnError (err);
1567:
1568:
1569: Success:
1570: if (recordFound == false)
1571: {
1572: ++btreePtr->leafRecords;
1573: M_BTreeHeaderDirty (btreePtr);
1574: }
1575:
1576: // create hint
1577: iterator->hint.writeCount = btreePtr->writeCount; //�� currently unused
1578: iterator->hint.nodeNum = insertNodeNum;
1579: iterator->hint.index = 0; // unused
1580: iterator->hint.reserved1 = 0;
1581: iterator->hint.reserved2 = 0;
1582:
1583: return noErr;
1584:
1585:
1586: ////////////////////////////// Error Exit ///////////////////////////////////
1587:
1588: ErrorExit:
1589:
1590: (void) ReleaseNode (btreePtr, &nodeRec);
1591:
1592: iterator->hint.writeCount = 0;
1593: iterator->hint.nodeNum = 0;
1594: iterator->hint.index = 0;
1595: iterator->hint.reserved1 = 0;
1596: iterator->hint.reserved2 = 0;
1597:
1598: return err;
1599: }
1600:
1601:
1602:
1603: //////////////////////////////// BTReplaceRecord ////////////////////////////////
1604:
1605: OSStatus BTReplaceRecord (FCB *filePtr,
1606: BTreeIterator *iterator,
1607: FSBufferDescriptor *record,
1608: UInt16 recordLen )
1609: {
1610: OSStatus err;
1611: BTreeControlBlockPtr btreePtr;
1612: TreePathTable treePathTable;
1613: SInt32 nodesNeeded;
1614: BlockDescriptor nodeRec;
1615: UInt32 insertNodeNum;
1616: UInt16 index;
1617: Boolean recordFit;
1618: Boolean validHint;
1619:
1620:
1621: ////////////////////////// Priliminary Checks ///////////////////////////////
1622:
1623: nodeRec.buffer = nil; // so we can call ReleaseNode
1624:
1625: err = CheckInsertParams (filePtr, iterator, record, recordLen);
1626: if (err != noErr)
1627: return err;
1628:
1629: LogStartTime(kTraceReplaceBTreeRecord);
1630:
1631: btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
1632:
1633: #if TARGET_OS_RHAPSODY
1634: RequireFileLock(btreePtr->fileRefNum, false);
1635: #endif
1636:
1637: ////////////////////////////// Take A Hint //////////////////////////////////
1638:
1639: err = IsItAHint (btreePtr, iterator, &validHint);
1640: M_ExitOnError (err);
1641:
1642: if (validHint)
1643: {
1644: insertNodeNum = iterator->hint.nodeNum;
1645:
1646: err = GetNode (btreePtr, insertNodeNum, &nodeRec);
1647: if( err == noErr )
1648: {
1649: err = TrySimpleReplace (btreePtr, nodeRec.buffer, iterator, record, recordLen, &recordFit);
1650: M_ExitOnError (err);
1651:
1652: if (recordFit)
1653: {
1654: err = UpdateNode (btreePtr, &nodeRec);
1655: M_ExitOnError (err);
1656:
1657: ++btreePtr->numValidHints;
1658:
1659: goto Success;
1660: }
1661: else
1662: {
1663: (void) BTInvalidateHint( iterator );
1664: }
1665:
1666: err = ReleaseNode (btreePtr, &nodeRec);
1667: M_ExitOnError (err);
1668: }
1669: else
1670: {
1671: (void) BTInvalidateHint( iterator );
1672: }
1673: }
1674:
1675:
1676: ////////////////////////////// Get A Clue ///////////////////////////////////
1677:
1678: err = SearchTree (btreePtr, &iterator->key, treePathTable, &insertNodeNum, &nodeRec, &index);
1679: M_ExitOnError (err); // record must exit for Replace
1680:
1681: // optimization - if simple replace will work then don't extend btree
1682: // �� if we tried this before, and failed because it wouldn't fit then we shouldn't try this again...
1683:
1684: err = TrySimpleReplace (btreePtr, nodeRec.buffer, iterator, record, recordLen, &recordFit);
1685: M_ExitOnError (err);
1686:
1687: if (recordFit)
1688: {
1689: err = UpdateNode (btreePtr, &nodeRec);
1690: M_ExitOnError (err);
1691:
1692: goto Success;
1693: }
1694:
1695:
1696: //////////////////////////// Make Some Room /////////////////////////////////
1697:
1698: nodesNeeded = btreePtr->treeDepth + 1 - btreePtr->freeNodes; //�� math limit
1699: if (nodesNeeded > 0)
1700: {
1701: nodesNeeded += btreePtr->totalNodes;
1702: if (nodesNeeded > CalcMapBits (btreePtr)) // we'll need to add a map node too!
1703: ++nodesNeeded;
1704:
1705: err = ExtendBTree (btreePtr, nodesNeeded);
1706: M_ExitOnError (err);
1707: }
1708:
1709:
1710: DeleteRecord (btreePtr, nodeRec.buffer, index); // delete existing key/record
1711:
1712: err = InsertTree (btreePtr, treePathTable, &iterator->key, record->bufferAddress,
1713: recordLen, &nodeRec, index, 1, kReplaceRecord, &insertNodeNum);
1714: M_ExitOnError (err);
1715:
1716: Success:
1717: // create hint
1718: iterator->hint.writeCount = btreePtr->writeCount; //�� currently unused
1719: iterator->hint.nodeNum = insertNodeNum;
1720: iterator->hint.index = 0; // unused
1721: iterator->hint.reserved1 = 0;
1722: iterator->hint.reserved2 = 0;
1723:
1724: LogEndTime(kTraceReplaceBTreeRecord, noErr);
1725:
1726: return noErr;
1727:
1728:
1729: ////////////////////////////// Error Exit ///////////////////////////////////
1730:
1731: ErrorExit:
1732:
1733: (void) ReleaseNode (btreePtr, &nodeRec);
1734:
1735: iterator->hint.writeCount = 0;
1736: iterator->hint.nodeNum = 0;
1737: iterator->hint.index = 0;
1738: iterator->hint.reserved1 = 0;
1739: iterator->hint.reserved2 = 0;
1740:
1741:
1742: LogEndTime(kTraceReplaceBTreeRecord, err);
1743:
1744: return err;
1745: }
1746:
1747:
1748:
1749: //////////////////////////////// BTDeleteRecord /////////////////////////////////
1750:
1751: OSStatus BTDeleteRecord (FCB *filePtr,
1752: BTreeIterator *iterator )
1753: {
1754: OSStatus err;
1755: BTreeControlBlockPtr btreePtr;
1756: TreePathTable treePathTable;
1757: BlockDescriptor nodeRec;
1758: UInt32 nodeNum;
1759: UInt16 index;
1760:
1761: LogStartTime(kTraceDeleteBTreeRecord);
1762:
1763: ////////////////////////// Priliminary Checks ///////////////////////////////
1764:
1765: nodeRec.buffer = nil; // so we can call ReleaseNode
1766:
1767: M_ReturnErrorIf (filePtr == nil, paramErr);
1768: M_ReturnErrorIf (iterator == nil, paramErr);
1769:
1770: btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
1771: if (btreePtr == nil)
1772: {
1773: err = fsBTInvalidFileErr;
1774: goto ErrorExit;
1775: }
1776:
1777: #if TARGET_OS_RHAPSODY
1778: RequireFileLock(btreePtr->fileRefNum, false);
1779: #endif
1780:
1781: #if SupportsKeyDescriptors
1782: if (btreePtr->keyDescPtr != nil)
1783: {
1784: err = CheckKey (&iterator->key, btreePtr->keyDescPtr, btreePtr->maxKeyLength);
1785: M_ExitOnError (err);
1786: }
1787: #endif
1788:
1789: /////////////////////////////// Find Key ////////////////////////////////////
1790:
1791: //�� check hint for simple delete case (index > 0, numRecords > 2)
1792:
1793: err = SearchTree (btreePtr, &iterator->key, treePathTable, &nodeNum, &nodeRec, &index);
1794: M_ExitOnError (err); // record must exit for Delete
1795:
1796:
1797: ///////////////////////////// Delete Record /////////////////////////////////
1798:
1799: err = DeleteTree (btreePtr, treePathTable, &nodeRec, index, 1);
1800: M_ExitOnError (err);
1801:
1802: --btreePtr->leafRecords;
1803: M_BTreeHeaderDirty (btreePtr);
1804:
1805: iterator->hint.nodeNum = 0;
1806:
1807: LogEndTime(kTraceDeleteBTreeRecord, noErr);
1808:
1809: return noErr;
1810:
1811: ////////////////////////////// Error Exit ///////////////////////////////////
1812:
1813: ErrorExit:
1814: (void) ReleaseNode (btreePtr, &nodeRec);
1815:
1816: LogEndTime(kTraceDeleteBTreeRecord, err);
1817:
1818: return err;
1819: }
1820:
1821:
1822:
1823: OSStatus BTGetInformation (FCB *filePtr,
1824: UInt16 version,
1825: BTreeInfoRec *info )
1826: {
1827: #pragma unused (version)
1828:
1829: BTreeControlBlockPtr btreePtr;
1830:
1831:
1832: M_ReturnErrorIf (filePtr == nil, paramErr);
1833:
1834: btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
1835:
1836: #if TARGET_OS_RHAPSODY
1837: RequireFileLock(btreePtr->fileRefNum, true);
1838: #endif
1839:
1840: M_ReturnErrorIf (btreePtr == nil, fsBTInvalidFileErr);
1841: M_ReturnErrorIf (info == nil, paramErr);
1842:
1843: //�� check version?
1844:
1845: info->nodeSize = btreePtr->nodeSize;
1846: info->maxKeyLength = btreePtr->maxKeyLength;
1847: info->treeDepth = btreePtr->treeDepth;
1848: info->numRecords = btreePtr->leafRecords;
1849: info->numNodes = btreePtr->totalNodes;
1850: info->numFreeNodes = btreePtr->freeNodes;
1851: info->keyDescriptor = btreePtr->keyDescPtr; //�� this won't do at all...
1852: info->reserved = 0;
1853:
1854: if (btreePtr->keyDescPtr == nil)
1855: info->keyDescLength = 0;
1856: else
1857: info->keyDescLength = (UInt32) btreePtr->keyDescPtr->length;
1858:
1859: return noErr;
1860: }
1861:
1862:
1863:
1864: /*-------------------------------------------------------------------------------
1865: Routine: BTFlushPath - Flush BTreeControlBlock to Header Node.
1866:
1867: Function: Brief_description_of_the_function_and_any_side_effects
1868:
1869:
1870: Input: pathPtr - pointer to path control block for B*Tree file to flush
1871:
1872: Output: none
1873:
1874: Result: noErr - success
1875: != noErr - failure
1876: -------------------------------------------------------------------------------*/
1877:
1878: OSStatus BTFlushPath (FCB *filePtr)
1879: {
1880: OSStatus err;
1881: BTreeControlBlockPtr btreePtr;
1882:
1883:
1884: LogStartTime(kTraceFlushBTree);
1885:
1886: M_ReturnErrorIf (filePtr == nil, paramErr);
1887:
1888: btreePtr = (BTreeControlBlockPtr) filePtr->fcbBTCBPtr;
1889:
1890: M_ReturnErrorIf (btreePtr == nil, fsBTInvalidFileErr);
1891:
1892: #if TARGET_OS_RHAPSODY
1893: RequireFileLock(btreePtr->fileRefNum, false);
1894: #endif
1895:
1896: err = UpdateHeader (btreePtr);
1897:
1898: LogEndTime(kTraceFlushBTree, err);
1899:
1900: return err;
1901: }
1902:
1903:
1904:
1905: /*-------------------------------------------------------------------------------
1906: Routine: BTInvalidateHint - Invalidates the hint within a BTreeInterator.
1907:
1908: Function: Invalidates the hint within a BTreeInterator.
1909:
1910:
1911: Input: iterator - pointer to BTreeIterator
1912:
1913: Output: iterator - iterator with the hint.nodeNum cleared
1914:
1915: Result: noErr - success
1916: paramErr - iterator == nil
1917: -------------------------------------------------------------------------------*/
1918:
1919:
1920: OSStatus BTInvalidateHint (BTreeIterator *iterator )
1921: {
1922: if (iterator == nil)
1923: return paramErr;
1924:
1925: iterator->hint.nodeNum = 0;
1926:
1927: return noErr;
1928: }
1929:
1930:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.