in hfs/btree.c [377:527]
static uint32_t traverseNode(uint32_t nodeNum, BTree* tree, unsigned char* map, int parentHeight, BTKey** firstKey, BTKey** lastKey,
uint32_t* heightTable, uint32_t* errCount, int displayTree) {
BTNodeDescriptor* descriptor;
BTKey* key;
BTKey* previousKey;
BTKey* retFirstKey;
BTKey* retLastKey;
int i, j;
int res;
uint32_t count;
off_t recordOffset;
off_t recordDataOffset;
off_t lastrecordDataOffset;
descriptor = readBTNodeDescriptor(nodeNum, tree);
previousKey = NULL;
count = 1;
if(displayTree) {
for(i = 0; i < descriptor->height; i++) {
printf(" ");
}
}
if(descriptor->kind == kBTLeafNode) {
if(displayTree)
printf("Leaf %d: %d", nodeNum, descriptor->numRecords);
if(descriptor->height != 1) {
printf("BTREE CONSISTENCY ERROR: Leaf node %d does not have height 1\n", nodeNum); fflush(stdout);
(*errCount)++;
}
} else if(descriptor->kind == kBTIndexNode) {
if(displayTree)
printf("Index %d: %d", nodeNum, descriptor->numRecords);
} else {
printf("BTREE CONSISTENCY ERROR: Unexpected node %d has kind %d\n", nodeNum, descriptor->kind); fflush(stdout);
(*errCount)++;
}
if(displayTree) {
printf("\n"); fflush(stdout);
}
if((map[nodeNum / 8] & (1 << (7 - (nodeNum % 8)))) == 0) {
printf("BTREE CONSISTENCY ERROR: Node %d not marked allocated\n", nodeNum); fflush(stdout);
(*errCount)++;
}
if(nodeNum == tree->headerRec->rootNode) {
if(descriptor->height != tree->headerRec->treeDepth) {
printf("BTREE CONSISTENCY ERROR: Root node %d (%d) does not have the proper height (%d)\n", nodeNum,
descriptor->height, tree->headerRec->treeDepth); fflush(stdout);
(*errCount)++;
}
} else {
if(descriptor->height != (parentHeight - 1)) {
printf("BTREE CONSISTENCY ERROR: Node %d does not have the proper height\n", nodeNum); fflush(stdout);
(*errCount)++;
}
}
/*if(descriptor->kind == kBTIndexNode && descriptor->numRecords < 2) {
printf("BTREE CONSISTENCY ERROR: Node %d does not have at least two children\n", nodeNum);
(*errCount)++;
}*/
heightTable[descriptor->height] = nodeNum;
lastrecordDataOffset = 0;
for(i = 0; i < descriptor->numRecords; i++) {
recordOffset = getRecordOffset(i, nodeNum, tree);
key = READ_KEY(tree, recordOffset, tree->io);
recordDataOffset = recordOffset + key->keyLength + sizeof(key->keyLength);
if((recordDataOffset - (nodeNum * tree->headerRec->nodeSize)) > (tree->headerRec->nodeSize - (sizeof(uint16_t) * (descriptor->numRecords + 1)))) {
printf("BTREE CONSISTENCY ERROR: Record data extends past offsets in node %d record %d\n", nodeNum, i); fflush(stdout);
(*errCount)++;
}
if(i == 0) {
*firstKey = READ_KEY(tree, recordOffset, tree->io);
}
if(i == (descriptor->numRecords - 1)) {
*lastKey = READ_KEY(tree, recordOffset, tree->io);
}
if(previousKey != NULL) {
res = COMPARE(tree, key, previousKey);
if(res < 0) {
printf("BTREE CONSISTENCY ERROR(traverse): Ordering between records within node not preserved in record %d node %d for ", i, nodeNum);
(*errCount)++;
tree->keyPrint(previousKey);
printf(" < ");
tree->keyPrint(key);
printf("\n"); fflush(stdout);
}
free(previousKey);
previousKey = NULL;
}
if(displayTree) {
for(j = 0; j < (descriptor->height - 1); j++) {
printf(" ");
}
tree->keyPrint(key);
printf("\n");
}
if(descriptor->kind == kBTIndexNode) {
count += traverseNode(getNodeNumberFromPointerRecord(recordDataOffset, tree->io),
tree, map, descriptor->height, &retFirstKey, &retLastKey, heightTable, errCount, displayTree);
if(COMPARE(tree, retFirstKey, key) != 0) {
printf("BTREE CONSISTENCY ERROR: Index node key does not match first key in record %d node %d\n", i, nodeNum); fflush(stdout);
(*errCount)++;
}
if(COMPARE(tree, retLastKey, key) < 0) {
printf("BTREE CONSISTENCY ERROR: Last key is less than the index node key in record %d node %d\n", i, nodeNum); fflush(stdout);
(*errCount)++;
}
free(retFirstKey);
free(key);
previousKey = retLastKey;
} else {
previousKey = key;
}
if(recordOffset < lastrecordDataOffset) {
printf("BTREE CONSISTENCY ERROR: Record offsets are not in order in node %d starting at record %d\n", nodeNum, i); fflush(stdout);
(*errCount)++;
}
lastrecordDataOffset = recordDataOffset;
}
if(previousKey != NULL) free(previousKey);
free(descriptor);
return count;
}