940 lines
32 KiB
C
940 lines
32 KiB
C
|
/****************************************************************************/
|
||
|
/* */
|
||
|
/* WFDCOPY.C - */
|
||
|
/* */
|
||
|
/* File Manager Diskette Copying Routines */
|
||
|
/* */
|
||
|
/****************************************************************************/
|
||
|
|
||
|
#include "winfile.h"
|
||
|
|
||
|
LONG APIENTRY LongPtrAdd(LPSTR, DWORD);
|
||
|
|
||
|
PBPB GetBootBPB(INT nSrceDrive);
|
||
|
PBPB GetBPB(INT nDrive, PDevPB pDevicePB);
|
||
|
BOOL CheckBPBCompatibility(PBPB pSrceBPB, int nSrcDriveType, PBPB pDestBPB, int nDestDriveType);
|
||
|
|
||
|
BOOL ModifyDeviceParams(
|
||
|
INT nDrive,
|
||
|
PDevPB pdpbParams,
|
||
|
HANDLE *phSaveParams,
|
||
|
PBPB pDriveBPB,
|
||
|
PBPB pMediaBPB);
|
||
|
|
||
|
BOOL FormatAllTracks(
|
||
|
PDISKINFO pDisketteInfo,
|
||
|
WORD wStartCylinder,
|
||
|
WORD wStartHead,
|
||
|
LPSTR lpDiskBuffer);
|
||
|
|
||
|
BOOL AllocDiskCopyBuffers(PDISKINFO pDisketteInfo);
|
||
|
VOID FreeBuffers(VOID);
|
||
|
VOID GetDisketteInfo(PDISKINFO pDisketteInfo, PBPB pBPB);
|
||
|
VOID DCopyMessageBox(HWND hwnd, WORD idString, WORD wFlags);
|
||
|
VOID PromptDisketteChange(HWND hwnd, BOOL bWrite);
|
||
|
INT ReadWriteMaxPossible(BOOL bWrite, WORD wStartCylinder, PDISKINFO pDisketteInfo);
|
||
|
INT ReadWrite(BOOL bWrite, WORD wStartCylinder, PDISKINFO pDisketteInfo);
|
||
|
BOOL RestoreDPB(INT nDisk, HANDLE hSavedParams);
|
||
|
INT ReadWriteCylinder(BOOL bWrite, WORD wCylinder, PDISKINFO pDisketteInfo);
|
||
|
|
||
|
|
||
|
/* The following structure is the Parameter block for the read-write
|
||
|
* operations using the IOCTL calls in DOS
|
||
|
*/
|
||
|
struct RW_PARMBLOCK {
|
||
|
BYTE bSplFn;
|
||
|
WORD wHead;
|
||
|
WORD wCylinder;
|
||
|
WORD wStSector;
|
||
|
WORD wCount;
|
||
|
LPSTR lpBuffer;
|
||
|
};
|
||
|
|
||
|
/* Global Variables */
|
||
|
BOOL bFormatDone;
|
||
|
BOOL bSingleDrive = TRUE;
|
||
|
WORD wCompletedCylinders = 0;
|
||
|
DWORD dwDisketteBufferSize;
|
||
|
LPSTR lpDosMemory;
|
||
|
LPSTR lpFormatBuffer;
|
||
|
LPSTR lpReadWritePtr;
|
||
|
LPSTR hpDisketteBuffer;
|
||
|
HANDLE hFormatBuffer;
|
||
|
HANDLE hDosMemory;
|
||
|
HANDLE hDisketteBuffer;
|
||
|
PDevPB pTrackLayout; /* DevPB with the track layout */
|
||
|
BOOTSEC BootSec;
|
||
|
|
||
|
/* External Variables */
|
||
|
extern BPB bpbList[];
|
||
|
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* GetBootBPB() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
/* This reads the boot sector of a floppy and returns a ptr to
|
||
|
* the BIOS PARAMETER BLOCK in the Boot sector.
|
||
|
*/
|
||
|
|
||
|
PBPB
|
||
|
GetBootBPB(
|
||
|
INT nSrceDrive
|
||
|
)
|
||
|
{
|
||
|
INT rc;
|
||
|
|
||
|
/* Make sure that the source diskette's boot sector is valid. */
|
||
|
rc = GenericReadWriteSector((LPSTR)&BootSec, INT13_READ, (WORD)nSrceDrive, 0, 0, 1);
|
||
|
|
||
|
if ((rc < 0) || ((BootSec.jump[0] != 0xE9) && (BootSec.jump[0] != 0xEB)))
|
||
|
return (PBPB)NULL;
|
||
|
|
||
|
return (PBPB)&(BootSec.BPB);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* GetBPB() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
/* Gets get the BPB of the Physical Drive.
|
||
|
*
|
||
|
* This uses the IOCTL calls if DOS ver >= 3.2; Otherwise it uses the
|
||
|
* BIOS calls to find out the drive type and picks us the BPB from a table.
|
||
|
* It also returns the DeviceParameterBlock thro params if DOS >= 3.2.
|
||
|
* Sets devType field of DeviceParameterBlock in any case (11.12.91) v-dougk
|
||
|
*/
|
||
|
|
||
|
PBPB
|
||
|
GetBPB(
|
||
|
INT nDrive,
|
||
|
PDevPB pDevicePB
|
||
|
)
|
||
|
{
|
||
|
INT iDisketteType;
|
||
|
PBPB pBPB = NULL;
|
||
|
|
||
|
/* Check the DOS version */
|
||
|
if (wDOSversion >= DOS_320) {
|
||
|
/* All fields in pDevicePB must be initialized to zero. */
|
||
|
memset(pDevicePB, 0, sizeof(DevPB));
|
||
|
|
||
|
/* Spl Function field must be set to get parameters */
|
||
|
pDevicePB->SplFunctions = 0;
|
||
|
pBPB = &(pDevicePB->BPB);
|
||
|
} else {
|
||
|
/* Find out the Drive type using the BIOS. */
|
||
|
if ((iDisketteType = GetDriveCapacity((WORD)nDrive)) == 0)
|
||
|
goto GBPB_Error;
|
||
|
|
||
|
/* Lookup this drive's default BPB. */
|
||
|
pBPB = &bpbList[iDisketteType+2];
|
||
|
|
||
|
switch (iDisketteType) {
|
||
|
case 1:
|
||
|
pDevicePB->devType = 0; // 360K
|
||
|
break;
|
||
|
case 2:
|
||
|
pDevicePB->devType = 1; // 1.2M
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GBPB_Error:
|
||
|
return (pBPB);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* CheckBPBCompatibility() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
/* Checks whether the two BPB are compatible for the purpose of performing
|
||
|
* the diskcopy operation.
|
||
|
*/
|
||
|
|
||
|
BOOL
|
||
|
CheckBPBCompatibility(
|
||
|
PBPB pSrceBPB,
|
||
|
int nSrcDriveType,
|
||
|
PBPB pDestBPB,
|
||
|
int nDestDriveType
|
||
|
)
|
||
|
{
|
||
|
/* Let us compare the media byte */
|
||
|
if (pSrceBPB->bMedia == 0xF9) {
|
||
|
/* If the source and dest have the same number of sectors,
|
||
|
* or if srce is 720KB and Dest is 1.44MB floppy drive,
|
||
|
* thnigs are kosher.
|
||
|
*/
|
||
|
if ((pSrceBPB->cSec == pDestBPB->cSec) ||
|
||
|
((pSrceBPB->secPerTrack == 9) && (pDestBPB -> bMedia == 0xF0)))
|
||
|
return (TRUE);
|
||
|
} else {
|
||
|
/* If they have the same media byte */
|
||
|
if ((pSrceBPB->bMedia == pDestBPB->bMedia) &&
|
||
|
(pSrceBPB->cbSec == pDestBPB->cbSec) && // bytes per sector are the same
|
||
|
(pSrceBPB->cSec == pDestBPB->cSec)) // total sectors on drive are the same
|
||
|
return (TRUE); /* They are compatible */
|
||
|
else if
|
||
|
/* srce is 160KB and dest is 320KB drive */
|
||
|
(((pSrceBPB->bMedia == MEDIA_160) && (pDestBPB->bMedia == MEDIA_320)) ||
|
||
|
/* or if srce is 180KB and dest is 360KB drive */
|
||
|
((pSrceBPB->bMedia == MEDIA_180) && (pDestBPB->bMedia == MEDIA_360)) ||
|
||
|
/* or if srce is 1.44MB and dest is 2.88MB drive */
|
||
|
((pSrceBPB->bMedia == MEDIA_1440) && (pDestBPB->bMedia == MEDIA_2880)
|
||
|
&& ((nSrcDriveType == 7) || (nSrcDriveType == 9))
|
||
|
&& (nDestDriveType == 9)) ||
|
||
|
/* or if srce is 360KB and dest is 1.2MB drive */
|
||
|
((pSrceBPB->bMedia == MEDIA_360) && (pDestBPB->secPerTrack == 15)))
|
||
|
return (TRUE); /* They are compatible */
|
||
|
}
|
||
|
|
||
|
/* All other combinations are currently incompatible. */
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* ModifyDeviceParams() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
/* Saves a copy of the drive parameters block and
|
||
|
* Checks if the BPB of Drive and BPB of disk are different and if
|
||
|
* so, modifies the drive parameter block accordingly.
|
||
|
*/
|
||
|
|
||
|
BOOL
|
||
|
ModifyDeviceParams(
|
||
|
INT nDrive,
|
||
|
PDevPB pdpbParams,
|
||
|
HANDLE *phSaveParams,
|
||
|
PBPB pDriveBPB,
|
||
|
PBPB pMediaBPB)
|
||
|
{
|
||
|
INT iDriveCode;
|
||
|
HANDLE hNewDPB;
|
||
|
PDevPB pNewDPB;
|
||
|
|
||
|
if (!(*phSaveParams = BuildDevPB(pdpbParams)))
|
||
|
return FALSE;
|
||
|
|
||
|
/* Check if the Disk and Drive have the same parameters */
|
||
|
if (pMediaBPB->bMedia != pDriveBPB->bMedia) {
|
||
|
/* They are not equal; So, it must be a 360KB floppy in a 1.2MB drive
|
||
|
* or a 720KB floppy in a 1.44MB drive kind of situation!.
|
||
|
* So, modify the DriveParameterBlock's BPB.
|
||
|
*/
|
||
|
*(PBPB)&(pdpbParams->BPB) = *pMediaBPB;
|
||
|
}
|
||
|
|
||
|
if (wDOSversion >= DOS_320) {
|
||
|
/* Build a DPB with TrackLayout */
|
||
|
if (!(hNewDPB = BuildDevPB(pdpbParams)))
|
||
|
goto MDP_Error;
|
||
|
|
||
|
pNewDPB = (PDevPB)LocalLock(hNewDPB);
|
||
|
|
||
|
pNewDPB->SplFunctions = 4; /* To Set parameters */
|
||
|
|
||
|
/* Check if this is a 360KB floppy; And if it is a 1.2MB drive, the
|
||
|
* number of cylinders and mediatype field are wrong; So, we modify
|
||
|
* these fields here anyway;
|
||
|
* This is required to format a 360KB floppy on a NCR PC916 machine;
|
||
|
* Fix for Bug #6894 --01-10-90-- SANKAR
|
||
|
*/
|
||
|
if (pMediaBPB->bMedia == MEDIA_360) {
|
||
|
pNewDPB->NumCyls = 40;
|
||
|
pNewDPB->bMediaType = 1;
|
||
|
}
|
||
|
|
||
|
LocalUnlock(hNewDPB);
|
||
|
LocalFree(hNewDPB);
|
||
|
} else {
|
||
|
iDriveCode = 0;
|
||
|
switch (pMediaBPB->bMedia) {
|
||
|
case MEDIA_360:
|
||
|
case MEDIA_320:
|
||
|
if ((pDriveBPB->bMedia == MEDIA_360) ||
|
||
|
(pDriveBPB->bMedia == MEDIA_320))
|
||
|
iDriveCode = 1; /* Must be 360/320KB in 360KB drive */
|
||
|
else
|
||
|
iDriveCode = 2; /* Must be 360/320Kb in 1.2MB drive */
|
||
|
break;
|
||
|
|
||
|
case MEDIA_1200:
|
||
|
iDriveCode = 3; /* Must be 1.2MB in 1.2MB drive */
|
||
|
break;
|
||
|
}
|
||
|
if (iDriveCode)
|
||
|
SetDASD((WORD)nDrive, (BYTE)iDriveCode);
|
||
|
}
|
||
|
return (TRUE);
|
||
|
|
||
|
/* Error handling */
|
||
|
MDP_Error:
|
||
|
if (hNewDPB)
|
||
|
LocalFree(hNewDPB);
|
||
|
if (*phSaveParams) {
|
||
|
LocalFree(*phSaveParams);
|
||
|
*phSaveParams = NULL;
|
||
|
}
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* FormatAllTracks() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
BOOL
|
||
|
FormatAllTracks(
|
||
|
PDISKINFO pDisketteInfo,
|
||
|
WORD wStartCylinder,
|
||
|
WORD wStartHead,
|
||
|
LPSTR lpDiskBuffer)
|
||
|
{
|
||
|
INT iErrCode;
|
||
|
BOOL bRetValue = TRUE;
|
||
|
WORD wTotalCylinders;
|
||
|
WORD wSecPerTrack;
|
||
|
WORD wHeads;
|
||
|
WORD wDrive;
|
||
|
|
||
|
LoadString(hAppInstance, IDS_FORMATTINGDEST, szMessage, 128);
|
||
|
SendDlgItemMessage(hdlgProgress, IDD_PROGRESS, WM_SETTEXT, 0, (LPARAM)szMessage);
|
||
|
|
||
|
bFormatDone = TRUE;
|
||
|
wDrive = pDisketteInfo->wDrive;
|
||
|
|
||
|
if (wDOSversion >= DOS_320) {
|
||
|
pTrackLayout->SplFunctions = 5;
|
||
|
} else {
|
||
|
if ((pTrackLayout->BPB.bMedia == 0xF9) && /* high density */
|
||
|
(pTrackLayout->BPB.secPerTrack == 15)) /* 1.2 Meg Drive */
|
||
|
SetDASD(wDrive, 3); /* 1.2 MB floppy in 1.2MB drive */
|
||
|
}
|
||
|
|
||
|
wTotalCylinders = pDisketteInfo->wLastCylinder + 1;
|
||
|
wSecPerTrack = pDisketteInfo->wSectorsPerTrack;
|
||
|
wHeads = pDisketteInfo->wHeads;
|
||
|
|
||
|
/* Format tracks one by one, checking if the user has "Aborted"
|
||
|
* after each track is formatted; DlgProgreeProc() will set the global
|
||
|
* bUserAbort, if the user has aborted;
|
||
|
*/
|
||
|
while (wStartCylinder < wTotalCylinders) {
|
||
|
/* Has the user aborted? */
|
||
|
if (WFQueryAbort()) {
|
||
|
bRetValue = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* If no message is pending, go ahead and format one track */
|
||
|
if ((iErrCode = GenericFormatTrack(wDrive, wStartCylinder, wStartHead, wSecPerTrack, lpDiskBuffer))) {
|
||
|
/* Check if it is a fatal error */
|
||
|
if (iErrCode == -1) {
|
||
|
bRetValue = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (++wStartHead >= wHeads) {
|
||
|
wStartHead = 0;
|
||
|
wStartCylinder++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (wDOSversion >= DOS_320) {
|
||
|
pTrackLayout->SplFunctions = 4;
|
||
|
}
|
||
|
|
||
|
return (bRetValue);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* GenericReadWriteSector() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
/* Checks the DOS version number; If it is >= 3.2, then IOCTL
|
||
|
* calls are made to read/write; Else it calls int13 read/write.
|
||
|
*/
|
||
|
|
||
|
INT
|
||
|
APIENTRY
|
||
|
GenericReadWriteSector(
|
||
|
LPSTR lpBuffer,
|
||
|
WORD wFunction,
|
||
|
WORD wDrive,
|
||
|
WORD wCylinder,
|
||
|
WORD wHead,
|
||
|
WORD wCount)
|
||
|
{
|
||
|
struct RW_PARMBLOCK RW_ParmBlock;
|
||
|
|
||
|
/* If the DOS version is >= 3.2, we use DOS IOCTL function calls. */
|
||
|
if (wDOSversion >= DOS_320) {
|
||
|
RW_ParmBlock.bSplFn = 0;
|
||
|
RW_ParmBlock.wHead = wHead;
|
||
|
RW_ParmBlock.wCylinder = wCylinder;
|
||
|
RW_ParmBlock.wStSector = 0;
|
||
|
RW_ParmBlock.wCount = wCount;
|
||
|
RW_ParmBlock.lpBuffer = lpBuffer;
|
||
|
|
||
|
return (0);
|
||
|
} else
|
||
|
/* Use Int13 function calls. */
|
||
|
return (MyReadWriteSector(lpBuffer, wFunction, wDrive, wCylinder, wHead, wCount));
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* AllocDiskCopyBuffers() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
BOOL
|
||
|
AllocDiskCopyBuffers(
|
||
|
PDISKINFO pDisketteInfo
|
||
|
)
|
||
|
{
|
||
|
HANDLE hMemTemp;
|
||
|
|
||
|
ENTER("AllocDiskCopyBuffers");
|
||
|
|
||
|
hFormatBuffer = LocalAlloc(LHND, (LONG)(2*CBSECTORSIZE));
|
||
|
if (!hFormatBuffer)
|
||
|
return FALSE;
|
||
|
lpFormatBuffer = (LPSTR)LocalLock(hFormatBuffer);
|
||
|
|
||
|
// We will try to reserve 16K for dialog boxes that comeup during diskcopy
|
||
|
|
||
|
hMemTemp = LocalAlloc(LHND, (16 * 1024));
|
||
|
if (!hMemTemp)
|
||
|
goto Failure;
|
||
|
|
||
|
hDosMemory = (HANDLE)NULL;
|
||
|
|
||
|
// now, lets try to allocate a buffer for the whole disk, and
|
||
|
// if that fails try smaller
|
||
|
// note, standard mode will only give us 1M chuncks
|
||
|
|
||
|
dwDisketteBufferSize = pDisketteInfo->wCylinderSize * (pDisketteInfo->wLastCylinder + 1);
|
||
|
|
||
|
// we will try down to 8 cylinders worth, less than that means
|
||
|
// there will be too much disk swapping so don't bother
|
||
|
|
||
|
do {
|
||
|
hDisketteBuffer = LocalAlloc(LHND, dwDisketteBufferSize);
|
||
|
|
||
|
if (hDisketteBuffer) {
|
||
|
hpDisketteBuffer = (LPSTR)LocalLock(hDisketteBuffer);
|
||
|
break;
|
||
|
} else {
|
||
|
// reduce request by 4 cylinders.
|
||
|
dwDisketteBufferSize -= pDisketteInfo->wCylinderSize * 4;
|
||
|
}
|
||
|
|
||
|
} while (dwDisketteBufferSize > (DWORD)(8 * pDisketteInfo->wCylinderSize));
|
||
|
|
||
|
LocalFree(hMemTemp); // now free this up for user
|
||
|
|
||
|
if (hDisketteBuffer)
|
||
|
return TRUE;
|
||
|
|
||
|
// fall through here to the failure case
|
||
|
Failure:
|
||
|
|
||
|
if (lpFormatBuffer) {
|
||
|
LocalUnlock(hFormatBuffer);
|
||
|
LocalFree(hFormatBuffer);
|
||
|
}
|
||
|
|
||
|
if (hDosMemory)
|
||
|
// +++GlobalDosFree - NO 32BIT FORM+++(hDosMemory);
|
||
|
LocalFree(hDosMemory);
|
||
|
|
||
|
LEAVE("AllocDiskCopyBuffers");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* FreeBuffers() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
VOID
|
||
|
FreeBuffers()
|
||
|
{
|
||
|
if (lpFormatBuffer) {
|
||
|
LocalUnlock(hFormatBuffer);
|
||
|
LocalFree(hFormatBuffer);
|
||
|
}
|
||
|
|
||
|
if (hDosMemory)
|
||
|
// +++GlobalDosFree - NO 32BIT FORM+++(hDosMemory);
|
||
|
LocalFree(hDosMemory);
|
||
|
|
||
|
if (hpDisketteBuffer) {
|
||
|
LocalUnlock(hDisketteBuffer);
|
||
|
LocalFree(hDisketteBuffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* GetDisketteInfo() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
VOID
|
||
|
GetDisketteInfo(
|
||
|
PDISKINFO pDisketteInfo,
|
||
|
PBPB pBPB
|
||
|
)
|
||
|
{
|
||
|
WORD secPerTrack;
|
||
|
|
||
|
secPerTrack = pBPB->secPerTrack;
|
||
|
|
||
|
/* Fill the DisketteInfo with the info from the default BPB. */
|
||
|
pDisketteInfo->wCylinderSize = secPerTrack * pBPB->cbSec * pBPB->cHead;
|
||
|
pDisketteInfo->wLastCylinder = (pBPB->cSec / (secPerTrack * pBPB->cHead))-1;
|
||
|
pDisketteInfo->wHeads = pBPB->cHead;
|
||
|
pDisketteInfo->wSectorsPerTrack = secPerTrack;
|
||
|
pDisketteInfo->wSectorSize = pBPB->cbSec;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* DCopyMessageBox() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
VOID
|
||
|
DCopyMessageBox(
|
||
|
HWND hwnd,
|
||
|
WORD idString,
|
||
|
WORD wFlags
|
||
|
)
|
||
|
{
|
||
|
LoadString(hAppInstance, IDS_COPYDISK, szTitle, sizeof(szTitle));
|
||
|
LoadString(hAppInstance, idString, szMessage, sizeof(szMessage));
|
||
|
|
||
|
MessageBox(hwnd, szMessage, szTitle, wFlags);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* PromptDisketteChange() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
VOID
|
||
|
PromptDisketteChange(
|
||
|
HWND hwnd,
|
||
|
BOOL bWrite
|
||
|
)
|
||
|
{
|
||
|
WORD idString;
|
||
|
|
||
|
if (bWrite)
|
||
|
idString = IDS_INSERTDEST;
|
||
|
else
|
||
|
idString = IDS_INSERTSRC;
|
||
|
|
||
|
/* These dialogs have to be sysmodal because the DiskCopy progress dialog
|
||
|
* is now made a SysModal one; The following messagebox will hang if it
|
||
|
* is NOT sysmodal;
|
||
|
* A part of the Fix for Bug #10075 --SANKAR-- 03-05-90
|
||
|
*/
|
||
|
DCopyMessageBox(hwnd, idString, MB_OK | MB_SYSTEMMODAL | MB_ICONINFORMATION);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* ReadWriteCylinder() - */
|
||
|
// BOOL bWrite; TRUE for Write, FALSE for Read
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
INT
|
||
|
ReadWriteCylinder(
|
||
|
BOOL bWrite,
|
||
|
WORD wCylinder,
|
||
|
PDISKINFO pDisketteInfo
|
||
|
)
|
||
|
{
|
||
|
register INT rc;
|
||
|
WORD wHead;
|
||
|
WORD wDrive;
|
||
|
WORD wSectorCount;
|
||
|
WORD wTrackSize;
|
||
|
LPSTR lpBuffer;
|
||
|
|
||
|
wDrive = pDisketteInfo->wDrive;
|
||
|
wSectorCount = pDisketteInfo->wSectorsPerTrack;
|
||
|
wTrackSize = (wSectorCount * pDisketteInfo->wSectorSize);
|
||
|
|
||
|
if (hDosMemory)
|
||
|
lpBuffer = lpDosMemory;
|
||
|
|
||
|
/* Perform the operation for all the heads for a given cylinder */
|
||
|
for (wHead=0; wHead < pDisketteInfo->wHeads; wHead++) {
|
||
|
if (!hDosMemory)
|
||
|
lpBuffer = lpReadWritePtr;
|
||
|
|
||
|
if (bWrite) {
|
||
|
if (hDosMemory)
|
||
|
memcpy(lpBuffer, lpReadWritePtr, wTrackSize);
|
||
|
|
||
|
rc = GenericReadWriteSector((LPSTR)lpBuffer,
|
||
|
INT13_WRITE,
|
||
|
wDrive,
|
||
|
wCylinder,
|
||
|
wHead,
|
||
|
wSectorCount);
|
||
|
if (rc) {
|
||
|
/* Format all tracks starting from the given track */
|
||
|
if (!bFormatDone) {
|
||
|
if (!FormatAllTracks(pDisketteInfo, wCylinder, wHead, lpFormatBuffer))
|
||
|
return (-1); /* Failure */
|
||
|
rc = GenericReadWriteSector((LPSTR)lpBuffer,
|
||
|
INT13_WRITE,
|
||
|
wDrive,
|
||
|
wCylinder,
|
||
|
wHead,
|
||
|
wSectorCount);
|
||
|
} else
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
|
rc = GenericReadWriteSector((LPSTR)lpBuffer,
|
||
|
INT13_READ,
|
||
|
wDrive,
|
||
|
wCylinder,
|
||
|
wHead,
|
||
|
wSectorCount);
|
||
|
if (hDosMemory)
|
||
|
memcpy(lpReadWritePtr, lpBuffer, wTrackSize);
|
||
|
|
||
|
/*** FIX30: What about the DOS 4.0 volume stuff??? ***/
|
||
|
}
|
||
|
|
||
|
if (rc)
|
||
|
return (-1);
|
||
|
|
||
|
lpReadWritePtr += wTrackSize;
|
||
|
}
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* ReadWriteMaxPossible() - */
|
||
|
// BOOL bWrite TRUE for Write, FALSE for Read
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
/* This reads or writes as many cylinders as possible into the hpDisketteBuffer.
|
||
|
* It returns the next cylinder to be read.
|
||
|
*/
|
||
|
|
||
|
INT
|
||
|
ReadWriteMaxPossible(
|
||
|
BOOL bWrite,
|
||
|
WORD wStartCylinder,
|
||
|
PDISKINFO pDisketteInfo
|
||
|
)
|
||
|
{
|
||
|
MSG msg;
|
||
|
WORD wPercentDone;
|
||
|
DWORD dwBufferSize;
|
||
|
|
||
|
dwBufferSize = dwDisketteBufferSize;
|
||
|
|
||
|
/* We will read a cylinder only if we can read the entire cylinder. */
|
||
|
while (dwBufferSize >= pDisketteInfo->wCylinderSize) {
|
||
|
/* Check if any messages are pending */
|
||
|
if (!PeekMessage((LPMSG)&msg, (HWND)NULL, 0, 0, PM_REMOVE)) {
|
||
|
/* No message; So, go ahead with read/write */
|
||
|
if (ReadWriteCylinder(bWrite, wStartCylinder, pDisketteInfo))
|
||
|
return (-1);
|
||
|
|
||
|
wStartCylinder++;
|
||
|
wCompletedCylinders++;
|
||
|
|
||
|
/* Have we read/written all the cylinders? */
|
||
|
if (wStartCylinder > pDisketteInfo->wLastCylinder)
|
||
|
break;
|
||
|
|
||
|
/* Since each cylinder is counted once during read and once during
|
||
|
* write, number of cylinders is multiplied by 50 and not 100.
|
||
|
*/
|
||
|
wPercentDone = (wCompletedCylinders * 50) / (pDisketteInfo->wLastCylinder + 1);
|
||
|
if (LoadString(hAppInstance, IDS_PERCENTCOMP, szTitle, 32)) {
|
||
|
wsprintf(szMessage, szTitle, wPercentDone);
|
||
|
SendDlgItemMessage(hdlgProgress, IDD_PROGRESS, WM_SETTEXT, 0, (LPARAM)szMessage);
|
||
|
}
|
||
|
|
||
|
dwBufferSize -= pDisketteInfo->wCylinderSize;
|
||
|
} else {
|
||
|
/* Check if this is a message for the ProgressDlg */
|
||
|
if (!IsDialogMessage(hdlgProgress, &msg)) {
|
||
|
TranslateMessage(&msg);
|
||
|
DispatchMessage(&msg);
|
||
|
} else {
|
||
|
/* That message might have resulted in a Abort */
|
||
|
if (bUserAbort)
|
||
|
return (-1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return (wStartCylinder);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* ReadWrite() - */
|
||
|
// BOOL bWrite TRUE for Write, FALSE for Read
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
/* This reads or writes as many cylinders as possible into the hpDisketteBuffer.
|
||
|
* It returns the next cylinder to be read.
|
||
|
*/
|
||
|
|
||
|
INT
|
||
|
ReadWrite(
|
||
|
BOOL bWrite,
|
||
|
WORD wStartCylinder,
|
||
|
PDISKINFO pDisketteInfo
|
||
|
)
|
||
|
{
|
||
|
INT iRetVal = 0;
|
||
|
return (iRetVal);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* RestoreDPB() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
BOOL
|
||
|
RestoreDPB(
|
||
|
INT nDisk,
|
||
|
HANDLE hSavedParams
|
||
|
)
|
||
|
{
|
||
|
register PDevPB pDevPB;
|
||
|
|
||
|
if (!(pDevPB = (PDevPB)LocalLock(hSavedParams)))
|
||
|
return (FALSE);
|
||
|
|
||
|
pDevPB->SplFunctions = 4;
|
||
|
LocalUnlock(hSavedParams);
|
||
|
LocalFree(hSavedParams);
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* CopyDiskette() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
/* NOTE: Returns positive value for success otherwise failure. */
|
||
|
|
||
|
INT
|
||
|
APIENTRY
|
||
|
CopyDiskette(
|
||
|
HWND hwnd,
|
||
|
WORD nSourceDisk,
|
||
|
WORD nDestDisk
|
||
|
)
|
||
|
{
|
||
|
INT rc = -1;
|
||
|
register WORD wCylinder;
|
||
|
WORD wNextCylinder;
|
||
|
PBPB pIoctlBPB; /* Source Drive's BPB (taken from DevicePB) */
|
||
|
PBPB pBootBPB; /* Boot Drive's BPB (taken from Boot sector) */
|
||
|
PBPB pDestBPB;
|
||
|
DevPB dpbSrceParams;
|
||
|
DevPB dpbDestParams;
|
||
|
HANDLE hTrackLayout = NULL;
|
||
|
HANDLE hSaveSrceParams;
|
||
|
HANDLE hSaveDestParams;
|
||
|
FARPROC lpfnDialog;
|
||
|
DISKINFO SourceDisketteInfo;
|
||
|
DISKINFO DestDisketteInfo;
|
||
|
|
||
|
/* Check if it is a two drive system; put message to insert both floppies */
|
||
|
if (nSourceDisk != nDestDisk) {
|
||
|
bSingleDrive = FALSE;
|
||
|
DCopyMessageBox(hwnd, IDS_INSERTSRCDEST, MB_OK);
|
||
|
} else {
|
||
|
bSingleDrive = TRUE;
|
||
|
DCopyMessageBox(hwnd, IDS_INSERTSRC, MB_OK);
|
||
|
}
|
||
|
|
||
|
/* Get the BiosParameterBlock of source drive */
|
||
|
if (!(pIoctlBPB = GetBPB(nSourceDisk, &dpbSrceParams)))
|
||
|
return (0);
|
||
|
|
||
|
/* Get the BiosParameterBlock of the Source Diskette */
|
||
|
if (!(pBootBPB = GetBootBPB(nSourceDisk)))
|
||
|
return (0);
|
||
|
|
||
|
/* Get the BPB and DPB for the Destination drive also; */
|
||
|
if (!bSingleDrive) {
|
||
|
if (!(pDestBPB = GetBPB(nDestDisk, &dpbDestParams)))
|
||
|
return (0);
|
||
|
|
||
|
/* Compare BPB of source and Dest to see if they are compatible */
|
||
|
if (!(CheckBPBCompatibility(pIoctlBPB, dpbSrceParams.devType, pDestBPB, dpbDestParams.devType))) {
|
||
|
DCopyMessageBox(hwnd, IDS_COPYSRCDESTINCOMPAT, MB_ICONHAND | MB_OK);
|
||
|
return (0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!ModifyDeviceParams(nSourceDisk, &dpbSrceParams, &hSaveSrceParams, pIoctlBPB, pBootBPB))
|
||
|
return (0);
|
||
|
|
||
|
if (!bSingleDrive) {
|
||
|
if (!ModifyDeviceParams(nDestDisk, &dpbDestParams, &hSaveDestParams, pDestBPB, pBootBPB)) {
|
||
|
RestoreDPB(nSourceDisk, hSaveSrceParams);
|
||
|
return (0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
GetDisketteInfo((PDISKINFO)&SourceDisketteInfo, pBootBPB);
|
||
|
|
||
|
/* The Destination Diskette must have the same format as the source */
|
||
|
DestDisketteInfo = SourceDisketteInfo;
|
||
|
|
||
|
/* Except the drive number */
|
||
|
SourceDisketteInfo.wDrive = nSourceDisk;
|
||
|
DestDisketteInfo.wDrive = nDestDisk;
|
||
|
|
||
|
/* In case we need to format the destination diskette, we need to know the
|
||
|
* track layout; So, build a DPB with the required track layout;
|
||
|
*/
|
||
|
if (wDOSversion >= DOS_320) {
|
||
|
if (!(hTrackLayout = BuildDevPB(&dpbSrceParams)))
|
||
|
goto Failure0;
|
||
|
|
||
|
pTrackLayout = (PDevPB)LocalLock(hTrackLayout);
|
||
|
|
||
|
/* The following is required to format a 360KB floppy in a 1.2MB
|
||
|
* drive of NCR PC916 machine; We do formatting, if the destination
|
||
|
* floppy is an unformatted one;
|
||
|
* Fix for Bug #6894 --01-10-90-- SANKAR --
|
||
|
*/
|
||
|
if (pTrackLayout->BPB.bMedia == MEDIA_360) {
|
||
|
pTrackLayout->NumCyls = 40;
|
||
|
pTrackLayout->bMediaType = 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* We wish we could do the following allocation at the begining of this
|
||
|
* function, but we can not do so, because we need SourceDisketteInfo
|
||
|
* and we just got it;
|
||
|
*/
|
||
|
if (!AllocDiskCopyBuffers((PDISKINFO)&SourceDisketteInfo)) {
|
||
|
DCopyMessageBox(hwnd, IDS_REASONS+DE_INSMEM, MB_ICONHAND | MB_OK);
|
||
|
goto Failure0;
|
||
|
}
|
||
|
|
||
|
bUserAbort = FALSE;
|
||
|
wCompletedCylinders = 0;
|
||
|
|
||
|
hdlgProgress = CreateDialog(hAppInstance, (LPSTR)MAKEINTRESOURCE(DISKCOPYPROGRESSDLG), hwnd, ProgressDlgProc);
|
||
|
if (!hdlgProgress)
|
||
|
goto Failure2;
|
||
|
|
||
|
EnableWindow(hwnd, FALSE);
|
||
|
|
||
|
/* Start with the first cylinder. */
|
||
|
wCylinder = 0;
|
||
|
while (wCylinder <= SourceDisketteInfo.wLastCylinder) {
|
||
|
/* If this is a single drive system, ask the user to insert
|
||
|
* the source diskette.
|
||
|
* Do not prompt for the first time, because the Source diskette is
|
||
|
* already in the drive.
|
||
|
*/
|
||
|
if (bSingleDrive && (wCylinder > 0))
|
||
|
PromptDisketteChange(hdlgProgress, FALSE);
|
||
|
|
||
|
/* Read in the current cylinder. */
|
||
|
rc = ReadWrite(FALSE, wCylinder, (PDISKINFO)&SourceDisketteInfo);
|
||
|
if (rc < 0)
|
||
|
break;
|
||
|
else
|
||
|
wNextCylinder = (WORD)rc;
|
||
|
|
||
|
/* If this is a single drive system, ask the user to insert
|
||
|
* the destination diskette.
|
||
|
*/
|
||
|
if (bSingleDrive)
|
||
|
PromptDisketteChange(hdlgProgress, TRUE);
|
||
|
|
||
|
/* Write out the current cylinder. */
|
||
|
bFormatDone = FALSE;
|
||
|
rc = ReadWrite(TRUE, wCylinder, (PDISKINFO)&DestDisketteInfo);
|
||
|
if (rc < 0)
|
||
|
break;
|
||
|
|
||
|
wCylinder = wNextCylinder;
|
||
|
}
|
||
|
|
||
|
EnableWindow(hwnd, TRUE);
|
||
|
DestroyWindow(hdlgProgress);
|
||
|
hdlgProgress = NULL;
|
||
|
Failure2:
|
||
|
FreeBuffers();
|
||
|
Failure0:
|
||
|
if (wDOSversion >= DOS_320) {
|
||
|
/* Reset the Source drive parameters to the same as old */
|
||
|
RestoreDPB(nSourceDisk, hSaveSrceParams);
|
||
|
if (!bSingleDrive) {
|
||
|
/* Reset the Dest drive parameters to the same as old */
|
||
|
RestoreDPB(nDestDisk, hSaveDestParams);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((wDOSversion >= DOS_320) && hTrackLayout) {
|
||
|
LocalUnlock(hTrackLayout);
|
||
|
LocalFree(hTrackLayout);
|
||
|
}
|
||
|
|
||
|
return (rc);
|
||
|
}
|