Category : OS/2 Files
Archive   : DSKCPY2A.ZIP
Filename : DSKCPY2.C

 
Output of file : DSKCPY2.C contained in archive : DSKCPY2A.ZIP
#include
#include
#include
#include
#include

#define INCL_BASE
#define INCL_DOSDEVIOCTL
#include

/* ------------------------------------------------------------------------ */

#define READ_SOURCE 1
#define COPY_TARGET 2
#define EXIT_DSKCPY -1

#define DSKCPY_ERROR_WRONG_FORMAT 0xffbf
// #define DSKCPY_ERROR_CANT_FORMAT 0xffbe /* Remove this definition when */
/* the format problem is fixed */

#define BUFSIZE 1024
#define OPENFLAGS (OPEN_FLAGS_DASD | OPEN_SHARE_DENYREADWRITE | OPEN_ACCESS_READWRITE)

/* Note, for the lockdrive/unlockdrive macros, the global variable _lockCmd
** must be accessable and set to zero!
*/
#define lockdrive(hf) (_DosError = DosDevIOCtl(0L, &_lockCmd, DSK_LOCKDRIVE, IOCTL_DISK, hf))
#define unlockdrive(hf) (_DosError = DosDevIOCtl(0L, &_lockCmd, DSK_UNLOCKDRIVE, IOCTL_DISK, hf))


/* --------------------------------------------------------------------------
** This structure is used instead of the BIOSPARAMETERBLOCK because the
** definition of that structure in some copies of bsedev.h is wrong! It
** seems to be missing the BYTE abReserved[6] field.
*/
typedef struct _BSPBLK
{
USHORT usBytesPerSector;
BYTE bSectorsPerCluster;
USHORT usReservedSectors;
BYTE cFATs;
USHORT cRootEntries;
USHORT cSectors;
BYTE bMedia;
USHORT usSectorsPerFAT;
USHORT usSectorsPerTrack;
USHORT cHeads;
ULONG cHiddenSectors;
ULONG cLargeSectors;
BYTE abReserved[6];
USHORT cCylinders;
BYTE bDeviceType;
USHORT fsDeviceAttr;
} BSPBLK;


/* Global variables ------------------------------------------------------ */

USHORT _DosError = 0; /* Most recent error code */
BYTE _lockCmd = 0; /* Used with [un]lockdrive macros */
ULONG _fmtData = 0L; /* Used with DSK_FORMATVERIFY */
/* (kudos to RMK!) */

BSPBLK sourceParms; /* Param block for source drive */
PBYTE *sourceBuffer; /* Array of pointers to track buffers */
ULONG sourceBytes; /* # bytes on source disk */
USHORT sourceTracks; /* # tracks on source disk */
USHORT bytesPerTrack; /* Bytes per track on source disk */
PTRACKLAYOUT sourceLayout; /* Pointer to track layout table */
USHORT sizeofLayoutElement; /* Total size of layout table */
int gotSource = FALSE; /* Bool: Source disk has been read */

BSPBLK targetParms; /* Param block for target disk */


/* Prototypes ------------------------------------------------------------ */

void copyr(void);
int query(char *fmt, ... );
HFILE opendrive(char *drive);
int readsource(HFILE hf);
BYTE fmttbl_bytessec(USHORT bytesPerSec);
int writetarget(HFILE hf);
int bspblkcmp(BSPBLK *blk1, BSPBLK *blk2);
void *Alloc(unsigned num, unsigned size);
void errorexit(HFILE hf);
int dskcpy_menu(int mlevel, char *drive);
int main(int argc, char **argv);


/* Code ------------------------------------------------------------------ */

/* -- Logon message --- */
void copyr()
{

puts("DskCpy2 -- Alternative disk copier for OS/2");
puts("Brady Flowers, Mankato, MN\n");
}



/* --- Print a formatted string, get a key and return the keycode --- */
int query(char *fmt, ... )
{
int ch;
va_list args;

va_start(args, fmt);
vprintf(fmt, args);
ch = getch();
puts("");
return ch;
}



/* --- Open disk drive ---
** parameter is asciiz drive specifier, i.e., "a:"
** returns handle to open drive or 0, sets/clears _DosError
*/
HFILE opendrive(char *drive)
{
USHORT result;
HFILE dHandle;

if ((strlen(drive) != 2) || (drive[1] != ':'))
_DosError = ERROR_INVALID_DATA;
else
do
{
_DosError = DosOpen(drive, &dHandle, &result, 0L, 0, FILE_OPEN, OPENFLAGS, 0L);
if (_DosError == ERROR_NOT_READY)
{
if ((query("Please place a disk in drive %s and strike any key (ESC to end)..", drive)) == 0x1b)
break;
}
else
break;
}
while (TRUE);

return _DosError ? 0 : dHandle;
}



