/*
	@(#)fileio.c	1.10	(2/20/85 10:06:59)
*/
#include "standalone.h"

#ifdef RF360
#define RF
#endif
#ifdef CWC43
#define CWC
#endif
#ifdef CWC38		/* Atasi */
#define CWC
#endif
#ifdef CWC21
#define CWC
#endif
#ifdef MSC21
#define MSC
#endif
#ifdef MSC10
#define MSC
#endif

#ifndef RF
#ifndef MSC
#ifndef CWC
#define MSC
#endif
#endif
#endif

extern wait4ret();
static short bsize;			/* Block size of file system */
static short bshift;			/* log2(bsize) */

/* Call the appropriate driver to do the transfer.
 * Return 0 on success, 1 on failure 
 */
diskio(dp)
register DIOB *dp;
{
	register int i;
#ifdef DEBUG
printf("diskio: "); dmpdiob(dp);
#endif DEBUG

	if (bsize == 1024)
	{	dp->diob_fdb <<= 1;
		dp->diob_nblks = 2;
	}
	else if (bsize == 2048)
	{	dp->diob_fdb <<= 2;
		dp->diob_nblks = 4;
	}
	else
		dp->diob_nblks = 1;

	switch(dp->diob_dix)
	{
#ifdef MSC
		case DIOB_MSC:
			i = mscio(dp);
			break;
#endif
#ifdef CWC
		case DIOB_CWC:
			i = cwcio(dp);
			break;
#endif
#ifdef RF
		case DIOB_RF:
			i = rfio(dp);
			break;
#endif
		case DIOB_CFC:
			i = cfcio(dp);
			break;
		default:
			printf("diskio: unknown driver index number %d.\n",
				dp->diob_dix);
			i = 99;
	}
	return (i);
}

#define	 INODESIZE	64
getinode(inodeno,inodeptr,diobptr)
register int inodeno;
register struct dinode *inodeptr;
register DIOB *diobptr;
{
	/* 64 is number of inodes in a 4K block (as in Berkeley fs) */
	struct dinode inodebuf[64];
	register int block, index;

#ifdef DEBUG
printf("getinode: ino=%d\n", inodeno);
#endif DEBUG
	block = (inodeno - 1) / (bsize/INODESIZE) + 2;
	index = (inodeno - 1) % (bsize/INODESIZE);
	diobptr->diob_fdb = block;
	diskio(diobptr);
	bcopy(diobptr->diob_buf,inodebuf,sizeof(inodebuf));
	bcopy(&inodebuf[index],inodeptr,sizeof(struct dinode));
}

getfname(name, index, buffer)
register char *name;
register int index;
register char *buffer;
{
	register int i = 0;
	register char c;

	while (name[index] == '/')
	    index++;

	if (!name[index])
		return (-1);		/* no more components in path */

	while (i < 14)
	{
	    c = name[index];
	    if (c != '/'  &&  c != '\0')
	    {
		buffer[i++] = c;
		index++;
	    }
	    else
		break;
	}
	buffer[i] = '\0';
	return (index);
}

findfile(file,filename)
register FILE    *file;
register char    *filename;
{
	struct   direct   dir;
	register int      length;
	register int      i;
	register char     c;

#ifdef DEBUG
printf("Searching for %s...\n", filename);
#endif DEBUG
	while((length=read(file,&dir,sizeof(dir))) == sizeof(dir))
	{
	    if (dir.d_ino)
	    {
#ifdef DEBUG
printf("Checking '%s',", dir.d_name);
#endif DEBUG
		for (i = 0;  i < sizeof(dir.d_name);  i++)
		{
		    c = filename[i];
		    if (c != dir.d_name[i])
			break;
		    if (c == '\0')
			return (dir.d_ino);
		}
		if (i == 14)
		    return (dir.d_ino);
	    }
	}
	return (0);
}


static char fopenerr[] = "FILE OPEN ERROR: ";

