/* This program reads/writes MS-DOS formatted disks, using the CPM bios routines. The data is converted to/from C (non-ascii) files. The code is written so that it can be compiled with Small-C, but uses K&R standard I/O whenever possible. Author: Bob Alverson 8717 Empire Ct. Cincinnati, OH 45231 513-729-1676 1.1 9 DEC 83 Add ability to read all four IBM formats 1.0 27 NOV 83 First working version. */ #include /* Define the disk bios calls */ #define SELDSK 9 /* Select disk drive */ #define SETTRK 10 /* Select track */ #define SETSEC 11 /* Select sector */ #define SETDMA 12 /* Set DMA address */ #define RDSEC 13 /* Read sector */ #define WRSEC 14 /* Write sector */ #define SECTRAN 16 /* Translate sector # */ #define CURDSK 25 /* bdos selected disk */ /* disk parameters */ #define ALLMAX 1024 /* maximum alloc table size */ #define DIRMAX 7*512 /* maximum directory size */ /* misc data */ #define DATSIZ 0x4000 /* size of data buffer */ /* global data */ char spttbl[4] = {32, 32, 36, 36}; /* sectors per track (logical) */ int spt; char alltbl[4] = {8, 4, 8, 4}; /* size of alloc table / 128 */ int allsiz; char dirtbl[4] = {28, 16, 28, 16}; /* size of directory / 128 */ int dirsiz; int blktbl[4] = {8, 4, 8, 4}; /* size of block / 128 */ int blksiz; int blklen; /* block size in bytes */ int secofs; char allmap[ALLMAX]; /* allocation map */ char dirbuf[DIRMAX]; /* directory data */ char datbuf[DATSIZ]; /* data transfer buffer */ char *datptr; int cpmdsk; /* cpm default disk */ char xfile[20]; /* filename to transfer */ int drive; /* drive of MSDOS disk */ int blk; /* MSDOS block number */ int xtra, blks; /* file length */ FILE *cfile; /* output file stream */ main() { fputs("\nRead MS-DOS disks, Version 1.1\nDec 9, 1983\n", stdout); do { fputs("Drive of MSDOS disk: ",stdout); fgets(xfile, 20, stdin); drive = toupper(*xfile) - 'A'; if (drive < 0 || drive >= 16) { fputs("\n\7Drive spec error!\n", stderr); drive = -1; /* flag bad drive */ } } /* do */ while (drive < 0); cpmdsk = bdos(CURDSK, 0); bios(SELDSK, drive, 0); /* select disk drive */ dettype(); readdsk(4, allsiz, allmap); /* read allocation map in */ readdsk(allsiz*2+4, dirsiz, dirbuf); /* read dir into memory */ bios(SELDSK, cpmdsk, 1); while (getnam()) { if (find()) { cfile = fopen(xfile, "w"); bios(SELDSK, drive, 1); datptr = datbuf; do { readblk(blk, datptr); if (blks) { /* complete sector */ --blks; datptr += blklen; } else { /* partial sector */ datptr += xtra; xtra = 0; } if (datptr > datbuf+DATSIZ-blklen) { bios(SELDSK, cpmdsk, 1); fwrite(datbuf, 1, datptr-datbuf, cfile); bios(SELDSK, drive, 1); datptr = datbuf; } /* if */ nxtblk(); } /* do */ while (blks || xtra); bios(SELDSK, cpmdsk, 1); fwrite(datbuf, 1, datptr-datbuf, cfile); fclose(cfile); } /* if */ else fputs("\nFile not found\n",stdout); } /* while */ } /* main */ dettype() /* determine disk type */ { char secbuf[128]; int dsktyp; readsec(0, 5, secbuf); dsktyp = (~ *secbuf) & 3; spt = spttbl[dsktyp]; allsiz = alltbl[dsktyp]; dirsiz = dirtbl[dsktyp]; blksiz = blktbl[dsktyp]; blklen = blksiz*128; secofs = ((allsiz - blksiz) << 1) + dirsiz + 4; } /* dettype */ getnam() { char *str, *ptr; fputs("\nEnter filename: ", stdout); str = fgets(xfile, 20, stdin); if (ptr=strchr(xfile, '\n')) *ptr = '\0'; return str; } /* read MSDOS block */ readblk(blkno, bufptr) int blkno; char *bufptr; { readdsk((blkno * blksiz) + secofs, blksiz, bufptr); } readdsk(dsksec, numsec, bufptr) int dsksec, numsec; char *bufptr; { do { readsec(dsksec/spt, (dsksec%spt)+1, bufptr); bufptr += 128; ++dsksec; } /* do */ while (--numsec); /* do all sectors requested */ } /* readdsk */ readsec(trk, sec, buf) int trk, sec; char *buf; { int retcode; bios(SETTRK, trk, 0); bios(SETSEC, sec, 0); bios(SETDMA, buf, 0); do { if (retcode = bios(RDSEC, 0, 0)) { char ask[3]; fputs("\nDisk read error\nIgnore or Retry? ", stdout); fgets(ask, 3, stdin); if (toupper(*ask) == 'I') retcode = 0; } /* if */ } /* do */ while (retcode); } /* readsec */ /* find next block (cluster) in chain */ nxtblk() { int nblk; int *blkptr; blkptr = allmap + ((blk*3) >> 1); nblk = *blkptr; if (blk & 1) nblk >>= 4; blk = nblk & 0x0fff; } /* find file name in directory buffer */ find() { char name[12]; char *dirptr; int *blkptr; fmtfn(xfile, name); dirptr = dirbuf; while (strncmp(dirptr, name, 11) && *dirptr) dirptr += 32; if (*dirptr) { blk = *(blkptr = dirptr+26); xtra = *(++blkptr); blks = (xtra/blklen) + *(++blkptr)*(512/blksiz); xtra %= blklen; return 1; } return 0; /* not found */ } /* format filename for directory search */ fmtfn(text, buf) char *text, *buf; { if (text[1] == ':') text += 2; /* skip over drive */ fmtbit(&text, buf, 8); fmtbit(&text, buf+8, 3); buf[11] = 0; } fmtbit(tptr, dest, cnt) int *tptr; /* should be char **text */ char *dest; int cnt; { char *text; text = *tptr; while (--cnt >= 0) { if (*text && *text != '.') *dest = toupper(*text++); /* no macro allowed */ else *dest = ' '; ++dest; } while (*text && *text != '.') ++text; if (*text == '.') ++text; /* scan past . */ *tptr = text; }