/*	File Copy Module 
			FileWrite, FileMake, FileErase, FileClose
				AllocCluster, DeAllocCluster
	"FCWRITE.C"
*/

/*=============================================================================
			INCLUDE FILES
*/

#include	"filecopy.os"
#include	"c:switch.os"
#include	"fcconst.h"
#include	"fcstruct.h"
#include	"fcdata.h"

/*=============================================================================
			HISTORY
    Last change:   13 March 1984	tpl

ver	0
rev	0
mod	d
patch	13


 mod
-----
  d		1 December 1983		tpl
	.Uncomment bioswrites. Finish debugging DeAllocCluster, UpdateFATs,
	and FileErase, FileMake, FileClose.

  c		30 November 1983	tpl
	.Start coding DeAllocCluster and UpdateFATs.

  b12		30 November 1983	tpl
	.FileWritem FileMake and FileClose seem to be working; they
	have been tested with all bioswrites commented out.

  b		16 November 1983	tpl
	.FileMake working. FileWrite, FileErase and FileClose mostly
	coded. Starting AllocCluster and DeAllocCluster coding.

  a		14 November 1983	tpl
	.Begin documenting what FileWrite, FileMake, FileClose and 
	FileErase are to do.

*/
/*=============================================================================
			CONSTANTS / DEFINITIONS
*/

#define		FORCEwrite	1

/*=============================================================================
			VARIABLES and DATA STRUCTURES
*/
/*page*/
/*=============================================================================
			ROUTINES
*/
/*---------------------------------------------------------------------------*/

int FileWrite( file, buffer, buff_size )
CHAR	*buffer;	/* Address of buffer to get data from.	    */
int	buff_size;	/* Size of buffer, i.e. 1024 for 1k.	    */
int	file;		/* FileOpen return value.		    */
				/* open_fcbs [file] is a pointer to an fcb.*/
