2 * Copyright (c) 2000 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
;
196 *nodeNum
= nodeNumber
;
200 ////////////////////////////////// Error Exit ///////////////////////////////////
204 (void) ReleaseNode (btreePtr
, &node
);
212 /*-------------------------------------------------------------------------------
214 Routine: FreeNode - Clear allocation bit for node.
216 Function: Finds the bit representing the node specified by nodeNum in the node
217 map and clears the bit.
220 Input: btreePtr - pointer to control block for BTree file
221 nodeNum - number of node to mark free
225 Result: noErr - success
226 fsBTNoMoreMapNodesErr - node number is beyond end of node map
227 != noErr - GetNode or ReleaseNode encountered some difficulty
228 -------------------------------------------------------------------------------*/
230 OSStatus
FreeNode (BTreeControlBlockPtr btreePtr
, UInt32 nodeNum
)
233 BlockDescriptor node
;
240 //////////////////////////// Find Map Record ////////////////////////////////
241 nodeIndex
= 0; // first node number of header map record
242 node
.buffer
= nil
; // invalidate node.buffer to get header node
243 node
.blockHeader
= nil
;
245 while (nodeNum
>= nodeIndex
)
247 err
= GetMapNode (btreePtr
, &node
, &mapPos
, &mapSize
);
250 nodeIndex
+= mapSize
<< 3; // covert to number of bits (nodes)
253 //////////////////////////// Mark Node Free /////////////////////////////////
256 ModifyBlockStart(btreePtr
->fileRefNum
, &node
);
258 nodeNum
-= (nodeIndex
- (mapSize
<< 3)); // relative to this map record
259 bitOffset
= 15 - (nodeNum
& 0x0000000F); // last 4 bits are bit offset
260 mapPos
+= nodeNum
>> 4; // point to word containing map bit
262 M_SWAP_BE16_ClearBitNum (*mapPos
, bitOffset
); // clear it
264 err
= UpdateNode (btreePtr
, &node
, 0, kLockTransaction
);
267 ++btreePtr
->freeNodes
;
268 btreePtr
->flags
|= kBTHeaderDirty
; // how about a macro for this
274 (void) ReleaseNode (btreePtr
, &node
);
281 /*-------------------------------------------------------------------------------
283 Routine: ExtendBTree - Call FSAgent to extend file, and allocate necessary map nodes.
285 Function: This routine calls the the FSAgent to extend the end of fork, if necessary,
286 to accomodate the number of nodes requested. It then allocates as many
287 map nodes as are necessary to account for all the nodes in the B*Tree.
288 If newTotalNodes is less than the current number of nodes, no action is
291 Note: Internal HFS File Manager BTree Module counts on an integral number of
292 long words in map records, although they are not long word aligned.
294 Input: btreePtr - pointer to control block for BTree file
295 newTotalNodes - total number of nodes the B*Tree is to extended to
299 Result: noErr - success
301 -------------------------------------------------------------------------------*/
303 OSStatus
ExtendBTree (BTreeControlBlockPtr btreePtr
,
304 UInt32 newTotalNodes
)
308 FSSize minEOF
, maxEOF
;
310 UInt32 oldTotalNodes
;
312 UInt32 mapBits
, totalMapBits
;
314 UInt32 nodeNum
, nextNodeNum
;
315 UInt32 firstNewMapNodeNum
, lastNewMapNodeNum
;
316 BlockDescriptor mapNode
, newNode
;
320 UInt16 mapNodeRecSize
;
321 UInt32 bitInWord
, bitInRecord
;
325 oldTotalNodes
= btreePtr
->totalNodes
;
326 if (newTotalNodes
<= oldTotalNodes
) // we're done!
329 nodeSize
= btreePtr
->nodeSize
;
330 filePtr
= GetFileControlBlock(btreePtr
->fileRefNum
);
332 mapNode
.buffer
= nil
;
333 mapNode
.blockHeader
= nil
;
334 newNode
.buffer
= nil
;
335 newNode
.blockHeader
= nil
;
337 mapNodeRecSize
= nodeSize
- sizeof(BTNodeDescriptor
) - 6; // 2 bytes of free space (see note)
340 //////////////////////// Count Bits In Node Map /////////////////////////////
344 err
= GetMapNode (btreePtr
, &mapNode
, &mapStart
, &mapSize
);
347 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
348 recStartBit
= totalMapBits
; // bit number of first bit in map record
349 totalMapBits
+= mapBits
;
351 } while ( ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
!= 0 );
353 if (DEBUG_BUILD
&& totalMapBits
!= CalcMapBits (btreePtr
))
354 Panic ("\pExtendBTree: totalMapBits != CalcMapBits");
356 /////////////////////// Extend LEOF If Necessary ////////////////////////////
358 minEOF
= (UInt64
)newTotalNodes
* (UInt64
)nodeSize
;
359 if ( filePtr
->fcbEOF
< minEOF
)
361 maxEOF
= (UInt64
)0x7fffffffLL
* (UInt64
)nodeSize
;
363 err
= btreePtr
->setEndOfForkProc (btreePtr
->fileRefNum
, minEOF
, maxEOF
);
368 //////////////////// Calc New Total Number Of Nodes /////////////////////////
370 newTotalNodes
= filePtr
->fcbEOF
/ nodeSize
; // hack!
371 // do we wish to perform any verification of newTotalNodes at this point?
373 btreePtr
->totalNodes
= newTotalNodes
; // do we need to update freeNodes here too?
376 ////////////// Calculate Number Of New Map Nodes Required ///////////////////
379 if (newTotalNodes
> totalMapBits
)
381 newMapNodes
= (((newTotalNodes
- totalMapBits
) >> 3) / mapNodeRecSize
) + 1;
382 firstNewMapNodeNum
= oldTotalNodes
;
383 lastNewMapNodeNum
= firstNewMapNodeNum
+ newMapNodes
- 1;
387 err
= ReleaseNode (btreePtr
, &mapNode
);
394 /////////////////////// Initialize New Map Nodes ////////////////////////////
395 // XXXdbg - this is the correct place for this:
396 ModifyBlockStart(btreePtr
->fileRefNum
, &mapNode
);
398 ((BTNodeDescriptor
*)mapNode
.buffer
)->fLink
= firstNewMapNodeNum
;
400 nodeNum
= firstNewMapNodeNum
;
403 err
= GetNewNode (btreePtr
, nodeNum
, &newNode
);
407 ModifyBlockStart(btreePtr
->fileRefNum
, &newNode
);
409 ((NodeDescPtr
)newNode
.buffer
)->numRecords
= 1;
410 ((NodeDescPtr
)newNode
.buffer
)->kind
= kBTMapNode
;
412 // set free space offset
413 *(UInt16
*)((Ptr
)newNode
.buffer
+ nodeSize
- 4) = nodeSize
- 6;
415 if (nodeNum
++ == lastNewMapNodeNum
)
418 ((BTNodeDescriptor
*)newNode
.buffer
)->fLink
= nodeNum
; // point to next map node
420 err
= UpdateNode (btreePtr
, &newNode
, 0, kLockTransaction
);
424 err
= UpdateNode (btreePtr
, &newNode
, 0, kLockTransaction
);
428 ///////////////////// Mark New Map Nodes Allocated //////////////////////////
430 nodeNum
= firstNewMapNodeNum
;
432 bitInRecord
= nodeNum
- recStartBit
;
434 while (bitInRecord
>= mapBits
)
436 nextNodeNum
= ((NodeDescPtr
)mapNode
.buffer
)->fLink
;
437 if ( nextNodeNum
== 0)
439 err
= fsBTNoMoreMapNodesErr
;
443 err
= UpdateNode (btreePtr
, &mapNode
, 0, kLockTransaction
);
446 err
= GetNode (btreePtr
, nextNodeNum
, &mapNode
);
450 ModifyBlockStart(btreePtr
->fileRefNum
, &mapNode
);
454 mapStart
= (UInt16
*) GetRecordAddress (btreePtr
, mapNode
.buffer
, mapIndex
);
455 mapSize
= GetRecordSize (btreePtr
, mapNode
.buffer
, mapIndex
);
457 if (DEBUG_BUILD
&& mapSize
!= M_MapRecordSize (btreePtr
->nodeSize
) )
459 Panic ("\pExtendBTree: mapSize != M_MapRecordSize");
462 mapBits
= mapSize
<< 3; // mapSize (in bytes) * 8
463 recStartBit
= totalMapBits
; // bit number of first bit in map record
464 totalMapBits
+= mapBits
;
466 bitInRecord
= nodeNum
- recStartBit
;
469 mapPos
= mapStart
+ ((nodeNum
- recStartBit
) >> 4);
470 bitInWord
= 15 - ((nodeNum
- recStartBit
) & 0x0000000F);
472 M_SWAP_BE16_SetBitNum (*mapPos
, bitInWord
);
476 } while (nodeNum
<= lastNewMapNodeNum
);
478 err
= UpdateNode (btreePtr
, &mapNode
, 0, kLockTransaction
);
482 //////////////////////////////// Success ////////////////////////////////////
486 btreePtr
->totalNodes
= newTotalNodes
;
487 btreePtr
->freeNodes
+= (newTotalNodes
- oldTotalNodes
) - newMapNodes
;
489 btreePtr
->flags
|= kBTHeaderDirty
; //\80\80 how about a macro for this
491 /* Force the b-tree header changes to disk */
492 (void) UpdateHeader (btreePtr
, true);
497 ////////////////////////////// Error Exit ///////////////////////////////////
501 (void) ReleaseNode (btreePtr
, &mapNode
);
502 (void) ReleaseNode (btreePtr
, &newNode
);
509 /*-------------------------------------------------------------------------------
511 Routine: GetMapNode - Get the next map node and pointer to the map record.
513 Function: Given a BlockDescriptor to a map node in nodePtr, GetMapNode releases
514 it and gets the next node. If nodePtr->buffer is nil, then the header
518 Input: btreePtr - pointer to control block for BTree file
519 nodePtr - pointer to a BlockDescriptor of a map node
521 Output: nodePtr - pointer to the BlockDescriptor for the next map node
522 mapPtr - pointer to the map record within the map node
523 mapSize - number of bytes in the map record
525 Result: noErr - success
526 fsBTNoMoreMapNodesErr - we've run out of map nodes
527 fsBTInvalidNodeErr - bad node, or not node type kMapNode
529 -------------------------------------------------------------------------------*/
531 OSStatus
GetMapNode (BTreeControlBlockPtr btreePtr
,
532 BlockDescriptor
*nodePtr
,
540 if (nodePtr
->buffer
!= nil
) // if iterator is valid...
542 nextNodeNum
= ((NodeDescPtr
)nodePtr
->buffer
)->fLink
;
543 if (nextNodeNum
== 0)
545 err
= fsBTNoMoreMapNodesErr
;
549 err
= ReleaseNode (btreePtr
, nodePtr
);
552 err
= GetNode (btreePtr
, nextNodeNum
, nodePtr
);
555 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTMapNode
)
557 err
= fsBTBadNodeType
;
561 ++btreePtr
->numMapNodesRead
;
564 err
= GetNode (btreePtr
, kHeaderNodeNum
, nodePtr
);
567 if ( ((NodeDescPtr
)nodePtr
->buffer
)->kind
!= kBTHeaderNode
)
569 err
= fsBTInvalidHeaderErr
; //\80\80 or fsBTBadNodeType
577 *mapPtr
= (UInt16
*) GetRecordAddress (btreePtr
, nodePtr
->buffer
, mapIndex
);
578 *mapSize
= GetRecordSize (btreePtr
, nodePtr
->buffer
, mapIndex
);
585 (void) ReleaseNode (btreePtr
, nodePtr
);
595 ////////////////////////////////// CalcMapBits //////////////////////////////////
597 UInt32
CalcMapBits (BTreeControlBlockPtr btreePtr
)
601 mapBits
= M_HeaderMapRecordSize (btreePtr
->nodeSize
) << 3;
603 while (mapBits
< btreePtr
->totalNodes
)
604 mapBits
+= M_MapRecordSize (btreePtr
->nodeSize
) << 3;