Category : Utilities for DOS and Windows Machines
Archive   : QDC10.ZIP
Filename : QDC.C

 
Output of file : QDC.C contained in archive : QDC10.ZIP
/*****************************************************************************

QDC 1.0 is (c) 1990 by Peter A. Dinda


QDC (Quick Disk Copy) 1.0 is designed to make it easy
to make disk copies of large (HD) diskettes on systems
that do not have multiple HD drives. QDC will save you
three to four disk swaps in coping a 1.44 MB disk on
a system with 550K of free conventional memory.


NOTE: QDC is a shareware product by Peter A. Dinda and
must be registered for continual use. Use of
QDC by any military organization is strictly
forbidden. Registration is $15. To register,
or to make any comments about QDC, mail:

Peter A. Dinda
404 N. Walbridge #7
Madison, WI 53714

Email: [email protected]
or [email protected]

BBS: Peter Dinda; MIC@MACC BBS; 608 263 6057

****************************************************************************/






#include
#include
#include
#include
#include

#define OWNER "*UNREGISTERED*"

#define MINARGS 2 /* Number of arguments QDC must see */
#define MAXARGS 2


#define READ 2 /* BIOS read sector command */
#define WRITE 3 /* BIOS write sector command */

#define DEFAULT 0 /* For getdfree() */
#define DRIVEA 0 /* Min legal drive number */

#define SECTSIZE 512 /* Limited to this by TC biosdisk() */
#define NUMBEROFTRIES 40 /* Max Number of reads to open shutter*/
#define MAXSECTS 9 /* Max sectors per BIOS call */

/* Potential Bug in the IBM BIOS! - It can read a maximum of only nine
sectors from side 1 of a floppy. It will read a whole track from
side 0. Therefore QDC bends over backwards to work.... MAXSECTS is
here as a result of this. If your BIOS does not have this bug, you
should be able to increase MAXSECTS and gain speed.
*/


#define IOFILE "!!QDC!!.IM" /* QDC's Image Filename */
#define WRITEBINARY "wb" /* fopen() op type */
#define READBINARY "rb" /* fopen() op type */




struct dinfo { /* What we find out about the */
int drivenum; /* source floppy using the */
int heads; /* Get_Disk_Info() function */
int tracks_per_disk;
int sects_per_track;
};

typedef struct dinfo DISKINFO;



/**************** Function Prototypes *****************************/

void help(void);
int Decode_Drive_Num(char *);
int Get_Disk_Info(DISKINFO *);
int Read_Disk_and_Write_Image(DISKINFO *, FILE *);
int Write_Disk(DISKINFO *, FILE*);

/******************************************************************/




main(int argc, char *argv[])
{
DISKINFO *disk; /* Everything about the source floppy */
struct dfree *dtable; /* For getdfree() */
FILE *io; /* Image file pointer */
char keypress;
float defree, need; /* For space comparisons */



if (argc < MINARGS) {
help();
exit(1);
}
else {

clrscr();
printf("QDC 1.0 (c)1990 Peter A. Dinda -> registered to: %s\n\n", OWNER);

if ((disk= (DISKINFO *) malloc(sizeof (DISKINFO))) !=NULL) {

if ((disk->drivenum = Decode_Drive_Num(argv[1])) < DRIVEA) {
puts("\aFAILURE: Invalid Drive!");
exit(1);
}
else {

printf("INITIAL: Insert your Source Disk into drive %c and press RETURN\n", toupper(*argv[1]));

while (getch() != '\r')
;

if (Get_Disk_Info(disk)) {
puts("\a\nFAILURE: Either there is no disk in the drive, a hardware error occured,");
puts( " or this is unrecognized disk format.");
exit(1);
}
else {

getdfree(DEFAULT, dtable);

defree =(float) (dtable->df_avail)*(dtable->df_sclus)*(dtable->df_bsec);
need = (float) (disk->heads)*(disk->sects_per_track)*(disk->tracks_per_disk) * (SECTSIZE);


if (defree < need ) {

puts("\a\nFAILURE: There is insufficient space on the default drive to create the Image");
puts(" File. You may want to delete some files from the default drive.");
printf(" %.0f bytes are needed.\n\n", need);
exit(1);
}
else {

io = fopen(IOFILE, WRITEBINARY);


if (!Read_Disk_and_Write_Image(disk, io)) {
fclose(io);
puts("\nSUCCESS: Creation of the Image File was successful. Insert your");
puts(" Destination Disk in the *same* drive and press RETURN.\n");

while (getch() != '\r')
;

io = fopen(IOFILE, READBINARY);

if (!Write_Disk(disk, io)) {

puts("\nSUCCESS: The QDC Copy Operation Was Successful!\n");
remove(IOFILE);
exit(0);

}
else {
puts("\a\nFAILURE: An error occurred while writing the duplicate disk. This is the");
puts(" result of either an open drive door, or an incompatible or damaged");
puts(" disk. If this was expected, please realize the duplicate may be");
puts(" unreliable!\n");
remove(IOFILE);
exit(1);
}
}
else {

puts("\a\nFAILURE: An error occurred while reading the disk. This is caused by either");
puts(" an open drive door or a damaged (or protected) disk.\n");
remove(IOFILE);
exit(1);
}
}
}
}
}
}
}




