/*

   FASTDISK by Thorsten Stolpmann
   
   Reworked for Lattice C 5.0.4. by Olli
   
   1.11.89:  first attempt to make it compile under lattice
   2.11.89:  build in ARP-Support
   3.11.89:  complete rework, gone cause to machine failure :-<
   4.11.89:  complete rework, second attempt. add In' features
   5.11.89:  do misc code optimizing
	     do more code optimizing
	     removed ALV-generation for "cback.o"
	     please remove the above sentence :-(
	           
*/

#define scmp !strnicmp
#define error(); { closeall(); loop(); }

#include <proto/arp.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/icon.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <devices/trackdisk.h>
#include <string.h>

/* Diskspezifische Daten */

#define NUMHEADS	2
#define BLOCKSIZE	512
#define SIZE		128
#define NUM_ENTRIES	72
#define NUMBLOCKS	1760 /* (NUMCYLC * NUMHEADS * NUMSECS) */
#define ROOTBLOCK	880
#define NUMLONGS	55
#define SECS_PER_TRACK	22

/* Diskblockparameter */

#define TYPE		0
#define HEADER_KEY	1
#define HIGHEST_SEQ	2
#define	SEQ_NUM		2
#define BLOCK_COUNT	2
#define	DATA_SIZE	3
#define	FIRST_DATA	4
#define	NEXT_DATA	4
#define CHECKSUM	5
#define DIR_HASHTAB	6
#define FH_ENDLIST	6
#define FH_BLOCKLIST	77
#define BITMAPINDEX	79
#define NAME		108
#define CREATE_TICKS	123
#define HASHCHAIN	124
#define	PARENT		125
#define EXTENSION	126
#define SECONDARY_TYPE	127
#define	BITMAP_CHECKSUM	0
#define NAMEOFFSET	433
#define NAMELENGTH	432

/*	Diskblock-Typ Definitionen 	*/

#define T_SHORT		2
#define T_DATA		8
#define T_LIST		16
#define ST_ROOT		1
#define ST_DIR		2
#define ST_FILE		-3

#define EMPTY		(unsigned long*) 0
#define BLOCKED		(unsigned long*) 0xFFFFFFFF

#define SOURCE		0
#define DESTINATION	1


/* Globale Variablen	*/

extern struct Library		*ArpBase;
struct IOExtTD		diskreq0,diskreq1,diskreq2;
struct MsgPort		*diskport;

int	diskchangecount0,diskchangecount1;
unsigned long	dirstack   [NUMBLOCKS];
unsigned short	sectormap  [NUMBLOCKS];
unsigned long	*buffermap [NUMBLOCKS];
unsigned long	*readmap   [NUMBLOCKS];
unsigned short	filestack  [NUMBLOCKS/2];
unsigned char	trackmap   [160];
unsigned short	dirstackptr ,filestackptr ,smptr;
unsigned char	formatflag, fastloadflag;
unsigned long	seccount, rootoff;
unsigned long	*trackbuffer;
unsigned long	*oldbuffer;
unsigned short	sourcedrive ,destinationdrive;
char		sourcedevice[5] = "DF0:";
char		destdevice[5] = "DF1:";
char 		spb[34];

/* Prototypes */


void moveblock(void);
void sortfiles(void);
void makefiles(void);
void makeroot(void);
void writeheaders(void);
void writeblank(void);
void writeboot(void);
void closeall(void);
void travel(int);
int is_special(unsigned char *);
int getfreesector(void);
void dofile(unsigned long*);
void makedirs(void);
void init(void);
void pushdir(int);
int popdir(void);
void pushfile(int);
int popfile(void);
void DoCheckSum(unsigned long*,int);
void ReadSector(int,unsigned long*);
unsigned long *GetSector(int);
void formattrack(int);
void WriteSector(int,unsigned long*);
void PutSector(int,unsigned long*);
unsigned long *allocbuffer(void);
void releasebuffer(unsigned long *);
void openall(void);
void checkdisks(void);
/*void error(void);*/
void closeall(void);

void sprintf(char*,char*,);

void do_fast(int,int,int,int);
void loop(void);
void pmsg(char*,int);