/* Write to the file described by the fcb addressed by open_fcbs [file].
  When new cluster is needed call AllocCluster.
  Return 0 if successfull write.
  Return FAIL if no more clusters and one is needed, i.e. out of space.
  Assumes that buff_size divides evenly into the cluster size in bytes.
*/
{
int		cluster_offset, num_records, save_DMA;
int		buff_offset;
CHAR		cur_disk, drive, i;
struct	ms_fcb	*curfcb;
struct	BPB	*curBPB;
	
#ifdef debugP
	printf("p..FileWrite       entering\n");
#endif

	cur_disk = CurDisk();
	drive = open_fcbs [file]->drive - 1;	/* drive -> 0=A, 1=B, 2=C..  */
	curfcb = open_fcbs [file];
	curBPB = frgn_BPB [drive];
	SelDisk( drive );
	save_DMA = GetDMA();

	if ( curfcb->cur_cluster == 0 ) { /* if first write to file. */
#ifdef debug
		printf("  first write to file.\n");
#endif
		curfcb->cur_cluster = curfcb->start_cluster
				= AllocCluster( 0, drive );
		if ( curfcb->cur_cluster == FAIL ) {
		/* Then no more clusters, i.e. out of space to allocate.   */
#ifdef debug
			printf("  Out of clusters. Leave FileWrite.\n");
#endif
			SetDMA( save_DMA );		/* Restore order. */
 			SelDisk( cur_disk );		/* Restore order. */
			return( FAIL );
			}/*if no more clusters*/

		curfcb->cur_record = 0;
		cluster_offset = ((curfcb->cur_cluster - 2)
				* curBPB->SectPerCluster)
				+ frgnDirInfo [drive]->dataOffset;
		curfcb->curBiosTrack
			= cluster_offset / curBPB->SectPerTrack;
		curfcb->curBiosSector
			= cluster_offset % curBPB->SectPerTrack;
		IncrSize( curfcb , drive);
    		}
	else {	/* if new cluster needed, allocate it.	*/
		if (curfcb->cur_record == curBPB->SectPerCluster) {
		/* If have written all records in the cluster 	*/
		/* Then allocate next cluster			*/
#ifdef debug
			printf("   allocate next cluster\n");
#endif
			    curfcb->cur_cluster
				= AllocCluster( curfcb->cur_cluster, drive);
			if ( curfcb->cur_cluster == FAIL ) {
			/* no more clusters, i.e. out of space to allocate. */
#ifdef debug
				printf("Out of clusters. Leave FileWrite.\n");
#endif
				SetDMA( save_DMA );  /* Restore order.	*/
 				SelDisk( cur_disk ); /* Restore order.	*/
				return( FAIL );
	    			}/*if no more clusters*/

			/* Else, prepare to write next cluster.	*/
			curfcb->cur_record = 0;
			cluster_offset = ((curfcb->cur_cluster - 2)
				* curBPB->SectPerCluster)
				+ frgnDirInfo [drive]->dataOffset;
			curfcb->curBiosTrack  =
				cluster_offset / curBPB->SectPerTrack;
			curfcb->curBiosSector =
				cluster_offset % curBPB->SectPerTrack;

			IncrSize( curfcb , drive);

			}/*if new cluster needed*/
		}/*else if new cluster needed*/

/* Compute the number of records to write to get buff_size bytes.	*/
	num_records = buff_size / curBPB->BytesInSector;
#ifdef debug
	printf("  num_records to write: %x hex\n",num_records);
	printf("  >> before write loop\n");
	ShowOpenFile( file);
#endif

/* Write loop. Write 'num_records' sectors to the disk.			 */
/* Assumes that a new cluster will not be needed, i.e. buff_size divides */
/* evenly into the cluster size in bytes.				 */

	buff_offset = 0;
	for ( i=0; i<num_records; ++i) { /* Write the buffer onto disk. */
		if (frgnWrite (drive, buffer + buff_offset,
			curfcb->curBiosTrack,
			curfcb->curBiosSector, 0)) {
			printf("Fatal error returned from BiosWrite call in FileWrite.\n");
			zabort();
			}

#ifdef debug
	printf("   Bios WRITE\n");
	printf("  BiosTrack: %x    BiosSector: %x\n",
			curfcb->curBiosTrack,
			curfcb->curBiosSector);
#endif
	buff_offset += curBPB->BytesInSector;

	/* Update curfcb for next record write. 		*/
	++curfcb->cur_record;
	if (++curfcb->curBiosSector == curBPB->SectPerTrack) {
		curfcb->curBiosSector = 0;
		++curfcb->curBiosTrack;
		}
	}/*for num_records write*/

	SetDMA( save_DMA);
	SelDisk( cur_disk );
	return( 0 );		/* Successfull write.	*/

	}/*FileWrite*/

/*page*/
/*---------------------------------------------------------------------------*/

IncrSize( fcb, drive )
  struct ms_fcb	*fcb;
  CHAR	drive;
{
/* Assumes that the number of bytes per cluster is an even power of two. */

  unsigned int	bytesInCluster;

#ifdef dbg1
	printf("p....IncrSize\n");
	printf("    before ... fcb->file_size[1],[0] : %x %x hex\n",
			fcb->file_size[1], fcb->file_size[0] );
#endif

    bytesInCluster = frgnDirInfo [drive]->bytesInCluster;
    if ( ( 0xffff - (fcb->file_size[0]-1) ) == bytesInCluster )
    {	/* If this addition will overflow one word of bytes, i.e. 64k bytes..*/
	/* Then overflow into high word of file size.	*/
	fcb->file_size[1] += 1;
	fcb->file_size[0] = 0;
    }
    else
	fcb->file_size[0] += bytesInCluster;

#ifdef dbg1
	printf("    after ...  fcb->file_size[1],[0] : %x %x hex\n",
			fcb->file_size[1], fcb->file_size[0] );
#endif

}/*IncrSize*/

