home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume38 / awdc / part01 / awdc.c next >
C/C++ Source or Header  |  1993-07-13  |  8KB  |  279 lines

  1. /* awdc - sector level floppy copy
  2.  
  3. awdc is a floppy disk copy problem with a difference - it copies at a
  4. sector level, ignoring such trivia as the number of sectors per track
  5. and number of tracks.  It stops when it reaches the end of either disc
  6. or encounters a transfer error.
  7.  
  8. It was written to solve a specific problem - transcribing UNIX tar
  9. archive discs from one type of floppy disc to another, on a DOS machine.
  10. For safety, the program will only copy sectors between removable media,
  11. so it should leave hard disks alone.  I am not particularly proud of it,
  12. but it solved my problem and may help others, so I am placing it in the
  13. public domain.  Use it entirely at your own risk.
  14.  
  15. Adrian Wontroba, Stade Computers Limited.       phone:  (+44) 21 373 9546
  16. uucp:   ...!uknet!stade!aw1             other: aw1%stade.co.uk@uknet.ac.uk
  17. snail:  14 Fourlands Avenue, Sutton Coldfield, West Midlands, B72 1YY, UK
  18.  
  19. */
  20.  
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <dos.h>
  24. #include <ctype.h>
  25. #include <string.h>
  26. #undef    NO_WRITE        /* if defined, no writes! */
  27. #define    BUFFERSIZE    32768    /* size of disk io buffer, max 64k  */
  28. char           *progname;    /* program name */
  29.  
  30. /*
  31.  * setmessage - output warning about disk parameter blocks
  32.  *
  33.  */
  34. void
  35. setmessage(void)
  36. {
  37.     fprintf(stderr,
  38.         "The action of this program is strongly influenced by\n"
  39.       "the content of the Disk Parameter Block for each drive.\n\n");
  40.     fprintf(stderr,
  41.         "Before using it (especially with non DOS media), the DPBs\n"
  42.         "should be initialised by issuing 'DIR x:' commands on the\n"
  43.         "input and output drives with equivalent DOS media.\n\n");
  44.     fprintf(stderr,
  45.         "The output disk must be pre-formatted.\n\n");
  46.     fprintf(stderr,
  47.         "As a safety measure, the program will only copy between\n"
  48.         "removeable media.\n\n");
  49. }                /* setmessage */
  50.  
  51. /*
  52.  * usage - output usage message
  53.  * 
  54.  */
  55. void
  56. usage(void)
  57. {
  58.     fprintf(stderr, "usage: %s <input drive letter> "
  59.         "<output drive letter>\n"
  60.         "eg 'awdc a b' to copy from a to b\n\n",
  61.         progname);
  62.     setmessage();
  63. }                /* usage */
  64.  
  65. /*
  66.  * myerror - print error message and errno and _doserrno to stderr
  67.  * 
  68.  */
  69. void
  70. myerror(char *s)
  71. {
  72.     int             e = errno;
  73.     int             d = _doserrno;
  74.  
  75.     fprintf(stderr, "\n%s: %s: %s (%d/%x), _doserrno = %d\n",
  76.         progname, s,
  77.      ((e > 0) && (e <= sys_nerr)) ? sys_errlist[e] : "Unknown error",
  78.         e, e, d);
  79. }                /* myerror */
  80.  
  81. /*
  82.  * get_drive - turn drive letter into drive number for absread/abswrite
  83.  * 0=A, 1=B etc.
  84.  * 
  85.  * Note - most DOS functions use 0=default, 1=A. etc. Beware.
  86.  * 
  87.  * error message and exit(1) on error
  88.  * 
  89.  */
  90. int
  91. get_drive(char *s)
  92. {
  93.     int             c;
  94.     int             d;
  95.     union REGS      regs;
  96.  
  97.     c = toupper(s[0]);
  98.     if ((c < 'A') || (c > 'Z')) {
  99.     fprintf(stderr, "Drive '%c' not supported\n", c);
  100.     exit(1);
  101.     } else {
  102.     d = c - 'A';
  103.     regs.h.ah = 0x44;    /* ioctl */
  104.     regs.h.al = 0x8;    /* check if block device is removeable */
  105.     regs.h.bl = d + 1;    /* drive code - 0 def, 1=A, etc */
  106.     intdos(®s, ®s);
  107.     if (regs.x.cflag) {
  108.         fprintf(stderr, "Unable to determine "
  109.             "exchangeability of %c, "
  110.             "ioctl error %d\n",
  111.             c, regs.x.ax);
  112.         exit(1);
  113.     }
  114.     if (regs.x.ax) {
  115.         fprintf(stderr, "%c is not an exchangeable drive\n",
  116.             c);
  117.         exit(1);
  118.     }
  119.     /* phew, its exchangeable */
  120.     }
  121.     return d;
  122. }                /* get_drive */
  123.  
  124. /*
  125.  * copy - copy one logical drive to another, until failure
  126.  * 
  127.  */
  128. void
  129. copy(int in, int out)
  130. {
  131.     union REGS      regs;
  132.     int             in_sectors;    /* sectors on input drive */
  133.     int             in_sector_size;    /* sector size */
  134.     int             out_sectors;/* sectors on output drive */
  135.     int             out_sector_size;    /* sector size */
  136.     int             sectors;    /* sectors to copy */
  137.     int             num;    /* max sectors per transfer */
  138.     int             n;        /* current sectors per transfer */
  139.     int             s_read;    /* sectors read */
  140.     int             s_written;    /* sectors written */
  141.     int             s;        /* current sector */
  142.     char           *buff;    /* buffer */
  143.  
  144.     /* device parameter block */
  145.     struct DPB {
  146.     unsigned char   special_functions;
  147.     unsigned char   device_type;
  148.     unsigned short int device_attributes;
  149.     unsigned short int max_cylinders;
  150.     unsigned char   media_type;
  151.     unsigned short int bytes_per_sector;
  152.     unsigned char   sectors_per_au;
  153.     unsigned short int sectors_reserved;
  154.     unsigned char   fats;
  155.     unsigned short int maxroot;
  156.     unsigned short int sectors;
  157.     unsigned char   media;
  158.     unsigned short int sectors_per_fat;
  159.     unsigned short int sectors_per_track;
  160.     unsigned short int heads;
  161.     unsigned long int hidden_sectors;
  162.     unsigned char   reserved[11];
  163.     };
  164.     struct DPB      dpb;
  165.  
  166.     /* get number of sectors on input drive */
  167.     memset(&dpb, 0, sizeof dpb);
  168.     regs.h.ah = 0x44;        /* ioctl */
  169.     regs.h.al = 0xd;        /* generic i/o control */
  170.     regs.h.bl = in + 1;        /* drive number */
  171.     regs.h.ch = 0x8;        /* disk drive */
  172.     regs.h.cl = 0x60;        /* get drive parameters */
  173.     regs.x.dx = (unsigned int) &dpb;    /* ugh! */
  174.     dpb.special_functions = 128;/* return build device driver bpb */
  175.     intdos(®s, ®s);
  176.     if (regs.x.cflag) {
  177.     fprintf(stderr, "Unable to get drive parameters for %c"
  178.         ", ioctl error %d\n",
  179.         in + 'A', regs.x.ax);
  180.     exit(1);
  181.     }
  182.     in_sectors = dpb.sectors;
  183.     in_sector_size = dpb.bytes_per_sector;
  184.     printf("Input drive %c has %d sectors of %d bytes\n",
  185.        in + 'A', in_sectors, in_sector_size);
  186.     /* get number of sectors on output drive */
  187.     memset(&dpb, 0, sizeof dpb);
  188.     regs.h.ah = 0x44;        /* ioctl */
  189.     regs.h.al = 0xd;        /* generic i/o control */
  190.     regs.h.bl = out + 1;    /* drive number */
  191.     regs.h.ch = 0x8;        /* disk drive */
  192.     regs.h.cl = 0x60;        /* get drive parameters */
  193.     regs.x.dx = (unsigned int) &dpb;    /* ugh! */
  194.     dpb.special_functions = 128;/* return build device driver bpb */
  195.     intdos(®s, ®s);
  196.     if (regs.x.cflag) {
  197.     fprintf(stderr, "Unable to get drive parameters for %c"
  198.         ", ioctl error %d\n",
  199.         out + 'A', regs.x.ax);
  200.     exit(1);
  201.     }
  202.     out_sectors = dpb.sectors;
  203.     out_sector_size = dpb.bytes_per_sector;
  204.     printf("Output drive %c has %d sectors of %d bytes\n",
  205.        out + 'A', out_sectors, out_sector_size);
  206.     if (in_sector_size != out_sector_size) {
  207.     fprintf(stderr, "Drives have different sector sizes\n");
  208.     exit(1);
  209.     }
  210.     /* decide how many sectors to copy */
  211.     if (in_sectors > out_sectors) {
  212.     fprintf(stderr, "Input drive larger than output\n"
  213.         "Data may be lost\n");
  214.     sectors = out_sectors;
  215.     } else {
  216.     sectors = in_sectors;
  217.     }
  218.     printf("Copying %d sectors\n", sectors);
  219.     /* get buffer */
  220.     if ((buff = malloc(BUFFERSIZE)) == NULL) {
  221.     fprintf(stderr, "malloc failed\n");
  222.     exit(1);
  223.     }
  224.     /* decide how many sectors to handle at a time */
  225.     num = BUFFERSIZE / in_sector_size;
  226.     s_read = 0;
  227.     s_written = 0;
  228.     s = 0;
  229.     while (sectors > 0) {
  230.     n = min(sectors, num);
  231.     printf("Sectors %5d to %5d\r", s, s + n - 1);
  232.     if (absread(in, n, s, buff)) {
  233.         /* read error */
  234.         myerror("absread");
  235.         break;
  236.     } else {
  237.         s_read += n;
  238. #ifdef NO_WRITE
  239.         /* do nothing to output drive ! */
  240. #else
  241.         if (abswrite(out, n, s, buff)) {
  242.         /* write error */
  243.         myerror("abswrite");
  244.         break;
  245.         } else {
  246.         s_written += num;
  247.         }
  248. #endif                /* NO_WRITE */
  249.     }
  250.     sectors -= n;
  251.     s += n;
  252.     }
  253.     printf("Sectors read from %c:  %5d\n"
  254.        "Sectors written to %c: %5d\n",
  255.        in + 'A', s_read, out + 'A', s_written);
  256. }                /* copy */
  257.  
  258. /*
  259.  * main
  260.  */
  261. int
  262. main(int argc, char *argv[])
  263. {
  264.     int             in_drive;    /* input drive number */
  265.     int             out_drive;    /* output drive number */
  266.  
  267.     progname = argv[0];
  268.     if (argc != 3) {
  269.     usage();
  270.     exit(1);
  271.     }
  272.     in_drive = get_drive(argv[1]);
  273.     out_drive = get_drive(argv[2]);
  274.     setmessage();
  275.     copy(in_drive, out_drive);
  276.     printf("OK\n");
  277.     exit(0);
  278. }                /* main */
  279.