home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PROGRAMS / UTILS / FLOPPIES / QDC10.ZIP / QDC.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-19  |  15.1 KB  |  480 lines

  1. /*****************************************************************************
  2.  
  3.      QDC 1.0 is (c) 1990 by Peter A. Dinda
  4.  
  5.  
  6.      QDC (Quick Disk Copy) 1.0 is designed to make it easy
  7.      to make disk copies of large (HD) diskettes on systems
  8.      that do not have multiple HD drives.  QDC will save you
  9.      three to four disk swaps in coping a 1.44 MB disk on
  10.      a system with 550K of free conventional memory.
  11.  
  12.  
  13.      NOTE:  QDC is a shareware product by Peter A. Dinda and
  14.             must be registered for continual use.  Use of
  15.             QDC by any military organization is strictly
  16.             forbidden.  Registration is $15.  To register,
  17.             or to make any comments about QDC, mail:
  18.  
  19.                    Peter A. Dinda
  20.                    404 N. Walbridge #7
  21.                    Madison, WI 53714
  22.  
  23.             Email:    dinda@VMS.macc.wisc.edu
  24.                    or dinda@jomby.cs.wisc.edu
  25.  
  26.             BBS:   Peter Dinda; MIC@MACC BBS; 608 263 6057
  27.  
  28.  ****************************************************************************/
  29.  
  30.  
  31.  
  32.  
  33.  
  34.  
  35. #include <stdio.h>
  36. #include <dos.h>
  37. #include <bios.h>
  38. #include <ctype.h>
  39. #include <conio.h>
  40.  
  41. #define OWNER "*UNREGISTERED*"
  42.  
  43. #define MINARGS 2                      /* Number of arguments QDC must see */
  44. #define MAXARGS 2
  45.  
  46.  
  47. #define READ  2                        /* BIOS read sector command */
  48. #define WRITE 3                        /* BIOS write sector command */
  49.  
  50. #define DEFAULT 0                      /* For getdfree() */
  51. #define DRIVEA  0                      /* Min legal drive number */
  52.  
  53. #define SECTSIZE      512              /* Limited to this by TC biosdisk() */
  54. #define NUMBEROFTRIES 40               /* Max Number of reads to open shutter*/
  55. #define MAXSECTS      9                /* Max sectors per BIOS call */
  56.  
  57. /* Potential Bug in the IBM BIOS! - It can read a maximum of only nine
  58.    sectors from side 1 of a floppy.  It will read a whole track from
  59.    side 0.  Therefore QDC bends over backwards to work....  MAXSECTS is
  60.    here as a result of this.  If your BIOS does not have this bug, you
  61.    should be able to increase MAXSECTS and gain speed.
  62. */
  63.  
  64.  
  65. #define IOFILE "!!QDC!!.IM"            /* QDC's Image Filename */
  66. #define WRITEBINARY "wb"               /* fopen() op type */
  67. #define READBINARY "rb"                /* fopen() op type */
  68.  
  69.  
  70.  
  71.  
  72. struct dinfo {                         /* What we find out about the */
  73.         int drivenum;                  /* source floppy using the    */
  74.         int heads;                     /* Get_Disk_Info() function   */
  75.           int tracks_per_disk;
  76.           int sects_per_track;
  77.              };
  78.  
  79. typedef struct dinfo DISKINFO;
  80.  
  81.  
  82.  
  83. /**************** Function Prototypes *****************************/
  84.  
  85. void help(void);
  86. int Decode_Drive_Num(char *);
  87. int Get_Disk_Info(DISKINFO *);
  88. int Read_Disk_and_Write_Image(DISKINFO *, FILE *);
  89. int Write_Disk(DISKINFO *, FILE*);
  90.  
  91. /******************************************************************/
  92.  
  93.  
  94.  
  95.  
  96. main(int argc, char *argv[])
  97. {
  98.    DISKINFO *disk;              /* Everything about the source floppy */
  99.    struct dfree *dtable;        /* For getdfree() */
  100.    FILE *io;                    /* Image file pointer */
  101.    char keypress;
  102.    float defree, need;          /* For space comparisons */
  103.  
  104.  
  105.  
  106.     if (argc < MINARGS) {
  107.       help();
  108.       exit(1);
  109.    }
  110.    else {
  111.  
  112.       clrscr();
  113.         printf("QDC 1.0 (c)1990 Peter A. Dinda -> registered to: %s\n\n", OWNER);
  114.  
  115.       if ((disk= (DISKINFO *) malloc(sizeof (DISKINFO))) !=NULL) {
  116.  
  117.          if ((disk->drivenum = Decode_Drive_Num(argv[1])) < DRIVEA) {
  118.             puts("\aFAILURE: Invalid Drive!");
  119.             exit(1);
  120.          }
  121.          else {
  122.  
  123.             printf("INITIAL: Insert your Source Disk into drive %c and press RETURN\n", toupper(*argv[1]));
  124.  
  125.             while (getch() != '\r')
  126.                ;
  127.  
  128.             if (Get_Disk_Info(disk)) {
  129.                puts("\a\nFAILURE: Either there is no disk in the drive, a hardware error occured,");
  130.                puts(  "         or this is unrecognized disk format.");
  131.                exit(1);
  132.             }
  133.             else {
  134.  
  135.                getdfree(DEFAULT, dtable);
  136.  
  137.                defree =(float) (dtable->df_avail)*(dtable->df_sclus)*(dtable->df_bsec);
  138.                need = (float) (disk->heads)*(disk->sects_per_track)*(disk->tracks_per_disk) * (SECTSIZE);
  139.  
  140.  
  141.                if (defree < need ) {
  142.  
  143.                   puts("\a\nFAILURE: There is insufficient space on the default drive to create the Image");
  144.                   puts("         File.  You may want to delete some files from the default drive.");
  145.                   printf("         %.0f bytes are needed.\n\n", need);
  146.                   exit(1);
  147.                }
  148.                else {
  149.  
  150.                   io = fopen(IOFILE, WRITEBINARY);
  151.  
  152.  
  153.                   if (!Read_Disk_and_Write_Image(disk, io)) {
  154.                      fclose(io);
  155.                      puts("\nSUCCESS: Creation of the Image File was successful.  Insert your");
  156.                      puts("         Destination Disk in the *same* drive and press RETURN.\n");
  157.  
  158.                      while (getch() != '\r')
  159.                         ;
  160.  
  161.                      io = fopen(IOFILE, READBINARY);
  162.  
  163.                             if (!Write_Disk(disk, io)) {
  164.  
  165.                         puts("\nSUCCESS: The QDC Copy Operation Was Successful!\n");
  166.                         remove(IOFILE);
  167.                         exit(0);
  168.  
  169.                      }
  170.                      else {
  171.                         puts("\a\nFAILURE: An error occurred while writing the duplicate disk.  This is the");
  172.                         puts("         result of either an open drive door, or an incompatible or damaged");
  173.                         puts("         disk.  If this was expected, please realize the duplicate may be");
  174.                         puts("         unreliable!\n");
  175.                         remove(IOFILE);
  176.                         exit(1);
  177.                      }
  178.                   }
  179.                   else {
  180.  
  181.                      puts("\a\nFAILURE: An error occurred while reading the disk.  This is caused by either");
  182.                      puts("         an open drive door or a damaged (or protected) disk.\n");
  183.                      remove(IOFILE);
  184.                      exit(1);
  185.                   }
  186.                }
  187.             }
  188.          }
  189.       }
  190.    }
  191. }
  192.  
  193.  
  194.  
  195.  
  196. /**************************************************************************
  197.       HELP FUNCTION:  Gives the User Help and Shows Beg Screen
  198.  **************************************************************************/
  199. void help(void)
  200. {
  201.    clrscr();
  202.  
  203.    puts("Welcome to QDC 1.0");
  204.    puts("------------------\n");
  205.    puts("QDC stands for Quick Disk Copy.  QDC is a replacement for DISKCOPY");
  206.    puts("that:");
  207.    puts("           1. Requires only one disk swap per copy operation.");
  208.    puts("           2. Works faster than DISKCOPY in *any* situation where you");
  209.    puts("              have only one drive for the type of disk you want to copy");
  210.    puts("           3. Maintains its speed in *any* amount of memory.\n");
  211.     puts("If you find QDC to be useful, please send $10 or so to:\n");
  212.    puts("                         Peter A. Dinda  Re: QDC");
  213.    puts("                         404 N. Walbridge #7");
  214.    puts("                         Madison, WI 53714\n");
  215.    puts("The command format for QDC is:\n");
  216.    puts("            QDC [drive letter]\n");
  217.    puts("where [drive letter] is the disk drive that contains the source disk.\n");
  218.    puts("Please see the accompanying documentation for more information.");
  219. }
  220.  
  221.  
  222.  
  223.  
  224.  
  225.  
  226. /*************************************************************************
  227.   Decode_Drive_Num takes the users drive letter argument and returns the
  228.   corresponding drive number to the caller.
  229.  *************************************************************************/
  230.  
  231. int Decode_Drive_Num(char *dlet)
  232. {
  233.    if (isupper(*dlet))
  234.       return (*dlet - 'A');
  235.    else if (islower(*dlet))
  236.       return (*dlet - 'a');
  237.    else
  238.       return (-1);
  239. }
  240.  
  241.  
  242.  
  243.  
  244. /***************************************************************************
  245.     Open_Shutter() simply does multiple single sector read attempts on
  246.     track 0 to force the drive to open the disk shutter.  If it has not
  247.     received a favorable read in NUMBEROFTRIES, it returns 1 as a failure
  248.     flag.  Open_Shutter returns ptr pointing to the sector it read.
  249.  ***************************************************************************/
  250.  
  251. int Open_Shutter(DISKINFO* info, void *ptr)
  252. {
  253.    int count;
  254.  
  255.    for (count=1 ; biosdisk(READ, info->drivenum, 0,0,1,1,ptr) &&
  256.        (count < NUMBEROFTRIES) ; count++)
  257.       ;
  258.  
  259.    if (count == NUMBEROFTRIES)
  260.       return (1);
  261.    else
  262.       return (0);
  263. }
  264.  
  265.  
  266.  
  267.  
  268. /**************************************************************************
  269.    Get_Disk_Info() calls Open_Shutter() to open any disk shutter and to
  270.    return track 0, side 0, sector 1 as bufptr.  Then it does some
  271.    arithmetic to determine the characteristics of the disk, returing same
  272.    in the DISKINFO structure that info points to.  Anyone interested in
  273.    the details of how the disk characteristics are determined - ie, why
  274.    this works, should consult Peter Norton's Guide to the IBM PC and
  275.    PS/2 or any other work that speaks about DOS and BIOS diskette services.
  276.  **************************************************************************/
  277.  
  278. int Get_Disk_Info(DISKINFO* info)
  279. {
  280.    void *bufptr;
  281.    unsigned char *temp;
  282.  
  283.  
  284.    if ((bufptr= (void *) malloc((SECTSIZE))) != NULL)  {
  285.  
  286.       if (Open_Shutter(info, bufptr))
  287.          return (1);
  288.       else {
  289.  
  290.          temp = bufptr;
  291.  
  292.          info->heads = (temp[27] * 256) + temp[26];
  293.          info->sects_per_track = (temp[25] * 256) + temp[24] ;
  294.          info->tracks_per_disk = ((temp[20] * 256) + temp[19]) / (info->heads * info->sects_per_track);
  295.  
  296.          return(0);
  297.       }
  298.    }
  299.    else {
  300.       puts("Insufficient Contiguous Memory...");
  301.       return (1);
  302.    }
  303. }
  304.  
  305.  
  306.  
  307.  
  308.  
  309.  
  310. /****************************************************************************
  311.    Read_Disk_and_Write_Image() does exactly what its name suggests.  It
  312.    calls Open_Shutter() to open any obstructing floppy shutter, then does
  313.    multi-sector reads using biosdisk (Turbo C specific, biosdisk basically
  314.    does an INT 0x19 after loading the registered properly with the functions
  315.    arguments - in this it is a very low level function) and writes the
  316.    results to the filename IOFILE in the current directory.  The reason
  317.    this function is a bit on the complicated side is due to an apparent
  318.    bug in the IBM (and compatible) BIOSes that allows for only up to
  319.    nine sector reads on the second side of any floppy.  A future version
  320.    of QDC will work even faster by making use of the ability to read
  321.    single tracks at a time on HD floppies on the first side.  Right now,
  322.    this is the simplest way to take care of the problem.
  323.  ****************************************************************************/
  324.  
  325. int Read_Disk_and_Write_Image(DISKINFO *info, FILE *out)
  326. {
  327.  
  328.    void *bufptr;              /* Points to what we have read */
  329.    char *temp;                /* Used to shoot the above to IOFILE */
  330.    int i;                     /* Counter */
  331.    int head;
  332.    int track;
  333.    int sectsleft;             /* These pertain to the current track and side */
  334.    int sectstoread;
  335.  
  336.  
  337.    printf("\nDrive %1d :: %1d heads, %2d sectors per track, %3d tracks\n\n",
  338.       info->drivenum, info->heads, info->sects_per_track, info->tracks_per_disk);
  339.  
  340.  
  341.    if ((bufptr= (void *) malloc(SECTSIZE*MAXSECTS)) != NULL)  {
  342.  
  343. /* Open the dust cover */
  344.  
  345.       if (Open_Shutter(info, bufptr))
  346.          return (1);
  347.  
  348.  
  349.       for (track=0; (track < info->tracks_per_disk) ; track++)  {
  350.          for (head=0; head<info->heads; head++) {
  351.  
  352.             sectsleft=info->sects_per_track ;
  353.  
  354.             do {
  355.  
  356.  
  357.                     if ((sectsleft >= MAXSECTS))
  358.                         sectstoread = MAXSECTS;
  359.                     else
  360.                         sectstoread = (sectsleft % MAXSECTS);
  361.  
  362.  
  363.  
  364.                printf("Reading: Track %2d, Head %1d, %2d Sectors starting at %2d ", track,
  365.                        head, sectstoread, info->sects_per_track - sectsleft +1);
  366.  
  367.  
  368.                if (i=biosdisk(READ, info->drivenum, head, track,
  369.                    info->sects_per_track - sectsleft + 1, sectstoread,
  370.                    bufptr)) {
  371.  
  372.                   printf("\aERROR 0x%X READING TRACK\n", i );
  373.                   return(1);
  374.                }
  375.                else  {
  376.                   temp=bufptr;
  377.                   for (i=0; i<SECTSIZE*(sectstoread) ; i++, temp++)
  378.                   putc(*temp, out);
  379.                   putchar('\r');
  380.                }
  381.  
  382.                sectsleft=sectsleft - sectstoread;
  383.  
  384.             }
  385.             while (sectsleft>0);
  386.          }
  387.       }
  388.    }
  389.    else {
  390.      puts("NOT ENOUGH CONTIGUOUS MEMORY");
  391.      return (1);
  392.    }
  393.  
  394.    puts("");
  395.    return (0);
  396. }
  397.  
  398.  
  399.  
  400.  
  401. /***************************************************************************
  402.     Write_Disk() is the exact opposite of Read_Disk_and_Write_Image().
  403.     It reads the image file produced by the latter function and writes
  404.     it - again using BIOS INT 0x19 to a floppy in the same drive the
  405.     original floppy resided in.  (This is the whole point to QDC, after
  406.     all - if you have two drives of the same kind, DISKCOPY *will* work
  407.     faster.
  408.  ***************************************************************************/
  409.  
  410. int Write_Disk(DISKINFO *info, FILE *inp)
  411. {
  412.  
  413.    void *bufptr;             /* Points to the sector we will write */
  414.    char *temp;               /* Used to read IOFILE sections into memory */
  415.     int i,a,b,c;              /* counters */
  416.     int head;
  417.    int track;
  418.    int sectsleft;            /* Apply to the current track and side only */
  419.     int sectstowrite;
  420.  
  421.  
  422.  
  423.  
  424.    if ((bufptr= (void *) malloc((SECTSIZE*MAXSECTS))) != NULL)  {
  425.  
  426. /* Open the dust cover */
  427.  
  428.       if (Open_Shutter(info, bufptr))
  429.          return (1);
  430.  
  431.  
  432.         for (track=0; (track < info->tracks_per_disk) ; track++)  {
  433.  
  434.          for (head=0; head<info->heads; head++) {
  435.  
  436.             sectsleft=info->sects_per_track ;
  437.  
  438.             do {
  439.  
  440.                     if (sectsleft >= MAXSECTS)
  441.                         sectstowrite = MAXSECTS;
  442.                     else
  443.                         sectstowrite = (sectsleft % MAXSECTS);
  444.  
  445.  
  446.                printf("Writing: Track %2d, Head %1d, %2d Sectors starting at %2d ", track,
  447.                        head, sectstowrite, info->sects_per_track - sectsleft +1);
  448.  
  449.                temp=bufptr;
  450.                for (i=0; i < (SECTSIZE * sectstowrite) ; i++, temp++)
  451.                   *temp = fgetc(inp);
  452.  
  453.                if ((i=biosdisk(WRITE, info->drivenum, head, track,
  454.                     info->sects_per_track - sectsleft + 1, sectstowrite,
  455.                     bufptr))) {
  456.  
  457.                   printf("\aERROR 0x%X WRITING TRACK\n", i );
  458.                   return(1);
  459.                }
  460.                else {
  461.                   printf("\r");
  462.                }
  463.  
  464.                sectsleft=sectsleft - sectstowrite;
  465.  
  466.             }
  467.             while (sectsleft>0);
  468.          }
  469.       }
  470.    }
  471.    else {
  472.       puts("NOT ENOUGH CONTIGUOUS MEMORY");
  473.       return (1);
  474.    }
  475.    puts("");
  476.    return (0);
  477. }
  478.  
  479.  
  480.