/* **************************************************************
 *								*
 *	      REMOVE A FILE FROM THE CONTROL AREA		*
 *		 last modified 02/10/84 dsb			*
 *								*
 ************************************************************** */

#include "libc.h"
#include "syslib.h"
#include "hardio.h"

/* #define DBUG 1 */

/* ***************** REVISION HISTORY OF THIS MODULE ***************   

    01/14/84	Works
    01/18/84	Turned module into an overlay.	Only the user-interface
		parts of the Erase function were kept here.  The parts
		that actually do the work must be accessible to the
		Add/Replace function in case it has to Replace, so those
		functions have been moved into the Utilities module.
    01/24/84	Fixed references to yorn as it now returns boolean
    01/27/84	Minor changes to name-getting procedure
    02/10/84	Made some loop counters register-type
*/
/*page*/

ovmain()	/* ERASE function */
{
    struct SDentry *sd_ent;
    struct OSTentry *ost_ent;
    char name[8], *cp;		    /* name of file to erase */
    int msgs[128];		    /* buffer for cross-reference */
    register int i,j,k;

    printf("\nThis is the ERASE option.\n\nWARNING!!! ERASING IS A ");
    printf("DANGEROUS PROCESS.\nIF INTERRUPTED IT COULD CORRUPT YOUR ");
    printf("ENTIRE\nCONTROL AREA DIRECTORY.\n\n");
    if(!yorn("Do you want to continue ") ||
       !yorn("Have you made a backup of your Control Area (Partition 0)"))
	return();

    do
    {
	printf("\nEnter the name of the file to be erased");
	printf("\n(or press ESC to go back to main menu) --> ");
	i = get_name(name);
	if(error)
	    i = 0;
	if(!i)
	    printf("\07Invalid input!");
	else if (name[0] == ESC)
	    return();
    } while (!i);

    if((sd_ent = find_sd(name)) == NULL)
    {
	printf("That file is not in System Directory.");
	delay(3000);
	return();
    }
    ost_ent = find_os(name);

    printf("\nYou have asked to ERASE this file:");
    dump_ent(sd_ent,ost_ent,(ost_ent != NULL));

    if(i=xref_os(name,msgs))
    { 
	printf("\n\nThis file is NEEDED by these OS's:   ");
	for(j=0; j<i; ++j)
	{
	    cp =(((struct OSTentry *)(ostable.buffer))+msgs[j])->load_list;
	    print8(cp);
	    printf("\n\t\t\t\t     ");
	}
    }

    if(i=xref_pt(name,msgs))
    {	
	printf("\n\nThis file is NEEDED to boot these products:  ");
	for(j=0; j<i; ++j)
	    printf("PRODUCT #%d  (%s)\n\t\t\t\t\t     ",
		    msgs[j],product[msgs[j]]);
    }

    printf("\n");
    if(!yorn("ARE YOU SURE YOU WANT TO ERASE IT"))
	return();
    printf("\nRemoving file ");
    print8(name);
    printf(" from System Directory.\n\nThe ERASE procedure will take ");
    printf("a few seconds.\nWARNING!!! DO NOT TOUCH THE COMPUTER UNTIL ");
    printf("\nTHE ERASE IS COMPLETED.\n\nDO NOT INTERRUPT THIS ERASE!!!");
    printf("\n\nErasing......");
    kill(sd_ent);		    /* physically remove it */
    sd_delete(sd_ent);		    /* remove its sd entry */
    os_delete(ost_ent); 	    /* remove its ost entry */
    putfile(sysdir);
    putfile(ostable);
    printf("\nErase is complete.");
    return();
} /* erase */


/*page*/
kill(sd_ent)			     /* perform physical removal */
struct SDentry *sd_ent;
{
    char tranbuf[512];
    struct SDentry *sdp;
    struct OSTentry *ostp;
    int max_sd;
    int trk,sec;
    int secs_to_move,secs_this_xfer;
    int srce_trk, srce_sec, dest_trk, dest_sec;
#ifdef DBUG
    char *clock = 0x40;
#endif

    max_sd = sd_entries()-1;
    if(((struct SDentry *)sysdir.buffer)+max_sd == sd_ent)  /* last one? */
	return();				/* if so don't move data */

    dest_trk = sd_ent->track;		       /* where to move down to */
    dest_sec = sd_ent->sector;
    srce_trk = (sd_ent+1)->track;	       /* where to start moving from */
    srce_sec = (sd_ent+1)->sector;	

    max_sd=sd_entries()-1;
    sdp = ((struct SDentry *)sysdir.buffer)+max_sd;  /* last entry */
    trk = sdp->track - srce_trk;		    /* length in tracks */
    sec = sdp->sector + sdp->length - srce_sec;     /* plus sectors */
    secs_to_move = SECTS_PER_TRACK*trk + sec;

#ifdef DBUG
    printf("%d sectors to move",secs_to_move);
    printf("\nStarting move at %02d:%02d:%02d'%02d",*(clock+3),*(clock+2),
		*(clock+1),*clock);
#endif

