1File: DSKUTIL.C                                                           Page       1
     1    
     2   /****************************************************************
     3   *								*
     4   *		CP/M-68K BDOS Disk Utilities Module		*
     5   *								*
     6   *	This module contains the miscellaneous utilities  	*
     7   *	for manipulating the disk in CP/M-68K.  Included are:	*
     8   *								*
     9   *		dirscan()   - general purpose dir scanning	*
    10   *		setaloc()   - set bit in allocation vector	*
    11   *		clraloc()   - clear bit in allocation vector	*
    12   *		getaloc()   - get free allocation block		*
    13   *		dchksum()   - directory checksum calculator	*
    14   *		dir_rd()    - read directory sector		*
    15   *		dir_wr()    - write directory sector		*
    16   *		rdwrt()	    - read/write disk sector		*
    17   *								*
    18   *								*
    19   *	Configured for Alcyon C on the VAX			*
    20   *								*
    21   ****************************************************************/
    22    
    23   #include "bdosinc.h"		/* Standard I/O declarations */
    24    
    25   #include "bdosdef.h"		/* Type and structure declarations for BDOS */
    26    
    27   #include "pktio.h"		/* Packet I/O definitions */
    28    
    29    
    30   /* declare external functions and variables */
    31   EXTERN UWORD	do_phio();	/* external physical disk I/O routine */
    32   EXTERN UWORD	error();	/* external error routine	*/
    33    
    34   EXTERN UWORD	log_dsk;	/* logged-on disk vector */
    35   EXTERN UWORD	ro_dsk;		/* read-only disk vector */
    36   EXTERN UWORD	crit_dsk;	/* critical disk vector */
    37    
    38    
    39   /**********************
    40   * read/write routine  *
    41   **********************/
    42    
    43   UWORD rdwrt(secnum, dma, parm)
    44   /* General disk sector read/write routine */
    45   /* It simply sets up a I/O packet and sends it to do_phio */
    46    
    47   LONG	secnum;			/* logical sector number to read/write */
    48   UBYTE	*dma;			/* dma address				*/
    49   REG WORD parm;			/* 0 for read, write parm + 1 for write */
    50    
    51   {
    52       struct iopb	rwpkt;
    53       BSETUP
    54    
    55       rwpkt.devnum = GBL.curdsk;		/* disk to read/write	*/
    56       if (parm)
    57       {
    58   	rwpkt.iofcn = (BYTE)write; /* if parm non-zero, we're doing a write */
    59   	rwpkt.ioflags = (BYTE)(parm-1);	/* pass write parm	*/
1File: DSKUTIL.C                                                           Page       2
    60           if ( ro_dsk & (1 << (rwpkt.devnum)) ) error(4);
    61   				/* don't write on read-only disk	*/
    62       }
    63       else
    64       {
    65   	rwpkt.iofcn = (BYTE)read;
    66   	rwpkt.ioflags = (BYTE)0;
    67       }
    68       rwpkt.devadr = secnum;			/* sector number	*/
    69       rwpkt.xferadr = dma;			/* dma address		*/
    70    
    71   /*		parameters that are currently not used by do_phio
    72       rwpkt.devtype = disk;
    73       rwpkt.xferlen = 1;
    74   				*/
    75       rwpkt.infop = GBL.dphp;			/* pass ptr to dph	*/
    76       while ( do_phio(&rwpkt) )
    77   	if ( error( parm ? 1 : 0 ) ) break;
    78       return(0);	
    79   }
    80    
    81    
    82   /***************************
    83   *  directory read routine  *
    84   ***************************/
    85    
    86   UWORD dir_rd(secnum)
    87    
    88   WORD secnum;
    89   {
    90       BSETUP
    91    
    92       return( rdwrt((LONG)secnum, GBL.dirbufp, 0) );
    93   }
    94    
    95    
    96   /****************************
    97   *  directory write routine  *
    98   ****************************/
    99    
   100   UWORD dir_wr(secnum)
   101    
   102   REG WORD secnum;
   103   {
   104       REG UWORD rtn;
   105       BSETUP
   106    
   107       rtn = rdwrt( (LONG)secnum, GBL.dirbufp, 2);
   108       if ( secnum < (GBL.parmp)->cks )
   109   	*((GBL.dphp)->csv + secnum) = dchksum();
   110       return(rtn);
   111   }
   112    
   113    
   114   /*******************************
   115   *  directory checksum routine  *
   116   *******************************/
   117    
   118   UBYTE dchksum()