/* Find and open the file.  Return 0 on success, 1 on failure. */
open(filename,file,driver,drive,nbpt,ntpc,ncpd,dp1,dp2,dp3,dp4,fssb,fseb)
char   *filename;
FILE   *file;
int	driver, drive, nbpt, ntpc, ncpd, dp1, dp2, dp3, dp4, fssb, fseb;
{
	struct	filsys superblk;
	struct  dinode inode;
	DIOB diskdiob;
	FILE dfile;
	char fname[16];
	register int i, fnameidx, inodeno, inomode;

#ifdef DEBUG
printf("open: name = `%s', file_buf = `%s'\n", filename, file->file_buf);
printf("      %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\n",
	driver, drive, nbpt, ntpc, ncpd, dp1, dp2, dp3, dp4, fssb, fseb);
#endif DEBUG

	diskdiob.diob_fdb = 1;
	diskdiob.diob_fnc = DIOB_RD;
	diskdiob.diob_dix = driver;
	diskdiob.diob_drv = drive;
	diskdiob.diob_dbt = nbpt;
	diskdiob.diob_dtc = ntpc;
	diskdiob.diob_dcd = ncpd;
	diskdiob.diob_dp1 = dp1;
	diskdiob.diob_dp2 = dp2;
	diskdiob.diob_dp3 = dp3;
	diskdiob.diob_dp4 = dp4;
	diskdiob.diob_fsb = fssb;
	diskdiob.diob_feb = fseb;

	if (diskio(&diskdiob))				/* Disk error */
		return (1);

	bcopy(diskdiob.diob_buf,&superblk,sizeof(superblk));
#ifdef DEBUG
dmpsuper(&superblk);
#endif DEBUG

	/* Determine block size of file system */
	bsize = 512; bshift = 9;
	if (superblk.s_magic == FsMAGIC)
	{   if (superblk.s_type == Fs2b)
	    {	bsize = 1024;
		bshift = 10;
	    }
	    if (superblk.s_type == Fs4b)
	    {	bsize = 2048;
		bshift = 11;
	    }
	}

	inodeno = 2;
	fnameidx = 0;
	while (1)
	{
		bytefill(&dfile,0,sizeof(FILE));
		bcopy(&diskdiob,&dfile.file_diob,sizeof(dfile.file_diob));
		getinode(inodeno,&inode,&dfile.file_diob);
#ifdef DEBUG
dmpinode(inodeno, &inode);
#endif DEBUG
		inomode = inode.di_mode & S_IFMT;
		if ((inomode == S_IFREG) || (inomode == 0))
		{
		    if (!strcmp(file->file_buf, "list")) /* not list command */
			break;
		    printf("<%s> is not a directory!\n", filename);
		    return (1);			/* Error return status */
		}
		else if (inomode != S_IFDIR)
		{
			printf(fopenerr);
			printf("<%s> is not a regular file or directory\n",
				filename);
			return (1);		/* Error return status */
		}
		bcopy(&inode,&dfile.file_ino,sizeof(dfile.file_ino));
		dfile.file_cblk = -1;
		fnameidx = getfname(filename,fnameidx,fname);
		if (fnameidx == -1)
		{
		    if (strcmp(file->file_buf, "list"))	/* list command */
			break;
		    printf("<%s> is a directory!\n", filename);
		    return (1);			/* Error return status */
		}
		inodeno = findfile(&dfile,fname);
		if (inodeno == 0)
		{
			printf(fopenerr);
			printf("<%s> file or directory name not found\n",
				filename);
			return (1);		/* Error return status */
		}
	}
	bytefill(file,0,sizeof(FILE));
	bcopy(&diskdiob,&file->file_diob,sizeof(DIOB));
	bcopy(&inode,&file->file_ino,sizeof(file->file_ino));
	file->file_cblk = -1;
	file->file_i1b = -1;
	file->file_i2b = -1;
	file->file_i3b = -1;
	return (0);			/* Good return status */
}

getc(file)
	FILE   *file;
	{
	char	byte;
	int	status;

	if (file->file_off >= file->file_ino.di_size)
	    {
	    return(EOF);
	    }
	else if ((status = read(file,&byte,sizeof(byte))) != sizeof(byte))
	    {
	    printf("getc: error in status = %d\n",status);
	    return(0);
	    }
	else
	    {
	    return(byte & 0xff);
	    }
	}

getw(file)
	FILE   *file;
	{
	int	word;
	int	status;

	if ((status = read(file,&word,sizeof(word))) != sizeof(word))
	    {
	    printf("getw: error status = %d\n",status);
	    return(0);
	    }
	else
	    {
	    return(word);
	    }
	}

read(file,address,length)
	FILE   *file;
	char   *address;
	int	length;
	{
	register int	xfrlen;
	register int    tmplen;
	register int    remlen;
	register int    offlen;
	register int    offset;

	xfrlen = 0;
	while (xfrlen < length  &&  file->file_off < file->file_ino.di_size)
	    {
	    readblk(file);
	    offset = file->file_off % bsize;
	    offlen = file->file_ino.di_size - file->file_off;
	    remlen = bsize - offset;
	    remlen = remlen > offlen ? offlen : remlen;
	    tmplen = length > remlen ? remlen : length;
	    bcopy(&file->file_buf[offset],address,tmplen);
	    xfrlen  += tmplen;
	    address += tmplen;
	    file->file_off += tmplen;
	    }
	return(xfrlen);
	}


