2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
33 Contains: BTree Node Allocation routines for the BTree Module.
35 Version: xxx put the technology version here xxx
37 Written by: Gordon Sheridan and Bill Bruffey
39 Copyright: © 1992-1999 by Apple Computer, Inc., all rights reserved.
45 Other Contact: Mark Day
47 Technology: File Systems
55 Change History (most recent first):
57 <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
58 <CS3> 11/24/97 djb Remove some debug code (Panic calls).
59 <CS2> 7/24/97 djb CallbackProcs now take refnum instead of an FCB.
60 <CS1> 4/23/97 djb first checked in
62 <HFS2> 2/19/97 djb Change E_BadNodeType to fsBTBadNodeType.
63 <HFS1> 12/19/96 djb first checked in
65 History applicable to original Scarecrow Design:
67 <4> 10/25/96 ser Changing for new VFPI
68 <3> 10/18/96 ser Converting over VFPI changes
69 <2> 1/10/96 msd Change 64-bit math to use real function names from Math64.i.
70 <1> 10/18/95 rst Moved from Scarecrow project.
72 <8> 1/12/95 wjk Adopt Model FileSystem changes in D5.
73 <7> 9/30/94 prp Get in sync with D2 interface changes.
74 <6> 7/22/94 wjk Convert to the new set of header files.
75 <5> 8/31/93 prp Use U64SetU instead of S64Set.
76 <4> 5/21/93 gs Fix ExtendBTree bug.
77 <3> 5/10/93 gs Fix pointer arithmetic bug in AllocateNode.
78 <2> 3/23/93 gs finish ExtendBTree routine.
79 <1> 2/8/93 gs first checked in
80 <0> 1/1/93 gs begin AllocateNode and FreeNode
84 #include "../../hfs_endian.h"
85 #include "../headers/BTreesPrivate.h"
87 ///////////////////// Routines Internal To BTreeAllocate.c //////////////////////
89 OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
90 BlockDescriptor
*nodePtr
,
94 /////////////////////////////////////////////////////////////////////////////////
96 /*-------------------------------------------------------------------------------
98 Routine: AllocateNode - Find Free Node, Mark It Used, and Return Node Number.
100 Function: Searches the map records for the first free node, marks it "in use" and
101 returns the node number found. This routine should really only be called
102 when we know there are free blocks, otherwise it's just a waste of time.
104 Note: We have to examine map nodes a word at a time rather than a long word
105 because the External BTree Mgr used map records that were not an integral
106 number of long words. Too bad. In our spare time could develop a more
107 sophisticated algorithm that read map records by long words (and long
108 word aligned) and handled the spare bytes at the beginning and end
111 Input: btreePtr - pointer to control block for BTree file
113 Output: nodeNum - number of node allocated
116 Result: noErr - success
117 fsBTNoMoreMapNodesErr - no free blocks were found
119 -------------------------------------------------------------------------------*/
121 OSStatus
AllocateNode (BTreeControlBlockPtr btreePtr
, UInt32
*nodeNum
)
124 BlockDescriptor node
;
125 UInt16
*mapPtr
, *pos
;
126 UInt16 mapSize
, size
;
133 nodeNumber
= 0; // first node number of header map record
134 node
.buffer
= nil
; // clear node.buffer to get header node
135 // - and for ErrorExit
136 node
.blockHeader
= nil
;
140 err
= GetMapNode (btreePtr
, &node
, &mapPtr
, &mapSize
);
144 ModifyBlockStart(btreePtr
->fileRefNum
, &node
);
146 //////////////////////// Find Word with Free Bit ////////////////////////////
150 size
>>= 1; // convert to number of words
151 //\80\80 assumes mapRecords contain an integral number of words
155 if ( *pos
++ != 0xFFFF ) // assume test fails, and increment pos
159 --pos
; // whoa! backup
161 if (*pos
!= 0xFFFF) // hey, we got one!
164 nodeNumber
+= mapSize
<< 3; // covert to number of bits (nodes)
167 ///////////////////////// Find Free Bit in Word /////////////////////////////
169 freeWord
= SWAP_BE16 (*pos
);
174 if ( (freeWord
& mask
) == 0)
177 } while (--bitOffset
);
179 ////////////////////// Calculate Free Node Number ///////////////////////////
181 nodeNumber
+= ((pos
- mapPtr
) << 4) + (15 - bitOffset
); // (pos-mapPtr) = # of words!
184 ///////////////////////// Check for End of Map //////////////////////////////
186 if (nodeNumber
>= btreePtr
->totalNodes
)
192 /////////////////////////// Allocate the Node ///////////////////////////////
194 *pos
|= SWAP_BE16 (mask
); // set the map bit for the node
196 err
= UpdateNode (btreePtr
, &node
, 0, kLockTransaction
);
199 --btreePtr
->freeNodes
;
200 btreePtr
->flags
|= kBTHeaderDirty
;
202 /* Account for allocations from node reserve */
203 BTUpdateReserve(btreePtr
, 1);
205 *nodeNum
= nodeNumber
;
209 ////////////////////////////////// Error Exit ///////////////////////////////////
213 (void) ReleaseNode (btreePtr
, &node
);
221 /*-------------------------------------------------------------------------------
223 Routine: FreeNode - Clear allocation bit for node.
225 Function: Finds the bit representing the node specified by nodeNum in the node
226 map and clears the bit.
229 Input: btreePtr - pointer to control block for BTree file
230 nodeNum - number of node to mark free
234 Result: noErr - success
235 fsBTNoMoreMapNodesErr - node number is beyond end of node map
236 != noErr - GetNode or ReleaseNode encountered some difficulty
237 -------------------------------------------------------------------------------*/
239 OSStatus
FreeNode (BTreeControlBlockPtr btreePtr
, UInt32 nodeNum
)
242 BlockDescriptor node
;
249 //////////////////////////// Find Map Record ////////////////////////////////
250 nodeIndex
= 0; // first node number of header map record
251 node
.buffer
= nil
; // invalidate node.buffer to get header node
252 node
.blockHeader
= nil
;
254 while (nodeNum
>= nodeIndex
)
256 err
= GetMapNode (btreePtr
, &node
, &mapPos
, &mapSize
);
259 nodeIndex
+= mapSize
<< 3; // covert to number of bits (nodes)
262 //////////////////////////// Mark Node Free /////////////////////////////////
265 ModifyBlockStart(btreePtr
->fileRefNum
, &node
);
267 nodeNum
-= (nodeIndex
- (mapSize
<< 3)); // relative to this map record
268 bitOffset
= 15 - (nodeNum
& 0x0000000F); // last 4 bits are bit offset
269 mapPos
+= nodeNum
>> 4; // point to word containing map bit
271 M_SWAP_BE16_ClearBitNum (*mapPos
, bitOffset
); // clear it
273 err
= UpdateNode (btreePtr
, &node
, 0, kLockTransaction
);
276 ++btreePtr
->freeNodes
;
277 btreePtr
->flags
|= kBTHeaderDirty
; // how about a macro for this
283 (void) ReleaseNode (btreePtr
, &node
);
290 /*-------------------------------------------------------------------------------
292 Routine: ExtendBTree - Call FSAgent to extend file, and allocate necessary map nodes.
294 Function: This routine calls the the FSAgent to extend the end of fork, if necessary,
295 to accomodate the number of nodes requested. It then allocates as many
296 map nodes as are necessary to account for all the nodes in the B*Tree.
297 If newTotalNodes is less than the current number of nodes, no action is
300 Note: Internal HFS File Manager BTree Module counts on an integral number of
301 long words in map records, although they are not long word aligned.
303 Input: btreePtr - pointer to control block for BTree file
304 newTotalNodes - total number of nodes the B*Tree is to extended to
308 Result: noErr - success
310 -------------------------------------------------------------------------------*/
312 OSStatus
ExtendBTree (BTreeControlBlockPtr btreePtr
,
313 UInt32 newTotalNodes
)
317 FSSize minEOF
, maxEOF
;
319 UInt32 oldTotalNodes
;
321 UInt32 mapBits
, totalMapBits
;
323 UInt32 nodeNum
, nextNodeNum
;
324 UInt32 firstNewMapNodeNum
, lastNewMapNodeNum
;
325 BlockDescriptor mapNode
, newNode
;
329 UInt16 mapNodeRecSize
;
330 UInt32 bitInWord
, bitInRecord
;
334 oldTotalNodes
= btreePtr
->totalNodes
;
335 if (newTotalNodes
<= oldTotalNodes
) // we're done!
338 nodeSize
= btreePtr
->nodeSize
;
339 filePtr
= GetFileControlBlock(btreePtr
->fileRefNum
);
341 mapNode
.buffer
= nil
;
342 mapNode
.blockHeader
= nil
;
343 newNode
.buffer
= nil
;
344 newNode
.blockHeader
= nil
;
346 mapNodeRecSize
= nodeSize
- sizeof(BTNodeDescriptor
) - 6; // 2 bytes of free space (see note)
349 //////////////////////// Count Bits In Node Map /////////////////////////////
353 err
= GetMapNode (btreePtr
, &mapNode
, &mapStart
, &mapSize
);
356 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
357 recStartBit
= totalMapBits
; // bit number of first bit in map record
358 totalMapBits
+= mapBits
;
360 } while ( ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
!= 0 );
362 if (DEBUG_BUILD
&& totalMapBits
!= CalcMapBits (btreePtr
))
363 Panic ("\pExtendBTree: totalMapBits != CalcMapBits");
365 /////////////////////// Extend LEOF If Necessary ////////////////////////////
367 minEOF
= (UInt64
)newTotalNodes
* (UInt64
)nodeSize
;
368 if ( filePtr
->fcbEOF
< minEOF
)
370 maxEOF
= (UInt64
)0x7fffffffLL
* (UInt64
)nodeSize
;
372 err
= btreePtr
->setEndOfForkProc (btreePtr
->fileRefNum
, minEOF
, maxEOF
);
377 //////////////////// Calc New Total Number Of Nodes /////////////////////////
379 newTotalNodes
= filePtr
->fcbEOF
/ nodeSize
; // hack!
380 // do we wish to perform any verification of newTotalNodes at this point?
382 btreePtr
->totalNodes
= newTotalNodes
; // do we need to update freeNodes here too?
385 ////////////// Calculate Number Of New Map Nodes Required ///////////////////
388 if (newTotalNodes
> totalMapBits
)
390 newMapNodes
= (((newTotalNodes
- totalMapBits
) >> 3) / mapNodeRecSize
) + 1;
391 firstNewMapNodeNum
= oldTotalNodes
;
392 lastNewMapNodeNum
= firstNewMapNodeNum
+ newMapNodes
- 1;
396 err
= ReleaseNode (btreePtr
, &mapNode
);
403 /////////////////////// Initialize New Map Nodes ////////////////////////////
404 // XXXdbg - this is the correct place for this:
405 ModifyBlockStart(btreePtr
->fileRefNum
, &mapNode
);
407 ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
= firstNewMapNodeNum
;
409 nodeNum
= firstNewMapNodeNum
;
412 err
= GetNewNode (btreePtr
, nodeNum
, &newNode
);
416 ModifyBlockStart(btreePtr
->fileRefNum
, &newNode
);
418 ((NodeDescPtr
)newNode
.buffer
)->numRecords
= 1;
419 ((NodeDescPtr
)newNode
.buffer
)->kind
= kBTMapNode
;
421 // set free space offset
422 *(UInt16
*)((Ptr
)newNode
.buffer
+ nodeSize
- 4) = nodeSize
- 6;
424 if (nodeNum
++ == lastNewMapNodeNum
)
427 ((BTNodeDescriptor
*)newNode
.buffer
)->fLink
= nodeNum
; // point to next map node
429 err
= UpdateNode (btreePtr
, &newNode
, 0, kLockTransaction
);
433 err
= UpdateNode (btreePtr
, &newNode
, 0, kLockTransaction
);
437 ///////////////////// Mark New Map Nodes Allocated //////////////////////////
439 nodeNum
= firstNewMapNodeNum
;
441 bitInRecord
= nodeNum
- recStartBit
;
443 while (bitInRecord
>= mapBits
)
445 nextNodeNum
= ((NodeDescPtr
)mapNode
.buffer
)->fLink
;
446 if ( nextNodeNum
== 0)
448 err
= fsBTNoMoreMapNodesErr
;
452 err
= UpdateNode (btreePtr
, &mapNode
, 0, kLockTransaction
);
455 err
= GetNode (btreePtr
, nextNodeNum
, &mapNode
);
459 ModifyBlockStart(btreePtr
->fileRefNum
, &mapNode
);
463 mapStart
= (UInt16
*) GetRecordAddress (btreePtr
, mapNode
.buffer
, mapIndex
);
464 mapSize
= GetRecordSize (btreePtr
, mapNode
.buffer
, mapIndex
);
466 if (DEBUG_BUILD
&& mapSize
!= M_MapRecordSize (btreePtr
->nodeSize
) )
468 Panic ("\pExtendBTree: mapSize != M_MapRecordSize");
471 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
472 recStartBit
= totalMapBits
; // bit number of first bit in map record
473 totalMapBits
+= mapBits
;
475 bitInRecord
= nodeNum
- recStartBit
;
478 mapPos
= mapStart
+ ((nodeNum
- recStartBit
) >> 4);
479 bitInWord
= 15 - ((nodeNum
- recStartBit
) & 0x0000000F);
481 M_SWAP_BE16_SetBitNum (*mapPos
, bitInWord
);
485 } while (nodeNum
<= lastNewMapNodeNum
);
487 err
= UpdateNode (btreePtr
, &mapNode
, 0, kLockTransaction
);
491 //////////////////////////////// Success ////////////////////////////////////
495 btreePtr
->totalNodes
= newTotalNodes
;
496 btreePtr
->freeNodes
+= (newTotalNodes
- oldTotalNodes
) - newMapNodes
;
498 btreePtr
->flags
|= kBTHeaderDirty
; //\80\80 how about a macro for this
500 /* Force the b-tree header changes to disk */
501 (void) UpdateHeader (btreePtr
, true);
506 ////////////////////////////// Error Exit ///////////////////////////////////
510 (void) ReleaseNode (btreePtr
, &mapNode
);
511 (void) ReleaseNode (btreePtr
, &newNode
);
518 /*-------------------------------------------------------------------------------
520 Routine: GetMapNode - Get the next map node and pointer to the map record.
522 Function: Given a BlockDescriptor to a map node in nodePtr, GetMapNode releases
523 it and gets the next node. If nodePtr->buffer is nil, then the header
527 Input: btreePtr - pointer to control block for BTree file
528 nodePtr - pointer to a BlockDescriptor of a map node
530 Output: nodePtr - pointer to the BlockDescriptor for the next map node
531 mapPtr - pointer to the map record within the map node
532 mapSize - number of bytes in the map record
534 Result: noErr - success
535 fsBTNoMoreMapNodesErr - we've run out of map nodes
536 fsBTInvalidNodeErr - bad node, or not node type kMapNode
538 -------------------------------------------------------------------------------*/
540 OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
541 BlockDescriptor
*nodePtr
,
549 if (nodePtr
->buffer
!= nil
) // if iterator is valid...
551 nextNodeNum
= ((NodeDescPtr
)nodePtr
->buffer
)->fLink
;
552 if (nextNodeNum
== 0)
554 err
= fsBTNoMoreMapNodesErr
;
558 err
= ReleaseNode (btreePtr
, nodePtr
);
561 err
= GetNode (btreePtr
, nextNodeNum
, nodePtr
);
564 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTMapNode
)
566 err
= fsBTBadNodeType
;
570 ++btreePtr
->numMapNodesRead
;
573 err
= GetNode (btreePtr
, kHeaderNodeNum
, nodePtr
);
576 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTHeaderNode
)
578 err
= fsBTInvalidHeaderErr
; //\80\80 or fsBTBadNodeType
586 *mapPtr
= (UInt16
*) GetRecordAddress (btreePtr
, nodePtr
->buffer
, mapIndex
);
587 *mapSize
= GetRecordSize (btreePtr
, nodePtr
->buffer
, mapIndex
);
594 (void) ReleaseNode (btreePtr
, nodePtr
);
604 ////////////////////////////////// CalcMapBits //////////////////////////////////
606 UInt32
CalcMapBits (BTreeControlBlockPtr btreePtr
)
610 mapBits
= M_HeaderMapRecordSize (btreePtr
->nodeSize
) << 3;
612 while (mapBits
< btreePtr
->totalNodes
)
613 mapBits
+= M_MapRecordSize (btreePtr
->nodeSize
) << 3;