/**************************************************************************
HELP FUNCTION: Gives the User Help and Shows Beg Screen
**************************************************************************/
void help(void)
{
clrscr();

puts("Welcome to QDC 1.0");
puts("------------------\n");
puts("QDC stands for Quick Disk Copy. QDC is a replacement for DISKCOPY");
puts("that:");
puts(" 1. Requires only one disk swap per copy operation.");
puts(" 2. Works faster than DISKCOPY in *any* situation where you");
puts(" have only one drive for the type of disk you want to copy");
puts(" 3. Maintains its speed in *any* amount of memory.\n");
puts("If you find QDC to be useful, please send $10 or so to:\n");
puts(" Peter A. Dinda Re: QDC");
puts(" 404 N. Walbridge #7");
puts(" Madison, WI 53714\n");
puts("The command format for QDC is:\n");
puts(" QDC [drive letter]\n");
puts("where [drive letter] is the disk drive that contains the source disk.\n");
puts("Please see the accompanying documentation for more information.");
}






/*************************************************************************
Decode_Drive_Num takes the users drive letter argument and returns the
corresponding drive number to the caller.
*************************************************************************/

int Decode_Drive_Num(char *dlet)
{
if (isupper(*dlet))
return (*dlet - 'A');
else if (islower(*dlet))
return (*dlet - 'a');
else
return (-1);
}





/***************************************************************************
Open_Shutter() simply does multiple single sector read attempts on
track 0 to force the drive to open the disk shutter. If it has not
received a favorable read in NUMBEROFTRIES, it returns 1 as a failure
flag. Open_Shutter returns ptr pointing to the sector it read.
***************************************************************************/

int Open_Shutter(DISKINFO* info, void *ptr)
{
int count;

for (count=1 ; biosdisk(READ, info->drivenum, 0,0,1,1,ptr) &&
(count < NUMBEROFTRIES) ; count++)
;

if (count == NUMBEROFTRIES)
return (1);
else
return (0);
}




/**************************************************************************
Get_Disk_Info() calls Open_Shutter() to open any disk shutter and to
return track 0, side 0, sector 1 as bufptr. Then it does some
arithmetic to determine the characteristics of the disk, returing same
in the DISKINFO structure that info points to. Anyone interested in
the details of how the disk characteristics are determined - ie, why
this works, should consult Peter Norton's Guide to the IBM PC and
PS/2 or any other work that speaks about DOS and BIOS diskette services.
**************************************************************************/

int Get_Disk_Info(DISKINFO* info)
{
void *bufptr;
unsigned char *temp;


if ((bufptr= (void *) malloc((SECTSIZE))) != NULL) {

if (Open_Shutter(info, bufptr))
return (1);
else {

temp = bufptr;

info->heads = (temp[27] * 256) + temp[26];
info->sects_per_track = (temp[25] * 256) + temp[24] ;
info->tracks_per_disk = ((temp[20] * 256) + temp[19]) / (info->heads * info->sects_per_track);

return(0);
}
}
else {
puts("Insufficient Contiguous Memory...");
return (1);
}
}