readblk(file)
register FILE  *file;
{
	register int	block;
	register int	ablock;
	register U8    *u8ptr;

	block = file->file_off >> bshift;
	if (block != file->file_cblk)
	    {
#ifdef DEBUG
printf("readblk: block=%d; ", block);
#endif DEBUG
	    if (0 <= block  &&  block <= 9)
		{
		u8ptr    = (U8 *)&file->file_ino.di_addr[block * 3];
		ablock  = *u8ptr++ << 16;
		ablock |= *u8ptr++ << 8;
		ablock |= *u8ptr;
		file->file_diob.diob_fdb = ablock;
		diskio(&file->file_diob);
		bcopy(file->file_diob.diob_buf,file->file_buf,bsize);
		}
	    else if (10 <= block  &&  block <= ((bsize/4) + 10 - 1))
		{
		u8ptr    = (U8 *)&file->file_ino.di_addr[30];
		ablock  = *u8ptr++ << 16;
		ablock |= *u8ptr++ << 8;
		ablock |= *u8ptr;
		if (ablock != file->file_i1b)
		    {
		    file->file_diob.diob_fdb = ablock;
		    diskio(&file->file_diob);
		    bcopy(file->file_diob.diob_buf,file->file_ib1,bsize);
		    file->file_i1b = ablock;
		    }
		file->file_diob.diob_fdb = file->file_ib1[block-10];
		diskio(&file->file_diob);
		bcopy(file->file_diob.diob_buf,file->file_buf,bsize);
		}
	    else if ((bsize/4 + 10) <= block 
		 &&  block <= ((bsize/4)*(bsize/4) + (bsize/4) + 10 -1))
		{
		u8ptr    = (U8 *)&file->file_ino.di_addr[33];
		ablock  = *u8ptr++ << 16;
		ablock |= *u8ptr++ << 8;
		ablock |= *u8ptr;
		if (ablock != file->file_i2b)
		    {
		    file->file_diob.diob_fdb = ablock;
		    diskio(&file->file_diob);
		    bcopy(file->file_diob.diob_buf,file->file_ib2,bsize);
		    file->file_i2b = ablock;
		    }
		ablock = file->file_ib2[(block - (bsize/4 + 10)) / (bsize/4)];
		if (ablock != file->file_i1b)
		    {
		    file->file_diob.diob_fdb = ablock;
		    diskio(&file->file_diob);
		    bcopy(file->file_diob.diob_buf,file->file_ib1,bsize);
		    file->file_i1b = ablock;
		    }
		file->file_diob.diob_fdb = file->file_ib1[(block - (bsize/4 + 10)) % (bsize/4)];
		diskio(&file->file_diob);
		bcopy(file->file_diob.diob_buf,file->file_buf,bsize);
		}
	    else
		{
		printf("readblk: indirect out of range\n");
		}
	    file->file_cblk = block;
	    }
}

#ifdef DEBUG
dmpinode(n, ino)
int n;
register struct dinode *ino;
{
	register int i;
	register char *p1, *p2;
	int addr;

	printf("inode #%d: md=%o,ln=%d,uid=%d,gid=%d,sz=%d\n",
		n, ino->di_mode, ino->di_nlink,
		ino->di_uid, ino->di_gid, ino->di_size);
	printf("addr: ");
	for (i=0; i<39; i+=3)
	{
		p1 = (char *) &addr;
		p2 = (char *) &ino->di_addr[i];
		*p1++ = 0;
		*p1++ = *p2++;
		*p1++ = *p2++;
		*p1++ = *p2++;
	        printf("%x,", addr);
	}
	 printf("\n");
}

dmpsuper(sp)
register struct	filsys	*sp;
{
	register int i;

	printf("superblk: isize=%d,fsize=%d,fname=%s,fpack=%s,type=%d\n",
		sp->s_isize, sp->s_fsize, sp->s_fname, sp->s_fpack, sp->s_type);
	printf("superblk: dinfo( ");
	for (i=0; i<4; i++)
	    printf("%2x,", sp->s_dinfo[i]);
	printf(")\n");
}
dmpdiob(dp)
register DIOB *dp;
{
printf("diob: dix=%d,fnc=%d,fdb=%d,nblks=%d,fsb=%d,feb=%d,drv=%d,dbt=%d,dtc=%d,dcd=%d\n",
	    dp->diob_dix, dp->diob_fnc, dp->diob_fdb, dp->diob_nblks,
	    dp->diob_fsb, dp->diob_feb, dp->diob_drv, dp->diob_dbt, dp->diob_dtc, dp->diob_dcd);

}

#endif DEBUG
