home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 11 Util
/
11-Util.zip
/
PMFLOPPY.ZIP
/
DSKCPY.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-04-24
|
18KB
|
562 lines
#define INCL_DOSERRORS
#define INCL_DOSPROCESS
#define INCL_BASE
#define INCL_DOSDEVIOCTL
#define INCL_DOSSESMGR
#define INCL_DOSMISC
#include <os2.h>
#include <malloc.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "pmfloppy.h"
/* Global variables ------------------------------------------------------ */
// PM vbls
extern HWND hWndFrame ;
// Disk handling vbls
extern int gotSource; /* Bool: Source disk has been read */
// user response vbls
extern USHORT FormatOptions; // Bit map indicating formatting choice
extern CHAR Volume[11]; // Volume Name
// "local" global vbls
BYTE _lockCmd; /* Used with [un]lockdrive macros */
ULONG _fmtData; /* 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 */
USHORT DiskError;
/* Prototypes ------------------------------------------------------------ */
VOID FAR readsource(USHORT);
VOID FAR writetarget(USHORT);
VOID FAR fmtdisk(USHORT);
BYTE fmttbl_bytessec(USHORT bytesPerSec);
int bspblkcmp(BSPBLK *blk1, BSPBLK *blk2);
void far *Alloc(unsigned num, unsigned size);
void ThreadErrorHandler(USHORT, USHORT, HFILE);
VOID fatset(int, CHAR *,int,int);
/* Code ------------------------------------------------------------------ */
/* --- 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
** DiskError
*/
VOID FAR readsource(USHORT Drive)
{
BYTE _parmCmd = 1;
USHORT trk, hd, cyl;
HFILE dHandle;
USHORT result;
static CHAR szdrive[] = "A:";
DiskError = 0;
/* 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(HARDERROR_DISABLE);
szdrive[0] = (CHAR) Drive;
DiskError = DosOpen(szdrive, &dHandle, &result, 0L, 0, FILE_OPEN, OPENFLAGS, 0L);
if (DiskError)
ThreadErrorHandler(UM_READERROR, Drive, dHandle);
lockdrive(dHandle);
if (DiskError)
ThreadErrorHandler(UM_READERROR, Drive, dHandle);
DiskError = DosDevIOCtl(&sourceParms, &_parmCmd, DSK_GETDEVICEPARAMS, IOCTL_DISK, dHandle);
if (!DiskError)
{
/* 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
ThreadErrorHandler(UM_READERROR, Drive, dHandle);
/* Allocate the array of BYTE pointers to hold the track data */
if ((sourceBuffer = (PBYTE *)Alloc(sourceTracks, sizeof(PBYTE))) == NULL)
ThreadErrorHandler(UM_READERROR, Drive, dHandle);
/* 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++)
{
WinPostMsg(hWndFrame,UM_READSTATUS,
MPFROM2SHORT((cyl*2)+hd,sourceTracks),MPFROMSHORT(Drive));
sourceLayout->usHead = hd;
if ((sourceBuffer[trk+hd] = (PBYTE)Alloc(bytesPerTrack, sizeof(BYTE))) == NULL)
ThreadErrorHandler(UM_READERROR, Drive, dHandle);
if (DiskError = DosDevIOCtl(sourceBuffer[trk+hd], sourceLayout, DSK_READTRACK, IOCTL_DISK, dHandle))
ThreadErrorHandler(UM_READERROR, Drive, dHandle);
}
}
WinPostMsg(hWndFrame,UM_READMSG,MPFROMSHORT(0),MPFROMSHORT(Drive));
gotSource = TRUE;
}
else
WinPostMsg(hWndFrame,UM_READERROR,MPFROMSHORT(DiskError),MPFROMSHORT(Drive));
if (dHandle) DosClose(dHandle);
unlockdrive(dHandle);
DosError(HARDERROR_ENABLE);
DosExit(EXIT_THREAD, 0);
} // readsource
/* --- 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 DiskError
*/
BYTE fmttbl_bytessec(USHORT bytesPerSec)
{
DiskError = NO_ERROR;
switch (bytesPerSec)
{
case 128: return 0;
case 256: return 1;
case 512: return 2;
case 1024: return 3;
}
DiskError = 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 (DiskError)
**
*/
VOID FAR writetarget(USHORT Drive)
{
BYTE _parmCmd = 1;
PTRACKFORMAT trkfmt;
USHORT sizeofTrkfmt;
int i, trk, hd, cyl, needFormat = FALSE;
HFILE hf;
USHORT result;
static CHAR szdrive[] = "A:";
BSPBLK targetParms;
/* Get source disk parameters */
DosError(HARDERROR_DISABLE);
szdrive[0] = (CHAR) Drive;
DiskError = DosOpen(szdrive, &hf, &result, 0L, 0, FILE_OPEN, OPENFLAGS, 0L);
if (DiskError)
ThreadErrorHandler(UM_WRITEERROR, Drive, hf);
lockdrive(hf);
if (DiskError)
ThreadErrorHandler(UM_WRITEERROR, Drive, hf);
/* Get target disk parameters */
DiskError = DosDevIOCtl(&targetParms, &_parmCmd, DSK_GETDEVICEPARAMS, IOCTL_DISK, hf);
if ((DiskError == ERROR_READ_FAULT) && (FormatOptions == IDD_WRF_NEVER))
ThreadErrorHandler(UM_WRITEERROR, Drive, hf);
if (((DiskError == ERROR_READ_FAULT) && (FormatOptions == IDD_WRF_MAYBE)) ||
(FormatOptions == IDD_WRF_ALWAYS))
{
/* If the disk needs formatting we build a format table for it based
** on the source disk.
*/
needFormat = TRUE;
DiskError = 0;
/* 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;
sizeofTrkfmt = sizeof(TRACKFORMAT) +
((4 * sizeof(BYTE)) *
(sourceParms.usSectorsPerTrack - 1));
if ((trkfmt = (PTRACKFORMAT)Alloc(sizeofTrkfmt, sizeof(BYTE))) == NULL)
ThreadErrorHandler(UM_WRITEERROR, Drive, 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);
}
}
else if (!DiskError)
/* Else if no other error, make sure that the target disk is the same
** format as the source.
*/
if (bspblkcmp(&sourceParms, &targetParms))
DiskError = DSKCPY_ERROR_WRONG_FORMAT;
if (!DiskError)
{
for (trk = 0, cyl = 0; trk < sourceTracks; trk += sourceParms.cHeads, cyl++)
{
sourceLayout->usCylinder = cyl;
for (hd = 0; hd < sourceParms.cHeads; hd++)
{
WinPostMsg(hWndFrame,UM_WRITESTATUS,
MPFROM2SHORT((cyl*2)+hd,sourceTracks),MPFROMSHORT(Drive));
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 (DiskError = DosDevIOCtl(&_fmtData, trkfmt, DSK_FORMATVERIFY, IOCTL_DISK, hf))
ThreadErrorHandler(UM_WRITEERROR, Drive, hf);
}
if (DiskError = DosDevIOCtl(sourceBuffer[trk+hd], sourceLayout, DSK_WRITETRACK, IOCTL_DISK, hf))
ThreadErrorHandler(UM_WRITEERROR, Drive, hf);
}
}
WinPostMsg(hWndFrame,UM_WRITEMSG,MPFROMSHORT(0),MPFROMSHORT(Drive));
if (needFormat) free(trkfmt);
}
else
WinPostMsg(hWndFrame,UM_WRITEERROR,MPFROMSHORT(DiskError),MPFROMSHORT(Drive));
if (hf) DosClose(hf);
unlockdrive(hf);
DosError(HARDERROR_ENABLE);
DosExit(EXIT_THREAD, 0);
} //writetarget
// --- format a disk ---
// parameter is ascii char indicating drive
//
// This will currently format a disk, but track 0 needs some addt'l work
// to set up the FAT table and the directory table. Also, I couldn't find
// a way to detect an unformatted low density disk in a high density drive.
// The MS Format program requires the user to provide that info, but I've
// seen third party stuff that detects this. Perhaps they write the first
// track HD, then try to read it? Anyway, it's kind of interesting
// to actually run this and see what it does.
//
VOID FAR fmtdisk(USHORT Drive)
{
BYTE _getparmCmd = 0;
PTRACKFORMAT trkfmt;
PTRACKLAYOUT trklout;
USHORT sizeofTrkfmt;
int i, j, trk, hd, cyl, sec;
HFILE hf;
USHORT result;
static CHAR szdrive[] = "A:";
BSPBLK BPB;
USHORT fmtTracks; /* # tracks on source disk */
USHORT ReservedSize;
PBYTE *sectordata;
PCHAR fatptr;
USHORT fatlen;
PCHAR rootptr;
USHORT rootsize;
USHORT rootentries;
USHORT writesize;
USHORT skippedsectors;
USHORT maxcluster;
USHORT size;
LONG devicesize;
/* Get format disk parameters */
DosError(HARDERROR_DISABLE);
szdrive[0] = (CHAR) Drive;
DiskError = DosOpen(szdrive, &hf, &result, 0L, 0, FILE_OPEN, OPENFLAGS, 0L);
if (DiskError)
ThreadErrorHandler(UM_FMTERROR, Drive, hf);
lockdrive(hf);
if (DiskError)
ThreadErrorHandler(UM_FMTERROR, Drive, hf);
/* Get target drive parameters */
DiskError = DosDevIOCtl(&BPB, &_getparmCmd, DSK_GETDEVICEPARAMS, IOCTL_DISK, hf);
if (DiskError)
ThreadErrorHandler(UM_FMTERROR, Drive, hf);
// build a format table for the disk
fmtTracks = BPB.cSectors / BPB.usSectorsPerTrack;
sizeofTrkfmt = sizeof(TRACKFORMAT) +
((4 * sizeof(BYTE)) *
(BPB.usSectorsPerTrack - 1));
if ((trkfmt = (PTRACKFORMAT)Alloc(sizeofTrkfmt, sizeof(BYTE))) == NULL)
ThreadErrorHandler(UM_FMTERROR, Drive, hf);
trkfmt->bCommand = 1;
trkfmt->cSectors = BPB.usSectorsPerTrack;
for (trk = 0; trk < trkfmt->cSectors; trk++)
{
trkfmt->FormatTable[trk].idSector = (BYTE)(trk+1);
trkfmt->FormatTable[trk].bBytesSector = fmttbl_bytessec(BPB.usBytesPerSector);
}
if (!DiskError)
{
for (trk = 0, cyl = 0; trk < fmtTracks; trk += BPB.cHeads, cyl++)
{
for (hd = 0; hd < BPB.cHeads; hd++)
{
WinPostMsg(hWndFrame,UM_FMTSTATUS,
MPFROM2SHORT((cyl*2)+hd,fmtTracks),MPFROMSHORT(Drive));
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 (DiskError = DosDevIOCtl(&_fmtData, trkfmt, DSK_FORMATVERIFY, IOCTL_DISK, hf))
ThreadErrorHandler(UM_FMTERROR, Drive, hf);
}
free(trkfmt);
}
// Allocate space for track 0
bytesPerTrack = BPB.usBytesPerSector * BPB.usSectorsPerTrack;
if ((sectordata = (PBYTE *)Alloc(bytesPerTrack, sizeof(PBYTE))) == NULL)
ThreadErrorHandler(UM_READERROR, Drive, hf);
ReservedSize = BPB.usBytesPerSector * BPB.usReservedSectors;
for (sec=0;sec<ReservedSize;sec++)
*(sectordata+sec) = 0;
for (sec=0;sec<sizeof(BSPBLK); sec++)
*(sectordata+sec+11) = ((CHAR *)(&BPB))[sec];
strncpy((sectordata+3),"OS/2 ",8);
fatptr = sectordata + ReservedSize;
fatlen = BPB.usSectorsPerFAT * BPB.usBytesPerSector;
for (i=0;i<BPB.cFATs * fatlen;i++)
fatptr[i] = -1;
rootptr = fatptr + BPB.cFATs * fatlen;
rootsize = BPB.usBytesPerSector *
((BPB.usBytesPerSector - 1 + 32*BPB.cRootEntries)/BPB.usBytesPerSector);
rootentries = rootsize / 32;
writesize = ReservedSize + fatlen*BPB.cFATs + rootsize;
skippedsectors = writesize / BPB.usBytesPerSector;
if (BPB.cSectors != 0)
{
devicesize = BPB.cSectors * BPB.usBytesPerSector;
maxcluster = (BPB.cSectors - skippedsectors) / BPB.bSectorsPerCluster + 2;
if (BPB.cSectors <= 20740)
size = 12;
else
size = 16;
}
else
{
devicesize = BPB.cLargeSectors * BPB.usBytesPerSector;
maxcluster =
(BPB.cLargeSectors - skippedsectors) / BPB.bSectorsPerCluster + 2;
if (BPB.cLargeSectors <= 20740)
size = 12;
else
size = 16;
}
for (i=2;i<maxcluster;i++)
for (j=0;j<BPB.cFATs;j++)
fatset(size,fatptr+j*fatlen,i,0);
for (i=0;i<BPB.cFATs;i++)
{
fatset(size,fatptr+i*fatlen,0,BPB.bMedia);
fatset(size,fatptr+i*fatlen,1,-1);
}
for (i=0;i<rootentries;i++)
for (j=0;j<32;j++)
rootptr[i*32+j] = 0;
for (i=0;i<11;i++)
rootptr[i] = Volume[i];
rootptr[11] = 8;
// write track 0
sizeofLayoutElement = sizeof(TRACKLAYOUT) + ((2 * sizeof(USHORT)) *
(BPB.usSectorsPerTrack - 1));
if (trklout = (PTRACKLAYOUT)Alloc(sizeofLayoutElement, sizeof(BYTE)))
{
trklout->bCommand = 1;
trklout->cSectors = BPB.usSectorsPerTrack;
for (trk = 0; trk < BPB.usSectorsPerTrack; trk++)
{
trklout->TrackTable[trk].usSectorNumber = trk+1;
trklout->TrackTable[trk].usSectorSize = BPB.usBytesPerSector;
}
}
for (sec=0;sec<skippedsectors;sec++)
{
cyl = sec / (BPB.usSectorsPerTrack * BPB.cHeads);
hd = (sec - cyl*BPB.usSectorsPerTrack*BPB.cHeads) / BPB.usSectorsPerTrack;
trklout->usHead = hd;
trklout->usCylinder = cyl;
trklout->usFirstSector = (sec - cyl*BPB.usSectorsPerTrack*BPB.cHeads
- hd*BPB.usSectorsPerTrack);
if (DiskError = DosDevIOCtl(sectordata+sec*BPB.usBytesPerSector,trklout,
DSK_WRITETRACK,IOCTL_DISK,hf))
ThreadErrorHandler(UM_FMTERROR, Drive, hf);
}
free(trklout);
free(sectordata);
WinPostMsg(hWndFrame,UM_FMTMSG,MPFROMSHORT(0),MPFROMSHORT(Drive));
}
else
WinPostMsg(hWndFrame,UM_FMTERROR,MPFROMSHORT(DiskError),MPFROMSHORT(Drive));
if (hf) DosClose(hf);
unlockdrive(hf);
DosError(HARDERROR_ENABLE);
DosExit(EXIT_THREAD, 0);
} // fmtdisk
VOID fatset(int size, CHAR * start,int index,int value)
{
int byteindex;
int * fatword;
if (size == 16)
((int *)start)[index] = value;
else
{
byteindex = (3*index)/2;
fatword = (int *)(start + byteindex);
if ((index & 1) == 0)
*fatword = (*fatword & 0xf000) | (value & 0xfff);
else
*fatword = (*fatword & 0xf) | ((value & 0xfff)<<4);
}
}
/* --- 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 DiskError to ERROR_NOT_ENOUGH_MEMORY upon failure
*/
void far *Alloc(unsigned num, unsigned size)
{
void far *rVal;
DiskError = NO_ERROR;
if ((rVal = _fmalloc(num * size)) == NULL)
DiskError = ERROR_NOT_ENOUGH_MEMORY;
return rVal;
}
void ThreadErrorHandler(USHORT Msg, USHORT Drive, HFILE dHandle)
{
WinPostMsg(hWndFrame,Msg,MPFROMSHORT(DiskError),MPFROMSHORT(Drive));
if (dHandle) DosClose(dHandle);
unlockdrive(dHandle);
DosError(HARDERROR_ENABLE);
DosExit(EXIT_THREAD, 0);
}