void do_fast(dr1,dr2,fastdir,noformat)
int dr1,dr2,fastdir,noformat;
{
	sourcedrive=dr1;
	destinationdrive=dr2;
	
	sourcedevice[2] = (char) ('0' + (char) sourcedrive);
	destdevice[2] = (char) ('0' + (char) destinationdrive);
	fastloadflag=!fastdir;
	formatflag=!noformat;
	
	pmsg("setting up",0);
	openall ();
	checkdisks();
	init ();
	pmsg("analyzing",0);
	travel (ROOTBLOCK);
	pmsg("moving blocks",0);
	moveblock ();
	pmsg("sorting files",0);
	sortfiles ();
	pmsg("making files",0);
	makefiles ();
	pmsg("making dirs",0);
	makedirs ();
	pmsg("making route",0);
	makeroot ();
	pmsg("writing headers",0);
	writeheaders ();
	pmsg("formating blanks",0);
	writeblank();
	pmsg("copying bootblock",0);
	writeboot ();
	pmsg("optimizing completed!",0);
	closeall ();
}

void travel(head)
int head;
{
	 unsigned long	*headbuffer,*workbuffer,*auxbuffer;
	int sector,hc,i,count;
	

	/*	Rekursives Durchlaufen des Directory-Trees in Zwischenordnung	*/

	headbuffer = buffermap[head];
	for (i=DIR_HASHTAB; i<=FH_BLOCKLIST; i++) {
		sector=headbuffer[i];
		if (sector) {
			workbuffer = buffermap[sector] = GetSector(sector);
			if ((workbuffer[TYPE] == T_SHORT) &&
			    (workbuffer[SECONDARY_TYPE] == ST_DIR)) {
				if (fastloadflag) {
					sectormap[sector] = ROOTBLOCK+2+dirstackptr;
				} else {
					sectormap[sector] = smptr++;
				}
				pushdir(sector);
				travel(sector);
			}
			else {
				sectormap[sector] = smptr++;
				pushfile(sector);

					/*	Existieren File List Blocks ?	*/

				auxbuffer = buffermap[sector];
				count = workbuffer[HIGHEST_SEQ];
				while (auxbuffer[EXTENSION]) {
					sector = auxbuffer[EXTENSION];
					auxbuffer = buffermap[sector] = GetSector(sector);
					count += auxbuffer[BLOCK_COUNT];
					sectormap[sector] = smptr++;
				}

				/*	Ist es ein .info-File?	*/

				if (is_special(workbuffer)) {
					sectormap[workbuffer[FIRST_DATA]] = smptr;
					smptr += count;
				}
			}

			/* Weitere Header-Blocks in der Hashchain ?	 */

			hc=workbuffer[HASHCHAIN];
			while (hc) {
				workbuffer = buffermap[hc] = GetSector(hc);
				if ((workbuffer[TYPE] == T_SHORT) &&
				    (workbuffer[SECONDARY_TYPE] == ST_DIR)) {
					sectormap[hc] = ROOTBLOCK+2+dirstackptr;
					if (fastloadflag) {
						sectormap[hc] = ROOTBLOCK+2+dirstackptr;
					} else {
						sectormap[hc] = smptr++;
					}
					pushdir(hc);
					travel(hc);
				}
				else {
					sectormap[hc]=smptr++;
					pushfile(hc);

					/*	Existieren File List Blocks ?	*/

					auxbuffer = buffermap[hc];
					count = workbuffer[HIGHEST_SEQ];
					while (auxbuffer[EXTENSION]) {
						sector = auxbuffer[EXTENSION];
						auxbuffer = buffermap[sector] = GetSector(sector);
						count += auxbuffer[BLOCK_COUNT];
						sectormap[sector] = smptr++;
					}

					/*	Ist es ein .info-File ?		*/

					if (is_special(workbuffer)) {
						sectormap[workbuffer[FIRST_DATA]] = smptr;
						smptr += count;
					}
				}
				hc=workbuffer[HASHCHAIN];
			}
		}
	}
}

