#include "ktypes.h"
#include "filesys.h"


static char     _ident213[] = "$Header: filesys.c,v 1.5 86/12/04 10:22:19 tom Exp $";


/*
 * routines which interpret KSOS filesystems.
 */


int             junit = -1;
long            jbno = -1;
struct jnode    jblock[SPB];


itemtree(i, parent, offset)
	unsigned        i;              /* number of self */
	unsigned        *parent;        /* VAR parent tree number */
	unsigned        *offset;        /* VAR offset in parent block */
{
	*parent = (i - 1) / MAXIND;
	*offset = (i - 1) % MAXIND;
}



blocktree(b, tn, offset)
	long            b;              /* block number in file */
	unsigned        *tn;            /* VAR tree number in index */
	unsigned        *offset;        /* VAR location in indir or jnode */
{
	long            w;

	if (b < MAXDIRJ)
	{
		*tn = 0;
		*offset = b;
	}
	else
	{
		w = b - MAXDIRJ;
		*tn = (w / MAXDIRI) + 1;
		*offset = (w % MAXDIRI);
	}
}



long indirect(fp, i)
	struct filep    *fp;
	unsigned        i;              /* tree position */
{
	long            pslot;          /* working slot number */
	unsigned        parent;         /* tree number of parent */
	unsigned        offset;         /* subscript in itable */
	struct indir    item;

	itemtree(i, &parent, &offset);

	if (parent == 0)
		pslot = fp->f_jnumb;
	else
		pslot = indirect(fp, parent);

	if (pslot == NULLP)
		return NULLP;

	if (readj(&fp->f_ext, pslot, &item) < 0
	|| (item.i_kind != JNODE && item.i_kind != INDIR))
		return NULLP;

	return (*(cardinal32*)item.i_itable[offset]);
}



long file_block(fp, n)
	struct filep    *fp;
	long            n;              /* block number in file */
{
	unsigned        tn, offset;
	long            islot;
	struct indir    item;

#ifdef DEBUG
dumpfilep("file_block (fp)",fp);
printf("file_block: n %d\n",n);
#endif

	blocktree(n, &tn, &offset);

	if (tn != 0)
		islot = indirect(fp, tn);
	else
		islot = fp->f_jnumb;

	if (islot == NULLP)
		return NULLP;

#ifdef DEBUG
printf("file_block: islot %d\n",islot);
#endif
	if (readj(&fp->f_ext, islot, &item) < 0
	|| (item.i_kind != JNODE && item.i_kind != INDIR))
		return  NULLP;
#ifdef DEBUG
dumpjnode("file_block (the item)",&item);
#endif
	return (*(cardinal32*)item.i_dtable[offset]);
}


move(from, to, count)
	register char           *from, *to;
	register int            count;
{
	if (count)
		do
			*to++ = *from++;
		while (--count);
}



/*
 * The following routines are exported.
 */

extopen(unit, extent, ex)
	unsigned        unit;
	unsigned        extent;
	struct extp     *ex;
{
	struct eitem    eitem;
	struct mitem    mitem;
	struct extp     xmap;

#ifdef DEBUG
printf("DEBUG(extopen): unit %d, extent %d\n",unit,extent);
#endif
	/* get extent item */

	xmap.x_unit = unit;
	xmap.x_offset = EXTMAP;
	xmap.x_slots = EXTSIZE;

	if (readj(&xmap, (long) extent, &eitem) < 0)
	{
		printf("warning: can't read extent map %d\n", extent);
		return -1;
	}

#ifdef DEBUG
dumpeitem("extopen (eitem)",&eitem);
#endif
	if (eitem.e_kind != EXTENT)
	{
		printf("warning: extent %d not in extent map\n", extent);
		return -1;
	}

	ex->x_unit = unit;
	ex->x_offset = *(cardinal32*) eitem.e_first;
	ex->x_slots = SPB;

	if (readj(ex, MOUNTLOC, &mitem) < 0)
	{
		printf("warning: can't read extent %d mount item\n", extent);
		return -1;
	}

	if (mitem.m_kind != MOUNT)
	{
		printf("warning: extent %d has bad mount item\n", extent);
		return -1;
	}
#ifdef DEBUG
dumpmitem("extopen (mitem)",&mitem);
#endif
	ex->x_slots =	*(cardinal32*)mitem.m_slots;
	ex->x_blocks =	*(cardinal32*)mitem.m_blocks;
	ex->x_user =	*(cardinal32*)mitem.m_user;
#ifdef DEBUG
dumpextp("extopen (filled-in ex)",ex);
#endif
	return 0;
}


get_file_block(fp, fbn,buffer)
	struct filep    *fp;            /* file pointer */
	long            fbn;            /* file block number */
	char		*buffer;	/* caller's buffer for I/O */
{
	long            xbn;            /* block number in ext */
	long            abn;            /* absolute block number */

	if (fbn < 0 || fbn >= fp->f_blocks)
	{
		printf("warning: block %d out of range\n", fbn);
		return -1;
	}

	xbn = file_block(fp, fbn);

	if (xbn == NULLP)
	{
		printf("warning: no block %D for file\n", fbn);
		return -1;
	}

	abn = xbn + fp->f_ext.x_offset + fp->f_ext.x_user;

	return get_abs_block(fp->f_ext.x_unit, abn, buffer);
}