/*page*/
/*---------------------------------------------------------------------------*/

int
FileMake( userFcb )
CHAR	*userFcb;		/* Pointer to an ms_fcb or an ms_fcb_ex.     */
{
/*	Erase any existing file of same name.
	Find an empty entry in the directory.
	Put into directory at this point an initialized dir_entry
	 of zero length.
	Put passed fcb into open_fcbs array.
	Returî the open_fcbs array index (current value of index_open_fcbs)
	 a positivå integer. This is tï bå passeä tï FileReaä, FileWrite,
 	 and FileErase for identification.
	A returned value of 'FAIL' means file not found.
	No mode allowed. ( Like RW or RO. )
*/
int	save_DMA, fcb_clear_size, cluster_offset, buff_offset;
CHAR	cur_disk, drive, i;
struct ms_dir_entry	*dir_entry;
struct ms_fcb		*fcb, empty_fcb;
struct ms_fcb_ex	*fcb_ex;

#ifdef debugP
	printf("p..FileMake	entering\n");
#endif

	if ( *userFcb == 0xff ) {	/* Then extended fcb.	*/
		fcb_ex = userFcb;
		fcb = userFcb + 7;
		}
	else {		/* else standard MSDOS fcb.	*/
		fcb = userFcb;
		fcb_ex = NULL;
		}

	if ( fcb->drive == 0) {	/* if = 0 use curDisk.		*/
		fcb->drive = drive = CurDisk();	/* 0=A, 1=B for CPM.	*/
		++fcb->drive;			/* 1=A, 2=B for fcb.	*/
		}
	else
		drive = fcb->drive -1;	/* So 0=A, 1=B, 2=C, ...	*/

#ifdef debug
	printf("  userFcb: %x    fcb: %x    fcb_ex: %x\n",
		  userFcb,	 fcb,	    fcb_ex);
	printf("  drive: %x hex    fcb->drive: %x hex\n", drive, fcb->drive);
#endif

/* continued next page */
/*page*/

	/* Erase any existing file by same name.	*/
	FileErase( fcb );

	/* Find empty entry to use.	*/
	empty_fcb.drive = fcb->drive;
	empty_fcb.name[0] = ERASED;
	clear( &empty_fcb.name[1], LENname + LENtype -1, 'A' );

	if ( (buff_offset = FirstDir( &empty_fcb )) == FAIL)
		return( FAIL );	/* No free directory space.	*/

	/* Use the found directory entry.	*/
	dir_entry = frgnDirBuffer + buff_offset; /* buff_offset in units of */
		  /* ms_dir_entry's since frgnDirBuffer is a pointer to one. */
	
	for (++index_open_fcbs, index_open_fcbs %= MAXfcbs; 
		open_fcbs [index_open_fcbs] != NULL;
		++index_open_fcbs, index_open_fcbs %= MAXfcbs)
		;

	/* Setup open_fcbs pointer to the fcb.	*/
	/* Clear all fields past the name/type. */

	open_fcbs [index_open_fcbs] = fcb;
	clear( &(fcb->cur_cluster),
		sizeof( struct ms_fcb ) - (LENname + LENtype), 0);

/* Put fcb name into name field of found entry in case this was an emtpy   */
/* entry and not a found one of the same name.				   */
/* First zero the entry to initialize it to a zero length file.		   */

	clear( dir_entry->name, sizeof( struct ms_dir_entry ), 0);
	blockmv( dir_entry->name, fcb->name, LENname + LENtype );

/* Put initilized entry into the directory on the disk.			*/
/* Bios Track and Sector are still set properly from FirstDir call.	*/

	cur_disk = CurDisk();
	SelDisk( drive );

	save_DMA = GetDMA();
	SetDMA( frgnDirBuffer );
	if (WriteDirSector (drive)) {
		printf("Fatal error returned from BiosWrite call in FileMake.\n");
		zabort();
		}
#ifdef debug
	printf("    bios WRITE in FileMake.\n");
#endif

	SetDMA( save_DMA );

	SelDisk( cur_disk );

#ifdef debug
	printf("  returning 'index_open_fcbs': %x  hex\n", index_open_fcbs);
	printf("   frgnDirBuffer:\n");
	Show_128byte_buffer( frgnDirBuffer );
	ShowOpenFile( index_open_fcbs );
	printf("p..FileMake        exiting\n");
#endif

	return( index_open_fcbs );

	}/*FileMake*/