void moveblock()
{
	int sector,dest,diff;
	
	/*	Zentriert die Header-Blocks auf der Diskette	*/

	if ((diff = (smptr-881)/SECS_PER_TRACK) > 2) {
		diff = (((diff/2)+1) * SECS_PER_TRACK) - 2;
	} else {
		diff = 0;
	}
	if (fastloadflag) {
		rootoff += dirstackptr;
		diff -= dirstackptr;
	}

	for (sector=2; sector < NUMBLOCKS; ++sector) {
		dest = sectormap[sector];
		if ((dest)
		 && (dest != 880)
		 && (dest != 881)
 		 && !((fastloadflag) &&
		      (buffermap[sector][SECONDARY_TYPE] == ST_DIR))) {
			if ((dest >= 882) && (dest-diff < ROOTBLOCK+rootoff)) {
				sectormap[sector] -= (ULONG) (diff+rootoff);
			} else {
				sectormap[sector] -= (ULONG) diff;					}
		}
	}
	seccount = (ULONG) ROOTBLOCK - diff;
}

void sortfiles()
{
	 int	file,count,top,temp;
	
	/* Erst die .info-Files kopieren */

	top = filestackptr-1;
	for (file = 0; file < top;file++) {
		if (is_special(buffermap[filestack[file]])) {
			temp = filestack[file];
			for (count=file; count < top; count++) {
				filestack[count] = filestack[count+1];
			}
			filestack[top--] = temp;
			file--;
		}
	}
}


int is_special(buffer)
 unsigned char	*buffer;
{

	/* Diese Files werden direkt hinter ihrem Headerblock abgelegt */

	pmsg(buffer+NAMEOFFSET,0);
	
	if (fastloadflag) {
		return (1);
	}

	if (scmp(buffer+NAMEOFFSET+buffer[NAMELENGTH]-5,".INFO",5)) {
		return (1);
	}

	if (scmp(buffer+NAMEOFFSET,"SYSTEM-CONFIGURATION",20)) {
		return (1);
	}

	if (scmp(buffer+NAMEOFFSET,"STARTUP-SEQUENCE",16)) {
		return (1);
	}
	return (0);
}

int getfreesector()
{

	/* Liefert naechsten freier Sector auf der Diskette */

	if (seccount == 2) {
		return (seccount = NUMBLOCKS-1);
	} else {
		return (--seccount);
	}
}

void makefiles()
{
	 int	file;

	/* kopiert alle File-Datenblocks auf die Zieldiskette.
	   Die neuen Sectorpositionen werden in den Headerblocks korrigiert. */

	while (file = popfile()) {
		dofile(buffermap[file]);
	}
}

void dofile(headbuffer)
 unsigned long	*headbuffer;
{
	 unsigned long	*workbuffer;
	 int sector,next_sector,more_to_come;

	if (headbuffer[FIRST_DATA]) {
		workbuffer = GetSector(headbuffer[FIRST_DATA]);
		if (is_special(headbuffer)) {
			sector = sectormap[headbuffer[FIRST_DATA]];
			if (sector == ROOTBLOCK) {
				sector += rootoff;
			}
		} else {
			sector = getfreesector();
		}
		sectormap[headbuffer[FIRST_DATA]] = sector;
		do {
			workbuffer[HEADER_KEY]=sectormap[headbuffer[HEADER_KEY]];
			more_to_come = workbuffer[NEXT_DATA];
			if (more_to_come) {
				if (is_special(headbuffer)) {
					next_sector = sector + 1;
					if (next_sector == ROOTBLOCK) {
						next_sector += rootoff;
					}
				} else {
					next_sector = getfreesector();
				}
				workbuffer[NEXT_DATA] = next_sector;
			}
			DoCheckSum(workbuffer,CHECKSUM);
			PutSector(sector,workbuffer);
			if (more_to_come) {
				workbuffer = GetSector(more_to_come);
				sector = sectormap[more_to_come] = next_sector;
			}
		} while (more_to_come);
	}
		/*	Aenderungen in File Header & File List Blocks	*/

	do {
		more_to_come = headbuffer[EXTENSION];
		sector = FH_BLOCKLIST;
		while (sector >= FH_ENDLIST) {
			headbuffer[sector--]=sectormap[headbuffer[sector]];
		}
		headbuffer[PARENT]     = sectormap[headbuffer[PARENT]];
		headbuffer[HEADER_KEY] = sectormap[headbuffer[HEADER_KEY]];
		headbuffer[FIRST_DATA] = sectormap[headbuffer[FIRST_DATA]];
		headbuffer[HASHCHAIN]  = sectormap[headbuffer[HASHCHAIN]];
		headbuffer[EXTENSION]  = sectormap[headbuffer[EXTENSION]];
		DoCheckSum(headbuffer,CHECKSUM);
		if (more_to_come) {
			headbuffer = buffermap[more_to_come];
		}
	} while (more_to_come);
}

