908 lines
30 KiB
C
908 lines
30 KiB
C
|
/****************************************************************************/
|
||
|
/* */
|
||
|
/* WFFORMAT.C - */
|
||
|
/* */
|
||
|
/* Windows File Manager Diskette Formatting Routines */
|
||
|
/* */
|
||
|
/****************************************************************************/
|
||
|
|
||
|
#include "winfile.h"
|
||
|
|
||
|
|
||
|
/* MyGetDriveType() returns */
|
||
|
#define NOCHANGE 0
|
||
|
#define CHANGE 1
|
||
|
|
||
|
/* Parameter Block for IOCTL Format call */
|
||
|
struct FORMATPARAMS {
|
||
|
BYTE bSpl; /* Special byte */
|
||
|
WORD wHead;
|
||
|
WORD wCylinder;
|
||
|
};
|
||
|
|
||
|
|
||
|
typedef struct _MEDIASENSE {
|
||
|
BYTE IsDefault;
|
||
|
BYTE DeviceType;
|
||
|
BYTE res[10];
|
||
|
} MEDIASENSE;
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* BIOS Parameter Block Table for Removable Media */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
/* Each entry contains data about a floppy drive type in the following format:
|
||
|
* Length
|
||
|
* cbSec - Bytes/Sector 2
|
||
|
* secPerClus - Sectors/Cluster 1
|
||
|
* cSecRes - # of Reserved Sectors 2
|
||
|
* cFAT - # of FATs 1
|
||
|
* cDir - # of Root Directory Entries 2
|
||
|
* cSec - # of Sectors on the disk 2
|
||
|
* bMedia - Media Descriptor Byte 1
|
||
|
* secPerFAT - Sectors/FAT 2
|
||
|
* secPerTrack - Sectors/Track 2
|
||
|
* cHead - # of Disk Heads 2
|
||
|
* cSecHidden - # of Hidden Sectors 2
|
||
|
*/
|
||
|
|
||
|
BPB bpbList[] =
|
||
|
{
|
||
|
{512, 1, 1, 2, 64, 1*8*40, MEDIA_160, 1, 8, 1, 0}, /* 8sec SS 48tpi 160KB 5.25" DOS 1.0 & above */
|
||
|
{512, 2, 1, 2, 112, 2*8*40, MEDIA_320, 1, 8, 2, 0}, /* 8sec DS 48tpi 320KB 5.25" DOS 1.1 & above */
|
||
|
{512, 1, 1, 2, 64, 1*9*40, MEDIA_180, 2, 9, 1, 0}, /* 9sec SS 48tpi 180KB 5.25" DOS 2.0 & above */
|
||
|
{512, 2, 1, 2, 112, 2*9*40, MEDIA_360, 2, 9, 2, 0}, /* 9sec DS 48tpi 360KB 5.25" DOS 2.0 & above */
|
||
|
{512, 1, 1, 2, 224, 2*15*80, MEDIA_1200, 7, 15, 2, 0}, /* 15sec DS 96tpi 1.2MB 5.25" DOS 3.0 & above */
|
||
|
{512, 2, 1, 2, 112, 2*9*80, MEDIA_720, 3, 9, 2, 0}, /* 9sec DS 96tpi 720KB 3.5" DOS 3.2 & above */
|
||
|
{512, 1, 1, 2, 224, 2*18*80, MEDIA_1440, 9, 18, 2, 0}, /* 18sec DS 96tpi 1.44M 3.5" DOS 3.3 & above */
|
||
|
{512, 2, 1, 2, 240, 2*36*80, MEDIA_2880, 9, 36, 2, 0} /* 36sec DS 96tpi 2.88M 3.5" DOS 5.0 & above */
|
||
|
};
|
||
|
|
||
|
|
||
|
/* Precompute the total number of usable clusters...
|
||
|
* cCluster = (cSec/secPerClus) - { cSecRes
|
||
|
* + (cFAT * secPerFat)
|
||
|
* + (cDir*32+cbSec-1)/cbSec }/secPerClus;
|
||
|
*/
|
||
|
WORD cCluster[] = {0x0139, 0x013B, 0x015F, 0x0162, 0x0943, 0x02C9, 0x0B1F, 0xB2F, 0};
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* BuildDevPB() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
HANDLE
|
||
|
APIENTRY
|
||
|
BuildDevPB(
|
||
|
PDevPB pDevPB
|
||
|
)
|
||
|
{
|
||
|
WORD wCount;
|
||
|
register HANDLE hNewDevPB;
|
||
|
PDevPB pNewDevPB;
|
||
|
WORD wSecSize;
|
||
|
register WORD *wPtr;
|
||
|
WORD wTrackNumber;
|
||
|
|
||
|
wCount = pDevPB->BPB.secPerTrack;
|
||
|
|
||
|
if (!(hNewDevPB = LocalAlloc(LHND, TRACKLAYOUT_OFFSET+2+wCount*4)))
|
||
|
return NULL;
|
||
|
|
||
|
pNewDevPB = (PDevPB)LocalLock(hNewDevPB);
|
||
|
|
||
|
memcpy(pNewDevPB, pDevPB, TRACKLAYOUT_OFFSET);
|
||
|
wSecSize = pDevPB->BPB.cbSec;
|
||
|
|
||
|
wPtr = (WORD *)((LPSTR)pNewDevPB + TRACKLAYOUT_OFFSET);
|
||
|
*wPtr++ = wCount;
|
||
|
|
||
|
for (wTrackNumber=1; wTrackNumber <= wCount; wTrackNumber++) {
|
||
|
*wPtr++ = wTrackNumber;
|
||
|
*wPtr++ = wSecSize;
|
||
|
}
|
||
|
|
||
|
LocalUnlock(hNewDevPB);
|
||
|
return hNewDevPB;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* SetDevParamsForFormat() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
BOOL
|
||
|
SetDevParamsForFormat(
|
||
|
INT nDrive,
|
||
|
PDevPB pDevPB,
|
||
|
BOOL fLowCapacity
|
||
|
)
|
||
|
{
|
||
|
HANDLE hLocHandle;
|
||
|
PDevPB pNewDevPB;
|
||
|
|
||
|
/* Allocate for the DPB with track layout */
|
||
|
if (!(hLocHandle = BuildDevPB(pDevPB)))
|
||
|
return FALSE;
|
||
|
|
||
|
pNewDevPB = (PDevPB)LocalLock(hLocHandle);
|
||
|
|
||
|
pNewDevPB->SplFunctions = 5;
|
||
|
/* Is this a 360KB floppy in a 1.2Mb drive */
|
||
|
if (fLowCapacity) {
|
||
|
/* Yes! Then change the number of cylinders and Media type */
|
||
|
/* Fix for Bug #???? --SANKAR-- 01-10-90 -- */
|
||
|
pNewDevPB->NumCyls = 40;
|
||
|
pNewDevPB->bMediaType = 1;
|
||
|
}
|
||
|
|
||
|
LocalUnlock(hLocHandle);
|
||
|
LocalFree(hLocHandle);
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* GenericFormatTrack() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
/* This calls IOCTL format if DOS ver >= 3.2; Else calls BIOS.
|
||
|
*
|
||
|
* Returns : 0 if no error
|
||
|
* > 0 if tolerable error (resuling in bad sectors);
|
||
|
* -1 if fatal error (Format has to be aborted);
|
||
|
*/
|
||
|
|
||
|
INT
|
||
|
APIENTRY
|
||
|
GenericFormatTrack(
|
||
|
WORD nDisk,
|
||
|
WORD wCylinder,
|
||
|
WORD wHead,
|
||
|
WORD wSecPerTrack,
|
||
|
LPSTR lpDiskBuffer
|
||
|
)
|
||
|
{
|
||
|
struct FORMATPARAMS FormatParams;
|
||
|
INT iRetVal = -1; /* FATAL Error by default */
|
||
|
register INT iErrCode;
|
||
|
|
||
|
#ifdef DEBUG
|
||
|
wsprintf(szMessage, "Formatting Head #%d, Cylinder#%d\n\r", wHead, wCylinder);
|
||
|
OutputDebugString(szMessage);
|
||
|
#endif
|
||
|
|
||
|
/* Check the DOS version */
|
||
|
if (wDOSversion >= DOS_320) {
|
||
|
FormatParams.bSpl = 0;
|
||
|
FormatParams.wHead = wHead;
|
||
|
FormatParams.wCylinder = wCylinder;
|
||
|
switch (iErrCode = 0) {
|
||
|
case NOERROR:
|
||
|
case CRCERROR:
|
||
|
case SECNOTFOUND:
|
||
|
case GENERALERROR:
|
||
|
iRetVal = iErrCode;
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
|
switch (iErrCode = FormatTrackHead(nDisk, wCylinder, wHead, wSecPerTrack, lpDiskBuffer)) {
|
||
|
case NOERROR:
|
||
|
case DATAERROR:
|
||
|
case ADDMARKNOTFOUND:
|
||
|
case SECTORNOTFOUND:
|
||
|
iRetVal = iErrCode;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return (iRetVal);
|
||
|
}
|
||
|
|
||
|
|
||
|
INT APIENTRY GetMediaType(INT nDrive)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* FormatFloppy() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
// note, the below comment is out of date. leave for reference only
|
||
|
|
||
|
/* The Format routine is intended to mimic the actions of the FORMAT command
|
||
|
* on MSDOS. We restrict the possible set of operations that Format must use
|
||
|
* in order to simplify life. The RESTRICTIONS are:
|
||
|
*
|
||
|
* -- If the drive selected for formatting is a Quad density drive, then the
|
||
|
* user will be asked if he wants to format it for 1.2 MB or 360 KB
|
||
|
* and the format will proceed accordingly;
|
||
|
* -- For all other types of drives, it will format the disk to the maximum
|
||
|
* capacity that the drive can handle.
|
||
|
*
|
||
|
* The requirements for Format are:
|
||
|
*
|
||
|
* 1) there be a disk in a "source" drive that contains a valid boot sector
|
||
|
* 2) there be a disk in a "destination" drive that is formattable.
|
||
|
*
|
||
|
* The algorithm for determining a drive's capacity is as follows:
|
||
|
*
|
||
|
* If Source == Destination then
|
||
|
* error
|
||
|
* If dosversion >= 3.20
|
||
|
* {
|
||
|
* Use generic get_device_parameters and Get BPB.
|
||
|
* if (the drive is a Quad density drive (1.2 MB), and if user wants
|
||
|
* to format for 360KB), take BPB for 360KB from the bpbList[].
|
||
|
* In all other cases, use the BPB of the device.
|
||
|
* }
|
||
|
* else
|
||
|
* {
|
||
|
* Ask INT 13 for the drive type.
|
||
|
* If error then {
|
||
|
* assume 48tpi double side
|
||
|
* Attempt to format track 0, head 1
|
||
|
* If error then
|
||
|
* assume 48tpi single side
|
||
|
* else
|
||
|
* if sectors per track = 15 then
|
||
|
* assume 96tpi
|
||
|
* Ask user if he wants to format for 1.2MB or 360KB and
|
||
|
* use the proper BPB from bpbList[]
|
||
|
* else
|
||
|
* error
|
||
|
* }
|
||
|
*
|
||
|
* Note that this does NOT take into account non-contiguous drive letters
|
||
|
* (see 3.2 spec) nor future drives nor user-installed device drivers.
|
||
|
*
|
||
|
* Format (dSrc, nDstDrive, nDstDriveInt13) will format drive nDstDrive using an updated
|
||
|
* boot sector from drive dSrc. We will allocate two blocks of memory, but
|
||
|
* only one at a time. The first one we allocate is the bit-map of bad
|
||
|
* clusters that we find during the format. The second is for the boot
|
||
|
* sector.
|
||
|
*
|
||
|
* Returns: 0 Success
|
||
|
* <> 0 error code
|
||
|
* 1 => NOMEMORY
|
||
|
* 3 => Invalid boot sector.
|
||
|
* 4 => System area of the floppy is bad
|
||
|
* 7 => Problem in writing in Dest diskette.
|
||
|
* 8 => Internal error
|
||
|
* 9 => Format has been aborted by user.
|
||
|
*/
|
||
|
|
||
|
// in:
|
||
|
// hWnd window to base messages on
|
||
|
//
|
||
|
// nSource drive to swipe boot stuff from
|
||
|
//
|
||
|
// nDest drive to format
|
||
|
//
|
||
|
// iCapacity SS48
|
||
|
// DS48
|
||
|
// DS96
|
||
|
// DS720KB
|
||
|
// DS144M
|
||
|
// DS288M
|
||
|
// -1 (device capacity)
|
||
|
//
|
||
|
// bMakeSysDisk make a system disk too
|
||
|
//
|
||
|
// bQuick do a quick format
|
||
|
//
|
||
|
// returns:
|
||
|
// 0 success
|
||
|
// != 0 error
|
||
|
//
|
||
|
|
||
|
INT
|
||
|
APIENTRY
|
||
|
FormatFloppy(
|
||
|
HWND hWnd,
|
||
|
WORD nDest,
|
||
|
INT iCapacity,
|
||
|
BOOL bMakeSysDisk,
|
||
|
BOOL bQuick
|
||
|
)
|
||
|
{
|
||
|
DPB DPB;
|
||
|
DBT dbtSave; /* Disk Base Table */
|
||
|
INT iErrCode;
|
||
|
PBPB pBPB;
|
||
|
WORD w;
|
||
|
WORD cClusters;
|
||
|
WORD wFATValue;
|
||
|
WORD wBadCluster;
|
||
|
WORD cBadSectors;
|
||
|
WORD cTotalTracks;
|
||
|
WORD wCurrentHead;
|
||
|
WORD wPercentDone;
|
||
|
WORD wCurrentTrack;
|
||
|
WORD cTracksToFormat;
|
||
|
WORD wFirstDataSector;
|
||
|
WORD nSource;
|
||
|
DevPB dpbDiskParms; /* Device Parameters */
|
||
|
LPDBT lpDBT;
|
||
|
LPSTR lpDiskBuffer;
|
||
|
LPSTR lpBadClusterList;
|
||
|
HANDLE hDiskBuffer;
|
||
|
HANDLE hBadClusterList;
|
||
|
HANDLE hSaveDiskParms = NULL;
|
||
|
PDevPB pdpbSaveDiskParms;
|
||
|
CHAR szMsg[128];
|
||
|
BOOL fLowCapacity = FALSE; /* Is a 360KB floppy in a 1.2MB drive? */
|
||
|
INT ret = 0; // default to success
|
||
|
|
||
|
nSource = (WORD)GetBootDisk();
|
||
|
|
||
|
/* Initialize for cleanup. */
|
||
|
hDiskBuffer = NULL;
|
||
|
lpDiskBuffer = NULL;
|
||
|
hBadClusterList = NULL;
|
||
|
lpBadClusterList = NULL;
|
||
|
bUserAbort = FALSE;
|
||
|
|
||
|
/* Create a dialogbox that displays the progress of formatting; and also
|
||
|
* gives the user a chance to abort formatting at anytime.
|
||
|
*/
|
||
|
hdlgProgress = CreateDialog(hAppInstance, MAKEINTRESOURCE(FORMATPROGRESSDLG), hWnd, ProgressDlgProc);
|
||
|
if (!hdlgProgress) {
|
||
|
ret = IDS_FFERR_MEM; // out of memory
|
||
|
goto FFErrExit1;
|
||
|
}
|
||
|
|
||
|
EnableWindow(hWnd, FALSE);
|
||
|
|
||
|
/* Flush to DOS disk buffers. */
|
||
|
DiskReset();
|
||
|
|
||
|
/* Get the Disk Base Table. */
|
||
|
if (!(lpDBT = GetDBT())) {
|
||
|
ret = IDS_FFERR_MEM;
|
||
|
goto FFErrExit2;
|
||
|
}
|
||
|
|
||
|
dbtSave = *lpDBT;
|
||
|
|
||
|
// this checks to see if we are trying to format the boot drive
|
||
|
// this is a no no
|
||
|
|
||
|
if ((nDest == nSource) || (!IsRemovableDrive(nDest))) {
|
||
|
ret = IDS_FFERR_SRCEQDST;
|
||
|
goto FFErrExit3;
|
||
|
}
|
||
|
|
||
|
/* Check if the sector size is of standard size; If not report error */
|
||
|
if (HIWORD(GetClusterInfo(nSource)) > CBSECTORSIZE) {
|
||
|
ret = IDS_FFERR_SECSIZE;
|
||
|
goto FFErrExit3;
|
||
|
}
|
||
|
|
||
|
/* Allocate boot sector, sector buffer, track buffer */
|
||
|
if (!(hDiskBuffer = LocalAlloc(LHND, (LONG)(2*CBSECTORSIZE)))) {
|
||
|
ret = IDS_FFERR_MEM;
|
||
|
goto FFErrExit3;
|
||
|
}
|
||
|
|
||
|
lpDiskBuffer = LocalLock(hDiskBuffer);
|
||
|
|
||
|
|
||
|
/* If DOS Version is 3.2 or above, use DeviceParameters() to get the BPB. */
|
||
|
if (wDOSversion >= DOS_320) {
|
||
|
|
||
|
/* NOTE: All the fields of dpbDiskParms must be initialized to 0,
|
||
|
* otherwise, INT 21h, Function 44h, Subfunction 0Dh does NOT work;
|
||
|
* This function is called in DeviceParameters().
|
||
|
*/
|
||
|
memset(&dpbDiskParms, 0, sizeof(DevPB));
|
||
|
pBPB = &(dpbDiskParms.BPB);
|
||
|
|
||
|
if (iCapacity != -1) {
|
||
|
|
||
|
w = (WORD)GetMediaType(nDest);
|
||
|
|
||
|
if (w) {
|
||
|
switch (w) {
|
||
|
case 2: // 720
|
||
|
if (iCapacity > DS720KB) {
|
||
|
w = IDS_720KB;
|
||
|
iCapacity = DS720KB;
|
||
|
} else
|
||
|
goto SensePass;
|
||
|
break;
|
||
|
|
||
|
case 7: // 1.44
|
||
|
if (iCapacity > DS144M) {
|
||
|
w = IDS_144MB;
|
||
|
iCapacity = DS144M;
|
||
|
} else
|
||
|
goto SensePass;
|
||
|
break;
|
||
|
default: // 2.88 and unknown case
|
||
|
goto SensePass;
|
||
|
}
|
||
|
|
||
|
LoadString(hAppInstance, IDS_FFERR_MEDIASENSE, szMsg, sizeof(szMsg));
|
||
|
LoadString(hAppInstance, w, szTitle, sizeof(szTitle));
|
||
|
wsprintf(szMessage, szMsg, (LPSTR)szTitle);
|
||
|
LoadString(hAppInstance, IDS_FORMATERR, szTitle, sizeof(szTitle));
|
||
|
if (MessageBox(hdlgProgress, szMessage, szTitle, MB_YESNO | MB_ICONINFORMATION) != IDYES) {
|
||
|
ret = IDS_FFERR_USERABORT;
|
||
|
goto FFErrExit3;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SensePass:
|
||
|
|
||
|
pBPB = &bpbList[iCapacity];
|
||
|
cClusters = cCluster[iCapacity];
|
||
|
|
||
|
// if we are formatting a 360K disk in a 1.2 MB drive set this
|
||
|
// special flag
|
||
|
|
||
|
if (iCapacity == DS48) {
|
||
|
// We must remember to change the number of cylinders
|
||
|
// while doing Set Device parameters; So, set this flag;
|
||
|
fLowCapacity = TRUE;
|
||
|
}
|
||
|
} else {
|
||
|
DWORD dwSec = pBPB->cSec;
|
||
|
|
||
|
// use the default device parameters
|
||
|
// NOTE: pBPB already points to proper data
|
||
|
|
||
|
/* HPVECTRA: DOS 3.2 and above gives wrong sector count. */
|
||
|
if (!pBPB->cSec)
|
||
|
dwSec = dpbDiskParms.NumCyls * pBPB->secPerTrack * pBPB->cHead;
|
||
|
|
||
|
/* Calculate the clusters for the disk. */
|
||
|
cClusters = (WORD)(dwSec / pBPB->secPerClus) -
|
||
|
(pBPB->cSecRes + (pBPB->cFAT * pBPB->secPerFAT) +
|
||
|
(pBPB->cDir*32 + pBPB->cbSec - 1) / pBPB->cbSec) / pBPB->secPerClus;
|
||
|
}
|
||
|
|
||
|
/* Save the DriveParameterBlock for restoration latter */
|
||
|
hSaveDiskParms = BuildDevPB(&dpbDiskParms);
|
||
|
if (!hSaveDiskParms) {
|
||
|
ret = IDS_FFERR_MEM;
|
||
|
goto FFErrExit3;
|
||
|
}
|
||
|
pdpbSaveDiskParms = (PDevPB)LocalLock(hSaveDiskParms);
|
||
|
|
||
|
/* Modify the parameters just for format */
|
||
|
memcpy(&(dpbDiskParms.BPB), pBPB, sizeof(BPB));
|
||
|
if (!SetDevParamsForFormat(nDest, &dpbDiskParms, fLowCapacity)) {
|
||
|
ret = IDS_FFERR_MEM;
|
||
|
goto FFErrExit3;
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
// DOS < 3.2
|
||
|
|
||
|
/* See if INT 13 knows the drive type. */
|
||
|
switch (MyGetDriveType(nDest)) {
|
||
|
case NOCHANGE:
|
||
|
/* We assume that the machine is using old ROMS...
|
||
|
* Assume that we are using a 9-sector Double-sided 48tpi diskette.
|
||
|
*/
|
||
|
pBPB = &bpbList[DS48];
|
||
|
cClusters = cCluster[DS48];
|
||
|
lpDBT->lastsector = (BYTE)pBPB->secPerTrack;
|
||
|
lpDBT->gaplengthf = 0x50;
|
||
|
|
||
|
/* Try to format a track on side 1. If this fails, assume that we
|
||
|
* have a Single-sided 48tpi diskette.
|
||
|
*/
|
||
|
if (FormatTrackHead(nDest, 0, 1, pBPB->secPerTrack, lpDiskBuffer)) {
|
||
|
pBPB = &bpbList[SS48];
|
||
|
cClusters = cCluster[SS48];
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case CHANGE:
|
||
|
if (iCapacity == DS48) {
|
||
|
/* User wants to format a 360KB floppy. */
|
||
|
pBPB = &bpbList[DS48];
|
||
|
cClusters = cCluster[DS48];
|
||
|
} else {
|
||
|
/* User wants to format a 1.2 MB floppy */
|
||
|
pBPB = &bpbList[DS96];
|
||
|
cClusters = cCluster[DS96];
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ret = IDS_FFERR_DRIVETYPE;
|
||
|
goto FFErrExit5;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
lpDBT->lastsector = (BYTE)pBPB->secPerTrack;
|
||
|
lpDBT->gaplengthf = (BYTE)(pBPB->secPerTrack == 15 ? 0x54 : 0x50);
|
||
|
|
||
|
if (wDOSversion < DOS_320) {
|
||
|
/* If 96tpi, fix up the Disk Base Table. */
|
||
|
if (pBPB->bMedia == MEDIA_1200) /* high density */
|
||
|
if (pBPB->secPerTrack == 15) /* then 1.2 Meg Drive */
|
||
|
SetDASD(nDest, 3); /* 1.2 MB floppy in 1.2MB drive */
|
||
|
}
|
||
|
|
||
|
LoadString(hAppInstance, IDS_PERCENTCOMP, szMsg, sizeof(szMsg));
|
||
|
|
||
|
/* We believe that we know EXACTLY what is out there. Allocate the boot
|
||
|
* sector and the bad-cluster bit-map. The boot sector buffer is reused as
|
||
|
* two consecutive sectors of the FAT.
|
||
|
*/
|
||
|
if (!(hBadClusterList = LocalAlloc(LHND, (LONG)((2 + cClusters + 7) / 8)))) {
|
||
|
ret = IDS_FFERR_MEM;
|
||
|
goto FFErrExit5;
|
||
|
}
|
||
|
|
||
|
lpBadClusterList = LocalLock(hBadClusterList);
|
||
|
|
||
|
/* Let's format 1 track at a time and record the bad sectors in the
|
||
|
* bitmap. Note that we round DOWN the number of tracks so that we
|
||
|
* don't format what might not be ours. Fail if there are any bad
|
||
|
* sectors in the system area.
|
||
|
*/
|
||
|
|
||
|
/* Compute number of tracks to format. */
|
||
|
if (!pBPB->cSec)
|
||
|
cTracksToFormat = (WORD)dpbDiskParms.NumCyls;
|
||
|
else
|
||
|
cTracksToFormat = (WORD)(pBPB->cSec / pBPB->secPerTrack);
|
||
|
|
||
|
|
||
|
/* Compute the starting track and head. */
|
||
|
wCurrentTrack = pBPB->cSecHidden / (pBPB->secPerTrack * pBPB->cHead);
|
||
|
wCurrentHead = (pBPB->cSecHidden % (pBPB->secPerTrack * pBPB->cHead))/pBPB->secPerTrack;
|
||
|
|
||
|
/* Compute the number of the first sector after the system area. */
|
||
|
wFirstDataSector = pBPB->cSecRes + pBPB->cFAT * pBPB->secPerFAT +
|
||
|
(pBPB->cDir * 32 + pBPB->cbSec-1) / pBPB->cbSec;
|
||
|
|
||
|
cTotalTracks = cTracksToFormat;
|
||
|
|
||
|
if (bQuick) {
|
||
|
|
||
|
// read the boot sector to make sure the capacity selected
|
||
|
// matches what it has been formated to
|
||
|
|
||
|
iErrCode = GenericReadWriteSector(lpDiskBuffer, INT13_READ, nDest, 0, 0, 1);
|
||
|
|
||
|
if (iErrCode || ((iCapacity != -1) && ((BOOTSEC *)lpDiskBuffer)->BPB.bMedia != bpbList[iCapacity].bMedia)) {
|
||
|
|
||
|
fFormatFlags &= ~FF_QUICK;
|
||
|
bQuick = FALSE;
|
||
|
|
||
|
LoadString(hAppInstance, IDS_FORMATQUICKFAILURE, szMessage, 128);
|
||
|
LoadString(hAppInstance, IDS_FORMAT, szTitle, 128);
|
||
|
|
||
|
iErrCode = MessageBox(hdlgProgress, szMessage, szTitle, MB_YESNO | MB_ICONEXCLAMATION);
|
||
|
|
||
|
if (iErrCode == IDYES)
|
||
|
goto NormalFormat;
|
||
|
else {
|
||
|
ret = IDS_FFERR_USERABORT;
|
||
|
goto FFErrExit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
NormalFormat:
|
||
|
|
||
|
/* 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 (cTracksToFormat) {
|
||
|
|
||
|
/* Has the user aborted? */
|
||
|
if (WFQueryAbort()) {
|
||
|
ret = IDS_FFERR_USERABORT;
|
||
|
goto FFErrExit;
|
||
|
}
|
||
|
|
||
|
/* If no message is pending, go ahead and format one track */
|
||
|
if ((iErrCode = GenericFormatTrack(nDest, wCurrentTrack, wCurrentHead, pBPB->secPerTrack, lpDiskBuffer))) {
|
||
|
|
||
|
/* Check if it is a fatal error */
|
||
|
if (iErrCode == -1) {
|
||
|
// ret = IDS_FFERR_BADTRACK;
|
||
|
ret = IDS_FFERR;
|
||
|
goto FFErrExit;
|
||
|
}
|
||
|
|
||
|
/* Bad Track. Compute the number of the first bad sector */
|
||
|
cBadSectors = (wCurrentTrack * pBPB->cHead + wCurrentHead) * pBPB->secPerTrack;
|
||
|
|
||
|
/* Fail if bad sector is in the system area */
|
||
|
if (cBadSectors < wFirstDataSector) {
|
||
|
// ret = IDS_FFERR_BADTRACK;
|
||
|
ret = IDS_FFERR;
|
||
|
goto FFErrExit;
|
||
|
}
|
||
|
|
||
|
/* Enumerate all bad sectors and mark the corresponding
|
||
|
* clusters as bad.
|
||
|
*/
|
||
|
for (w=cBadSectors; w < cBadSectors + pBPB->secPerTrack; w++) {
|
||
|
wBadCluster = (w - wFirstDataSector) / pBPB->secPerClus + 2;
|
||
|
lpBadClusterList[wBadCluster/8] |= 1 << (wBadCluster % 8);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cTracksToFormat--;
|
||
|
|
||
|
/* Display the percentage of progress message */
|
||
|
wPercentDone = (WORD)MulDiv(cTotalTracks - cTracksToFormat, 100, cTotalTracks);
|
||
|
|
||
|
/* All tracks might have been formatted. But,
|
||
|
* Still FAT and Root dir are to be created; It takes time; So,
|
||
|
* make the user believe that still 1% formatting is left.
|
||
|
*/
|
||
|
if (wPercentDone == 100)
|
||
|
LoadString(hAppInstance, IDS_CREATEROOT, szMessage, sizeof(szMessage));
|
||
|
else
|
||
|
wsprintf(szMessage, szMsg, wPercentDone);
|
||
|
|
||
|
SendDlgItemMessage(hdlgProgress, IDD_PROGRESS, WM_SETTEXT, 0, (LPARAM)szMessage);
|
||
|
|
||
|
if (++wCurrentHead >= pBPB->cHead) {
|
||
|
wCurrentHead = 0;
|
||
|
wCurrentTrack++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Write out the boot sector(s). */
|
||
|
w = (WORD)WriteBootSector(nSource, nDest, pBPB, lpDiskBuffer);
|
||
|
if (w) {
|
||
|
// ret = IDS_FFERR_WRITEBOOT;
|
||
|
if (w == 0x16) // int24 unknown command, assume
|
||
|
ret = IDS_SYSDISKNOFILES; // the int25 read failed
|
||
|
else
|
||
|
ret = IDS_FFERR;
|
||
|
goto FFErrExit;
|
||
|
}
|
||
|
|
||
|
/* Has the user aborted? */
|
||
|
if (WFQueryAbort()) {
|
||
|
ret = IDS_FFERR_USERABORT;
|
||
|
goto FFErrExit;
|
||
|
}
|
||
|
|
||
|
/* Format is complete. Create correct DPB in system */
|
||
|
SetDPB(nDest, pBPB, &DPB);
|
||
|
|
||
|
// if doing a quick format keep the old bad cluster list
|
||
|
|
||
|
/* Create FAT entries for each of the formatted clusters. */
|
||
|
for (w=2; w < (WORD)(cClusters+2); w++) {
|
||
|
|
||
|
if (bQuick) {
|
||
|
wFATValue = 0;
|
||
|
|
||
|
// is this entry reserved or marked as bad
|
||
|
|
||
|
if ((wFATValue >= 0xFFF0) &&
|
||
|
(wFATValue <= 0xFFF7)) {
|
||
|
// yes, don't change it!
|
||
|
} else {
|
||
|
// mark as free
|
||
|
|
||
|
if (0) {
|
||
|
// ret = IDS_FFERR_WRITEFAT;
|
||
|
ret = IDS_FFERR;
|
||
|
goto FFErrExit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
/* Was this cluster bad? */
|
||
|
if (lpBadClusterList[w/8] & (1 << (w % 8)))
|
||
|
wFATValue = 0xFFF7;
|
||
|
else
|
||
|
wFATValue = 0;
|
||
|
|
||
|
/* Add this entry to the FAT (possibly writing the sector). */
|
||
|
if (0) {
|
||
|
// ret = IDS_FFERR_WRITEFAT;
|
||
|
ret = IDS_FFERR;
|
||
|
goto FFErrExit;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
if (WFQueryAbort()) { /* Has the user aborted? */
|
||
|
ret = IDS_FFERR_USERABORT;
|
||
|
goto FFErrExit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Clean out the root directory. */
|
||
|
memset(lpDiskBuffer, 0, CBSECTORSIZE);
|
||
|
|
||
|
for (w=0; w < (WORD)((pBPB->cDir*32 + pBPB->cbSec-1)/pBPB->cbSec); w++) {
|
||
|
/* Has the user aborted? */
|
||
|
if (WFQueryAbort()) {
|
||
|
ret = IDS_FFERR_USERABORT;
|
||
|
goto FFErrExit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Should we make it a system disk also? */
|
||
|
if (bMakeSysDisk) {
|
||
|
LoadString(hAppInstance, IDS_COPYSYSFILES, szMessage, 32);
|
||
|
SendDlgItemMessage(hdlgProgress, IDD_PROGRESS, WM_SETTEXT, 0, (LPARAM)szMessage);
|
||
|
if (MakeSystemDiskette(nDest, TRUE)) {
|
||
|
if (bUserAbort)
|
||
|
ret = IDS_FFERR_USERABORT;
|
||
|
else
|
||
|
ret = IDS_FFERR_SYSFILES;
|
||
|
goto FFErrExit;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Normal Exit. */
|
||
|
|
||
|
LocalUnlock(hBadClusterList);
|
||
|
LocalFree(hBadClusterList);
|
||
|
LocalUnlock(hDiskBuffer);
|
||
|
|
||
|
if (hSaveDiskParms) {
|
||
|
/* Restore the DriveParameterBlock */
|
||
|
pdpbSaveDiskParms->SplFunctions = 4;
|
||
|
|
||
|
LocalUnlock(hSaveDiskParms);
|
||
|
LocalFree(hSaveDiskParms);
|
||
|
}
|
||
|
|
||
|
LocalFree(hDiskBuffer);
|
||
|
*lpDBT = dbtSave;
|
||
|
EnableWindow(hWnd, TRUE);
|
||
|
DestroyWindow(hdlgProgress);
|
||
|
hdlgProgress = NULL;
|
||
|
return TRUE;
|
||
|
|
||
|
FFErrExit:
|
||
|
LocalUnlock(hBadClusterList);
|
||
|
LocalFree(hBadClusterList);
|
||
|
FFErrExit5:
|
||
|
if (hSaveDiskParms) {
|
||
|
/* Restore the DriveParameterBlock */
|
||
|
pdpbSaveDiskParms->SplFunctions = 4;
|
||
|
|
||
|
LocalUnlock(hSaveDiskParms);
|
||
|
LocalFree(hSaveDiskParms);
|
||
|
}
|
||
|
LocalUnlock(hDiskBuffer);
|
||
|
LocalFree(hDiskBuffer);
|
||
|
FFErrExit3:
|
||
|
*lpDBT = dbtSave;
|
||
|
FFErrExit2:
|
||
|
EnableWindow(hWnd, TRUE);
|
||
|
DestroyWindow(hdlgProgress);
|
||
|
hdlgProgress = NULL;
|
||
|
FFErrExit1:
|
||
|
|
||
|
if (ret != IDS_FFERR_USERABORT) {
|
||
|
LoadString(hAppInstance, IDS_FORMATERR, szTitle, sizeof(szTitle));
|
||
|
LoadString(hAppInstance, ret, szMessage, sizeof(szMessage));
|
||
|
MessageBox(hWnd, szMessage, szTitle, MB_OK | MB_ICONSTOP);
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
/* */
|
||
|
/* GetDriveCapacity() - */
|
||
|
/* */
|
||
|
/*--------------------------------------------------------------------------*/
|
||
|
|
||
|
/* Parameter:
|
||
|
* Drive number;
|
||
|
* Returns:
|
||
|
* 0 if Error;
|
||
|
* 1 if 360KB floppy;
|
||
|
* 2 if 1.2MB floppy;
|
||
|
* 3 if 720KB, 3.5" floppy;
|
||
|
* 4 if 1.44MB, 3.5" floppy;
|
||
|
* 5 if 2.88MB, 3.5" floppy;
|
||
|
*
|
||
|
* these are used +2 as indexes into bpbList[] FIX31
|
||
|
*
|
||
|
* HACK ALERT:
|
||
|
* One might wonder why on earth we are not using int13h Fn 8 to
|
||
|
* perform this function; The reason is that in old compaq 386/16
|
||
|
* machines(though the BIOS is dated Sep 1986), this function is NOT
|
||
|
* supported! So, we are forced to do the following:
|
||
|
* We check the DOS version; If it is >= 3.2, then we make IOCTL
|
||
|
* calls to get the Drive parameters and we find the Drive capacity;
|
||
|
* If DOS version is < 3.2, then there can't be 3.5" floppies at all;
|
||
|
* The only high capacity floppy possible is the 5.25", 1.2MB floppy;
|
||
|
* So, we call MyGetDriveType() (int13h, Fn 15h) to find if the
|
||
|
* change-line is supported by the drive; If it is supported then it
|
||
|
* must be a 1.2MB floppy; Otherwise, it is a 360KB floppy;
|
||
|
* What do you think? Smart! Ugh?
|
||
|
*/
|
||
|
|
||
|
WORD
|
||
|
APIENTRY
|
||
|
GetDriveCapacity(
|
||
|
WORD nDrive
|
||
|
)
|
||
|
{
|
||
|
DevPB dpbDiskParms; /* Device Parameters */
|
||
|
PBPB pBPB;
|
||
|
|
||
|
|
||
|
if (wDOSversion >= DOS_320) {
|
||
|
|
||
|
/* NOTE: All the fields of dpbDiskParms must be initialized to 0,
|
||
|
* otherwise, INT 21h, Function 44h, Subfunction 0Dh does NOT work;
|
||
|
* This function is called in DeviceParameters().
|
||
|
*/
|
||
|
memset(&dpbDiskParms, 0, sizeof(DevPB));
|
||
|
dpbDiskParms.SplFunctions = 0;
|
||
|
|
||
|
pBPB = &(dpbDiskParms.BPB);
|
||
|
|
||
|
/* Check if this is a 1.44MB drive */
|
||
|
if (pBPB->bMedia == MEDIA_1440) {
|
||
|
if (pBPB->secPerTrack == 18)
|
||
|
return 4; /* 1.44MB drive */
|
||
|
else if (pBPB->secPerTrack == 36)
|
||
|
return 5; /* 2.88MB drive */
|
||
|
}
|
||
|
|
||
|
/* Check if this is a 720KB or 1.2MB drive */
|
||
|
if (pBPB->bMedia == MEDIA_1200) {
|
||
|
if (pBPB->secPerFAT == 3)
|
||
|
return 3; /* 720KB drive */
|
||
|
if (pBPB->secPerFAT == 7)
|
||
|
return 2; /* 1.2MB drive */
|
||
|
}
|
||
|
|
||
|
if (pBPB->bMedia == MEDIA_360)
|
||
|
return 1; /* Must be a 386KB floppy. */
|
||
|
|
||
|
return 0; // I don't know!
|
||
|
} else {
|
||
|
|
||
|
/* See if INT 13 Fn 15h knows the drive type. */
|
||
|
switch (MyGetDriveType(nDrive)) {
|
||
|
case NOCHANGE:
|
||
|
/* We assume that the machine is using old ROMS... */
|
||
|
return 1; /* No changeline support! Must be 360KB floppy */
|
||
|
break;
|
||
|
|
||
|
case CHANGE:
|
||
|
return 2; /* DOS versions < 3.2 can not have 1.44 or 720KB
|
||
|
* drive; So, this has to be a 1.2MB drive
|
||
|
*/
|
||
|
break;
|
||
|
default:
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
}
|