home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 8 Other / 08-Other.zip / DSKCPY2A.ZIP / DSKCPY2.C next >
C/C++ Source or Header  |  1989-08-22  |  17KB  |  569 lines

  1. #include <stdio.h>
  2. #include <conio.h>
  3. #include <stdlib.h>
  4. #include <stdarg.h>
  5. #include <string.h>
  6.  
  7. #define INCL_BASE
  8. #define INCL_DOSDEVIOCTL
  9. #include <os2.h>
  10.  
  11. /* ------------------------------------------------------------------------ */
  12.  
  13. #define READ_SOURCE 1
  14. #define COPY_TARGET 2
  15. #define EXIT_DSKCPY -1
  16.  
  17. #define DSKCPY_ERROR_WRONG_FORMAT 0xffbf
  18. // #define DSKCPY_ERROR_CANT_FORMAT  0xffbe  /* Remove this definition when */
  19.                                              /* the format problem is fixed */
  20.  
  21. #define BUFSIZE   1024
  22. #define OPENFLAGS (OPEN_FLAGS_DASD | OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE)
  23.  
  24.   /* Note, for the lockdrive/unlockdrive macros, the global variable _lockCmd
  25.   **  must be accessable and set to zero!
  26.   */
  27. #define lockdrive(hf)   (_DosError = DosDevIOCtl(0L, &_lockCmd, DSK_LOCKDRIVE,   IOCTL_DISK, hf))
  28. #define unlockdrive(hf) (_DosError = DosDevIOCtl(0L, &_lockCmd, DSK_UNLOCKDRIVE, IOCTL_DISK, hf))
  29.  
  30.  
  31. /* --------------------------------------------------------------------------
  32. ** This structure is used instead of the BIOSPARAMETERBLOCK because the
  33. ** definition of that structure in some copies of bsedev.h is wrong!  It
  34. ** seems to be missing the BYTE abReserved[6] field.
  35. */
  36. typedef struct _BSPBLK
  37.   {
  38.   USHORT usBytesPerSector;
  39.   BYTE   bSectorsPerCluster;
  40.   USHORT usReservedSectors;
  41.   BYTE   cFATs;
  42.   USHORT cRootEntries;
  43.   USHORT cSectors;
  44.   BYTE   bMedia;
  45.   USHORT usSectorsPerFAT;
  46.   USHORT usSectorsPerTrack;
  47.   USHORT cHeads;
  48.   ULONG  cHiddenSectors;
  49.   ULONG  cLargeSectors;
  50.   BYTE   abReserved[6];
  51.   USHORT cCylinders;
  52.   BYTE   bDeviceType;
  53.   USHORT fsDeviceAttr;
  54.   } BSPBLK;
  55.  
  56.  
  57. /* Global variables ------------------------------------------------------ */
  58.  
  59. USHORT       _DosError = 0;       /* Most recent error code             */
  60. BYTE         _lockCmd  = 0;       /* Used with [un]lockdrive macros     */
  61. ULONG        _fmtData  = 0L;      /* Used with DSK_FORMATVERIFY         */
  62.                                   /*  (kudos to RMK!)                   */
  63.  
  64. BSPBLK       sourceParms;         /* Param block for source drive       */
  65. PBYTE        *sourceBuffer;       /* Array of pointers to track buffers */
  66. ULONG        sourceBytes;         /* # bytes on source disk             */
  67. USHORT       sourceTracks;        /* # tracks on source disk            */
  68. USHORT       bytesPerTrack;       /* Bytes per track on source disk     */
  69. PTRACKLAYOUT sourceLayout;        /* Pointer to track layout table      */
  70. USHORT       sizeofLayoutElement; /* Total size of layout table         */
  71. int          gotSource = FALSE;   /* Bool: Source disk has been read    */
  72.  
  73. BSPBLK       targetParms;         /* Param block for target disk        */
  74.  
  75.  
  76. /* Prototypes ------------------------------------------------------------ */
  77.  
  78. void  copyr(void);
  79. int   query(char *fmt, ... );
  80. HFILE opendrive(char *drive);
  81. int   readsource(HFILE hf);
  82. BYTE  fmttbl_bytessec(USHORT bytesPerSec);
  83. int   writetarget(HFILE hf);
  84. int   bspblkcmp(BSPBLK *blk1, BSPBLK *blk2);
  85. void  *Alloc(unsigned num, unsigned size);
  86. void  errorexit(HFILE hf);
  87. int   dskcpy_menu(int mlevel, char *drive);
  88. int   main(int argc, char **argv);
  89.  
  90.  
  91. /* Code ------------------------------------------------------------------ */
  92.  
  93.   /* -- Logon message --- */
  94. void copyr()
  95.   {
  96.  
  97.   puts("DskCpy2 -- Alternative disk copier for OS/2");
  98.   puts("Brady Flowers, Mankato, MN\n");
  99.   }
  100.  
  101.  
  102.  
  103.   /* --- Print a formatted string, get a key and return the keycode --- */
  104. int query(char *fmt, ... )
  105.   {
  106.   int ch;
  107.   va_list args;
  108.  
  109.   va_start(args, fmt);
  110.   vprintf(fmt, args);
  111.   ch = getch();
  112.   puts("");
  113.   return ch;
  114.   }
  115.  
  116.  
  117.  
  118.   /* --- Open disk drive ---
  119.   **       parameter is asciiz drive specifier, i.e., "a:"
  120.   **       returns handle to open drive or 0, sets/clears _DosError
  121.   */
  122. HFILE opendrive(char *drive)
  123.   {
  124.   USHORT result;
  125.   HFILE  dHandle;
  126.  
  127.   if ((strlen(drive) != 2) || (drive[1] != ':'))
  128.     _DosError = ERROR_INVALID_DATA;
  129.   else 
  130.     do
  131.       {
  132.       _DosError = DosOpen(drive, &dHandle, &result, 0L, 0, FILE_OPEN, OPENFLAGS, 0L);
  133.       if (_DosError == ERROR_NOT_READY)
  134.         {
  135.         if ((query("Please place a disk in drive %s and strike any key (ESC to end)..", drive)) == 0x1b)
  136.           break;
  137.         }
  138.       else
  139.         break;
  140.       }
  141.     while (TRUE);
  142.  
  143.   return _DosError ? 0 : dHandle;
  144.   }
  145.  
  146.  
  147.  
  148.   /* --- Read source disk into memory ---
  149.   **       parameter is drive handle as returned from opendrive()
  150.   **       reads the entire source disk into memory allocating as it goes,
  151.   **        when done sourceBuffer points to an array of buffer pointers,
  152.   **        one for each track on the disk and each the the size of a track
  153.   **        in bytes.
  154.   **       sets global variables:
  155.   **        gotSource
  156.   **        sourceBytes
  157.   **        sourceTracks
  158.   **        bytesPerTrack
  159.   **        sizeofLayoutElement
  160.   **        sourceBuffer
  161.   **        sourceLayout
  162.   **        _DosError
  163.   **       returns 0 if success else error code (_DosError)
  164.   */
  165. int readsource(HFILE hf)
  166.   {
  167.   BYTE _parmCmd = 1;
  168.   int  trk, hd, cyl;
  169.  
  170.   /* If this isn't the first time here, free memory from last time first */
  171.   if (gotSource)
  172.     {
  173.     for (trk = 0; trk < sourceTracks; trk++)
  174.       free(sourceBuffer[trk]);
  175.     free(sourceBuffer);
  176.     free(sourceLayout);
  177.     sourceBuffer = NULL;
  178.     sourceLayout = NULL;
  179.     gotSource = FALSE;
  180.     }
  181.  
  182.   /* Get source disk parameters */
  183.   _DosError = DosDevIOCtl(&sourceParms, &_parmCmd, DSK_GETDEVICEPARAMS, IOCTL_DISK, hf);
  184.   if (!_DosError)
  185.     {
  186.     /* Set all the informational variables and build a track layout table
  187.     **  for use with the following sector reads.
  188.     */
  189.     sourceBytes   = (ULONG)(sourceParms.usBytesPerSector) *
  190.                     (ULONG)(sourceParms.cSectors);
  191.     sourceTracks  = sourceParms.cSectors         /
  192.                     sourceParms.usSectorsPerTrack;
  193.     bytesPerTrack = sourceParms.usBytesPerSector *
  194.                     sourceParms.usSectorsPerTrack;
  195.  
  196.     sizeofLayoutElement = sizeof(TRACKLAYOUT)   +
  197.                           ((2 * sizeof(USHORT)) *
  198.                           (sourceParms.usSectorsPerTrack - 1));
  199.  
  200.     if (sourceLayout = (PTRACKLAYOUT)Alloc(sizeofLayoutElement, sizeof(BYTE)))
  201.       {
  202.       sourceLayout->bCommand = 1;
  203.       sourceLayout->usFirstSector = 0;
  204.       sourceLayout->cSectors = sourceParms.usSectorsPerTrack;
  205.       for (trk = 0; trk < sourceParms.usSectorsPerTrack; trk++)
  206.         {
  207.         sourceLayout->TrackTable[trk].usSectorNumber = trk+1;
  208.         sourceLayout->TrackTable[trk].usSectorSize = sourceParms.usBytesPerSector;
  209.         }
  210.       }
  211.     else
  212.       errorexit(hf);
  213.  
  214.     /* Allocate the array of BYTE pointers to hold the track data */
  215.     if ((sourceBuffer = (PBYTE *)Alloc(sourceTracks, sizeof(PBYTE))) == NULL)
  216.       errorexit(hf);
  217.  
  218.     printf("Reading %d cylinders, %d heads, %d sectors, %d bytes per sector\n",
  219.            sourceTracks / sourceParms.cHeads, sourceParms.cHeads,
  220.            sourceParms.usSectorsPerTrack,     sourceParms.usBytesPerSector);
  221.  
  222.     /* For each track, allocate a buffer and read the sector into it */
  223.     for (trk = 0, cyl = 0; trk < sourceTracks; trk += sourceParms.cHeads, cyl++)
  224.       {
  225.       sourceLayout->usCylinder = cyl;
  226.       for (hd = 0; hd < sourceParms.cHeads; hd++)
  227.         {
  228.         printf("\rCylinder %d, Head %d", cyl, hd);
  229.         sourceLayout->usHead = hd;
  230.         if ((sourceBuffer[trk+hd] = (PBYTE)Alloc(bytesPerTrack, sizeof(BYTE))) == NULL)
  231.           errorexit(hf);
  232.         if (_DosError = DosDevIOCtl(sourceBuffer[trk+hd], sourceLayout, DSK_READTRACK, IOCTL_DISK, hf))
  233.           errorexit(hf);
  234.         }
  235.       }
  236.  
  237.     puts("\rDone.                 \n");
  238.     gotSource = TRUE;
  239.     }
  240.  
  241.   return _DosError;
  242.   }
  243.  
  244.  
  245.  
  246.   /* --- Translate bytes per sector into 0-3 code ---
  247.   **       the four sector sizes listed below are alluded to in the OS/2
  248.   **        docs however only 512 byte sectors are allowed under OS/2 1.x
  249.   **       returns the code or -1 and sets _DosError
  250.   */
  251. BYTE fmttbl_bytessec(USHORT bytesPerSec)
  252.   {
  253.  
  254.   _DosError = NO_ERROR;
  255.   switch (bytesPerSec)
  256.     {
  257.     case 128:  return 0;
  258.     case 256:  return 1;
  259.     case 512:  return 2;
  260.     case 1024: return 3;
  261.     }
  262.   _DosError = ERROR_BAD_FORMAT;
  263.   return -1;
  264.   }
  265.  
  266.  
  267.  
  268.   /* --- write information read by readsource() onto target disk ---
  269.   **       parameter is drive handle as returned by opendrive()
  270.   **       checks the target disk, if it's the same format as the source
  271.   **        or not formatted at all, write the information contained in
  272.   **        sourceBuffer formatting if neccessary.
  273.   **       returns 0 if successful else errorcode (_DosError)
  274.   **
  275.   **  -------------------------------------------------------------------
  276.   **    NOTE: THIS ROUTINE, AS WRITTEN WORKS FINE IF IT DOESN'T HAVE TO
  277.   **          FORMAT THE DISK.  IT FAILS ON THE FIRST CALL TO DosDevIOCtl
  278.   **          WITH THE DSK_FORMATVERIFY PARAMETER.
  279.   **  -------------------------------------------------------------------
  280.   */
  281. int writetarget(HFILE hf)
  282.   {
  283.   BYTE         _parmCmd = 1;
  284.   PTRACKFORMAT trkfmt;
  285.   USHORT       sizeofTrkfmt;
  286.   int          i, trk, hd, cyl, needFormat = FALSE;
  287.  
  288.   /* Get target disk parameters */
  289.   _DosError = DosDevIOCtl(&targetParms, &_parmCmd, DSK_GETDEVICEPARAMS, IOCTL_DISK, hf);
  290.  
  291.   if (_DosError == ERROR_READ_FAULT)
  292.     {
  293. #if defined (DSKCPY_ERROR_CANT_FORMAT)
  294.     _DosError = DSKCPY_ERROR_CANT_FORMAT;
  295. #else
  296.     /* If the disk needs formatting we build a format table for it based
  297.     **  on the source disk.
  298.     */
  299.     needFormat = TRUE;
  300.     _DosError = 0;
  301.     sizeofTrkfmt = sizeof(TRACKFORMAT) +
  302.                     ((4 * sizeof(BYTE)) *
  303.                     (sourceParms.usSectorsPerTrack - 1));
  304.     if ((trkfmt = (PTRACKFORMAT)Alloc(sizeofTrkfmt, sizeof(BYTE))) == NULL)
  305.       errorexit(hf);
  306.     trkfmt->bCommand = 1;
  307.     trkfmt->cSectors = sourceParms.usSectorsPerTrack;
  308.     for (trk = 0; trk < trkfmt->cSectors; trk++)
  309.       {
  310.       trkfmt->FormatTable[trk].idSector = (BYTE)(trk+1);
  311.       trkfmt->FormatTable[trk].bBytesSector = fmttbl_bytessec(sourceParms.usBytesPerSector);
  312.       }
  313. #endif
  314.     }
  315.   else if (!_DosError)
  316.     /* Else if no other error, make sure that the target disk is the same
  317.     **  format as the source.
  318.     */
  319.     if (bspblkcmp(&sourceParms, &targetParms))
  320.       _DosError = DSKCPY_ERROR_WRONG_FORMAT;
  321.  
  322.  
  323.   if (!_DosError)
  324.     {
  325.     printf("Writing %d cylinders, %d heads, %d sectors, %d bytes per sector\n",
  326.            sourceTracks / sourceParms.cHeads, sourceParms.cHeads,
  327.            sourceParms.usSectorsPerTrack,     sourceParms.usBytesPerSector);
  328.     if (needFormat)
  329.       puts("Formatting while copying.");
  330.  
  331.     for (trk = 0, cyl = 0; trk < sourceTracks; trk += sourceParms.cHeads, cyl++)
  332.       {
  333.       sourceLayout->usCylinder = cyl;
  334.       for (hd = 0; hd < sourceParms.cHeads; hd++)
  335.         {
  336.         printf("\rCylinder %d, Head %d", cyl, hd);
  337.         sourceLayout->usHead = hd;
  338.         if (needFormat)
  339.           {
  340.           trkfmt->usHead = hd;
  341.           trkfmt->usCylinder = cyl;
  342.           for (i = 0; i < trkfmt->cSectors; i++)
  343.             {
  344.             trkfmt->FormatTable[i].bHead = (BYTE)hd;
  345.             trkfmt->FormatTable[i].bCylinder = (BYTE)cyl;
  346.             }
  347.  
  348. #if defined (DEBUG)
  349.     puts("");
  350.     printf("bCommand   %d\n", trkfmt->bCommand);
  351.     printf("usHead     %d\n", trkfmt->usHead);
  352.     printf("usCylinder %d\n", trkfmt->usCylinder);
  353.     printf("usReserved %d\n", trkfmt->usReserved);
  354.     printf("cSectors   %d\n", trkfmt->cSectors);
  355.     getch();
  356.     for (i = 0; i < trkfmt->cSectors; i++)
  357.       {
  358.       printf(" ft[%d].bCylinder    %d\n", i, trkfmt->FormatTable[i].bCylinder);
  359.       printf(" ft[%d].bHead        %d\n", i, trkfmt->FormatTable[i].bHead);
  360.       printf(" ft[%d].idSector     %d\n", i, trkfmt->FormatTable[i].idSector);
  361.       printf(" ft[%d].bBytesSector %d\n", i, trkfmt->FormatTable[i].bBytesSector);
  362.       getch();
  363.       }
  364.     printf("Ready.");
  365.     getch();
  366.     puts("");
  367. #endif
  368.  
  369.           if (_DosError = DosDevIOCtl(&_fmtData, trkfmt, DSK_FORMATVERIFY, IOCTL_DISK, hf))
  370.             errorexit(hf);
  371.           }
  372.         if (_DosError = DosDevIOCtl(sourceBuffer[trk+hd], sourceLayout, DSK_WRITETRACK, IOCTL_DISK, hf))
  373.           errorexit(hf);
  374.         }
  375.       }
  376.  
  377.     puts("\rDone.                 \n");
  378.     if (needFormat) free(trkfmt);
  379.     }
  380.  
  381.   return _DosError;
  382.   }
  383.  
  384.  
  385.  
  386.   /* --- compare two BSPBLK structures ---
  387.   **       returns 0 if both are the same except for possibly the
  388.   **        abReserved field, else returns non-zero.
  389.   */
  390. int bspblkcmp(BSPBLK *blk1, BSPBLK *blk2)
  391.   {
  392.   BSPBLK tmp1, tmp2;
  393.  
  394.   tmp1 = *blk1;
  395.   tmp2 = *blk2;
  396.   memset(tmp1.abReserved, 0, 6);
  397.   memset(tmp2.abReserved, 0, 6);
  398.   return memcmp(&tmp1, &tmp2, sizeof(BSPBLK));
  399.   }
  400.  
  401.  
  402.  
  403.   /* --- calloc type routine ---
  404.   **       sets _DosError to ERROR_NOT_ENOUGH_MEMORY upon failure
  405.   */
  406. void *Alloc(unsigned num, unsigned size)
  407.   {
  408.   void *rVal;
  409.  
  410.   _DosError = NO_ERROR;
  411.   if ((rVal = calloc(num, size)) == NULL)
  412.     _DosError = ERROR_NOT_ENOUGH_MEMORY;
  413.  
  414.   return rVal;
  415.   }
  416.  
  417.  
  418.  
  419.   /* --- error handler ---
  420.   **       parameter is disk handle as returned from opendrive()
  421.   **       prints system error message if possible, closes the disk
  422.   **        handle if neccessary, gets a key stroke, and exits.
  423.   */
  424. void errorexit(HFILE hf)
  425.   {
  426.   USHORT cbBuf;
  427.   CHAR   *msgBuf;
  428.  
  429.   if (_DosError == DSKCPY_ERROR_WRONG_FORMAT)
  430.     {
  431.     /* Special handling for this non-fatal error */
  432.     fprintf(stderr, "\nThe TARGET disk is not the correct format!");
  433.     fprintf(stderr, "\nStrike any key to return to menu..");
  434.     getch();
  435.     fprintf(stderr, "\n\n");
  436.     return;
  437.     }
  438.  
  439. #if defined (DSKCPY_ERROR_CANT_FORMAT)
  440.   if (_DosError == DSKCPY_ERROR_CANT_FORMAT)
  441.     {
  442.     /* Special handling for this non-fatal error */
  443.     fprintf(stderr, "\nThe TARGET disk must be preformatted!");
  444.     fprintf(stderr, "\nStrike any key to return to menu..");
  445.     getch();
  446.     fprintf(stderr, "\n\n");
  447.     return;
  448.     }
  449. #endif
  450.  
  451.   puts("");
  452.   if ((msgBuf = (PCHAR)calloc(BUFSIZE, sizeof(CHAR))) != NULL)
  453.     {
  454.     DosGetMessage(NULL, 0, msgBuf, BUFSIZE, _DosError, "oso001.msg", &cbBuf);
  455.     fputs(msgBuf, stderr);
  456.     free(msgBuf);
  457.     }
  458.   else
  459.     fprintf(stderr, "SYS%04d: error text unavailable\n", _DosError);
  460.  
  461.   if (hf) DosClose(hf);
  462.   fprintf(stderr, "Strike any key to exit..");
  463.   getch();
  464.   fprintf(stderr, "\n");
  465.   DosExit(EXIT_PROCESS, _DosError);
  466.   }
  467.  
  468.  
  469.  
  470.   /* --- _very_ simpleminded menu ---
  471.   **       parameters are: mlevel: TRUE if source has been read
  472.   **                       drive: asciiz drive specifier, i.e., "a:"
  473.   **       returns READ_SOURCE, COPY_TARGET, or EXIT_DSKCPY
  474.   */
  475. int dskcpy_menu(int mlevel, char *drive)
  476.   {
  477.   int ch;
  478.  
  479.   printf(" 1. Read SOURCE disk into memory from drive %s\n", drive);
  480.   if (mlevel)
  481.     printf(" 2. Copy memory image to TARGET disk in drive %s\n", drive);
  482.   puts(" Q. Exit DskCpy2\n");
  483.   printf("Enter Choice --> ");
  484.   do
  485.     switch (ch = getch())
  486.       {
  487.       case 'R':
  488.       case 'r':
  489.       case '1':
  490.         puts("Read\n");
  491.         ch = READ_SOURCE;
  492.         break;
  493.  
  494.       case 'C':
  495.       case 'c':
  496.       case '2':
  497.         if (mlevel)
  498.           {
  499.           puts("Copy\n");
  500.           ch = COPY_TARGET;
  501.           }
  502.         else
  503.           ch = 0;
  504.         break;
  505.  
  506.       case 'Q':
  507.       case 'q':
  508.       case '\x1b':
  509.         puts("Exit\n");
  510.         ch = EXIT_DSKCPY;
  511.         break;
  512.  
  513.       default:
  514.         ch = 0;
  515.       }
  516.   while (!ch);
  517.   return ch;
  518.   }
  519.  
  520.  
  521.  
  522. int main(int argc, char **argv)
  523.   {
  524.   HFILE dHandle;
  525.   char  *drive = "a:";
  526.   int   choice;
  527.  
  528.   copyr();
  529.   if ((argc > 2) || ((argc == 2) && (argv[1][1] != ':')))
  530.     {
  531.     fputs("usage: dskcpy2 drive_letter:", stderr);
  532.     exit(1);
  533.     }
  534.  
  535.   if (argc == 2)
  536.     drive = argv[1];
  537.  
  538.   DosError(HARDERROR_DISABLE);
  539.   do
  540.     {
  541.     choice = dskcpy_menu(gotSource, drive);
  542.     switch (choice)
  543.       {
  544.       case READ_SOURCE:
  545.         query("Place SOURCE disk in drive %s and strike any key when ready..", drive);
  546.         if ((dHandle = opendrive(drive)) == 0) errorexit(dHandle);
  547.         if (lockdrive(dHandle))                errorexit(dHandle);
  548.         if (readsource(dHandle))               errorexit(dHandle);
  549.         if (unlockdrive(dHandle))              errorexit(dHandle);
  550.         DosClose(dHandle);
  551.         break;
  552.       case COPY_TARGET:
  553.         query("Place TARGET disk in drive %s and strike any key when ready..", drive);
  554.         if ((dHandle = opendrive(drive)) == 0) errorexit(dHandle);
  555.         if (lockdrive(dHandle))                errorexit(dHandle);
  556.         if (writetarget(dHandle))              errorexit(dHandle);
  557.         if (unlockdrive(dHandle))              errorexit(dHandle);
  558.         DosClose(dHandle);
  559.         break;
  560.       default:
  561.         break;
  562.       }
  563.     }
  564.   while (choice != EXIT_DSKCPY);
  565.  
  566.   return _DosError;
  567.   }
  568.  
  569.