/*************************************************************
 *                                                           *
 *    ths  Filesystem                  04.10.94      V1.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"


static struct file_operations ths_file_ops =
{
	NULL,		/* lseek - default */
	ths_read,		/* read */
	NULL,		/* write */
	NULL,		/* readdir - bad */
	NULL,		/* select - default */
	NULL,		/* ioctl - default */
	NULL,		/* mmap */
	NULL,		/* no special open is needed */
	NULL,		/* release */
	NULL		/* fsync */
};

static struct file_operations ths_dir_ops =
{
	NULL,		/* lseek - default */
	ths_dir_read,		/* read */
	NULL,		/* write */
	ths_readdir,		/* readdir - bad */
	NULL,		/* select - default */
	NULL,		/* ioctl - default */
	NULL,		/* mmap */
	NULL,		/* no special open is needed */
	NULL,		/* release */
	NULL		/* fsync */
};

struct inode_operations ths_dir_inode_ops =
{
	&ths_dir_ops,  /* default directory file-ops */
	NULL,			/* create */
	ths_lookup,			/* lookup */
	NULL,			/* link */
	NULL,			/* unlink */
	NULL,			/* symlink */
	NULL,			/* mkdir */
	NULL,			/* rmdir */
	NULL,			/* mknod */
	NULL,			/* rename */
	NULL,			/* readlink */
	NULL,			/* follow_link */
	NULL,			/* bmap */
	NULL,			/* truncate */
	NULL			/* permission */
};

struct inode_operations ths_file_inode_ops =
{
	&ths_file_ops,  /* default directory file-ops */
	NULL,			/* create */
	NULL,			/* lookup */
	NULL,			/* link */
	NULL,			/* unlink */
	NULL,			/* symlink */
	NULL,			/* mkdir */
	NULL,			/* rmdir */
	NULL,			/* mknod */
	NULL,			/* rename */
	NULL,			/* readlink */
	NULL,			/* follow_link */
	NULL,			/* bmap */
	NULL,			/* truncate */
	NULL			/* permission */
};

void ths_read_inode(struct inode *in)
{
	struct ths_buffer tbf,tbf2;
	struct ths_inode_info *ths_inode;
	struct ths_sb_info *ths_sb;
	struct ths_dir *dir=NULL;
	int i,tmp,test;
	unsigned char *data=NULL;

#ifdef DEBUG
	printk("read_inode : %ld\n",in->i_ino);
#endif

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


	in->i_uid = 0;
	in->i_gid = 0;
	in->i_nlink = 1;
	in->i_blocks = 0;
	in->i_blksize = 0;
	in->i_mode |= S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;

	if(in->i_ino==THS_ROOT_INODE)
	{
/*
 * Root-Inode
 */
		in->i_mode = in->i_mode | S_IFDIR;
		in->i_op = &ths_dir_inode_ops;
		in->i_atime = 0;
		in->i_mtime = 0;
		in->i_ctime = 0;
		ths_inode->Cluster = (short)ths_sb->RootStart;
		strcpy(ths_inode->name,"Rootdir");
		for(i=0;i<ths_sb->RootMaxEintraege*32;)
		{
			if(!(i&0x1ff))
			{
				if(ths_read_sektor(in->i_sb,(ths_sb->RootStart+(i>>9)), &tbf2))
				{
					printk("Fehler\n");
					return;
				}
				data = tbf2.data[0];
			}
			if(data[i&0x1ff]==0x00)
			{
				ths_free_sektor(&tbf2);
				break;
			}
			i+=32;
			if(!(i&0x1ff))
				ths_free_sektor(&tbf2);
		}
		in->i_size=i;
#ifdef DEBUG
		printk("Groesse Root: %d\n",i);
#endif
	}
	else
	{
/*
 * Andere Inode
 */
		test=0;
		if((in->i_ino>>4) < ths_sb->DatenStart)
		{
			test=1;
		}
		if(test)
		{
			if(ths_read_sektor(in->i_sb,in->i_ino>>4,&tbf))
			{
				printk("Fehler\n");
				return;
			}
		}
		else
		{
			if(ths_read_cluster(in->i_sb,((in->i_ino>>4)-ths_sb->DatenStart)/ths_sb->SektorenProCluster,0,&tbf))
			{
				printk("Fehler\n");
				return;
			}
		}
/*
 * Position des Eintrags im Sektor berechnen
 */
		data = tbf.data[((in->i_ino>>4)-ths_sb->DatenStart)&(tbf.sektore-1)];
		tmp = in->i_ino & 0x0f;
		tmp *= 32;
		dir = (struct ths_dir *)&data[tmp];
#ifdef DEBUG
		printk("offset : %d , %ld\n",tmp,((in->i_ino>>4)-ths_sb->DatenStart)&(tbf.sektore-1));
#endif
/*
 * Informationen eintragen
 */
		if(dir->attribut & 0x10)
		{
			in->i_mode |= S_IFDIR;
			in->i_op = &ths_dir_inode_ops;
			for(i=0;i<1000*32;)
			{
				if(!(i&0x1ff))
				{
					if(!((i/512)%ths_sb->SektorenProCluster))
					{
						if(ths_read_cluster(in->i_sb,CHS(dir->cluster),(long)i,&tbf2))
						{
							printk("Fehler\n");
							return;
						}
					}
					data = tbf2.data[(i/512)%tbf2.sektore];
				}
				if(data[i&0x1ff]==0x00)
				{
					ths_free_cluster(&tbf2);
					break;
				}
				i+=32;
				if(!((i&0x1ff)||((i/512)%ths_sb->SektorenProCluster)))
					ths_free_cluster(&tbf2);
			}
			in->i_size=i;
#ifdef DEBUG
			printk("Groesse Sub: %d\n",i);
#endif
		}
		else
		{
			in->i_mode |= S_IFREG;
			in->i_op = &ths_file_inode_ops;
			in->i_size = CHL(dir->laenge);
		}

		for(i=0;i<8;i++)
			ths_inode->name[i]=dir->name[i];
		ths_inode->name[i++]=0x20;
		for(;i<12;i++)
			ths_inode->name[i]=dir->endung[i-9];
		ths_inode->name[i]='\0';


		in->i_atime = time_ms2u(CHS(dir->datum),CHS(dir->zeit));
		in->i_mtime = in->i_atime;
		in->i_ctime = in->i_atime;

		ths_inode->Cluster = CHS(dir->cluster);

		if(test)
			ths_free_sektor(&tbf);
		else
			ths_free_cluster(&tbf);
	}
#ifdef DEBUG
	printk("Name : %s ",ths_inode->name);
	if(in->i_ino != THS_ROOT_INODE)
		printk("Attribut : 0x%x ",dir->attribut);
	printk("Cl : 0x%x ",ths_inode->Cluster);
	printk("L : 0x%lx\n",in->i_size);
#endif
}