/* --- Read source disk into memory ---
** parameter is drive handle as returned from opendrive()
** reads the entire source disk into memory allocating as it goes,
** when done sourceBuffer points to an array of buffer pointers,
** one for each track on the disk and each the the size of a track
** in bytes.
** sets global variables:
** gotSource
** sourceBytes
** sourceTracks
** bytesPerTrack
** sizeofLayoutElement
** sourceBuffer
** sourceLayout
** _DosError
** returns 0 if success else error code (_DosError)
*/
int readsource(HFILE hf)
{
BYTE _parmCmd = 1;
int trk, hd, cyl;

/* If this isn't the first time here, free memory from last time first */
if (gotSource)
{
for (trk = 0; trk < sourceTracks; trk++)
free(sourceBuffer[trk]);
free(sourceBuffer);
free(sourceLayout);
sourceBuffer = NULL;
sourceLayout = NULL;
gotSource = FALSE;
}

/* Get source disk parameters */
_DosError = DosDevIOCtl(&sourceParms, &_parmCmd, DSK_GETDEVICEPARAMS, IOCTL_DISK, hf);
if (!_DosError)
{
/* Set all the informational variables and build a track layout table
** for use with the following sector reads.
*/
sourceBytes = (ULONG)(sourceParms.usBytesPerSector) *
(ULONG)(sourceParms.cSectors);
sourceTracks = sourceParms.cSectors /
sourceParms.usSectorsPerTrack;
bytesPerTrack = sourceParms.usBytesPerSector *
sourceParms.usSectorsPerTrack;

sizeofLayoutElement = sizeof(TRACKLAYOUT) +
((2 * sizeof(USHORT)) *
(sourceParms.usSectorsPerTrack - 1));

if (sourceLayout = (PTRACKLAYOUT)Alloc(sizeofLayoutElement, sizeof(BYTE)))
{
sourceLayout->bCommand = 1;
sourceLayout->usFirstSector = 0;
sourceLayout->cSectors = sourceParms.usSectorsPerTrack;
for (trk = 0; trk < sourceParms.usSectorsPerTrack; trk++)
{
sourceLayout->TrackTable[trk].usSectorNumber = trk+1;
sourceLayout->TrackTable[trk].usSectorSize = sourceParms.usBytesPerSector;
}
}
else
errorexit(hf);

/* Allocate the array of BYTE pointers to hold the track data */
if ((sourceBuffer = (PBYTE *)Alloc(sourceTracks, sizeof(PBYTE))) == NULL)
errorexit(hf);

printf("Reading %d cylinders, %d heads, %d sectors, %d bytes per sector\n",
sourceTracks / sourceParms.cHeads, sourceParms.cHeads,
sourceParms.usSectorsPerTrack, sourceParms.usBytesPerSector);

/* For each track, allocate a buffer and read the sector into it */
for (trk = 0, cyl = 0; trk < sourceTracks; trk += sourceParms.cHeads, cyl++)
{
sourceLayout->usCylinder = cyl;
for (hd = 0; hd < sourceParms.cHeads; hd++)
{
printf("\rCylinder %d, Head %d", cyl, hd);
sourceLayout->usHead = hd;
if ((sourceBuffer[trk+hd] = (PBYTE)Alloc(bytesPerTrack, sizeof(BYTE))) == NULL)
errorexit(hf);
if (_DosError = DosDevIOCtl(sourceBuffer[trk+hd], sourceLayout, DSK_READTRACK, IOCTL_DISK, hf))
errorexit(hf);
}
}

puts("\rDone. \n");
gotSource = TRUE;
}

return _DosError;
}



/* --- Translate bytes per sector into 0-3 code ---
** the four sector sizes listed below are alluded to in the OS/2
** docs however only 512 byte sectors are allowed under OS/2 1.x
** returns the code or -1 and sets _DosError
*/
BYTE fmttbl_bytessec(USHORT bytesPerSec)
{

_DosError = NO_ERROR;
switch (bytesPerSec)
{
case 128: return 0;
case 256: return 1;
case 512: return 2;
case 1024: return 3;
}
_DosError = ERROR_BAD_FORMAT;
return -1;
}



