2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
28 Contains: BTree Node Allocation routines for the BTree Module.
30 Version: xxx put the technology version here xxx
32 Written by: Gordon Sheridan and Bill Bruffey
34 Copyright: © 1992-1999 by Apple Computer, Inc., all rights reserved.
40 Other Contact: Mark Day
42 Technology: File Systems
50 Change History (most recent first):
52 <MOSXS> 6/1/99 djb Sync up with Mac OS 8.6.
53 <CS3> 11/24/97 djb Remove some debug code (Panic calls).
54 <CS2> 7/24/97 djb CallbackProcs now take refnum instead of an FCB.
55 <CS1> 4/23/97 djb first checked in
57 <HFS2> 2/19/97 djb Change E_BadNodeType to fsBTBadNodeType.
58 <HFS1> 12/19/96 djb first checked in
60 History applicable to original Scarecrow Design:
62 <4> 10/25/96 ser Changing for new VFPI
63 <3> 10/18/96 ser Converting over VFPI changes
64 <2> 1/10/96 msd Change 64-bit math to use real function names from Math64.i.
65 <1> 10/18/95 rst Moved from Scarecrow project.
67 <8> 1/12/95 wjk Adopt Model FileSystem changes in D5.
68 <7> 9/30/94 prp Get in sync with D2 interface changes.
69 <6> 7/22/94 wjk Convert to the new set of header files.
70 <5> 8/31/93 prp Use U64SetU instead of S64Set.
71 <4> 5/21/93 gs Fix ExtendBTree bug.
72 <3> 5/10/93 gs Fix pointer arithmetic bug in AllocateNode.
73 <2> 3/23/93 gs finish ExtendBTree routine.
74 <1> 2/8/93 gs first checked in
75 <0> 1/1/93 gs begin AllocateNode and FreeNode
79 #include "../../hfs_endian.h"
80 #include "../headers/BTreesPrivate.h"
82 ///////////////////// Routines Internal To BTreeAllocate.c //////////////////////
84 OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
85 BlockDescriptor
*nodePtr
,
89 /////////////////////////////////////////////////////////////////////////////////
91 /*-------------------------------------------------------------------------------
93 Routine: AllocateNode - Find Free Node, Mark It Used, and Return Node Number.
95 Function: Searches the map records for the first free node, marks it "in use" and
96 returns the node number found. This routine should really only be called
97 when we know there are free blocks, otherwise it's just a waste of time.
99 Note: We have to examine map nodes a word at a time rather than a long word
100 because the External BTree Mgr used map records that were not an integral
101 number of long words. Too bad. In our spare time could develop a more
102 sophisticated algorithm that read map records by long words (and long
103 word aligned) and handled the spare bytes at the beginning and end
106 Input: btreePtr - pointer to control block for BTree file
108 Output: nodeNum - number of node allocated
111 Result: noErr - success
112 fsBTNoMoreMapNodesErr - no free blocks were found
114 -------------------------------------------------------------------------------*/
116 OSStatus
AllocateNode (BTreeControlBlockPtr btreePtr
, UInt32
*nodeNum
)
119 BlockDescriptor node
;
120 UInt16
*mapPtr
, *pos
;
121 UInt16 mapSize
, size
;
128 nodeNumber
= 0; // first node number of header map record
129 node
.buffer
= nil
; // clear node.buffer to get header node
130 // - and for ErrorExit
131 node
.blockHeader
= nil
;
135 err
= GetMapNode (btreePtr
, &node
, &mapPtr
, &mapSize
);
139 ModifyBlockStart(btreePtr
->fileRefNum
, &node
);
141 //////////////////////// Find Word with Free Bit ////////////////////////////
145 size
>>= 1; // convert to number of words
146 //\80\80 assumes mapRecords contain an integral number of words
150 if ( *pos
++ != 0xFFFF ) // assume test fails, and increment pos
154 --pos
; // whoa! backup
156 if (*pos
!= 0xFFFF) // hey, we got one!
159 nodeNumber
+= mapSize
<< 3; // covert to number of bits (nodes)
162 ///////////////////////// Find Free Bit in Word /////////////////////////////
164 freeWord
= SWAP_BE16 (*pos
);
169 if ( (freeWord
& mask
) == 0)
172 } while (--bitOffset
);
174 ////////////////////// Calculate Free Node Number ///////////////////////////
176 nodeNumber
+= ((pos
- mapPtr
) << 4) + (15 - bitOffset
); // (pos-mapPtr) = # of words!
179 ///////////////////////// Check for End of Map //////////////////////////////
181 if (nodeNumber
>= btreePtr
->totalNodes
)
187 /////////////////////////// Allocate the Node ///////////////////////////////
189 *pos
|= SWAP_BE16 (mask
); // set the map bit for the node
191 err
= UpdateNode (btreePtr
, &node
, 0, kLockTransaction
);
194 --btreePtr
->freeNodes
;
195 btreePtr
->flags
|= kBTHeaderDirty
;
197 /* Account for allocations from node reserve */
198 BTUpdateReserve(btreePtr
, 1);
200 *nodeNum
= nodeNumber
;
204 ////////////////////////////////// Error Exit ///////////////////////////////////
208 (void) ReleaseNode (btreePtr
, &node
);
216 /*-------------------------------------------------------------------------------
218 Routine: FreeNode - Clear allocation bit for node.
220 Function: Finds the bit representing the node specified by nodeNum in the node
221 map and clears the bit.
224 Input: btreePtr - pointer to control block for BTree file
225 nodeNum - number of node to mark free
229 Result: noErr - success
230 fsBTNoMoreMapNodesErr - node number is beyond end of node map
231 != noErr - GetNode or ReleaseNode encountered some difficulty
232 -------------------------------------------------------------------------------*/
234 OSStatus
FreeNode (BTreeControlBlockPtr btreePtr
, UInt32 nodeNum
)
237 BlockDescriptor node
;
244 //////////////////////////// Find Map Record ////////////////////////////////
245 nodeIndex
= 0; // first node number of header map record
246 node
.buffer
= nil
; // invalidate node.buffer to get header node
247 node
.blockHeader
= nil
;
249 while (nodeNum
>= nodeIndex
)
251 err
= GetMapNode (btreePtr
, &node
, &mapPos
, &mapSize
);
254 nodeIndex
+= mapSize
<< 3; // covert to number of bits (nodes)
257 //////////////////////////// Mark Node Free /////////////////////////////////
260 ModifyBlockStart(btreePtr
->fileRefNum
, &node
);
262 nodeNum
-= (nodeIndex
- (mapSize
<< 3)); // relative to this map record
263 bitOffset
= 15 - (nodeNum
& 0x0000000F); // last 4 bits are bit offset
264 mapPos
+= nodeNum
>> 4; // point to word containing map bit
266 M_SWAP_BE16_ClearBitNum (*mapPos
, bitOffset
); // clear it
268 err
= UpdateNode (btreePtr
, &node
, 0, kLockTransaction
);
271 ++btreePtr
->freeNodes
;
272 btreePtr
->flags
|= kBTHeaderDirty
; // how about a macro for this
278 (void) ReleaseNode (btreePtr
, &node
);
285 /*-------------------------------------------------------------------------------
287 Routine: ExtendBTree - Call FSAgent to extend file, and allocate necessary map nodes.
289 Function: This routine calls the the FSAgent to extend the end of fork, if necessary,
290 to accomodate the number of nodes requested. It then allocates as many
291 map nodes as are necessary to account for all the nodes in the B*Tree.
292 If newTotalNodes is less than the current number of nodes, no action is
295 Note: Internal HFS File Manager BTree Module counts on an integral number of
296 long words in map records, although they are not long word aligned.
298 Input: btreePtr - pointer to control block for BTree file
299 newTotalNodes - total number of nodes the B*Tree is to extended to
303 Result: noErr - success
305 -------------------------------------------------------------------------------*/
307 OSStatus
ExtendBTree (BTreeControlBlockPtr btreePtr
,
308 UInt32 newTotalNodes
)
312 FSSize minEOF
, maxEOF
;
314 UInt32 oldTotalNodes
;
316 UInt32 mapBits
, totalMapBits
;
318 UInt32 nodeNum
, nextNodeNum
;
319 UInt32 firstNewMapNodeNum
, lastNewMapNodeNum
;
320 BlockDescriptor mapNode
, newNode
;
324 UInt16 mapNodeRecSize
;
325 UInt32 bitInWord
, bitInRecord
;
329 oldTotalNodes
= btreePtr
->totalNodes
;
330 if (newTotalNodes
<= oldTotalNodes
) // we're done!
333 nodeSize
= btreePtr
->nodeSize
;
334 filePtr
= GetFileControlBlock(btreePtr
->fileRefNum
);
336 mapNode
.buffer
= nil
;
337 mapNode
.blockHeader
= nil
;
338 newNode
.buffer
= nil
;
339 newNode
.blockHeader
= nil
;
341 mapNodeRecSize
= nodeSize
- sizeof(BTNodeDescriptor
) - 6; // 2 bytes of free space (see note)
344 //////////////////////// Count Bits In Node Map /////////////////////////////
348 err
= GetMapNode (btreePtr
, &mapNode
, &mapStart
, &mapSize
);
351 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
352 recStartBit
= totalMapBits
; // bit number of first bit in map record
353 totalMapBits
+= mapBits
;
355 } while ( ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
!= 0 );
357 if (DEBUG_BUILD
&& totalMapBits
!= CalcMapBits (btreePtr
))
358 Panic ("\pExtendBTree: totalMapBits != CalcMapBits");
360 /////////////////////// Extend LEOF If Necessary ////////////////////////////
362 minEOF
= (UInt64
)newTotalNodes
* (UInt64
)nodeSize
;
363 if ( filePtr
->fcbEOF
< minEOF
)
365 maxEOF
= (UInt64
)0x7fffffffLL
* (UInt64
)nodeSize
;
367 err
= btreePtr
->setEndOfForkProc (btreePtr
->fileRefNum
, minEOF
, maxEOF
);
372 //////////////////// Calc New Total Number Of Nodes /////////////////////////
374 newTotalNodes
= filePtr
->fcbEOF
/ nodeSize
; // hack!
375 // do we wish to perform any verification of newTotalNodes at this point?
377 btreePtr
->totalNodes
= newTotalNodes
; // do we need to update freeNodes here too?
380 ////////////// Calculate Number Of New Map Nodes Required ///////////////////
383 if (newTotalNodes
> totalMapBits
)
385 newMapNodes
= (((newTotalNodes
- totalMapBits
) >> 3) / mapNodeRecSize
) + 1;
386 firstNewMapNodeNum
= oldTotalNodes
;
387 lastNewMapNodeNum
= firstNewMapNodeNum
+ newMapNodes
- 1;
391 err
= ReleaseNode (btreePtr
, &mapNode
);
398 /////////////////////// Initialize New Map Nodes ////////////////////////////
399 // XXXdbg - this is the correct place for this:
400 ModifyBlockStart(btreePtr
->fileRefNum
, &mapNode
);
402 ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
= firstNewMapNodeNum
;
404 nodeNum
= firstNewMapNodeNum
;
407 err
= GetNewNode (btreePtr
, nodeNum
, &newNode
);
411 ModifyBlockStart(btreePtr
->fileRefNum
, &newNode
);
413 ((NodeDescPtr
)newNode
.buffer
)->numRecords
= 1;
414 ((NodeDescPtr
)newNode
.buffer
)->kind
= kBTMapNode
;
416 // set free space offset
417 *(UInt16
*)((Ptr
)newNode
.buffer
+ nodeSize
- 4) = nodeSize
- 6;
419 if (nodeNum
++ == lastNewMapNodeNum
)
422 ((BTNodeDescriptor
*)newNode
.buffer
)->fLink
= nodeNum
; // point to next map node
424 err
= UpdateNode (btreePtr
, &newNode
, 0, kLockTransaction
);
428 err
= UpdateNode (btreePtr
, &newNode
, 0, kLockTransaction
);
432 ///////////////////// Mark New Map Nodes Allocated //////////////////////////
434 nodeNum
= firstNewMapNodeNum
;
436 bitInRecord
= nodeNum
- recStartBit
;
438 while (bitInRecord
>= mapBits
)
440 nextNodeNum
= ((NodeDescPtr
)mapNode
.buffer
)->fLink
;
441 if ( nextNodeNum
== 0)
443 err
= fsBTNoMoreMapNodesErr
;
447 err
= UpdateNode (btreePtr
, &mapNode
, 0, kLockTransaction
);
450 err
= GetNode (btreePtr
, nextNodeNum
, &mapNode
);
454 ModifyBlockStart(btreePtr
->fileRefNum
, &mapNode
);
458 mapStart
= (UInt16
*) GetRecordAddress (btreePtr
, mapNode
.buffer
, mapIndex
);
459 mapSize
= GetRecordSize (btreePtr
, mapNode
.buffer
, mapIndex
);
461 if (DEBUG_BUILD
&& mapSize
!= M_MapRecordSize (btreePtr
->nodeSize
) )
463 Panic ("\pExtendBTree: mapSize != M_MapRecordSize");
466 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
467 recStartBit
= totalMapBits
; // bit number of first bit in map record
468 totalMapBits
+= mapBits
;
470 bitInRecord
= nodeNum
- recStartBit
;
473 mapPos
= mapStart
+ ((nodeNum
- recStartBit
) >> 4);
474 bitInWord
= 15 - ((nodeNum
- recStartBit
) & 0x0000000F);
476 M_SWAP_BE16_SetBitNum (*mapPos
, bitInWord
);
480 } while (nodeNum
<= lastNewMapNodeNum
);
482 err
= UpdateNode (btreePtr
, &mapNode
, 0, kLockTransaction
);
486 //////////////////////////////// Success ////////////////////////////////////
490 btreePtr
->totalNodes
= newTotalNodes
;
491 btreePtr
->freeNodes
+= (newTotalNodes
- oldTotalNodes
) - newMapNodes
;
493 btreePtr
->flags
|= kBTHeaderDirty
; //\80\80 how about a macro for this
495 /* Force the b-tree header changes to disk */
496 (void) UpdateHeader (btreePtr
, true);
501 ////////////////////////////// Error Exit ///////////////////////////////////
505 (void) ReleaseNode (btreePtr
, &mapNode
);
506 (void) ReleaseNode (btreePtr
, &newNode
);
513 /*-------------------------------------------------------------------------------
515 Routine: GetMapNode - Get the next map node and pointer to the map record.
517 Function: Given a BlockDescriptor to a map node in nodePtr, GetMapNode releases
518 it and gets the next node. If nodePtr->buffer is nil, then the header
522 Input: btreePtr - pointer to control block for BTree file
523 nodePtr - pointer to a BlockDescriptor of a map node
525 Output: nodePtr - pointer to the BlockDescriptor for the next map node
526 mapPtr - pointer to the map record within the map node
527 mapSize - number of bytes in the map record
529 Result: noErr - success
530 fsBTNoMoreMapNodesErr - we've run out of map nodes
531 fsBTInvalidNodeErr - bad node, or not node type kMapNode
533 -------------------------------------------------------------------------------*/
535 OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
536 BlockDescriptor
*nodePtr
,
544 if (nodePtr
->buffer
!= nil
) // if iterator is valid...
546 nextNodeNum
= ((NodeDescPtr
)nodePtr
->buffer
)->fLink
;
547 if (nextNodeNum
== 0)
549 err
= fsBTNoMoreMapNodesErr
;
553 err
= ReleaseNode (btreePtr
, nodePtr
);
556 err
= GetNode (btreePtr
, nextNodeNum
, nodePtr
);
559 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTMapNode
)
561 err
= fsBTBadNodeType
;
565 ++btreePtr
->numMapNodesRead
;
568 err
= GetNode (btreePtr
, kHeaderNodeNum
, nodePtr
);
571 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTHeaderNode
)
573 err
= fsBTInvalidHeaderErr
; //\80\80 or fsBTBadNodeType
581 *mapPtr
= (UInt16
*) GetRecordAddress (btreePtr
, nodePtr
->buffer
, mapIndex
);
582 *mapSize
= GetRecordSize (btreePtr
, nodePtr
->buffer
, mapIndex
);
589 (void) ReleaseNode (btreePtr
, nodePtr
);
599 ////////////////////////////////// CalcMapBits //////////////////////////////////
601 UInt32
CalcMapBits (BTreeControlBlockPtr btreePtr
)
605 mapBits
= M_HeaderMapRecordSize (btreePtr
->nodeSize
) << 3;
607 while (mapBits
< btreePtr
->totalNodes
)
608 mapBits
+= M_MapRecordSize (btreePtr
->nodeSize
) << 3;