|
|
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: BTreeAllocate.c
27:
28: Contains: BTree Node Allocation routines for the BTree Module.
29:
30: Version: xxx put the technology version here xxx
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: (djb) Don Brady
47: (ser) Scott Roberts
48: (msd) Mark Day
49:
50: Change History (most recent first):
51:
52: <CS3> 11/24/97 djb Remove some debug code (Panic calls).
53: <CS2> 7/24/97 djb CallbackProcs now take refnum instead of an FCB.
54: <CS1> 4/23/97 djb first checked in
55:
56: <HFS2> 2/19/97 djb Change E_BadNodeType to fsBTBadNodeType.
57: <HFS1> 12/19/96 djb first checked in
58:
59: History applicable to original Scarecrow Design:
60:
61: <4> 10/25/96 ser Changing for new VFPI
62: <3> 10/18/96 ser Converting over VFPI changes
63: <2> 1/10/96 msd Change 64-bit math to use real function names from Math64.i.
64: <1> 10/18/95 rst Moved from Scarecrow project.
65:
66: <8> 1/12/95 wjk Adopt Model FileSystem changes in D5.
67: <7> 9/30/94 prp Get in sync with D2 interface changes.
68: <6> 7/22/94 wjk Convert to the new set of header files.
69: <5> 8/31/93 prp Use U64SetU instead of S64Set.
70: <4> 5/21/93 gs Fix ExtendBTree bug.
71: <3> 5/10/93 gs Fix pointer arithmetic bug in AllocateNode.
72: <2> 3/23/93 gs finish ExtendBTree routine.
73: <1> 2/8/93 gs first checked in
74: <0> 1/1/93 gs begin AllocateNode and FreeNode
75:
76: */
77:
78: #include "../headers/BTreesPrivate.h"
79:
80: ///////////////////// Routines Internal To BTreeAllocate.c //////////////////////
81:
82: OSStatus GetMapNode (BTreeControlBlockPtr btreePtr,
83: BlockDescriptor *nodePtr,
84: UInt16 **mapPtr,
85: UInt16 *mapSize );
86:
87: /////////////////////////////////////////////////////////////////////////////////
88:
89: /*-------------------------------------------------------------------------------
90:
91: Routine: AllocateNode - Find Free Node, Mark It Used, and Return Node Number.
92:
93: Function: Searches the map records for the first free node, marks it "in use" and
94: returns the node number found. This routine should really only be called
95: when we know there are free blocks, otherwise it's just a waste of time.
96:
97: Note: We have to examine map nodes a word at a time rather than a long word
98: because the External BTree Mgr used map records that were not an integral
99: number of long words. Too bad. In our spare time could develop a more
100: sophisticated algorithm that read map records by long words (and long
101: word aligned) and handled the spare bytes at the beginning and end
102: appropriately.
103:
104: Input: btreePtr - pointer to control block for BTree file
105:
106: Output: nodeNum - number of node allocated
107:
108:
109: Result: noErr - success
110: fsBTNoMoreMapNodesErr - no free blocks were found
111: != noErr - failure
112: -------------------------------------------------------------------------------*/
113:
114: OSStatus AllocateNode (BTreeControlBlockPtr btreePtr, UInt32 *nodeNum)
115: {
116: OSStatus err;
117: BlockDescriptor node;
118: UInt16 *mapPtr, *pos;
119: UInt16 mapSize, size;
120: UInt16 freeWord;
121: UInt16 mask;
122: UInt16 bitOffset;
123: UInt32 nodeNumber;
124:
125:
126: nodeNumber = 0; // first node number of header map record
127: node.buffer = nil; // clear node.buffer to get header node
128: // - and for ErrorExit
129:
130: while (true)
131: {
132: err = GetMapNode (btreePtr, &node, &mapPtr, &mapSize);
133: M_ExitOnError (err);
134:
135: //////////////////////// Find Word with Free Bit ////////////////////////////
136:
137: pos = mapPtr;
138: size = mapSize;
139: size >>= 1; // convert to number of words
140: //�� assumes mapRecords contain an integral number of words
141:
142: while ( size-- )
143: {
144: if ( *pos++ != 0xFFFF ) // assume test fails, and increment pos
145: break;
146: }
147:
148: --pos; // whoa! backup
149:
150: if (*pos != 0xFFFF) // hey, we got one!
151: break;
152:
153: nodeNumber += mapSize << 3; // covert to number of bits (nodes)
154: }
155:
156: ///////////////////////// Find Free Bit in Word /////////////////////////////
157:
158: freeWord = *pos;
159: bitOffset = 15;
160: mask = 0x8000;
161:
162: do {
163: if ( (freeWord & mask) == 0)
164: break;
165: mask >>= 1;
166: } while (--bitOffset);
167:
168: ////////////////////// Calculate Free Node Number ///////////////////////////
169:
170: nodeNumber += ((pos - mapPtr) << 4) + (15 - bitOffset); // (pos-mapPtr) = # of words!
171:
172:
173: ///////////////////////// Check for End of Map //////////////////////////////
174:
175: if (nodeNumber >= btreePtr->totalNodes)
176: {
177: err = fsBTFullErr;
178: goto ErrorExit;
179: }
180:
181: /////////////////////////// Allocate the Node ///////////////////////////////
182:
183: *pos |= mask; // set the map bit for the node
184:
185: err = UpdateNode (btreePtr, &node);
186: M_ExitOnError (err);
187:
188: --btreePtr->freeNodes;
189: btreePtr->flags |= kBTHeaderDirty;
190: *nodeNum = nodeNumber;
191:
192: return noErr;
193:
194: ////////////////////////////////// Error Exit ///////////////////////////////////
195:
196: ErrorExit:
197:
198: (void) ReleaseNode (btreePtr, &node);
199: *nodeNum = 0;
200:
201: return err;
202: }
203:
204:
205:
206: /*-------------------------------------------------------------------------------
207:
208: Routine: FreeNode - Clear allocation bit for node.
209:
210: Function: Finds the bit representing the node specified by nodeNum in the node
211: map and clears the bit.
212:
213:
214: Input: btreePtr - pointer to control block for BTree file
215: nodeNum - number of node to mark free
216:
217: Output: none
218:
219: Result: noErr - success
220: fsBTNoMoreMapNodesErr - node number is beyond end of node map
221: != noErr - GetNode or ReleaseNode encountered some difficulty
222: -------------------------------------------------------------------------------*/
223:
224: OSStatus FreeNode (BTreeControlBlockPtr btreePtr, UInt32 nodeNum)
225: {
226: OSStatus err;
227: BlockDescriptor node;
228: UInt32 nodeIndex;
229: UInt16 mapSize;
230: UInt16 *mapPos;
231: UInt16 bitOffset;
232:
233:
234: //////////////////////////// Find Map Record ////////////////////////////////
235: nodeIndex = 0; // first node number of header map record
236: node.buffer = nil; // invalidate node.buffer to get header node
237:
238: while (nodeNum >= nodeIndex)
239: {
240: err = GetMapNode (btreePtr, &node, &mapPos, &mapSize);
241: M_ExitOnError (err);
242:
243: nodeIndex += mapSize << 3; // covert to number of bits (nodes)
244: }
245:
246: //////////////////////////// Mark Node Free /////////////////////////////////
247:
248: nodeNum -= (nodeIndex - (mapSize << 3)); // relative to this map record
249: bitOffset = 15 - (nodeNum & 0x0000000F); // last 4 bits are bit offset
250: mapPos += nodeNum >> 4; // point to word containing map bit
251: M_ClearBitNum (*mapPos, bitOffset); // clear it
252:
253: err = UpdateNode (btreePtr, &node);
254: M_ExitOnError (err);
255:
256:
257: ++btreePtr->freeNodes;
258: btreePtr->flags |= kBTHeaderDirty; //�� how about a macro for this
259:
260: return noErr;
261:
262: ErrorExit:
263:
264: (void) ReleaseNode (btreePtr, &node);
265:
266: return err;
267: }
268:
269:
270:
271: /*-------------------------------------------------------------------------------
272:
273: Routine: ExtendBTree - Call FSAgent to extend file, and allocate necessary map nodes.
274:
275: Function: This routine calls the the FSAgent to extend the end of fork, if necessary,
276: to accomodate the number of nodes requested. It then allocates as many
277: map nodes as are necessary to account for all the nodes in the B*Tree.
278: If newTotalNodes is less than the current number of nodes, no action is
279: taken.
280:
281: Note: Internal HFS File Manager BTree Module counts on an integral number of
282: long words in map records, although they are not long word aligned.
283:
284: Input: btreePtr - pointer to control block for BTree file
285: newTotalNodes - total number of nodes the B*Tree is to extended to
286:
287: Output: none
288:
289: Result: noErr - success
290: != noErr - failure
291: -------------------------------------------------------------------------------*/
292:
293: OSStatus ExtendBTree (BTreeControlBlockPtr btreePtr,
294: UInt32 newTotalNodes )
295: {
296: OSStatus err;
297: FCB *filePtr;
298: FSSize minEOF, maxEOF;
299: UInt16 nodeSize;
300: UInt32 oldTotalNodes;
301: UInt32 newMapNodes;
302: UInt32 mapBits, totalMapBits;
303: UInt32 recStartBit;
304: UInt32 nodeNum, nextNodeNum;
305: UInt32 firstNewMapNodeNum, lastNewMapNodeNum;
306: BlockDescriptor mapNode, newNode;
307: UInt16 *mapPos;
308: UInt16 *mapStart;
309: UInt16 mapSize;
310: UInt16 mapNodeRecSize;
311: UInt32 bitInWord, bitInRecord;
312: UInt16 mapIndex;
313:
314:
315: oldTotalNodes = btreePtr->totalNodes;
316: if (newTotalNodes <= oldTotalNodes) // we're done!
317: return noErr;
318:
319: nodeSize = btreePtr->nodeSize;
320: filePtr = GetFileControlBlock(btreePtr->fileRefNum);
321:
322: mapNode.buffer = nil;
323: newNode.buffer = nil;
324:
325: mapNodeRecSize = nodeSize - sizeof(BTNodeDescriptor) - 6; // 2 bytes of free space (see note)
326:
327: //�� update for proper 64 bit arithmetic!!
328:
329:
330: //////////////////////// Count Bits In Node Map /////////////////////////////
331:
332: totalMapBits = 0;
333: do {
334: err = GetMapNode (btreePtr, &mapNode, &mapStart, &mapSize);
335: M_ExitOnError (err);
336:
337: mapBits = mapSize << 3; // mapSize (in bytes) * 8
338: recStartBit = totalMapBits; // bit number of first bit in map record
339: totalMapBits += mapBits;
340:
341: } while ( ((BTNodeDescriptor*)mapNode.buffer)->fLink != 0 );
342:
343: if (DEBUG_BUILD && totalMapBits != CalcMapBits (btreePtr))
344: Panic ("\pExtendBTree: totalMapBits != CalcMapBits");
345:
346: /////////////////////// Extend LEOF If Necessary ////////////////////////////
347:
348: minEOF = newTotalNodes * nodeSize;
349: if ( filePtr->fcbEOF < minEOF )
350: {
351: //��
352: //�� ???? Does this B*Tree pack stop working when LEOF > 2^32-1?
353: //��
354: maxEOF = ((UInt32)0xFFFFFFFFL);
355:
356: err = btreePtr->setEndOfForkProc (btreePtr->fileRefNum, minEOF, maxEOF);
357: M_ExitOnError (err);
358: }
359:
360:
361: //////////////////// Calc New Total Number Of Nodes /////////////////////////
362:
363: newTotalNodes = filePtr->fcbEOF / nodeSize; //�� hack!
364: //�� do we wish to perform any verification of newTotalNodes at this point?
365:
366: btreePtr->totalNodes = newTotalNodes; //�� do we need to update freeNodes here too?
367:
368:
369: ////////////// Calculate Number Of New Map Nodes Required ///////////////////
370:
371: newMapNodes = 0;
372: if (newTotalNodes > totalMapBits)
373: {
374: newMapNodes = (((newTotalNodes - totalMapBits) >> 3) / mapNodeRecSize) + 1;
375: firstNewMapNodeNum = oldTotalNodes;
376: lastNewMapNodeNum = firstNewMapNodeNum + newMapNodes - 1;
377: }
378: else
379: {
380: err = ReleaseNode (btreePtr, &mapNode);
381: M_ExitOnError (err);
382:
383: goto Success;
384: }
385:
386:
387: /////////////////////// Initialize New Map Nodes ////////////////////////////
388:
389: ((BTNodeDescriptor*)mapNode.buffer)->fLink = firstNewMapNodeNum;
390:
391: nodeNum = firstNewMapNodeNum;
392: while (true)
393: {
394: err = GetNewNode (btreePtr, nodeNum, &newNode);
395: M_ExitOnError (err);
396:
397: ((NodeDescPtr)newNode.buffer)->numRecords = 1;
398: ((NodeDescPtr)newNode.buffer)->type = kMapNode;
399:
400: // set free space offset
401: *(UInt16 *)((Ptr)newNode.buffer + nodeSize - 4) = nodeSize - 6;
402:
403: if (nodeNum++ == lastNewMapNodeNum)
404: break;
405:
406: ((BTNodeDescriptor*)newNode.buffer)->fLink = nodeNum; // point to next map node
407:
408: err = UpdateNode (btreePtr, &newNode);
409: M_ExitOnError (err);
410: }
411:
412: err = UpdateNode (btreePtr, &newNode);
413: M_ExitOnError (err);
414:
415:
416: ///////////////////// Mark New Map Nodes Allocated //////////////////////////
417:
418: nodeNum = firstNewMapNodeNum;
419: do {
420: bitInRecord = nodeNum - recStartBit;
421:
422: while (bitInRecord >= mapBits)
423: {
424: nextNodeNum = ((NodeDescPtr)mapNode.buffer)->fLink;
425: if ( nextNodeNum == 0)
426: {
427: err = fsBTNoMoreMapNodesErr;
428: goto ErrorExit;
429: }
430:
431: err = UpdateNode (btreePtr, &mapNode);
432: M_ExitOnError (err);
433:
434: err = GetNode (btreePtr, nextNodeNum, &mapNode);
435: M_ExitOnError (err);
436:
437: mapIndex = 0;
438:
439: mapStart = (UInt16 *) GetRecordAddress (btreePtr, mapNode.buffer, mapIndex);
440: mapSize = GetRecordSize (btreePtr, mapNode.buffer, mapIndex);
441:
442: if (DEBUG_BUILD && mapSize != M_MapRecordSize (btreePtr->nodeSize) )
443: {
444: Panic ("\pExtendBTree: mapSize != M_MapRecordSize");
445: }
446:
447: mapBits = mapSize << 3; // mapSize (in bytes) * 8
448: recStartBit = totalMapBits; // bit number of first bit in map record
449: totalMapBits += mapBits;
450:
451: bitInRecord = nodeNum - recStartBit;
452: }
453:
454: mapPos = mapStart + ((nodeNum - recStartBit) >> 4);
455: bitInWord = 15 - ((nodeNum - recStartBit) & 0x0000000F);
456: M_SetBitNum (*mapPos, bitInWord);
457:
458: ++nodeNum;
459:
460: } while (nodeNum <= lastNewMapNodeNum);
461:
462: err = UpdateNode (btreePtr, &mapNode);
463: M_ExitOnError (err);
464:
465:
466: //////////////////////////////// Success ////////////////////////////////////
467:
468: Success:
469:
470: btreePtr->totalNodes = newTotalNodes;
471: btreePtr->freeNodes += (newTotalNodes - oldTotalNodes) - newMapNodes;
472:
473: btreePtr->flags |= kBTHeaderDirty; //�� how about a macro for this
474:
475: return noErr;
476:
477:
478: ////////////////////////////// Error Exit ///////////////////////////////////
479:
480: ErrorExit:
481:
482: (void) ReleaseNode (btreePtr, &mapNode);
483: (void) ReleaseNode (btreePtr, &newNode);
484:
485: return err;
486: }
487:
488:
489:
490: /*-------------------------------------------------------------------------------
491:
492: Routine: GetMapNode - Get the next map node and pointer to the map record.
493:
494: Function: Given a BlockDescriptor to a map node in nodePtr, GetMapNode releases
495: it and gets the next node. If nodePtr->buffer is nil, then the header
496: node is retrieved.
497:
498:
499: Input: btreePtr - pointer to control block for BTree file
500: nodePtr - pointer to a BlockDescriptor of a map node
501:
502: Output: nodePtr - pointer to the BlockDescriptor for the next map node
503: mapPtr - pointer to the map record within the map node
504: mapSize - number of bytes in the map record
505:
506: Result: noErr - success
507: fsBTNoMoreMapNodesErr - we've run out of map nodes
508: fsBTInvalidNodeErr - bad node, or not node type kMapNode
509: != noErr - failure
510: -------------------------------------------------------------------------------*/
511:
512: OSStatus GetMapNode (BTreeControlBlockPtr btreePtr,
513: BlockDescriptor *nodePtr,
514: UInt16 **mapPtr,
515: UInt16 *mapSize )
516: {
517: OSStatus err;
518: UInt16 mapIndex;
519: UInt32 nextNodeNum;
520:
521: if (nodePtr->buffer != nil) // if iterator is valid...
522: {
523: nextNodeNum = ((NodeDescPtr)nodePtr->buffer)->fLink;
524: if (nextNodeNum == 0)
525: {
526: err = fsBTNoMoreMapNodesErr;
527: goto ErrorExit;
528: }
529:
530: err = ReleaseNode (btreePtr, nodePtr);
531: M_ExitOnError (err);
532:
533: err = GetNode (btreePtr, nextNodeNum, nodePtr);
534: M_ExitOnError (err);
535:
536: if ( ((NodeDescPtr)nodePtr->buffer)->type != kMapNode)
537: {
538: err = fsBTBadNodeType;
539: goto ErrorExit;
540: }
541:
542: ++btreePtr->numMapNodesRead;
543: mapIndex = 0;
544: } else {
545: err = GetNode (btreePtr, kHeaderNodeNum, nodePtr);
546: M_ExitOnError (err);
547:
548: if ( ((NodeDescPtr)nodePtr->buffer)->type != kHeaderNode)
549: {
550: err = fsBTInvalidHeaderErr; //�� or fsBTBadNodeType
551: goto ErrorExit;
552: }
553:
554: mapIndex = 2;
555: }
556:
557:
558: *mapPtr = (UInt16 *) GetRecordAddress (btreePtr, nodePtr->buffer, mapIndex);
559: *mapSize = GetRecordSize (btreePtr, nodePtr->buffer, mapIndex);
560:
561: return noErr;
562:
563:
564: ErrorExit:
565:
566: (void) ReleaseNode (btreePtr, nodePtr);
567:
568: *mapPtr = nil;
569: *mapSize = 0;
570:
571: return err;
572: }
573:
574:
575:
576: ////////////////////////////////// CalcMapBits //////////////////////////////////
577:
578: UInt32 CalcMapBits (BTreeControlBlockPtr btreePtr)
579: {
580: UInt32 mapBits;
581:
582: mapBits = M_HeaderMapRecordSize (btreePtr->nodeSize) << 3;
583:
584: while (mapBits < btreePtr->totalNodes)
585: mapBits += M_MapRecordSize (btreePtr->nodeSize) << 3;
586:
587: return mapBits;
588: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.