/*page*/
/*---------------------------------------------------------------------------*/

FileErase( userFcb )
  CHAR	*userFcb;		/* Pointer to an ms_fcb or an ms_fcb_ex.     */
{
/* Put an 0xe5 in the directory entry corresponding to userFcb.
   Must be unambiguous?
   Needs 'DeAllocate" routine to deallocate clusters in the FAT list for the
	file being erased.
*/
  struct ms_dir_entry	*dir_entry;
  struct ms_fcb		*fcb;
  struct ms_fcb_ex	*fcb_ex;
  CHAR	cur_disk, drive;
  int	buff_offset, save_DMA;
  int	retValue;

#ifdef debugP
	printf("p..FileErase       enter\n");
#endif
/* Find the file with a FirstDir. Put an 0xe5 in the first byte of the name
	field and write it back to the disk.
   Deallocate all clusters in its list.
   Make sure ALL FATs on the disk are properly updated.
*/

	if (*userFcb == 0xff) {	/* Then extended fcb.	*/
		fcb_ex = userFcb;
		fcb = userFcb + 7;
		}
	else {		/* else standard MSDOS fcb.	*/
		fcb = userFcb;
		fcb_ex = NULL;
		}

	if (fcb->drive == 0) {	/* if = 0 use curDisk.		*/
		fcb->drive = drive = CurDisk();	/* 0=A, 1=B for CPM.	*/
		++fcb->drive;			/* 1=A, 2=B for fcb.	*/
		}
	else
		drive = fcb->drive -1;	/* So 0=A, 1=B, 2=C, ...	*/

#ifdef debug
	printf("  userFcb: %x    fcb: %x    fcb_ex: %x\n",
		  userFcb,	 fcb,	    fcb_ex);
	printf("  drive: %x hex    fcb->drive: %x hex\n", drive, fcb->drive);
#endif

/* continued next page */
/*page*/

	if( (buff_offset = FirstDir( fcb )) == FAIL )
		return( FAIL );		/* Not found so tell caller.	*/

	/* Erase the found directory entry.	*/
	dir_entry = frgnDirBuffer + buff_offset;
			/* buff_offset is in units of ms_dir_entry's since */
			/*  frgnDirBuffer is an ms_dir_entry pointer.	   */
	dir_entry->name[0] = ERASED;

/* Write to directory to erase the entry.	*/
/* Bios Track and Sector are still set properly from FirstDir call.	*/

	cur_disk = CurDisk ();
	SelDisk (drive);

	save_DMA = GetDMA ();
	SetDMA (frgnDirBuffer);
	if (WriteDirSector (drive)) { 
		printf("Fatal error returned from BiosWrite call in FileErase.\n");
		zabort();
		}
#ifdef debug
	printf("    >> bios WRITE\n");
#endif

	SetDMA (save_DMA);

/* Free all the clusters presently allocated to the file being erased.       */
	if (dir_entry->start_cluster != 0) {
		/* If there are clusters to free. */
		DeAllocCluster( dir_entry->start_cluster, drive );

		UpdateFATs( drive );
			/* Update the FATs on the disk with free cluster */
			/*pointers from the erased file.		     */
		}

	SelDisk( cur_disk );

	}/*FileErase*/

