2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
25 Contains: BTree Node Allocation routines for the BTree Module.
27 Version: xxx put the technology version here xxx
29 Written by: Gordon Sheridan and Bill Bruffey
31 Copyright: © 1992-1999 by Apple Computer, Inc., all rights reserved.
37 Other Contact: Mark Day
39 Technology: File Systems
47 Change History (most recent first):
49 <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
50 <CS3> 11/24/97 djb Remove some debug code (Panic calls).
51 <CS2> 7/24/97 djb CallbackProcs now take refnum instead of an FCB.
52 <CS1> 4/23/97 djb first checked in
54 <HFS2> 2/19/97 djb Change E_BadNodeType to fsBTBadNodeType.
55 <HFS1> 12/19/96 djb first checked in
57 History applicable to original Scarecrow Design:
59 <4> 10/25/96 ser Changing for new VFPI
60 <3> 10/18/96 ser Converting over VFPI changes
61 <2> 1/10/96 msd Change 64-bit math to use real function names from Math64.i.
62 <1> 10/18/95 rst Moved from Scarecrow project.
64 <8> 1/12/95 wjk Adopt Model FileSystem changes in D5.
65 <7> 9/30/94 prp Get in sync with D2 interface changes.
66 <6> 7/22/94 wjk Convert to the new set of header files.
67 <5> 8/31/93 prp Use U64SetU instead of S64Set.
68 <4> 5/21/93 gs Fix ExtendBTree bug.
69 <3> 5/10/93 gs Fix pointer arithmetic bug in AllocateNode.
70 <2> 3/23/93 gs finish ExtendBTree routine.
71 <1> 2/8/93 gs first checked in
72 <0> 1/1/93 gs begin AllocateNode and FreeNode
76 #include "../../hfs_endian.h"
77 #include "../headers/BTreesPrivate.h"
79 ///////////////////// Routines Internal To BTreeAllocate.c //////////////////////
81 OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
82 BlockDescriptor
*nodePtr
,
86 /////////////////////////////////////////////////////////////////////////////////
88 /*-------------------------------------------------------------------------------
90 Routine: AllocateNode - Find Free Node, Mark It Used, and Return Node Number.
92 Function: Searches the map records for the first free node, marks it "in use" and
93 returns the node number found. This routine should really only be called
94 when we know there are free blocks, otherwise it's just a waste of time.
96 Note: We have to examine map nodes a word at a time rather than a long word
97 because the External BTree Mgr used map records that were not an integral
98 number of long words. Too bad. In our spare time could develop a more
99 sophisticated algorithm that read map records by long words (and long
100 word aligned) and handled the spare bytes at the beginning and end
103 Input: btreePtr - pointer to control block for BTree file
105 Output: nodeNum - number of node allocated
108 Result: noErr - success
109 fsBTNoMoreMapNodesErr - no free blocks were found
111 -------------------------------------------------------------------------------*/
113 OSStatus
AllocateNode (BTreeControlBlockPtr btreePtr
, UInt32
*nodeNum
)
116 BlockDescriptor node
;
117 UInt16
*mapPtr
, *pos
;
118 UInt16 mapSize
, size
;
125 nodeNumber
= 0; // first node number of header map record
126 node
.buffer
= nil
; // clear node.buffer to get header node
127 // - and for ErrorExit
131 err
= GetMapNode (btreePtr
, &node
, &mapPtr
, &mapSize
);
134 //////////////////////// Find Word with Free Bit ////////////////////////////
138 size
>>= 1; // convert to number of words
139 //\80\80 assumes mapRecords contain an integral number of words
143 if ( *pos
++ != 0xFFFF ) // assume test fails, and increment pos
147 --pos
; // whoa! backup
149 if (*pos
!= 0xFFFF) // hey, we got one!
152 nodeNumber
+= mapSize
<< 3; // covert to number of bits (nodes)
155 ///////////////////////// Find Free Bit in Word /////////////////////////////
157 freeWord
= SWAP_BE16 (*pos
);
162 if ( (freeWord
& mask
) == 0)
165 } while (--bitOffset
);
167 ////////////////////// Calculate Free Node Number ///////////////////////////
169 nodeNumber
+= ((pos
- mapPtr
) << 4) + (15 - bitOffset
); // (pos-mapPtr) = # of words!
172 ///////////////////////// Check for End of Map //////////////////////////////
174 if (nodeNumber
>= btreePtr
->totalNodes
)
180 /////////////////////////// Allocate the Node ///////////////////////////////
182 *pos
|= SWAP_BE16 (mask
); // set the map bit for the node
184 err
= UpdateNode (btreePtr
, &node
, 0, kLockTransaction
);
187 --btreePtr
->freeNodes
;
188 btreePtr
->flags
|= kBTHeaderDirty
;
189 *nodeNum
= nodeNumber
;
193 ////////////////////////////////// Error Exit ///////////////////////////////////
197 (void) ReleaseNode (btreePtr
, &node
);
205 /*-------------------------------------------------------------------------------
207 Routine: FreeNode - Clear allocation bit for node.
209 Function: Finds the bit representing the node specified by nodeNum in the node
210 map and clears the bit.
213 Input: btreePtr - pointer to control block for BTree file
214 nodeNum - number of node to mark free
218 Result: noErr - success
219 fsBTNoMoreMapNodesErr - node number is beyond end of node map
220 != noErr - GetNode or ReleaseNode encountered some difficulty
221 -------------------------------------------------------------------------------*/
223 OSStatus
FreeNode (BTreeControlBlockPtr btreePtr
, UInt32 nodeNum
)
226 BlockDescriptor node
;
233 //////////////////////////// Find Map Record ////////////////////////////////
234 nodeIndex
= 0; // first node number of header map record
235 node
.buffer
= nil
; // invalidate node.buffer to get header node
237 while (nodeNum
>= nodeIndex
)
239 err
= GetMapNode (btreePtr
, &node
, &mapPos
, &mapSize
);
242 nodeIndex
+= mapSize
<< 3; // covert to number of bits (nodes)
245 //////////////////////////// Mark Node Free /////////////////////////////////
247 nodeNum
-= (nodeIndex
- (mapSize
<< 3)); // relative to this map record
248 bitOffset
= 15 - (nodeNum
& 0x0000000F); // last 4 bits are bit offset
249 mapPos
+= nodeNum
>> 4; // point to word containing map bit
251 M_SWAP_BE16_ClearBitNum (*mapPos
, bitOffset
); // clear it
253 err
= UpdateNode (btreePtr
, &node
, 0, kLockTransaction
);
256 ++btreePtr
->freeNodes
;
257 btreePtr
->flags
|= kBTHeaderDirty
; // how about a macro for this
263 (void) ReleaseNode (btreePtr
, &node
);
270 /*-------------------------------------------------------------------------------
272 Routine: ExtendBTree - Call FSAgent to extend file, and allocate necessary map nodes.
274 Function: This routine calls the the FSAgent to extend the end of fork, if necessary,
275 to accomodate the number of nodes requested. It then allocates as many
276 map nodes as are necessary to account for all the nodes in the B*Tree.
277 If newTotalNodes is less than the current number of nodes, no action is
280 Note: Internal HFS File Manager BTree Module counts on an integral number of
281 long words in map records, although they are not long word aligned.
283 Input: btreePtr - pointer to control block for BTree file
284 newTotalNodes - total number of nodes the B*Tree is to extended to
288 Result: noErr - success
290 -------------------------------------------------------------------------------*/
292 OSStatus
ExtendBTree (BTreeControlBlockPtr btreePtr
,
293 UInt32 newTotalNodes
)
297 FSSize minEOF
, maxEOF
;
299 UInt32 oldTotalNodes
;
301 UInt32 mapBits
, totalMapBits
;
303 UInt32 nodeNum
, nextNodeNum
;
304 UInt32 firstNewMapNodeNum
, lastNewMapNodeNum
;
305 BlockDescriptor mapNode
, newNode
;
309 UInt16 mapNodeRecSize
;
310 UInt32 bitInWord
, bitInRecord
;
314 oldTotalNodes
= btreePtr
->totalNodes
;
315 if (newTotalNodes
<= oldTotalNodes
) // we're done!
318 nodeSize
= btreePtr
->nodeSize
;
319 filePtr
= GetFileControlBlock(btreePtr
->fileRefNum
);
321 mapNode
.buffer
= nil
;
322 newNode
.buffer
= nil
;
324 mapNodeRecSize
= nodeSize
- sizeof(BTNodeDescriptor
) - 6; // 2 bytes of free space (see note)
326 // update for proper 64 bit arithmetic!!
329 //////////////////////// Count Bits In Node Map /////////////////////////////
333 err
= GetMapNode (btreePtr
, &mapNode
, &mapStart
, &mapSize
);
336 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
337 recStartBit
= totalMapBits
; // bit number of first bit in map record
338 totalMapBits
+= mapBits
;
340 } while ( ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
!= 0 );
342 if (DEBUG_BUILD
&& totalMapBits
!= CalcMapBits (btreePtr
))
343 Panic ("\pExtendBTree: totalMapBits != CalcMapBits");
345 /////////////////////// Extend LEOF If Necessary ////////////////////////////
347 minEOF
= newTotalNodes
* nodeSize
;
348 if ( filePtr
->fcbEOF
< minEOF
)
351 // ???? Does this B*Tree pack stop working when LEOF > 2^32-1?
353 maxEOF
= ((UInt32
)0xFFFFFFFFL
);
355 err
= btreePtr
->setEndOfForkProc (btreePtr
->fileRefNum
, minEOF
, maxEOF
);
360 //////////////////// Calc New Total Number Of Nodes /////////////////////////
362 newTotalNodes
= filePtr
->fcbEOF
/ nodeSize
; // hack!
363 // do we wish to perform any verification of newTotalNodes at this point?
365 btreePtr
->totalNodes
= newTotalNodes
; // do we need to update freeNodes here too?
368 ////////////// Calculate Number Of New Map Nodes Required ///////////////////
371 if (newTotalNodes
> totalMapBits
)
373 newMapNodes
= (((newTotalNodes
- totalMapBits
) >> 3) / mapNodeRecSize
) + 1;
374 firstNewMapNodeNum
= oldTotalNodes
;
375 lastNewMapNodeNum
= firstNewMapNodeNum
+ newMapNodes
- 1;
379 err
= ReleaseNode (btreePtr
, &mapNode
);
386 /////////////////////// Initialize New Map Nodes ////////////////////////////
388 ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
= firstNewMapNodeNum
;
390 nodeNum
= firstNewMapNodeNum
;
393 err
= GetNewNode (btreePtr
, nodeNum
, &newNode
);
396 ((NodeDescPtr
)newNode
.buffer
)->numRecords
= 1;
397 ((NodeDescPtr
)newNode
.buffer
)->kind
= kBTMapNode
;
399 // set free space offset
400 *(UInt16
*)((Ptr
)newNode
.buffer
+ nodeSize
- 4) = nodeSize
- 6;
402 if (nodeNum
++ == lastNewMapNodeNum
)
405 ((BTNodeDescriptor
*)newNode
.buffer
)->fLink
= nodeNum
; // point to next map node
407 err
= UpdateNode (btreePtr
, &newNode
, 0, kLockTransaction
);
411 err
= UpdateNode (btreePtr
, &newNode
, 0, kLockTransaction
);
415 ///////////////////// Mark New Map Nodes Allocated //////////////////////////
417 nodeNum
= firstNewMapNodeNum
;
419 bitInRecord
= nodeNum
- recStartBit
;
421 while (bitInRecord
>= mapBits
)
423 nextNodeNum
= ((NodeDescPtr
)mapNode
.buffer
)->fLink
;
424 if ( nextNodeNum
== 0)
426 err
= fsBTNoMoreMapNodesErr
;
430 err
= UpdateNode (btreePtr
, &mapNode
, 0, kLockTransaction
);
433 err
= GetNode (btreePtr
, nextNodeNum
, &mapNode
);
438 mapStart
= (UInt16
*) GetRecordAddress (btreePtr
, mapNode
.buffer
, mapIndex
);
439 mapSize
= GetRecordSize (btreePtr
, mapNode
.buffer
, mapIndex
);
441 if (DEBUG_BUILD
&& mapSize
!= M_MapRecordSize (btreePtr
->nodeSize
) )
443 Panic ("\pExtendBTree: mapSize != M_MapRecordSize");
446 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
447 recStartBit
= totalMapBits
; // bit number of first bit in map record
448 totalMapBits
+= mapBits
;
450 bitInRecord
= nodeNum
- recStartBit
;
453 mapPos
= mapStart
+ ((nodeNum
- recStartBit
) >> 4);
454 bitInWord
= 15 - ((nodeNum
- recStartBit
) & 0x0000000F);
456 M_SWAP_BE16_SetBitNum (*mapPos
, bitInWord
);
460 } while (nodeNum
<= lastNewMapNodeNum
);
462 err
= UpdateNode (btreePtr
, &mapNode
, 0, kLockTransaction
);
466 //////////////////////////////// Success ////////////////////////////////////
470 btreePtr
->totalNodes
= newTotalNodes
;
471 btreePtr
->freeNodes
+= (newTotalNodes
- oldTotalNodes
) - newMapNodes
;
473 btreePtr
->flags
|= kBTHeaderDirty
; //\80\80 how about a macro for this
478 ////////////////////////////// Error Exit ///////////////////////////////////
482 (void) ReleaseNode (btreePtr
, &mapNode
);
483 (void) ReleaseNode (btreePtr
, &newNode
);
490 /*-------------------------------------------------------------------------------
492 Routine: GetMapNode - Get the next map node and pointer to the map record.
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
499 Input: btreePtr - pointer to control block for BTree file
500 nodePtr - pointer to a BlockDescriptor of a map node
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
506 Result: noErr - success
507 fsBTNoMoreMapNodesErr - we've run out of map nodes
508 fsBTInvalidNodeErr - bad node, or not node type kMapNode
510 -------------------------------------------------------------------------------*/
512 OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
513 BlockDescriptor
*nodePtr
,
521 if (nodePtr
->buffer
!= nil
) // if iterator is valid...
523 nextNodeNum
= ((NodeDescPtr
)nodePtr
->buffer
)->fLink
;
524 if (nextNodeNum
== 0)
526 err
= fsBTNoMoreMapNodesErr
;
530 err
= ReleaseNode (btreePtr
, nodePtr
);
533 err
= GetNode (btreePtr
, nextNodeNum
, nodePtr
);
536 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTMapNode
)
538 err
= fsBTBadNodeType
;
542 ++btreePtr
->numMapNodesRead
;
545 err
= GetNode (btreePtr
, kHeaderNodeNum
, nodePtr
);
548 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTHeaderNode
)
550 err
= fsBTInvalidHeaderErr
; //\80\80 or fsBTBadNodeType
558 *mapPtr
= (UInt16
*) GetRecordAddress (btreePtr
, nodePtr
->buffer
, mapIndex
);
559 *mapSize
= GetRecordSize (btreePtr
, nodePtr
->buffer
, mapIndex
);
566 (void) ReleaseNode (btreePtr
, nodePtr
);
576 ////////////////////////////////// CalcMapBits //////////////////////////////////
578 UInt32
CalcMapBits (BTreeControlBlockPtr btreePtr
)
582 mapBits
= M_HeaderMapRecordSize (btreePtr
->nodeSize
) << 3;
584 while (mapBits
< btreePtr
->totalNodes
)
585 mapBits
+= M_MapRecordSize (btreePtr
->nodeSize
) << 3;