2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
26 Contains: BTree Node Allocation routines for the BTree Module.
28 Version: xxx put the technology version here xxx
30 Written by: Gordon Sheridan and Bill Bruffey
32 Copyright: © 1992-1999 by Apple Computer, Inc., all rights reserved.
35 #include "BTreePrivate.h"
36 #include "hfs_endian.h"
38 ///////////////////// Routines Internal To BTreeAllocate.c //////////////////////
40 OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
41 BlockDescriptor
*nodePtr
,
45 /////////////////////////////////////////////////////////////////////////////////
47 /*-------------------------------------------------------------------------------
49 Routine: AllocateNode - Find Free Node, Mark It Used, and Return Node Number.
51 Function: Searches the map records for the first free node, marks it "in use" and
52 returns the node number found. This routine should really only be called
53 when we know there are free blocks, otherwise it's just a waste of time.
55 Note: We have to examine map nodes a word at a time rather than a long word
56 because the External BTree Mgr used map records that were not an integral
57 number of long words. Too bad. In our spare time could develop a more
58 sophisticated algorithm that read map records by long words (and long
59 word aligned) and handled the spare bytes at the beginning and end
62 Input: btreePtr - pointer to control block for BTree file
64 Output: nodeNum - number of node allocated
67 Result: noErr - success
68 fsBTNoMoreMapNodesErr - no free blocks were found
70 -------------------------------------------------------------------------------*/
72 OSStatus
AllocateNode (BTreeControlBlockPtr btreePtr
, UInt32
*nodeNum
)
84 nodeNumber
= 0; // first node number of header map record
85 node
.buffer
= nil
; // clear node.buffer to get header node
86 // - and for ErrorExit
90 err
= GetMapNode (btreePtr
, &node
, &mapPtr
, &mapSize
);
93 //////////////////////// Find Word with Free Bit ////////////////////////////
97 size
>>= 1; // convert to number of words
98 //¥¥ assumes mapRecords contain an integral number of words
102 if ( *pos
++ != 0xFFFF ) // assume test fails, and increment pos
106 --pos
; // whoa! backup
108 if (*pos
!= 0xFFFF) // hey, we got one!
111 nodeNumber
+= mapSize
<< 3; // covert to number of bits (nodes)
114 ///////////////////////// Find Free Bit in Word /////////////////////////////
116 freeWord
= SWAP_BE16 (*pos
);
121 if ( (freeWord
& mask
) == 0)
124 } while (--bitOffset
);
126 ////////////////////// Calculate Free Node Number ///////////////////////////
128 nodeNumber
+= ((pos
- mapPtr
) << 4) + (15 - bitOffset
); // (pos-mapPtr) = # of words!
131 ///////////////////////// Check for End of Map //////////////////////////////
133 if (nodeNumber
>= btreePtr
->totalNodes
)
139 /////////////////////////// Allocate the Node ///////////////////////////////
141 *pos
|= SWAP_BE16 (mask
); // set the map bit for the node
143 err
= UpdateNode (btreePtr
, &node
);
146 --btreePtr
->freeNodes
;
147 btreePtr
->flags
|= kBTHeaderDirty
;
148 *nodeNum
= nodeNumber
;
152 ////////////////////////////////// Error Exit ///////////////////////////////////
156 (void) ReleaseNode (btreePtr
, &node
);
164 /*-------------------------------------------------------------------------------
166 Routine: FreeNode - Clear allocation bit for node.
168 Function: Finds the bit representing the node specified by nodeNum in the node
169 map and clears the bit.
172 Input: btreePtr - pointer to control block for BTree file
173 nodeNum - number of node to mark free
177 Result: noErr - success
178 fsBTNoMoreMapNodesErr - node number is beyond end of node map
179 != noErr - GetNode or ReleaseNode encountered some difficulty
180 -------------------------------------------------------------------------------*/
182 OSStatus
FreeNode (BTreeControlBlockPtr btreePtr
, UInt32 nodeNum
)
185 BlockDescriptor node
;
192 //////////////////////////// Find Map Record ////////////////////////////////
193 nodeIndex
= 0; // first node number of header map record
194 node
.buffer
= nil
; // invalidate node.buffer to get header node
196 while (nodeNum
>= nodeIndex
)
198 err
= GetMapNode (btreePtr
, &node
, &mapPos
, &mapSize
);
201 nodeIndex
+= mapSize
<< 3; // covert to number of bits (nodes)
204 //////////////////////////// Mark Node Free /////////////////////////////////
206 nodeNum
-= (nodeIndex
- (mapSize
<< 3)); // relative to this map record
207 bitOffset
= 15 - (nodeNum
& 0x0000000F); // last 4 bits are bit offset
208 mapPos
+= nodeNum
>> 4; // point to word containing map bit
209 M_SWAP_BE16_ClearBitNum (*mapPos
, bitOffset
); // clear it
211 err
= UpdateNode (btreePtr
, &node
);
215 ++btreePtr
->freeNodes
;
216 btreePtr
->flags
|= kBTHeaderDirty
; //¥¥ how about a macro for this
222 (void) ReleaseNode (btreePtr
, &node
);
229 /*-------------------------------------------------------------------------------
231 Routine: ExtendBTree - Call FSAgent to extend file, and allocate necessary map nodes.
233 Function: This routine calls the the FSAgent to extend the end of fork, if necessary,
234 to accomodate the number of nodes requested. It then allocates as many
235 map nodes as are necessary to account for all the nodes in the B*Tree.
236 If newTotalNodes is less than the current number of nodes, no action is
239 Note: Internal HFS File Manager BTree Module counts on an integral number of
240 long words in map records, although they are not long word aligned.
242 Input: btreePtr - pointer to control block for BTree file
243 newTotalNodes - total number of nodes the B*Tree is to extended to
247 Result: noErr - success
249 -------------------------------------------------------------------------------*/
251 OSStatus
ExtendBTree (BTreeControlBlockPtr btreePtr
,
252 UInt32 newTotalNodes
)
256 FSSize minEOF
, maxEOF
;
258 UInt32 oldTotalNodes
;
260 UInt32 mapBits
, totalMapBits
;
262 UInt32 nodeNum
, nextNodeNum
;
263 UInt32 firstNewMapNodeNum
, lastNewMapNodeNum
;
264 BlockDescriptor mapNode
, newNode
;
268 UInt16 mapNodeRecSize
;
269 UInt32 bitInWord
, bitInRecord
;
273 oldTotalNodes
= btreePtr
->totalNodes
;
274 if (newTotalNodes
<= oldTotalNodes
) // we're done!
277 nodeSize
= btreePtr
->nodeSize
;
278 filePtr
= btreePtr
->fcbPtr
;
280 mapNode
.buffer
= nil
;
281 newNode
.buffer
= nil
;
283 mapNodeRecSize
= nodeSize
- sizeof(BTNodeDescriptor
) - 6; // 2 bytes of free space (see note)
285 //¥¥ update for proper 64 bit arithmetic!!
288 //////////////////////// Count Bits In Node Map /////////////////////////////
292 err
= GetMapNode (btreePtr
, &mapNode
, &mapStart
, &mapSize
);
295 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
296 recStartBit
= totalMapBits
; // bit number of first bit in map record
297 totalMapBits
+= mapBits
;
299 } while ( ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
!= 0 );
301 if (DEBUG_BUILD
&& totalMapBits
!= CalcMapBits (btreePtr
))
302 Panic ("\pExtendBTree: totalMapBits != CalcMapBits");
304 /////////////////////// Extend LEOF If Necessary ////////////////////////////
306 minEOF
= (UInt64
)newTotalNodes
* (UInt64
)nodeSize
;
307 if ( filePtr
->fcbLogicalSize
< minEOF
)
309 maxEOF
= 0xFFFFFFFFFFFFFFFFULL
;
311 err
= btreePtr
->setEndOfForkProc (btreePtr
->fcbPtr
, minEOF
, maxEOF
);
316 //////////////////// Calc New Total Number Of Nodes /////////////////////////
318 newTotalNodes
= (UInt32
)(filePtr
->fcbLogicalSize
/ nodeSize
); //¥¥ hack!
319 //¥¥ do we wish to perform any verification of newTotalNodes at this point?
321 btreePtr
->totalNodes
= newTotalNodes
; //¥¥ do we need to update freeNodes here too?
324 ////////////// Calculate Number Of New Map Nodes Required ///////////////////
327 if (newTotalNodes
> totalMapBits
)
329 newMapNodes
= (((newTotalNodes
- totalMapBits
) >> 3) / mapNodeRecSize
) + 1;
330 firstNewMapNodeNum
= oldTotalNodes
;
331 lastNewMapNodeNum
= firstNewMapNodeNum
+ newMapNodes
- 1;
335 err
= ReleaseNode (btreePtr
, &mapNode
);
342 /////////////////////// Initialize New Map Nodes ////////////////////////////
344 ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
= firstNewMapNodeNum
;
346 nodeNum
= firstNewMapNodeNum
;
349 err
= GetNewNode (btreePtr
, nodeNum
, &newNode
);
352 ((NodeDescPtr
)newNode
.buffer
)->numRecords
= 1;
353 ((NodeDescPtr
)newNode
.buffer
)->kind
= kBTMapNode
;
355 // set free space offset
356 *(UInt16
*)((Ptr
)newNode
.buffer
+ nodeSize
- 4) = nodeSize
- 6;
358 if (nodeNum
++ == lastNewMapNodeNum
)
361 ((BTNodeDescriptor
*)newNode
.buffer
)->fLink
= nodeNum
; // point to next map node
363 err
= UpdateNode (btreePtr
, &newNode
);
367 err
= UpdateNode (btreePtr
, &newNode
);
371 ///////////////////// Mark New Map Nodes Allocated //////////////////////////
373 nodeNum
= firstNewMapNodeNum
;
375 bitInRecord
= nodeNum
- recStartBit
;
377 while (bitInRecord
>= mapBits
)
379 nextNodeNum
= ((NodeDescPtr
)mapNode
.buffer
)->fLink
;
380 if ( nextNodeNum
== 0)
382 err
= fsBTNoMoreMapNodesErr
;
386 err
= UpdateNode (btreePtr
, &mapNode
);
389 err
= GetNode (btreePtr
, nextNodeNum
, &mapNode
);
394 mapStart
= (UInt16
*) GetRecordAddress (btreePtr
, mapNode
.buffer
, mapIndex
);
395 mapSize
= GetRecordSize (btreePtr
, mapNode
.buffer
, mapIndex
);
397 if (DEBUG_BUILD
&& mapSize
!= M_MapRecordSize (btreePtr
->nodeSize
) )
399 Panic ("\pExtendBTree: mapSize != M_MapRecordSize");
402 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
403 recStartBit
= totalMapBits
; // bit number of first bit in map record
404 totalMapBits
+= mapBits
;
406 bitInRecord
= nodeNum
- recStartBit
;
409 mapPos
= mapStart
+ ((nodeNum
- recStartBit
) >> 4);
410 bitInWord
= 15 - ((nodeNum
- recStartBit
) & 0x0000000F);
411 M_SWAP_BE16_SetBitNum (*mapPos
, bitInWord
);
415 } while (nodeNum
<= lastNewMapNodeNum
);
417 err
= UpdateNode (btreePtr
, &mapNode
);
421 //////////////////////////////// Success ////////////////////////////////////
425 btreePtr
->totalNodes
= newTotalNodes
;
426 btreePtr
->freeNodes
+= (newTotalNodes
- oldTotalNodes
) - newMapNodes
;
428 btreePtr
->flags
|= kBTHeaderDirty
; //¥¥ how about a macro for this
433 ////////////////////////////// Error Exit ///////////////////////////////////
437 (void) ReleaseNode (btreePtr
, &mapNode
);
438 (void) ReleaseNode (btreePtr
, &newNode
);
445 /*-------------------------------------------------------------------------------
447 Routine: GetMapNode - Get the next map node and pointer to the map record.
449 Function: Given a BlockDescriptor to a map node in nodePtr, GetMapNode releases
450 it and gets the next node. If nodePtr->buffer is nil, then the header
454 Input: btreePtr - pointer to control block for BTree file
455 nodePtr - pointer to a BlockDescriptor of a map node
457 Output: nodePtr - pointer to the BlockDescriptor for the next map node
458 mapPtr - pointer to the map record within the map node
459 mapSize - number of bytes in the map record
461 Result: noErr - success
462 fsBTNoMoreMapNodesErr - we've run out of map nodes
463 fsBTInvalidNodeErr - bad node, or not node type kMapNode
465 -------------------------------------------------------------------------------*/
467 OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
468 BlockDescriptor
*nodePtr
,
476 if (nodePtr
->buffer
!= nil
) // if iterator is valid...
478 nextNodeNum
= ((NodeDescPtr
)nodePtr
->buffer
)->fLink
;
479 if (nextNodeNum
== 0)
481 err
= fsBTNoMoreMapNodesErr
;
485 err
= ReleaseNode (btreePtr
, nodePtr
);
488 err
= GetNode (btreePtr
, nextNodeNum
, nodePtr
);
491 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTMapNode
)
493 err
= fsBTBadNodeType
;
497 ++btreePtr
->numMapNodesRead
;
500 err
= GetNode (btreePtr
, kHeaderNodeNum
, nodePtr
);
503 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTHeaderNode
)
505 err
= fsBTInvalidHeaderErr
; //¥¥ or fsBTBadNodeType
513 *mapPtr
= (UInt16
*) GetRecordAddress (btreePtr
, nodePtr
->buffer
, mapIndex
);
514 *mapSize
= GetRecordSize (btreePtr
, nodePtr
->buffer
, mapIndex
);
521 (void) ReleaseNode (btreePtr
, nodePtr
);
531 ////////////////////////////////// CalcMapBits //////////////////////////////////
533 UInt32
CalcMapBits (BTreeControlBlockPtr btreePtr
)
537 mapBits
= (UInt32
)(M_HeaderMapRecordSize (btreePtr
->nodeSize
) << 3);
539 while (mapBits
< btreePtr
->totalNodes
)
540 mapBits
+= M_MapRecordSize (btreePtr
->nodeSize
) << 3;