/*---------------------------------------------------------------------------*/
/*page*/
#ifdef	NEWFEAT
/* Macros for getting and setting the date */
#define	MSTime(h,m,s)	((int) ((h << 11) | ((m & 0x7F) << 5) | (s & 0x1F)))
#define MSDate(d,m,y)	((int) ((((y < 80 ? 20 + y : y - 80) & 0x7F) << 9) | (d & 0x1F) | ((m & 0xF) << 5)))
#ifdef cpm80
#define CPMsecond	(*(CHAR *) 0x41)
#define	CPMminute	(*(CHAR *) 0x42)
#define CPMhour		(*(CHAR *) 0x43)
#define	CPMmonth	(*(CHAR *) 0x44)
#define CPMday		(*(CHAR *) 0x45)
#define CPMyear		(*(CHAR *) 0x46)
#endif
#endif

FileClose (file)
int	file;		/* A file descriptor returned by Open or Make.	*/
{
/* Put a dir_entry in the directory with all fields set correctly, incl. the
	first cluster field.
   Find the correponding entry in the directory and overwrite it with the
	new dir_entry info.
*/
int			save_DMA, buff_offset;
struct ms_dir_entry	*dir_entry;
CHAR			cur_disk;
struct ms_fcb		*curfcb;

#ifdef debugP
	printf("p..FileClose       enter\n");
#endif
/* FirstDir for the correct dir entry then write it back with the appropriate
	fields set.
*/
	curfcb = open_fcbs [file];
	if ( curfcb == NULL) {
		printf("%cFatal error in FileClose. File never opened or made.\n",BELL);
		zabort();
		}
	iæ ¨ (buff_offseô ½ FirstDir¨ curfcb)© =½ FAIÌ ) {
		printf("%cFataì erroò iî FileClose® Nï directorù entrù tï Close.\n",
									BELL);
		zabort();
		}

	/* Use the found directory entry.	*/
	dir_entry = frgnDirBuffer + buff_offset;
			/* buff_offset is in units of ms_dir_entry's since */
			/*  frgnDirBuffer is an ms_dir_entry pointer.	   */
/* The fields that must be set correctly are:
	attribute, fileTime, fileDate, start_cluster and size_in_bytes.
   For now set start_cluster and size_in_bytes.
   The size_in_bytes field should be set to the file_size field of the fcb,
which is set to the nearest cluster in the FileWrite routine.
*/

	dir_entry->start_cluster = curfcb->start_cluster;
	dir_entry->size_in_bytes[0] = curfcb->file_size[0];
	dir_entry->size_in_bytes[1] = curfcb->file_size[1];

#ifdef NEWFEAT
	*(int *)(&dir_entry->fileTime [0]) = MSTime (CPMhour, CPMminute, CPMsecond);
	*(int *)(&dir_entry->fileDate [0]) = MSDate (CPMday, CPMmonth, CPMyear);
#endif


/* Put entry into the directory on the disk.			*/
/* Bios Track and Sector are still set properly from FirstDir call.	*/

	cur_disk = CurDisk();
	SelDisk( curfcb->drive -1);

	save_DMA = GetDMA();
	if (WriteDirSector (curfcb->drive-1)) {
		printf("Fatal error returned from BiosWrite call in FileClose.\n");
	    	zabort();
		}
#ifdef debug
	printf("  >> Bios WRITE. Assume last SelTrack/Sector ok.\n");
#endif

	UpdateFATs( curfcb->drive -1);
				/* Update the FATs on the disk with the      */
				/*clusters used by the fie being closed.     */
	SetDMA( save_DMA );

	SelDisk( cur_disk );
	open_fcbs [file] = NULL; /* free file */

	}/*FileClose*/

/*page*/
/*---------------------------------------------------------------------------*/