1File: DSKUTIL.C                                                           Page       3
   119   /* Compute checksum over one directory sector */
   120   /* Note that this implementation is dependant on the representation */
   121   /*   of a LONG and is therefore not very portable.  But it's fast   */
   122   {
   123       REG LONG	*p;		/* local temp variables */
   124       REG LONG	lsum;
   125       REG WORD	i;
   126    
   127       BSETUP
   128    
   129       p = GBL.dirbufp;		/* point to directory buffer */
   130       lsum = 0;
   131       i = SECLEN / (sizeof lsum);
   132       do
   133       {
   134   	lsum += *p++;		/* add next 4 bytes of directory */
   135   	i -= 1;
   136       } while (i);
   137       lsum += (lsum >> 16);
   138       lsum += (lsum >> 8);
   139       return( (UBYTE)(lsum & 0xff) );
   140   }
   141    
   142    
   143   /************************
   144   *  dirscan entry point	*
   145   ************************/
   146    
   147   UWORD dirscan(funcp, fcbp, parms)
   148    
   149   BOOLEAN (*funcp)();		/* funcp is a pointer to a Boolean function */
   150   REG struct fcb *fcbp;		/* fcbp is a pointer to a fcb */
   151   REG UWORD parms;		/* parms is 16 bit set of bit parameters */
   152    
   153   /* Parms & 1  = 0 to start at beginning of dir, 1 to continue from last */
   154   /* Parms & 2  = 0 to stop when *funcp is true, 1 to go until end	*/
   155   /* Parms & 4  = 0 to check the dir checksum, 1 to store new checksum	*/
   156   /* Parms & 8  = 0 to stop at hiwater, 1 to go until end of directory	*/
   157    
   158   #define continue 1
   159   #define full	 2
   160   #define initckv  4
   161   #define pasthw   8
   162    
   163   {
   164       REG UWORD 	i;		/* loop counter		*/
   165       REG struct dpb *dparmp;	/* pointer to disk parm block */
   166       REG UWORD 	dirsec;		/* sector number we're working on */
   167       REG UWORD  	rtn;		/* return value		*/
   168       REG UBYTE	*p;		/* scratch pointer	*/
   169       REG UWORD	bitvec;		/* disk nmbr represented as a vector */
   170    
   171       BSETUP
   172    
   173       dparmp = GBL.parmp;			/* init ptr to dpb */
   174       rtn  = 255;				/* assume it doesn't work */
   175    
   176       i = ( (parms & continue) ? GBL.srchpos + 1 : 0 );
   177       while ( (parms & pasthw) || (i <= ((GBL.dphp)->hiwater + 1)) )
1File: DSKUTIL.C                                                           Page       4
   178       {				/* main directory scanning loop		*/
   179   	if ( i > dparmp->drm ) break;
   180   	if ( ! (i & 3) )
   181   	{			/* inside loop happens when we need to
   182   				   read another directory sector	*/
   183   retry:	    dirsec = i >> 2;
   184   	    dir_rd(dirsec);	/* read the directory sector	*/
   185   	    if ( dirsec < (dparmp->cks) )  /* checksumming on this sector? */
   186   	    {
   187   		p = ((GBL.dphp)->csv) + dirsec;
   188   					/* point to checksum vector byte  */
   189   		if (parms & initckv) *p = dchksum();
   190   		else if (*p != dchksum())
   191   		{			/* checksum error! */
   192   		    (GBL.dphp)->hiwater = dparmp->drm;  /* reset hi water */
   193   		    bitvec = 1 << (GBL.curdsk);
   194   		    if (crit_dsk & bitvec)	/* if disk in critical mode */
   195   			ro_dsk |= bitvec;	/* then set it to r/o	*/
   196   		    else
   197   		    {
   198   			log_dsk &= ~bitvec;	/* else log it off  */
   199   			seldsk(GBL.curdsk);	/* and re-select it */
   200   			goto retry;		/* and re-do current op */
   201   		    }
   202   		}
   203   	    }
   204   	}
   205    
   206   	GBL.srchpos = i;
   207   	if ( (*funcp)(fcbp, (GBL.dirbufp) + (i&3), i) )
   208   			/* call function with parms of (1) fcb ptr,
   209   			   (2) pointer to directory entry, and
   210   		   	   (3) directory index		  	*/
   211   	{
   212   	    if (parms & full) rtn = 0;	/* found a match, but keep going */
   213   	    else return(i & 3);		/* return directory code	*/
   214   	}
   215   	i += 1;
   216       }
   217       return(rtn);
   218   }
   219    
   220    
   221   /****************************************
   222   *  Routines to manage allocation vector *
   223   *	setaloc()			*
   224   *	clraloc()			*
   225   *	getaloc()			*
   226   ****************************************/
   227    
   228   setaloc(bitnum)
   229   /*  Set bit in allocation vector	*/
   230   REG UWORD	bitnum;
   231   {
   232       BSETUP
   233    
   234       if (bitnum >= 0 && bitnum <= (GBL.parmp)->dsm)
   235           *((GBL.dphp)->alv + (bitnum>>3)) |= 0x80 >> (bitnum & 7);
   236   }
