static int addRecord()

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;
      }
    }
  }
}