int AllocCluster( pres_cluster, drive )
  unsigned   int	pres_cluster;	/* Present cluster to link from.*/
  int	drive;			/* 0=A, B=1, C=2, ...			*/
{
/* Given the present cluster, find another cluster that is free and link it
to the present cluster in all FATs on the disk.
   Two algorithms present themselves.
1. One is to look alternately forward and back in relation to the present
cluster. This is what CP/M does, so that the next cluster is as close to the
present cluster as possible.
2. The other is to only look forward and wrap around when the end of the FAT
is reached. Since clusters are initially allocated in groups ( i.e. several
clusters in order allocated to the same file, hence a 'group' of clusters),
always looking forward may increas the chance of again allocating clusters
in a group for a given file.

  Initially try method 2.

   If pres_cluster == 0, then find the first available cluster.
So look for the first free cluster starting at the first cluster, = cluster #2.

If a free cluster cannot be found, return a FAIL (=0xffff) to indicate failure.

*/

unsigned int	last_cluster, new_cluster;
int		curFAT;

#ifdef debugP
	printf("p....AllocCluster       entering       pres_cluster: %x hex\n",
						     pres_cluster );
#endif

	curFAT = addr_FAT [drive];
	last_cluster = frgnDirInfo [drive]->lastCluster;

	if ( pres_cluster == 0 ) {
		if ((new_cluster = Find0Cluster( 2, last_cluster, drive)) 
		== FAIL)
			return (FAIL);

#ifdef debug
		printf("  pres_cluster = 0, so first cluster in file.\n");
		printf("  Fat BEFORE allocation\n");
		Show_128byte_buffer (curFAT
			+((new_cluster+new_cluster/2)/128)*128);
#endif

		/* Mark new end of alloc cluster list.		*/
		if ((new_cluster % 2) == 0)		/* if even */
		    *(curFAT + new_cluster + new_cluster/2 ) |= 0xfff;
		else
		    *(curFAT + new_cluster + new_cluster/2) |= 0xfff0;

#ifdef debug
		printf("  Fat AFTER allocation\n");
		Show_128byte_buffer (curFAT
			+((new_cluster+new_cluster/2)/128)*128);
#endif
		return (new_cluster);
		}
	else {
		if ((new_cluster = 
			Find0Cluster (pres_cluster, last_cluster, drive))
				== FAIL)
			if ((new_cluster 
				= Find0Cluster (2, pres_cluster, drive))
					== FAIL)
				return (FAIL);
#ifdef debug
		printf("  pres_cluster non-zero, so not first cluster in file.\n");
		printf("  Fat BEFORE allocation\n");
		printf("  New cluster:\n");
		Show_128byte_buffer(curFAT
			+((new_cluster + new_cluster/2)/128)*128);
#endif
		/* Mark new end of alloc cluster list.		*/
		if ((new_cluster % 2) == 0)		/* if even */
			*(curFAT + new_cluster + new_cluster/2 ) |= 0xfff;
		else
			*(curFAT + new_cluster + new_cluster/2) |= 0xfff0;

		/* Update old end of alloc cluster list.	*/
		if ( ( pres_cluster % 2) == 0 )		/* if even */
			*(curFAT + pres_cluster + pres_cluster/2)
						&= (new_cluster + 0xf000);
		else
		    	*(curFAT + pres_cluster + pres_cluster/2)
					&= ((new_cluster << 4) + 0x000f);

#ifdef debug
		printf("  Fat AFTER allocation\n");
		printf("  New cluster:\n");
		Show_128byte_buffer(curFAT
		+((new_cluster + new_cluster/2)/128)*128);
#endif
		return( new_cluster );
		}/*else*/

	}/*AllocCluster*/

/*---------------------------------------------------------------------------*/

int
Find0Cluster( start_cluster, last_cluster, drive )
  unsigned   int	start_cluster, last_cluster;
  int	drive;
{
  unsigned   int	next_cluster, cur_cluster;
#ifdef debug
	printf("p....Find0Cluster");
#endif

    for( cur_cluster=start_cluster; cur_cluster<last_cluster; ++cur_cluster)
    {
	next_cluster = *( addr_FAT[drive] + cur_cluster + cur_cluster/2);
	if( (cur_cluster % 2) == 0)		/* if even */
	    next_cluster &= 0x0fff;
	else
	    next_cluster >>= 4;
	if ( next_cluster == 0 )	/* then non-allocated cluster found. */
	{
#ifdef debug
	printf("      cluster %x hex is free.\n", cur_cluster);
#endif
	    return( cur_cluster );
	}

    }/*for*/

    return( FAIL );

}/*Find0Cluster*/