1File: DSKUTIL.C                                                           Page       5
   237    
   238    
   239   clraloc(bitnum)
   240   /* Clear bit in allocation vector	*/
   241   REG UWORD	bitnum;
   242   {
   243       BSETUP
   244    
   245       if (bitnum > 0 && bitnum <= (GBL.parmp)->dsm)
   246   	*((GBL.dphp)->alv + (bitnum>>3)) &= ~(0x80 >> (bitnum & 7));
   247   }
   248    
   249    
   250   UWORD	chkaloc(i)
   251   /* Check bit i in allocation vector			*/
   252   /* Return non-zero if block free, else return zero	*/
   253   REG UWORD i;
   254   {
   255       BSETUP
   256    
   257       return( ~(*( (GBL.dphp)->alv + (i >> 3) )) & (0x80 >> (i&7)) );
   258   }
   259    
   260    
   261   UWORD	getaloc(leftblk)
   262   /* Get a free block in the file system and set the bit in allocation vector */
   263   /* It is passed the block number of the last block allocated to the file    */
   264   /* It tries to allocate the block closest to the block that was passed	    */
   265   REG UWORD leftblk;
   266   {
   267       REG UWORD	blk;		/* block number to allocate	*/
   268       REG UWORD	rtblk;		/* high block number to try	*/
   269       REG UWORD	diskmax;	/* # bits in alv - 1		*/
   270    
   271       BSETUP
   272       LOCK			/* need to lock the file system while messing
   273   				   with the allocation vector		*/
   274    
   275       diskmax = (GBL.parmp)->dsm;
   276   				/* get disk max field from dpb		*/
   277       rtblk = leftblk;
   278       blk = ~0;			/* -1 returned if no free block found	*/
   279       while (leftblk || rtblk < diskmax)
   280       {
   281   	if (leftblk)
   282   	    if (chkaloc(--leftblk))
   283   	    {
   284   		blk = leftblk;
   285   		break;
   286   	    }
   287   	if (rtblk < diskmax)
   288   	    if (chkaloc(++rtblk))
   289   	    {
   290   		blk = rtblk;
   291   		break;
   292   	    }
   293       }
   294       if (blk != ~0) setaloc(blk);
   295       UNLOCK
1File: DSKUTIL.C                                                           Page       6
   296       return(blk);
   297   }