/* --- write information read by readsource() onto target disk ---
** parameter is drive handle as returned by opendrive()
** checks the target disk, if it's the same format as the source
** or not formatted at all, write the information contained in
** sourceBuffer formatting if neccessary.
** returns 0 if successful else errorcode (_DosError)
**
** -------------------------------------------------------------------
** NOTE: THIS ROUTINE, AS WRITTEN WORKS FINE IF IT DOESN'T HAVE TO
** FORMAT THE DISK. IT FAILS ON THE FIRST CALL TO DosDevIOCtl
** WITH THE DSK_FORMATVERIFY PARAMETER.
** -------------------------------------------------------------------
*/
int writetarget(HFILE hf)
{
BYTE _parmCmd = 1;
PTRACKFORMAT trkfmt;
USHORT sizeofTrkfmt;
int i, trk, hd, cyl, needFormat = FALSE;

/* Get target disk parameters */
_DosError = DosDevIOCtl(&targetParms, &_parmCmd, DSK_GETDEVICEPARAMS, IOCTL_DISK, hf);

if (_DosError == ERROR_READ_FAULT)
{
#if defined (DSKCPY_ERROR_CANT_FORMAT)
_DosError = DSKCPY_ERROR_CANT_FORMAT;
#else
/* If the disk needs formatting we build a format table for it based
** on the source disk.
*/
needFormat = TRUE;
_DosError = 0;
sizeofTrkfmt = sizeof(TRACKFORMAT) +
((4 * sizeof(BYTE)) *
(sourceParms.usSectorsPerTrack - 1));
if ((trkfmt = (PTRACKFORMAT)Alloc(sizeofTrkfmt, sizeof(BYTE))) == NULL)
errorexit(hf);
trkfmt->bCommand = 1;
trkfmt->cSectors = sourceParms.usSectorsPerTrack;
for (trk = 0; trk < trkfmt->cSectors; trk++)
{
trkfmt->FormatTable[trk].idSector = (BYTE)(trk+1);
trkfmt->FormatTable[trk].bBytesSector = fmttbl_bytessec(sourceParms.usBytesPerSector);
}
#endif
}
else if (!_DosError)
/* Else if no other error, make sure that the target disk is the same
** format as the source.
*/
if (bspblkcmp(&sourceParms, &targetParms))
_DosError = DSKCPY_ERROR_WRONG_FORMAT;


if (!_DosError)
{
printf("Writing %d cylinders, %d heads, %d sectors, %d bytes per sector\n",
sourceTracks / sourceParms.cHeads, sourceParms.cHeads,
sourceParms.usSectorsPerTrack, sourceParms.usBytesPerSector);
if (needFormat)
puts("Formatting while copying.");

for (trk = 0, cyl = 0; trk < sourceTracks; trk += sourceParms.cHeads, cyl++)
{
sourceLayout->usCylinder = cyl;
for (hd = 0; hd < sourceParms.cHeads; hd++)
{
printf("\rCylinder %d, Head %d", cyl, hd);
sourceLayout->usHead = hd;
if (needFormat)
{
trkfmt->usHead = hd;

trkfmt->usCylinder = cyl;
for (i = 0; i < trkfmt->cSectors; i++)
{
trkfmt->FormatTable[i].bHead = (BYTE)hd;
trkfmt->FormatTable[i].bCylinder = (BYTE)cyl;
}

#if defined (DEBUG)
puts("");
printf("bCommand %d\n", trkfmt->bCommand);
printf("usHead %d\n", trkfmt->usHead);
printf("usCylinder %d\n", trkfmt->usCylinder);
printf("usReserved %d\n", trkfmt->usReserved);
printf("cSectors %d\n", trkfmt->cSectors);
getch();
for (i = 0; i < trkfmt->cSectors; i++)
{
printf(" ft[%d].bCylinder %d\n", i, trkfmt->FormatTable[i].bCylinder);
printf(" ft[%d].bHead %d\n", i, trkfmt->FormatTable[i].bHead);
printf(" ft[%d].idSector %d\n", i, trkfmt->FormatTable[i].idSector);
printf(" ft[%d].bBytesSector %d\n", i, trkfmt->FormatTable[i].bBytesSector);
getch();
}
printf("Ready.");
getch();
puts("");
#endif

if (_DosError = DosDevIOCtl(&_fmtData, trkfmt, DSK_FORMATVERIFY, IOCTL_DISK, hf))
errorexit(hf);
}
if (_DosError = DosDevIOCtl(sourceBuffer[trk+hd], sourceLayout, DSK_WRITETRACK, IOCTL_DISK, hf))
errorexit(hf);
}
}

puts("\rDone. \n");
if (needFormat) free(trkfmt);
}

return _DosError;
}



/* --- compare two BSPBLK structures ---
** returns 0 if both are the same except for possibly the
** abReserved field, else returns non-zero.
*/
int bspblkcmp(BSPBLK *blk1, BSPBLK *blk2)
{
BSPBLK tmp1, tmp2;

tmp1 = *blk1;
tmp2 = *blk2;
memset(tmp1.abReserved, 0, 6);
memset(tmp2.abReserved, 0, 6);
return memcmp(&tmp1, &tmp2, sizeof(BSPBLK));
}