/*---------------------------------------------------------------------------*/
/*page*/

int
DeAllocCluster( start_cluster, drive )

  unsigned int	start_cluster;/* Starting cluster of list to delete from FAT.*/
  CHAR		drive;			/* 0=A, B=1, C=2, ...		*/

/* Deallocate ( free ) all clusters starting with the start_cluster to the
	end of the linked list, i.e. 0xfff is found in the FAT.
  Return FAIL if start_cluster is not allocated.

	Get what start_cluster points to, and call it next_cluster.
	Put a 0xfff into where start_cluster points.
	Let start_cluster = next_cluster
	If start_cluster = 0xfff return
	Else go to step one.	
*/
{
  unsigned int	next_cluster;

#ifdef debugP
	printf("p....DeAllocCluster     enter\n");
	printf("      start_cluster: %x hex\n", start_cluster);
#endif

    if ( start_cluster == 0 )
	return FAIL;

    next_cluster = 0;
    while ( next_cluster != 0xfff )
    {
	next_cluster = *( addr_FAT[drive] + start_cluster + start_cluster/2);

    /* Extract the next_cluster and deallocate ( free ) the cluster by       */
    /*setting the cluster to zero, but retaining the byte of the neighboring */
    /*cluster.								     */

	if( (start_cluster % 2) == 0)		/* if even */
	{
	    next_cluster &= 0x0fff;
	    *( addr_FAT[drive] + start_cluster + start_cluster/2) &= 0xf000;
	}
	else					/* else odd */
	{
	    *( addr_FAT[drive] + start_cluster + start_cluster/2) &= 0x000f;
	    next_cluster >>= 4;
	}

#ifdef debug
	printf("  start_cluster: %x hex     next_cluster: %x hex\n",
		start_cluster,		next_cluster);
#endif

	if ( next_cluster == 0 )	/* if = 0, then bad cluster list. */
	{
	    printf( "  Please check MSDOS partition for unclaimed allocation");
	    printf(" clusters.\n");
	    return FAIL;
	}
	start_cluster = next_cluster;

    }/*while*/

    return 0;	/* All is well.	*/

}/*DeAllocCluster*/

/*---------------------------------------------------------------------------*/

UpdateFATs( drive )
  int	drive;		/* Drive to get FAT from. A = 0, B = 1, C = 2, ... */
{
/*  ASSUMES THAT THE PASSED DRIVE IS THE CURRENTLY LOGGED IN DRIVE !!! */

  int	sizeFAT, save_DMA, track, sector;
  int	offset;
  CHAR	numFATs, j, i;

#ifdef debug
	printf("p....UpdateFATs\n");
#endif

/* Compute number of sectors per FAT.	*/

    sizeFAT = frgn_BPB [drive]->SectPerFAT * frgn_BPB [drive]->BytesInSect;

#ifdef debug
    printf("  addr_FAT[%x]: %x hex     sizeFAT: %x hex  %d decimal\n",
	       drive, addr_FAT[drive], sizeFAT, sizeFAT );
#endif

/* GetDMA address and save. */
    save_DMA = GetDMA();

    numFATs = frgn_BPB [drive]->num_FATs;

	for ( j=0; j<numFATs; ++j) {	/* For each FAT on the disk.	*/
		offset = 0;
		track = 0;
		sector = frgn_BPB [drive]->reserved_sect
			+ (frgn_BPB [drive]->SectPerFAT * j);

		for ( i=0; i < frgn_BPB [drive]->SectPerFAT; ++i) {
			/* Read in all sectors of the first FAT on the disk.	*/
			SetDMA( addr_FAT [drive] + offset );
			if (frgnWrite (drive, addr_FAT [drive] + offset, track,
				sector, FORCEwrite)) {
				printf("Fatal error in writing the FAT's onto the disk.\n");
		 		printf("Please erase the last MSDOS file copied as it probably ");
				printf("is not correct on the disk.\n");
				zabort();
				}
		offset += frgn_BPB [drive]->BytesInSector;
#ifdef debug
		printf("         bios WRITE in UpdateFATs at:\n");
		printf("    track: %x    sector: %x\n",
			track, sector);
#endif
		++sector;
		track += sector / frgn_BPB [drive]->SectPerTrack;
		sector = sector % frgn_BPB [drive]->SectPerTrack;

		}/*for #sects/FAT*/

	}/*for number of FATs on disk*/

	/* Reset DMA address to value saved. */
	SetDMA( save_DMA);

}/*UpdateFATs*/

