home *** CD-ROM | disk | FTP | other *** search
/ Shareware Supreme Volume 6 #1 / swsii.zip / swsii / 126 / SPRDPR20.ZIP / COPYDISK.C < prev    next >
C/C++ Source or Header  |  1990-03-12  |  15KB  |  504 lines

  1. /*******************************************************************************
  2. *  Program:    COPYDISK.C  C 5.1 and MASM 5.1
  3. *
  4. *  Purpose:    Copies volume label, subdirectory structure and all files
  5. *           regardless of attribute type from one disk medium to another.
  6. *
  7. *  Author:        Gordon Harris
  8. *            3349 Humboldt Ave S
  9. *            Minneapolis, MN 55408
  10. *
  11. *            Comments can be addressed to my
  12. *            CompuSurve address: [72611,620]
  13. *
  14. *
  15. *
  16. * Description: COPYDISK is an XCOPY like utility which allows you to copy
  17. *           an entire disk to a drive of differing type, e.g. copy
  18. *           the contents of a 1.2 m floppy to a 1.44 m floppy, etc.
  19. *
  20. *           Unlike XCOPY, COPYDISK will copy the volume label from the
  21. *           source disk to the target, as well as copying all
  22. *           subdirectories and files including hidden, system or read-
  23. *           only files and directories.  All files on the target disk
  24. *           created by COPYDISK will have identical attributes (dates,
  25. *           times, etc) as the files on the source disk.  If the
  26. *           source disk is bootable, so will the resulting target disk.
  27. *
  28. *  Syntax:     The syntax for using COPYDISK is:
  29. *
  30. *           COPYDISK sourcedrive: targetdrive: [-n] [-x] [-f]
  31. *
  32. *           where "sourcedrive:" and "targetdrive:" are valid dos drives
  33. *           and [-n], [-x] and [-f] are optional parameters.
  34. *
  35. *  Operation:  Given valid parameters, COPYDISK (1) performs a media check
  36. *           on the indicated drives, (2) prompts the user for permission
  37. *           to delete all existing data from the target drive, (3) copies
  38. *           the volume label from the source drive to the target and then
  39. *           (4) proceeds to copy all files and directories from the source
  40. *           to the target.
  41. *
  42. *           COPYDISK will abort if its check of the media type of the
  43. *           target disk reveals that it is a fixed disk.  This protects
  44. *           you from inadvertently deleting the contents of a hard disk
  45. *           either by using an incorrect parameter for the target drive
  46. *           or by using a virtual drive name created by ASSIGN or SUBST
  47. *           which represents a fixed disk drive or subdirectory on a
  48. *           hard disk.
  49. *
  50. *           During the media check, COPYDISK installs its own critical
  51. *           error handler.  If a error is detected reading either the
  52. *           source or target drives, COPYDISK will prompt you to retry
  53. *           access to the disk.  If you choose not to retry access to
  54. *           the target disk, COPYDISK will prompt you as to whether you
  55. *           wish to format the target.
  56. *
  57. *           COPYDISK will also abort if the data on the source disk is
  58. *           too large to fit on the empty target disk, or if any errors
  59. *           occur reading data from the source or writing data to the
  60. *           target disks.
  61. *
  62. *  Optional Parameters:
  63. *        -n (no prompt).  This is useful when using COPYDISK in batch
  64. *           files.  With the "-n" parameter, COPYDISK will not prompt you
  65. *           for permission to delete all data from the target disk.
  66. *
  67. *        -x (relaxed media checking).  With this parameter, the target
  68. *           disk may be a hard disk and the source data may be larger
  69. *           than the capacity of the target disk.
  70. *
  71. *        -f (format target automatically if media check failure).  With
  72. *           this parameter, the DOS FORMAT.COM command will be spawned
  73. *           without prompting if the target disk fails the media check.
  74. *
  75. *  Credits:    Ray Duncan, Advanced MS DOS Programming, 1988, Microsoft Press
  76. *           Kevin P. Welch, "WFINDER"
  77. *
  78. *
  79. ********************************************************************************/
  80. #include <dos.h>
  81. #include <stdio.h>
  82. #include <stdlib.h>
  83. #include <fcntl.h>
  84. #include <errno.h>
  85. #include <malloc.h>
  86. #include <process.h>
  87. #include "COPYDISK.h"
  88.  
  89. char        *pSource;
  90. size_t        nBufSize;
  91. int        errno;
  92. int        nNumFiles;
  93. char        szSyntaxMsg [] = "Syntax: COPYDISK sourcedrive: targetdrive: -NoPrompt \n\n",
  94.         szMsg[80] = "\n";
  95.  
  96. union REGS inregs, outregs;
  97. struct SREGS segregs;
  98. unsigned _osversion;
  99.  
  100. main(int argc, char * argv[] )
  101.    {
  102.    int        bPrompt, bCheck, bFormat, n;
  103.    struct   drvinfo_t drv1, drv2;
  104.    int        crterror = 0;
  105.    char     szDrive1 [10], szDrive2 [10];
  106.  
  107.    errno = EINVAL;
  108.  
  109.    strcpy (szDrive1, " :\\*.*");
  110.    strcpy (szDrive2, " :");
  111.    if (argc < 3)
  112.       ErrExit("");
  113.    szDrive1 [0] = toupper(*argv [1]);
  114.    szDrive2 [0] = toupper(*argv [2]);
  115.  
  116.    /* check for same source & target drives */
  117.    if (szDrive1 [0] == szDrive2 [0])
  118.       ErrExit("Sourcedrive = Targetdrive");
  119.  
  120.    /* check remaining parameters */
  121.    bPrompt = TRUE;
  122.    bCheck  = TRUE;
  123.    bFormat = FALSE;
  124.    for (n = 3; n < argc; n++)
  125.       {
  126.       if (argv [n] [0] == '-' || argv [n] [0] == '/')
  127.      switch ( toupper(argv [n] [1]) )
  128.         {
  129.         case 'N':
  130.            bPrompt = FALSE;
  131.            break;
  132.         case 'X':
  133.            bCheck = FALSE;
  134.            break;
  135.         case 'F':
  136.            bFormat = TRUE;
  137.         }
  138.       }
  139.  
  140.    /* install critical error handler */
  141.    setint24 (&crterror);
  142.  
  143.    /* perform media check on source drive */
  144.    while ( !drvinfo(szDrive1 [0] - '@', &drv1))
  145.       {
  146.       if (!crterror)
  147.      {
  148.      sprintf (szMsg, "Source drive %c: not valid", *szDrive1);
  149.      ErrExit (szMsg);
  150.      }
  151.       crterror = 0;
  152.       printf("\r\7Error reading source disk %c:  Retry? (Y/N)  \b", *szDrive1);
  153.       if (toupper (getche()) != 'Y')
  154.      ErrExit ("");
  155.       }
  156.  
  157.    /* perform media check on target drive */
  158.    while ( !drvinfo(szDrive2 [0] - '@', &drv2))
  159.       {
  160.       if (!crterror)
  161.      {
  162.      sprintf (szMsg, "Target drive %c: not valid", *szDrive2);
  163.      ErrExit (szMsg);
  164.      }
  165.  
  166.       if (!bFormat)
  167.      {
  168.      printf("\r\7Error reading target disk %c:  Retry? (Y/N)  \b", *szDrive2);
  169.      if (toupper (getche()) == 'Y')
  170.         continue;
  171.      printf ("\rDo you wish to format disk in drive %c: ? (Y/N) ",*szDrive2);
  172.      bFormat = (toupper (getche()) == 'Y');
  173.      }
  174.  
  175.       if (crterror && bFormat)
  176.      {
  177.      switch (LOBYTE(_osversion))
  178.         {
  179.         case 3:
  180.            strcpy(szMsg, "/H");
  181.            break;
  182.         case 4:
  183.            strcpy(szMsg, "/AUTOTEST");
  184.            break;
  185.         default:
  186.            szMsg[0] = '\0';
  187.         }
  188.      printf("\rFormatting %s                                     \n", szDrive2);
  189.      spawnlp(P_WAIT,"format.com", "format.com", szDrive2, szMsg, NULL);
  190.      }
  191.       else
  192.      {
  193.      ErrExit("");
  194.      }
  195.       crterror = 0;
  196.       bFormat = FALSE;
  197.       }
  198.  
  199.    /* de-install critical error handler here */
  200.    restint24 ();
  201.  
  202.    /* check results of previous media check */
  203.    if (bCheck)
  204.       {
  205.       if (drv2.type == 0x0f8)
  206.      {
  207.      errno = EACCES;
  208.      sprintf(szMsg, "Targetdrive %c: is a fixed disk", *szDrive2);
  209.      ErrExit(szMsg);
  210.      }
  211.  
  212.       if (drv1.lDataSize > drv2.lDiskSpace)
  213.      {
  214.      sprintf (szMsg, "Source drive %c: data too large for target drive %c",
  215.               *szDrive1, *szDrive2);
  216.      ErrExit(szMsg);
  217.      }
  218.       }
  219.  
  220.    if (bPrompt)
  221.       {
  222.       printf ("\rWARNING: all data on drive %c will be deleted.  Do you wish to continue? (Y/N) ", *szDrive2);
  223.       if (toupper (getche()) != 'Y')
  224.      exit(1);
  225.       }
  226.  
  227.    volcopy (szDrive1[0] - '@', szDrive2 [0] - '@');
  228.  
  229.    printf ("\rDeleting files and directories on drive %c:"
  230.        "                                     \r", *szDrive2);
  231.    strcat (szDrive2, "\\");
  232.    chdir (szDrive2);
  233.    strcat (szDrive2, "*.*");
  234.    DelAll(szDrive2, _A_NORMAL | _A_RDONLY | _A_HIDDEN | _A_SYSTEM);
  235.  
  236.    /* Allocate file buffer */
  237.    nBufSize = _memmax();
  238.    pSource = malloc (nBufSize);
  239.  
  240.    if (pSource == NULL)
  241.       {
  242.       ErrExit ("Insufficient memory available");
  243.       }
  244.  
  245.    nNumFiles = 0;
  246.    szDrive1 [2] = '\0';
  247.    szDrive2 [2] = '\0';
  248.    printf ("Copying files and directories from drive %c: to %c:\n%s\\\n", *szDrive1, *szDrive2, szDrive2);
  249.    strcat (szDrive1, "\\*.*");
  250.    strcat (szDrive2, "\\*.*");
  251.    CopyAll(szDrive1, szDrive2, _A_NORMAL | _A_RDONLY | _A_HIDDEN | _A_SYSTEM);
  252.    free(pSource);
  253.    printf(" %d file(s) copied                            \n", nNumFiles);
  254.    }
  255.  
  256. void ErrExit (char *msg)
  257.    {
  258.    fprintf(stderr, "\nError %d--%s%s", errno, _strerror(msg), szSyntaxMsg);
  259.    exit(errno);
  260.    }
  261.  
  262.  
  263. BOOL DelAll(
  264.    PSTR     szFileSpec,
  265.    WORD     wAttributes)
  266.    {
  267.    BOOL     bContinue;
  268.    WORD     wEntry, wDirEntries;
  269.    struct find_t     DirEntry;
  270.    char     szPath[64], szSpec[64], szEntry[64],
  271.         szCurFile [64], szCurDir [64];
  272.  
  273.    /* initialization */
  274.    bContinue = TRUE;
  275.    wDirEntries = 0;
  276.  
  277.    /* separate file spec into path and wildcards */
  278.    for (wEntry=strlen(szFileSpec)-1; szFileSpec[wEntry]!='\\'; wEntry-- );
  279.  
  280.    strcpy( szPath, szFileSpec );
  281.    szPath[wEntry] = 0;
  282.  
  283.    strcpy( szCurFile, szFileSpec );
  284.    szCurFile[wEntry + 1] = 0;
  285.  
  286.    strcpy( szSpec, &szFileSpec[wEntry+1] );
  287.  
  288.    /* perform search for normal files */
  289.    if ( _dos_findfirst(szFileSpec,wAttributes,&DirEntry) == 0 )
  290.       {
  291.       /* repeat until all entries exhausted */
  292.       do {
  293.          /* output current file name */
  294.      szCurFile[wEntry + 1] = 0;
  295.      strcat (szCurFile, DirEntry.name);
  296.      if (DirEntry.attrib != _A_NORMAL || DirEntry.attrib != _A_ARCH)
  297.         _dos_setfileattr (szCurFile, _A_NORMAL);
  298.      unlink (szCurFile);
  299.      } while ( _dos_findnext(&DirEntry) == 0 );
  300.       }
  301.  
  302.    /* perform search for sub-directories */
  303.    sprintf( szEntry, "%s\\*.*", szPath );
  304.    if ( _dos_findfirst(szEntry,_A_SUBDIR | _A_NORMAL | _A_RDONLY | _A_HIDDEN | _A_SYSTEM, &DirEntry) == 0 )
  305.       {
  306.       /* repeat until all entries exhausted */
  307.       do {
  308.          /* eliminate special directory entries */
  309.      if ( (DirEntry.attrib & _A_SUBDIR) && (DirEntry.name[0]!='.') )
  310.         {
  311.         sprintf( szEntry, "%s\\%s\\%s", szPath, DirEntry.name, szSpec );
  312.         sprintf( szCurDir, "%s\\%s", szPath, DirEntry.name);
  313.         bContinue = DelAll( szEntry, wAttributes );
  314.         rmdir (szCurDir);
  315.         }
  316.      } while ( (bContinue)&&(_dos_findnext(&DirEntry) == 0) );
  317.       }
  318.  
  319.    /* return final result */
  320.    return( bContinue );
  321.    }
  322.  
  323.  
  324. BOOL CopyAll(
  325.    PSTR     szFileSpec1,
  326.    PSTR     szFileSpec2,
  327.    WORD     wAttributes)
  328.    {
  329.    BOOL     bContinue;
  330.    WORD     wEntry, wDirEntries;
  331.  
  332.    struct find_t  DirEntry;
  333.    struct find_t near *pDirEntry;
  334.    char near      *pPos;
  335.    int          hSource, hTarget;
  336.    size_t      nRead, nWrite, nNumRead, nNumWrite;
  337.    long       lTotRead, lTotWrite;
  338.    int          n, nFiles;
  339.  
  340.    char     szPath[64], szSpec[64], szEntry[64],
  341.         szCurFile [68], szNewFile [68], szNewDir [64];
  342.  
  343.  
  344.    /* initialization */
  345.    bContinue = TRUE;
  346.    wDirEntries = 0;
  347.  
  348.    /* separate file spec into path and wildcards */
  349.    for (wEntry=strlen(szFileSpec1)-1; szFileSpec1[wEntry]!='\\'; wEntry-- );
  350.  
  351.    strcpy( szPath, szFileSpec1 );
  352.    szPath[wEntry] = 0;
  353.  
  354.    strcpy( szCurFile, szFileSpec1 );
  355.    szCurFile[wEntry + 1] = 0;
  356.  
  357.    strcpy( szNewFile, szFileSpec1 );
  358.    szNewFile[wEntry + 1] = 0;
  359.    szNewFile[0] = szFileSpec2[0];
  360.  
  361.    strcpy( szSpec, &szFileSpec1[wEntry+1] );
  362.  
  363.    lTotRead = 0L;
  364.    lTotWrite = 0;
  365.  
  366.    /* perform search for normal files */
  367.    if ( _dos_findfirst(szFileSpec1,wAttributes,&DirEntry) == 0 )
  368.       {
  369.       /* repeat until all entries exhausted */
  370.       do {
  371.      nFiles = 0;
  372.      pPos = pSource;
  373.  
  374.      while (pPos + (sizeof (DirEntry) * 2) < pSource + nBufSize)
  375.         {
  376.         /* copy DirEntry into buffer */
  377.         memcpy (pPos, &DirEntry, sizeof (DirEntry) );
  378.         pDirEntry = pPos;
  379.         pPos += sizeof (DirEntry);
  380.  
  381.         /* Open source file */
  382.         szCurFile[wEntry + 1] = '\0';
  383.         strcat (szCurFile, DirEntry.name);
  384.         if (lTotRead == 0L)
  385.            {
  386.            if (_dos_open (szCurFile, O_RDONLY, &hSource) != 0)
  387.           {
  388.           sprintf (szMsg, "Could not open file %s", szCurFile);
  389.           ErrExit(szMsg);
  390.           }
  391.            }
  392.  
  393.         /* read as much of file into buffer as possible */
  394.         if(_dos_read(hSource, pPos, nBufSize - (pPos - pSource), &nNumRead) != 0)
  395.            {
  396.            sprintf (szMsg, "Error reading file %s", szCurFile);
  397.            ErrExit (szMsg);
  398.            }
  399.  
  400.         pPos += nNumRead;
  401.         lTotRead += (long) nNumRead;
  402.         nFiles++;
  403.         printf(" %-12s %7ld bytes read   \r",
  404.             pDirEntry->name,
  405.             lTotRead);
  406.  
  407.         if (lTotRead == DirEntry.size)
  408.            {
  409.            _dos_close (hSource);
  410.            lTotRead = 0L;
  411.            if (_dos_findnext(&DirEntry) != 0)
  412.           break;
  413.            }
  414.         else
  415.            break;
  416.         }
  417.  
  418.      /* Write new files */
  419.      /* position of first file */
  420.      pDirEntry = pSource;
  421.      pPos = pSource + sizeof (DirEntry);
  422.      for (n = 0; n < nFiles; n++)
  423.         {
  424.         /* check to see if we are finishing a file.. */
  425.         if (lTotWrite == 0)
  426.            {
  427.            szNewFile[wEntry + 1] = '\0';
  428.            strcat (szNewFile, pDirEntry->name);
  429.  
  430.            if (_dos_creat (szNewFile, pDirEntry->attrib, &hTarget) != 0)
  431.           {
  432.           sprintf (szMsg, "Could not create file %s", szNewFile);
  433.           ErrExit (szMsg);
  434.           }
  435.            }
  436.  
  437.         if (pDirEntry->size > nBufSize - (pPos - pSource))
  438.            nWrite = nBufSize - (pPos - pSource);
  439.         else
  440.            nWrite = pDirEntry->size;
  441.  
  442.         if ( (pDirEntry->size - lTotWrite) < nWrite)
  443.            nWrite = (unsigned int) (pDirEntry->size - lTotWrite);
  444.  
  445.         if ( _dos_write (hTarget, pPos, nWrite, &nNumWrite) != 0 )
  446.            {
  447.            sprintf (szMsg, "Error writing file %s", szNewFile);
  448.            ErrExit (szMsg);
  449.            }
  450.         if (nNumWrite != nWrite)
  451.            {
  452.            sprintf (szMsg, "Error writing file %s", szNewFile);
  453.            ErrExit (szMsg);
  454.            }
  455.  
  456.         lTotWrite += (long) nNumWrite;
  457.  
  458.         pPos += (unsigned long) nWrite;
  459.  
  460.         printf(" %-12s %7ld bytes written\r",
  461.             pDirEntry->name,
  462.             lTotWrite);
  463.  
  464.         if (lTotWrite == pDirEntry->size)
  465.            {
  466.            lTotWrite = 0L;
  467.            _dos_setftime( hTarget, pDirEntry->wr_date, pDirEntry->wr_time);
  468.            _dos_close (hTarget);
  469.            nNumFiles++;
  470.            }
  471.  
  472.         pDirEntry = pPos;
  473.         pPos += sizeof (DirEntry);
  474.         }
  475.  
  476.      } while ( lTotRead != 0L || _dos_findnext(&DirEntry) == 0 );
  477.       }
  478.  
  479.    /* perform search for sub-directories */
  480.    sprintf( szEntry, "%s\\*.*", szPath );
  481.    if ( _dos_findfirst(szEntry,_A_SUBDIR | _A_NORMAL | _A_RDONLY | _A_HIDDEN | _A_SYSTEM, &DirEntry) == 0 )
  482.       {
  483.       /* repeat until all entries exhausted */
  484.       do {
  485.          /* eliminate special directory entries */
  486.      if ( (DirEntry.attrib & _A_SUBDIR) && (DirEntry.name[0]!='.') )
  487.         {
  488.         sprintf( szEntry, "%s\\%s\\%s", szPath, DirEntry.name, szSpec );
  489.         sprintf( szNewDir, "%s\\%s", szPath, DirEntry.name);
  490.  
  491.         szNewDir [0] = szFileSpec2 [0];
  492.         mkdir (szNewDir);
  493.         _dos_setfileattr(szNewDir, DirEntry.attrib);
  494.  
  495.         printf("%s%s\n", szNewDir, "                                          ");
  496.         bContinue = CopyAll( szEntry,szFileSpec2, wAttributes );
  497.         }
  498.      } while ( (bContinue)&&(_dos_findnext(&DirEntry) == 0) );
  499.       }
  500.  
  501.    /* return final result */
  502.    return( bContinue );
  503.    }
  504.