void makedirs()
{
	 unsigned long	*headbuffer;
	int dir,sector;
	
	/* Aenderungen in den Directory-Header Blocks */

	while (dir = popdir()) {
		headbuffer = buffermap[dir];
		for ( sector = FH_BLOCKLIST;
		      sector >= FH_ENDLIST;
		      --sector) {
			if (headbuffer[sector]) {
				headbuffer[sector]=sectormap[headbuffer[sector]];
			}
		}
		headbuffer[PARENT]     = sectormap[headbuffer[PARENT]];
		headbuffer[HEADER_KEY] = sectormap[headbuffer[HEADER_KEY]];
		headbuffer[HASHCHAIN]  = sectormap[headbuffer[HASHCHAIN]];
		headbuffer[EXTENSION]  = sectormap[headbuffer[EXTENSION]];
		DoCheckSum(headbuffer,CHECKSUM);
	}
}		

void makeroot()
{
	 unsigned long	*headbuffer,*workbuffer;
	int sector,bmsector,mask,offset,count;
	
	workbuffer = allocbuffer();
	headbuffer = buffermap[ROOTBLOCK];

	/* Aenderungen im Rootblock */

	bmsector = sectormap[headbuffer[BITMAPINDEX]];
	for ( sector = FH_BLOCKLIST; sector >= FH_ENDLIST; --sector) {
		if (headbuffer[sector]) {
			headbuffer[sector]=sectormap[headbuffer[sector]];
		}
	}
	headbuffer[BITMAPINDEX] = bmsector;
	headbuffer[CREATE_TICKS] += 1;	/* Wichtig ! Hiermit wird gesichert, */
					/* dass AmigaDOS Quell- und Zieldisk */
					/* unterscheiden kann. */
	DoCheckSum(headbuffer,CHECKSUM);

	/* Neuen Bit-Map Sector erstellen */

	for (count=1; count <= NUMLONGS; ++count) {
		workbuffer[count] = 0xFFFFFFFF;
	}

	for (count = 2; count < NUMBLOCKS; ++count) {
		sector = sectormap[count];
		if (sector) {
			offset = 1 + ((sector-2)/32);
			mask   = (ULONG) 1 << ((sector-2) & 0x1f);
			workbuffer[offset] -= (ULONG) mask;
		}
	}
	DoCheckSum(workbuffer,BITMAP_CHECKSUM);
	PutSector(bmsector,workbuffer);
}

void writeheaders()
{
	int	buffer;

	/* Alle Header-Blocks werden auf Zieldisk geschrieben */

	for (buffer=0; buffer<NUMBLOCKS; ++buffer) {
		dirstack[buffer] = NULL;
	}

	for (buffer = 2; buffer<NUMBLOCKS; ++buffer) {
		if (buffermap[buffer]) {
			dirstack[sectormap[buffer]] = (ULONG) buffermap[buffer];
			buffermap[buffer] = NULL;
		}
	}

	for (buffer = 0; buffer<NUMBLOCKS; ++buffer) {
		if (dirstack[buffer]) {
			PutSector((ULONG) buffer,dirstack[buffer]);
		}
	}
	PutSector(NULL,NULL);
}

void writeblank()
{
	int	i;

	/* Formatiert nicht belegte Tracks auf der Zieldisk */

	if (formatflag) {
		for (i=0; i < 160; i++) {
			if ( !(trackmap[i])) {
				formattrack(i);
				WaitIO(&diskreq2);
				trackmap[i]=1;
			}
		}
	}
}

void writeboot()
{
	 unsigned long *workbuffer;

	/* Bootsectoren uebertragen */

	workbuffer = allocbuffer();
	ReadSector (0L,workbuffer);
	WriteSector(0L,workbuffer);
	WaitIO(&diskreq1);
	ReadSector (1L,workbuffer);
	WriteSector(1L,workbuffer);
	WaitIO(&diskreq1);
	diskreq1 . iotd_Req.io_Command = ETD_UPDATE;
	diskreq1 . iotd_Count		= diskchangecount1;
	DoIO (&diskreq1);
	releasebuffer(workbuffer);
}

