home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
-
- 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: dinda@VMS.macc.wisc.edu
- or dinda@jomby.cs.wisc.edu
-
- BBS: Peter Dinda; MIC@MACC BBS; 608 263 6057
-
- ****************************************************************************/
-
-
-
-
-
-
- #include <stdio.h>
- #include <dos.h>
- #include <bios.h>
- #include <ctype.h>
- #include <conio.h>
-
- #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; head<info->heads; 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<SECTSIZE*(sectstoread) ; i++, temp++)
- 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; head<info->heads; 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);
- }
-
-