static uint32_t splitNode()

in hfs/btree.c [916:996]


static uint32_t splitNode(uint32_t node, BTNodeDescriptor* descriptor, BTree* tree) {
  int nodesToMove;
  
  int i;
  off_t internalOffset;
  
  BTNodeDescriptor* fDescriptor;
  
  BTNodeDescriptor newDescriptor;
  uint32_t newNodeNum;
  off_t newNodeOffset;
  
  off_t toMove;
  size_t toMoveLength;
  unsigned char *buffer;
  
  off_t offsetsToMove;
  size_t offsetsToMoveLength;
  uint16_t *offsetsBuffer;
    
  nodesToMove = descriptor->numRecords - (descriptor->numRecords/2);
   
  toMove = getRecordOffset(descriptor->numRecords/2, node, tree);
  toMoveLength = getRecordOffset(descriptor->numRecords, node, tree) - toMove;
  buffer = (unsigned char *)malloc(toMoveLength);
  ASSERT(READ(tree->io, toMove, toMoveLength, buffer), "READ");
  
  offsetsToMove = (node * tree->headerRec->nodeSize) + tree->headerRec->nodeSize - (sizeof(uint16_t) * (descriptor->numRecords + 1));
  offsetsToMoveLength = sizeof(uint16_t) * (nodesToMove + 1);
  offsetsBuffer = (uint16_t *)malloc(offsetsToMoveLength);
  ASSERT(READ(tree->io, offsetsToMove, offsetsToMoveLength, offsetsBuffer), "READ");
  
  for(i = 0; i < (nodesToMove + 1); i++) {
    FLIPENDIAN(offsetsBuffer[i]);
  }
  
  internalOffset = offsetsBuffer[nodesToMove] - 14;
  
  for(i = 0; i < (nodesToMove + 1); i++) {
    offsetsBuffer[i] -= internalOffset;
    FLIPENDIAN(offsetsBuffer[i]);
  }
  
  newNodeNum = getNewNode(tree);
  newNodeOffset = newNodeNum * tree->headerRec->nodeSize;
  
  newDescriptor.fLink = descriptor->fLink;
  newDescriptor.bLink = node;
  newDescriptor.kind = descriptor->kind;
  newDescriptor.height = descriptor->height;
  newDescriptor.numRecords = nodesToMove;
  newDescriptor.reserved = 0;
  ASSERT(writeBTNodeDescriptor(&newDescriptor, newNodeNum, tree), "writeBTNodeDescriptor");
  
  if(newDescriptor.fLink != 0) {    
    fDescriptor = readBTNodeDescriptor(newDescriptor.fLink, tree);
    fDescriptor->bLink = newNodeNum;
    ASSERT(writeBTNodeDescriptor(fDescriptor, newDescriptor.fLink, tree), "writeBTNodeDescriptor");
    free(fDescriptor);
  }
  
  descriptor->fLink = newNodeNum;
  descriptor->numRecords = descriptor->numRecords/2;
  ASSERT(writeBTNodeDescriptor(descriptor, node, tree), "writeBTNodeDescriptor");
  
  ASSERT(WRITE(tree->io, newNodeOffset + 14, toMoveLength, buffer), "WRITE");
  ASSERT(WRITE(tree->io, newNodeOffset + tree->headerRec->nodeSize - (sizeof(uint16_t) * (nodesToMove + 1)), offsetsToMoveLength, offsetsBuffer), "WRITE");
  
  // The offset for the existing descriptor's new numRecords will happen to be where the old data was, which is now where the free space starts
  // So we don't have to manually set the free space offset
  
  free(buffer);
  free(offsetsBuffer);
  
  if(descriptor->kind == kBTLeafNode && node == tree->headerRec->lastLeafNode) {
    tree->headerRec->lastLeafNode = newNodeNum;
    ASSERT(writeBTHeaderRec(tree), "writeBTHeaderRec");
  }
  
  return newNodeNum;
}