Category : C Source Code
Archive   : PDTAR.ZIP
Filename : DOSIO.C

 
Output of file : DOSIO.C contained in archive : PDTAR.ZIP
/*
* Dos direct-disk I/O routines for PDTAR
* By E. Roskos 2/88
* For Minix-compatible multivolume tar implementation under DOS
*
* These routines are based on my Minix "build" I/O code, although
* changed a lot...
*/

#ifdef MSDOS

#include
#include
#include

extern int physdrv;
extern int devsize;
extern int ftty;
static long curblk = 0;
static int inited = 0;

/*
* Local I/O buffers. We do the actual disk I/O to one of these two.
* The reason is that we select which one we'll use, and set iobuf to
* point to it, in order to get a block of memory that doesn't cross
* a 64K boundary -- because the DMA controller can't do I/O across
* a 64K boundary.
*/
static char buf1[512], buf2[512];
static char *iobuf;

/*
* DMAoverrun checks whether buff1 crosses a 64K boundary.
*/
static int
DMAoverrun(buff1)
char *buff1;
{
int i;

i = (int)buff1;
return(i > i + 512);
}

/*
* absio does absolute disk I/O, using the ROM BIOS
* It performs BIOS operation "fn", on "drive", specifying
* block number "blocknr" and buffer "buff" (which must
* be in the single (small-model) data segment).
* Note that the block numbering scheme corresponds to the
* Minix, PC/IX, and DOS 2.x block numbering, not the DOS
* 3.x block numbering.
*/
static int
absio(fn, drive, blocknr, buff)
int fn;
int drive;
long blocknr;
char *buff;
{
union REGS iregs;
union REGS oregs;
int track;

iregs.h.ah = fn;
iregs.h.dl = drive;
track = blocknr / 9;
iregs.h.dh = track & 1;
iregs.h.ch = track >> 1;
iregs.h.cl = (blocknr % 9) + 1;
iregs.h.al = 1;
iregs.x.bx = (int)buff;

int86(0x13, &iregs, &oregs);

if (oregs.x.cflag)
{
#ifdef DEBUGIO
fprintf(stderr, "absio: error %sing drv %c block %d address %x: bios code %x\n",
fn==2? "read" : "writ", 'A'+drive, blocknr, buff, oregs.h.ah&0xff);
#endif /* DEBUGIO */
return(oregs.h.ah&0xff);
}
else
{
return(0);
}
}

/*
* initdiskio initializes the floppy disk subsystem and selects
* a local buffer for us to use, if this is the first time it is
* called. Otherwise, it does nothing.
*/
static void
initdskio()
{
if (!inited)
{
absio(0, 0, 0, 0);
if (DMAoverrun(buf1))
iobuf = buf2;
else
iobuf = buf1;
inited++;
}
}

/*
* absread performs an absolute disk read of "drive"'s block
* "blocknr", reading into the buffer at "buff".
*/
static int
absread(drive, blocknr, buff)
int drive;
long blocknr;
char *buff;
{
int err;

initdskio();
err = absio(2, drive, blocknr, iobuf);
if (!err)
memcpy(buff, iobuf, 512);
return(err);
}

/*
* abswrite performs an absolute disk write of "drive"'s block
* "blocknr", reading into the buffer at "buff".
*/
static int
abswrite(drive, blocknr, buff)
int drive;
long blocknr;
char *buff;
{
int err;

initdskio();
memcpy(iobuf, buff, 512);
return(absio(3, drive, blocknr, iobuf));
}

/*
* physrw reads or writes the data at "buf" for length "len", which
* must be a multiple of 512 bytes; it reads if fread is 1, or writes
* if fread is 0. The data is read/written on the next consecutive
* block of the floppy disk; if the end of the disk has been reached
* (as determined by the disk size block count in the global variable
* devsize) it asks the user to change disks before it performs the I/O,
* then performs the I/O to block 0 of the new disk.
*/
static int
physrw(buf, len, fread)
char *buf;
int len;
int fread;
{
int err;
int errct = 0;
int nbytes;
static void diskerr();

nbytes = len; /* save for return value */

/* be sure size of xfer is a multiple of DOS physical block size */
if (len & 0x1ff)
{
fprintf(stderr, "tar: fatal error: phys disk I/O must be ");
fprintf(stderr, "multiple of 512 bytes\n");
exit(1);
}

/* convert byte count to DOS block count */
len >>= 9;

/* now read or write a block at a time into the buffer */
while (len > 0)
{
/* check for time to change disks */
if (curblk >= devsize)
{
uprintf(ftty, "\ntar: Change disks and press [Enter]: ");
while (ugetc(ftty)!='\n') ;
curblk = 0;
}

/* read or write the next block */
if (fread)
err = absread(physdrv, curblk, buf);
else
err = abswrite(physdrv, curblk, buf);

/* check for an error */
if (err)
{
diskerr(fread? "reading" : "writing",
physdrv, curblk, err);
errct++;
}
/* increment block number & buf addr, decrement count */
curblk++;
buf += 512;
len--;
}
if (errct)
return(-1);
else
return(nbytes);
}

/*
* physwrite is the "write" version of physrw, and is what is called
* from outside this package. It writes the data at "buf" for
* length "len", which must be a multiple of 512 bytes, as described
* above under "physrw".
*/
int
physwrite(buf, len)
char *buf;
int len;
{
return(physrw(buf, len, 0));
}

/*
* see comments for physwrite
*/
int
physread(buf, len)
char *buf;
int len;
{
return(physrw(buf, len, 1));
}


/*
* This routine prints an error message for disk I/O: the operation
* ("reading", "writing") is in s, the drive number in "drive",
* the sector number in "sectnum", and the BIOS AH return code
* is in "err".
*/
static void
diskerr(s,drive,sectnum,err)
int sectnum, err,drive;
char *s;
{
extern char *derrtab[];
char *mp;
fprintf(stderr, "Error %s drive %c, sector: %d, code: %d = '",
s, drive+'A',sectnum, err);
switch (err)
{
case 0:
mp = "No error";
break;
case 1:
mp = "Bad command passed to BIOS";
break;
case 2:
mp = "Address mark not found";
break;
case 3:
mp = "Disk is write protected";
break;
case 4:
mp = "Sector not found";
break;
case 8:
mp = "DMA overrun";
break;
case 9:
mp = "DMA crosses 64K boundary (internal error)";
break;
case 0x10:
mp = "Bad CRC on disk read";
break;
case 0x20:
mp = "Disk controller has failed";
break;
case 0x40:
mp = "Seek failed";
break;
case 0x80:
mp = "No response from controller";
break;
default:
mp = "Unknown error";
break;
}
fprintf(stderr,"%s'\n", mp);
}

#endif /* MSDOS */


  3 Responses to “Category : C Source Code
Archive   : PDTAR.ZIP
Filename : DOSIO.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/