/****************************************************************************
Read_Disk_and_Write_Image() does exactly what its name suggests. It
calls Open_Shutter() to open any obstructing floppy shutter, then does
multi-sector reads using biosdisk (Turbo C specific, biosdisk basically
does an INT 0x19 after loading the registered properly with the functions
arguments - in this it is a very low level function) and writes the
results to the filename IOFILE in the current directory. The reason
this function is a bit on the complicated side is due to an apparent
bug in the IBM (and compatible) BIOSes that allows for only up to
nine sector reads on the second side of any floppy. A future version
of QDC will work even faster by making use of the ability to read
single tracks at a time on HD floppies on the first side. Right now,
this is the simplest way to take care of the problem.
****************************************************************************/

int Read_Disk_and_Write_Image(DISKINFO *info, FILE *out)
{

void *bufptr; /* Points to what we have read */
char *temp; /* Used to shoot the above to IOFILE */
int i; /* Counter */
int head;
int track;
int sectsleft; /* These pertain to the current track and side */
int sectstoread;


printf("\nDrive %1d :: %1d heads, %2d sectors per track, %3d tracks\n\n",
info->drivenum, info->heads, info->sects_per_track, info->tracks_per_disk);


if ((bufptr= (void *) malloc(SECTSIZE*MAXSECTS)) != NULL) {

/* Open the dust cover */

if (Open_Shutter(info, bufptr))
return (1);


for (track=0; (track < info->tracks_per_disk) ; track++) {
for (head=0; headheads; head++) {

sectsleft=info->sects_per_track ;

do {


if ((sectsleft >= MAXSECTS))
sectstoread = MAXSECTS;
else
sectstoread = (sectsleft % MAXSECTS);



printf("Reading: Track %2d, Head %1d, %2d Sectors starting at %2d ", track,
head, sectstoread, info->sects_per_track - sectsleft +1);


if (i=biosdisk(READ, info->drivenum, head, track,
info->sects_per_track - sectsleft + 1, sectstoread,
bufptr)) {

printf("\aERROR 0x%X READING TRACK\n", i );
return(1);
}
else {
temp=bufptr;
for (i=0; i putc(*temp, out);
putchar('\r');
}

sectsleft=sectsleft - sectstoread;

}
while (sectsleft>0);
}
}
}
else {
puts("NOT ENOUGH CONTIGUOUS MEMORY");
return (1);
}

puts("");
return (0);
}




/***************************************************************************
Write_Disk() is the exact opposite of Read_Disk_and_Write_Image().
It reads the image file produced by the latter function and writes
it - again using BIOS INT 0x19 to a floppy in the same drive the
original floppy resided in. (This is the whole point to QDC, after
all - if you have two drives of the same kind, DISKCOPY *will* work
faster.
***************************************************************************/

int Write_Disk(DISKINFO *info, FILE *inp)
{

void *bufptr; /* Points to the sector we will write */
char *temp; /* Used to read IOFILE sections into memory */
int i,a,b,c; /* counters */
int head;
int track;
int sectsleft; /* Apply to the current track and side only */
int sectstowrite;




if ((bufptr= (void *) malloc((SECTSIZE*MAXSECTS))) != NULL) {

/* Open the dust cover */

if (Open_Shutter(info, bufptr))
return (1);


for (track=0; (track < info->tracks_per_disk) ; track++) {

for (head=0; headheads; head++) {

sectsleft=info->sects_per_track ;

do {

if (sectsleft >= MAXSECTS)
sectstowrite = MAXSECTS;
else
sectstowrite = (sectsleft % MAXSECTS);


printf("Writing: Track %2d, Head %1d, %2d Sectors starting at %2d ", track,
head, sectstowrite, info->sects_per_track - sectsleft +1);

temp=bufptr;
for (i=0; i < (SECTSIZE * sectstowrite) ; i++, temp++)
*temp = fgetc(inp);

if ((i=biosdisk(WRITE, info->drivenum, head, track,
info->sects_per_track - sectsleft + 1, sectstowrite,
bufptr))) {

printf("\aERROR 0x%X WRITING TRACK\n", i );
return(1);
}
else {
printf("\r");
}

sectsleft=sectsleft - sectstowrite;

}
while (sectsleft>0);
}
}
}
else {
puts("NOT ENOUGH CONTIGUOUS MEMORY");
return (1);
}
puts("");
return (0);
}




  3 Responses to “Category : Utilities for DOS and Windows Machines
Archive   : QDC10.ZIP
Filename : QDC.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/