in hfs/btree.c [1123:1257]
static int addRecord(BTree* tree, uint32_t root, BTKey* searchKey, size_t length, unsigned char* content, int* callAgain) {
BTNodeDescriptor* descriptor;
BTKey* key;
off_t recordOffset;
off_t recordDataOffset;
off_t lastRecordDataOffset;
size_t freeSpace;
int res;
int i;
uint32_t newNode;
uint32_t newNodeBigEndian;
uint32_t nodeBigEndian;
descriptor = readBTNodeDescriptor(root, tree);
if(descriptor == NULL)
return 0;
freeSpace = getFreeSpace(root, descriptor, tree);
lastRecordDataOffset = 0;
for(i = 0; i < descriptor->numRecords; i++) {
recordOffset = getRecordOffset(i, root, tree);
key = READ_KEY(tree, recordOffset, tree->io);
recordDataOffset = recordOffset + key->keyLength + sizeof(key->keyLength);
res = COMPARE(tree, key, searchKey);
if(res == 0) {
free(key);
free(descriptor);
return 0;
} else if(res > 0) {
free(key);
break;
}
free(key);
lastRecordDataOffset = recordDataOffset;
}
if(descriptor->kind == kBTLeafNode) {
if(freeSpace < (sizeof(searchKey->keyLength) + searchKey->keyLength + length + sizeof(uint16_t))) {
newNode = splitNode(root, descriptor, tree);
if(i < descriptor->numRecords) {
doAddRecord(tree, root, searchKey, length, content);
} else {
doAddRecord(tree, newNode, searchKey, length, content);
}
free(descriptor);
return newNode;
} else {
doAddRecord(tree, root, searchKey, length, content);
free(descriptor);
return 0;
}
} else {
if(lastRecordDataOffset == 0) {
if(descriptor->numRecords == 0) {
hfs_panic("empty index node in btree");
return 0;
}
key = READ_KEY(tree, (root * tree->headerRec->nodeSize) + 14, tree->io);
recordDataOffset = recordOffset + key->keyLength + sizeof(key->keyLength);
nodeBigEndian = getNodeNumberFromPointerRecord(recordDataOffset, tree->io);
FLIPENDIAN(nodeBigEndian);
free(key);
key = READ_KEY(tree, (root * tree->headerRec->nodeSize) + 14, tree->io);
recordDataOffset = recordOffset + key->keyLength + sizeof(key->keyLength);
if(searchKey->keyLength != key->keyLength) {
if(searchKey->keyLength > key->keyLength && freeSpace < (searchKey->keyLength - key->keyLength)) {
// very unlikely. We need to split this node before we can resize the key of this index. Do that first, and tell them to call again.
*callAgain = TRUE;
return splitNode(root, descriptor, tree);
}
moveRecordsDown(tree, descriptor, 1, root, searchKey->keyLength - key->keyLength, 0);
}
free(key);
ASSERT(WRITE_KEY(tree, recordOffset, searchKey, tree->io), "WRITE_KEY");
ASSERT(WRITE(tree->io, recordOffset + sizeof(uint16_t) + searchKey->keyLength, sizeof(uint32_t), &nodeBigEndian), "WRITE");
FLIPENDIAN(nodeBigEndian);
newNode = addRecord(tree, nodeBigEndian, searchKey, length, content, callAgain);
} else {
newNode = addRecord(tree, getNodeNumberFromPointerRecord(lastRecordDataOffset, tree->io), searchKey, length, content, callAgain);
}
if(newNode == 0) {
free(descriptor);
return 0;
} else {
newNodeBigEndian = newNode;
key = READ_KEY(tree, newNode * tree->headerRec->nodeSize + 14, tree->io);
FLIPENDIAN(newNodeBigEndian);
if(freeSpace < (sizeof(key->keyLength) + key->keyLength + sizeof(newNodeBigEndian) + sizeof(uint16_t))) {
newNode = splitNode(root, descriptor, tree);
if(i < descriptor->numRecords) {
doAddRecord(tree, root, key, sizeof(newNodeBigEndian), (unsigned char*)(&newNodeBigEndian));
} else {
doAddRecord(tree, newNode, key, sizeof(newNodeBigEndian), (unsigned char*)(&newNodeBigEndian));
}
free(key);
free(descriptor);
return newNode;
} else {
doAddRecord(tree, root, key, sizeof(newNodeBigEndian), (unsigned char*)(&newNodeBigEndian));
free(key);
free(descriptor);
return 0;
}
}
}
}