void init()
{
	 unsigned long	*headbuffer,*workbuffer;
	 unsigned long	count,offset,mask;

	

	/* Feldinitialisierungen */

	for (count=0L; count < NUMBLOCKS; ++count) {
		sectormap [count] = NULL;
		buffermap [count] = NULL;
		dirstack  [count] = NULL;
		readmap   [count] = EMPTY;
	}
	sectormap[0] = 0L;
	sectormap[1] = 1L;

	/* Trackbuffer */

	for (count=0; count <= 160; count++) {
		trackmap[count] = 0;
	}

	if ( !(trackbuffer = AllocMem(NUMSECS * BLOCKSIZE, MEMF_CHIP | MEMF_CLEAR))) {
		pmsg("can't allocate trackbuffer!",1);
		error();
	}

	/* Rootblock laden */

	smptr = ROOTBLOCK;
	headbuffer = buffermap[ROOTBLOCK] = GetSector(ROOTBLOCK);
	sectormap[ROOTBLOCK] = smptr++;
	sectormap[headbuffer[BITMAPINDEX]] = smptr++;

	/* Markieren aller nicht belegter Bloecke (BAM-Selection) */

	workbuffer = GetSector(headbuffer[BITMAPINDEX]);
	for (count = 2L; count < NUMBLOCKS; ++count) {
		offset = 1L + ((count-2L)/32L);
		mask   = 1L << ((count-2L) & 0x1fL);
		if (workbuffer[offset] & mask) {
			if (readmap[count]) {
				releasebuffer(readmap[count]);
			}
			readmap[count] = BLOCKED;
		}
	}
	readmap[ROOTBLOCK] = readmap[headbuffer[BITMAPINDEX]] = BLOCKED;
	readmap[0] = readmap[1] = BLOCKED;
	releasebuffer(workbuffer);
}

void pushdir(sector)
 int	sector;
{
	dirstack[dirstackptr++] = sector;
}

int popdir()
{
	if ((dirstackptr) == 0)
		return (NULL);
	else
		return (dirstack[--dirstackptr]);
}

void pushfile(sector)
int	sector;
{
	filestack[filestackptr++] = sector;
}

int popfile()
{
	if ((filestackptr) == 0)
		return (NULL);
	else
		return (filestack[--filestackptr]);
}

void DoCheckSum(buffer,pos)
 unsigned long	*buffer;
 int pos;
{
	int count;
	  unsigned long	checksum;

	/* CheckSum fuer normale und Bit-Map Blocks errechnen */

	buffer[pos] = checksum = NULL;
	for (count=0; count < SIZE; ++count) {
		checksum += (unsigned long) buffer[count];
	}
	buffer[pos] -= (unsigned long) checksum;
}

void ReadSector (sector,buffer)
int sector;
 unsigned long *buffer;
{
	/* Laedt einen Sector von der Quell-Diskette */

	diskreq0 . iotd_Req.io_Length 	= BLOCKSIZE;      
	diskreq0 . iotd_Req.io_Data 	= (APTR) buffer;	
	diskreq0 . iotd_Req.io_Command = ETD_READ;
	diskreq0 . iotd_Count 		= diskchangecount0;
	diskreq0 . iotd_Req.io_Offset 	= sector*512;
	DoIO (&diskreq0);
	if (diskreq0 . iotd_Req.io_Error) {
		sprintf(spb,"DF%ld: readerror %ld on %ld!",(int)sourcedrive,(int)diskreq0.iotd_Req.io_Error,(int)sector);
		pmsg(spb,1);
		error();
	}
}

unsigned long *GetSector(sector)
 int	sector;
{
	 unsigned long	*workbuffer,*temp;
	 int	track,sec;

	/* Holt einen Sector von der Quell-Diskette oder */
	/* liefert den entsprechenden Buffer. */

	if (sector >= NUMBLOCKS) {
		sprintf(spb,"DF%ld: illegal sector %ld!",(int)sourcedrive,(int)sector);
		pmsg(spb,1);
		error();
	}
	if (readmap[sector]) {
		if (readmap[sector] == BLOCKED) {
			sprintf(spb,"DF%ld: double reference to %ld!",(int)sourcedrive,(int)sector);
			pmsg(spb,1);
			error();
		} else {
			temp = readmap[sector];
			readmap[sector] = BLOCKED;
			return (temp);
		}
	} else {
		workbuffer = allocbuffer();
		ReadSector (sector,workbuffer);
		readmap[sector] = BLOCKED;
		track = sector / SECS_PER_TRACK;
		for (sec=track*SECS_PER_TRACK; sec < (track+1)*SECS_PER_TRACK; sec++) {
			if (readmap[sec] == EMPTY) {
				if (readmap[sec] = allocbuffer()) {
					ReadSector(sec,readmap[sec]);
				} else {
					break;
				}
			}
		}
		return (workbuffer);
	}
}

