2140 lines
71 KiB
C
2140 lines
71 KiB
C
/*
|
|
(C) Copyright Digital Instrumentation Technology, Inc., 1990 - 1993
|
|
All Rights Reserved
|
|
*/
|
|
|
|
/*
|
|
DIT TransferPro macTree.c - Generic B*-Tree data structure
|
|
management functions, i.e. that work with both Catalog and Extents
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
#include "macSG.h" /* BOOL */
|
|
#include "macPort.h" /* MAX_TRANSFER */
|
|
#include "dm.h"
|
|
|
|
static char *Module = "macTree";
|
|
static unsigned int bitmapNodes(struct m_volume *,
|
|
struct bitmap_record *, unsigned int);
|
|
|
|
/*-------------------------- macBuildTree ------------------------------
|
|
Builds a B*-Tree from a buffer containing nodes of the tree in
|
|
Macintosh format.
|
|
------------------------------------------------------------------------*/
|
|
|
|
int macBuildTree ( volume, treeType, buffer )
|
|
struct m_volume *volume;
|
|
unsigned int treeType;
|
|
char *buffer;
|
|
{
|
|
int retval = E_NONE;
|
|
struct BtreeNode **tree;
|
|
char *bufptr = buffer;
|
|
unsigned int numnodes, bmpnodes;
|
|
int i, count;
|
|
int volmtreesize;
|
|
int headtreesize;
|
|
|
|
char *funcname = "MacBuildTree";
|
|
|
|
if (treeType == CATALOG_TREE )
|
|
{
|
|
tree = volume->catalog;
|
|
volmtreesize = volume->vib->drCTFlSize*sizeof(char);
|
|
}
|
|
else
|
|
{
|
|
tree = volume->extents;
|
|
volmtreesize = volume->vib->drXTFlSize*sizeof(char);
|
|
}
|
|
|
|
/* Unpack header node */
|
|
if ( (tree[0] = (struct BtreeNode *)malloc (sizeof (struct BtreeNode)) ) ==
|
|
(struct BtreeNode *)0)
|
|
{
|
|
retval = set_error( E_MEMORY, Module, funcname, "");
|
|
}
|
|
else
|
|
{
|
|
for( i = 0; i < NODE_SIZE; i++ )
|
|
{
|
|
tree[0]->BtNodes.nodeBytes[i] = 0;
|
|
}
|
|
|
|
if( (retval = macUnPackHeaderNode(&tree[0]->BtNodes.BtHeader, bufptr))
|
|
== E_NONE )
|
|
{
|
|
bufptr += tree[0]->BtNodes.BtHeader.hnHdrRec.hrNodeSize;
|
|
numnodes = tree[0]->BtNodes.BtHeader.hnHdrRec.hrTotalNodes -
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrFreeNodes;
|
|
}
|
|
}
|
|
|
|
if ( tree[0]->BtNodes.BtHeader.hnHdrRec.hrNodeSize <= 0 ||
|
|
numnodes > volume->maxNodes )
|
|
{
|
|
retval = set_error( E_RANGE, Module, funcname,
|
|
"Bad vib or %s tree header.", (treeType == CATALOG_TREE)?
|
|
"catalog" : "extents" );
|
|
}
|
|
|
|
bmpnodes = bitmapNodes(volume, (struct bitmap_record *)
|
|
tree[0]->BtNodes.BtHeader.hnBitMap.bitmap,
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrTotalNodes);
|
|
if ( bmpnodes != numnodes )
|
|
return (E_BTREEBMPNODE);
|
|
|
|
headtreesize = bmpnodes*tree[0]->BtNodes.BtHeader.hnHdrRec.hrNodeSize;
|
|
if ( headtreesize > volmtreesize)
|
|
return (E_BTREENODESZ);
|
|
|
|
/* Loop through the buffer, processing each node */
|
|
for( count = 1; retval == E_NONE &&
|
|
count < tree[0]->BtNodes.BtHeader.hnHdrRec.hrTotalNodes; count++ )
|
|
{
|
|
/* if node does not appear in the bitmap */
|
|
if ( !macInBitmapRec((struct bitmap_record *)
|
|
(tree[0]->BtNodes.BtHeader.hnBitMap.bitmap),count) )
|
|
{
|
|
/* zero this one out, it's not needed */
|
|
tree[count] = 0;
|
|
}
|
|
else if ( (tree[count] = (struct BtreeNode *)malloc(
|
|
sizeof(struct BtreeNode))) == (struct BtreeNode *)0 )
|
|
{
|
|
retval = set_error( E_MEMORY, Module, funcname, "malloc failed: %s",
|
|
"tree" );
|
|
}
|
|
else
|
|
{
|
|
for( i = 0; (unsigned short)i < tree[0]->BtNodes.BtHeader.hnHdrRec.hrNodeSize; i++ )
|
|
{
|
|
tree[count]->BtNodes.nodeBytes[i] = 0;
|
|
}
|
|
|
|
switch( (unsigned char) *(bufptr + NODE_TYPE_OFFSET) )
|
|
{
|
|
case INDEX_NODE:
|
|
retval = macUnPackIndexNode(treeType,&tree[count]->BtNodes.BtIndex,
|
|
bufptr );
|
|
break;
|
|
case BITMAP_NODE:
|
|
macUnPackMapNode(&tree[count]->BtNodes.BtMap,
|
|
bufptr );
|
|
break;
|
|
case LEAF_NODE:
|
|
retval = macUnPackLeafNode( treeType,
|
|
&tree[count]->BtNodes.BtLeaf, bufptr );
|
|
break;
|
|
default:
|
|
retval = set_error( E_MEDIUM, Module, funcname,
|
|
"bad node type at node %d: %x", count,
|
|
tree[count]->BtNodes.nodeBytes[NODE_TYPE_OFFSET] );
|
|
break;
|
|
}
|
|
}
|
|
bufptr += tree[0]->BtNodes.BtHeader.hnHdrRec.hrNodeSize;
|
|
}
|
|
|
|
return (retval);
|
|
}
|
|
|
|
/*-------------------------- searchTree ------------------------------
|
|
Finds a file or directory record in a B*-Tree
|
|
------------------------------------------------------------------------*/
|
|
int searchTree(volume, targetKey, treeType, targetRecNum, nodeNum )
|
|
struct m_volume *volume;
|
|
struct record_key *targetKey;
|
|
unsigned int treeType;
|
|
int *targetRecNum;
|
|
unsigned int *nodeNum;
|
|
{
|
|
int retval = E_NONE,
|
|
i = 0;
|
|
struct BtreeNode **tree;
|
|
char *funcname = "searchTree";
|
|
unsigned int rootNum = 0;
|
|
unsigned int treeNodes;
|
|
|
|
if (treeType == CATALOG_TREE )
|
|
{
|
|
tree = volume->catalog;
|
|
treeNodes = volume->vib->drCTFlSize/NODE_SIZE;
|
|
}
|
|
else
|
|
{
|
|
tree = volume->extents;
|
|
treeNodes = volume->vib->drXTFlSize/NODE_SIZE;
|
|
}
|
|
|
|
while( i < treeNodes &&
|
|
(!tree[i] || tree[i]->BtNodes.BtHeader.hnDesc.ndType !=
|
|
(unsigned char) HEADER_NODE) )
|
|
{
|
|
i++;
|
|
}
|
|
if( i == treeNodes )
|
|
{
|
|
retval = set_error(E_NOTFOUND, Module, funcname,
|
|
"Can't find header node in tree");
|
|
}
|
|
else if( (rootNum = tree[i]->BtNodes.BtHeader.hnHdrRec.hrRootNode) == 0 )
|
|
{
|
|
retval = set_error(E_NOTFOUND, Module, funcname,"");
|
|
}
|
|
|
|
if( retval == E_NONE )
|
|
{
|
|
retval=travTree(volume, targetKey, treeType, rootNum, targetRecNum,
|
|
nodeNum);
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
/*-------------------------- travTree ------------------------------
|
|
recurses through B*-Tree looking for location of leaf rec
|
|
------------------------------------------------------------------------*/
|
|
int travTree(volume, targetKey, treeType, curNode, targetRec, nodeNum)
|
|
struct m_volume *volume;
|
|
struct record_key *targetKey;
|
|
unsigned int treeType;
|
|
unsigned int curNode;
|
|
int *targetRec;
|
|
unsigned int *nodeNum;
|
|
{
|
|
int retval = E_NONE;
|
|
unsigned int nextNode;
|
|
struct BtreeNode **tree;
|
|
char *funcname = "travTree";
|
|
|
|
if (treeType == CATALOG_TREE )
|
|
{
|
|
tree = volume->catalog;
|
|
}
|
|
else
|
|
{
|
|
tree = volume->extents;
|
|
}
|
|
|
|
/* if arrived at appropriate leaf node, process records */
|
|
|
|
if ( curNode > volume->maxNodes || !tree[curNode] )
|
|
{
|
|
retval = set_error( E_RANGE, Module, funcname, "Node not found" );
|
|
}
|
|
else if( tree[curNode]->BtNodes.BtLeaf.lnDesc.ndType == LEAF_NODE )
|
|
{
|
|
retval = scanLeafRecs(targetKey, &tree[curNode]->BtNodes.BtLeaf,
|
|
targetRec, treeType);
|
|
*nodeNum = curNode;
|
|
}
|
|
else
|
|
{
|
|
retval = scanPtrRecs(targetKey, &tree[curNode]->BtNodes.BtIndex,
|
|
&nextNode, targetRec, treeType);
|
|
|
|
/* if not an exact hit, decrement numbers for next travTree call */
|
|
|
|
if( retval == E_NOTFOUND )
|
|
{
|
|
if ( *targetRec > 0 )
|
|
{
|
|
(*targetRec)--;
|
|
}
|
|
nextNode = tree[curNode]->BtNodes.BtIndex.
|
|
inRecList[*targetRec]->ptrPointer;
|
|
retval = clear_error();
|
|
}
|
|
|
|
if ( retval == E_NONE )
|
|
{
|
|
retval = travTree(volume, targetKey, treeType, nextNode, targetRec,
|
|
nodeNum);
|
|
}
|
|
}
|
|
return(retval);
|
|
}
|
|
|
|
/*--- macDelNodeFromTree ----------------------------------
|
|
*/
|
|
int macDelNodeFromTree( volume, nodeNum, tree, treeType )
|
|
struct m_volume *volume;
|
|
unsigned int nodeNum;
|
|
struct BtreeNode **tree;
|
|
int treeType;
|
|
{
|
|
int retval = E_NONE;
|
|
char *funcname = "macDelNodeFromTree";
|
|
int fNode = -1;
|
|
int bNode = -1;
|
|
|
|
if( nodeNum == 0 )
|
|
{
|
|
retval = set_error(E_PERMISSION, Module, funcname,
|
|
"Can't delete node zero");
|
|
}
|
|
else
|
|
{
|
|
/* if nodeNum'th node was last in a linked list */
|
|
if( tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndFLink == UNASSIGNED_NODE &&
|
|
tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndBLink != UNASSIGNED_NODE )
|
|
{
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrLastLeaf =
|
|
tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndBLink;
|
|
bNode = tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndBLink;
|
|
tree[bNode]->BtNodes.BtLeaf.lnDesc.ndFLink = UNASSIGNED_NODE;
|
|
}
|
|
|
|
/* if nodeNum'th node was first in a linked list */
|
|
else if( tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndFLink != UNASSIGNED_NODE &&
|
|
tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndBLink == UNASSIGNED_NODE )
|
|
{
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrFirstLeaf =
|
|
tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndFLink;
|
|
fNode = tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndFLink;
|
|
tree[fNode]->BtNodes.BtLeaf.lnDesc.ndBLink = UNASSIGNED_NODE;
|
|
}
|
|
/* if nodeNum'th node in middle of a linked list */
|
|
else if( tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndBLink != UNASSIGNED_NODE &&
|
|
tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndFLink != UNASSIGNED_NODE )
|
|
{
|
|
bNode = tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndBLink;
|
|
fNode = tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndFLink;
|
|
tree[fNode]->BtNodes.BtLeaf.lnDesc.ndBLink =
|
|
tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndBLink;
|
|
tree[bNode]->BtNodes.BtLeaf.lnDesc.ndFLink =
|
|
tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndFLink;
|
|
}
|
|
|
|
|
|
free( (char *) tree[nodeNum] );
|
|
tree[nodeNum] = 0;
|
|
|
|
/* update catalog header info */
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrFreeNodes++;
|
|
|
|
|
|
macClearBitmapRec((struct bitmap_record *)
|
|
(tree[0]->BtNodes.BtHeader.hnBitMap.bitmap), nodeNum);
|
|
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
macSetBitmapRec ( &volume->catBitmap, 0 );
|
|
macSetBitmapRec ( &volume->catBitmap, nodeNum );
|
|
if ( bNode >= 0 )
|
|
{
|
|
macSetBitmapRec ( &volume->catBitmap, bNode );
|
|
}
|
|
if ( fNode >= 0 )
|
|
{
|
|
macSetBitmapRec ( &volume->catBitmap, fNode );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
macSetBitmapRec ( &volume->extBitmap, 0 );
|
|
macSetBitmapRec ( &volume->extBitmap, nodeNum );
|
|
if ( bNode >= 0 )
|
|
{
|
|
macSetBitmapRec ( &volume->extBitmap, bNode );
|
|
}
|
|
if ( fNode >= 0 )
|
|
{
|
|
macSetBitmapRec ( &volume->extBitmap, fNode );
|
|
}
|
|
}
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
|
|
/*--------------------- macDelRecFromTree ------------------------------
|
|
Delete a record from recNum'th position in nodeNum'th node of tree
|
|
assumes that all necessary checks have been made.
|
|
---------------------------------------------------------------------*/
|
|
|
|
int macDelRecFromTree( volume, nodeNum, recNum, treeType )
|
|
struct m_volume *volume;
|
|
unsigned int nodeNum;
|
|
int recNum;
|
|
int treeType;
|
|
{
|
|
int retval = E_NONE;
|
|
struct BtreeNode **tree;
|
|
char *funcname = "macDelRecFromTree";
|
|
int j;
|
|
unsigned int parNode = UNASSIGNED_NODE;
|
|
int parRec = UNASSIGNED_REC;
|
|
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
tree = volume->catalog;
|
|
}
|
|
else
|
|
{
|
|
tree = volume->extents;
|
|
}
|
|
|
|
if( tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndType == LEAF_NODE &&
|
|
((struct thread_record *)tree[nodeNum]->BtNodes.BtLeaf.lnRecList[recNum])
|
|
->thdType != THREAD_REC && treeType == CATALOG_TREE )
|
|
{
|
|
retval = macDelRecFromDir( volume, recNum, nodeNum );
|
|
}
|
|
|
|
if ( retval == E_NONE )
|
|
{
|
|
/* look for the parent before we free things up */
|
|
if ( recNum == 0 &&
|
|
(retval = macFindParent(nodeNum,tree,&parNode,&parRec,
|
|
treeType)) != E_NONE )
|
|
{
|
|
;
|
|
}
|
|
else if( tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndType == INDEX_NODE )
|
|
{
|
|
free ( tree[nodeNum]->BtNodes.BtIndex.inRecList[recNum] );
|
|
tree[nodeNum]->BtNodes.BtIndex.inRecList[recNum] = 0;
|
|
}
|
|
else if(tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndType == LEAF_NODE)
|
|
{
|
|
free ( tree[nodeNum]->BtNodes.BtLeaf.lnRecList[recNum] );
|
|
tree[nodeNum]->BtNodes.BtLeaf.lnRecList[recNum] = 0;
|
|
}
|
|
}
|
|
|
|
/* riffle existing records toward top of list */
|
|
for( j = recNum;
|
|
j < (int)(tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndRecs-1)
|
|
&& retval == E_NONE; j++ )
|
|
{
|
|
if( tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndType == INDEX_NODE )
|
|
{
|
|
tree[nodeNum]->BtNodes.BtIndex.inRecList[j] =
|
|
tree[nodeNum]->BtNodes.BtIndex.inRecList[j+1];
|
|
}
|
|
else if(tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndType == LEAF_NODE)
|
|
{
|
|
tree[nodeNum]->BtNodes.BtLeaf.lnRecList[j] =
|
|
tree[nodeNum]->BtNodes.BtLeaf.lnRecList[j+1];
|
|
}
|
|
else
|
|
{
|
|
retval = set_error(E_RANGE, Module, funcname,
|
|
"Unrecognized node type in tree.");
|
|
}
|
|
}
|
|
|
|
if( retval == E_NONE )
|
|
{
|
|
|
|
if (tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndType == LEAF_NODE )
|
|
{
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrTotalRecs--;
|
|
}
|
|
(tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndRecs) -= 1;
|
|
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
macSetBitmapRec ( &volume->catBitmap, 0 );
|
|
macSetBitmapRec ( &volume->catBitmap, nodeNum );
|
|
}
|
|
else
|
|
{
|
|
macSetBitmapRec ( &volume->extBitmap, 0 );
|
|
macSetBitmapRec ( &volume->extBitmap, nodeNum );
|
|
}
|
|
|
|
/* delete root node if now empty -- only with extents tree! */
|
|
if( nodeNum == tree[0]->BtNodes.BtHeader.hnHdrRec.hrRootNode )
|
|
{
|
|
if( tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndRecs == 0 &&
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrTotalRecs == 0 &&
|
|
(retval = macDelNodeFromTree(volume, nodeNum, tree, treeType))
|
|
== E_NONE )
|
|
{
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrDepthCount = 0;
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrRootNode = 0;
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrFirstLeaf = 0;
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrLastLeaf = 0;
|
|
}
|
|
}
|
|
/* adjust parents of child nodes if deletion repercusses above */
|
|
else if( recNum == 0 )
|
|
{
|
|
/* if records still remain in this node, update parent index node */
|
|
if(retval == E_NONE &&
|
|
tree[nodeNum]->BtNodes.BtLeaf.lnDesc.ndRecs > 0 )
|
|
{
|
|
retval = macCorrectParents( volume, nodeNum,
|
|
recNum, parNode, parRec, treeType );
|
|
}
|
|
/* if no records remain, remove node from tree */
|
|
else if( retval == E_NONE &&
|
|
(retval = macDelRecFromTree(volume, parNode, parRec,
|
|
treeType)) == E_NONE )
|
|
{
|
|
retval = macDelNodeFromTree( volume, nodeNum, tree, treeType );
|
|
}
|
|
if( retval == E_NONE )
|
|
{
|
|
if( tree[tree[0]->BtNodes.BtHeader.hnHdrRec.hrRootNode]->
|
|
BtNodes.BtIndex.inDesc.ndType == INDEX_NODE &&
|
|
tree[tree[0]->BtNodes.BtHeader.hnHdrRec.hrRootNode]->
|
|
BtNodes.BtIndex.inDesc.ndRecs == 1 )
|
|
{
|
|
retval = macDelOldRootFromTree( volume, tree, treeType );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return( retval );
|
|
}
|
|
|
|
/*--- macCorrectParents ----------------------------------
|
|
* propagates change in key record to root of tree if necessary
|
|
*/
|
|
|
|
int macCorrectParents( volume, childNodeNum, childRecNum, parNodeNum, parRecNum,
|
|
treeType )
|
|
struct m_volume *volume;
|
|
unsigned int childNodeNum;
|
|
int childRecNum;
|
|
unsigned int parNodeNum;
|
|
int parRecNum;
|
|
int treeType;
|
|
{
|
|
int retval = E_NONE;
|
|
struct BtreeNode **tree;
|
|
unsigned int newParNode = 0;
|
|
int newParRec = 0;
|
|
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
tree = volume->catalog;
|
|
}
|
|
else
|
|
{
|
|
tree = volume->extents;
|
|
}
|
|
if( tree[childNodeNum]->BtNodes.BtIndex.inDesc.ndType == INDEX_NODE )
|
|
{
|
|
/* update parent pointer record of a child pointer record */
|
|
memcpy( (char *)tree[parNodeNum]->BtNodes.BtIndex.
|
|
inRecList[parRecNum], (char *)tree[childNodeNum]->BtNodes.BtIndex.
|
|
inRecList[childRecNum], sizeof(struct record_key) );
|
|
}
|
|
else /* if LEAF_NODE */
|
|
{
|
|
memcpy( (char *)tree[parNodeNum]->BtNodes.BtIndex.
|
|
inRecList[parRecNum], (char *)tree[childNodeNum]->BtNodes.BtLeaf.
|
|
lnRecList[childRecNum], sizeof(struct record_key) );
|
|
tree[parNodeNum]->BtNodes.BtIndex.inRecList[parRecNum]->ptrRecKey.
|
|
key.ckr.ckrKeyLen = (treeType == EXTENTS_TREE)?
|
|
EXTENT_KEYLENGTH : POINTER_REC_KEYLENGTH;
|
|
}
|
|
|
|
if( parRecNum == 0 &&
|
|
parNodeNum != tree[0]->BtNodes.BtHeader.hnHdrRec.hrRootNode )
|
|
{
|
|
/* find parent node and record position */
|
|
retval = macFindParent(parNodeNum, tree, &newParNode, &newParRec,
|
|
treeType);
|
|
|
|
if( retval == E_NONE )
|
|
{
|
|
retval = macCorrectParents( volume, parNodeNum, parRecNum,
|
|
newParNode, newParRec, treeType );
|
|
}
|
|
}
|
|
if ( retval == E_NONE )
|
|
{
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
macSetBitmapRec ( &volume->catBitmap, parNodeNum );
|
|
}
|
|
else
|
|
{
|
|
macSetBitmapRec ( &volume->extBitmap, parNodeNum );
|
|
}
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
|
|
/*--- macAddRecToTree ----------------------------------
|
|
* adds rec to currNode
|
|
*/
|
|
|
|
int macAddRecToTree( volume, currNode, rec, currRecNum, treeType )
|
|
struct m_volume *volume;
|
|
int *currNode;
|
|
void *rec;
|
|
int *currRecNum;
|
|
int treeType;
|
|
{
|
|
int retval = E_NONE,
|
|
scanResult = 0,
|
|
recLocus = 0;
|
|
struct BtreeNode **tree;
|
|
char *funcname = "macAddRecToTree";
|
|
unsigned int newNode = UNASSIGNED_NODE;
|
|
void *newRec;
|
|
unsigned int parNode;
|
|
int parRec;
|
|
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
tree = volume->catalog;
|
|
}
|
|
else
|
|
{
|
|
tree = volume->extents;
|
|
}
|
|
|
|
/* following calls are to get a value in recLocus */
|
|
if( tree[*currNode]->BtNodes.BtIndex.inDesc.ndType == INDEX_NODE )
|
|
{
|
|
retval = scanPtrRecs((struct record_key *)rec, (struct index_node *)
|
|
tree[*currNode], (unsigned int *)&scanResult, &recLocus, treeType);
|
|
|
|
if( retval == E_NOTFOUND )
|
|
{
|
|
retval = clear_error();
|
|
}
|
|
|
|
if( scanResult >= tree[0]->BtNodes.BtHeader.hnHdrRec.hrTotalNodes ||
|
|
(unsigned short)recLocus > tree[*currNode]->BtNodes.BtIndex.inDesc.ndRecs ||
|
|
recLocus < 0 )
|
|
{
|
|
retval = set_error(E_RANGE, Module, funcname,
|
|
"Can't add rec to tree: vib->drCTFlSize = %d and ndRecs =%d\n",
|
|
volume->vib->drCTFlSize, tree[*currNode]->BtNodes.BtIndex.inDesc.ndRecs);
|
|
}
|
|
}
|
|
else if( tree[*currNode]->BtNodes.BtLeaf.lnDesc.ndType == LEAF_NODE )
|
|
{
|
|
retval = scanLeafRecs( &((struct file_record *)rec)->filRecKey,
|
|
(struct leaf_node *)tree[*currNode], &recLocus, treeType);
|
|
|
|
if( (unsigned short)recLocus > tree[*currNode]->BtNodes.BtLeaf.lnDesc.ndRecs ||
|
|
recLocus < 0 )
|
|
{
|
|
retval = set_error(E_RANGE,Module,funcname,
|
|
"Can't add record to node.");
|
|
}
|
|
|
|
if( retval == E_NOTFOUND )
|
|
{
|
|
retval = clear_error();
|
|
}
|
|
}
|
|
|
|
if( tree[*currNode]->BtNodes.BtIndex.inDesc.ndType == INDEX_NODE )
|
|
{
|
|
if ( (newRec = (struct pointer_record *) malloc
|
|
(sizeof (struct pointer_record)) )
|
|
== (struct pointer_record *)0 )
|
|
{
|
|
retval = set_error(E_MEMORY, Module, funcname,
|
|
"Insufficent memory");
|
|
}
|
|
else
|
|
{
|
|
memcpy ( (char *)newRec, (char *)rec,
|
|
sizeof( struct pointer_record));
|
|
}
|
|
}
|
|
else if( tree[*currNode]->BtNodes.BtLeaf.lnDesc.ndType == LEAF_NODE )
|
|
{
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
switch ( *((char *)rec + sizeof(struct record_key)) )
|
|
{
|
|
case FILE_REC:
|
|
if ( (newRec = (struct file_record *) malloc
|
|
(sizeof (struct file_record)) )
|
|
== (struct file_record *)0 )
|
|
{
|
|
retval = set_error(E_MEMORY, Module, funcname,
|
|
"Insufficent memory");
|
|
}
|
|
else
|
|
{
|
|
memcpy ( (char *)newRec, (char *)rec,
|
|
sizeof( struct file_record));
|
|
}
|
|
break;
|
|
|
|
case DIRECTORY_REC:
|
|
if ( (newRec = (struct dir_record *) malloc
|
|
(sizeof (struct dir_record)) )
|
|
== (struct dir_record *)0 )
|
|
{
|
|
retval = set_error(E_MEMORY, Module, funcname,
|
|
"Insufficent memory");
|
|
}
|
|
else
|
|
{
|
|
memcpy ( (char *)newRec, (char *)rec,
|
|
sizeof( struct dir_record));
|
|
}
|
|
break;
|
|
|
|
case THREAD_REC:
|
|
if ( (newRec = (struct thread_record *) malloc
|
|
(sizeof (struct thread_record)) )
|
|
== (struct thread_record *)0 )
|
|
{
|
|
retval = set_error(E_MEMORY, Module, funcname,
|
|
"Insufficent memory");
|
|
}
|
|
else
|
|
{
|
|
memcpy ( (char *)newRec, (char *)rec,
|
|
sizeof( struct thread_record));
|
|
}
|
|
break;
|
|
|
|
case ALIAS_REC:
|
|
if ( (newRec = (struct alias_record *) malloc
|
|
(sizeof (struct alias_record)) )
|
|
== (struct alias_record *)0 )
|
|
{
|
|
retval = set_error(E_MEMORY, Module, funcname,
|
|
"Insufficent memory");
|
|
}
|
|
else
|
|
{
|
|
memcpy ( (char *)newRec, (char *)rec,
|
|
sizeof( struct alias_record));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
retval = set_error (E_RANGE, Module, funcname,
|
|
"Unrecogized record type.");
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( (newRec = (struct extent_record *) malloc
|
|
(sizeof (struct extent_record)) )
|
|
== (struct extent_record *)0 )
|
|
{
|
|
retval = set_error(E_MEMORY, Module, funcname,
|
|
"Insufficent memory");
|
|
}
|
|
else
|
|
{
|
|
memcpy ( (char *)newRec, (char *)rec,
|
|
sizeof( struct extent_record));
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( retval == E_NONE && recLocus == 0 &&
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrDepthCount > 1 &&
|
|
*currNode != tree[0]->BtNodes.BtHeader.hnHdrRec.hrRootNode )
|
|
{
|
|
retval = macFindParent( *currNode, tree, &parNode, &parRec, treeType );
|
|
}
|
|
|
|
if( retval == E_NONE )
|
|
{
|
|
retval = macInsertRec(volume, newRec, *currNode, recLocus,
|
|
&newNode, treeType );
|
|
}
|
|
|
|
/* only update index nodes if new record replaced first record */
|
|
if( retval == E_NONE && recLocus == 0 )
|
|
{
|
|
retval = macCorrectPtrRec( volume, tree, *currNode, parNode, parRec,
|
|
treeType );
|
|
}
|
|
|
|
/* if new node was allocated, add pointer record for it */
|
|
if( retval == E_NONE && newNode != UNASSIGNED_NODE )
|
|
{
|
|
retval = macAddNodeToTree( volume, *currNode, newNode, treeType );
|
|
}
|
|
|
|
if( retval == E_NONE )
|
|
{
|
|
*currRecNum = recLocus;
|
|
if( tree[*currNode]->BtNodes.BtLeaf.lnDesc.ndType == LEAF_NODE )
|
|
{
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrTotalRecs++;
|
|
}
|
|
|
|
/* tell calling function where new record is */
|
|
if ( newNode != UNASSIGNED_NODE &&
|
|
newRec == tree[newNode]->BtNodes.BtLeaf.lnRecList[0] )
|
|
{
|
|
*currNode = newNode;
|
|
*currRecNum = 0;
|
|
}
|
|
else if ( newNode != UNASSIGNED_NODE &&
|
|
newRec == tree[newNode]->BtNodes.BtLeaf.lnRecList[1] )
|
|
{
|
|
*currNode = newNode;
|
|
*currRecNum = 1;
|
|
}
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
macSetBitmapRec ( &volume->catBitmap, 0 );
|
|
}
|
|
else
|
|
{
|
|
macSetBitmapRec ( &volume->extBitmap, 0 );
|
|
}
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
|
|
/*--------------- macInsertRec -------------------------------------------
|
|
*
|
|
* Currently this function always creates a new node if there is not room
|
|
* in the current one. In order to conserve space in the tree, it should really
|
|
* look for a forward link first, and try to add it there. This could
|
|
* probably be done with a recursive call to macInsertRec() in the code
|
|
* below. The trick is that when you pass the rec on to the next node, you
|
|
* are forcing an update on the index record above it (if there is one),
|
|
* since the inserted record will always be the first record in the forward
|
|
* link. This modification could conceivably introduce some difficult-to-
|
|
* discover bugs, and should be undertaken with extreme caution and a good
|
|
* backup, as well as lots of testing.
|
|
*/
|
|
|
|
int macInsertRec( volume, rec, currNode, recNum, newNodeNum, treeType )
|
|
struct m_volume *volume;
|
|
void *rec;
|
|
unsigned int currNode;
|
|
int recNum;
|
|
unsigned int *newNodeNum;
|
|
unsigned int treeType;
|
|
{
|
|
int retval = E_NONE,
|
|
counter = 0,
|
|
currNodeRecs = 0,
|
|
j;
|
|
struct BtreeNode **tree;
|
|
char *funcname="macInsertRec";
|
|
|
|
|
|
if (treeType == CATALOG_TREE )
|
|
{
|
|
tree = volume->catalog;
|
|
}
|
|
else
|
|
{
|
|
tree = volume->extents;
|
|
}
|
|
|
|
/* move existing records down to make room for new one */
|
|
|
|
for( j = tree[currNode]->BtNodes.BtLeaf.lnDesc.ndRecs;
|
|
j > recNum && retval == E_NONE; j-- )
|
|
{
|
|
if( tree[currNode]->BtNodes.BtLeaf.lnDesc.ndType == INDEX_NODE )
|
|
{
|
|
tree[currNode]->BtNodes.BtIndex.inRecList[j] =
|
|
tree[currNode]->BtNodes.BtIndex.inRecList[j-1];
|
|
}
|
|
else if(tree[currNode]->BtNodes.BtLeaf.lnDesc.ndType == LEAF_NODE)
|
|
{
|
|
tree[currNode]->BtNodes.BtLeaf.lnRecList[j] =
|
|
tree[currNode]->BtNodes.BtLeaf.lnRecList[j-1];
|
|
}
|
|
else
|
|
{
|
|
retval = set_error(E_RANGE, Module, funcname,
|
|
"Unrecognized node type in tree.");
|
|
}
|
|
}
|
|
/* add the new record */
|
|
if( retval == E_NONE )
|
|
{
|
|
if( tree[currNode]->BtNodes.BtIndex.inDesc.ndType == INDEX_NODE )
|
|
{
|
|
tree[currNode]->BtNodes.BtIndex.inRecList[j] =
|
|
(struct pointer_record *)rec;
|
|
tree[currNode]->BtNodes.BtIndex.inDesc.ndRecs++;
|
|
}
|
|
else if(tree[currNode]->BtNodes.BtLeaf.lnDesc.ndType == LEAF_NODE)
|
|
{
|
|
tree[currNode]->BtNodes.BtLeaf.lnRecList[j] = rec;
|
|
tree[currNode]->BtNodes.BtLeaf.lnDesc.ndRecs++;
|
|
}
|
|
else
|
|
{
|
|
retval = set_error(E_RANGE, Module, funcname,
|
|
"Unrecognized node type in tree.");
|
|
}
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
macSetBitmapRec ( &volume->catBitmap, 0 );
|
|
macSetBitmapRec ( &volume->catBitmap, currNode );
|
|
}
|
|
else
|
|
{
|
|
macSetBitmapRec ( &volume->extBitmap, 0 );
|
|
macSetBitmapRec ( &volume->extBitmap, currNode );
|
|
}
|
|
}
|
|
|
|
/* calculate number of records desired in this node */
|
|
if( retval == E_NONE )
|
|
{
|
|
currNodeRecs = macCountNdRecs((struct leaf_node *)tree[currNode],
|
|
treeType);
|
|
}
|
|
|
|
/* add overflow record(s) to new node */
|
|
if( retval == E_NONE &&
|
|
(unsigned short)currNodeRecs <
|
|
(tree[currNode]->BtNodes.BtLeaf.lnDesc.ndRecs) )
|
|
{
|
|
if( (retval = macGetNextNode( volume, currNode, newNodeNum, treeType ))
|
|
!= E_NONE )
|
|
{
|
|
; /* call for new node failed */
|
|
}
|
|
else if( tree[currNode]->BtNodes.BtLeaf.lnDesc.ndType == LEAF_NODE )
|
|
{
|
|
for( j = 0, counter = currNodeRecs;
|
|
counter <
|
|
(int)((tree[currNode]->BtNodes.BtLeaf.lnDesc.ndRecs)+1);
|
|
counter++, j++ )
|
|
{
|
|
tree[*newNodeNum]->BtNodes.BtLeaf.lnRecList[j] =
|
|
tree[currNode]->BtNodes.BtLeaf.lnRecList[counter];
|
|
tree[currNode]->BtNodes.BtLeaf.lnRecList[counter] = 0;
|
|
tree[*newNodeNum]->BtNodes.BtLeaf.lnDesc.ndRecs++;
|
|
tree[currNode]->BtNodes.BtLeaf.lnDesc.ndRecs--;
|
|
}
|
|
}
|
|
else if(tree[currNode]->BtNodes.BtIndex.inDesc.ndType
|
|
== INDEX_NODE )
|
|
{
|
|
for( j = 0, counter = currNodeRecs;
|
|
counter <
|
|
(int)((tree[currNode]->BtNodes.BtLeaf.lnDesc.ndRecs)+1);
|
|
counter++, j++ )
|
|
{
|
|
tree[*newNodeNum]->BtNodes.BtIndex.inRecList[j] =
|
|
tree[currNode]->BtNodes.BtIndex.inRecList[counter];
|
|
tree[currNode]->BtNodes.BtIndex.inRecList[counter] = 0;
|
|
tree[*newNodeNum]->BtNodes.BtIndex.inDesc.ndRecs++;
|
|
tree[currNode]->BtNodes.BtIndex.inDesc.ndRecs--;
|
|
}
|
|
}
|
|
if ( retval == E_NONE )
|
|
{
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
macSetBitmapRec ( &volume->catBitmap, *newNodeNum );
|
|
}
|
|
else
|
|
{
|
|
macSetBitmapRec ( &volume->extBitmap, *newNodeNum );
|
|
}
|
|
|
|
if ( (unsigned short)recNum >= tree[currNode]->BtNodes.BtIndex.inDesc.ndRecs )
|
|
{
|
|
recNum = recNum -
|
|
tree[currNode]->BtNodes.BtIndex.inDesc.ndRecs;
|
|
currNode = *newNodeNum;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* update altered node */
|
|
if( retval == E_NONE && treeType == CATALOG_TREE )
|
|
{
|
|
if( tree[currNode]->BtNodes.BtLeaf.lnDesc.ndType == LEAF_NODE &&
|
|
((struct thread_record *)tree[currNode]->BtNodes.BtLeaf.
|
|
lnRecList[recNum])->thdType != THREAD_REC )
|
|
{
|
|
retval = macAddRecToDir( volume, recNum, currNode );
|
|
}
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
/*--------------- macCorrectPtrRec -------------------------------------------
|
|
* updates index nodes if necessary.
|
|
*/
|
|
|
|
int macCorrectPtrRec( volume, tree, currNode, parNode, parRec, treeType )
|
|
struct m_volume *volume;
|
|
struct BtreeNode **tree;
|
|
unsigned int currNode;
|
|
unsigned int parNode;
|
|
int parRec;
|
|
unsigned int treeType;
|
|
{
|
|
int retval = E_NONE;
|
|
char *funcname="macCorrectPtrRec";
|
|
|
|
/* find parent index node */
|
|
if( currNode == tree[0]->BtNodes.BtHeader.hnHdrRec.hrRootNode )
|
|
{
|
|
;
|
|
}
|
|
else
|
|
{
|
|
if( retval == E_NONE )
|
|
{
|
|
/* check values returned */
|
|
if( (unsigned short)parRec >
|
|
tree[parNode]->BtNodes.BtIndex.inDesc.ndRecs ||
|
|
tree[parNode]->BtNodes.BtIndex.inRecList[parRec]->ptrPointer
|
|
!= currNode)
|
|
{
|
|
retval = set_error(E_NOTFOUND,Module,funcname,
|
|
"Can't find parent node.");
|
|
}
|
|
|
|
/* update pointer record data */
|
|
if( retval == E_NONE )
|
|
{
|
|
memcpy( (char *)tree[parNode]->BtNodes.BtIndex.
|
|
inRecList[parRec], (char *)tree[currNode]->BtNodes.
|
|
BtLeaf.lnRecList[0], sizeof(struct record_key) );
|
|
|
|
/* reset correct pointer ckrKeyLen */
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
tree[parNode]->BtNodes.BtIndex.inRecList[parRec]->ptrRecKey.
|
|
key.ckr.ckrKeyLen = POINTER_REC_KEYLENGTH;
|
|
macSetBitmapRec (&volume->catBitmap, parNode);
|
|
}
|
|
else
|
|
{
|
|
tree[parNode]->BtNodes.BtIndex.inRecList[parRec]->ptrRecKey.
|
|
key.ckr.ckrKeyLen = EXTENT_KEYLENGTH;
|
|
macSetBitmapRec (&volume->extBitmap, parNode);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
/*--------------- macAddNodeToTree -------------------------------------------
|
|
*
|
|
* add new node to the tree.
|
|
*
|
|
*/
|
|
|
|
int macAddNodeToTree(volume, currNode, newNode, treeType )
|
|
struct m_volume *volume;
|
|
unsigned int currNode;
|
|
unsigned int newNode;
|
|
unsigned int treeType;
|
|
{
|
|
int retval = E_NONE,
|
|
parRec = 0;
|
|
unsigned int parNode = 0;
|
|
struct pointer_record newPtrRec;
|
|
struct BtreeNode **tree;
|
|
|
|
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
tree = volume->catalog;
|
|
}
|
|
else
|
|
{
|
|
tree = volume->extents;
|
|
}
|
|
/* special case: add level to tree */
|
|
if( currNode == tree[0]->BtNodes.BtHeader.hnHdrRec.hrRootNode )
|
|
{
|
|
retval = macAddNewRootToTree( volume, currNode, newNode, treeType );
|
|
}
|
|
else
|
|
{
|
|
/* find parent index node for currNode */
|
|
retval = macFindParent( currNode, tree, &parNode, &parRec, treeType );
|
|
|
|
/* slot for new pointer record will immediately follow that for
|
|
currNode */
|
|
if( retval == E_NONE )
|
|
{
|
|
memcpy( (char *)&newPtrRec.ptrRecKey.key.ckr,
|
|
(char *)tree[newNode]->BtNodes.BtLeaf.lnRecList[0],
|
|
sizeof(struct record_key) );
|
|
|
|
/* reset correct pointer ckrKeyLen */
|
|
if ( treeType == EXTENTS_TREE )
|
|
{
|
|
newPtrRec.ptrRecKey.key.ckr.ckrKeyLen = EXTENT_KEYLENGTH;
|
|
}
|
|
else
|
|
{
|
|
newPtrRec.ptrRecKey.key.ckr.ckrKeyLen = POINTER_REC_KEYLENGTH;
|
|
}
|
|
newPtrRec.ptrPointer = newNode;
|
|
|
|
/* add the new pointer record to parent node */
|
|
retval = macAddRecToTree( volume,(int *) &parNode,
|
|
(void *)&newPtrRec, &parRec, treeType );
|
|
|
|
/* current strategy adds only successor leaf nodes */
|
|
if( retval == E_NONE &&
|
|
tree[newNode]->BtNodes.BtLeaf.lnDesc.ndType == LEAF_NODE
|
|
&& tree[newNode]->BtNodes.BtLeaf.lnDesc.ndFLink == 0 )
|
|
{
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrLastLeaf = newNode;
|
|
}
|
|
}
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
|
|
/*--------------- macAddNewRootToTree -------------------------------------------
|
|
* creates a new root node for tree
|
|
*/
|
|
|
|
int macAddNewRootToTree( volume, child1, child2, treeType )
|
|
struct m_volume *volume;
|
|
unsigned int child1;
|
|
unsigned int child2;
|
|
unsigned int treeType;
|
|
{
|
|
int retval = E_NONE;
|
|
unsigned int newRootNode;
|
|
struct BtreeNode **tree;
|
|
char *funcname = "macAddNewRootToTree";
|
|
|
|
if ( treeType == CATALOG_TREE)
|
|
{
|
|
tree = volume->catalog;
|
|
}
|
|
else
|
|
{
|
|
tree = volume->extents;
|
|
}
|
|
if ( (retval = macGetNextNode(volume,UNASSIGNED_NODE,&newRootNode,
|
|
treeType)) == E_NONE )
|
|
{
|
|
tree[newRootNode]->BtNodes.BtIndex.inDesc.ndFLink = UNASSIGNED_NODE;
|
|
tree[newRootNode]->BtNodes.BtIndex.inDesc.ndBLink = UNASSIGNED_NODE;
|
|
tree[newRootNode]->BtNodes.BtIndex.inDesc.ndType = INDEX_NODE;
|
|
tree[newRootNode]->BtNodes.BtIndex.inDesc.ndLevel =
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrDepthCount+1;
|
|
tree[newRootNode]->BtNodes.BtIndex.inDesc.ndRecs = (short)2;
|
|
tree[newRootNode]->BtNodes.BtIndex.inDesc.ndReserved = 0;
|
|
|
|
if ( (tree[newRootNode]->BtNodes.BtIndex.inRecList[0] =
|
|
(struct pointer_record *)malloc(sizeof (struct pointer_record)) )
|
|
== (struct pointer_record *)0)
|
|
{
|
|
retval = set_error (E_MEMORY, Module, funcname,
|
|
"Insufficient memory.");
|
|
}
|
|
else if ( (tree[newRootNode]->BtNodes.BtIndex.inRecList[1] =
|
|
(struct pointer_record *)malloc(sizeof (struct pointer_record)) )
|
|
== (struct pointer_record *)0)
|
|
{
|
|
free (tree[newRootNode]->BtNodes.BtIndex.inRecList[0]);
|
|
tree[newRootNode]->BtNodes.BtIndex.inRecList[0] = 0;
|
|
retval = set_error (E_MEMORY, Module, funcname,
|
|
"Insufficient memory.");
|
|
}
|
|
|
|
if ( retval == E_NONE )
|
|
{
|
|
/* child1 */
|
|
memcpy( (char *)tree[newRootNode]-> BtNodes.BtIndex.inRecList[0],
|
|
(char *)tree[child1]-> BtNodes.BtLeaf.lnRecList[0],
|
|
sizeof(struct record_key) );
|
|
tree[newRootNode]->BtNodes.BtIndex.inRecList[0]->
|
|
ptrRecKey.key.ckr.ckrKeyLen = (treeType == EXTENTS_TREE)?
|
|
EXTENT_KEYLENGTH : POINTER_REC_KEYLENGTH;
|
|
tree[newRootNode]->BtNodes.BtIndex.inRecList[0]->ptrPointer =
|
|
child1;
|
|
|
|
/* child2 */
|
|
memcpy( (char *)tree[newRootNode]->BtNodes.BtIndex.inRecList[1],
|
|
(char *)tree[child2]->BtNodes.BtLeaf.lnRecList[0],
|
|
sizeof(struct record_key) );
|
|
tree[newRootNode]->BtNodes.BtIndex. inRecList[1]->
|
|
ptrRecKey.key.ckr.ckrKeyLen = (treeType == EXTENTS_TREE)?
|
|
EXTENT_KEYLENGTH : POINTER_REC_KEYLENGTH;
|
|
tree[newRootNode]->BtNodes.BtIndex.inRecList[1]->ptrPointer =
|
|
child2;
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrRootNode = newRootNode;
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrDepthCount++;
|
|
}
|
|
|
|
if ( retval == E_NONE )
|
|
{
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
macSetBitmapRec (&volume->catBitmap, 0);
|
|
macSetBitmapRec (&volume->catBitmap, newRootNode);
|
|
}
|
|
else
|
|
{
|
|
macSetBitmapRec (&volume->extBitmap, 0);
|
|
macSetBitmapRec (&volume->extBitmap, newRootNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
/*--------------- macDelOldRootFromTree --------------------------------------
|
|
* removes old root node for tree
|
|
* n.b. this function called only when old root node has only one record
|
|
*/
|
|
|
|
int macDelOldRootFromTree( volume, tree, treeType )
|
|
struct m_volume *volume;
|
|
struct BtreeNode **tree;
|
|
int treeType;
|
|
{
|
|
int retval = E_NONE;
|
|
unsigned int oldRootNode = tree[0]->BtNodes.BtHeader.hnHdrRec.hrRootNode;
|
|
unsigned int childNode =
|
|
tree[oldRootNode]->BtNodes.BtIndex.inRecList[0]->ptrPointer;
|
|
char *funcname = "macDelOldRootFromTree";
|
|
|
|
|
|
/* child node cannot be part of a horizontal linked list */
|
|
if( tree[childNode]->BtNodes.BtIndex.inDesc.ndFLink != UNASSIGNED_NODE ||
|
|
tree[childNode]->BtNodes.BtIndex.inDesc.ndBLink != UNASSIGNED_NODE )
|
|
{
|
|
retval = set_error(E_DATA, Module, funcname, "Bad data in tree");
|
|
}
|
|
else
|
|
{
|
|
free (tree[oldRootNode]->BtNodes.BtIndex.inRecList[0]);
|
|
tree[oldRootNode]->BtNodes.BtIndex.inRecList[0] = 0;
|
|
memcpy( (char *)tree[oldRootNode], (char *)tree[childNode],
|
|
sizeof(struct leaf_node) );
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrDepthCount -= 1;
|
|
|
|
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrFreeNodes++;
|
|
if ( tree[0]->BtNodes.BtHeader.hnHdrRec.hrFirstLeaf == childNode )
|
|
{
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrFirstLeaf = oldRootNode;
|
|
}
|
|
if ( tree[0]->BtNodes.BtHeader.hnHdrRec.hrLastLeaf == childNode )
|
|
{
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrLastLeaf = oldRootNode;
|
|
}
|
|
|
|
macClearBitmapRec((struct bitmap_record *)
|
|
(tree[0]->BtNodes.BtHeader.hnBitMap.bitmap), childNode);
|
|
free( (char *)tree[childNode] );
|
|
tree[childNode] = (struct BtreeNode *)0;
|
|
}
|
|
if ( retval == E_NONE )
|
|
{
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
macSetBitmapRec (&volume->catBitmap, 0);
|
|
macSetBitmapRec (&volume->catBitmap, oldRootNode);
|
|
macSetBitmapRec (&volume->catBitmap, childNode);
|
|
}
|
|
else
|
|
{
|
|
macSetBitmapRec (&volume->extBitmap, 0);
|
|
macSetBitmapRec (&volume->extBitmap, oldRootNode);
|
|
macSetBitmapRec (&volume->extBitmap, childNode);
|
|
}
|
|
}
|
|
|
|
|
|
return(retval);
|
|
}
|
|
|
|
/*--------------- macGetNextNode -------------------------------------------
|
|
* gets next free tree tree node.
|
|
*/
|
|
|
|
int macGetNextNode(volume, currNode, newNode, treeType )
|
|
struct m_volume *volume;
|
|
unsigned int currNode;
|
|
unsigned int *newNode;
|
|
unsigned int treeType;
|
|
{
|
|
int retval = E_NONE;
|
|
char *funcname = "macGetNextNode";
|
|
struct BtreeNode **tree;
|
|
int tNode = -1;
|
|
int a;
|
|
|
|
if (treeType == CATALOG_TREE )
|
|
{
|
|
tree = volume->catalog;
|
|
}
|
|
else
|
|
{
|
|
tree = volume->extents;
|
|
}
|
|
|
|
/* find next unused node in Catalog tree */
|
|
*newNode = macNextFreeNode((struct bitmap_record *)
|
|
tree[0]->BtNodes.BtHeader.hnBitMap.bitmap,
|
|
(int)tree[0]->BtNodes.BtHeader.hnHdrRec.hrTotalNodes );
|
|
|
|
if( *newNode == UNASSIGNED_NODE )
|
|
{
|
|
if( (retval = macAllocTreeExtent(volume, treeType)) == E_NONE )
|
|
{
|
|
retval = macGetNextNode( volume, currNode, newNode, treeType );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if((tree[*newNode]=(struct BtreeNode *)malloc(
|
|
sizeof(struct BtreeNode))) == (struct BtreeNode *)0)
|
|
{
|
|
retval = set_error(E_MEMORY, Module, funcname,"");
|
|
}
|
|
|
|
if( retval == E_NONE )
|
|
{
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrFreeNodes--;
|
|
macSetBitmapRec((struct bitmap_record *)
|
|
(tree[0]->BtNodes.BtHeader.hnBitMap.bitmap), *newNode);
|
|
for ( a = 0; a < MAXRECORDS; a++ )
|
|
{
|
|
tree[*newNode]->BtNodes.BtLeaf.lnRecList[a] = 0;
|
|
}
|
|
}
|
|
|
|
/* currNode check is used to create the free-standing root node */
|
|
if ( retval == E_NONE && currNode != UNASSIGNED_NODE )
|
|
{
|
|
/* initialize new node -- index nodes of non-root level
|
|
DO use FLink & BLink */
|
|
tree[*newNode]->BtNodes.BtLeaf.lnDesc.ndFLink =
|
|
tree[currNode]->BtNodes.BtLeaf.lnDesc.ndFLink;
|
|
tree[currNode]->BtNodes.BtLeaf.lnDesc.ndFLink = *newNode;
|
|
tree[*newNode]->BtNodes.BtLeaf.lnDesc.ndBLink = currNode;
|
|
tree[*newNode]->BtNodes.BtLeaf.lnDesc.ndRecs = (short)0;
|
|
tree[*newNode]->BtNodes.BtLeaf.lnDesc.ndLevel =
|
|
tree[currNode]->BtNodes.BtLeaf.lnDesc.ndLevel;
|
|
tree[*newNode]->BtNodes.BtLeaf.lnDesc.ndType =
|
|
tree[currNode]->BtNodes.BtLeaf.lnDesc.ndType;
|
|
|
|
if( tree[*newNode]->BtNodes.BtLeaf.lnDesc.ndType
|
|
== LEAF_NODE &&
|
|
tree[*newNode]->BtNodes.BtLeaf.lnDesc.ndFLink
|
|
== UNASSIGNED_NODE )
|
|
{
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrLastLeaf = *newNode;
|
|
}
|
|
|
|
if( tree[*newNode]->BtNodes.BtLeaf.lnDesc.ndFLink
|
|
!= UNASSIGNED_NODE )
|
|
{
|
|
tNode = tree[*newNode]->BtNodes.BtLeaf.lnDesc.ndFLink;
|
|
tree[tNode]->BtNodes.BtLeaf.lnDesc.ndBLink = *newNode;
|
|
}
|
|
}
|
|
}
|
|
if ( retval == E_NONE )
|
|
{
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
macSetBitmapRec (&volume->catBitmap, 0);
|
|
macSetBitmapRec (&volume->catBitmap, currNode);
|
|
macSetBitmapRec (&volume->catBitmap, *newNode);
|
|
if ( tNode >= 0 )
|
|
{
|
|
macSetBitmapRec (&volume->catBitmap, tNode);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
macSetBitmapRec (&volume->extBitmap, 0);
|
|
macSetBitmapRec (&volume->extBitmap, currNode);
|
|
macSetBitmapRec (&volume->extBitmap, *newNode);
|
|
if ( tNode >= 0 )
|
|
{
|
|
macSetBitmapRec (&volume->extBitmap, tNode);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return(retval);
|
|
}
|
|
|
|
|
|
/*--- macCountNdRecs ---------------------------------------
|
|
*/
|
|
|
|
int macCountNdRecs( currNode, treeType )
|
|
struct leaf_node *currNode;
|
|
unsigned int treeType;
|
|
{
|
|
/* usable space starts out at node size - size of the node descriptor -
|
|
the one extra record offset at the end of the node (there is always one
|
|
more than there are records, and it is two bytes) */
|
|
int usableSpace = NODE_SIZE-sizeof(struct node_descriptor)-
|
|
(sizeof(short)),
|
|
i = 0,
|
|
recNum = 0,
|
|
recSize = 0;
|
|
|
|
|
|
while( usableSpace > 0 && (unsigned short)i < currNode->lnDesc.ndRecs )
|
|
{
|
|
if ( (unsigned char)currNode->lnDesc.ndType == LEAF_NODE )
|
|
{
|
|
if ( treeType == EXTENTS_TREE )
|
|
{
|
|
recSize = sizeof (struct xkrKey) +
|
|
3 * sizeof (struct extent_descriptor);
|
|
}
|
|
else
|
|
{
|
|
macCalcRecSize(&recSize, currNode->lnRecList[i]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* sizeof(struct pointer_record) includes an extra char
|
|
for null terminating name strings */
|
|
recSize = sizeof( struct pointer_record ) - 1;
|
|
}
|
|
|
|
usableSpace -= recSize + sizeof(short);
|
|
|
|
if( usableSpace >= 0 )
|
|
{
|
|
(recNum)++;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
return( recNum );
|
|
}
|
|
|
|
|
|
/*--- macCalcRecSize ---------------------------------------
|
|
*/
|
|
|
|
int macCalcRecSize( recSize, currRec )
|
|
int *recSize;
|
|
void *currRec;
|
|
{
|
|
int keylen,
|
|
datalen,
|
|
retval = E_NONE;
|
|
char *funcname = "macCalcRecSize";
|
|
|
|
/* record size includes key */
|
|
if ( (keylen = ((struct record_key *)currRec)->key.ckr.ckrKeyLen+1) <= 0 ||
|
|
keylen > sizeof(struct record_key) )
|
|
{
|
|
retval = set_error( E_RANGE, Module, funcname,"Illegal key length.");
|
|
}
|
|
else
|
|
{
|
|
/* keylens must be padded out */
|
|
keylen += (keylen % 2)? 1 : 0;
|
|
|
|
switch ( *( (char *)currRec + sizeof (struct record_key) ))
|
|
{
|
|
case FILE_REC:
|
|
datalen = sizeof(struct file_record) -
|
|
sizeof(struct record_key);
|
|
break;
|
|
case DIRECTORY_REC:
|
|
datalen = sizeof(struct dir_record) -
|
|
sizeof(struct record_key);
|
|
break;
|
|
case THREAD_REC:
|
|
datalen = sizeof(struct thread_record) -
|
|
sizeof(struct record_key);
|
|
break;
|
|
case ALIAS_REC:
|
|
datalen = sizeof(struct alias_record) -
|
|
sizeof(struct record_key);
|
|
break;
|
|
default:
|
|
datalen = 0;
|
|
retval = set_error(E_RANGE, Module, funcname,
|
|
"Illegal record type.");
|
|
break;
|
|
}
|
|
}
|
|
if ( retval == E_NONE )
|
|
{
|
|
*recSize = keylen + datalen;
|
|
}
|
|
|
|
return( retval );
|
|
}
|
|
|
|
/*--------------- macFindParent -------------------------------------------
|
|
* searches tree for nodeno and recno of currNode's parent pointer record
|
|
* or where it would reside if it existed
|
|
*/
|
|
|
|
int macFindParent( currNode, tree, parNodeNum, parRecNum, treeType )
|
|
unsigned int currNode;
|
|
struct BtreeNode **tree;
|
|
unsigned int *parNodeNum;
|
|
int *parRecNum;
|
|
int treeType;
|
|
{
|
|
int retval = E_NONE;
|
|
unsigned int currSrchNode = 0;
|
|
struct pointer_record targetPtrRec;
|
|
|
|
/* update pointer record data to reflect new reference record */
|
|
|
|
memcpy( (char *)&targetPtrRec.ptrRecKey,
|
|
(char *) tree[currNode]->BtNodes.BtLeaf.lnRecList[0],
|
|
sizeof(struct record_key) );
|
|
|
|
targetPtrRec.ptrRecKey.key.ckr.ckrKeyLen = (treeType == EXTENTS_TREE)?
|
|
EXTENT_KEYLENGTH : POINTER_REC_KEYLENGTH;
|
|
targetPtrRec.ptrPointer = currNode;
|
|
|
|
currSrchNode = tree[0]->BtNodes.BtHeader.hnHdrRec.hrRootNode;
|
|
|
|
retval = macFindPtrRec(&targetPtrRec,
|
|
(tree[currNode]->BtNodes.BtIndex.inDesc.ndLevel), tree,
|
|
(unsigned int)treeType, currSrchNode, parRecNum, parNodeNum);
|
|
|
|
if( retval == E_NOTFOUND &&
|
|
tree[*parNodeNum]->BtNodes.BtIndex.inRecList[*parRecNum]->ptrPointer ==
|
|
currNode )
|
|
{
|
|
retval = clear_error();
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
/*-------------------------- macFindPtrRec ------------------------------
|
|
finds location (or proper would-be) of pointer rec in index node(s)
|
|
convoluted is an understatement for the logic in this function. Some
|
|
white knight who has a couple of hours to kill, please clean it up.
|
|
------------------------------------------------------------------------*/
|
|
int macFindPtrRec(targetRec, childLevel, tree, treeType, currNodeNo,
|
|
recNum, nodeNum)
|
|
struct pointer_record *targetRec;
|
|
int childLevel;
|
|
struct BtreeNode **tree;
|
|
unsigned int treeType;
|
|
unsigned int currNodeNo;
|
|
int *recNum;
|
|
unsigned int *nodeNum;
|
|
{
|
|
int retval = E_NONE;
|
|
unsigned int childNdNum;
|
|
char *funcname = "macFindPtrRec";
|
|
|
|
*nodeNum = currNodeNo;
|
|
|
|
retval = scanPtrRecs(&targetRec->ptrRecKey,
|
|
&tree[currNodeNo]->BtNodes.BtIndex, &childNdNum, recNum, treeType);
|
|
|
|
/* test result of index node scan: */
|
|
if( retval == E_NONE )
|
|
{
|
|
/* scanPtrRecs doesn't check ptrPointer */
|
|
if( tree[currNodeNo]->BtNodes.BtIndex.inRecList[*recNum]->ptrPointer ==
|
|
targetRec->ptrPointer )
|
|
{
|
|
*nodeNum = currNodeNo;
|
|
}
|
|
}
|
|
|
|
/* if no hit, set up for next call to macFindPtrRec */
|
|
if( retval == E_NOTFOUND )
|
|
{
|
|
if ( *recNum > 0 )
|
|
{
|
|
(*recNum)--;
|
|
}
|
|
if( tree[currNodeNo]->BtNodes.BtIndex.inRecList[*recNum]->
|
|
ptrPointer == targetRec->ptrPointer )
|
|
{
|
|
*nodeNum = currNodeNo;
|
|
retval = clear_error();
|
|
}
|
|
else
|
|
{
|
|
childNdNum = tree[currNodeNo]->BtNodes.BtIndex.
|
|
inRecList[*recNum]->ptrPointer;
|
|
}
|
|
/* else leave retval what it be */
|
|
}
|
|
|
|
/* search next level if not found */
|
|
if( retval == E_NONE && tree[childNdNum]->BtNodes.BtIndex.inDesc.ndLevel
|
|
> (unsigned char)childLevel )
|
|
{
|
|
retval = macFindPtrRec(targetRec, childLevel, tree, treeType,
|
|
childNdNum, recNum, nodeNum);
|
|
}
|
|
|
|
if( retval == E_NOTFOUND )
|
|
{
|
|
retval = clear_error();
|
|
if (tree[childNdNum]->BtNodes.BtIndex.inDesc.ndLevel >
|
|
(unsigned char)childLevel )
|
|
{
|
|
retval = macFindPtrRec(targetRec, childLevel, tree, treeType,
|
|
childNdNum, recNum, nodeNum);
|
|
}
|
|
else
|
|
{
|
|
*nodeNum = childNdNum;
|
|
|
|
retval = set_error(E_NOTFOUND,Module,funcname,
|
|
"Can't find pointer record.");
|
|
}
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
/*-- macAllocTreeExtent ------------
|
|
*
|
|
*/
|
|
|
|
int macAllocTreeExtent( volume, treeType )
|
|
struct m_volume *volume;
|
|
unsigned int treeType;
|
|
{
|
|
int retval = E_NONE;
|
|
struct BtreeNode **tree;
|
|
struct extent_descriptor *ed;
|
|
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
tree = volume->catalog;
|
|
}
|
|
else
|
|
{
|
|
tree = volume->extents;
|
|
}
|
|
|
|
retval = macAddExtentToTree(volume, treeType, &ed);
|
|
|
|
if ( retval == E_NONE )
|
|
{
|
|
macAddExtentToVib(volume->vib, ed->ed_length);
|
|
macAddExtentToVbm(volume->vbm, ed->ed_start, ed->ed_length);
|
|
|
|
/* update tree header -- each node occupies one block */
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrTotalNodes += ed->ed_length;
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrFreeNodes += ed->ed_length;
|
|
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
volume->vib->drCTFlSize +=
|
|
(ed->ed_length * volume->vib->drAlBlkSiz);
|
|
}
|
|
else
|
|
{
|
|
volume->vib->drXTFlSize +=
|
|
(ed->ed_length * volume->vib->drAlBlkSiz);
|
|
}
|
|
}
|
|
if ( retval == E_NONE )
|
|
{
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
macSetBitmapRec (&volume->catBitmap, 0);
|
|
}
|
|
else
|
|
{
|
|
macSetBitmapRec (&volume->extBitmap, 0);
|
|
}
|
|
}
|
|
|
|
|
|
return( retval );
|
|
}
|
|
|
|
/*-- macAddExtentToTree ----------------------------------------
|
|
points ed to next extent to be populated
|
|
---------------------------------------------------------------*/
|
|
|
|
int macAddExtentToTree( volume, treeType, ed)
|
|
struct m_volume *volume;
|
|
unsigned int treeType;
|
|
struct extent_descriptor **ed;
|
|
{
|
|
int retval = E_NONE;
|
|
int a, done = 0;
|
|
unsigned int xNodeNum = UNASSIGNED_NODE;
|
|
int xRecNum = UNASSIGNED_REC, blockCount = 0;
|
|
int extSize = ((treeType == CATALOG_TREE) ?
|
|
volume->vib->drCTClpSiz/volume->vib->drAlBlkSiz :
|
|
volume->vib->drXTClpSiz/volume->vib->drAlBlkSiz );
|
|
struct extent_descriptor *vibExtPtr =
|
|
((treeType == CATALOG_TREE) ? volume->vib->drCTExtRec :
|
|
volume->vib->drXTExtRec);
|
|
struct extent_record tempXRec;
|
|
struct extent_record *rec;
|
|
char *funcname = "macAddExtentToTree";
|
|
|
|
*ed = 0;
|
|
/* zero out tempXRec */
|
|
for ( a = 0; a< sizeof(struct extent_record); a++ )
|
|
{
|
|
*((char *)(&tempXRec)+a) = '\0';
|
|
}
|
|
|
|
for ( a = 0; a < 3 && vibExtPtr[a].ed_length && retval == E_NONE; a++ )
|
|
{
|
|
blockCount += vibExtPtr[a].ed_length;
|
|
}
|
|
if( a < 3 )
|
|
{
|
|
*ed = &vibExtPtr[a];
|
|
}
|
|
else
|
|
{
|
|
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
|
|
/* Implicit Assumption: no extents tree records */
|
|
/* will be found or added to extents tree */
|
|
/* xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx */
|
|
|
|
/* find locus for first extent record for this file */
|
|
buildXRecKey((struct record_key *) &tempXRec, CATALOG_TREE_ID,
|
|
DATA_FORK, (unsigned short)blockCount);
|
|
|
|
if( volume->extents[0]->BtNodes.BtHeader.hnHdrRec.hrTotalRecs == 0 )
|
|
{
|
|
retval = macPlantTree(volume, EXTENTS_TREE );
|
|
}
|
|
if ( retval == E_NONE )
|
|
{
|
|
retval = searchTree(volume, (struct record_key *)&tempXRec,
|
|
EXTENTS_TREE, &xRecNum, &xNodeNum);
|
|
}
|
|
|
|
if( retval == E_NOTFOUND )
|
|
{
|
|
retval = clear_error();
|
|
}
|
|
|
|
/* if no extent records exist for this file, add one to tree */
|
|
if( retval == E_NONE &&
|
|
((unsigned short) xRecNum >=
|
|
volume->extents[xNodeNum]->BtNodes.BtLeaf.lnDesc.ndRecs ||
|
|
((struct extent_record *)volume->extents[xNodeNum]->
|
|
BtNodes.BtLeaf.lnRecList[xRecNum])->xkrRecKey.key.xkr.xkrFNum !=
|
|
CATALOG_TREE_ID) )
|
|
{
|
|
/* add this record to tree */
|
|
if( retval == E_NONE )
|
|
{
|
|
retval = macAddRecToTree( volume, (int *)&xNodeNum,
|
|
(void *)&tempXRec,
|
|
&xRecNum, EXTENTS_TREE );
|
|
}
|
|
|
|
if( retval == E_NONE )
|
|
{
|
|
*ed = ((struct extent_record *)
|
|
volume->extents[xNodeNum]->BtNodes.BtLeaf.
|
|
lnRecList[xRecNum])->xkrExtents;
|
|
}
|
|
}
|
|
/* found a record -- march through leaf records */
|
|
else
|
|
{
|
|
while( retval == E_NONE && !done )
|
|
{
|
|
rec = (struct extent_record *)volume->extents[xNodeNum]->
|
|
BtNodes.BtLeaf.lnRecList[xRecNum];
|
|
|
|
macSetBitmapRec (&volume->extBitmap, xNodeNum);
|
|
|
|
for ( a = 0; done == 0 && a < 3; a++ )
|
|
{
|
|
if( rec->xkrExtents[a].ed_length == 0 )
|
|
{
|
|
rec->xkrExtents[a].ed_length =
|
|
tempXRec.xkrExtents[0].ed_length;
|
|
rec->xkrExtents[a].ed_start =
|
|
tempXRec.xkrExtents[0].ed_start;
|
|
*ed = &rec->xkrExtents[a];
|
|
done = 1;
|
|
}
|
|
else
|
|
{
|
|
blockCount += rec->xkrExtents[a].ed_length;
|
|
}
|
|
}
|
|
/* find or add next extent record */
|
|
if( !done )
|
|
{
|
|
xRecNum++;
|
|
|
|
/* if no more records in this node */
|
|
if((unsigned short) xRecNum >=
|
|
volume->extents[xNodeNum]->BtNodes.BtLeaf.
|
|
lnDesc.ndRecs)
|
|
{
|
|
/* if at last node or if next record not for this file */
|
|
if( volume->extents[xNodeNum]->BtNodes.BtLeaf.
|
|
lnDesc.ndFLink == UNASSIGNED_NODE ||
|
|
((struct extent_record *)volume->
|
|
extents[volume->extents[xNodeNum]->
|
|
BtNodes.BtLeaf.lnDesc.ndFLink]->BtNodes.BtLeaf.
|
|
lnRecList[0])->xkrRecKey.key.xkr.xkrFNum
|
|
!= tempXRec.xkrRecKey.key.xkr.xkrFNum )
|
|
{
|
|
tempXRec.xkrRecKey.key.xkr.xkrFABN = (short)blockCount;
|
|
retval = macAddRecToTree(volume, (int *)&xNodeNum,
|
|
(void *) &tempXRec, &xRecNum, EXTENTS_TREE);
|
|
}
|
|
else
|
|
{
|
|
/* correct extent_record before adding to extents */
|
|
xNodeNum = volume->extents[xNodeNum]->BtNodes.
|
|
BtLeaf.lnDesc.ndFLink;
|
|
xRecNum = 0;
|
|
}
|
|
}
|
|
/* if next record in this node is not for target file */
|
|
else if( ((struct extent_record *)
|
|
volume->extents[xNodeNum]->BtNodes.BtLeaf.
|
|
lnRecList[xRecNum])->xkrRecKey.key.xkr.xkrFNum
|
|
!= tempXRec.xkrRecKey.key.xkr.xkrFNum )
|
|
{
|
|
tempXRec.xkrRecKey.key.xkr.xkrFABN = (short)blockCount;
|
|
retval = macAddRecToTree( volume, (int *)&xNodeNum,
|
|
(void *) &tempXRec, &xRecNum, EXTENTS_TREE );
|
|
done = 1;
|
|
if( retval == E_NONE )
|
|
{
|
|
*ed = ((struct extent_record *)
|
|
volume->extents[xNodeNum]->BtNodes.BtLeaf.
|
|
lnRecList[xRecNum])->xkrExtents;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if( retval == E_NONE && *ed )
|
|
{
|
|
if ( (retval = macFindBiggestExtent(volume->vib,volume->vbm,*ed))
|
|
== E_NONE )
|
|
{
|
|
if( (*ed)->ed_length >= (unsigned short) extSize )
|
|
{
|
|
(*ed)->ed_length = (unsigned short) extSize;
|
|
}
|
|
else if ( (*ed)->ed_length < (unsigned short) extSize )
|
|
{
|
|
retval = set_error( E_SPACE, Module, funcname, "" );
|
|
}
|
|
/* added to bitmap in calling function */
|
|
}
|
|
}
|
|
|
|
|
|
return( retval );
|
|
}
|
|
|
|
/*-------------------------- macPlantTree ------------------------------
|
|
puts first record into empty tree
|
|
------------------------------------------------------------------------*/
|
|
int macPlantTree(volume, treeType )
|
|
struct m_volume *volume;
|
|
unsigned int treeType;
|
|
{
|
|
int retval = E_NONE,
|
|
a;
|
|
struct BtreeNode **tree;
|
|
char *funcname = "macPlantTree";
|
|
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
tree = volume->catalog;
|
|
}
|
|
else
|
|
{
|
|
tree = volume->extents;
|
|
}
|
|
|
|
if((tree[1]=(struct BtreeNode *)malloc(sizeof(struct BtreeNode)))
|
|
== (struct BtreeNode *)0)
|
|
{
|
|
retval = set_error(E_MEMORY, Module, funcname,"");
|
|
}
|
|
|
|
if( retval == E_NONE )
|
|
{
|
|
for ( a = 0; a< sizeof(struct BtreeNode); a++ )
|
|
{
|
|
*((char *)(tree[1])+a) = '\0';
|
|
}
|
|
|
|
/* initialize header node */
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrDepthCount = 1;
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrRootNode = 1;
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrLastLeaf = 1;
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrFirstLeaf = 1;
|
|
|
|
tree[0]->BtNodes.BtHeader.hnHdrRec.hrFreeNodes--;
|
|
macSetBitmapRec((struct bitmap_record *)
|
|
(tree[0]->BtNodes.BtHeader.hnBitMap.bitmap), 1);
|
|
|
|
/* initialize new node */
|
|
tree[1]->BtNodes.BtLeaf.lnDesc.ndFLink = UNASSIGNED_NODE;
|
|
tree[1]->BtNodes.BtLeaf.lnDesc.ndBLink = UNASSIGNED_NODE;
|
|
tree[1]->BtNodes.BtLeaf.lnDesc.ndType = LEAF_NODE;
|
|
tree[1]->BtNodes.BtLeaf.lnDesc.ndLevel = LEAF_LEVEL;
|
|
tree[1]->BtNodes.BtLeaf.lnDesc.ndRecs = (short)0;
|
|
if ( retval == E_NONE )
|
|
{
|
|
if ( treeType == CATALOG_TREE )
|
|
{
|
|
macSetBitmapRec (&volume->catBitmap, 0);
|
|
macSetBitmapRec (&volume->catBitmap, 1);
|
|
}
|
|
else
|
|
{
|
|
macSetBitmapRec (&volume->extBitmap, 0);
|
|
macSetBitmapRec (&volume->extBitmap, 1);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
return( retval );
|
|
}
|
|
|
|
/*-------------------------- scanPtrRecs ------------------------------
|
|
searches index node for pointer record associated with targetKey
|
|
------------------------------------------------------------------------*/
|
|
int scanPtrRecs(targetKey, currIndex, childNodeNum, targetRec, treeType)
|
|
struct record_key *targetKey;
|
|
struct index_node *currIndex;
|
|
unsigned int *childNodeNum;
|
|
int *targetRec;
|
|
int treeType;
|
|
{
|
|
int retval = E_NONE;
|
|
|
|
if( treeType == EXTENTS_TREE )
|
|
{
|
|
retval = scanXPtrRecs(targetKey, currIndex, childNodeNum, targetRec);
|
|
}
|
|
else
|
|
{
|
|
retval = scanCPtrRecs(targetKey, currIndex, childNodeNum, targetRec);
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
/*-------------------------- scanLeafRecs ------------------------------
|
|
searches leaf node for record associated with targetKey entity
|
|
------------------------------------------------------------------------*/
|
|
int scanLeafRecs(targetKey, leafNode, targetRec, treeType)
|
|
struct record_key *targetKey;
|
|
struct leaf_node *leafNode;
|
|
int *targetRec;
|
|
unsigned int treeType;
|
|
{
|
|
int retval = E_NONE;
|
|
|
|
if( treeType == EXTENTS_TREE )
|
|
{
|
|
retval = scanXLeafRecs(targetKey, leafNode, targetRec);
|
|
}
|
|
else
|
|
{
|
|
retval = scanCLeafRecs(targetKey, leafNode, targetRec);
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
/*-------------------------- macFreeTree ------------------------------
|
|
frees a tree
|
|
------------------------------------------------------------------------*/
|
|
int macFreeTree( tree, treeType, vib )
|
|
struct BtreeNode ***tree;
|
|
int treeType;
|
|
struct m_VIB *vib;
|
|
{
|
|
int retval = E_NONE;
|
|
|
|
int nodeCount,
|
|
treeSize = ((treeType == CATALOG_TREE) ?
|
|
vib->drCTFlSize : vib->drXTFlSize)/NODE_SIZE;
|
|
int i;
|
|
|
|
/* loop through nodes of tree, freeing records... */
|
|
|
|
for( nodeCount = 0;
|
|
*tree && nodeCount < treeSize;
|
|
nodeCount++ )
|
|
{
|
|
if( !(*tree)[nodeCount] )
|
|
{
|
|
; /* pass over unused nodes */
|
|
}
|
|
else
|
|
{
|
|
switch( (*tree)[nodeCount]->BtNodes.nodeBytes[NODE_TYPE_OFFSET] )
|
|
{
|
|
case INDEX_NODE:
|
|
for( i = 0;
|
|
(*tree)[nodeCount]->BtNodes.BtIndex.inRecList[i];
|
|
i++ )
|
|
{
|
|
free ( (char *)(*tree)[nodeCount]->BtNodes.BtIndex.
|
|
inRecList[i]);
|
|
(*tree)[nodeCount]->BtNodes.BtIndex.inRecList[i] = 0;
|
|
}
|
|
break;
|
|
case LEAF_NODE:
|
|
for( i = 0;
|
|
(*tree)[nodeCount]->BtNodes.BtLeaf.lnRecList[i];
|
|
i++ )
|
|
{
|
|
free ( (char *)(*tree)[nodeCount]->BtNodes.BtLeaf.
|
|
lnRecList[i]);
|
|
(*tree)[nodeCount]->BtNodes.BtLeaf.lnRecList[i] = 0;
|
|
}
|
|
break;
|
|
}
|
|
free( (char *)(*tree)[nodeCount] );
|
|
}
|
|
}
|
|
|
|
if ( *tree )
|
|
{
|
|
free( (char *)(*tree) );
|
|
*tree = 0;
|
|
}
|
|
|
|
return(retval);
|
|
}
|
|
|
|
|
|
/*--------------------- macWriteTreeExtent ------------------------------
|
|
Writes an extent of the catalog or extent tree to disk.
|
|
---------------------------------------------------------------------*/
|
|
|
|
int macWriteTreeExtent ( volume, ed, buffer, bufOffset, treeType )
|
|
struct m_volume *volume;
|
|
struct extent_descriptor *ed;
|
|
char *buffer;
|
|
int bufOffset;
|
|
int treeType;
|
|
{
|
|
int retval = E_NONE;
|
|
unsigned int block;
|
|
unsigned int blockStart;
|
|
unsigned int offset = 0;
|
|
unsigned int length;
|
|
unsigned int bytes_to_xfer = 0;
|
|
unsigned int bytes_xferred;
|
|
struct bitmap_record *bitmap = (treeType == CATALOG_TREE) ?
|
|
&volume->catBitmap : &volume->extBitmap;
|
|
int firstNode = bufOffset / NODE_SIZE;
|
|
int lastNode =
|
|
firstNode + (ed->ed_length * volume->vib->drAlBlkSiz)/NODE_SIZE;
|
|
int i = firstNode;
|
|
int start, end;
|
|
char *bufptr = buffer + bufOffset;
|
|
|
|
|
|
/* Find actual block number. */
|
|
blockStart = au_to_partition_block (volume->vib, ed->ed_start,
|
|
volume->vstartblk);
|
|
|
|
while( retval == E_NONE && i < lastNode )
|
|
{
|
|
/* Build block of contiguous nodes to write */
|
|
|
|
while ( i < lastNode && !macInBitmapRec (bitmap, i) )
|
|
{
|
|
i++; /* skip over unused nodes */
|
|
}
|
|
if ( i < lastNode )
|
|
{
|
|
start = i;
|
|
offset = (start - firstNode) * NODE_SIZE;
|
|
while ( i < lastNode && macInBitmapRec(bitmap, i) )
|
|
{
|
|
i++; /* build contiguous block of used nodes */
|
|
}
|
|
end = i;
|
|
length = (end - start) * NODE_SIZE;
|
|
block = blockStart + (start - firstNode);
|
|
bytes_xferred = 0;
|
|
while( retval == E_NONE && bytes_xferred < length )
|
|
{
|
|
if( (length - bytes_xferred) > MAX_TRANSFER )
|
|
{
|
|
bytes_to_xfer = MAX_TRANSFER;
|
|
}
|
|
else
|
|
{
|
|
bytes_to_xfer = (length - bytes_xferred);
|
|
}
|
|
|
|
retval = macWriteBlockDevice( volume->device, bufptr+offset,
|
|
block, bytes_to_xfer/SCSI_BLOCK_SIZE);
|
|
|
|
block += bytes_to_xfer/SCSI_BLOCK_SIZE;
|
|
offset += bytes_to_xfer;
|
|
bytes_xferred += bytes_to_xfer;
|
|
}
|
|
}
|
|
}
|
|
|
|
return (retval);
|
|
}
|
|
|
|
|
|
static unsigned int bitmapNodes(volume, bmp, totalnodes)
|
|
struct m_volume *volume;
|
|
struct bitmap_record * bmp;
|
|
unsigned int totalnodes;
|
|
{
|
|
int count;
|
|
unsigned int bitmapnodes = 0;
|
|
|
|
/* temparary fix for Btree bitmap overflow */
|
|
if (totalnodes > 2048)
|
|
totalnodes = 2048;
|
|
|
|
for(count = 0; count < totalnodes; count++) {
|
|
if ( macInBitmapRec(bmp, count) )
|
|
bitmapnodes++;
|
|
}
|
|
return (bitmapnodes);
|
|
}
|