/*---------------------------------------------------------------------------*/
frgnWrite (drive, dma, track, sector, writemode)
int	drive;
CHAR	*dma;
int	track, sector, writemode;
{
int	i, xlate_sector, convert;
int	t, s;

	convert  = frgn_BPB [drive]->BytesInSector / 128;
	track *= frgn_BPB [drive]->SectPerTrack * convert;
	sector *= convert;
	t = (track + sector) / 128;
	s = (track + sector) % 128;
	for (i = 0; i < convert; ++i, dma += 128) {
		SetDMA (dma);
		settrk (t);
		xlate_sector = sectran (s + i, 
			frgn_dph [drive]->translate_table);
		setsect (xlate_sector);
		if (dmsbios (BIOSWRITE, 0, writemode, 0, 0) == 1) return TRUE;
		}
	return FALSE;
	}
/*---------------------------------------------------------------------------*/
WriteDirSector (drive)
int	drive;
{
int	i, xlate_sector, convert, dma;
int	track, sector, t, s;

	convert  = frgn_BPB [drive]->BytesInSector / 128;
	track = frgnDirInfo [drive]->curTrack * frgn_BPB [drive]->SectPerTrack * convert;
	sector = frgnDirInfo [drive]->curSector * convert;
	t = (track + sector) / 128;
	s = (track + sector) % 128;
	for (i = 0, dma = &frgnDirBuffer; i < convert; ++i, dma += 128) {
		SetDMA (dma);
		settrk (t);
		xlate_sector 
			= sectran (s + i, frgn_dph [drive]->translate_table);
		setsect (xlate_sector);
		if (dmsbios (BIOSWRITE, 0, FORCEwrite, 0, 0) == 1) return TRUE;
		}
	return FALSE;
	}
/*---------------------------------------------------------------------------*/
/*page*/

Show_128lbyte_buffer(buff_ptr)
  CHAR	*buff_ptr;
{
  CHAR	*buff_begin;
  int	i, j, prnt_char;

    printf("%04x = hex address.\n", buff_ptr);
    buff_begin = buff_ptr;
    while( buff_ptr < buff_begin + WRbuffSIZE )
    {
	for ( i=0; i<16; ++i)
	{
	    if ( (i % 4) == 0)
		putchar(SPACE);
	    printf("%02x", *buff_ptr++);
	}/*for*/

	printf("       ");
	buff_ptr -= 16;		/* Output same in ascii.	*/

	for ( i=0; i<16; ++i)
	{
	    if ( (i % 8) == 0)
		putchar(SPACE);
	    if ( (*buff_ptr < DEL) && (*buff_ptr >= SPACE) )
		printf("%c", *buff_ptr);
	    else
		printf("_");
	    ++buff_ptr;
	}/*for*/

	printf("\n");
    }/*while*/

}/*Show_128byte_buffer*/
/*---------------------------------------------------------------------------*/

/*++++++++++++++++++++++++++++++++ END ++++++++++++++++++++++++++++++++++++++*/