void formattrack(track)
 int track;
{

	/* Formatiert einen Track auf der Zieldiskette */

	
	diskreq2 . iotd_Req.io_Length	= NUMSECS * BLOCKSIZE;      
	diskreq2 . iotd_Req.io_Data	= (APTR) trackbuffer;	
	diskreq2 . iotd_Req.io_Command = TD_FORMAT;
	diskreq2 . iotd_Count		= diskchangecount1;
	diskreq2 . iotd_Req.io_Offset	= track * (NUMSECS * BLOCKSIZE);
	SendIO (&diskreq2);
	if (diskreq1 . iotd_Req.io_Error) {
		sprintf(spb,"DF%ld: formaterror %ld on cyl %ld!",(int)destinationdrive,(int)diskreq2.iotd_Req.io_Error,(int)track/2);
		error();
	}
}

void WriteSector(sector,buffer)
 int sector;
 unsigned long *buffer;
{
	 short int	track;

	/* Falls noch nicht geschehen, formatieren des Ziel-Tracks */

	track = (sector / 11);
	if ( (formatflag) && !(trackmap[track])) {
		formattrack(track);
		trackmap[track] = 1;
	}

	/* Schreibt einen Sector auf die Ziel-Diskette */

	diskreq1 . iotd_Req.io_Length	= BLOCKSIZE;      
	diskreq1 . iotd_Req.io_Data	= (APTR) buffer;	
	diskreq1 . iotd_Req.io_Command = ETD_WRITE;
	diskreq1 . iotd_Count		= diskchangecount1;
	diskreq1 . iotd_Req.io_Offset	= sector*512;
	SendIO (&diskreq1); /* Asynchroner Schreibzugriff */
}

void PutSector(sector,buffer)
 int sector;
 unsigned long *buffer;
{

	/* Schreibt Sector auf Zieldisk und deallociert den Buffer */

	if (oldbuffer) {
		WaitIO(&diskreq1); /* Warten auf das Ende des letzten Schreibzugriffs */
		if (diskreq1 . iotd_Req.io_Error) {
			sprintf(spb,"DF%ld: write error %ld on %ld!",(int)destinationdrive,(int)diskreq1.iotd_Req.io_Error,(int)sector);
			pmsg(spb,1);
			error();
		}
		releasebuffer(oldbuffer);
	}
	if (oldbuffer = buffer) {
		WriteSector(sector, buffer);
	}
}

unsigned long *allocbuffer()
{
	 unsigned long	*buffer;
	 int sec;

	/* Allociert 512 Byte Chip-Memory als Sector-Buffer */
	/* Falls kein Chip-Mem mehr vorhanden ist, wird ein */
	/* bestehender, nicht unbedingt benoetigter Sector  */
	/* deallociert. 				    */

	buffer = AllocMem((long) BLOCKSIZE, MEMF_CHIP);
	if (buffer == NULL) {
		for (sec=2; sec<NUMBLOCKS; sec++) {
			if ((readmap[sec]) && 
			    (readmap[sec] != BLOCKED) &&
			    (readmap[sec][TYPE] == T_DATA)) {
				buffer = readmap[sec];
				readmap[sec] = EMPTY;
				break;
			}
		}
		if (sec == NUMBLOCKS) {
			pmsg("out of CHIP-mem!",1);
			error();
		}
	}
	return (buffer);
}

void releasebuffer(buffer)
 unsigned long *buffer;
{

	/* Deallociert einen 512-Byte Buffer */

	if (buffer) {
		FreeMem(buffer, (long) BLOCKSIZE);
	}
}

