/*************************************************************
 *                                                           *
 *    ths  Filesystem                  04.08.94      V0.1    *
 *                                                           *
 *    Thomas Scheuermann     ths@ai-lab.fh-furtwangen.de     *
 *                                                           *
 *************************************************************/

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/locks.h>
#include <linux/fs.h>
#include <linux/malloc.h>

#include <asm/system.h>
#include <asm/segment.h>
#include <asm/bitops.h>

#include "ths.h"
#include "ths_i.h"

int ths_dir_read(struct inode *in, struct file *fp, char *buf, int count)
{
	printk("dir_read\n");
	return -EISDIR;
}

int ths_readdir(struct inode *in, struct file *fp,struct dirent *eintrag, int count)
{
	struct ths_buffer tbf;
	struct ths_inode_info *ths_inode;
	struct ths_sb_info *ths_sb;
	struct ths_dir *dir;
	long sektor=0,len,pos1;
	int i,j;
	unsigned char *data=NULL;

	ths_inode = (struct ths_inode_info *)&(in->u.generic_ip);
	ths_sb = (struct ths_sb_info *)in->i_sb->u.generic_sbp;

#ifdef DEBUG
	printk("readdir : %s : %ld\n",ths_inode->name,in->i_ino);
#endif

	len = in->i_size;
	pos1 = fp->f_pos;
/*
 * . und .. im Rootverzeichnis emulieren
 */
	if(in->i_ino==THS_ROOT_INODE)
		pos1-=64;
	if(pos1<0)
	{
		j=0;
		put_fs_byte('.',j+eintrag->d_name);
		j++;
		if(pos1==-32)
		{
			put_fs_byte('.',j+eintrag->d_name);
			j++;
		}
		if(pos1==-64)
			put_fs_long(THS_ROOT_INODE,&eintrag->d_ino);
		put_fs_byte(0,j+eintrag->d_name);
		put_fs_word(j,&eintrag->d_reclen);
		fp->f_pos+=32;
		return j;
	}

	while(pos1 < len)
	{
		if(in->i_ino==THS_ROOT_INODE)
		{
			sektor = (long)ths_sb->RootStart + (pos1>>9);
			if(ths_read_sektor(in->i_sb,sektor, &tbf))
			{
				printk("Fehler\n");
				return -1;
			}
		}
		else
		{
			if(ths_read_cluster(in->i_sb,ths_inode->Cluster,pos1,&tbf))
			{
				printk("Fehler\n");
				return -1;
			}
		}

		data = tbf.data[(pos1/512)%tbf.sektore];
		dir = (struct ths_dir *)&(data[(pos1 & 0x01ff)]);

/*
 * Test, ob der Eintrag geloescht wurde oder ob es sich
 * um den Namen des Volumes handelt.
 */
		if(dir->name[0]==0xe5||(dir->attribut & 0x08))
		{
			fp->f_pos += 32;
			pos1 += 32;
			if(in->i_ino==THS_ROOT_INODE)
				ths_free_sektor(&tbf);
			else
				ths_free_cluster(&tbf);
			continue;
		}

/*
 * Daten an den User uebergeben
 */
		for(i=0,j=0;i<11;i++)
		{
			if(i==8 && dir->name[i]!=0x20)
			{
				put_fs_byte('.',j+eintrag->d_name);
				j++;
			}
			if(dir->name[i]!=0x20)
			{
				put_fs_byte(dir->name[i],j+eintrag->d_name);
				j++;
			}
		}

		put_fs_long(sektor * 16 + ((pos1 & 0x01ff) >>5),&eintrag->d_ino);
		put_fs_byte(0,j+eintrag->d_name);
		put_fs_word(j,&eintrag->d_reclen);


		if(in->i_ino==THS_ROOT_INODE)
			ths_free_sektor(&tbf);
		else
			ths_free_cluster(&tbf);
		fp->f_pos += 32;
		pos1 += 32;
		return j;
	}
	return 0;
}


int ths_lookup(struct inode *in,const char *name, int l, struct inode **result)
{
	struct ths_inode_info *ths_inode;
	struct ths_sb_info *ths_sb;
	struct ths_dir *dir=NULL;
	struct ths_buffer tbf;
	long sektor,len,innr;
	int addr,i,test;
	unsigned char *data=NULL;

	sektor = 0;
	addr = 0;

	ths_inode = (struct ths_inode_info *)&(in->u.generic_ip);
	ths_sb = (struct ths_sb_info *)in->i_sb->u.generic_sbp;

#ifdef DEBUG
	printk("lookup : %s laenge : %d\n",name,l);
#endif

	len = in->i_size;

	i=0;

	while(i < len)
	{
		if((i & 0x1ff) ==0)
		{
			if(in->i_ino==THS_ROOT_INODE)
			{
				sektor = (long)ths_inode->Cluster + (i>>9);
				if(ths_read_sektor(in->i_sb,sektor, &tbf))
				{
					printk("Fehler\n");
					return -1;
				}
			}
			else 
			{
				if(!((i/512)%ths_sb->SektorenProCluster))
				{
					if(ths_read_cluster(in->i_sb,ths_inode->Cluster,i,&tbf))
					{
						printk("Fehler\n");
						return -1;
					}
				}
			}	
			data = tbf.data[(i/512)%tbf.sektore];
		}
		dir = (struct ths_dir *)&(data[(i & 0x01ff)]);

/*
 * Namensvergleich
 */
		test=vergleich(dir,name,l);

		if(name[0]=='.' && l == 1 && in->i_ino == THS_ROOT_INODE)
			test = 1;

		if(test)
		{
			innr = tbf.cluster ? (tbf.cluster*tbf.sektore+ths_sb->DatenStart)*16 + ((i&((0x100<<tbf.sektore)-1))>>5) :
								tbf.sektnr[0]*16 + ((i&0x1ff)>>5);
			if(l==1 && name[0] =='.')
				innr = in->i_ino;
			if(l==2 && name[0] =='.' && name[1] =='.' && dir->cluster ==0)
				innr = THS_ROOT_INODE;
			*result = iget(in->i_sb,innr);
			if(!*result)
			{
				iput(in);
				if(in->i_ino==THS_ROOT_INODE)
					ths_free_sektor(&tbf);
				else
					ths_free_cluster(&tbf);
				return -EACCES;
			}
			iput(in);
			if(in->i_ino==THS_ROOT_INODE)
				ths_free_sektor(&tbf);
			else
				ths_free_cluster(&tbf);
			return 0;
		}
		i+=32;
		if((i & 0x1ff) ==0)
		{
			if(in->i_ino==THS_ROOT_INODE)
				ths_free_sektor(&tbf);
			else if(!((i/512)%tbf.sektore))
				ths_free_cluster(&tbf);
		}
	}
	iput(in);
	return -ENOENT;
}