/* --- calloc type routine ---
** sets _DosError to ERROR_NOT_ENOUGH_MEMORY upon failure
*/
void *Alloc(unsigned num, unsigned size)
{
void *rVal;

_DosError = NO_ERROR;
if ((rVal = calloc(num, size)) == NULL)
_DosError = ERROR_NOT_ENOUGH_MEMORY;

return rVal;
}



/* --- error handler ---
** parameter is disk handle as returned from opendrive()
** prints system error message if possible, closes the disk
** handle if neccessary, gets a key stroke, and exits.
*/
void errorexit(HFILE hf)
{
USHORT cbBuf;
CHAR *msgBuf;

if (_DosError == DSKCPY_ERROR_WRONG_FORMAT)
{
/* Special handling for this non-fatal error */
fprintf(stderr, "\nThe TARGET disk is not the correct format!");
fprintf(stderr, "\nStrike any key to return to menu..");
getch();
fprintf(stderr, "\n\n");
return;
}

#if defined (DSKCPY_ERROR_CANT_FORMAT)
if (_DosError == DSKCPY_ERROR_CANT_FORMAT)
{
/* Special handling for this non-fatal error */
fprintf(stderr, "\nThe TARGET disk must be preformatted!");
fprintf(stderr, "\nStrike any key to return to menu..");
getch();
fprintf(stderr, "\n\n");
return;
}
#endif

puts("");
if ((msgBuf = (PCHAR)calloc(BUFSIZE, sizeof(CHAR))) != NULL)
{
DosGetMessage(NULL, 0, msgBuf, BUFSIZE, _DosError, "oso001.msg", &cbBuf);
fputs(msgBuf, stderr);
free(msgBuf);
}
else
fprintf(stderr, "SYS%04d: error text unavailable\n", _DosError);

if (hf) DosClose(hf);
fprintf(stderr, "Strike any key to exit..");
getch();
fprintf(stderr, "\n");
DosExit(EXIT_PROCESS, _DosError);
}



/* --- _very_ simpleminded menu ---
** parameters are: mlevel: TRUE if source has been read
** drive: asciiz drive specifier, i.e., "a:"
** returns READ_SOURCE, COPY_TARGET, or EXIT_DSKCPY
*/
int dskcpy_menu(int mlevel, char *drive)
{
int ch;

printf(" 1. Read SOURCE disk into memory from drive %s\n", drive);
if (mlevel)
printf(" 2. Copy memory image to TARGET disk in drive %s\n", drive);
puts(" Q. Exit DskCpy2\n");
printf("Enter Choice --> ");
do
switch (ch = getch())
{
case 'R':
case 'r':
case '1':
puts("Read\n");
ch = READ_SOURCE;
break;

case 'C':
case 'c':
case '2':
if (mlevel)
{
puts("Copy\n");
ch = COPY_TARGET;
}
else
ch = 0;
break;

case 'Q':
case 'q':
case '\x1b':
puts("Exit\n");
ch = EXIT_DSKCPY;
break;

default:
ch = 0;
}
while (!ch);
return ch;
}



int main(int argc, char **argv)
{
HFILE dHandle;
char *drive = "a:";
int choice;

copyr();
if ((argc > 2) || ((argc == 2) && (argv[1][1] != ':')))
{
fputs("usage: dskcpy2 drive_letter:", stderr);
exit(1);
}

if (argc == 2)
drive = argv[1];

DosError(HARDERROR_DISABLE);
do
{
choice = dskcpy_menu(gotSource, drive);
switch (choice)
{
case READ_SOURCE:
query("Place SOURCE disk in drive %s and strike any key when ready..", drive);
if ((dHandle = opendrive(drive)) == 0) errorexit(dHandle);
if (lockdrive(dHandle)) errorexit(dHandle);
if (readsource(dHandle)) errorexit(dHandle);
if (unlockdrive(dHandle)) errorexit(dHandle);
DosClose(dHandle);
break;
case COPY_TARGET:
query("Place TARGET disk in drive %s and strike any key when ready..", drive);
if ((dHandle = opendrive(drive)) == 0) errorexit(dHandle);
if (lockdrive(dHandle)) errorexit(dHandle);
if (writetarget(dHandle)) errorexit(dHandle);
if (unlockdrive(dHandle)) errorexit(dHandle);
DosClose(dHandle);
break;
default:
break;
}
}
while (choice != EXIT_DSKCPY);

return _DosError;
}



  3 Responses to “Category : OS/2 Files
Archive   : DSKCPY2A.ZIP
Filename : DSKCPY2.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/