/* ib1_alloc.c: IB1 driver block allocation routines

   Copyright (C) 2000 Maurer IT Systemlösungen KEG

   The Gnome Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.

   The Gnome Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public
   License along with the Gnome Library; see the file COPYING.LIB.  If not,
   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.

   Author: Dietmar Maurer <dietmar@maurer-it.com>

*/

#include "ib1_driver.h"

/**
 * ib1_bitmap_init:
 * @efs:
 * @first_block: block offset
 *
 * Description: initialize the block allocation bitmap. The
 * block before @first_block can´t be free´d.
 */

void
ib1_bitmap_init (IB1EFS *efs, guint32 first_block)
{
	efs->bmap.fb = first_block;
	efs->bmap.bc = 0;
	efs->bmap.dbc = 0;
	efs->bmap.alen = 512;
	efs->bmap.data = g_malloc0 (efs->bmap.alen);
	efs->bmap.fbc = g_malloc0 (efs->bmap.alen);
}

/**
 * ib1_bitmap_free:
 * @efs:
 *
 * Description: free´s allocatee resources in the bitmap.
 */

void
ib1_bitmap_free (IB1EFS *efs)
{
	gint i;

	for (i=0; i < efs->bmap.dbc; i++) 
		if (efs->bmap.data[i]) g_free (efs->bmap.data[i]);

	g_free (efs->bmap.data);
	g_free (efs->bmap.fbc);
}

static guint32
ib1_block_init (IB1EFS *efs, guint32 block)
{
	IB1CacheEntry *ce;
	guint32 *buf;
	gint i;

	if (block != (efs->bmap.bc+efs->bmap.fb)) return 0;
	if (!block) return 0;
	
	if (!(ce = ib1_cache_map (efs, block, TRUE))) return 0;
	buf = (guint32 *) ce->data;
	for (i = 0; i < 128; i++) buf[i] = 0;
	
	return block;
}

/**
 * ib1_block_alloc:
 * @efs:
 *
 * Description: allocates a free block.
 *
 * Returns: the block number of the allocated block, or zero on failure. 
 */

guint32
ib1_block_alloc(IB1EFS *efs)
{
	guint b,i,j,k,rb;
	guint32 rval;

	g_return_val_if_fail (((EFS*)efs)->mode&EFS_WRITE, 0);

	for (b = 0; b < efs->bmap.dbc; b++) if (efs->bmap.fbc[b] > 0) {
		for (i=0;i<128;i++) if (efs->bmap.data[b][i] != 0xffffffff) {
			k = 1<<31;
			for (j=0;j<32;j++) {
				rb = b*512*8+i*32+j;
				if ((efs->bmap.data[b][i]&k) == 0) {
					efs->bmap.data[b][i] |= k;
					rval = efs->bmap.fb + rb;
					if (rb >= efs->bmap.bc) {
						rval = ib1_block_init 
							(efs, rval);
						if (rval) efs->bmap.bc = rb + 1;
					}
					if (rval) efs->bmap.fbc[b]--;
					return rval;
				}
				k=k>>1;
			}
		}
	}
	
	i = efs->bmap.bc;
	
	if ((rval = ib1_block_init (efs, efs->bmap.fb + i))) {
		efs->bmap.bc++;
		if (efs->bmap.bc >= (efs->bmap.dbc*512*8)) {
			if (efs->bmap.dbc >= efs->bmap.alen) {
				efs->bmap.alen += 512;
				efs->bmap.data = g_realloc (efs->bmap.data, 
							    efs->bmap.alen);
				efs->bmap.fbc = g_realloc (efs->bmap.fbc, 
							   efs->bmap.alen);
			}

			efs->bmap.data[efs->bmap.dbc] = g_malloc0(512);
			efs->bmap.fbc[efs->bmap.dbc] = 512*8;
			efs->bmap.dbc++;
		}

		b = i/(512*8);
		j = (i%(512*8))/32;
		k = 1 << (31-(i%(512*8))%32);
	
		efs->bmap.data[b][j] |= k;
		efs->bmap.fbc[b]--;
	}

	return rval;	
}

gint
ib1_block_get_fbc (IB1EFS *efs)
{
	gint i, db, ind, bi;
	gint free = 0;
	gint lb = 0;

	for (i = 0; i < efs->bmap.bc; i++) {
		db = i/(512*8);
		ind = (i%(512*8))/32;
		bi = 1 << (31-((i%(512*8))%32));
		if (efs->bmap.data[db][ind]&bi) lb = i;
		else free++;
	}
	
	free -= (efs->bmap.bc -1 - lb);
	efs->bmap.bc = lb+efs->bmap.fb;

	return free;
}

/**
 * ib1_block_free:
 * @efs:
 * @block: block number to free
 *
 * Description: marks @block as free.
 */

void   
ib1_block_free (IB1EFS *efs, guint32 block)
{
	guint b,j,k;

	g_return_if_fail (block >= efs->bmap.fb);

	for (j=0; j < IB1_CACHE_SIZE; j++) if (efs->cache[j].block == block)
		efs->cache[j].dirty = FALSE;

	block -= efs->bmap.fb;
	b = block/(512*8);
	j = (block%(512*8))/32;
	k = 1 << (31-(block%(512*8))%32);

	if (efs->bmap.data[b]) {
		if (!(efs->bmap.data[b][j]&k)) {
			g_warning ("block is not allocated!");
			return;
		}

		efs->bmap.data[b][j] &= ~k;
		efs->bmap.fbc[b]++;
	}
}


syntax highlighted by Code2HTML, v. 0.9.1