void openall()
{
	int	err;

	/* Oeffnen der Disk-Devices */

	smptr=ROOTBLOCK;
	rootoff=2;
	oldbuffer=trackbuffer=dirstackptr=filestackptr=0;
	diskreq0.iotd_Req.io_Device=0;
	diskreq1.iotd_Req.io_Device=0;
	diskreq2.iotd_Req.io_Device=0;

	if ( !(diskport = CreatePort (NULL, NULL))) {
		pmsg("can't create MsgPort!",1);
		error();
	}

	diskreq0.iotd_Req.io_Message.mn_ReplyPort=diskport;
	diskreq1.iotd_Req.io_Message.mn_ReplyPort=diskport;
	diskreq2.iotd_Req.io_Message.mn_ReplyPort=diskport;
	
	if (err = OpenDevice (TD_NAME, sourcedrive, &diskreq0, NULL)) {
		sprintf(spb,"DF%ld: openerror %ld!",(int)sourcedrive,(int)err);
		pmsg(spb,1);
		diskreq0.iotd_Req.io_Device=0;
		error();
	}

	if (err = OpenDevice (TD_NAME, destinationdrive, &diskreq1, NULL)) {
		sprintf(spb,"DF%ld: openerror %ld!",(int)destinationdrive,(int)err);
		pmsg(spb,1);
		diskreq1.iotd_Req.io_Device=0;
		error();
	}

	if (err = OpenDevice (TD_NAME, destinationdrive, &diskreq2, NULL)) {
		sprintf(spb,"DF%ld: openerror %ld!",(int)destinationdrive,(int)err);
		pmsg(spb,1);
		diskreq2.iotd_Req.io_Device=0;
		error();
	}

	/* Disk-Validation abstellen */

	/* ARP by Olli */
	
	err=-1;

	SendPacket(ACTION_INHIBIT,&err,DeviceProc(destdevice));
	SendPacket(ACTION_INHIBIT,&err,DeviceProc(sourcedevice));
	
}

void checkdisks()
{
	diskreq0 . iotd_Req.io_Command = TD_CHANGESTATE;
	DoIO (&diskreq0);
	if (diskreq0 . iotd_Req.io_Actual) {
		sprintf(spb,"no disk in DF%ld:!",(int)sourcedrive);
		pmsg(spb,1);
		error();
	}

	diskreq1 . iotd_Req.io_Command = TD_CHANGESTATE;
	DoIO (&diskreq1);
	if (diskreq1 . iotd_Req.io_Actual) {
		sprintf(spb,"no disk in DF%ld:!",(int)destinationdrive);
		pmsg(spb,1);
		error();
	}

	diskreq1 . iotd_Req.io_Command = TD_PROTSTATUS;
	DoIO (&diskreq1);
	if (diskreq1 . iotd_Req.io_Actual) {
		sprintf(spb,"DF%ld: write-protect on!",(int)destinationdrive);
		pmsg(spb,1);
		error();
	}

	diskreq0 . iotd_Req.io_Command = TD_CHANGENUM;
	DoIO (&diskreq0);
	diskchangecount0 = diskreq0 . iotd_Req.io_Actual;

	diskreq1 . iotd_Req.io_Command = TD_CHANGENUM;
	DoIO (&diskreq1);
	diskchangecount1 = diskreq1 . iotd_Req.io_Actual;

}

/*void error()
{
	closeall();
	loop();
}*/

void closeall()
{
	int	count;

	/* Schliessen der Disk-Devices */
	/* Deallocieren der Buffer     */
	/* Schliessen der Library      */

	if (oldbuffer) {
		releasebuffer(oldbuffer);
	}

	for (count = NULL; count<NUMBLOCKS; ++count) {
		if (buffermap[count]) {
			releasebuffer(buffermap[count]);
		}
		if ((readmap[count]) && (readmap[count] != BLOCKED)) {
			releasebuffer(readmap[count]);
		} 
	}

	if (trackbuffer) {
		FreeMem(trackbuffer,NUMSECS * BLOCKSIZE);
	}

	if (diskreq0.iotd_Req.io_Device) CloseDevice(&diskreq0);
	if (diskreq1.iotd_Req.io_Device) {
		CloseDevice(&diskreq1);
		SendPacket(ACTION_INHIBIT,0,DeviceProc(destdevice));
		SendPacket(ACTION_INHIBIT,0,DeviceProc(sourcedevice));
	}
	if (diskreq2.iotd_Req.io_Device) CloseDevice(&diskreq2);

	if (diskport) {
		DeletePort (diskport);
	}
}