    while(secs_to_move > 0)
    {
	if(secs_to_move >= 4)
	    secs_this_xfer = 4;
	else
	    secs_this_xfer = secs_to_move;

	hd_xfer(READ,srce_trk,srce_sec,tranbuf,secs_this_xfer);
	hd_xfer(WRITE,dest_trk,dest_sec,tranbuf,secs_this_xfer);

	srce_sec += secs_this_xfer;
	dest_sec += secs_this_xfer;
	if(srce_sec > SECTS_PER_TRACK)
	{
	    srce_sec -= SECTS_PER_TRACK;
	    ++srce_trk;
	}
	if(dest_sec > SECTS_PER_TRACK)
	{
	    dest_sec -=SECTS_PER_TRACK;
	    ++dest_trk;
	}
	secs_to_move -= secs_this_xfer;
    } /* while there are sectors to be moved */
#ifdef DBUG
    printf("\nFinished move at %02d:%02d:%02d'%02d",*(clock+3),*(clock+2),
		*(clock+1),*clock);
#endif
    return();
} /* kill_sd (physically remove a file) */

/*page*/
sd_delete(sd_ent)		/* remove entry from System Directory */
struct SDentry *sd_ent;
{
    int ent_num,max;
    int i;

    ent_num = sd_ent - (struct SDentry *)sysdir.buffer;
    max = sd_entries()-1;
    if((ent_num < 0) || (ent_num > max))
    {
	printf("\n\07**BUG** bad SD entry # %d in sd_delete()",ent_num);
	return();
    }
    for(i=ent_num; i<max ; ++i,++sd_ent)
    {
	blockmv(sd_ent,sd_ent+1,sizeof(struct SDentry));  /* move next down */
	fix_loc(sd_ent);		      /* put right disk address in  */
    }
    clear(((struct SDentry *)sysdir.buffer)+max,sizeof(struct SDentry),0);
    return();
} /* sd_delete (remove entry in System Directory) */

os_delete(os_ent)		/* remove entry from OS Table  */
struct OSTentry *os_ent;
{
    int ent_num,max;

    if(os_ent == NULL)
	return();

    ent_num = os_ent - (struct OSTentry *)ostable.buffer;
    max = ost_entries()-1;
    if((ent_num < 0) || (ent_num > max))
    {
	printf("\n\07**BUG** bad OS entry # %d in os_delete()",ent_num);
	return();
    }
    blockmv(os_ent,os_ent+1,(max-ent_num) * sizeof(struct OSTentry));
    clear(((struct OSTentry *)ostable.buffer)+max,sizeof(struct OSTentry),0);
    return();
} /* os_delete (remove entry in OS Table) */

/*page*/
fix_loc(ent)		/* correct the track & sector address of an entry */
struct SDentry *ent;
{
    int trk,sec;

    trk = 3;		/* defaults: if this is the first entry, these */
    sec = 1;		/* are the right track and sector for it. */

    if(ent != (struct SDentry *)sysdir.buffer)
    {
	--ent;				 /* look at previous entry */
	trk = ent->track;		 /* calculate our starting address */
	sec = ent->sector + ent->length; /* as their starting address plus */
	while(sec > SECTS_PER_TRACK)	 /* length.  Make sure sector lies */
	{				 /* in range. */
	    sec -= SECTS_PER_TRACK;
	    ++trk;
	}
	++ent;				 /* restore pointer to current entry */
    }

    ent->track = trk;
    ent->sector = sec;
} /* fix_loc (adjust SD entry's disk address fields after a move) */

/*page*/
xref_pt(name,buf)     /* list product types that require a given file */
char name[];	      /* put the numbers of any that do into the buffer  */
int buf[];	      /* (which caller must assure is big enough).    */
{		      /* Return value is number of entries made. */
    struct PTentry *pt;
    char *cp;
    register int i,j,maxp;
    int ref = 0;

    maxp = pr_entries();
    pt = (struct PTentry *) prodtable.buffer;
    for(i=0; i < maxp; ++i,++pt)       /* outer loop - entry num, until end */
    { 
	cp = pt->bp2_name;
	for(j=0; j<3; ++j,cp+=8)       /* inner loop - role in boot process */
	    if(!strncmp(name,cp,8))    /* see if name matches something here */
	    {
		buf[ref++] = pt->type; /* if so, put product number in buf */
		break;		       /* and break to outer loop */
	    }
			       /* end of inner loop (index = field in entry) */
    }			       /* end of outer loop (index = entry number)  */
    return(ref);
} /* xref_pt */

xref_os(name,buf)     /* number the  OS's that require a given file */
char name[];
int buf[];
{
    struct OSTentry *os;
    int i,j,k,maxos;
    int ref = 0;
    os = (struct OSTentry *)ostable.buffer;
    maxos = ost_entries();
    for(i=0; i < maxos; ++i)	/* outer loop - os entry, until end of table */
	for(j=1; j<8; ++j)	/* inner loop - position in load list  */
	    if(!strncmp(name,&((os+i)->load_list[j][0]),8))
	    {
		buf[ref++] = i;
		break;
	    }
    return(ref);
} /* xref_os */

strncmp(name,&((os+i)->load_lis