void
gdbWriteHeader(GDatabase *db)
{
	char version[2];
	char type;
	
	if (db == NULL || db->fp == NULL)
		return;

	version[0] = DB_MAJOR_VER;
	version[1] = DB_MINOR_VER;

	type = (char)db->type;

	fseek(db->fp, 0, SEEK_SET);

	/* Write the magic string. */
	fputs(DB_MAGIC, db->fp);

	fwrite(version, sizeof(char), 2, db->fp);
	fwrite(&type,   sizeof(char), 1, db->fp);

	if (DB_HEADER_BLOCK_SIZE > DB_HEADER_DATA_SIZE)
		gdbPad(db->fp, DB_HEADER_BLOCK_SIZE - DB_HEADER_DATA_SIZE);

	fflush(db->fp);
}
Exemple #2
0
void
btreeEraseNode(BTreeNode *node)
{
    GdbBlock *block;

    if (node == NULL || node->block->offset == 0)
    {
        return;
    }
    block = node->block;

    gdbFreeBlock(block->db, block->offset, block->type);

#if 0
    rawFileSeek(block->db->fp, block->offset, SEEK_SET);
    gdbPad(block->db->fp, block->size);
#endif
}
Exemple #3
0
GDatabase *
gdbCreate(const char *filename, GdbType type)
{
	GDatabase *db;
	FILE      *fp;

	cxReturnValueUnless(filename != NULL, NULL);

	fp = fopen(filename, "w+");

	if (fp == NULL)
	{
		pmError(PM_ERROR_WARNING,
				_("GNUpdate DB: "
				  "Unable to open database %s for reading/writing.\n"),
				filename);

		return NULL;
	}

	MEM_CHECK(db = (GDatabase *)malloc(sizeof(GDatabase)));
	memset(db, 0, sizeof(GDatabase));

	__setupDatabase(db);

	db->filename = strdup(filename);
	db->type     = type;
	db->fp       = fp;

	gdbWriteHeader(db);

	/* Leave enough room for the free block list. */
	fseek(db->fp, DB_FREE_BLOCK_LIST_OFFSET, SEEK_SET);
	gdbPad(db->fp, DB_FREE_BLOCK_LIST_SIZE);

	db->mainTree = btreeCreate(db, 5);

	return db;
}
Exemple #4
0
void
gdbWriteHeader(GDatabase *db)
{
    uint8_t version[2];
    uint8_t type;
    offset_t offset;

    if (db == NULL || db->idxRawFile == NULL)
    {
        return;
    }

    version[0] = DB_MAJOR_VER;
    version[1] = DB_MINOR_VER;

    type = db->type;

    rawFileSeek(db->idxRawFile, 0, SEEK_SET);
    offset = 0;

    /* Write the magic string. */

    rawFilePuts(db->idxRawFile, offset, DB_MAGIC);
    offset += strlen(DB_MAGIC);

    rawFileWrite(db->idxRawFile, offset, version, sizeof(uint8_t), 2, LOC_DB_0011);
    offset += (sizeof(uint8_t) * 2);

    rawFileWrite(db->idxRawFile, offset, &type,   sizeof(uint8_t), 1, LOC_DB_0012);
    offset += sizeof(uint8_t);

    if (DB_HEADER_BLOCK_SIZE > DB_HEADER_DATA_SIZE)
    {
        gdbPad(db->idxRawFile, offset, DB_HEADER_BLOCK_SIZE - DB_HEADER_DATA_SIZE);
    }
}
offset_t *
gdbReserveBlockChain(GDatabase *db, unsigned short count,
					 blocktype_t blockType)
{
	GdbFreeBlock  *freeBlocks, *newFreeBlocks;
	offset_t      *chain;
	offset_t       offset;
	unsigned short blockSize;
	long           blockCount, fillCount, newListCount;
	long           i, j, result;

	if (db == NULL || count == 0 || !GDB_VALID_BLOCK_TYPE(blockType))
		return NULL;

	/* Get the block size for this type. */
	blockSize = blockTypeInfo[blockType - 1].multiple;

	/* Create the chain. */
	MEM_CHECK(chain = (offset_t *)malloc(count * sizeof(offset_t)));

	/* Lock the free block list. */
	gdbLockFreeBlockList(db, DB_WRITE_LOCK);

	/* Get the free block list. */
	result = gdbGetFreeBlockList(db, &freeBlocks, &blockCount);

	if (result == 0)
	{
		gdbUnlockFreeBlockList(db);
		gdbFreeBlockList(freeBlocks);

		fseek(db->fp, 0L, SEEK_END);
		offset = ftell(db->fp);

		/* Fill in the chain with the reserved offsets. */
		for (i = 0; i < count; i++)
			chain[i] = offset + (i * blockSize);

		gdbPad(db->fp, count * blockSize);

		return chain;
	}

	fillCount = 0;
	j = 0;

	/* Create the new array of free blocks. */
	MEM_CHECK(newFreeBlocks = (GdbFreeBlock *)malloc(blockCount *
													 sizeof(GdbFreeBlock)));
	memset(newFreeBlocks, 0, blockCount * sizeof(GdbFreeBlock));
	
	for (i = 0; i < blockCount; i++)
	{
		if (fillCount < count && freeBlocks[i].size == blockSize)
		{
			chain[fillCount++] = freeBlocks[i].offset;
		}
		else
		{
			newFreeBlocks[j].offset = freeBlocks[i].offset;
			newFreeBlocks[j].size   = freeBlocks[i].size;

			j++;
		}
	}

	newListCount = j;
	
	if (fillCount != count)
	{
		if (fillCount > 0)
			gdbWriteFreeBlockList(db, newFreeBlocks, newListCount);

		gdbUnlockFreeBlockList(db);

		gdbFreeBlockList(newFreeBlocks);
		gdbFreeBlockList(freeBlocks);

		fseek(db->fp, 0L, SEEK_END);
		offset = ftell(db->fp);

		/* Fill in the chain with the reserved offsets. */
		for (i = fillCount, j = 0; i < count; i++, j++)
			chain[i] = offset + (j * blockSize);

		gdbPad(db->fp, (count - fillCount) * blockSize);

		qsort(chain, count, sizeof(offset_t), __offsetCompare);
		
		return chain;
	}

	/* Write the new list to disk. */
	gdbWriteFreeBlockList(db, newFreeBlocks, newListCount);

	/* Unlock the list. */
	gdbUnlockFreeBlockList(db);

	/* Free up the memory for the lists. */
	gdbFreeBlockList(newFreeBlocks);
	gdbFreeBlockList(freeBlocks);

	/* Sort it. */
	qsort(chain, count, sizeof(offset_t), __offsetCompare);

	return chain;
}
void
gdbWriteBlock(GdbBlock *block)
{
	GDatabase    *db;
	char         *buffer;
	offset_t     *oldChain;
	blocktype_t   typeIndex;
	unsigned int  oldChainCount, oldDataSize;
	unsigned int  i, pos;
	
	if (block == NULL || !GDB_IS_DIRTY(block))
		return;

	/* Set a couple of vars we'll be using. */
	db        = block->db;
	typeIndex = block->type - 1;

	/* Save the old data. */
	oldDataSize   = block->dataSize;
	oldChainCount = block->chainCount;
	oldChain      = block->chain;

	/* See if there is a write function assigned. */
	if (blockTypeInfo[typeIndex].writeBlock != NULL)
	{
		/* Write the block info to a buffer. */
		blockTypeInfo[typeIndex].writeBlock(block, &buffer, &block->dataSize);
	}
	else
	{
		buffer = (char *)block->detail;
	}

	if (buffer == NULL)
	{
		pmError(PM_ERROR_FATAL,
				_("GNUpdate DB: buffer == NULL in %s, line %d\n"),
				__FILE__, __LINE__);
		exit(1);
	}

	/* Get the number of needed blocks. */
	block->chainCount = gdbGetNeededBlockCount(block->dataSize,
											   block->multiple);

	if (oldChainCount == 0)
	{
		/* Reserve new blocks. */
		block->chain = gdbReserveBlockChain(db, block->chainCount,
											block->type);
	}
	else if (block->chainCount < oldChainCount)
	{
		/* The number of needed blocks is shorter than before. */
		MEM_CHECK(block->chain = (offset_t *)malloc(block->chainCount *
													sizeof(offset_t)));
		memcpy(block->chain, oldChain, block->chainCount * sizeof(offset_t));
	}
	else if (block->chainCount > oldChainCount)
	{
		offset_t *newChain;
		int j;
		
		/* The number of needed blocks is longer than before. */
		MEM_CHECK(block->chain = (offset_t *)malloc(block->chainCount *
													sizeof(offset_t)));
			
		newChain = gdbReserveBlockChain(db, block->chainCount - oldChainCount,
										block->type);
		
		memcpy(block->chain, oldChain, oldChainCount * sizeof(offset_t));
		
		for (i = oldChainCount, j = 0; i < block->chainCount; i++, j++)
			block->chain[i] = newChain[j];

		free(newChain);
	}

	/*
	 * Set the offset and next block, if this spills over into
	 * additional blocks.
	 */
	block->offset = block->chain[0];

	if (block->chainCount > 1)
		block->next = block->chain[1];
	else
		block->next = 0;
	
	/* Write the first block header */
	gdbWriteBlockHeader(block);

	/* Write the first block. */
	fwrite(buffer, 1,
		   (block->dataSize < block->multiple - GDB_BLOCK_HEADER_SIZE ?
			block->dataSize : block->multiple - GDB_BLOCK_HEADER_SIZE),
		   db->fp);

	if (block->dataSize < block->multiple - GDB_BLOCK_HEADER_SIZE)
	{
		gdbPad(db->fp, block->multiple - GDB_BLOCK_HEADER_SIZE -
			   block->dataSize);
	}
	else
	{
		char *blockBuffer;
		
		MEM_CHECK(blockBuffer = (char *)malloc(block->multiple));

		pos = block->multiple - GDB_BLOCK_HEADER_SIZE;
		
		/* Write any overflow blocks. */
		for (i = 1; i < block->chainCount; i++)
		{
			offset_t nextOffset;
			unsigned long relPos;
			
			nextOffset = ((i + 1 < block->chainCount) ?
						  block->chain[i + 1] : 0);

			relPos = block->dataSize - pos;
			
			/* Reset the block buffer. */
			memset(blockBuffer, 0, block->multiple);

			/* Write to it. */
			nextOffset = htonl(nextOffset);

			memcpy(blockBuffer, &nextOffset, sizeof(offset_t));
			memcpy(blockBuffer + sizeof(offset_t), buffer + pos,
				   (relPos < block->multiple - sizeof(offset_t) ?
					relPos : block->multiple - sizeof(offset_t)));
			
			/* Write the block buffer. */
			if (block->chain[i - 1] + block->multiple != block->chain[i])
				fseek(db->fp, block->chain[i], SEEK_SET);

			fwrite(blockBuffer, 1, block->multiple, db->fp);

			pos += block->multiple - sizeof(offset_t);
		}

		free(blockBuffer);
	}

	if (oldChainCount != 0)
	{
		/* If the chain shrunk, free up the discarded blocks. */
		if (block->chainCount < oldChainCount)
		{
			gdbFreeBlockChain(db, &oldChain[block->chainCount],
							  oldChainCount - block->chainCount, block->type);
		}
		
		if (oldChainCount != block->chainCount)
			free(oldChain);
	}

	fflush(db->fp);

	if (buffer != block->detail)
		free(buffer);
}
Exemple #7
0
GdbStatus
gdbAddTree(GDatabase *db, BTree *tree, const char *key, BTree **newTree)
{
	GdbStatus   status;
	offset_t    offset;
	short       blockSize;
	blocktype_t type;
	
	if (db == NULL || tree == NULL || db->fp == NULL || key == NULL ||
		newTree == NULL)
	{
		return GDB_ERROR;
	}

	*newTree = btreeCreate(db, 5);

	offset = (*newTree)->block->offset;
	blockSize = (*newTree)->block->multiple;
	type = (*newTree)->block->type;

	if (*newTree == NULL)
	{
		*newTree = NULL;

		return GDB_ERROR;
	}

	status = btreeInsert(tree, key, offset, 0);

	if (status == GDB_DUPLICATE)
	{
		/* Return the existing newTree. */
		btreeClose(*newTree);
		gdbFreeBlock(db, offset, type);

		offset = btreeSearch(tree, key);

		if (offset == 0)
		{
			/* I doubt this will ever happen. */
			pmError(PM_ERROR_FATAL,
					_("GNUpdate DB: Possible database corruption! Back up "
					  "your database and contact a developer.\n"));
			exit(1);
		}

		*newTree = btreeOpen(db, offset);

		status = GDB_SUCCESS;
	}
	else if (status == GDB_ERROR)
	{
		btreeClose(*newTree);

		fseek(db->fp, offset, SEEK_SET);

#if 0
		gdbPad(db->fp, blockSize);
#endif

		gdbFreeBlock(db, offset, type);

		*newTree = NULL;
	}

	return status;
}