Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

907 lines
30 KiB

  1. /****************************************************************************/
  2. /* */
  3. /* WFFORMAT.C - */
  4. /* */
  5. /* Windows File Manager Diskette Formatting Routines */
  6. /* */
  7. /****************************************************************************/
  8. #include "winfile.h"
  9. /* MyGetDriveType() returns */
  10. #define NOCHANGE 0
  11. #define CHANGE 1
  12. /* Parameter Block for IOCTL Format call */
  13. struct FORMATPARAMS {
  14. BYTE bSpl; /* Special byte */
  15. WORD wHead;
  16. WORD wCylinder;
  17. };
  18. typedef struct _MEDIASENSE {
  19. BYTE IsDefault;
  20. BYTE DeviceType;
  21. BYTE res[10];
  22. } MEDIASENSE;
  23. /*--------------------------------------------------------------------------*/
  24. /* BIOS Parameter Block Table for Removable Media */
  25. /*--------------------------------------------------------------------------*/
  26. /* Each entry contains data about a floppy drive type in the following format:
  27. * Length
  28. * cbSec - Bytes/Sector 2
  29. * secPerClus - Sectors/Cluster 1
  30. * cSecRes - # of Reserved Sectors 2
  31. * cFAT - # of FATs 1
  32. * cDir - # of Root Directory Entries 2
  33. * cSec - # of Sectors on the disk 2
  34. * bMedia - Media Descriptor Byte 1
  35. * secPerFAT - Sectors/FAT 2
  36. * secPerTrack - Sectors/Track 2
  37. * cHead - # of Disk Heads 2
  38. * cSecHidden - # of Hidden Sectors 2
  39. */
  40. BPB bpbList[] =
  41. {
  42. {512, 1, 1, 2, 64, 1*8*40, MEDIA_160, 1, 8, 1, 0}, /* 8sec SS 48tpi 160KB 5.25" DOS 1.0 & above */
  43. {512, 2, 1, 2, 112, 2*8*40, MEDIA_320, 1, 8, 2, 0}, /* 8sec DS 48tpi 320KB 5.25" DOS 1.1 & above */
  44. {512, 1, 1, 2, 64, 1*9*40, MEDIA_180, 2, 9, 1, 0}, /* 9sec SS 48tpi 180KB 5.25" DOS 2.0 & above */
  45. {512, 2, 1, 2, 112, 2*9*40, MEDIA_360, 2, 9, 2, 0}, /* 9sec DS 48tpi 360KB 5.25" DOS 2.0 & above */
  46. {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 */
  47. {512, 2, 1, 2, 112, 2*9*80, MEDIA_720, 3, 9, 2, 0}, /* 9sec DS 96tpi 720KB 3.5" DOS 3.2 & above */
  48. {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 */
  49. {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 */
  50. };
  51. /* Precompute the total number of usable clusters...
  52. * cCluster = (cSec/secPerClus) - { cSecRes
  53. * + (cFAT * secPerFat)
  54. * + (cDir*32+cbSec-1)/cbSec }/secPerClus;
  55. */
  56. WORD cCluster[] = {0x0139, 0x013B, 0x015F, 0x0162, 0x0943, 0x02C9, 0x0B1F, 0xB2F, 0};
  57. /*--------------------------------------------------------------------------*/
  58. /* */
  59. /* BuildDevPB() - */
  60. /* */
  61. /*--------------------------------------------------------------------------*/
  62. HANDLE
  63. APIENTRY
  64. BuildDevPB(
  65. PDevPB pDevPB
  66. )
  67. {
  68. WORD wCount;
  69. register HANDLE hNewDevPB;
  70. PDevPB pNewDevPB;
  71. WORD wSecSize;
  72. register WORD *wPtr;
  73. WORD wTrackNumber;
  74. wCount = pDevPB->BPB.secPerTrack;
  75. if (!(hNewDevPB = LocalAlloc(LHND, TRACKLAYOUT_OFFSET+2+wCount*4)))
  76. return NULL;
  77. pNewDevPB = (PDevPB)LocalLock(hNewDevPB);
  78. memcpy(pNewDevPB, pDevPB, TRACKLAYOUT_OFFSET);
  79. wSecSize = pDevPB->BPB.cbSec;
  80. wPtr = (WORD *)((LPSTR)pNewDevPB + TRACKLAYOUT_OFFSET);
  81. *wPtr++ = wCount;
  82. for (wTrackNumber=1; wTrackNumber <= wCount; wTrackNumber++) {
  83. *wPtr++ = wTrackNumber;
  84. *wPtr++ = wSecSize;
  85. }
  86. LocalUnlock(hNewDevPB);
  87. return hNewDevPB;
  88. }
  89. /*--------------------------------------------------------------------------*/
  90. /* */
  91. /* SetDevParamsForFormat() - */
  92. /* */
  93. /*--------------------------------------------------------------------------*/
  94. BOOL
  95. SetDevParamsForFormat(
  96. INT nDrive,
  97. PDevPB pDevPB,
  98. BOOL fLowCapacity
  99. )
  100. {
  101. HANDLE hLocHandle;
  102. PDevPB pNewDevPB;
  103. /* Allocate for the DPB with track layout */
  104. if (!(hLocHandle = BuildDevPB(pDevPB)))
  105. return FALSE;
  106. pNewDevPB = (PDevPB)LocalLock(hLocHandle);
  107. pNewDevPB->SplFunctions = 5;
  108. /* Is this a 360KB floppy in a 1.2Mb drive */
  109. if (fLowCapacity) {
  110. /* Yes! Then change the number of cylinders and Media type */
  111. /* Fix for Bug #???? --SANKAR-- 01-10-90 -- */
  112. pNewDevPB->NumCyls = 40;
  113. pNewDevPB->bMediaType = 1;
  114. }
  115. LocalUnlock(hLocHandle);
  116. LocalFree(hLocHandle);
  117. return TRUE;
  118. }
  119. /*--------------------------------------------------------------------------*/
  120. /* */
  121. /* GenericFormatTrack() - */
  122. /* */
  123. /*--------------------------------------------------------------------------*/
  124. /* This calls IOCTL format if DOS ver >= 3.2; Else calls BIOS.
  125. *
  126. * Returns : 0 if no error
  127. * > 0 if tolerable error (resuling in bad sectors);
  128. * -1 if fatal error (Format has to be aborted);
  129. */
  130. INT
  131. APIENTRY
  132. GenericFormatTrack(
  133. WORD nDisk,
  134. WORD wCylinder,
  135. WORD wHead,
  136. WORD wSecPerTrack,
  137. LPSTR lpDiskBuffer
  138. )
  139. {
  140. struct FORMATPARAMS FormatParams;
  141. INT iRetVal = -1; /* FATAL Error by default */
  142. register INT iErrCode;
  143. #ifdef DEBUG
  144. wsprintf(szMessage, "Formatting Head #%d, Cylinder#%d\n\r", wHead, wCylinder);
  145. OutputDebugString(szMessage);
  146. #endif
  147. /* Check the DOS version */
  148. if (wDOSversion >= DOS_320) {
  149. FormatParams.bSpl = 0;
  150. FormatParams.wHead = wHead;
  151. FormatParams.wCylinder = wCylinder;
  152. switch (iErrCode = 0) {
  153. case NOERROR:
  154. case CRCERROR:
  155. case SECNOTFOUND:
  156. case GENERALERROR:
  157. iRetVal = iErrCode;
  158. break;
  159. }
  160. } else {
  161. switch (iErrCode = FormatTrackHead(nDisk, wCylinder, wHead, wSecPerTrack, lpDiskBuffer)) {
  162. case NOERROR:
  163. case DATAERROR:
  164. case ADDMARKNOTFOUND:
  165. case SECTORNOTFOUND:
  166. iRetVal = iErrCode;
  167. break;
  168. }
  169. }
  170. return (iRetVal);
  171. }
  172. INT APIENTRY GetMediaType(INT nDrive)
  173. {
  174. return 0;
  175. }
  176. /*--------------------------------------------------------------------------*/
  177. /* */
  178. /* FormatFloppy() - */
  179. /* */
  180. /*--------------------------------------------------------------------------*/
  181. // note, the below comment is out of date. leave for reference only
  182. /* The Format routine is intended to mimic the actions of the FORMAT command
  183. * on MSDOS. We restrict the possible set of operations that Format must use
  184. * in order to simplify life. The RESTRICTIONS are:
  185. *
  186. * -- If the drive selected for formatting is a Quad density drive, then the
  187. * user will be asked if he wants to format it for 1.2 MB or 360 KB
  188. * and the format will proceed accordingly;
  189. * -- For all other types of drives, it will format the disk to the maximum
  190. * capacity that the drive can handle.
  191. *
  192. * The requirements for Format are:
  193. *
  194. * 1) there be a disk in a "source" drive that contains a valid boot sector
  195. * 2) there be a disk in a "destination" drive that is formattable.
  196. *
  197. * The algorithm for determining a drive's capacity is as follows:
  198. *
  199. * If Source == Destination then
  200. * error
  201. * If dosversion >= 3.20
  202. * {
  203. * Use generic get_device_parameters and Get BPB.
  204. * if (the drive is a Quad density drive (1.2 MB), and if user wants
  205. * to format for 360KB), take BPB for 360KB from the bpbList[].
  206. * In all other cases, use the BPB of the device.
  207. * }
  208. * else
  209. * {
  210. * Ask INT 13 for the drive type.
  211. * If error then {
  212. * assume 48tpi double side
  213. * Attempt to format track 0, head 1
  214. * If error then
  215. * assume 48tpi single side
  216. * else
  217. * if sectors per track = 15 then
  218. * assume 96tpi
  219. * Ask user if he wants to format for 1.2MB or 360KB and
  220. * use the proper BPB from bpbList[]
  221. * else
  222. * error
  223. * }
  224. *
  225. * Note that this does NOT take into account non-contiguous drive letters
  226. * (see 3.2 spec) nor future drives nor user-installed device drivers.
  227. *
  228. * Format (dSrc, nDstDrive, nDstDriveInt13) will format drive nDstDrive using an updated
  229. * boot sector from drive dSrc. We will allocate two blocks of memory, but
  230. * only one at a time. The first one we allocate is the bit-map of bad
  231. * clusters that we find during the format. The second is for the boot
  232. * sector.
  233. *
  234. * Returns: 0 Success
  235. * <> 0 error code
  236. * 1 => NOMEMORY
  237. * 3 => Invalid boot sector.
  238. * 4 => System area of the floppy is bad
  239. * 7 => Problem in writing in Dest diskette.
  240. * 8 => Internal error
  241. * 9 => Format has been aborted by user.
  242. */
  243. // in:
  244. // hWnd window to base messages on
  245. //
  246. // nSource drive to swipe boot stuff from
  247. //
  248. // nDest drive to format
  249. //
  250. // iCapacity SS48
  251. // DS48
  252. // DS96
  253. // DS720KB
  254. // DS144M
  255. // DS288M
  256. // -1 (device capacity)
  257. //
  258. // bMakeSysDisk make a system disk too
  259. //
  260. // bQuick do a quick format
  261. //
  262. // returns:
  263. // 0 success
  264. // != 0 error
  265. //
  266. INT
  267. APIENTRY
  268. FormatFloppy(
  269. HWND hWnd,
  270. WORD nDest,
  271. INT iCapacity,
  272. BOOL bMakeSysDisk,
  273. BOOL bQuick
  274. )
  275. {
  276. DPB DPB;
  277. DBT dbtSave; /* Disk Base Table */
  278. INT iErrCode;
  279. PBPB pBPB;
  280. WORD w;
  281. WORD cClusters;
  282. WORD wFATValue;
  283. WORD wBadCluster;
  284. WORD cBadSectors;
  285. WORD cTotalTracks;
  286. WORD wCurrentHead;
  287. WORD wPercentDone;
  288. WORD wCurrentTrack;
  289. WORD cTracksToFormat;
  290. WORD wFirstDataSector;
  291. WORD nSource;
  292. DevPB dpbDiskParms; /* Device Parameters */
  293. LPDBT lpDBT;
  294. LPSTR lpDiskBuffer;
  295. LPSTR lpBadClusterList;
  296. HANDLE hDiskBuffer;
  297. HANDLE hBadClusterList;
  298. HANDLE hSaveDiskParms = NULL;
  299. PDevPB pdpbSaveDiskParms;
  300. CHAR szMsg[128];
  301. BOOL fLowCapacity = FALSE; /* Is a 360KB floppy in a 1.2MB drive? */
  302. INT ret = 0; // default to success
  303. nSource = (WORD)GetBootDisk();
  304. /* Initialize for cleanup. */
  305. hDiskBuffer = NULL;
  306. lpDiskBuffer = NULL;
  307. hBadClusterList = NULL;
  308. lpBadClusterList = NULL;
  309. bUserAbort = FALSE;
  310. /* Create a dialogbox that displays the progress of formatting; and also
  311. * gives the user a chance to abort formatting at anytime.
  312. */
  313. hdlgProgress = CreateDialog(hAppInstance, MAKEINTRESOURCE(FORMATPROGRESSDLG), hWnd, ProgressDlgProc);
  314. if (!hdlgProgress) {
  315. ret = IDS_FFERR_MEM; // out of memory
  316. goto FFErrExit1;
  317. }
  318. EnableWindow(hWnd, FALSE);
  319. /* Flush to DOS disk buffers. */
  320. DiskReset();
  321. /* Get the Disk Base Table. */
  322. if (!(lpDBT = GetDBT())) {
  323. ret = IDS_FFERR_MEM;
  324. goto FFErrExit2;
  325. }
  326. dbtSave = *lpDBT;
  327. // this checks to see if we are trying to format the boot drive
  328. // this is a no no
  329. if ((nDest == nSource) || (!IsRemovableDrive(nDest))) {
  330. ret = IDS_FFERR_SRCEQDST;
  331. goto FFErrExit3;
  332. }
  333. /* Check if the sector size is of standard size; If not report error */
  334. if (HIWORD(GetClusterInfo(nSource)) > CBSECTORSIZE) {
  335. ret = IDS_FFERR_SECSIZE;
  336. goto FFErrExit3;
  337. }
  338. /* Allocate boot sector, sector buffer, track buffer */
  339. if (!(hDiskBuffer = LocalAlloc(LHND, (LONG)(2*CBSECTORSIZE)))) {
  340. ret = IDS_FFERR_MEM;
  341. goto FFErrExit3;
  342. }
  343. lpDiskBuffer = LocalLock(hDiskBuffer);
  344. /* If DOS Version is 3.2 or above, use DeviceParameters() to get the BPB. */
  345. if (wDOSversion >= DOS_320) {
  346. /* NOTE: All the fields of dpbDiskParms must be initialized to 0,
  347. * otherwise, INT 21h, Function 44h, Subfunction 0Dh does NOT work;
  348. * This function is called in DeviceParameters().
  349. */
  350. memset(&dpbDiskParms, 0, sizeof(DevPB));
  351. pBPB = &(dpbDiskParms.BPB);
  352. if (iCapacity != -1) {
  353. w = (WORD)GetMediaType(nDest);
  354. if (w) {
  355. switch (w) {
  356. case 2: // 720
  357. if (iCapacity > DS720KB) {
  358. w = IDS_720KB;
  359. iCapacity = DS720KB;
  360. } else
  361. goto SensePass;
  362. break;
  363. case 7: // 1.44
  364. if (iCapacity > DS144M) {
  365. w = IDS_144MB;
  366. iCapacity = DS144M;
  367. } else
  368. goto SensePass;
  369. break;
  370. default: // 2.88 and unknown case
  371. goto SensePass;
  372. }
  373. LoadString(hAppInstance, IDS_FFERR_MEDIASENSE, szMsg, sizeof(szMsg));
  374. LoadString(hAppInstance, w, szTitle, sizeof(szTitle));
  375. wsprintf(szMessage, szMsg, (LPSTR)szTitle);
  376. LoadString(hAppInstance, IDS_FORMATERR, szTitle, sizeof(szTitle));
  377. if (MessageBox(hdlgProgress, szMessage, szTitle, MB_YESNO | MB_ICONINFORMATION) != IDYES) {
  378. ret = IDS_FFERR_USERABORT;
  379. goto FFErrExit3;
  380. }
  381. }
  382. SensePass:
  383. pBPB = &bpbList[iCapacity];
  384. cClusters = cCluster[iCapacity];
  385. // if we are formatting a 360K disk in a 1.2 MB drive set this
  386. // special flag
  387. if (iCapacity == DS48) {
  388. // We must remember to change the number of cylinders
  389. // while doing Set Device parameters; So, set this flag;
  390. fLowCapacity = TRUE;
  391. }
  392. } else {
  393. DWORD dwSec = pBPB->cSec;
  394. // use the default device parameters
  395. // NOTE: pBPB already points to proper data
  396. /* HPVECTRA: DOS 3.2 and above gives wrong sector count. */
  397. if (!pBPB->cSec)
  398. dwSec = dpbDiskParms.NumCyls * pBPB->secPerTrack * pBPB->cHead;
  399. /* Calculate the clusters for the disk. */
  400. cClusters = (WORD)(dwSec / pBPB->secPerClus) -
  401. (pBPB->cSecRes + (pBPB->cFAT * pBPB->secPerFAT) +
  402. (pBPB->cDir*32 + pBPB->cbSec - 1) / pBPB->cbSec) / pBPB->secPerClus;
  403. }
  404. /* Save the DriveParameterBlock for restoration latter */
  405. hSaveDiskParms = BuildDevPB(&dpbDiskParms);
  406. if (!hSaveDiskParms) {
  407. ret = IDS_FFERR_MEM;
  408. goto FFErrExit3;
  409. }
  410. pdpbSaveDiskParms = (PDevPB)LocalLock(hSaveDiskParms);
  411. /* Modify the parameters just for format */
  412. memcpy(&(dpbDiskParms.BPB), pBPB, sizeof(BPB));
  413. if (!SetDevParamsForFormat(nDest, &dpbDiskParms, fLowCapacity)) {
  414. ret = IDS_FFERR_MEM;
  415. goto FFErrExit3;
  416. }
  417. } else {
  418. // DOS < 3.2
  419. /* See if INT 13 knows the drive type. */
  420. switch (MyGetDriveType(nDest)) {
  421. case NOCHANGE:
  422. /* We assume that the machine is using old ROMS...
  423. * Assume that we are using a 9-sector Double-sided 48tpi diskette.
  424. */
  425. pBPB = &bpbList[DS48];
  426. cClusters = cCluster[DS48];
  427. lpDBT->lastsector = (BYTE)pBPB->secPerTrack;
  428. lpDBT->gaplengthf = 0x50;
  429. /* Try to format a track on side 1. If this fails, assume that we
  430. * have a Single-sided 48tpi diskette.
  431. */
  432. if (FormatTrackHead(nDest, 0, 1, pBPB->secPerTrack, lpDiskBuffer)) {
  433. pBPB = &bpbList[SS48];
  434. cClusters = cCluster[SS48];
  435. }
  436. break;
  437. case CHANGE:
  438. if (iCapacity == DS48) {
  439. /* User wants to format a 360KB floppy. */
  440. pBPB = &bpbList[DS48];
  441. cClusters = cCluster[DS48];
  442. } else {
  443. /* User wants to format a 1.2 MB floppy */
  444. pBPB = &bpbList[DS96];
  445. cClusters = cCluster[DS96];
  446. }
  447. break;
  448. default:
  449. ret = IDS_FFERR_DRIVETYPE;
  450. goto FFErrExit5;
  451. }
  452. }
  453. lpDBT->lastsector = (BYTE)pBPB->secPerTrack;
  454. lpDBT->gaplengthf = (BYTE)(pBPB->secPerTrack == 15 ? 0x54 : 0x50);
  455. if (wDOSversion < DOS_320) {
  456. /* If 96tpi, fix up the Disk Base Table. */
  457. if (pBPB->bMedia == MEDIA_1200) /* high density */
  458. if (pBPB->secPerTrack == 15) /* then 1.2 Meg Drive */
  459. SetDASD(nDest, 3); /* 1.2 MB floppy in 1.2MB drive */
  460. }
  461. LoadString(hAppInstance, IDS_PERCENTCOMP, szMsg, sizeof(szMsg));
  462. /* We believe that we know EXACTLY what is out there. Allocate the boot
  463. * sector and the bad-cluster bit-map. The boot sector buffer is reused as
  464. * two consecutive sectors of the FAT.
  465. */
  466. if (!(hBadClusterList = LocalAlloc(LHND, (LONG)((2 + cClusters + 7) / 8)))) {
  467. ret = IDS_FFERR_MEM;
  468. goto FFErrExit5;
  469. }
  470. lpBadClusterList = LocalLock(hBadClusterList);
  471. /* Let's format 1 track at a time and record the bad sectors in the
  472. * bitmap. Note that we round DOWN the number of tracks so that we
  473. * don't format what might not be ours. Fail if there are any bad
  474. * sectors in the system area.
  475. */
  476. /* Compute number of tracks to format. */
  477. if (!pBPB->cSec)
  478. cTracksToFormat = (WORD)dpbDiskParms.NumCyls;
  479. else
  480. cTracksToFormat = (WORD)(pBPB->cSec / pBPB->secPerTrack);
  481. /* Compute the starting track and head. */
  482. wCurrentTrack = pBPB->cSecHidden / (pBPB->secPerTrack * pBPB->cHead);
  483. wCurrentHead = (pBPB->cSecHidden % (pBPB->secPerTrack * pBPB->cHead))/pBPB->secPerTrack;
  484. /* Compute the number of the first sector after the system area. */
  485. wFirstDataSector = pBPB->cSecRes + pBPB->cFAT * pBPB->secPerFAT +
  486. (pBPB->cDir * 32 + pBPB->cbSec-1) / pBPB->cbSec;
  487. cTotalTracks = cTracksToFormat;
  488. if (bQuick) {
  489. // read the boot sector to make sure the capacity selected
  490. // matches what it has been formated to
  491. iErrCode = GenericReadWriteSector(lpDiskBuffer, INT13_READ, nDest, 0, 0, 1);
  492. if (iErrCode || ((iCapacity != -1) && ((BOOTSEC *)lpDiskBuffer)->BPB.bMedia != bpbList[iCapacity].bMedia)) {
  493. fFormatFlags &= ~FF_QUICK;
  494. bQuick = FALSE;
  495. LoadString(hAppInstance, IDS_FORMATQUICKFAILURE, szMessage, 128);
  496. LoadString(hAppInstance, IDS_FORMAT, szTitle, 128);
  497. iErrCode = MessageBox(hdlgProgress, szMessage, szTitle, MB_YESNO | MB_ICONEXCLAMATION);
  498. if (iErrCode == IDYES)
  499. goto NormalFormat;
  500. else {
  501. ret = IDS_FFERR_USERABORT;
  502. goto FFErrExit;
  503. }
  504. }
  505. } else {
  506. NormalFormat:
  507. /* Format tracks one by one, checking if the user has "Aborted"
  508. * after each track is formatted; DlgProgreeProc() will set the global
  509. * bUserAbort, if the user has aborted;
  510. */
  511. while (cTracksToFormat) {
  512. /* Has the user aborted? */
  513. if (WFQueryAbort()) {
  514. ret = IDS_FFERR_USERABORT;
  515. goto FFErrExit;
  516. }
  517. /* If no message is pending, go ahead and format one track */
  518. if ((iErrCode = GenericFormatTrack(nDest, wCurrentTrack, wCurrentHead, pBPB->secPerTrack, lpDiskBuffer))) {
  519. /* Check if it is a fatal error */
  520. if (iErrCode == -1) {
  521. // ret = IDS_FFERR_BADTRACK;
  522. ret = IDS_FFERR;
  523. goto FFErrExit;
  524. }
  525. /* Bad Track. Compute the number of the first bad sector */
  526. cBadSectors = (wCurrentTrack * pBPB->cHead + wCurrentHead) * pBPB->secPerTrack;
  527. /* Fail if bad sector is in the system area */
  528. if (cBadSectors < wFirstDataSector) {
  529. // ret = IDS_FFERR_BADTRACK;
  530. ret = IDS_FFERR;
  531. goto FFErrExit;
  532. }
  533. /* Enumerate all bad sectors and mark the corresponding
  534. * clusters as bad.
  535. */
  536. for (w=cBadSectors; w < cBadSectors + pBPB->secPerTrack; w++) {
  537. wBadCluster = (w - wFirstDataSector) / pBPB->secPerClus + 2;
  538. lpBadClusterList[wBadCluster/8] |= 1 << (wBadCluster % 8);
  539. }
  540. }
  541. cTracksToFormat--;
  542. /* Display the percentage of progress message */
  543. wPercentDone = (WORD)MulDiv(cTotalTracks - cTracksToFormat, 100, cTotalTracks);
  544. /* All tracks might have been formatted. But,
  545. * Still FAT and Root dir are to be created; It takes time; So,
  546. * make the user believe that still 1% formatting is left.
  547. */
  548. if (wPercentDone == 100)
  549. LoadString(hAppInstance, IDS_CREATEROOT, szMessage, sizeof(szMessage));
  550. else
  551. wsprintf(szMessage, szMsg, wPercentDone);
  552. SendDlgItemMessage(hdlgProgress, IDD_PROGRESS, WM_SETTEXT, 0, (LPARAM)szMessage);
  553. if (++wCurrentHead >= pBPB->cHead) {
  554. wCurrentHead = 0;
  555. wCurrentTrack++;
  556. }
  557. }
  558. }
  559. /* Write out the boot sector(s). */
  560. w = (WORD)WriteBootSector(nSource, nDest, pBPB, lpDiskBuffer);
  561. if (w) {
  562. // ret = IDS_FFERR_WRITEBOOT;
  563. if (w == 0x16) // int24 unknown command, assume
  564. ret = IDS_SYSDISKNOFILES; // the int25 read failed
  565. else
  566. ret = IDS_FFERR;
  567. goto FFErrExit;
  568. }
  569. /* Has the user aborted? */
  570. if (WFQueryAbort()) {
  571. ret = IDS_FFERR_USERABORT;
  572. goto FFErrExit;
  573. }
  574. /* Format is complete. Create correct DPB in system */
  575. SetDPB(nDest, pBPB, &DPB);
  576. // if doing a quick format keep the old bad cluster list
  577. /* Create FAT entries for each of the formatted clusters. */
  578. for (w=2; w < (WORD)(cClusters+2); w++) {
  579. if (bQuick) {
  580. wFATValue = 0;
  581. // is this entry reserved or marked as bad
  582. if ((wFATValue >= 0xFFF0) &&
  583. (wFATValue <= 0xFFF7)) {
  584. // yes, don't change it!
  585. } else {
  586. // mark as free
  587. if (0) {
  588. // ret = IDS_FFERR_WRITEFAT;
  589. ret = IDS_FFERR;
  590. goto FFErrExit;
  591. }
  592. }
  593. } else {
  594. /* Was this cluster bad? */
  595. if (lpBadClusterList[w/8] & (1 << (w % 8)))
  596. wFATValue = 0xFFF7;
  597. else
  598. wFATValue = 0;
  599. /* Add this entry to the FAT (possibly writing the sector). */
  600. if (0) {
  601. // ret = IDS_FFERR_WRITEFAT;
  602. ret = IDS_FFERR;
  603. goto FFErrExit;
  604. }
  605. }
  606. if (WFQueryAbort()) { /* Has the user aborted? */
  607. ret = IDS_FFERR_USERABORT;
  608. goto FFErrExit;
  609. }
  610. }
  611. /* Clean out the root directory. */
  612. memset(lpDiskBuffer, 0, CBSECTORSIZE);
  613. for (w=0; w < (WORD)((pBPB->cDir*32 + pBPB->cbSec-1)/pBPB->cbSec); w++) {
  614. /* Has the user aborted? */
  615. if (WFQueryAbort()) {
  616. ret = IDS_FFERR_USERABORT;
  617. goto FFErrExit;
  618. }
  619. }
  620. /* Should we make it a system disk also? */
  621. if (bMakeSysDisk) {
  622. LoadString(hAppInstance, IDS_COPYSYSFILES, szMessage, 32);
  623. SendDlgItemMessage(hdlgProgress, IDD_PROGRESS, WM_SETTEXT, 0, (LPARAM)szMessage);
  624. if (MakeSystemDiskette(nDest, TRUE)) {
  625. if (bUserAbort)
  626. ret = IDS_FFERR_USERABORT;
  627. else
  628. ret = IDS_FFERR_SYSFILES;
  629. goto FFErrExit;
  630. }
  631. }
  632. /* Normal Exit. */
  633. LocalUnlock(hBadClusterList);
  634. LocalFree(hBadClusterList);
  635. LocalUnlock(hDiskBuffer);
  636. if (hSaveDiskParms) {
  637. /* Restore the DriveParameterBlock */
  638. pdpbSaveDiskParms->SplFunctions = 4;
  639. LocalUnlock(hSaveDiskParms);
  640. LocalFree(hSaveDiskParms);
  641. }
  642. LocalFree(hDiskBuffer);
  643. *lpDBT = dbtSave;
  644. EnableWindow(hWnd, TRUE);
  645. DestroyWindow(hdlgProgress);
  646. hdlgProgress = NULL;
  647. return TRUE;
  648. FFErrExit:
  649. LocalUnlock(hBadClusterList);
  650. LocalFree(hBadClusterList);
  651. FFErrExit5:
  652. if (hSaveDiskParms) {
  653. /* Restore the DriveParameterBlock */
  654. pdpbSaveDiskParms->SplFunctions = 4;
  655. LocalUnlock(hSaveDiskParms);
  656. LocalFree(hSaveDiskParms);
  657. }
  658. LocalUnlock(hDiskBuffer);
  659. LocalFree(hDiskBuffer);
  660. FFErrExit3:
  661. *lpDBT = dbtSave;
  662. FFErrExit2:
  663. EnableWindow(hWnd, TRUE);
  664. DestroyWindow(hdlgProgress);
  665. hdlgProgress = NULL;
  666. FFErrExit1:
  667. if (ret != IDS_FFERR_USERABORT) {
  668. LoadString(hAppInstance, IDS_FORMATERR, szTitle, sizeof(szTitle));
  669. LoadString(hAppInstance, ret, szMessage, sizeof(szMessage));
  670. MessageBox(hWnd, szMessage, szTitle, MB_OK | MB_ICONSTOP);
  671. }
  672. return FALSE;
  673. }
  674. /*--------------------------------------------------------------------------*/
  675. /* */
  676. /* GetDriveCapacity() - */
  677. /* */
  678. /*--------------------------------------------------------------------------*/
  679. /* Parameter:
  680. * Drive number;
  681. * Returns:
  682. * 0 if Error;
  683. * 1 if 360KB floppy;
  684. * 2 if 1.2MB floppy;
  685. * 3 if 720KB, 3.5" floppy;
  686. * 4 if 1.44MB, 3.5" floppy;
  687. * 5 if 2.88MB, 3.5" floppy;
  688. *
  689. * these are used +2 as indexes into bpbList[] FIX31
  690. *
  691. * HACK ALERT:
  692. * One might wonder why on earth we are not using int13h Fn 8 to
  693. * perform this function; The reason is that in old compaq 386/16
  694. * machines(though the BIOS is dated Sep 1986), this function is NOT
  695. * supported! So, we are forced to do the following:
  696. * We check the DOS version; If it is >= 3.2, then we make IOCTL
  697. * calls to get the Drive parameters and we find the Drive capacity;
  698. * If DOS version is < 3.2, then there can't be 3.5" floppies at all;
  699. * The only high capacity floppy possible is the 5.25", 1.2MB floppy;
  700. * So, we call MyGetDriveType() (int13h, Fn 15h) to find if the
  701. * change-line is supported by the drive; If it is supported then it
  702. * must be a 1.2MB floppy; Otherwise, it is a 360KB floppy;
  703. * What do you think? Smart! Ugh?
  704. */
  705. WORD
  706. APIENTRY
  707. GetDriveCapacity(
  708. WORD nDrive
  709. )
  710. {
  711. DevPB dpbDiskParms; /* Device Parameters */
  712. PBPB pBPB;
  713. if (wDOSversion >= DOS_320) {
  714. /* NOTE: All the fields of dpbDiskParms must be initialized to 0,
  715. * otherwise, INT 21h, Function 44h, Subfunction 0Dh does NOT work;
  716. * This function is called in DeviceParameters().
  717. */
  718. memset(&dpbDiskParms, 0, sizeof(DevPB));
  719. dpbDiskParms.SplFunctions = 0;
  720. pBPB = &(dpbDiskParms.BPB);
  721. /* Check if this is a 1.44MB drive */
  722. if (pBPB->bMedia == MEDIA_1440) {
  723. if (pBPB->secPerTrack == 18)
  724. return 4; /* 1.44MB drive */
  725. else if (pBPB->secPerTrack == 36)
  726. return 5; /* 2.88MB drive */
  727. }
  728. /* Check if this is a 720KB or 1.2MB drive */
  729. if (pBPB->bMedia == MEDIA_1200) {
  730. if (pBPB->secPerFAT == 3)
  731. return 3; /* 720KB drive */
  732. if (pBPB->secPerFAT == 7)
  733. return 2; /* 1.2MB drive */
  734. }
  735. if (pBPB->bMedia == MEDIA_360)
  736. return 1; /* Must be a 386KB floppy. */
  737. return 0; // I don't know!
  738. } else {
  739. /* See if INT 13 Fn 15h knows the drive type. */
  740. switch (MyGetDriveType(nDrive)) {
  741. case NOCHANGE:
  742. /* We assume that the machine is using old ROMS... */
  743. return 1; /* No changeline support! Must be 360KB floppy */
  744. break;
  745. case CHANGE:
  746. return 2; /* DOS versions < 3.2 can not have 1.44 or 720KB
  747. * drive; So, this has to be a 1.2MB drive
  748. */
  749. break;
  750. default:
  751. return 0;
  752. }
  753. }
  754. }