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.

857 lines
23 KiB

  1. #include "spprecmp.h"
  2. #pragma hdrstop
  3. //
  4. // This variable is needed since it contains a buffer that can
  5. // be used in kernel mode. The buffer is used by NtFsControlFile,
  6. // since the Zw API is not exported
  7. //
  8. extern PSETUP_COMMUNICATION CommunicationParams;
  9. #define VERIFY_SIZE 65536
  10. typedef struct {
  11. UCHAR IntelNearJumpCommand[1]; // Intel Jump command
  12. UCHAR BootStrapJumpOffset[2]; // offset of boot strap code
  13. UCHAR OemData[8]; // OEM data
  14. UCHAR BytesPerSector[2]; // BPB
  15. UCHAR SectorsPerCluster[1]; //
  16. UCHAR ReservedSectors[2]; //
  17. UCHAR Fats[1]; //
  18. UCHAR RootEntries[2]; //
  19. UCHAR Sectors[2]; //
  20. UCHAR Media[1]; //
  21. UCHAR SectorsPerFat[2]; //
  22. UCHAR SectorsPerTrack[2]; //
  23. UCHAR Heads[2]; //
  24. UCHAR HiddenSectors[4]; //
  25. UCHAR LargeSectors[4]; //
  26. UCHAR PhysicalDrive[1]; // 0 = removable, 80h = fixed
  27. UCHAR CurrentHead[1]; // not used by fs utils
  28. UCHAR Signature[1]; // boot signature
  29. UCHAR SerialNumber[4]; // serial number
  30. UCHAR Label[11]; // volume label, aligned padded
  31. UCHAR SystemIdText[8]; // system ID, FAT for example
  32. } UNALIGNED_SECTOR_ZERO, *PUNALIGNED_SECTOR_ZERO;
  33. #define CSEC_FAT32MEG 65536
  34. #define CSEC_FAT16BIT 32680
  35. #define MIN_CLUS_BIG 4085 // Minimum clusters for a big FAT.
  36. #define MAX_CLUS_BIG 65525 // Maximum + 1 clusters for big FAT.
  37. USHORT
  38. ComputeSecPerCluster(
  39. IN ULONG NumSectors,
  40. IN BOOLEAN SmallFat
  41. )
  42. /*++
  43. Routine Description:
  44. This routine computes the number of sectors per cluster.
  45. Arguments:
  46. NumSectors - Supplies the number of sectors on the disk.
  47. SmallFat - Supplies whether or not the FAT should be small.
  48. Return Value:
  49. The number of sectors per cluster necessary.
  50. --*/
  51. {
  52. ULONG threshold;
  53. USHORT sec_per_clus;
  54. USHORT min_sec_per_clus;
  55. threshold = SmallFat ? MIN_CLUS_BIG : MAX_CLUS_BIG;
  56. sec_per_clus = 1;
  57. while (NumSectors >= threshold) {
  58. sec_per_clus *= 2;
  59. threshold *= 2;
  60. }
  61. if (SmallFat) {
  62. min_sec_per_clus = 8;
  63. } else {
  64. min_sec_per_clus = 4;
  65. }
  66. return max(sec_per_clus, min_sec_per_clus);
  67. }
  68. ULONG
  69. SpComputeSerialNumber(
  70. VOID
  71. )
  72. /*++
  73. Routine Description:
  74. This routine computes a new serial number for a volume.
  75. Arguments:
  76. Seed - Supplies a seed for the serial number.
  77. Return Value:
  78. A new volume serial number.
  79. --*/
  80. {
  81. PUCHAR p;
  82. ULONG i;
  83. TIME_FIELDS time_fields;
  84. static ULONG Seed = 0;
  85. ULONG SerialNumber;
  86. BOOLEAN b;
  87. //
  88. // If this is the first time we've entered this routine,
  89. // generate a seed value based on the real time clock.
  90. //
  91. if(!Seed) {
  92. b = HalQueryRealTimeClock(&time_fields);
  93. ASSERT(b);
  94. Seed = ((time_fields.Year - 1970) *366*24*60*60) +
  95. (time_fields.Month *31*24*60*60) +
  96. (time_fields.Day *24*60*60) +
  97. (time_fields.Hour *60*60) +
  98. (time_fields.Minute *60) +
  99. time_fields.Second +
  100. ((ULONG)time_fields.Milliseconds << 10);
  101. ASSERT(Seed);
  102. if(!Seed) {
  103. Seed = 1;
  104. }
  105. }
  106. SerialNumber = Seed;
  107. p = (PUCHAR)&SerialNumber;
  108. for(i=0; i<sizeof(ULONG); i++) {
  109. SerialNumber += p[i];
  110. SerialNumber = (SerialNumber >> 2) + (SerialNumber << 30);
  111. }
  112. if(++Seed == 0) { // unlikely, but possible.
  113. Seed++;
  114. }
  115. return SerialNumber;
  116. }
  117. VOID
  118. EditFat(
  119. IN USHORT ClusterNumber,
  120. IN USHORT ClusterEntry,
  121. IN OUT PUCHAR Fat,
  122. IN BOOLEAN SmallFat
  123. )
  124. /*++
  125. Routine Description:
  126. This routine edits the FAT entry 'ClusterNumber' with 'ClusterEntry'.
  127. Arguments:
  128. ClusterNumber - Supplies the number of the cluster to edit.
  129. ClusterEntry - Supplies the new value for that cluster number.
  130. Fat - Supplies the FAT to edit.
  131. SmallFat - Supplies whether or not the FAT is small.
  132. Return Value:
  133. None.
  134. --*/
  135. {
  136. ULONG n;
  137. if (SmallFat) {
  138. n = ClusterNumber*3;
  139. if (n%2) {
  140. Fat[n/2] = (UCHAR) ((Fat[n/2]&0x0F) | ((ClusterEntry&0x000F)<<4));
  141. Fat[n/2 + 1] = (UCHAR) ((ClusterEntry&0x0FF0)>>4);
  142. } else {
  143. Fat[n/2] = (UCHAR) (ClusterEntry&0x00FF);
  144. Fat[n/2 + 1] = (UCHAR) ((Fat[n/2 + 1]&0xF0) |
  145. ((ClusterEntry&0x0F00)>>8));
  146. }
  147. } else {
  148. ((PUSHORT) Fat)[ClusterNumber] = ClusterEntry;
  149. }
  150. }
  151. NTSTATUS
  152. FmtFillFormatBuffer(
  153. IN ULONGLONG NumberOfSectors,
  154. IN ULONG SectorSize,
  155. IN ULONG SectorsPerTrack,
  156. IN ULONG NumberOfHeads,
  157. IN ULONGLONG NumberOfHiddenSectors,
  158. OUT PVOID FormatBuffer,
  159. IN ULONG FormatBufferSize,
  160. OUT PULONGLONG SuperAreaSize,
  161. IN PULONG BadSectorsList,
  162. IN ULONG NumberOfBadSectors,
  163. OUT PUCHAR SystemId
  164. )
  165. /*++
  166. Routine Description:
  167. This routine computes a FAT super area based on the disk size,
  168. disk geometry, and bad sectors of the volume.
  169. Arguments:
  170. NumberOfSectors - Supplies the number of sectors on the volume.
  171. SectorSize - Supplies the number of bytes per sector.
  172. SectorsPerTrack - Supplies the number of sectors per track.
  173. NumberOfHeads - Supplies the number of heads.
  174. NumberOfHiddenSectors - Supplies the number of hidden sectors.
  175. FormatBuffer - Returns the super area for the volume.
  176. FormatBufferSize - Supplies the number of bytes in the supplied
  177. buffer.
  178. SuperAreaSize - Returns the number of bytes in the super area.
  179. BadSectorsList - Supplies the list of bad sectors on the volume.
  180. NumberOfBadSectors - Supplies the number of bad sectors in the list.
  181. Return Value:
  182. ENOMEM - The buffer wasn't big enough.
  183. E2BIG - The disk is too large to be formatted.
  184. EIO - There is a bad sector in the super area.
  185. EINVAL - There is a bad sector off the end of the disk.
  186. ESUCCESS
  187. --*/
  188. {
  189. PUNALIGNED_SECTOR_ZERO psecz;
  190. PUCHAR puchar;
  191. USHORT tmp_ushort;
  192. ULONG tmp_ulong;
  193. BOOLEAN small_fat;
  194. ULONG num_sectors;
  195. UCHAR partition_id;
  196. ULONG sec_per_fat;
  197. ULONG sec_per_root;
  198. ULONG sec_per_clus;
  199. ULONG i;
  200. ULONG sec_per_sa;
  201. RtlZeroMemory(FormatBuffer,FormatBufferSize);
  202. // Make sure that there's enough room for the BPB.
  203. if(!FormatBuffer || FormatBufferSize < SectorSize) {
  204. return(STATUS_BUFFER_TOO_SMALL);
  205. }
  206. // Compute the number of sectors on disk.
  207. num_sectors = (ULONG)NumberOfSectors;
  208. // Compute the partition identifier.
  209. partition_id = num_sectors < CSEC_FAT16BIT ? PARTITION_FAT_12 :
  210. num_sectors < CSEC_FAT32MEG ? PARTITION_FAT_16 :
  211. PARTITION_HUGE;
  212. // Compute whether or not to have a big or small FAT.
  213. small_fat = (BOOLEAN) (partition_id == PARTITION_FAT_12);
  214. psecz = (PUNALIGNED_SECTOR_ZERO) FormatBuffer;
  215. puchar = (PUCHAR) FormatBuffer;
  216. //
  217. // Copy the fat boot code into the format buffer.
  218. //
  219. if (!IsNEC_98) { //NEC98
  220. ASSERT(sizeof(FatBootCode) == 512);
  221. RtlMoveMemory(psecz,FatBootCode,sizeof(FatBootCode));
  222. // Set up the jump instruction.
  223. psecz->IntelNearJumpCommand[0] = 0xeb;
  224. psecz->IntelNearJumpCommand[1] = 0x3c;
  225. psecz->IntelNearJumpCommand[2] = 0x90;
  226. } else {
  227. ASSERT(sizeof(PC98FatBootCode) == 512);
  228. RtlMoveMemory(psecz,PC98FatBootCode,sizeof(PC98FatBootCode));
  229. //
  230. // Already written jump instruction to bootcode.
  231. // So,do not reset jump code.
  232. //
  233. } //NEC98
  234. // Set up the OEM data.
  235. memcpy(psecz->OemData, "MSDOS5.0", 8);
  236. // Set up the bytes per sector.
  237. U_USHORT(psecz->BytesPerSector) = (USHORT)SectorSize;
  238. // Set up the number of sectors per cluster.
  239. sec_per_clus = ComputeSecPerCluster(num_sectors, small_fat);
  240. if (sec_per_clus > 128) {
  241. // The disk is too large to be formatted.
  242. return(STATUS_INVALID_PARAMETER);
  243. }
  244. psecz->SectorsPerCluster[0] = (UCHAR) sec_per_clus;
  245. // Set up the number of reserved sectors.
  246. U_USHORT(psecz->ReservedSectors) = (USHORT)max(1,512/SectorSize);
  247. // Set up the number of FATs.
  248. psecz->Fats[0] = 2;
  249. // Set up the number of root entries and number of sectors for the root.
  250. U_USHORT(psecz->RootEntries) = 512;
  251. sec_per_root = (512*32 - 1)/SectorSize + 1;
  252. // Set up the number of sectors.
  253. if (num_sectors >= 1<<16) {
  254. tmp_ushort = 0;
  255. tmp_ulong = num_sectors;
  256. } else {
  257. tmp_ushort = (USHORT) num_sectors;
  258. tmp_ulong = 0;
  259. }
  260. U_USHORT(psecz->Sectors) = tmp_ushort;
  261. U_ULONG(psecz->LargeSectors) = tmp_ulong;
  262. // Set up the media byte.
  263. psecz->Media[0] = 0xF8;
  264. // Set up the number of sectors per FAT.
  265. if (small_fat) {
  266. sec_per_fat = num_sectors/(2 + SectorSize*sec_per_clus*2/3);
  267. } else {
  268. sec_per_fat = num_sectors/(2 + SectorSize*sec_per_clus/2);
  269. }
  270. sec_per_fat++;
  271. U_USHORT(psecz->SectorsPerFat) = (USHORT)sec_per_fat;
  272. // Set up the number of sectors per track.
  273. U_USHORT(psecz->SectorsPerTrack) = (USHORT)SectorsPerTrack;
  274. // Set up the number of heads.
  275. U_USHORT(psecz->Heads) = (USHORT)NumberOfHeads;
  276. // Set up the number of hidden sectors.
  277. U_ULONG(psecz->HiddenSectors) = (ULONG)NumberOfHiddenSectors;
  278. // Set up the physical drive number.
  279. psecz->PhysicalDrive[0] = 0x80;
  280. psecz->CurrentHead[0] = 0;
  281. // Set up the BPB signature.
  282. psecz->Signature[0] = 0x29;
  283. // Set up the serial number.
  284. U_ULONG(psecz->SerialNumber) = SpComputeSerialNumber();
  285. // Set up the volume label.
  286. memcpy(psecz->Label, "NO NAME ",11);
  287. // Set up the system id.
  288. memcpy(psecz->SystemIdText, small_fat ? "FAT12 " : "FAT16 ", 8);
  289. // Set up the boot signature.
  290. puchar[510] = 0x55;
  291. puchar[511] = 0xAA;
  292. // Now make sure that the buffer has enough room for both of the
  293. // FATs and the root directory.
  294. sec_per_sa = 1 + 2*sec_per_fat + sec_per_root;
  295. *SuperAreaSize = SectorSize*sec_per_sa;
  296. if (*SuperAreaSize > FormatBufferSize) {
  297. return(STATUS_BUFFER_TOO_SMALL);
  298. }
  299. // Set up the first FAT.
  300. puchar[SectorSize] = 0xF8;
  301. puchar[SectorSize + 1] = 0xFF;
  302. puchar[SectorSize + 2] = 0xFF;
  303. if (!small_fat) {
  304. puchar[SectorSize + 3] = 0xFF;
  305. }
  306. for (i = 0; i < NumberOfBadSectors; i++) {
  307. if (BadSectorsList[i] < sec_per_sa) {
  308. // There's a bad sector in the super area.
  309. return(STATUS_UNSUCCESSFUL);
  310. }
  311. if (BadSectorsList[i] >= num_sectors) {
  312. // Bad sector out of range.
  313. return(STATUS_NONEXISTENT_SECTOR);
  314. }
  315. // Compute the bad cluster number;
  316. tmp_ushort = (USHORT)
  317. ((BadSectorsList[i] - sec_per_sa)/sec_per_clus + 2);
  318. EditFat(tmp_ushort, (USHORT) 0xFFF7, &puchar[SectorSize], small_fat);
  319. }
  320. // Copy the first FAT onto the second.
  321. memcpy(&puchar[SectorSize*(1 + sec_per_fat)],
  322. &puchar[SectorSize],
  323. (unsigned int) SectorSize*sec_per_fat);
  324. *SystemId = partition_id;
  325. return(STATUS_SUCCESS);
  326. }
  327. VOID
  328. FmtVerifySectors(
  329. IN HANDLE Handle,
  330. IN ULONG NumberOfSectors,
  331. IN ULONG SectorSize,
  332. OUT PULONG* BadSectorsList,
  333. OUT PULONG NumberOfBadSectors
  334. )
  335. /*++
  336. Routine Description:
  337. This routine verifies all of the sectors on the volume.
  338. It returns a pointer to a list of bad sectors. The pointer
  339. will be NULL if there was an error detected.
  340. Arguments:
  341. Handle - Supplies a handle to the partition for verifying.
  342. NumberOfSectors - Supplies the number of partition sectors.
  343. SectorSize - Supplies the number of bytes per sector.
  344. BadSectorsList - Returns the list of bad sectors.
  345. NumberOfBadSectors - Returns the number of bad sectors in the list.
  346. Return Value:
  347. None.
  348. --*/
  349. {
  350. ULONG num_read_sec;
  351. ULONG i, j;
  352. PULONG bad_sec_buf;
  353. ULONG max_num_bad;
  354. PVOID Gauge;
  355. IO_STATUS_BLOCK IoStatusBlock;
  356. NTSTATUS Status;
  357. VERIFY_INFORMATION VerifyInfo;
  358. max_num_bad = 100;
  359. bad_sec_buf = SpMemAlloc(max_num_bad*sizeof(ULONG));
  360. ASSERT(bad_sec_buf);
  361. *NumberOfBadSectors = 0;
  362. num_read_sec = VERIFY_SIZE/SectorSize;
  363. //
  364. // Initialize the Gas Gauge
  365. //
  366. SpFormatMessage(
  367. TemporaryBuffer,
  368. sizeof(TemporaryBuffer),
  369. SP_TEXT_SETUP_IS_FORMATTING
  370. );
  371. Gauge = SpCreateAndDisplayGauge(
  372. NumberOfSectors/num_read_sec,
  373. 0,
  374. VideoVars.ScreenHeight - STATUS_HEIGHT - (3*GAUGE_HEIGHT/2),
  375. TemporaryBuffer,
  376. NULL,
  377. GF_PERCENTAGE,
  378. 0
  379. );
  380. VerifyInfo.StartingOffset.QuadPart = 0;
  381. for (i = 0; i < NumberOfSectors; i += num_read_sec) {
  382. if (i + num_read_sec > NumberOfSectors) {
  383. num_read_sec = NumberOfSectors - i;
  384. }
  385. //
  386. // Verify this many sectors at the current offset.
  387. //
  388. VerifyInfo.Length = num_read_sec * SectorSize;
  389. Status = ZwDeviceIoControlFile(
  390. Handle,
  391. NULL,
  392. NULL,
  393. NULL,
  394. &IoStatusBlock,
  395. IOCTL_DISK_VERIFY,
  396. &VerifyInfo,
  397. sizeof(VerifyInfo),
  398. NULL,
  399. 0
  400. );
  401. //
  402. // I/O should be synchronous.
  403. //
  404. ASSERT(Status != STATUS_PENDING);
  405. if(!NT_SUCCESS(Status)) {
  406. //
  407. // Range is bad -- verify individual sectors.
  408. //
  409. VerifyInfo.Length = SectorSize;
  410. for (j = 0; j < num_read_sec; j++) {
  411. Status = ZwDeviceIoControlFile(
  412. Handle,
  413. NULL,
  414. NULL,
  415. NULL,
  416. &IoStatusBlock,
  417. IOCTL_DISK_VERIFY,
  418. &VerifyInfo,
  419. sizeof(VerifyInfo),
  420. NULL,
  421. 0
  422. );
  423. ASSERT(Status != STATUS_PENDING);
  424. if(!NT_SUCCESS(Status)) {
  425. if (*NumberOfBadSectors == max_num_bad) {
  426. max_num_bad += 100;
  427. bad_sec_buf = SpMemRealloc(
  428. bad_sec_buf,
  429. max_num_bad*sizeof(ULONG)
  430. );
  431. ASSERT(bad_sec_buf);
  432. }
  433. bad_sec_buf[(*NumberOfBadSectors)++] = i + j;
  434. }
  435. //
  436. // Advance to next sector.
  437. //
  438. VerifyInfo.StartingOffset.QuadPart += SectorSize;
  439. }
  440. } else {
  441. //
  442. // Advance to next range of sectors.
  443. //
  444. VerifyInfo.StartingOffset.QuadPart += VerifyInfo.Length;
  445. }
  446. if(Gauge) {
  447. SpTickGauge(Gauge);
  448. }
  449. }
  450. if(Gauge) {
  451. SpTickGauge(Gauge);
  452. }
  453. *BadSectorsList = bad_sec_buf;
  454. //return(STATUS_SUCCESS);
  455. }
  456. #if 0
  457. //
  458. // Code not used, we call autoformat
  459. //
  460. NTSTATUS
  461. SpFatFormat(
  462. IN PDISK_REGION Region
  463. )
  464. /*++
  465. Routine Description:
  466. This routine does a FAT format on the given partition.
  467. The caller should have cleared the screen and displayed
  468. any message in the upper portion; this routine will
  469. maintain the gas gauge in the lower portion of the screen.
  470. Arguments:
  471. Region - supplies the disk region descriptor for the
  472. partition to be formatted.
  473. Return Value:
  474. --*/
  475. {
  476. ULONG hidden_sectors;
  477. PULONG bad_sectors;
  478. ULONG num_bad_sectors;
  479. PVOID format_buffer;
  480. PVOID unaligned_format_buffer;
  481. ULONG max_sec_per_sa;
  482. ULONG super_area_size;
  483. PHARD_DISK pHardDisk;
  484. ULONG PartitionOrdinal;
  485. NTSTATUS Status;
  486. HANDLE Handle;
  487. ULONG BytesPerSector;
  488. IO_STATUS_BLOCK IoStatusBlock;
  489. LARGE_INTEGER LargeZero;
  490. UCHAR SysId;
  491. ULONG ActualSectorCount;
  492. SET_PARTITION_INFORMATION PartitionInfo;
  493. ASSERT(Region->PartitionedSpace);
  494. ASSERT(Region->TablePosition < PTABLE_DIMENSION);
  495. ASSERT(Region->Filesystem != FilesystemDoubleSpace);
  496. pHardDisk = &HardDisks[Region->DiskNumber];
  497. BytesPerSector = pHardDisk->Geometry.BytesPerSector;
  498. PartitionOrdinal = SpPtGetOrdinal(Region,PartitionOrdinalCurrent);
  499. //
  500. // Make SURE it's not partition0! The results of formatting partition0
  501. // are so disasterous that theis warrants a special check.
  502. //
  503. if(!PartitionOrdinal) {
  504. SpBugCheck(
  505. SETUP_BUGCHECK_PARTITION,
  506. PARTITIONBUG_B,
  507. Region->DiskNumber,
  508. 0
  509. );
  510. }
  511. #ifdef _X86_
  512. //
  513. // If we're going to format C:, then clear the previous OS entry
  514. // in boot.ini.
  515. //
  516. if(Region == SpPtValidSystemPartition()) {
  517. *OldSystemLine = '\0';
  518. }
  519. #endif
  520. //
  521. // Query the number of hidden sectors and the actual number
  522. // of sectors in the volume.
  523. //
  524. SpPtGetSectorLayoutInformation(Region,&hidden_sectors,&ActualSectorCount);
  525. //
  526. // Open the partition for read/write access.
  527. // This shouldn't lock the volume so we need to lock it below.
  528. //
  529. Status = SpOpenPartition(
  530. pHardDisk->DevicePath,
  531. PartitionOrdinal,
  532. &Handle,
  533. TRUE
  534. );
  535. if(!NT_SUCCESS(Status)) {
  536. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL,
  537. "SETUP: SpFatFormat: unable to open %ws partition %u (%lx)\n",
  538. pHardDisk->DevicePath,
  539. PartitionOrdinal,
  540. Status
  541. ));
  542. return(Status);
  543. }
  544. //
  545. // Lock the drive
  546. //
  547. Status = SpLockUnlockVolume( Handle, TRUE );
  548. //
  549. // We shouldn't have any file opened that would cause this volume
  550. // to already be locked, so if we get failure (ie, STATUS_ACCESS_DENIED)
  551. // something is really wrong. This typically indicates something is
  552. // wrong with the hard disk that won't allow us to access it.
  553. //
  554. if(!NT_SUCCESS(Status)) {
  555. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpFatFormat: status %lx, unable to lock drive \n",Status));
  556. ZwClose(Handle);
  557. return(Status);
  558. }
  559. bad_sectors = NULL;
  560. FmtVerifySectors(
  561. Handle,
  562. ActualSectorCount,
  563. BytesPerSector,
  564. &bad_sectors,
  565. &num_bad_sectors
  566. );
  567. max_sec_per_sa = 1 +
  568. 2*((2*65536 - 1)/BytesPerSector + 1) +
  569. ((512*32 - 1)/BytesPerSector + 1);
  570. unaligned_format_buffer = SpMemAlloc(max_sec_per_sa*BytesPerSector);
  571. ASSERT(unaligned_format_buffer);
  572. format_buffer = ALIGN(unaligned_format_buffer,BytesPerSector);
  573. Status = FmtFillFormatBuffer(
  574. ActualSectorCount,
  575. BytesPerSector,
  576. pHardDisk->Geometry.SectorsPerTrack,
  577. pHardDisk->Geometry.TracksPerCylinder,
  578. hidden_sectors,
  579. format_buffer,
  580. max_sec_per_sa*BytesPerSector,
  581. &super_area_size,
  582. bad_sectors,
  583. num_bad_sectors,
  584. &SysId
  585. );
  586. if(bad_sectors) {
  587. SpMemFree(bad_sectors);
  588. }
  589. if(!NT_SUCCESS(Status)) {
  590. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpFatFormat: status %lx from FmtFillFormatBuffer\n",Status));
  591. SpLockUnlockVolume( Handle, FALSE );
  592. ZwClose(Handle);
  593. SpMemFree(unaligned_format_buffer);
  594. return(Status);
  595. }
  596. //
  597. // Write the super area.
  598. //
  599. LargeZero.QuadPart = 0;
  600. Status = ZwWriteFile(
  601. Handle,
  602. NULL,
  603. NULL,
  604. NULL,
  605. &IoStatusBlock,
  606. format_buffer,
  607. super_area_size,
  608. &LargeZero,
  609. NULL
  610. );
  611. //
  612. // I/O should be synchronous.
  613. //
  614. ASSERT(Status != STATUS_PENDING);
  615. SpMemFree(unaligned_format_buffer);
  616. if(!NT_SUCCESS(Status)) {
  617. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpFatFormat: status %lx from ZwWriteFile\n",Status));
  618. SpLockUnlockVolume( Handle, FALSE );
  619. ZwClose(Handle);
  620. return(Status);
  621. }
  622. //
  623. // If we wrote the super area then the drive is now FAT!
  624. // If we don't change, say, a type of ntfs to fat, then code
  625. // that lays down the x86 boot code (i386\bootini.c) will
  626. // come along and write 16 sectors of NTFS boot code into
  627. // sector 0 of our nice FAT volume -- very bad!
  628. // Preserve the filesystem type of FilesystemNewlyCreated
  629. // since other code later in setup relies on this.
  630. //
  631. if(Region->Filesystem >= FilesystemFirstKnown) {
  632. Region->Filesystem = FilesystemFat;
  633. }
  634. //
  635. // Set the partition type.
  636. //
  637. PartitionInfo.PartitionType = SysId;
  638. Status = ZwDeviceIoControlFile(
  639. Handle,
  640. NULL,
  641. NULL,
  642. NULL,
  643. &IoStatusBlock,
  644. IOCTL_DISK_SET_PARTITION_INFO,
  645. &PartitionInfo,
  646. sizeof(PartitionInfo),
  647. NULL,
  648. 0
  649. );
  650. if(!NT_SUCCESS(Status)) {
  651. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: unable to set partition type (status = %lx)\n",Status));
  652. }
  653. //
  654. // Dismount the drive
  655. //
  656. Status = SpDismountVolume( Handle );
  657. if(!NT_SUCCESS(Status)) {
  658. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpFatFormat: status %lx, unable to dismount drive\n",Status));
  659. SpLockUnlockVolume( Handle, FALSE );
  660. ZwClose(Handle);
  661. return(Status);
  662. }
  663. //
  664. // Unlock the drive
  665. //
  666. Status = SpLockUnlockVolume( Handle, FALSE );
  667. if(!NT_SUCCESS(Status)) {
  668. KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpFatFormat: status %lx, unable to unlock drive\n",Status));
  669. }
  670. ZwClose(Handle);
  671. return(Status);
  672. }
  673. #endif